Skip to content

Commit

Permalink
paths: Fixed dots followed by dotdots
Browse files Browse the repository at this point in the history
Unlike normal files, dots (".") should not change the depth when
attempting to skip dotdot ("..") entries.

A weird nuance in the path parser, but at least it had a relatively easy
fix.

Added test_paths_dot_dotdots to prevent a regression.
  • Loading branch information
geky committed Nov 23, 2024
1 parent 39c3c66 commit f234ff9
Show file tree
Hide file tree
Showing 2 changed files with 195 additions and 1 deletion.
4 changes: 3 additions & 1 deletion lfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1522,7 +1522,9 @@ static lfs_stag_t lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir,
break;
}

if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) {
if (sufflen == 1 && memcmp(suffix, ".", 1) == 0) {
// noop
} else if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) {
depth -= 1;
if (depth == 0) {
name = suffix + sufflen;
Expand Down
192 changes: 192 additions & 0 deletions tests/test_paths.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1845,6 +1845,198 @@ code = '''
lfs_unmount(&lfs) => 0;
'''

# dot dot dot path tests
[cases.test_paths_dot_dotdots]
defines.DIR = [false, true]
code = '''
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;

// create paths
lfs_mkdir(&lfs, "no") => 0;
lfs_mkdir(&lfs, "no/no") => 0;
lfs_mkdir(&lfs, "coffee") => 0;
lfs_mkdir(&lfs, "coffee/no") => 0;
if (DIR) {
lfs_mkdir(&lfs, "/coffee/drip") => 0;
lfs_mkdir(&lfs, "/no/./../coffee/coldbrew") => 0;
lfs_mkdir(&lfs, "/coffee/no/./../turkish") => 0;
lfs_mkdir(&lfs, "/no/no/./.././../coffee/tubruk") => 0;
lfs_mkdir(&lfs, "/no/no/./.././../coffee/no/./../vietnamese") => 0;
lfs_mkdir(&lfs, "/no/no/./.././../no/no/./.././../coffee/thai") => 0;
} else {
lfs_file_t file;
lfs_file_open(&lfs, &file, "/coffee/drip",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_file_open(&lfs, &file, "/no/./../coffee/coldbrew",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_file_open(&lfs, &file, "/coffee/no/./../turkish",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/tubruk",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/no/./../vietnamese",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_file_open(&lfs, &file, "/no/no/./.././../no/no/./.././../coffee/thai",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0;
}

// stat paths
struct lfs_info info;
lfs_stat(&lfs, "/no/no/./.././../no/no/./.././../coffee/drip", &info) => 0;
assert(strcmp(info.name, "drip") == 0);
assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG));
lfs_stat(&lfs, "/no/no/./.././../coffee/no/./../coldbrew", &info) => 0;
assert(strcmp(info.name, "coldbrew") == 0);
assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG));
lfs_stat(&lfs, "/no/no/./.././../coffee/turkish", &info) => 0;
assert(strcmp(info.name, "turkish") == 0);
assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG));
lfs_stat(&lfs, "/coffee/no/./../tubruk", &info) => 0;
assert(strcmp(info.name, "tubruk") == 0);
assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG));
lfs_stat(&lfs, "/no/./../coffee/vietnamese", &info) => 0;
assert(strcmp(info.name, "vietnamese") == 0);
assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG));
lfs_stat(&lfs, "/coffee/thai", &info) => 0;
assert(strcmp(info.name, "thai") == 0);
assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG));

// file open paths, only works on files!
if (DIR) {
lfs_file_t file;
lfs_file_open(&lfs, &file, "/coffee/drip",
LFS_O_RDONLY) => LFS_ERR_ISDIR;
lfs_file_open(&lfs, &file, "/no/./../coffee/coldbrew",
LFS_O_RDONLY) => LFS_ERR_ISDIR;
lfs_file_open(&lfs, &file, "/coffee/no/./../turkish",
LFS_O_RDONLY) => LFS_ERR_ISDIR;
lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/tubruk",
LFS_O_RDONLY) => LFS_ERR_ISDIR;
lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/no/./../vietnamese",
LFS_O_RDONLY) => LFS_ERR_ISDIR;
lfs_file_open(&lfs, &file, "/no/no/./.././../no/no/./.././../coffee/thai",
LFS_O_RDONLY) => LFS_ERR_ISDIR;
} else {
lfs_file_t file;
lfs_file_open(&lfs, &file, "/coffee/drip",
LFS_O_RDONLY) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_file_open(&lfs, &file, "/no/./../coffee/coldbrew",
LFS_O_RDONLY) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_file_open(&lfs, &file, "/coffee/no/./../turkish",
LFS_O_RDONLY) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/tubruk",
LFS_O_RDONLY) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/no/./../vietnamese",
LFS_O_RDONLY) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_file_open(&lfs, &file, "/no/no/./.././../no/no/./.././../coffee/thai",
LFS_O_RDONLY) => 0;
lfs_file_close(&lfs, &file) => 0;
}

// dir open paths, only works on dirs!
if (DIR) {
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/coffee/drip") => 0;
lfs_dir_close(&lfs, &dir) => 0;
lfs_dir_open(&lfs, &dir, "/no/./../coffee/coldbrew") => 0;
lfs_dir_close(&lfs, &dir) => 0;
lfs_dir_open(&lfs, &dir, "/coffee/no/./../turkish") => 0;
lfs_dir_close(&lfs, &dir) => 0;
lfs_dir_open(&lfs, &dir, "/no/no/./.././../coffee/tubruk") => 0;
lfs_dir_close(&lfs, &dir) => 0;
lfs_dir_open(&lfs, &dir, "/no/no/./.././../coffee/no/./../vietnamese") => 0;
lfs_dir_close(&lfs, &dir) => 0;
lfs_dir_open(&lfs, &dir, "/no/no/./.././../no/no/./.././../coffee/thai") => 0;
lfs_dir_close(&lfs, &dir) => 0;
} else {
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/coffee/drip") => LFS_ERR_NOTDIR;
lfs_dir_open(&lfs, &dir, "/no/./../coffee/coldbrew") => LFS_ERR_NOTDIR;
lfs_dir_open(&lfs, &dir, "/coffee/no/./../turkish") => LFS_ERR_NOTDIR;
lfs_dir_open(&lfs, &dir, "/no/no/./.././../coffee/tubruk") => LFS_ERR_NOTDIR;
lfs_dir_open(&lfs, &dir, "/no/no/./.././../coffee/no/./../vietnamese") => LFS_ERR_NOTDIR;
lfs_dir_open(&lfs, &dir, "/no/no/./.././../no/no/./.././../coffee/thai") => LFS_ERR_NOTDIR;
}

// rename paths
lfs_mkdir(&lfs, "espresso") => 0;
lfs_rename(&lfs,
"/no/no/./.././../no/no/./.././../coffee/drip",
"/espresso/espresso") => 0;
lfs_rename(&lfs,
"/no/no/./.././../coffee/no/./../coldbrew",
"/no/./../espresso/americano") => 0;
lfs_rename(&lfs,
"/no/no/./.././../coffee/turkish",
"/espresso/no/./../macchiato") => 0;
lfs_rename(&lfs,
"/coffee/no/./../tubruk",
"/no/no/./.././../espresso/latte") => 0;
lfs_rename(&lfs,
"/no/./../coffee/vietnamese",
"/no/no/./.././../espresso/no/./../cappuccino") => 0;
lfs_rename(&lfs,
"/coffee/thai",
"/no/no/./.././../no/no/./.././../espresso/mocha") => 0;

// stat paths
lfs_stat(&lfs, "/no/no/./.././../no/no/./.././../espresso/espresso", &info) => 0;
assert(strcmp(info.name, "espresso") == 0);
assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG));
lfs_stat(&lfs, "/no/no/./.././../espresso/no/./../americano", &info) => 0;
assert(strcmp(info.name, "americano") == 0);
assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG));
lfs_stat(&lfs, "/no/no/./.././../espresso/macchiato", &info) => 0;
assert(strcmp(info.name, "macchiato") == 0);
assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG));
lfs_stat(&lfs, "/espresso/no/./../latte", &info) => 0;
assert(strcmp(info.name, "latte") == 0);
assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG));
lfs_stat(&lfs, "/no/./../espresso/cappuccino", &info) => 0;
assert(strcmp(info.name, "cappuccino") == 0);
assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG));
lfs_stat(&lfs, "/espresso/mocha", &info) => 0;
assert(strcmp(info.name, "mocha") == 0);
assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG));

lfs_stat(&lfs, "/no/no/./.././../no/no/./.././../coffee/drip", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "/no/no/./.././../coffee/no/./../coldbrew", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "/no/no/./.././../coffee/turkish", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "/coffee/no/./../tubruk", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "/no/./../coffee/vietnamese", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "/coffee/thai", &info) => LFS_ERR_NOENT;

// remove paths
lfs_remove(&lfs, "/espresso/espresso") => 0;
lfs_remove(&lfs, "/no/./../espresso/americano") => 0;
lfs_remove(&lfs, "/espresso/no/./../macchiato") => 0;
lfs_remove(&lfs, "/no/no/./.././../espresso/latte") => 0;
lfs_remove(&lfs, "/no/no/./.././../espresso/no/./../cappuccino") => 0;
lfs_remove(&lfs, "/no/no/./.././../no/no/./.././../espresso/mocha") => 0;

// stat paths
lfs_stat(&lfs, "/no/no/./.././../no/no/./.././../espresso/espresso", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "/no/no/./.././../espresso/no/./../americano", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "/no/no/./.././../espresso/macchiato", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "/espresso/no/./../latte", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "/no/./../espresso/cappuccino", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "/espresso/mocha", &info) => LFS_ERR_NOENT;

lfs_unmount(&lfs) => 0;
'''

# dot dot dot path tests
[cases.test_paths_dotdotdots]
defines.DIR = [false, true]
Expand Down

0 comments on commit f234ff9

Please sign in to comment.