opendir() requires chdir()? - Page 1
Forum section: electronics / general

author: MikeK
author_rank: Super Contributor
timestamp: October 04, 2023, 06:35:14 pm
content: I have a short program to output a directory's files. If I open the current directory withopendir("."), it works fine. But if I specify a path, it will list the filenames correctly, but the attributes are wrong. The mtime is wrong, the size is wrong, and the directory flag is wrong (probably others as well).I addedchdir()as a fluke and it works. But I'm not understanding whychdir()is necessary. Shouldn'topendir()return the data for that directory?(I've taken this code from a book which, presumably, was tested and worked withoutchdir().)Code:#include <stdio.h>#include <stdlib.h>#include <dirent.h>#include <time.h>#include <sys/stat.h>#include <string.h>#include <unistd.h>int main(void) {DIR *folder;struct dirent *file;struct stat filestat;char s;char *dir = "/home/mike/python";folder = opendir(dir);chdir(dir);if (folder == NULL) {puts("Unable to read directory");exit(1);}while ((file=readdir(folder)) != NULL) {stat(file->d_name, &filestat);sprintf(s, "%5ld", filestat.st_size);printf("%-14s %s %s",file->d_name,S_ISDIR(filestat.st_mode) ? "<DIR>" : s,ctime(&filestat.st_mtime));}closedir(folder);return(0);}

author: Nominal Animal
author_rank: Super Contributor
timestamp: October 04, 2023, 06:55:40 pm
content: Quote from: MikeK on October 04, 2023, 06:35:14 pmWhy don't you use the proper interface for that,scandir()ornftw()?Quote from: MikeK on October 04, 2023, 06:35:14 pmThed_namefield of astruct direntonly contains the file name part.When you doDIR *dir = opendir("/home/myself/python");and somestruct dirent *ent = readdir(dir);you might haveent->d_namecontaining sayexample.py.The problem is when you dostat(ent->d_name, &filestat)Because relative paths (including plain file names) given tostat()refer to files and paths starting from the current working directory, you won't 'stat' the correct paths at all!You are trying to obtain the information on files in the current working directory, that have the same name as files in the directory opened viaopendir().The solution is to either construct the full path by combining the directory you used, a slash, and the entryd_namefield, or to usefstatat(dirfd(DIR), ent->d_name, &filestat, 0);. However, if you do havefstatat()available, you also havescandir()available, in which case you're using the wrong tool for the job anyway.Alternatively, you can just do achdir(target-directory)first, andDIR *dir = opendir(".");.And if you want to traverse entire directory trees, you'd better usenftw(), or if you have a Microsoft-like deep dislike towards anything POSIX, the BSD-originatingfts interface.Other than in very specific cases like kernel pseudofilesystems and having to be compatible with Windows, you should never use opendir()/readdir() directly, because you won't handle the cases where the directories are modified during scanning anyway. The proper interfaces are supposed to handle that sanely.

author: MikeK
author_rank: Super Contributor
timestamp: October 04, 2023, 07:30:54 pm
content: Great. Thank you.EDIT: Yes, thanks for that thorough explanation.