Untitled

 avatar
unknown
plain_text
11 days ago
5.2 kB
7
Indexable
StrongPtr<Node> find(StrongPtr<Node> dir, const char* name) {
    // Ensure the starting node is either a directory or a symlink.
    if (!dir->is_dir() && !dir->is_symlink()) {
        return StrongPtr<Node>();
    }

    // Compute the length of the incoming path.
    int name_len = 0;
    while (name[name_len] != '\0') {
        name_len++;
    }

    // Create a mutable copy of the path.
    char* path_copy = new char[name_len + 1];
    for (int i = 0; i < name_len; i++) {
        path_copy[i] = name[i];
    }
    path_copy[name_len] = '\0';

    // Use a separate pointer for traversal.
    char* curr_ptr = path_copy;
    
    // If the path is absolute, start from the root.
    if (curr_ptr[0] == '/') {
        dir = root;
    }
    
    // Save the parent directory (for relative symlink resolution).
    StrongPtr<Node> parent = dir;
    
    // Count how many symlinks we have resolved (to avoid infinite loops).
    int sl_count = 0;

    while (*curr_ptr != '\0') {
        // Skip any leading '/' characters.
        while (*curr_ptr == '/') {
            curr_ptr++;
        }
        if (*curr_ptr == '\0') break;
        
        // --- If the current node is a directory ---
        if (dir->is_dir()) {
            // Update the parent pointer before descending.
            parent = dir;
            
            // Extract the next path segment into a buffer.
            char target_name[256];
            int j = 0;
            while (curr_ptr[j] != '/' && curr_ptr[j] != '\0' && j < 255) {
                target_name[j] = curr_ptr[j];
                j++;
            }
            target_name[j] = '\0';
            
            // Search through the directory entries for a match.
            StrongPtr<Node> next_node;
            uint32_t entry_count = dir->entry_count();
            uint32_t offset = 0;
            bool match_found = false;
            for (uint32_t k = 0; k < entry_count; k++) {
                DirEntry entry;
                dir->read_all(offset, sizeof(DirEntry), (char*)&entry);
                offset += entry.rec_len;
                
                if (entry.name_len == (uint8_t)j) {
                    bool match = true;
                    for (int l = 0; l < j; l++) {
                        if (entry.name[l] != target_name[l]) {
                            match = false;
                            break;
                        }
                    }
                    if (match) {
                        next_node = get_inode(entry.inode);
                        if (next_node == nullptr || next_node->currInode == nullptr) {
                            delete[] path_copy;
                            return StrongPtr<Node>();
                        }
                        match_found = true;
                        break;
                    }
                }
            }
            if (!match_found) {
                delete[] path_copy;
                return StrongPtr<Node>();
            }
            // Advance the traversal pointer by the length of the segment.
            curr_ptr += j;
            // Set the current directory to the found node.
            dir = next_node;
            continue;
        }
        
        // --- If the current node is a symbolic link ---
        if (dir->is_symlink()) {
            sl_count++;
            if (sl_count > 100) {
                delete[] path_copy;
                return StrongPtr<Node>();
            }
            char sl_target[256];
            dir->get_symbol(sl_target);
            
            // Determine the length of the symlink target.
            int target_len = 0;
            while (sl_target[target_len] != '\0') {
                target_len++;
            }
            // Determine the length of the remaining path.
            int remaining_len = 0;
            while (curr_ptr[remaining_len] != '\0') {
                remaining_len++;
            }
            
            // Allocate a new path: symlink target + "/" + remaining path (if any).
            int new_path_len = target_len + (remaining_len > 0 ? 1 + remaining_len : 0);
            char* new_path = new char[new_path_len + 1];
            for (int i = 0; i < target_len; i++) {
                new_path[i] = sl_target[i];
            }
            if (remaining_len > 0) {
                new_path[target_len] = '/';
                for (int i = 0; i < remaining_len; i++) {
                    new_path[target_len + 1 + i] = curr_ptr[i];
                }
                new_path[new_path_len] = '\0';
            } else {
                new_path[target_len] = '\0';
            }
            // For absolute symlink targets, start from the root.
            // For relative targets, interpret them relative to the parent directory.
            if (sl_target[0] == '/') {
                dir = root;
            } else {
                dir = parent;
            }
            // Free the old path copy and update our traversal pointer.
            delete[] path_copy;
            path_copy = new_path;
            curr_ptr = path_copy;
            continue;
        }
    }
    delete[] path_copy;
    return dir;
}
Editor is loading...
Leave a Comment