简体   繁体   中英

Implementing the ls -al command in C

As a part of an assignment from one of my classes, I have to write a program in C to duplicate the results of the ls -al command. I have read up on the necessary materials but I am still not getting the right output. Here is my code so far, its only supposed to print out the file size and the file name, but the file sizes its printing are not correct.

Code:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>

int main(int argc, char* argv[])
{
    DIR *mydir;
    struct dirent *myfile;
    struct stat mystat;

    mydir = opendir(argv[1]);
    while((myfile = readdir(mydir)) != NULL)
    {
        stat(myfile->d_name, &mystat);    
        printf("%d",mystat.st_size);
        printf(" %s\n", myfile->d_name);
    }
    closedir(mydir);
}

These are my results after executing the code:

[root@localhost ~]# ./a.out Downloads
4096 ..
4096 hw22.c
4096 ankur.txt
4096 .
4096 destination.txt

Here are the correct sizes:

[root@localhost ~]# ls -al Downloads
total 20
drwxr-xr-x.  2 root root 4096 Nov 26 01:35 .
dr-xr-x---. 24 root root 4096 Nov 26 01:29 ..
-rw-r--r--.  1 root root   27 Nov 21 06:32 ankur.txt
-rw-r--r--.  1 root root   38 Nov 21 06:50 destination.txt
-rw-r--r--.  1 root root 1139 Nov 25 23:38 hw22.c

Can anyone please point out my mistake.

Thanks,

Ankur

myfile->d_name is the file name not the path, so you need to append the file name to the directory "Downloads/file.txt" first, if it's is not the working directory:

char buf[512];    
while((myfile = readdir(mydir)) != NULL)
{
    sprintf(buf, "%s/%s", argv[1], myfile->d_name);
    stat(buf, &mystat);
....

As to why it prints 4096 that is the size of the links . and .. from the last call to stat() .

Note: you should allocate a buffer large enough to hold the directory name, the file name the NULL byte and the separator, something like this

strlen(argv[1]) + NAME_MAX + 2;

This is the final code I got to work for anyone interested. It prints the correct file sizes. Credit goes to asker and mux for answering, just putting the code together. Input I got this to work for is "./main ." .

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>

int main(int argc, char* argv[])
{
    DIR *mydir;
    struct dirent *myfile;
    struct stat mystat;

    char buf[512];
    mydir = opendir(argv[1]);
    while((myfile = readdir(mydir)) != NULL)
    {
        sprintf(buf, "%s/%s", argv[1], myfile->d_name);
        stat(buf, &mystat);
        printf("%zu",mystat.st_size);
        printf(" %s\n", myfile->d_name);
    }
    closedir(mydir);
}

I believe you'll observe that if you ./a.out . you will get the behaviour you expect.

You have a slightly subtle bug, observable if you examine the return code of your call to stat(2) .

The fundamental mistake: the dirent s returned by readdir(2) (the myfile in your code) will have a d_name relative to mydir . Your code will stat .. first, succeed, and so mystat will contain valid data for .. , then all subsequent calls to stat(2) will fail, returning -1 , which you do not check for, so mystat will not be modified, and you will print the st_size for the old value, ie that of .. .

The trouble is that when you stat("ankur.txt", &mystat) , you are not working on the file "Downloads/ankur.txt" . Most likely, the stat() is failing; alternatively, it is reporting on a different file.

Consequently, you need to look at whether your system supports fstatat() — new in POSIX 2008 — or arrange to prefix the name of the file with name of the directory.

或者只是系统(“ls -al”)也可以工作!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM