0
  • プラットフォーム:Windows XP Service Pack 3
  • コンパイラ:Code::Blocksバージョン12.11

私は現在、POSIXディレクトリ関数を使用して特定のディレクトリを再帰的に削除するプログラムを作成しています。しかし、readdir()とそれに対応するdirent構造に問題があります。readdirのドキュメントを読みました関数を複数回呼び出すと、関数によって返される構造体に保持されているデータが上書きされます。したがって、readdir()は構造体自体のメモリを割り当ててから、戻り値をキャプチャする構造体にポインタアドレスを再割り当てする必要があると思いました。私はこの理論をテストし、そのメンバーd_nameに正しいreaddir()割り当てメモリを使用しました。私が抱えている問題は、ディレクトリストリームが空の場合、readdirがNULLポインタを返すことです。そのため、条件(dirent_ptr!= NULL)を指定したwhileループを使用して、ディレクトリ全体を反復処理します。しかし、readdir()は構造体のメモリ割り当てを処理するので、私は単に異なる構造体を宣言し、readdir()にその仕事をさせます。なんらかの理由で不規則にdirent構造体がNULLに初期化される(またはそれが私のコンパイラーである可能性があります)ので、ループが開始されないのは ■条件文は最初は真ではありません。だから私の質問は私がここで何を間違っているのかということだと思いますか?

重要な変数宣言と含まれているライブラリは次のとおりです。これらの変数はすべてグローバルに宣言されていることに注意してください。

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>

int recursive_delete(const char *path);
int file_delete(const char *path, int file_size);

struct dirent *direntp;
struct stat *statp;

struct switches
{
    int verbose;
    int no_prompt;
    int continue_if_error;
    int files_only;
}; struct switches switches;

相対パスを解決するのではなく、引数として指定されたパスにcdしてから、を使用します。および..移動するワイルドカードは、相対パス(d_names)が有効になるようにディレクトリをスローしました。また、スイッチの構造にはコマンドラインスイッチが含まれているだけなので無視する必要があります。次のコードのエラーを認識していますが、上記の問題を乗り越えることができないため、残念ながら修正できません。

int recursive_delete(const char *path)
{
    DIR *dirp;
    int return_value = 0;
    int recursive_return_value = 0;

    if((chdir(path)) == -1)
    {
        perror("ERROR(3)");
        return 1;
    }
    printf("CDED to \"%s\"\n", path);

    dirp = opendir(".");
    if(dirp == NULL)
    {
        perror("ERROR(4)");
        return 1;
    }
    printf("OPENED \"%s\"\n", path);

    while(direntp != NULL)
    {
        direntp = readdir(dirp);
        if( (direntp == NULL) && (errno != 0) )
        {
            perror("ERROR(5)");
            return 1;
        }
        printf("READ \"%s\" FROM \"%s\"\n", direntp->d_name, path);

        if( (strcmp(direntp->d_name, ".")!=0) && (strcmp(direntp->d_name, "..")!=0) )
        {
            if((stat(direntp->d_name, statp)) == -1)
            {
                perror("ERROR(6)");
                return 1;
            }
            printf("STATED \"%s\"\n", direntp->d_name);

            if(S_ISREG(statp->st_mode))
            {
                printf("DELETING \"...\\%s\\%s\"\n", path, direntp->d_name);
                return_value += file_delete(direntp->d_name, statp->st_size);
                if( (!switches.continue_if_error) && (return_value != 0) )
                {
                    break;
                }
            }
            else if(S_ISDIR(statp->st_mode))
            {
                printf("\n\n\nCALLING RECURSIVE DELETE with \"%s\"\n", direntp->d_name);
                recursive_return_value = recursive_delete(direntp->d_name);
                return_value += recursive_return_value;

                if( (!switches.continue_if_error) && (recursive_return_value != 0) )
                {
                    break;
                }

                if( (!switches.files_only) && (recursive_return_value == 0) )
                {
                    if((chdir("..")) == -1)
                    {
                        perror("ERROR(6)");
                        return 1;
                    }
                    printf("CDED BACK TO \"%s\" FROM \"%s\"\n", path, direntp->d_name);

                    if((rmdir(direntp->d_name)) == -1)
                    {
                        perror("ERROR(7)");
                        return 1;
                    }

                    if(switches.verbose)
                    {
                        printf("DELETED DIRECTORY \"...\\%s\\\"\n\n\n", direntp->d_name);
                    }
                }
            }
        }
    }

    return return_value;
}
4

2 に答える 2

1

添付されたコードから、direntpがどこで初期化されているか(whileループの前)は明確ではありません。おそらく次のようなことを試してください:

direntp = readdir(dirp);
while(direntp != NULL)
{
    // all your work here

    direntp = readdir(dirp);
}

このパターンによりdirentp、whileループが初期化および更新されます。ただし、コードを一目見ただけでは、whileループが最初に何をしているのか正確にはわかりません。ループはどのように変化していますか direntpdirp

if(の代わりにwhile)テストを実行して、再帰呼び出しに「ループ」効果を処理させることができる可能性があります...

于 2013-03-26T22:01:12.180 に答える
1

コード構造は次のようになります(わかりやすくするためにほとんどのエラーチェックは省略されています)。

int recursive_delete(const char *path)
{
  DIR* dirp = NULL;
  int return_value = 0;
  char* initial_cur_dir = malloc(1000);

  getcwd(initial_cur_dir, 1000);
  chdir(path);
  dirp = opendir(".");

  while (dirp != NULL)
  {
    struct dirent* direntp;
    struct stat stat;

    direntp = readdir(dirp);

    if (direntp == NULL)
      break;

    stat(direntp->d_name, &stat);

    if (S_ISDIR(statp->st_mode))
    {
      if (strcmp(direntp->d_name, ".") && strcmp(direntp->d_name, ".."))
      {
        return_value += recursive_delete(direntp->d_name);
      }
    }
    else if (S_ISREG(statp->st_mode))
    {
      unlink(direntp->d_name);
    }
  }

  if (initial_cur_dir != NULL)
  {
    chdir(initial_cur_dir);
    rmdir(path);
  }

ErrorLabel: // you should goto here when an error is detected

  if (dirp != NULL)
  {
    closedir(dirp);
  }

  if (initial_cur_dir != NULL)
  {
    chdir(initial_cur_dir);
    free(initial_cur_dir);
  }

  return return_value;
}
于 2013-03-26T22:04:16.617 に答える