バグ:フォルダの削除

Posted: 2012年09月11日

フォルダを削除する際によく書いてしまうバグを紹介します。

プログラムプログラム:

 #include  <stdio.h>
 #include  <Windows.h>

 int main(int argc, char *argv[])
 {
    char *pszDirPath = _T("C:\aaa\bbb\ccc");

    // 処理

    // フォルダの削除
    if( ::RemoveDirectory(pszDirPath) == 0 ) {
        return -1;
    }

    return 0;
 }

このプログラムにどのようなフォルダ削除関連のバグがあると思いますか?

  • フォルダの中にファイルが存在する場合は、エラーになる
  • すでに削除されている場合は、エラーになる
  • フォルダが読み取り専用の場合は、エラーになる

改善版プログラム改善版プログラム:

 #include  <stdio.h>
 #include  <Windows.h>

 BOOL RemoveDirectoryEX(LPCTSTR lpszFolderPath, BOOL bRecursive)
 {
    // ディレクトリ内のファイル走査用のファイル名作成
    TCHAR szFindFilePathName[MAX_PATH];
    strncpy( szFindFilePathName, lpszFolderPath, MAX_PATH );
    strncat_s( szFindFilePathName, _T("*"), MAX_PATH );

    if (bRecursive == TRUE) {
        WIN32_FIND_DATA lpFindData;
        HANDLE hFindFile = ::FindFirstFile(szFindFilePathName, &lpFindData);

        do {
            bool bDirectory = (lpFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;
            // 読み取り専用を外す
            SetFileAttributes(lpFindData.cFileName, GetFileAttributes(lpFindData.cFileName) & ~FILE_ATTRIBUTE_READONLY);

            if(bDirectory == true) {
                if (strcmp(lpFindData.cFileName, _T("..")) == 0
                    && strcmp(lpFindData.cFileName, _T(".")) == 0) {
                    continue;
                }
                //子ディレクトリの削除を行う
                RemoveDirectoryEX(lpFindData.cFileName, bRecursive);
            }
            if(bDirectory == false) {
                // ファイルの削除
                ::DeleteFile(lpFindData.cFileName);
            }
        } while(::FindNextFile(hFindFile, &lpFindData));

        ::FindClose(hFindFile);
    }
    // 自身のフォルダを削除
    ::RemoveDirectory(lpszFolderPath);
 }

 int main(int argc, char *argv[])
 {
    char *pszDirPath = _T("C:\aaa\bbb\ccc");
    // 処理

    if (::PathIsDirectory(pszDirPath) == TRUE)
        // フォルダの作成
        if( RemoveDirectoryEX(pszDirPath, TRUE) == TRUE ) {
            return -1;
        }
    }

    return 0;
 }

解説解説:

PathIsDirectoryでフォルダの存在チェックを行なっています。
その他の存在チェックの確認方法もありますが
Win32 Apiを用いたプログラムのためこのメソッドを採用いたしました。

SetFileAttributes、GetFileAttributesで
特定のファイルの属性値を取得し、取得した属性から読み取り専用を削除しています。

FindFirstFileで指定条件のパスに一致するファイルを取得します。
今回は「C:\\aaa\\bbb\\ccc\\*」つまり「ccc」フォルダの中のファイル、フォルダ全てを取得
取得方法は、FindNextFileで次のファイルを取得しFALSEが返却された時にすべてのファイルを取得したことになります。
ループ内では、フォルダの場合は、再度今回用意したRemoveDirectoryEXを呼び出します。
ファイルの場合は、ファイルの削除を行います。

最後にFindCloseでFindFirstFileの終了処理を行い
RemoveDirectoryで指定されたフォルダの削除を行います。

カテゴリー: バグ, プログラム | タグ: , , | コメント無し »

コメント