C opendir () не открывает каталог? - PullRequest
0 голосов
/ 28 апреля 2018

Я не настолько опытен в C, но у меня есть задание в одном из моих классов, и у меня есть несколько проблем при открытии каталога.

Цель программы (перефразировать):

  1. Если флаг или каталог не указан, перечислите имена файлов в текущем каталоге.
  2. Если указан флаг (-l), укажите дополнительную информацию о каждом файле.
  3. Если указан флаг и каталог, перейдите в этот каталог и перечислите информацию о каждом файле (или каталоге) в этом каталоге. Нет необходимости проходить через подкаталоги.

Не нужно обрабатывать получение только каталога, но без флага или неверного каталога. Это больше подтверждение концепции.

Мне удалось удовлетворить части 1 и 2, но часть 3 продолжает ломаться, вызывая ошибку сегментации.

Мой код выглядит следующим образом:

void recursedirect(char* flag, char* directory)
{
    DIR* dir;
    struct dirent *entry;

    printf("Flag: %s\nDirectory: %s\n\n", flag, directory);

    if (flag == NULL)
    // No flag provided, therefore only do file names.
    {
        dir = opendir(".");
        entry = readdir(dir);

        while (entry != NULL) 
        {
            printf ("%s\n", entry->d_name);
            entry = readdir(dir);
        }
    }
    else if (strcmp(flag, "-l") == 0 && directory == NULL)
    // No directory provided, but flag provided
    {
        dir = opendir(".");
        entry = readdir(dir);

        while (entry != NULL) 
        {
            fileinfo(directory);
            entry = readdir(dir);
        }   
    }
    else if (strcmp(flag, "-l") != 0)
    {
        printf("Invalid flag.\n");
    }
    else
    // A directory is provided
    {
        dir = opendir(directory);

        if (dir != NULL)
        {
            entry = readdir(dir);

            while (entry != NULL) 
            {
                fileinfo(directory);
                entry = readdir(dir);
            }   
        }
        else
            printf("Something went wrong. It might be an invalid filename.\n");
    }
}

В частности, утверждение else в конце доставляет мне неприятности. Я пытался дать ему любые пути к файлам, которые я могу придумать, жестко закодированные и другие, и это все еще вызывает у меня проблемы Я предполагаю, что это что-то простое, но у меня недостаточно опыта, чтобы понять, что это такое.

fileinfo - это функция, которая распечатывает информацию о файле, указав DIR и dirent в качестве аргументов. Тем не менее, ошибка определенно не в том коде, что я могу сказать.

РЕДАКТИРОВАТЬ: Я сделал ошибку, не разделяя все. Мой основной метод довольно прост.

int main (int argc, char** argv)
{
    char* flag = argv[1];
    char* directory = argv[2];

    recursedirect(flag, directory);
}//main

Включает в себя следующее:

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

И функция fileinfo выглядит следующим образом (немного отредактировано, как я понял, мне больше не нужно указывать аргумент DIR *dir):

void fileinfo(struct dirent *entry)
{
    struct stat fileStats;
    stat(entry->d_name, &fileStats);

    printf("File Name: %s\n", entry->d_name);
    printf("File Size: %d bytes\n", (int) fileStats.st_size);
    printf("Number of Blocks: %d\n", (int) fileStats.st_blocks);
    printf("Number of Links/References: %d\n", (int) fileStats.st_nlink);
    printf("I-Node: %d\n", (int) fileStats.st_ino);
    printf("Device ID: %d\n", (int) fileStats.st_dev);
    printf("User ID: %d\n", (int) fileStats.st_uid);
    printf("Group ID: %d\n", (int) fileStats.st_gid);

    stat("alphabet",&fileStats);
    printf("Time of Last Access: %s", ctime(&fileStats.st_atime));
    printf("Time of Last Modification: %s", ctime(&fileStats.st_mtime));
    printf("Time of Last Status Change: %s", ctime(&fileStats.st_ctime));

    stat(entry->d_name, &fileStats);
    printf("File Permissions: ");
    printf((int) (S_ISDIR(fileStats.st_mode)) ? "d" : "-");
    printf((int) (fileStats.st_mode & S_IRUSR) ? "r" : "-");
    printf((int) (fileStats.st_mode & S_IWUSR) ? "w" : "-");
    printf((int) (fileStats.st_mode & S_IXUSR) ? "x" : "-");
    printf((int) (fileStats.st_mode & S_IRGRP) ? "r" : "-");
    printf((int) (fileStats.st_mode & S_IWGRP) ? "w" : "-");
    printf((int) (fileStats.st_mode & S_IXGRP) ? "x" : "-");
    printf((int) (fileStats.st_mode & S_IROTH) ? "r" : "-");
    printf((int) (fileStats.st_mode & S_IWOTH) ? "w" : "-");
    printf((int) (fileStats.st_mode & S_IXOTH) ? "x\n\n" : "-\n\n");
}

