【问题标题】:Linux "ls -al" like program in CLinux "ls -al" 类似于 C 中的程序
【发布时间】:2015-07-11 16:27:18
【问题描述】:

我有作业要编写一个 C 程序,它的作用类似于 Linux 的“ls -al”命令。我知道互联网上有很多示例程序,它们正在做我需要的事情,但我有一个特定的问题,我找不到解决方案。我还想提一下,我是 C 编程的新手。这是我的代码:

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

int list_dir(const char *dirname)     { 

struct dirent* current_directory;
struct stat my_stat;
struct tm lt;  
struct passwd *pwd; // For User-ID

DIR* directory = opendir(dirname);


    if(directory == NULL)     { 

    printf("list_dir : %s : %s \n", dirname, strerror(errno));

    return 0;
}   

    printf("Directory : %s\n", dirname);
    printf("\n");

    while( (current_directory = readdir(directory) ) )     { 

    stat(current_directory->d_name, &my_stat);  

        if ( (stat(current_directory->d_name, &my_stat) ) == 0 )    {

        pwd = getpwuid(my_stat.st_uid); // Get User-ID

    }

        // Last Modified 
        time_t t = my_stat.st_mtime;
        localtime_r(&t, &lt);
        char timebuf[80];
        strftime(timebuf, sizeof(timebuf), "%c", &lt);

        if (pwd != 0) {

        printf("%s \t %ld \t %s \t %s", pwd->pw_name, (long)my_stat.st_size, timebuf, current_directory->d_name);
        printf("\n");

        } else  {

            printf("%d \t %ld \t %s \t %s", my_stat.st_uid, (long)my_stat.st_size, timebuf, current_directory->d_name);
            printf("\n");
        } 
}
    closedir(directory);        

    return 0; 
}

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

    if ( argc == 1 ) {

    return list_dir ( "." );

    } else {

    int ret = 0;

    for (int i = 1; i < argc; i += 1 ) {

        if ( list_dir ( argv[i] ) != 0 ) {

        ret = 1; 
        }
    }

    return ret;
     } 
} 

程序必须显示与“ls -al”相同的内容(没有权限)。到目前为止一切顺利,如果我用“gcc -std=gnu99 -o list_dir list_dir.c”编译它并用“./list_dir”执行程序,我得到与“ls -al”相同的结果,它看起来像这样:

 username    1599    Fri May  1 20:43:57 2015    list_dir.c

但是,如果我使用以下内容运行程序:“./list_dir /home/username/Downloads/”,我会得到这个:

 32727   0   Sun May  8 07:09:04 4461391     selection_sort.c

如您所见,程序无法获取有关用户名、文件大小和年份的正确信息。由于 if(pwd != 0) 语句的 else 情况,此信息也出现了。如果我没有 else 情况,程序只会打印出可以获取正确信息的文件。另外,如果我删除了这个 if 语句和 if 语句:

 if ( (stat(current_directory->d_name, &my_stat) ) == 0 )

我遇到了分段错误。

所以我的问题是: 1.我做错了什么。我知道我做错了什么,因为作为家庭作业的提示,我有一个程序运行示例,还提示我可以使用“stat、lstat、readlink、getpwnam、getpwuid、strftime”。

2.有什么方法可以通过 stat() 和 User-ID 获取用户名,还是只能通过 getpwuid 获取?

【问题讨论】:

  • gdb 单步执行怎么样?
  • gdb 是个好主意,但最初可能表明存在问题实际原因下游的访问冲突。 strace 可能会更有效,因为它会在 stat() 调用中显示 ENOENT。
  • 需要检查每个目录项,判断是子目录还是目录列表的末尾还是普通文件还是特殊文件还是链接等
  • stat() 失败时代码没有处理条件
  • 为什么这个语句:'#include ' 列出了两次?

标签: c linux ls


【解决方案1】:

这里,

    if ( (stat(current_directory->d_name, &my_stat) ) == 0 ) {
       pwd = getpwuid(my_stat.st_uid); // Get User-ID
    }

如果stat() 失败会怎样? pwd 将具有未初始化的值或先前迭代设置的值不正确。

stat 失败的原因是,current_directory-&gt;d_name 仅包含文件名,而 stat 需要完整路径。因此,您需要将目录名称添加到文件中并将其传递给stat()。您现在只传递文件名。

类似:

   char buf[1024];
   errno = 0;
   snprintf(buf, sizeof buf, "%s/%s", dirname, current_directory->d_name);
   if ( (stat(buf, &my_stat) ) == 0 ) {
     ...
   }
   else {
      printf("%s: %s\n", buf, strerror(errno));
      // exit here or continue to the next entry in the directory 
      //depending how you wish to handle failure
   }

并在stat()失败时处理错误。

循环内还有另一个stat(),它什么都不做。

【讨论】:

  • 非常感谢!使用 char[] 和 snprintf 解决了这个问题。在阅读有关 stat() 的内容时,我可能错过了这部分内容,即预期文件的完整路径。
  • 不客气。我刚刚看到您询问有关获取 uid 的问题:不,stat() 无法提供有关用户名的信息。所以你接近使用getpwuid 是可以的。但是,您可以存储 UID(和相应的用户名),这样如果 UID 已经在您的列表中,您就不需要调用 getpwuid。在您的玩具示例中可能无关紧要,但需要注意。
猜你喜欢
  • 2019-11-03
  • 2012-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-25
  • 1970-01-01
  • 2021-12-27
  • 2011-12-18
相关资源
最近更新 更多