klibc-bot for Ben Hutchings
2023-Jan-13 22:15 UTC
[klibc] [klibc:master] ls: Handle relative directory names correctly
Commit-ID: 3d63cd68496a1c8aeccbdac6488bc1f002700bc8 Gitweb: http://git.kernel.org/?p=libs/klibc/klibc.git;a=commit;h=3d63cd68496a1c8aeccbdac6488bc1f002700bc8 Author: Ben Hutchings <ben at decadent.org.uk> AuthorDate: Sat, 31 Dec 2022 16:00:28 +0100 Committer: Ben Hutchings <ben at decadent.org.uk> CommitDate: Sat, 31 Dec 2022 16:04:19 +0100 [klibc] ls: Handle relative directory names correctly ls currently starts to list a directory with chdir(path) and opendir(path). This obviously fails for relative names. That could be fixed by using opendir(".") instead. However, if multiple relative directory names are given, this would still fail after the first such directory. Instead, leave the current directory unchanged and use the fstatat() and readlinkat() functions to get information about files in each directory. Signed-off-by: Ben Hutchings <ben at decadent.org.uk> --- usr/utils/ls.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/usr/utils/ls.c b/usr/utils/ls.c index 9677bc0f..50af4349 100644 --- a/usr/utils/ls.c +++ b/usr/utils/ls.c @@ -50,7 +50,7 @@ static void do_preformat(const struct stat *st) return; } -static void do_stat(const struct stat *st, const char *path) +static void do_stat(const struct stat *st, int dir_fd, const char *path) { char *fmt, *link_name; int rc; @@ -138,7 +138,7 @@ static void do_stat(const struct stat *st, const char *path) perror("malloc"); exit(1); } - rc = readlink(path, link_name, max_linksiz); + rc = readlinkat(dir_fd, path, link_name, max_linksiz); if (rc == -1) { free(link_name); perror("readlink"); @@ -156,28 +156,26 @@ static void do_stat(const struct stat *st, const char *path) static void do_dir(const char *path, int preformat) { DIR *dir; + int dir_fd; struct dirent *dent; struct stat st; - if (chdir(path) == -1) { - perror(path); - exit(1); - } - dir = opendir(path); if (dir == NULL) { perror(path); exit(1); } + dir_fd = dirfd(dir); while ((dent = readdir(dir)) != NULL) { - if (lstat(dent->d_name, &st)) { + if (fstatat(dir_fd, dent->d_name, &st, + AT_SYMLINK_NOFOLLOW)) { perror(dent->d_name); exit(1); } (preformat) ? do_preformat(&st) : - do_stat(&st, dent->d_name); + do_stat(&st, dir_fd, dent->d_name); } closedir(dir); @@ -218,7 +216,7 @@ int main(int argc, char *argv[]) S_ISDIR(st.st_mode) ? do_dir(argv[i], 0) : - do_stat(&st, argv[i]); + do_stat(&st, AT_FDCWD, argv[i]); } return 0;