问题
I'm new to C but trying some system calls.
I'm writing program that iterates through all files in a directory and prints the current file name and size. I can get the program to print the file name but it errors when I preform the stat system call.
Here is some of the code:
while (dptr = readdir(dirp)) {
if (stat(dptr->d_name, &buf) != 0) {
//Always does this and it does print the file name
printf("Error on when getting size of %s \n", dptr->d_name);
} else {
//Never gets here
printf("%u", buf.st_size);
}
}
I have the structs described like this:
struct stat buf;
struct dirent *dptr;
DIR *dirp;
If I change:
if (stat(dptr->d_name, &buf) != 0)
to
if (stat(dptr->d_name, &buf) != [EACCES])
It still goes into the loop which makes me think it can't read the file name but it's printing it in the error statement without a problem.
Can someone point me in the right direction? Thanks!
Аркадий
回答1:
First, stat() returns -1 if an error is encountered, not the actual error code. The error code will be set in errno. An easy way to print the error is to use perror().
Second, dptr->d_name only provides a relative filename of the file and not the full filename. To obtain the full filename, you must generate it from the relative filename and the directory name.
Here is an example:
int cwdloop(void)
{
DIR * dirp;
struct stat buff;
struct dirent * dptr;
char filename[1024];
char dirname[1024];
if (!(getcwd(dirname, 1024)))
{
perror("getcwd");
return(1);
};
dirp = opendir(dirname);
if (!(dirp))
{
perror("opendir()");
return(1);
};
while ((dptr = readdir(dirp)))
{
snprintf(filename, 1024, "%s/%s", dirname, dptr->d_name);
if (stat(filename, &buff) != 0)
{
perror("stat()");
return(1);
} else {
printf("size: %u\n", (unsigned)buff.st_size);
};
};
closedir(dirp);
return(0);
}
回答2:
These things are a lot easier to deal with if you know the exact error. Try
printf("error = %d: %s", errno, strerror(errno));
回答3:
One common problem with this kind of code is using just the filename as path name. The d_name
entry of dirent structure does not provide you full pathname but provides pathname relative to your directory.
To resolve this you can either
construct the full path name and then pass it to
stat
orchdir
to the directory before callingstat
.
回答4:
The direct answer to the question is covered by other answers. I'm providing this as a complimentary answer. While you're debugging stat()
system call, you may find the following function helpful for nicely formatting the stat buffer that's returned.
How to format, and print or log stat()
system call:
static void logstat(struct stat *sp)
{
int mode = sp->st_mode;
if (sp->st_size > 1000000000)
printf(" File Size: %lluGB\n", sp->st_size / 1000000000);
else if(sp->st_size > 1000000)
printf(" File Size: %lluMB\n", sp->st_size / 1000000);
else
printf(" File Size: %llu bytes\n", sp->st_size);
printf(" Number of Links: %d\n", sp->st_nlink);
printf(" File inode: %d\n", sp->st_ino);
printf(" File type: ");
switch (mode & S_IFMT) {
case S_IFBLK:
printf("BLK\n");
break;
case S_IFCHR:
printf("CHR\n");
break;
case S_IFDIR:
printf("DIR\n");
break;
case S_IFIFO:
printf("FIFO\n");
break;
case S_IFLNK:
printf("LINK\n");
break;
case S_IFREG:
printf("REG\n");
break;
case S_IFSOCK:
printf("SOCK\n");
break;
}
printf(" File Permissions: ");
printf( (S_ISDIR(sp->st_mode) ? "d" : "-");
printf( (sp->st_mode & S_IRUSR) ? "r" : "-");
printf( (sp->st_mode & S_IWUSR) ? "w" : "-");
printf( (sp->st_mode & S_IXUSR) ? "x" : "-");
printf( (sp->st_mode & S_IRGRP) ? "r" : "-");
printf( (sp->st_mode & S_IWGRP) ? "w" : "-");
printf( (sp->st_mode & S_IXGRP) ? "x" : "-");
printf( (sp->st_mode & S_IROTH) ? "r" : "-");
printf( (sp->st_mode & S_IWOTH) ? "w" : "-");
printf( (sp->st_mode & S_IXOTH) ? "x" : "-");
printf("\n\n");
}
来源:https://stackoverflow.com/questions/8524876/c-programming-stat-system-call-error