static HRESULT CALLBACK OpenList_Open ( POPENLIST_FILE polf, LPARAM lArgs) { HRESULT hr = S_OK; if (E_CANCEL != polf->hr) // Possible if a queue'd open was canceled on progman and we are being called for possible batch undo handling { hr = E_FILE_UNSUPPORTED; if (g_app.fDiagnostic) bprintfl("\nDeletePath \"%s\" recursive = %d", polf->szPathName, g_app.fSubDirs); DWORD fdwTraverse = 0; if (g_app.fSubDirs) fdwTraverse |= TDT_SUBDIRS; //if (g_app.fNoFiles) fdwTraverse |= TDT_NOFILES; //if (g_app.fNoDirs) fdwTraverse |= TDT_NODIRS; if (g_app.fContinue) fdwTraverse |= TDT_CONTINUE; if (g_app.fDiagnostic) fdwTraverse |= TDT_DIAGNOSTIC; DWORD fdwSecurity = 0; if (g_app.fNoDelete) fdwSecurity = DP_S_NODELETE; DWORD fdwVerbose = 0; if (g_app.fVerbose) fdwVerbose |= DP_V_VERBOSE; if (g_app.fDiagnostic) fdwVerbose |= DP_V_DIAGNOSTIC; if (g_app.fQuiet) fdwVerbose |= DP_V_QUIET; int err = DeletePath(polf->szPathName, TEXT(""), fdwTraverse, fdwSecurity, fdwVerbose, g_bprint); // DeletePath has already reported errors. /* if (err && ERROR_NO_MORE_FILES != err) { TCHAR szErr[MAX_PATH]; if (GetLastErrorText(err, szErr, NUMCHARS(szErr)) <= 0) wsprintf(szErr, TEXT("Error %d"), err); bprintfl ("%s\n", szErr); } */ if (g_app.fContinue) hr = S_OK; else if (err) hr = E_CANCEL; } return hr; }
int __cdecl main() { HRESULT hr = App_Early_Initialize(); if (SUCCEEDED(hr)) { hr = App_ExecuteCommandLine (GetCommandLine(), TRUE); if (FAILED(hr)) g_app.fUsage = TRUE; } if (g_app.fShowLogo || g_app.fUsage) { LPCTSTR pszAppName = _pszModuleName; bprintfl("%s version 1.0.0 Built " __DATE__ __TIME__, pszAppName); } if (g_app.fUsage) { LPCTSTR pszAppName = _pszModuleName; bprintf("\nusage: %s [/? | /HELP] [@{argfile}] [args] <dir>\n\n", pszAppName); bprintf(" remove directory <dir>, taking ownership and removing\n"); bprintf(" ACLs as necessary. Where [args] is one or more of\n\n"); for (int ii = 0; ii < NUMELMS(g_aAppCommands); ++ii) { CMDTABLE * pCmd = &g_aAppCommands[ii]; if ( ! pCmd->pszName) break; LPCTSTR pszCmd = pCmd->pszName; TCHAR szCmd[128]; if (pCmd->cmd.cParams > 0) { StrCopy(szCmd, pCmd->pszName, NUMCHARS(szCmd)); int cch = StrLen(szCmd); szCmd[cch++] = ':'; StrCopy(szCmd+cch, pCmd->pszArgType, NUMCHARS(szCmd)-cch); pszCmd = szCmd; } bprintf(" /%-16s", pszCmd); bprintf(" %s\n", pCmd->pszUsage); } } App_Cleanup(SUCCEEDED(hr)); return (int)hr; }
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; }
HRESULT App_CookArgList ( HCMDLIST * phlst, LPCTSTR aArgs[], UINT ixFirst, // first arg to execute UINT cArgs) // count of args to execute { HRESULT hr = S_FALSE; // there were no args... TCHAR szTempArg[64]; // temp if we need to copy and arg HCMDLIST hlst; *phlst = NULL; hr = Vector_Create(&hlst, cArgs, -1); if (FAILED(hr)) return hr; // look at args, parsing switches and building up the array of filename pointers // UINT ixLast = (ixFirst + cArgs); for (UINT ii = ixFirst; ii < ixLast; ++ii) { LPCTSTR pszArg = aArgs[ii]; if ( ! pszArg) break; // assume a file open command. // hr = S_OK; CMDSWITCH cmd = {APP_CMD_PATH, 0, 1, NULL}; // if the first character of the arg is an '@', what follows should be a command file. // if (pszArg[0] == '@') { // command will be an argfile command // cmd.idCmd = APP_CMD_ARGFILE; cmd.cParams = 1; // on arg needed cmd.pszParams = NULL; // no default // if next character is not a 0, it must be the filename // otherwise, suck up the next token and use it as the filename. // pszArg = StrCharNext (pszArg); // skip '@' if (0 != pszArg[0]) { cmd.pszParams = pszArg; } else if (ii+1 < ixLast) // next pszArg belongs to us.. { LPCTSTR pszT = aArgs[ii+1]; if ('-' != pszT[0] && '/' != pszT[0]) { cmd.pszParams = pszT; ++ii; // advance the loop counter. } } } else if ('-' == pszArg[0] || '/' == pszArg[0]) { pszArg = StrCharNext (pszArg); if (0 == pszArg[0]) { hr = E_INVALIDARG; goto bail; } // look for a ':' in the arg, and // LPCTSTR psz = StrCharNext(pszArg); LPCTSTR pszParam = NULL; while (0 != psz[0]) { // if the arg contains a colon, set pszParam to point to it // and extract the stuff before the colon as the actual arg. // if (':' == psz[0]) { pszParam = StrCharNext (psz); UINT cch = (UINT)(((LPARAM)psz - (LPARAM)pszArg) / NUMBYTES(TCHAR)); StrCopyN (szTempArg, NUMCHARS(szTempArg), pszArg, cch + 1); DASSERT(0 == szTempArg[min(NUMCHARS(szTempArg)-1, cch)]); pszArg = szTempArg; break; } psz = StrCharNext(psz); } // lookup the argment // if ( ! App_LookupCmdLineArg (g_aAppCommands, pszArg, &cmd)) { bprintfl("%s is not a valid argument", pszArg); hr = E_INVALIDARG; goto bail; } if (pszParam) { if (cmd.cParams < 1) { // if we have a param, but the arg doesn't take any, bail. // bprintfl("the %s argument is does not take parameters", pszArg); hr = E_INVALIDARG; goto bail; } cmd.pszParams = pszParam; } else { // if the command needs args, but none have been found so // far, try sucking up the next token in the command line // if (cmd.cParams > 0 && NULL == cmd.pszParams) { if (ii+1 < ixLast) // next pszArg belongs to us.. { LPCTSTR pszT = aArgs[ii+1]; if ('-' != pszT[0] && '/' != pszT[0]) { cmd.pszParams = pszT; ++ii; // advance the loop counter. } } } } } else { // not a switch, this is an implied file-open command // cmd.pszParams = pszArg; } // if the command needs an arg, but we dont have one. // the command line is in error. // if ((cmd.cParams > 0) && (NULL == cmd.pszParams)) { bprintfl("the %s argument requires parameters", pszArg); g_app.fUsage = true; hr = E_INVALIDARG; goto bail; } // append the command. // Vector_AppendItem(hlst, cmd); } // return the command list // *phlst = hlst; bail: if (FAILED(hr) || Vector_GetCountSafe(hlst) < 1) { *phlst = NULL; if (hlst) Vector_Delete (hlst); } return hr; }
int RemoveFileDACLs(LPCWSTR pszPath, BOOL fDiagnostic, BPRINT_BUFFER *pbp) { // // make sure that we have ESE_SECURITY priviledge // int err = 0; if ( ! AddLocalPrivilege(ESE_SECURITY)) { err = GetLastError(); if (fDiagnostic) ReportError(err, "AdjustTokenPrivileges"); } // setup globals, this do nothing if this is not the first time // this function was called. // InitStandardSids(fDiagnostic, pbp); //InitUserSid(fDiagnostic, pbp); InitOwnerSid(fDiagnostic, pbp); // // Attempt to put a NULL Dacl on the file/directory // SECURITY_DESCRIPTOR si; ZeroMemory(&si, sizeof(si)); InitializeSecurityDescriptor(&si, SECURITY_DESCRIPTOR_REVISION); MSC_SUPPRESS_WARNING(6248) // warning: setting the DACL to null will result in unprotected object... SetSecurityDescriptorDacl (&si, TRUE, NULL, FALSE); if ( ! SetFileSecurityW(pszPath, DACL_SECURITY_INFORMATION, &si)) { err = GetLastError(); if (fDiagnostic) ReportErrorW (err, "SetFileSecurity(DACL)[1] ", pszPath); } else { if (fDiagnostic) { if (bprint_IsEmpty(*pbp)) bprintfl(*pbp, "DACLs removed from %s", pszPath); else bprint(*pbp, " DACLs removed"); } return 0; } // // Attempt to make take ownership of the file. // SetSecurityDescriptorOwner (&si, ls.OwnerSid, FALSE); if (SetFileSecurityW(pszPath, OWNER_SECURITY_INFORMATION, &si)) err = 0; else { err = GetLastError(); if (fDiagnostic) ReportErrorW (err, "SetFileSecurity(Owner)[1] ", pszPath); //ZeroMemory(&si,sizeof(si)); //InitializeSecurityDescriptor(&si, SECURITY_DESCRIPTOR_REVISION); //SetSecurityDescriptorOwner (&si, ls.OwnerSid, FALSE); if ( ! AddLocalPrivilege(ESE_TAKE_OWNERSHIP)) { static bool fReportedSeTakeOwner = false; if (fDiagnostic && ! fReportedSeTakeOwner) { ReportErrorW(GetLastError(), "SeTakeOwnership ", pszPath); fReportedSeTakeOwner = true; } } else if ( ! SetFileSecurityW(pszPath, OWNER_SECURITY_INFORMATION, &si)) { err = GetLastError(); if (fDiagnostic) ReportErrorW (err, "SetFileSecurity(Owner)[2] ", pszPath); } else { err = 0; } } // if we successfully took ownership, try again to set a NULL DACL // if ( ! err) { if (fDiagnostic) { if (bprint_IsEmpty(*pbp)) bprintfl(*pbp, "Ownership taken of %s", pszPath); else bprint(*pbp, " Ownership taken"); } if ( ! SetFileSecurityW(pszPath, DACL_SECURITY_INFORMATION, &si)) { err = GetLastError(); if (fDiagnostic) ReportErrorW (err, "SetFileSecurity(DACL)[2] ", pszPath); } else { if (fDiagnostic) { if (bprint_IsEmpty(*pbp)) bprintfl(*pbp, "DACLs removed from %s", pszPath); else bprintfl(*pbp, " DACLs removed", pszPath); } return 0; } } return err; }
bool AddLocalPrivilege(int ePriv) { if (ePriv < 0 || ePriv >= NUMELMS(g_aPrivs)) { ASSERT(!"unsupported priv requested"); return false; } if ( ! ls.hToken) { if ( ! OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, TRUE, &ls.hToken)) { if (GetLastError() == ERROR_NO_TOKEN) { if ( ! OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &ls.hToken)) return false; } else return false; } } // have we queried this already? if (ls.aCurr[ePriv].Luid.LowPart || ls.aCurr[ePriv].Luid.HighPart) { return (ls.aCurr[ePriv].Attributes & SE_PRIVILEGE_ENABLED) != 0; } PLUID pluid = &g_aPrivs[ePriv].luid; if ( ! pluid->LowPart && ! pluid->HighPart && ! LookupPrivilegeValue(NULL, g_aPrivs[ePriv].psz, &g_aPrivs[ePriv].luid)) { return false; } TOKEN_PRIVILEGES tp = {1}; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; tp.Privileges[0].Luid = *pluid; TOKEN_PRIVILEGES tpOrig = {1}; tpOrig.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; tpOrig.Privileges[0].Luid = *pluid; // // enable or disable the privilege // DWORD cb = sizeof(tpOrig); if ( ! AdjustTokenPrivileges(ls.hToken, FALSE, &tp, cb, &tpOrig, &cb)) { bprintfl(*g_pbpDiag, " %d passed, %d needed", sizeof(tpOrig), cb); return false; } ls.aOrig[ePriv].Luid = tpOrig.Privileges[0].Luid; ls.aOrig[ePriv].Attributes = tpOrig.Privileges[0].Attributes; ls.aCurr[ePriv].Luid = tp.Privileges[0].Luid; ls.aCurr[ePriv].Attributes = tp.Privileges[0].Attributes; return true; }
static int RecursiveDeleteDirectory(LPCTSTR pszPathIn, DWORD fdwFlags) { BPRINT_BUFFER & bp = *g_pbpDiag; DeletePathData dpd; ZeroMemory(&dpd, sizeof(dpd)); dpd.pbp = &g_bpErr; //this is for traversal testing... //dpd.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) { if (PathCanonicalize(szCanonPath, pszPathIn)) pszPath = szCanonPath; if (PathIsRelative(pszPath)) return ERROR_INVALID_PARAMETER; } // 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. static const WCHAR szPre[]= L"\\\\?\\"; WCHAR szFullPath[MAX_PATH + NUMCHARS(szPre)]; WCHAR * pszFullPath = szFullPath; WCHAR * pszFilePart = NULL; lstrcpyW(szFullPath, szPre); MultiByteToWideChar(CP_ACP, 0, pszPath, -1, szFullPath + NUMCHARS(szPre)-1, MAX_PATH); /* UINT cchFullPath = GetFullPathNameW(pszPath, MAX_PATH, szFullPath + NUMCHARS(szPre)-1, &pszFilePart); if (cchFullPath >= NUMCHARS(szFullPath)-1) { pszFullPath = (TCHAR *)LocalAlloc(LPTR, (cchFullPath + NUMCHARS(szPre) + 2) * sizeof(WCHAR)); if (pszFullPath) { lstrcpyW(pszFullPath, szPre); if (GetFullPathNameW(pszPath, cchFullPath+2, pszFullPath + NUMCHARS(szPre)-1, &pszFilePart) <= cchFullPath+2) pszPath = pszFullPath; } } else pszPath = szFullPath; */ int err = 0; DWORD fdwFileAttributes = GetFileAttributesW(szFullPath); 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\\*"), fIsDir ? TEXT("Directory") : TEXT("File"), fdwFlags, pszPath); if (fIsDir) { err = TraverseDirectoryTreeW(szFullPath, L"*", fdwFlags, DeletePathCallback, &dpd, 0); if ( ! err || (fdwFlags & TDT_CONTINUE)) { bprint_EndLine(bp); if ( ! dpd.fNoDelete && ! RemoveDirectoryW(szFullPath)) { bprint_EndLine(bp); err = GetLastError(); ReportError(err, "RemoveDirectory", pszPath); } } } else // initial path is a file, not a directory. { if ( ! dpd.fNoDelete && ! DeleteFileW(szFullPath)) { bprint_EndLine(bp); err = GetLastError(); ReportError(err, "DeleteFile", pszPath); } } bprint_EndLine(bp); 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 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; }