Untitled
unknown
plain_text
8 months ago
5.2 kB
8
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