【问题标题】:Linux "ls -l" implementation using file descriptors in C/C++在 C/C++ 中使用文件描述符的 Linux “ls -l” 实现
【发布时间】:2013-12-25 09:04:03
【问题描述】:

我需要用 C 语言实现ls 程序。 我想找到一种不使用<dirent.h> 库的方法。

我可以在 Linux C 中使用文件描述符获取目录中的文件列表吗?

谢谢。

【问题讨论】:

  • ls 不是已经用 C 语言编写了吗?
  • 是的,但它使用的是 dirent 库。当然,如果可能的话,我想用普通的文件描述符来做到这一点。
  • dirent库也是C.

标签: c linux directory file-descriptor ls


【解决方案1】:

作为一名学生,我最近不得不在 ECE 巴黎工程学院的系统编程课上做同样的工作。

这是我的一段代码。我尚未对其进行测试,但它应该可以正常工作,而且它有很好的文档记录,因此您可以通过阅读 cmets 来理解它的每一部分。

 // This is the lsd function, yet another C implement of the classic ls, using UNIX functions

// Featuring "stat", "opendir", and "readdir"
// Credits: Jalil Benayachi, ECE PARIS - under MIT license
// contact [at] thejals.com

// Also thanks to some contributors on Stackoverflow 

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


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

    //Defining the different components of the program
        //The directory: it's the folder we're browsing (we'll use an argument (argv) in order to identify it)
    DIR *thedirectory;
        //The file: when a file is found in the directory readdir loop, it's going to be called this way.
    struct dirent *thefile;
        //The stat: It's how we'll retrieve the stats associated to the file. 
    struct stat thestat;
        //will be used to determine the file owner & group
    struct passwd *tf; 
    struct group *gf;

    //Creating a placeholder for the string. 
    //We create this so later it can be properly adressed.
    //It's reasonnable here to consider a 512 maximum lenght, as we're just going to use it to display a path to a file, 
    //but we could have used a strlen/malloc combo and declared a simple buf[] at this moment
    char buf[512];

    //It's time to assign thedirectory to the argument: this way the user will be able to browse any folder simply by mentionning it 
    //when launching the lsd program.
    thedirectory = opendir(argv[1]);

    //If a file is found (readdir returns a NOT NULL value), the loop starts/keep going until it has listed all of them. 
    while((thefile = readdir(thedirectory)) != NULL) 
    {   
        //We sprint "thedirectory/thefile" which defines the path to our file 
        sprintf(buf, "%s/%s", argv[1], thefile->d_name);
        //Then we use stat function in order to retrieve information about the file
        stat(buf, &thestat);

        //Now, we can print a few things !
        // Here's the right order
        // [file type] [permissions] [number of hard links] [owner] [group] [size in bytes] [time of last modification] [filename]

        // [file type]
        //Let's start with the file type
        //The stat manual is pretty complete and gives details about st_mode and S_IFMT: http://manpagesfr.free.fr/man/man2/stat.2.html
        //
        switch (thestat.st_mode & S_IFMT) {
            case S_IFBLK:  printf("b "); break;
            case S_IFCHR:  printf("c "); break; 
            case S_IFDIR:  printf("d "); break; //It's a (sub)directory 
            case S_IFIFO:  printf("p "); break; //fifo
            case S_IFLNK:  printf("l "); break; //Sym link
            case S_IFSOCK: printf("s "); break;
            //Filetype isn't identified
            default:       printf("- "); break;
                }
        //[permissions]
        //Same for the permissions, we have to test the different rights
        //READ http://linux.die.net/man/2/chmod 
        printf( (thestat.st_mode & S_IRUSR) ? " r" : " -");
        printf( (thestat.st_mode & S_IWUSR) ? "w" : "-");
        printf( (thestat.st_mode & S_IXUSR) ? "x" : "-");
        printf( (thestat.st_mode & S_IRGRP) ? "r" : "-");
        printf( (thestat.st_mode & S_IWGRP) ? "w" : "-");
        printf( (thestat.st_mode & S_IXGRP) ? "x" : "-");
        printf( (thestat.st_mode & S_IROTH) ? "r" : "-");
        printf( (thestat.st_mode & S_IWOTH) ? "w" : "-");
        printf( (thestat.st_mode & S_IXOTH) ? "x" : "-");

        // [number of hard links] 
        // Quoting: http://www.gnu.org/software/libc/manual/html_node/Attribute-Meanings.html
        // "This count keeps track of how many directories have entries for this file. 
        // If the count is ever decremented to zero, then the file itself is discarded as soon as no process still holds it open."
        printf("\t%d ", thestat.st_nlink);

        //[owner] 
        // http://linux.die.net/man/3/getpwuid
        tf = getpwuid(thestat.st_uid);
        printf("\t%s ", tf->pw_name);

        //[group]
        // http://linux.die.net/man/3/getgrgid
        gf = getgrgid(thestat.st_gid);
        printf("\t%s ", gf->gr_name);

        //And the easy-cheesy part
        //[size in bytes] [time of last modification] [filename]
        printf("%zu",thestat.st_size);
        printf(" %s", thefile->d_name);
        printf(" %s", ctime(&thestat.st_mtime));
    }
    closedir(thedirectory);
}

