static int WINAPI DpdDeleteFile ( LPCWSTR pszPath, int ochName, DeletePathData & dpd, DWORD fdwVerbose, DWORD fdwFlags) { int err = 0; if (dpd.fNoDelete) { if (fdwVerbose) bprintf(*dpd.pbp, TEXT("NoDelete %s "), pszPath); return 0; } if (fdwVerbose) bprintf(*dpd.pbp, TEXT("Deleting %s "), pszPath); if (DeleteFileW(pszPath)) { dpd.cFilesDeleted += 1; } else { err = GetLastError(); if ((ERROR_ACCESS_DENIED == err) && (fdwFlags & DPD_F_REMOVEDACLS)) { if ( ! dpd.fDirAlreadyTriedDACLRemove && (ochName > 1)) { LPWSTR pszParent = strdupW(pszPath); pszParent[ochName-1] = 0; //StrCopyN(szParent, NUMCHARS(szParent), pszPath, ochName); int errT = RemoveFileDACLs(pszParent, dpd.fDiagnostic, dpd.pbp); if (errT) err = errT; else if (DeleteFileW(pszPath)) { err = 0; dpd.cFilesDeleted += 1; } else { err = GetLastError(); } // dont try to remove dacls again for this directory. dpd.fDirAlreadyTriedDACLRemove = true; free(pszParent); } // the error _may_ have been cleared by the time we get here, if it hasn't // then try and remove dacls from the file, then try again to delete the file. // if (ERROR_ACCESS_DENIED == err) { int errT = RemoveFileDACLs(pszPath, dpd.fDiagnostic, dpd.pbp); if (errT) err = errT; else if (DeleteFileW(pszPath)) { err = 0; dpd.cFilesDeleted += 1; } else { err = GetLastError(); } } } if (err) { dpd.cDeleteFailures += 1; if (fdwVerbose) { bprint_Sep(*dpd.pbp, ' '); bprint_AppendErrorText(*dpd.pbp, err); } } } return err; }
static bool WINAPI DeletePathCallback ( VOID * pvUser, LPCWSTR pszPath, // path and filename, may be absolute or relative. int ochName, // offset from start of pszPath to first char of the file/dir name. DWORD fdwFlags, int cDepth, int ixItem, const WIN32_FIND_DATAW & wfd) { DeletePathData & dpd = *(DeletePathData*)pvUser; if (dpd.fAborting) return false; BPRINT_BUFFER & bp = *dpd.pbp; const bool fDirectory = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; const bool fProtected = (wfd.dwFileAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)) != 0; dpd.cTotalVisited += 1; if (fDirectory) dpd.cDirsVisited += 1; else dpd.cFilesVisited += 1; dpd.cLastDepth = cDepth; dpd.cMaxDepth = max(cDepth, dpd.cMaxDepth); if (fProtected) { // build attributes flags that don't contain readonly or system (or hidden) DWORD fdwAttr = wfd.dwFileAttributes & (FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY); if ((fdwFlags & TDT_DIAGNOSTIC) || dpd.fDiagnostic) bprintfl(*dpd.pbp, TEXT("Clearing%s%s attrib(s) from %s"), (wfd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? TEXT(" SYS") : TEXT(""), (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? TEXT(" RO") : TEXT(""), pszPath); if ( ! SetFileAttributesW(pszPath, fdwAttr)) { int err = GetLastError(); if (ERROR_ACCESS_DENIED == err) { int errT = RemoveFileDACLs(pszPath, dpd.fDiagnostic, dpd.pbp); if (errT) err = errT; else if (SetFileAttributesW(pszPath, fdwAttr)) err = 0; else err = GetLastError(); } } } if (fdwFlags & TDT_FIRST) dpd.fDirAlreadyTriedDACLRemove = false; bprint_EndLine(bp); int err = ERROR_SUCCESS; if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // When we get the DIRLAST callback, it should be after we have deleted all of the children. // NOW we can try and remove the directory. // if (fdwFlags & TDT_DIRLAST) { err = DpdRemoveDirectory(pszPath, ochName, dpd, dpd.fDiagnostic, DPD_F_REMOVEDACLS); } } else { err = DpdDeleteFile(pszPath, ochName, dpd, dpd.fDiagnostic, DPD_F_REMOVEDACLS); } if (err && ! (fdwFlags & TDT_CONTINUE)) { bprint_EndLine(bp); if (dpd.fDiagnostic) bprintl(bp, "Aborting."); dpd.fAborting = true; return false; } bprint_EndLine(bp); return true; }
int TraverseDirectoryTreeW ( LPCWSTR pszPath, LPCWSTR pszPattern, DWORD fdwFlags, PFNTraverseDirectoryTreeCallbackW 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 = lstrlenW(pszPath); int cchMax = cchPath + MAX_PATH + 2; LPWSTR psz = (LPWSTR)malloc(cchMax * sizeof(WCHAR)); lstrcpyW(psz, pszPath); LPWSTR pszNext = psz + lstrlenW(psz); bool fMatchAll = false; if (pszPattern && pszPattern[0]) { if (0 == lstrcmpW(pszPattern, L"*.*") || 0 == lstrcmpW(pszPattern, L"*")) { fMatchAll = true; } pszNext = PathAddBackslashW(psz); lstrcpyW(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_DATAW wfd; HANDLE hFind = FindFirstFileW(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 = FindFirstFileW(psz, &wfd); if (INVALID_HANDLE_VALUE == hFind) { errT = GetLastError(); if (errT != err) ReportErrorW(errT, "FindFirstFile ", psz); } else { err = 0; } } } if (err) ReportErrorW(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) { lstrcpyW(pszNext, wfd.cFileName); if ( ! pfnCallback(pvUser, psz, pszNext - psz, (fdwFlags & ~(TDT_DIRLAST | TDT_DIRFIRST)) | dwFirst, nCurrentDepth, ixCurrentItem, wfd)) break; dwFirst = 0; } } while (FindNextFileW(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); lstrcpyW(pszNext, L"*"); hFind = FindFirstFileW(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 (FindNextFileW(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; lstrcpyW(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 = TraverseDirectoryTreeW(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; }
static int WINAPI DpdRemoveDirectory ( LPCTSTR pszPath, int ochName, DeletePathData & dpd, DWORD fdwVerbose, DWORD fdwFlags) { int err = 0; if (dpd.fNoDelete) { if (fdwVerbose) bprintf(*dpd.pbp, TEXT("NoRemove %s "), pszPath); return 0; } if (fdwVerbose) bprintf(*dpd.pbp, TEXT("Removing %s "), pszPath); if (RemoveDirectory(pszPath)) { dpd.cDirsRemoved += 1; } else { err = GetLastError(); if ((ERROR_ACCESS_DENIED == err) && (fdwFlags & DPD_F_REMOVEDACLS)) { if ( ! dpd.fDirAlreadyTriedDACLRemove && (ochName > 1)) { TCHAR szParent[MAX_PATH]; StrCopyN(szParent, NUMCHARS(szParent), pszPath, ochName); int errT = RemoveFileDACLs(szParent, fdwVerbose & (TDT_DIAGNOSTIC | TDT_USER_F_VERBOSE), dpd.pbp); if (errT) err = errT; else if (RemoveDirectory(pszPath)) { err = 0; dpd.cDirsRemoved += 1; } else { err = GetLastError(); } // dont try to remove dacls again for this directory. dpd.fDirAlreadyTriedDACLRemove = true; } // the error _may_ have been cleared by the time we get here, if it hasn't // then try and remove dacls from the file, then try again to delete the file. // if (ERROR_ACCESS_DENIED == err) { int errT = RemoveFileDACLs(pszPath, fdwVerbose & (TDT_DIAGNOSTIC | TDT_USER_F_VERBOSE), dpd.pbp); if (errT) err = errT; else if (RemoveDirectory(pszPath)) { err = 0; dpd.cDirsRemoved += 1; } else { err = GetLastError(); } } } if (err) { dpd.cRemoveFailures += 1; if (fdwVerbose) { bprint_Sep(*dpd.pbp, ' '); bprint_AppendErrorText(*dpd.pbp, err); } } } return err; }