2015-11-30 3 views
1

Я пытаюсь написать программу ls-alike, которая производит выходные данные, такие как ls -l с разрешениями, владельцами, временем и именем файла. Он работает хорошо, если я передаю . (или ничего), поэтому он работает с текущим каталогом. Но если я передаю любой другой каталог в или из текущего, perror говорит, что он «не может получить доступ» к файлам.lstat: не удается получить доступ к файлам в другом каталоге

Пожалуйста, помогите мне выяснить, что мешает lstat получить доступ к файлам в другом каталоге.

Я использую gcc и текстовый редактор, не IDE, начал учиться использовать gdb (пытался отлаживать, но не нашел того, что указывало бы мне на какое решение я должен искать). Вот почему я решил поставить здесь весь код, так что любой может его запустить. Может быть, я пропущу неправильные аргументы, может быть, это неправильное поведение lstat, я не знаю. Я пытался найти что-то об этом в Интернете, но без результата.

Вот что я сделал до этого момента:

#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; 
} 

выхода, когда он работает отлично (только с текущим каталогом):

[email protected]:~/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 

выхода, когда он терпит неудачу:

[email protected]:~/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 

обновление: с предлагаемым решением Я добавил к 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 

поэтому выход теперь производит имена файлов точно так, как ls -l, а не их полные пути.

ответ

1

Что вам не хватает, так это добавить dir, который вы хотите изучить в переменной pathbuf. Просто рассмотреть с помощью следующей реализации логинсервера

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); 
} 
1

Я думаю, что ваша программа терпит неудачу, потому что вы даете ей относительный URL-адрес в качестве параметра, и он точно не знает, где вы находитесь. вы должны вызвать функцию getcwd, чтобы сначала иметь свой текущий каталог, присоединиться к нему с параметром программы, и он должен работать лучше. Или, может быть, попытайтесь передать ./testDir в качестве параметра, а не только testDir /, чтобы указать, что вам нужен каталог, расположенный в текущем каталоге.

+2

Наблюдение это хорошо, но вы должны присоединиться значение '' dir' и entry-> d_name', не результат 'getcwd()'. (Рабочий каталог никогда не изменяется, а относительные пути должны быть в порядке.) –

+0

Передача './TestDir' не работает: показывает те же результаты. – yulian

+0

@ m-Oehm Вы правы, не видели обращения к readdir. – KeylorSanchez

Смежные вопросы