我希望这会有所帮助 :) 以及其他一些浏览 stackoverflow 的学生 =)

【讨论】:

  • 有没有办法像 ls -al 打印一样按顺序打印文件?
【解决方案2】:

这取决于您所说的“没有任何库”。

从最严格的意义上说,您可以使用汇编手动读取磁盘,但这将非常困难且不可移植。

接下来,您可以使用汇编来进行 Linux 系统调用。但是,内核只是一个大库。

您的意思可能是:除了 C 标准库之外没有任何库。 我相信这是不可能的。

【讨论】:

    【解决方案3】:

    如果我理解正确,您不想使用 glibc 提供的功能,而是想直接使用内核提供的系统调用来读取目录的内容。这意味着直接使用文件描述符。您可以像往常一样使用系统调用 open() 或 openat() 打开目录,就像打开常规文件一样。

    要读取目录的内容,您可以使用 getdents() 系统调用来读取目录的条目。 getdents 的手册页中有这些函数的示例用法。

    【讨论】:

      【解决方案4】:
      #include <unistd.h>
      #include <stdio.h>
      #include <sys/stat.h>
      #include <sys/types.h>
      #include<stdlib.h>
      #include<dirent.h>
      #include<time.h>
      #include<pwd.h>
      #include <grp.h>
      int main(int argc, char **argv)
      {
        struct passwd *pw;
        struct group *gp;
        DIR *mydir;
        char *c;
        int i;
        struct dirent *myfile;
        struct stat fileStat;
        mydir=opendir(".");
        stat(".",&fileStat); 
        while((myfile=readdir(mydir))!=NULL)
        {
          stat(myfile->d_name,&fileStat);  
          printf( (S_ISDIR(fileStat.st_mode)) ? "d" : "-");
          printf( (fileStat.st_mode & S_IRUSR) ? "r" : "-");
          printf( (fileStat.st_mode & S_IWUSR) ? "w" : "-");
          printf( (fileStat.st_mode & S_IXUSR) ? "x" : "-");
          printf( (fileStat.st_mode & S_IRGRP) ? "r" : "-");
          printf( (fileStat.st_mode & S_IWGRP) ? "w" : "-");
          printf( (fileStat.st_mode & S_IXGRP) ? "x" : "-");
          printf( (fileStat.st_mode & S_IROTH) ? "r" : "-");
          printf( (fileStat.st_mode & S_IWOTH) ? "w" : "-");
          printf( (fileStat.st_mode & S_IXOTH) ? "x" : "-"); 
          printf(" ");
          printf("%d ",fileStat.st_nlink);
          pw=getpwuid(fileStat.st_uid);
          printf("%s ",pw->pw_name);
          gp=getgrgid(fileStat.st_gid);
          printf("%s ",gp->gr_name);
          printf("%4d ",fileStat.st_size);
          c=ctime(&fileStat.st_mtime);
          for(i=4;i<=15;i++)
            printf("%c",c[i]);
          printf(" ");
          printf("%s\n",myfile->d_name);
        }
        closedir(mydir);  
        return 0;
      }
      

      【讨论】:

        【解决方案5】:

        嘿希望这个命令对你有帮助:

        execlp("ls","ls","-l",NULL);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-02-26
          • 1970-01-01
          • 1970-01-01
          • 2013-03-15
          • 1970-01-01
          • 2012-11-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多