fix symlink handling in resolve_path

This commit is contained in:
ІО-23 Шмуляр Олег 2025-05-17 22:27:11 +03:00
parent db6187be39
commit 1dbdbd20d3
1 changed files with 103 additions and 74 deletions

177
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) {
rp->parent_inode_ptr = -1; pr_warn("parent '%s' does not exist\n", next_fname);
rp->parent_inode_ptr = -1;
}
rp->target_inode_ptr = -1;
break; break;
} }
@ -975,83 +977,110 @@ 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) {
char symlink_path[FS_MAX_PATH_LEN+1]; if (i+1 < path_len) {
int symlink_path_len = read_symlink(res, symlink_path); char symlink_path[FS_MAX_PATH_LEN+1];
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;
break; rp->target_inode_ptr = -1;
} break;
}
if (!strcmp(symlink_path, "/")) { if (symlink_path[0] == '/') {
rp->parent_inode_ptr = 0; memmove(&(path[symlink_path_len]), &(path[i+1]), path_len-i-1);
rp->target_inode_ptr = 0; strcpy(path, &(symlink_path[1]));
strcpy(rp->parent_fname, "/"); path[symlink_path_len-1] = '/';
strcpy(rp->target_fname, "/"); path_len = symlink_path_len + path_len - i - 1;
return; i = -1;
}
if (symlink_path[0] == '/') { next_fname_ptr = 0;
res = 0; strcpy(current_fname, "/");
memmove(&(path[symlink_path_len]), &(path[i+1]), path_len-i-1); memset(next_fname, 0, FS_MAX_FNAME_LEN);
path[symlink_path_len-1] = '/'; } else {
memcpy(path, &(symlink_path[1]), symlink_path_len-1); memmove(&(path[symlink_path_len+1]), &(path[i+1]), path_len-i-1);
path_len = symlink_path_len + path_len - i + 1; strcpy(path, symlink_path);
i = -1; path[symlink_path_len] = '/';
strcpy(next_fname, "/"); 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 { } else {
memmove(&(path[symlink_path_len+1]), &(path[i+1]), path_len-i-1); if (!(params & FOLLOW_LAST_SYMLINK)) {
path[symlink_path_len] = '/'; rp->target_inode_ptr = res;
memcpy(path, symlink_path, symlink_path_len); strcpy(rp->parent_fname, current_fname);
path_len = symlink_path_len + path_len - i + 2; strcpy(rp->target_fname, next_fname);
i = -1; 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;
}
if (!strcmp(symlink_path, "/")) {
rp->parent_inode_ptr = 0;
rp->target_inode_ptr = 0;
strcpy(rp->parent_fname, "/");
strcpy(rp->target_fname, "/");
break;
}
if (symlink_path[0] == '/') {
strcpy(path, &(symlink_path[1]));
path_len = symlink_path_len - 1;
i = -1;
next_fname_ptr = 0;
strcpy(current_fname, "/");
memset(next_fname, 0, FS_MAX_FNAME_LEN);
} else {
strcpy(path, symlink_path);
path_len = symlink_path_len;
i = -1;
next_fname_ptr = 0;
strcpy(current_fname, next_fname);
memset(next_fname, 0, FS_MAX_FNAME_LEN);
}
} }
} else if (d.ftype == REGULAR) { } else if (d.ftype == REGULAR) {
pr_warn("'%s' is a regular file\n", next_fname); if (i+1 < path_len) {
rp->parent_inode_ptr = -1; pr_warn("'%s': regular file not in the end of a path\n", next_fname);
break; rp->parent_inode_ptr = -1;
rp->target_inode_ptr = -1;
break;
} else {
rp->target_inode_ptr = res;
strcpy(rp->parent_fname, current_fname);
strcpy(rp->target_fname, next_fname);
}
} else if (d.ftype == DIRECTORY) { } else if (d.ftype == DIRECTORY) {
pr("Found directory '%s'\n", next_fname); if (i+1 < path_len) {
current_inode_ptr = res; pr("Found directory '%s'\n", next_fname);
rp->parent_inode_ptr = res; 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);
}
} }
next_fname_ptr = 0;
strcpy(current_fname, next_fname);
memset(next_fname, 0, FS_MAX_FNAME_LEN);
} }
if (rp->parent_inode_ptr < 0) {
rp->target_inode_ptr = -1;
return;
}
strcpy(rp->parent_fname, current_fname);
{
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;
}
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 {
rp->target_inode_ptr = res;
strcpy(rp->target_fname, next_fname);
}
}
return;
} }