Search code examples
cprintingsymlinkls

How to show symbolic links like LS -al?


I've created a rough program that prints out a similar prompt to that of ls -al using C. While it works nearly perfectly besides not being able to dynamically print out the directory that wasnt able to be opened as no arguments are given its just run in the currently directory so i figured . would suffice but if theres a better way to dynamically do such let me know. I was wondering how can you print out the symbolic links to a file if there are any like is displayed below.

CODE

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <grp.h>
#include <time.h>
#include <pwd.h>
#include <errno.h>
#include <string.h>

int main(void)
{
    DIR *mydir;
    DIR *thedir;
    struct dirent *myfile;
    struct stat myStat;
    struct passwd *pwd;
    int size = 0;
    struct tm lt;
    char buf[1024];
    char length[100];
    long width;
    struct group *gf;
    int len = 0;
    mydir = opendir("./");
    thedir = opendir("./");
    if(mydir!= NULL){
    while((myfile = readdir(thedir)) != NULL){
        lstat(myfile->d_name, &myStat);
        size += myStat.st_blocks;
        width = (long)myStat.st_size;
        sprintf(length, "%ld", width);
        if(len < strlen(length)){
        len = strlen(length);
     }

    }

    printf("total %d\n", size/2);
    closedir(thedir);

    while((myfile = readdir(mydir)) != NULL)
    {

        lstat(myfile->d_name, &myStat);
        if((lstat(myfile->d_name, &myStat) ) == 0){
            pwd = getpwuid(myStat.st_uid);
        }
        gf = getgrgid(myStat.st_gid);
        time_t t = myStat.st_mtime;
        localtime_r(&t, &lt);
        char timebuf[80];
        char timebuf2[80];

        strftime(timebuf, sizeof(timebuf), "%F", &lt);
        strftime(timebuf2, sizeof(timebuf2), "%R", &lt);
        printf( (S_ISDIR(myStat.st_mode)) ? "d" : "-");
        printf( (myStat.st_mode & S_IRUSR) ? "r" : "-");
        printf( (myStat.st_mode & S_IWUSR) ? "w" : "-");
        printf( (myStat.st_mode & S_IXUSR) ? "x" : "-");
        printf( (myStat.st_mode & S_IRGRP) ? "r" : "-");
        printf( (myStat.st_mode & S_IWGRP) ? "w" : "-");
        printf( (myStat.st_mode & S_IXGRP) ? "x" : "-");
        printf( (myStat.st_mode & S_IROTH) ? "r" : "-");
        printf( (myStat.st_mode & S_IWOTH) ? "w" : "-");
        printf( (myStat.st_mode & S_IXOTH) ? "x" : "-");
        printf(" ");
        printf("%ld ", myStat.st_nlink);
        if(pwd != 0){
            printf("%s %s %*ld %s %s %s\n", pwd->pw_name, gf->gr_name, len, (long)myStat.st_size, timebuf, timebuf2, myfile->d_name);
        }else  {

            printf("%d %s %*ld %s %s %s\n", myStat.st_uid, gf->gr_name, len, (long)myStat.st_size, timebuf, timebuf2, myfile->d_name);
            printf("\n");
        } 
        }
    closedir(mydir);
    }else{
        printf("ls: cannot open directory .: Permission denied");

    }


}

Current Output

total 8
-rw-rw-r-- 1 travis travis    0 2019-04-04 17:11 file2.txt
-rw-rw-r-- 1 travis travis    0 2019-04-04 17:11 file1.txt
drwxrwxr-x 4 travis travis 4096 2019-04-04 17:11 ..
drwxrwxr-x 2 travis travis 4096 2019-04-04 17:11 .
-rwxrwxrwx 1 travis travis    9 2019-04-04 17:11 link1
-rwxrwxrwx 1 travis travis    9 2019-04-04 17:11 link2

Desired output

total 8
-rw-rw-r-- 1 travis travis    0 2019-04-04 17:11 file2.txt
-rw-rw-r-- 1 travis travis    0 2019-04-04 17:11 file1.txt
drwxrwxr-x 4 travis travis 4096 2019-04-04 17:11 ..
drwxrwxr-x 2 travis travis 4096 2019-04-04 17:11 .
lrwxrwxrwx 1 travis travis    9 2019-04-04 17:11 link1 -> file1.txt
lrwxrwxrwx 1 travis travis    9 2019-04-04 17:11 link2 -> file2.txt

Solution

  • In your program you look at st_nlink but it concerns the hard link (ln ...), not the symbolic links (ln -s ...)

    Look at readlink for the path you want to write

    SYNOPSIS

      #include <unistd.h>
    
      ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);
    

    DESCRIPTION

      readlink()  places  the  contents  of the symbolic link pathname in the
      buffer buf, which has size bufsiz.  readlink() does not append  a  null
      byte  to buf.  It will (silently) truncate the contents (to a length of
      bufsiz characters), in case the buffer is too small to hold all of  the
       contents.
    

    For instance replace

       if(pwd != 0){
           printf("%s %s %*ld %s %s %s\n", pwd->pw_name, gf->gr_name, len, (long)myStat.st_size, timebuf, timebuf2, myfile->d_name);
       }else  {
    
           printf("%d %s %*ld %s %s %s\n", myStat.st_uid, gf->gr_name, len, (long)myStat.st_size, timebuf, timebuf2, myfile->d_name);
           printf("\n");
       } 
    

    by

        if(pwd != 0){
            printf("%s %s %*ld %s %s %s", pwd->pw_name, gf->gr_name, len, (long)myStat.st_size, timebuf, timebuf2, myfile->d_name);
        }else  {
            printf("%d %s %*ld %s %s %s", myStat.st_uid, gf->gr_name, len, (long)myStat.st_size, timebuf, timebuf2, myfile->d_name);
        } 
    
        char linkname[PATH_MAX];
        ssize_t r = readlink(myfile->d_name, linkname, PATH_MAX);
    
        if (r != -1) {
          linkname[r] = '\0';
          printf(" -> %s\n", linkname);
        }
        else
          putchar('\n');