wip: add support or reading symlinks in resolve_path

This commit is contained in:
ІО-23 Шмуляр Олег 2025-05-17 20:51:09 +03:00
parent 552e574cde
commit db6187be39
1 changed files with 125 additions and 15 deletions

140
src/fs.c
View File

@ -907,18 +907,21 @@ fs_remove_fname_from_directory_finish:
return 0; return 0;
} }
static void resolve_path(struct resolved_path *rp, char *path, unsigned int params) static void resolve_path(struct resolved_path * const rp, const char * const original_path, const unsigned int params)
{ {
rp->parent_inode_ptr = -1; rp->parent_inode_ptr = -1;
rp->target_inode_ptr = -1; rp->target_inode_ptr = -1;
int path_len = strlen(path); int path_len = strlen(original_path);
if (!path_len) { if (!path_len) {
pr_err("no path specified\n"); pr_err("no path specified\n");
return; return;
} }
char path[FS_MAX_PATH_LEN+1];
strcpy(path, original_path);
if (!strcmp(path, "/")) { if (!strcmp(path, "/")) {
rp->parent_inode_ptr = 0; rp->parent_inode_ptr = 0;
rp->target_inode_ptr = 0; rp->target_inode_ptr = 0;
@ -961,25 +964,54 @@ static void resolve_path(struct resolved_path *rp, char *path, unsigned int para
if (i+1 == path_len) if (i+1 == path_len)
continue; continue;
{ int res = find_fname_in_directory(current_inode_ptr, next_fname);
int res = find_fname_in_directory(current_inode_ptr, next_fname); if (res < 0) {
if (res < 0) { pr_warn("directory '%s' does not exist\n", next_fname);
pr_warn("directory '%s' does not exist\n", next_fname); rp->parent_inode_ptr = -1;
break;
}
struct fs_inode d;
read_block(read_inode_ptr(res), &d);
if (d.ftype == SYMLINK) {
char symlink_path[FS_MAX_PATH_LEN+1];
int symlink_path_len = read_symlink(res, symlink_path);
if (symlink_path_len < 0) {
pr_warn("broken symlink\n");
rp->parent_inode_ptr = -1; rp->parent_inode_ptr = -1;
break; break;
} }
{ if (!strcmp(symlink_path, "/")) {
struct fs_inode d; rp->parent_inode_ptr = 0;
read_block(read_inode_ptr(res), &d); rp->target_inode_ptr = 0;
strcpy(rp->parent_fname, "/");
if (d.ftype == REGULAR) { strcpy(rp->target_fname, "/");
pr_warn("'%s' is a regular file\n", next_fname); return;
rp->parent_inode_ptr = -1;
break;
}
} }
if (symlink_path[0] == '/') {
res = 0;
memmove(&(path[symlink_path_len]), &(path[i+1]), path_len-i-1);
path[symlink_path_len-1] = '/';
memcpy(path, &(symlink_path[1]), symlink_path_len-1);
path_len = symlink_path_len + path_len - i + 1;
i = -1;
strcpy(next_fname, "/");
} else {
memmove(&(path[symlink_path_len+1]), &(path[i+1]), path_len-i-1);
path[symlink_path_len] = '/';
memcpy(path, symlink_path, symlink_path_len);
path_len = symlink_path_len + path_len - i + 2;
i = -1;
}
} else if (d.ftype == REGULAR) {
pr_warn("'%s' is a regular file\n", next_fname);
rp->parent_inode_ptr = -1;
break;
} else if (d.ftype == DIRECTORY) {
pr("Found directory '%s'\n", next_fname); pr("Found directory '%s'\n", next_fname);
current_inode_ptr = res; current_inode_ptr = res;
rp->parent_inode_ptr = res; rp->parent_inode_ptr = res;
@ -1002,6 +1034,17 @@ static void resolve_path(struct resolved_path *rp, char *path, unsigned int para
if (res < 0) { if (res < 0) {
pr_warn("target fname '%s' does not exist\n", next_fname); pr_warn("target fname '%s' does not exist\n", next_fname);
rp->target_inode_ptr = -1; rp->target_inode_ptr = -1;
}
struct fs_inode i;
read_block(res, &i);
if (i.ftype == SYMLINK && (params & FOLLOW_LAST_SYMLINK))
struct
/*
rp->target_inode_ptr = res;
strcpy(rp->target_fname, next_fname);
*/
} else { } else {
rp->target_inode_ptr = res; rp->target_inode_ptr = res;
strcpy(rp->target_fname, next_fname); strcpy(rp->target_fname, next_fname);
@ -1631,6 +1674,73 @@ int fs_ln(void *d)
return 0; return 0;
} }
static int read_symlink(int symlink_inode_ptr, char *path)
{
struct fs_inode i;
read_block(read_inode_ptr(symlink_inode_ptr), &i);
path[0] = '\0';
int bytes_read = 0;
for (int j = 0; j < BLOCK_ADDRESSES_PER_INODE; j++) {
if (!i.blocks[j]) {
pr_err("inode size (%d) indicates existing block but it's address is absent in inode, symlink at inode_ptr=%d might be broken\n",
i.size, symlink_inode_ptr);
return -1;
}
char data[FS_BLOCK_SIZE];
read_block(i.blocks[j], data);
if (i.size - bytes_read < FS_BLOCK_SIZE) {
memcpy(&(path[bytes_read]), data, i.size - bytes_read);
bytes_read = i.size;
path[bytes_read] = '\0';
} else {
memcpy(&(path[bytes_read]), data, FS_BLOCK_SIZE);
bytes_read += FS_BLOCK_SIZE;
path[bytes_read] = '\0';
}
if (i.size == bytes_read)
goto finish_reading;
}
for (unsigned int next_ext = i.next_extension; ; ) {
struct fs_inode_extension ext;
read_block(next_ext, &ext);
for (int j = 0; j < BLOCK_ADDRESSES_PER_INODE_EXTENSION; j++) {
if (!ext.blocks[j]) {
pr_err("inode size (%d) indicates existing block but it's address is absent in inode extension, symlink at inode_ptr=%d might be broken\n",
i.size, symlink_inode_ptr);
return -1;
}
char data[FS_BLOCK_SIZE];
read_block(ext.blocks[j], data);
if (i.size - bytes_read < FS_BLOCK_SIZE) {
memcpy(&(path[bytes_read]), data, i.size - bytes_read);
bytes_read = i.size;
path[bytes_read] = '\0';
} else {
memcpy(&(path[bytes_read]), data, FS_BLOCK_SIZE);
bytes_read += FS_BLOCK_SIZE;
path[bytes_read] = '\0';
}
if (i.size == bytes_read)
goto finish_reading;
}
next_ext = ext.next_extension;
}
finish_reading:
return bytes_read;
}
int fs_symlink(void *d) int fs_symlink(void *d)
{ {
char *target_path = ((char **) d)[0]; char *target_path = ((char **) d)[0];