简体   繁体   English

lstat:无法访问另一个目录中的文件

[英]lstat: can't access files in another directory

I'm trying to write ls-alike program that produces output like ls -l with permissions, owners, time and name of the file. 我正在尝试编写类似ls的程序,该程序产生具有许可权,所有者,时间和文件名的ls -l类的输出。 It works good if I pass . 如果我通过那很好. (or nothing), so it works with the current directory. (或什么都没有),因此它可以与当前目录一起使用。 But if I pass any other directory in or out of the current one, perror says it "can't access" the files. 但是,如果我在当前目录中传入或传出其他任何目录, perror表示它“无法访问”文件。

Please, help me figure out what prevents lstat from accessing files in another dirs. 请帮我找出导致lstat无法访问其他目录中文件的原因。

I use gcc and a text editor, no IDE, started learning to use gdb (tried to debug but didn't find something that would point me to what kind of solution shall I look for). 我使用了gcc和一个文本编辑器(没有IDE),开始学习使用gdb(试图进行调试,但是没有找到可以使我指出要寻找哪种解决方案的东西)。 That's why I decided to put here all the code, so anybody can run it. 这就是为什么我决定将所有代码放在这里,以便任何人都可以运行它的原因。 Maybe I pass wrong arguments, maybe it is some kind of lstat 's wrong behavior, I don't know. 也许我传递了错误的论点,也许是lstat的某种错误行为,我不知道。 I've been trying to find something about it on the web, but with no result. 我一直在尝试在网上找到有关它的内容,但没有结果。

Here is what I've done up to this moment: 这是我到目前为止所做的:

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>     // open()
#include <unistd.h>    // close()
#include <sys/param.h>
#include <string.h>
#include <limits.h>    // PATH_MAX
#include <pwd.h>       // structure for getpwuid()
#include <grp.h>       // structure for getgrgid()
#include <time.h>      // ctime()

static void ls(const char *dir);
void get_info(const char *name, int offset);
int get_maxsize(const char *name);


int main(int argc, char ** argv)
{
    if (argc == 1)
        ls(".");
    else
        while (--argc > 0)
            ls(*++argv);
    return 0;
}


static void ls(const char *dir)
{
    struct dirent * entry;
    DIR *d = opendir(dir);
    char pathbuf[PATH_MAX + 1];
    int offset = 0;

    if (d == 0) {
        perror("ls");
        return;
    }

    /* find max file size for better ls-alike output */
    while ((entry = readdir(d)) != NULL) {
        realpath(entry->d_name, pathbuf);
        /* pathbuf OR entry->d_name here: */
        if (get_maxsize(entry->d_name) > offset)
            offset = get_maxsize(pathbuf);
    }
    closedir(d);

    d = opendir(dir);
    while ((entry = readdir(d)) != NULL) {
        /* pathbuf OR entry->d_name here: */
        realpath(entry->d_name, pathbuf);
        get_info(entry->d_name, offset);
    }
    closedir(d);
}


void get_info(const char *name, int offset)
{
    struct stat statbuf;
    struct passwd *pwdPtr;
    struct group *grpPtr;
    int length = 0;
    char *time = NULL;

    /* skip . and .. dirs */
    if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
        return;

    if (lstat(name, &statbuf) == -1) {
        fprintf(stderr, "can't access %s\n", name);
        perror("get_info");
        return;
    } 
    else
        switch (statbuf.st_mode & S_IFMT) {
            case S_IFREG: printf("-"); break;
            case S_IFDIR: printf("d"); break;
            case S_IFCHR: printf("c"); break;
            case S_IFBLK: printf("b"); break;
            case S_IFLNK: printf("l"); break;
            case S_IFSOCK: printf("s"); break;
            case S_IFIFO: printf("p"); break;
        }

    /* owner */
    if (statbuf.st_mode & S_IREAD) printf("r");
    else printf("-");
    if (statbuf.st_mode & S_IWRITE) printf("w");
    else printf("-");
    if (statbuf.st_mode & S_IEXEC) printf("x");
    else printf("-");

    /* group */
    if (statbuf.st_mode & S_IRGRP) printf("r");
    else printf("-");
    if (statbuf.st_mode & S_IWGRP) printf("w");
    else printf("-");
    if (statbuf.st_mode & S_IXGRP) printf("x");
    else printf("-");

    /* other users */
    if (statbuf.st_mode & S_IROTH) printf("r");
    else printf("-");
    if (statbuf.st_mode & S_IWOTH) printf("w");
    else printf("-");
    if (statbuf.st_mode & S_IXOTH) printf("x");
    else printf("-");

    /* hard links */
    printf(" %2zu", statbuf.st_nlink);

    /* owner name */
    if ((pwdPtr = getpwuid(statbuf.st_uid)) == NULL) {
        perror("getpwuid");
        exit(EXIT_FAILURE);
    } 
    else {
        printf(" %s", pwdPtr->pw_name);
    }

    /* gruop name */
    if ((grpPtr = getgrgid(statbuf.st_gid)) == NULL) {
        perror("getgrgid");
        exit(EXIT_FAILURE);
    } 
    else {
        printf(" %s", grpPtr->gr_name);
    }

    /* size in bytes */
    /* "C uses an asterisk in the position of the field
       width specifier to indicate to printf that it will
       find the variable that contains the value of the field
       width as an additional parameter." 
       http://www.eecs.wsu.edu/~cs150/reading/printf.htm */
    while(offset != 0)
    {
        offset /= 10;             /* n=n/10 */
        ++length;
    }
    printf(" %*d", length, (int)statbuf.st_size);

    /* last modifying time */
    time = ctime(&statbuf.st_mtime);
    time[strlen(time) - 1] = 0;
    printf(" %s", time);

    /* index */
    // ToDo

    /* filename */
    printf(" %s", name);

    printf("\n");
    // -,d,c,b,l,s,p
    //if ((statbuf.st_mode & S_IFMT) == S_IFREG)
    //    printf("- %8ld %s\n", statbuf.st_size, name);
}


int get_maxsize(const char *name)
{
    struct stat statbuf;

    if (lstat(name, &statbuf) == -1) {
        fprintf(stderr, "can't access %s\n", name);
        perror("get_maxsize");
        return -1;
    }
    return statbuf.st_size;
}

Output when it works fine (only with current directory): 正常工作时输出(仅适用于当前目录):

yulian@deb:~/programming/os$ ./readDir .
-rw-rw-rw-  1 yulian yulian  4387 Mon Nov 30 06:31:51 2015 readDir.c
-rw-rw-rw-  1 yulian yulian   282 Sun Nov 29 04:43:03 2015 sometext.txt
-rwxr-xr-x  1 yulian yulian 13792 Sat Nov 28 11:54:09 2015 readDir
drwxr-xr-x  2 yulian yulian  4096 Fri Nov 27 05:26:42 2015 testDir 
// there is test dir called `testDir` where it fails

Output when it fails: 失败时输出:

yulian@deb:~/programming/os$ ./readDir testDir/
can't access 2.jpg
get_maxsize: No such file or directory
can't access ETicket_edc7cb12cdc23e6c04a308f34fd31c28.pdf
get_maxsize: No such file or directory

update: with the suggested solution I added to get_info : 更新:与建议的解决方案,我添加到get_info

....
char *filemane = NULL;

filemane = strrchr(name, '/') + 1;
/* to prevent . and .. from output */
if (strcmp(filemane, ".") == 0 || strcmp(filemane, "..") == 0)
    return;
...
/* filename */
printf(" %s", filemane);          // and changed the argument here

so the output now produces file names exactly as ls -l , not their full paths. 因此,输出现在生成的文件名与ls -l完全相同,而不是其完整路径。

I think that your program fails because you give it a relative URL as a parameter, and it doesn't know exactly where you are. 我认为您的程序失败了,因为您给它提供了一个相对URL作为参数,并且它并不确切地知道您的位置。 you should call the getcwd function to first have your current directory, join it with the parameter of the program and it should work better. 您应该调用getcwd函数以首先拥有当前目录,并将其与程序的参数连接起来,这样应该可以更好地工作。 Or maybe try to pass ./testDir as a parameter and not just testDir/ to specify that you want a directory located in the current directory. 或者,也许尝试传递./testDir作为参数,而不只是传递testDir /,以指定您希望目录位于当前目录中。

What you're missing is to add the dir you want to explore into the pathbuf variable. 您缺少的是将要浏览的目录添加到pathbuf变量中。 Simply consider using the following implementation of ls 只需考虑使用以下ls实现

static void ls(const char *dir)
{
    struct dirent * entry;
    DIR *d = opendir(dir);
    char pathbuf[PATH_MAX + 1];
    char tmp[PATH_MAX+1];
    int offset = 0;

    if (d == 0) {
        perror("ls");
        return;
    }

    /* find max file size for better ls-alike output */
    while ((entry = readdir(d)) != NULL) {
        /* pathbuf OR entry->d_name here: */
        // realpath(entry->d_name, pathbuf);
        snprintf (tmp, PATH_MAX, "%s/%s", dir, entry->d_name);
        if (get_maxsize(tmp) > offset)
            offset = get_maxsize(tmp);
    }
    closedir(d);

    d = opendir(dir);
    while ((entry = readdir(d)) != NULL) {
        /* pathbuf OR entry->d_name here: */
        // realpath(entry->d_name, pathbuf);
        snprintf (tmp, PATH_MAX, "%s/%s", dir, entry->d_name);
        get_info(tmp, offset);
    }
    closedir(d);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM