ext: Properly follow relative symlinks
This commit is contained in:
parent
af4fb9a387
commit
fe637af458
|
@ -339,15 +339,28 @@ static uint32_t *create_alloc_map(struct ext2_file_handle *fd,
|
|||
return alloc_map;
|
||||
}
|
||||
|
||||
static bool symlink_to_inode(struct ext2_inode *inode, struct ext2_file_handle *fd) {
|
||||
static bool symlink_to_inode(struct ext2_inode *inode, struct ext2_file_handle *fd,
|
||||
const char *cwd, size_t cwd_len) {
|
||||
// I cannot find whether this is 0-terminated or not, so I'm gonna take the
|
||||
// safe route here and assume it is not.
|
||||
if (inode->i_size < 59) {
|
||||
struct ext2_dir_entry dir;
|
||||
char *symlink = (char *)inode->i_blocks;
|
||||
symlink[59] = 0;
|
||||
if (!ext2_parse_dirent(&dir, fd, symlink))
|
||||
|
||||
char *abs = ext_mem_alloc(4096);
|
||||
char *cwd_copy = ext_mem_alloc(cwd_len + 1);
|
||||
memcpy(cwd_copy, cwd, cwd_len);
|
||||
get_absolute_path(abs, symlink, cwd_copy);
|
||||
|
||||
pmm_free(cwd_copy, cwd_len + 1);
|
||||
|
||||
if (!ext2_parse_dirent(&dir, fd, abs)) {
|
||||
pmm_free(abs, 4096);
|
||||
return false;
|
||||
}
|
||||
pmm_free(abs, 4096);
|
||||
|
||||
ext2_get_inode(inode, fd, dir.inode);
|
||||
return true;
|
||||
} else {
|
||||
|
@ -367,10 +380,15 @@ static bool ext2_parse_dirent(struct ext2_dir_entry *dir, struct ext2_file_handl
|
|||
|
||||
bool ret;
|
||||
|
||||
const char *cwd = path;
|
||||
size_t cwd_len = 0;
|
||||
|
||||
next:
|
||||
memset(token, 0, 256);
|
||||
|
||||
for (size_t i = 0; i < 255 && *path != '/' && *path != '\0'; i++, path++)
|
||||
size_t next_cwd_len = cwd_len;
|
||||
|
||||
for (size_t i = 0; i < 255 && *path != '/' && *path != '\0'; i++, path++, next_cwd_len++)
|
||||
token[i] = *path;
|
||||
|
||||
if (*path == '\0')
|
||||
|
@ -404,7 +422,7 @@ next:
|
|||
ext2_get_inode(¤t_inode, fd, dir->inode);
|
||||
while ((current_inode.i_mode & FMT_MASK) != S_IFDIR) {
|
||||
if ((current_inode.i_mode & FMT_MASK) == S_IFLNK) {
|
||||
if (!symlink_to_inode(¤t_inode, fd)) {
|
||||
if (!symlink_to_inode(¤t_inode, fd, cwd, cwd_len)) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
@ -415,6 +433,7 @@ next:
|
|||
}
|
||||
}
|
||||
pmm_free(alloc_map, current_inode.i_blocks_count * sizeof(uint32_t));
|
||||
cwd_len = next_cwd_len;
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
@ -471,7 +490,18 @@ struct file_handle *ext2_open(struct volume *part, const char *path) {
|
|||
|
||||
struct ext2_dir_entry entry;
|
||||
|
||||
size_t cwd_len = 0;
|
||||
char *cwd = ext_mem_alloc(4096);
|
||||
for (int i = strlen(path) - 1; i > 0; i--) {
|
||||
if (path[i] == '/' || path[i] == 0) {
|
||||
cwd_len = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
memcpy(cwd, path, cwd_len);
|
||||
|
||||
if (!ext2_parse_dirent(&entry, ret, path)) {
|
||||
pmm_free(cwd, 4096);
|
||||
pmm_free(ret, sizeof(struct ext2_file_handle));
|
||||
return NULL;
|
||||
}
|
||||
|
@ -480,17 +510,21 @@ struct file_handle *ext2_open(struct volume *part, const char *path) {
|
|||
|
||||
while ((ret->inode.i_mode & FMT_MASK) != S_IFREG) {
|
||||
if ((ret->inode.i_mode & FMT_MASK) == S_IFLNK) {
|
||||
if (!symlink_to_inode(&ret->inode, ret)) {
|
||||
if (!symlink_to_inode(&ret->inode, ret, cwd, cwd_len)) {
|
||||
pmm_free(cwd, 4096);
|
||||
pmm_free(ret, sizeof(struct ext2_file_handle));
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
print("ext2: Entity is not regular file nor symlink\n");
|
||||
pmm_free(cwd, 4096);
|
||||
pmm_free(ret, sizeof(struct ext2_file_handle));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
pmm_free(cwd, 4096);
|
||||
|
||||
ret->size = ret->inode.i_size;
|
||||
|
||||
ret->alloc_map = create_alloc_map(ret, &ret->inode);
|
||||
|
|
|
@ -37,6 +37,8 @@ extern bool quiet, serial, editor_enabled;
|
|||
|
||||
bool parse_resolution(size_t *width, size_t *height, size_t *bpp, const char *buf);
|
||||
|
||||
void get_absolute_path(char *path_ptr, const char *path, const char *pwd);
|
||||
|
||||
uint32_t get_crc32(void *_stream, size_t len);
|
||||
|
||||
uint32_t oct2bin(uint8_t *str, uint32_t max);
|
||||
|
|
|
@ -41,3 +41,69 @@ uint64_t strtoui(const char *s, const char **end, int base) {
|
|||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void get_absolute_path(char *path_ptr, const char *path, const char *pwd) {
|
||||
char *orig_ptr = path_ptr;
|
||||
|
||||
if (!*path) {
|
||||
strcpy(path_ptr, pwd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (*path != '/') {
|
||||
strcpy(path_ptr, pwd);
|
||||
path_ptr += strlen(path_ptr);
|
||||
} else {
|
||||
*path_ptr = '/';
|
||||
path_ptr++;
|
||||
path++;
|
||||
}
|
||||
|
||||
goto first_run;
|
||||
|
||||
for (;;) {
|
||||
switch (*path) {
|
||||
case '/':
|
||||
path++;
|
||||
first_run:
|
||||
if (*path == '/') continue;
|
||||
if ((!strncmp(path, ".\0", 2))
|
||||
|| (!strncmp(path, "./\0", 3))) {
|
||||
goto term;
|
||||
}
|
||||
if ((!strncmp(path, "..\0", 3))
|
||||
|| (!strncmp(path, "../\0", 4))) {
|
||||
while (*path_ptr != '/') path_ptr--;
|
||||
if (path_ptr == orig_ptr) path_ptr++;
|
||||
goto term;
|
||||
}
|
||||
if (!strncmp(path, "../", 3)) {
|
||||
while (*path_ptr != '/') path_ptr--;
|
||||
if (path_ptr == orig_ptr) path_ptr++;
|
||||
path += 2;
|
||||
*path_ptr = 0;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(path, "./", 2)) {
|
||||
path += 1;
|
||||
continue;
|
||||
}
|
||||
if (((path_ptr - 1) != orig_ptr) && (*(path_ptr - 1) != '/')) {
|
||||
*path_ptr = '/';
|
||||
path_ptr++;
|
||||
}
|
||||
continue;
|
||||
case '\0':
|
||||
term:
|
||||
if ((*(path_ptr - 1) == '/') && ((path_ptr - 1) != orig_ptr))
|
||||
path_ptr--;
|
||||
*path_ptr = 0;
|
||||
return;
|
||||
default:
|
||||
*path_ptr = *path;
|
||||
path++;
|
||||
path_ptr++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue