Implementing the ls -al command in C
Asked Answered
T

4

20

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

Terenceterencio answered 25/11, 2012 at 18:39 Comment(4)
Works okay for me. Check the return value of stat() to see if there is an error.Dubrovnik
Works fine here too. Introduce error checks for everything (opendir(), readdir(), stat()).Academy
Works fine if you run it on ., but not if you give it another directory.Allergic
This is besides the point of the question, but I would suggest you not run programs (especially when learning) as root. I would instead use sudo to run specific programs as rootEwaewald
P
17

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;
Planetary answered 25/11, 2012 at 18:49 Comment(2)
Thank you very much for your response, making your suggested additions worked. The program is giving the correct file sizes now. Thanks.Terenceterencio
This is unbelievable useful when doing my OS papers that i needed to to install drivers in the kernel 2.6.39 emulating with qemu and just one init.. I still didn't figure somethings out but thanks!! haha!!Sargeant
D
9

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);
}
Desta answered 13/10, 2015 at 0:37 Comment(0)
A
2

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 dirents 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, i.e. that of ...

Allergic answered 25/11, 2012 at 18:51 Comment(1)
Thanks for your reply, I see the problem in my code now. But exactly why does this happen? I thought that when we execute the opendir() command, the program is automatically adjusting the file paths for that directory.Terenceterencio
P
1

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.

Panel answered 25/11, 2012 at 18:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.