fix symlink handling in resolve_path

This commit is contained in:
ІО-23 Шмуляр Олег 2025-05-17 22:27:11 +03:00
parent db6187be39
commit 1dbdbd20d3

129
src/fs.c
View File

@ -24,6 +24,7 @@ static unsigned int fs_cwd_inode_ptr;
static struct fs_file_description fs_file_descriptions[FS_MAX_OPEN_FD]; static struct fs_file_description fs_file_descriptions[FS_MAX_OPEN_FD];
static int extract_basename(char *path, char *name); static int extract_basename(char *path, char *name);
static int read_symlink(int symlink_inode_ptr, char *path);
static int read_block(unsigned int block_no, void *data) static int read_block(unsigned int block_no, void *data)
@ -953,21 +954,22 @@ static void resolve_path(struct resolved_path * const rp, const char * const ori
if (path[i] != '/') { if (path[i] != '/') {
next_fname[next_fname_ptr] = path[i]; next_fname[next_fname_ptr] = path[i];
next_fname_ptr++; next_fname_ptr++;
continue;
} }
// path[i] == '/', trying to change current directory if ((path[i] != '/') && (i+1 < path_len))
continue;
if (!next_fname_ptr) if (!next_fname_ptr)
continue; continue;
if (i+1 == path_len)
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); if (i+1 < path_len) {
pr_warn("parent '%s' does not exist\n", next_fname);
rp->parent_inode_ptr = -1; rp->parent_inode_ptr = -1;
}
rp->target_inode_ptr = -1;
break; break;
} }
@ -975,12 +977,53 @@ static void resolve_path(struct resolved_path * const rp, const char * const ori
read_block(read_inode_ptr(res), &d); read_block(read_inode_ptr(res), &d);
if (d.ftype == SYMLINK) { if (d.ftype == SYMLINK) {
if (i+1 < path_len) {
char symlink_path[FS_MAX_PATH_LEN+1]; char symlink_path[FS_MAX_PATH_LEN+1];
int symlink_path_len = read_symlink(res, symlink_path); int symlink_path_len = read_symlink(res, symlink_path);
if (symlink_path_len < 0) { if (symlink_path_len < 0) {
pr_warn("broken symlink\n"); pr_warn("broken symlink\n");
rp->parent_inode_ptr = -1; rp->parent_inode_ptr = -1;
rp->target_inode_ptr = -1;
break;
}
if (symlink_path[0] == '/') {
memmove(&(path[symlink_path_len]), &(path[i+1]), path_len-i-1);
strcpy(path, &(symlink_path[1]));
path[symlink_path_len-1] = '/';
path_len = symlink_path_len + path_len - i - 1;
i = -1;
next_fname_ptr = 0;
strcpy(current_fname, "/");
memset(next_fname, 0, FS_MAX_FNAME_LEN);
} else {
memmove(&(path[symlink_path_len+1]), &(path[i+1]), path_len-i-1);
strcpy(path, symlink_path);
path[symlink_path_len] = '/';
path_len = symlink_path_len + path_len - i;
i = -1;
next_fname_ptr = 0;
strcpy(current_fname, next_fname);
memset(next_fname, 0, FS_MAX_FNAME_LEN);
}
} else {
if (!(params & FOLLOW_LAST_SYMLINK)) {
rp->target_inode_ptr = res;
strcpy(rp->parent_fname, current_fname);
strcpy(rp->target_fname, next_fname);
break;
}
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->target_inode_ptr = -1;
break; break;
} }
@ -989,69 +1032,55 @@ static void resolve_path(struct resolved_path * const rp, const char * const ori
rp->target_inode_ptr = 0; rp->target_inode_ptr = 0;
strcpy(rp->parent_fname, "/"); strcpy(rp->parent_fname, "/");
strcpy(rp->target_fname, "/"); strcpy(rp->target_fname, "/");
return; break;
} }
if (symlink_path[0] == '/') { if (symlink_path[0] == '/') {
res = 0; strcpy(path, &(symlink_path[1]));
memmove(&(path[symlink_path_len]), &(path[i+1]), path_len-i-1); path_len = symlink_path_len - 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; i = -1;
strcpy(next_fname, "/");
next_fname_ptr = 0;
strcpy(current_fname, "/");
memset(next_fname, 0, FS_MAX_FNAME_LEN);
} else { } else {
memmove(&(path[symlink_path_len+1]), &(path[i+1]), path_len-i-1); strcpy(path, symlink_path);
path[symlink_path_len] = '/'; path_len = symlink_path_len;
memcpy(path, symlink_path, symlink_path_len);
path_len = symlink_path_len + path_len - i + 2;
i = -1; 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);
current_inode_ptr = res;
rp->parent_inode_ptr = res;
}
next_fname_ptr = 0; next_fname_ptr = 0;
strcpy(current_fname, next_fname); strcpy(current_fname, next_fname);
memset(next_fname, 0, FS_MAX_FNAME_LEN); memset(next_fname, 0, FS_MAX_FNAME_LEN);
} }
if (rp->parent_inode_ptr < 0) {
rp->target_inode_ptr = -1;
return;
} }
} else if (d.ftype == REGULAR) {
strcpy(rp->parent_fname, current_fname); if (i+1 < path_len) {
pr_warn("'%s': regular file not in the end of a path\n", next_fname);
{ rp->parent_inode_ptr = -1;
int res = find_fname_in_directory(current_inode_ptr, next_fname);
if (res < 0) {
pr_warn("target fname '%s' does not exist\n", next_fname);
rp->target_inode_ptr = -1; rp->target_inode_ptr = -1;
} break;
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->parent_fname, current_fname);
strcpy(rp->target_fname, next_fname);
}
} else if (d.ftype == DIRECTORY) {
if (i+1 < path_len) {
pr("Found directory '%s'\n", next_fname);
current_inode_ptr = res;
rp->parent_inode_ptr = res;
next_fname_ptr = 0;
strcpy(current_fname, next_fname);
memset(next_fname, 0, FS_MAX_FNAME_LEN);
} else {
rp->target_inode_ptr = res;
strcpy(rp->parent_fname, current_fname);
strcpy(rp->target_fname, next_fname); strcpy(rp->target_fname, next_fname);
} }
} }
return; }
} }