bool HashDirectoryTree(const char *path, const char **extensions_filter, EVP_MD_CTX *crypto_context) { HashDirectoryTreeState state; memset(state.buffer, 0, 1024); state.extensions_filter = extensions_filter; state.crypto_context = crypto_context; return TraverseDirectoryTree(path, HashDirectoryTreeCallback, &state); }
int TraverseDirectoryTree ( LPCTSTR pszPath, LPCTSTR pszPattern, DWORD fdwFlags, PFNTraverseDirectoryTreeCallback pfnCallback, LPVOID pvUser, int nCurrentDepth) { bool fSubdirs = (fdwFlags & TDT_SUBDIRS) != 0; bool fDiagnostic = (fdwFlags & TDT_DIAGNOSTIC) != 0; //bool fDirFirst = (fdwFlags & TDT_DIRFIRST) != 0; //bool fDirLast = (fdwFlags & TDT_DIRLAST) != 0; if (fDiagnostic) { if (pszPattern) bprintfl(*g_pbpDiag, "TDT[%d]: %04x path = '%s' pattern = '%s' subdirs = %d", nCurrentDepth, fdwFlags, pszPath, pszPattern, fSubdirs); else bprintfl(*g_pbpDiag, "TDT[%d]: %04x path = '%s' pattern = NULL subdirs = %d", nCurrentDepth, fdwFlags, pszPath, fSubdirs); } // build a string containing path\pattern, we will pass this // into FindFirstFile. there are some special cases. // we treat paths that end in \ as meaning path\*. // we replace *.* with * since it means the same thing and // is easier to parse. (this is a special case go back to DOS). // int cchPath = lstrlen(pszPath); int cchMax = cchPath + MAX_PATH + 2; LPTSTR psz = (LPTSTR)malloc(cchMax * sizeof(TCHAR)); lstrcpy(psz, pszPath); LPTSTR pszNext = psz + lstrlen(psz); bool fMatchAll = false; if (pszPattern && pszPattern[0]) { if (0 == lstrcmp(pszPattern, TEXT("*.*")) || 0 == lstrcmp(pszPattern, TEXT("*"))) { fMatchAll = true; } pszNext = PathAddBackslash(psz); lstrcpy(pszNext, pszPattern); } else if (pszNext > psz && (pszNext[-1] == '\\' || pszNext[-1] == '/')) { fMatchAll = true; pszNext[0] = '*'; pszNext[1] = 0; } HRESULT hr = S_OK; int err = ERROR_SUCCESS; int ixCurrentItem = 0; DWORD dwFirst = TDT_FIRST; LinkedFindData * pdirs = NULL; WIN32_FIND_DATA wfd; HANDLE hFind = FindFirstFile(psz, &wfd); if (INVALID_HANDLE_VALUE == hFind) { err = GetLastError(); // if we can't open the directory because of an access denied error // it might be the DACLs that are causing the problem. If so, then // just remove the dacls. we are going to be deleting the directory // anway... // if (ERROR_ACCESS_DENIED == err) { int errT = RemoveFileDACLs(pszPath, fdwFlags & TDT_DIAGNOSTIC, g_pbpDiag); if (errT) err = errT; else { hFind = FindFirstFile(psz, &wfd); if (INVALID_HANDLE_VALUE == hFind) { errT = GetLastError(); if (errT != err) ReportError(errT, "FindFirstFile ", psz); } else { err = 0; } } } if (err) ReportError(err, "FindFirstFile ", psz); } if (hFind && INVALID_HANDLE_VALUE != hFind) { do { // ignore . and .. if (IsDotOrDotDot(wfd.cFileName)) continue; ++ixCurrentItem; bool fSkip = false; if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // if we are recursing, and we happen to be matching all, then remember this // directory for later (so we don't need to enumerate again for dirs). // otherwise we will have to re-enumerate in this directory to get subdirs. if (fSubdirs && fMatchAll) { LinkedFindData * pdir = (LinkedFindData*)malloc(sizeof(LinkedFindData)); pdir->wfd = wfd; pdir->next = pdirs; pdirs = pdir; fSkip = true; // we will do the callback for this directory later, if at all. } else if (fdwFlags & TDT_NODIRS) fSkip = true; } else { if (fdwFlags & TDT_NOFILES) fSkip = true; } if (fDiagnostic) bprintfl (*g_pbpDiag, "TDT[%d]: 0x%08x %s %s", nCurrentDepth, wfd.dwFileAttributes, wfd.cFileName, fSkip ? "<skip>" : ""); if ( ! fSkip) { lstrcpy(pszNext, wfd.cFileName); if ( ! pfnCallback(pvUser, psz, pszNext - psz, (fdwFlags & ~(TDT_DIRLAST | TDT_DIRFIRST)) | dwFirst, nCurrentDepth, ixCurrentItem, wfd)) break; dwFirst = 0; } } while (FindNextFile(hFind, &wfd)); if (fDiagnostic) bprintfl (*g_pbpDiag, "TDT[%d]: Done with %s %s", nCurrentDepth, pszPath, pszPattern); } // we want to traverse subdirs, but we were unable to build a list of dirs when we // enumerated the files, so re-enumerate with * to get the directories. if (fSubdirs && ! fMatchAll) { if (hFind && INVALID_HANDLE_VALUE != hFind) FindClose(hFind); lstrcpy(pszNext, TEXT("*")); hFind = FindFirstFile(psz, &wfd); if (INVALID_HANDLE_VALUE != hFind) { do { if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && ! IsDotOrDotDot(wfd.cFileName)) { LinkedFindData * pdir = (LinkedFindData*)malloc(sizeof(LinkedFindData)); pdir->wfd = wfd; pdir->next = pdirs; pdirs = pdir; } } while (FindNextFile(hFind, &wfd)); } } err = GetLastError(); if (ERROR_NO_MORE_FILES == err) err = ERROR_SUCCESS; // now traverse and callback subdirectories. // if (fSubdirs && pdirs) { pdirs = ReverseLinkedList(pdirs); while (pdirs) { LinkedFindData * pdir = pdirs; pdirs = pdirs->next; lstrcpy(pszNext, pdir->wfd.cFileName); if ((fdwFlags & TDT_DIRFIRST) && ! (fdwFlags & TDT_NODIRS)) { if (fDiagnostic) bprintfl (*g_pbpDiag, "TDT[%d]: DIRFIRST 0x%08x %s %s", nCurrentDepth, pszPath, pszPattern); if ( ! pfnCallback(pvUser, psz, pszNext - psz, TDT_DIRFIRST | (fdwFlags & ~TDT_DIRLAST) | dwFirst, nCurrentDepth, ixCurrentItem, pdir->wfd)) break; dwFirst = 0; } err = TraverseDirectoryTree(psz, pszPattern, fdwFlags, pfnCallback, pvUser, nCurrentDepth+1); if ((fdwFlags & TDT_DIRLAST) && ! (fdwFlags & TDT_NODIRS)) { if (fDiagnostic) bprintfl (*g_pbpDiag, "TDT[%d]: DIRLAST 0x%08x %s %s", nCurrentDepth, pszPath, pszPattern); if ( ! pfnCallback(pvUser, psz, pszNext - psz, TDT_DIRLAST | (fdwFlags & ~TDT_DIRFIRST) | dwFirst, nCurrentDepth, ixCurrentItem, pdir->wfd)) break; dwFirst = 0; } } } if (hFind && INVALID_HANDLE_VALUE != hFind) FindClose(hFind); return err; }
int DeletePath(LPCTSTR pszPathIn, LPCTSTR pszPattern, DWORD fdwTraverse, DWORD fdwSecurity, DWORD fdwVerbose, BPRINT_BUFFER & bp) { DWORD fdwFlags = fdwTraverse & (TDT_INPUTMASK & ~TDT_USERMASK); if (fdwVerbose & DP_V_VERBOSE) fdwFlags |= TDT_USER_F_VERBOSE; if (fdwVerbose & DP_V_DIAGNOSTIC) fdwFlags |= TDT_DIAGNOSTIC; bool fQuiet = (fdwVerbose & DP_V_QUIET) != 0; DeletePathData lad; ZeroStruct(&lad); lad.pbp = &bp; if (fdwSecurity & DP_S_NODELETE) lad.fNoDelete = true; fdwFlags |= TDT_DIRLAST; // So we get directory callbacks after children have been deleted. // if the path isn't too long, convert to canonical form. for long paths // they has better provide canonical form to begin with. // TCHAR szCanonPath[MAX_PATH+1]; LPCTSTR pszPath = pszPathIn; if (lstrlen(pszPathIn) < MAX_PATH && PathCanonicalize(szCanonPath, pszPathIn)) { pszPath = szCanonPath; } // the unicode versions of the windows file api's can handle very long // path names if they are canonical and if they are preceeded by \\?\. // if we are build unicode, take advantage of that capability. #ifdef UNICODE static const TCHAR szPre[]= TEXT("\\\\?\\"); TCHAR szFullPath[MAX_PATH + NUMCHARS(szPre)]; TCHAR * pszFullPath = szFullPath; TCHAR * pszFilePart = NULL; lstrcpy(szFullPath, szPre); UINT cchFullPath = GetFullPathName(pszPath, MAX_PATH, szFullPath + NUMCHARS(szPre)-1, &pszFilePart); if (cchFullPath >= NUMCHARS(szFullPath)-1) { pszFullPath = (TCHAR *)LocalAlloc(LPTR, (cchFullPath + NUMCHARS(szPre) + 2) * sizeof(TCHAR)); if (pszFullPath) { lstrcpy(pszFullPath, szPre); if (GetFullPathName(pszPath, cchFullPath+2, pszFullPath + NUMCHARS(szPre)-1, &pszFilePart) <= cchFullPath+2) pszPath = pszFullPath; } } else pszPath = szFullPath; #endif int err = 0; DWORD fdwFileAttributes = GetFileAttributes(pszPath); if (INVALID_FILE_ATTRIBUTES == fdwFileAttributes) { fdwFileAttributes = 0; err = GetLastError(); ReportError(err, "Could not get attributes for ", pszPath); return err; } const bool fIsDir = (fdwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; if (fdwFlags & TDT_DIAGNOSTIC) bprintfl(bp, TEXT("Delete %s 0x%04X %s\\%s"), fIsDir ? TEXT("Directory") : TEXT("File"), fdwFlags, pszPath, pszPattern); if (fIsDir) { if (fdwTraverse & TDT_SUBDIRS) { if ( ! pszPattern || ! pszPattern[0]) err = TraverseDirectoryTree(pszPath, TEXT("*"), fdwFlags, DeletePathCallback, &lad, 0); else err = TraverseDirectoryTree(pszPath, pszPattern, fdwFlags, DeletePathCallback, &lad, 0); } if ( ! err || (fdwFlags & TDT_CONTINUE)) { bprint_EndLine(bp); if ( ! (fdwTraverse & TDT_NODIRS) && (!pszPattern || !pszPattern[0])) { if ( ! fQuiet) { bprint(bp, lad.fNoDelete ? TEXT("NoRemove ") : TEXT("Removing ")); bprint(bp, pszPath); } if ( ! lad.fNoDelete && ! RemoveDirectory(pszPath)) { bprint_EndLine(bp); err = GetLastError(); ReportError(err, "RemoveDirectory", pszPath); if ( ! (fdwFlags & TDT_CONTINUE)) if ( ! fQuiet) bprintl(bp, "Aborting."); } } } } else // initial path is a file, not a directory. { if (fdwTraverse & TDT_SUBDIRS) { if ( ! pszPattern || ! pszPattern[0]) { err = TraverseDirectoryTree(pszPath, TEXT("*"), fdwFlags, DeletePathCallback, &lad, 0); } else { //#pragma REMIND("TJ: add code to split the file from the path and recurse on the filename.") } } if (fdwTraverse & TDT_NOFILES) { // Nothing to do. } else if ( ! pszPattern || ! pszPattern[0]) { if ( ! fQuiet) { bprint(bp, lad.fNoDelete ? TEXT("NoDelete ") : TEXT("Deleting ")); bprint(bp, pszPath); } if ( ! lad.fNoDelete && ! DeleteFile(pszPath)) { bprint_EndLine(bp); err = GetLastError(); ReportError(err, "DeleteFile", pszPath); if ( ! (fdwFlags & TDT_CONTINUE)) if ( ! fQuiet) bprintl(bp, "Aborting."); } } } bprint_EndLine(bp); return err; }