Что касается дополнительных разъяснений по ошибочным входам, ./files и ./files -l оба работают. ./files с любым недопустимым флагом перехватывается как задумано. Однако ./files -l *any valid filepath* постоянно завершается ошибкой.

Все компилируется с использованием gcc в Ubuntu 14.04.5 в IDE c9.io.

Спасибо!

РЕДАКТИРОВАТЬ 2: я пытался удалить и вернуть файл, и теперь странно, я не получаю ошибку. Тем не менее, теперь он не будет печатать полную информацию о файле для чего-либо. Я исправлю еще.

РЕДАКТИРОВАТЬ 3: я исправил это с одним исключением. Проблема была неправильной, если оператор проверял флаг. Видимо что-то пошло не так в IDE. Теперь я получаю эту ошибку: Couldn't open MANPATH=/home/ubuntu/.nvm/versions/node/v6.11.2/share/man:/usr/local/rvm/rubies/ruby-2.4.0/share/man:/usr/local/man:/usr/local/share/man:/usr/share/man:/usr/local/rvm/man

Похоже, что это не код и в некотором роде проблема с сервером c9. Я попытался предоставить полные права как для исходного кода, так и для файлов скомпилированного кода, перезапустить рабочую область и перезапустить Apache2. Спасибо всем за все!

1 Ответ

0 голосов
/ 28 апреля 2018

В дополнение к комментариям, оставленным chux , вы можете воспользоваться реструктуризацией своего кода для повторного использования похожих блоков. Вы упоминаете, что вы решили части 1 и 2 (представлены первыми двумя ветвями в ваших утверждениях if). Итак, теоретически следующее, если блоки выдают правильный вывод. Если вы упростите его, чтобы код переписывался меньше, вы можете воспользоваться.

if (flag == NULL)
// No flag provided, therefore only do file names.
{
    dir = opendir(".");
    entry = readdir(dir);

    while (entry != NULL) 
    {
        printf ("%s\n", entry->d_name);
        entry = readdir(dir);
    }
}
else if (strcmp(flag, "-l") == 0 && directory == NULL)
// No directory provided, but flag provided
{
    dir = opendir(".");
    entry = readdir(dir);

    while (entry != NULL) 
    {
        fileinfo(directory);
        entry = readdir(dir);
    }   
}

Вместо того, чтобы писать таким образом, вы могли бы заранее проверить флаг и установить переменную (в этом случае more_file_info != 0 говорит нам напечатать, и мы return, если флаг недействителен).

int more_file_info = 0;
if (flag != NULL) {
    if(strcmp(flag, "-l") == 0) {
        more_file_info = 1;
    } else {
        printf("Invalid flag.\n");
        return;
    }
}

Затем вы можете упростить / реорганизовать приведенный выше (предположительно работающий) код следующим образом:

void recursedirect(char* flag, char* directory)
{
    DIR* dir;
    struct dirent *entry;
    int more_file_info = 0;

    printf("Flag: %s\nDirectory: %s\n\n", flag, directory);
    // Validate argument up front
    if (flag != NULL) {
        if(strcmp(flag, "-l") == 0) {
            more_file_info = 1;
        } else {
            printf("Invalid flag.\n");
            return;
        }
    }

    // The 'directory' parameter only changes opendir, so we reflect that here
    if(directory != NULL) {
        dir = opendir(directory);
    } else {
        dir = opendir(".");
    }
    // Adding some error checking, per comment
    if(dir == NULL) {
        printf("Couldn't open %s\n", directory);
        return;
    }
    // The readdir() loop is basically the same
    entry = readdir(dir);
    while (entry != NULL)
    {
        // Although we check a flag every time this loop runs,
        // it makes the code easier to follow
        if(more_file_info != 0) {
            printf ("%s\n", entry->d_name);
        } else {
            fileinfo(directory);
            // Or should this be:
            // fileinfo(entry);
        }
        entry = readdir(dir); 
    }
}

Это устраняет большое количество дублирующегося кода и, как мы надеемся, должно облегчить поиск и устранение неисправностей. Также обратите внимание, что это обрабатывает случай, когда указывается каталог, а флаг - нет, и вы можете явно проверить, требуется ли другое поведение. Надеемся, с более подробной информацией мы можем предоставить более подходящий ответ.

...