Search code examples
cdirectoryoperating-systemposixsymlink

Scan a directory to find files pointed by soft links


I'm trying to do this exercise for my Operating Systems class: I'm supposed to pass a specific directory through command line to find any files in it pointed by soft links.

This is what I've done:

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

int main(int argc, char *argv[])
{

 DIR *dir_ptr;
 struct dirent *dir_str;
 struct stat buf;
 struct stat buf2;

 if(argc!=2)
 {
  printf("Error! I need a directory.\n");
  exit(-1);
 }


 if((dir_ptr=opendir(argv[1]))==NULL)       
 {
  printf("Opendir error: %s\n", strerror(errno));
  exit(-1);
 }

 while((dir_str=readdir(dir_ptr))!=NULL)
 {
  lstat(dir_str->d_name, &buf);     
  if(S_ISLNK(buf.st_mode))
  {
   stat(dir_str->d_name, &buf2);
   printf("'%s' points to a file of %ld bytes.\n", dir_str->d_name, buf2.st_size);
  }

 }

 closedir(dir_ptr);
 exit(0);

}

Now here's my problem: this program just writes to standard output all soft links that point to a file of a certain size. Instead, I need it prints all the files pointed by a soft link. Secondly, strangely this program seems to work only if no directory is required, I mean, getting the current directory with getcwd()and passing the returned pathname to opendir(). This one infact doesn't even prints all the soft links in the passed directory.

Thanks in advance! Any help would be much appreciated.

EDIT: Let us assume we have this directory named "my_directory" with these files:

justatext.txt
softlink1 (it points to justatext.txt)
justanothertext.txt
softlink2(it points to justanothertext)

When I pass "my_directory" through command line (./a.out my_directory), I want that the program writes to standard output "justatext.txt" and "justanothertext.txt" because these files in the directory are pointed by softlinks. If I pass this directory to my program, no output is printed.


Solution

  • OK, I think I've solved my problem. Summarizing all the advices in the comments, this is what I did and it seems to work:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <limits.h>     
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <dirent.h>
    
    int main(int argc, char *argv[])
    {
    
     DIR *dir_ptr;
     struct dirent *dir_str;
     struct stat buf;
     struct stat buf2;
     char *buf3;            
     ssize_t nbyte, bufsize;
     int flag=0;
    
     if(argc!=2)
     {
      printf("Error! I need a directory.\n");
      exit(EXIT_FAILURE);
     }
    
     if((dir_ptr=opendir(argv[1]))==NULL)
     {
      printf("Opendir error: %s\n", strerror(errno));
      exit(EXIT_FAILURE);
     }
    
     chdir(argv[1]);    
    
     while((dir_str=readdir(dir_ptr))!=NULL)    
     {
      lstat(dir_str->d_name, &buf);     
      bufsize=buf.st_size+1;    
      if(buf.st_size==0)        
       bufsize=PATH_MAX;        
    
      buf3=malloc(bufsize); 
      if(buf3==NULL)
      {
       perror("malloc");
       exit(EXIT_FAILURE);
      }
      nbyte=readlink(dir_str->d_name, buf3, bufsize);   
    
      if(S_ISLNK(buf.st_mode))  
      {
       stat(dir_str->d_name, &buf2);
       printf("%s is a file of %ld bytes pointed by a symbolic link (%s).\n", buf3, buf2.st_size, dir_str->d_name);
       flag+=1;
      }
    
     }
    
     if(flag==0)
      printf("No files pointed by a syslink found in this directory!\n");
    
     free(buf3);
     closedir(dir_ptr);
     exit(0);
    
    }
    

    First of all, I used chdir() in order to change the current directory with the one passed through command line; then I implemented readlink() to obtain the path name in the symbolic link named as its argument. Also I used exit(EXIT_FAILURE) to close the program if an error occurs.

    I don't know if this is fully correct. Please let me know if it's not so!