diff options
author | elfmz <fenix1905@tut.by> | 2021-12-31 00:27:16 +0300 |
---|---|---|
committer | elfmz <fenix1905@tut.by> | 2021-12-31 02:27:02 +0300 |
commit | a14dc1a81c797928d4f1b7d6a6b46ecc63f98308 (patch) | |
tree | c27c61ac33582bc4d469c6608cd042add388f230 /far2l/src/delete.cpp | |
parent | d5f1bf245e96834d44390d1723cfef3dfbb1fb02 (diff) |
shuffle a bit far2l sources
Diffstat (limited to 'far2l/src/delete.cpp')
-rw-r--r-- | far2l/src/delete.cpp | 962 |
1 files changed, 962 insertions, 0 deletions
diff --git a/far2l/src/delete.cpp b/far2l/src/delete.cpp new file mode 100644 index 00000000..03e1db96 --- /dev/null +++ b/far2l/src/delete.cpp @@ -0,0 +1,962 @@ +/* +delete.cpp + +Удаление файлов +*/ +/* +Copyright (c) 1996 Eugene Roshal +Copyright (c) 2000 Far Group +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "headers.hpp" + + +#include "lang.hpp" +#include "panel.hpp" +#include "chgprior.hpp" +#include "filepanels.hpp" +#include "scantree.hpp" +#include "treelist.hpp" +#include "savescr.hpp" +#include "ctrlobj.hpp" +#include "filelist.hpp" +#include "manager.hpp" +#include "constitle.hpp" +#include "TPreRedrawFunc.hpp" +#include "cddrv.hpp" +#include "interf.hpp" +#include "keyboard.hpp" +#include "message.hpp" +#include "config.hpp" +#include "pathmix.hpp" +#include "dirmix.hpp" +#include "strmix.hpp" +#include "panelmix.hpp" +#include "mix.hpp" +#include "dirinfo.hpp" +#include "wakeful.hpp" +#include "execute.hpp" + +#if defined(__APPLE__) || defined(__FreeBSD__) + #include <errno.h> +#endif + +static void ShellDeleteMsg(const wchar_t *Name,int Wipe,int Percent); +static int ShellRemoveFile(const wchar_t *Name,int Wipe); +static int ERemoveDirectory(const wchar_t *Name,int Wipe); +static int RemoveToRecycleBin(const wchar_t *Name); +static int WipeFile(const wchar_t *Name); +static int WipeDirectory(const wchar_t *Name); +static void PR_ShellDeleteMsg(); + +static int ReadOnlyDeleteMode,SkipMode,SkipWipeMode,SkipFoldersMode,DeleteAllFolders; +ULONG ProcessedItems; + +ConsoleTitle *DeleteTitle=nullptr; + +enum {DELETE_SUCCESS,DELETE_YES,DELETE_SKIP,DELETE_CANCEL}; + +struct AskDeleteReadOnly +{ + AskDeleteReadOnly(const wchar_t *Name,int Wipe); + + ~AskDeleteReadOnly() + { + if (_ump) + _ump->Unmake(); + } + + inline int Choice() const + { + return _r; + } + + private: + IUnmakeWritablePtr _ump; + int _r; +}; + +void ShellDelete(Panel *SrcPanel,int Wipe) +{ + SudoClientRegion scr; + //todo ChangePriority ChPriority(Opt.DelThreadPriority); + TPreRedrawFuncGuard preRedrawFuncGuard(PR_ShellDeleteMsg); + FAR_FIND_DATA_EX FindData; + FARString strDeleteFilesMsg; + FARString strSelName; + FARString strDizName; + FARString strFullName; + DWORD FileAttr; + int SelCount,UpdateDiz; + int DizPresent; + int Ret; + BOOL NeedUpdate=TRUE, NeedSetUpADir=FALSE; + int Opt_DeleteToRecycleBin=Opt.DeleteToRecycleBin; + /*& 31.05.2001 OT Запретить перерисовку текущего фрейма*/ + Frame *FrameFromLaunched=FrameManager->GetCurrentFrame(); + FrameFromLaunched->Lock(); + DeleteAllFolders=!Opt.Confirm.DeleteFolder; + UpdateDiz=(Opt.Diz.UpdateMode==DIZ_UPDATE_ALWAYS || + (SrcPanel->IsDizDisplayed() && + Opt.Diz.UpdateMode==DIZ_UPDATE_IF_DISPLAYED)); + + if (!(SelCount=SrcPanel->GetSelCount())) + goto done; + + // TODO: Удаление в корзину только для FIXED-дисков + { +// char FSysNameSrc[NM]; + SrcPanel->GetSelNameCompat(nullptr,FileAttr); + SrcPanel->GetSelNameCompat(&strSelName,FileAttr); + } + + if (SelCount==1) + { + SrcPanel->GetSelNameCompat(nullptr,FileAttr); + SrcPanel->GetSelNameCompat(&strSelName,FileAttr); + + if (TestParentFolderName(strSelName) || strSelName.IsEmpty()) + { + NeedUpdate=FALSE; + goto done; + } + + strDeleteFilesMsg = strSelName; + } + else + { + // в зависимости от числа ставим нужное окончание + const wchar_t *Ends; + wchar_t StrItems[16]; + _itow(SelCount,StrItems,10); + Ends=MSG(MAskDeleteItemsA); + int LenItems=StrLength(StrItems); + + if (LenItems > 0) + { + if ((LenItems >= 2 && StrItems[LenItems-2] == L'1') || + StrItems[LenItems-1] >= L'5' || + StrItems[LenItems-1] == L'0') + Ends=MSG(MAskDeleteItemsS); + else if (StrItems[LenItems-1] == L'1') + Ends=MSG(MAskDeleteItems0); + } + + strDeleteFilesMsg.Format(MSG(MAskDeleteItems),SelCount,Ends); + } + + Ret=1; + + if (Ret && (Opt.Confirm.Delete || SelCount>1))// || (FileAttr & FILE_ATTRIBUTE_DIRECTORY))) + { + const wchar_t *DelMsg; + const wchar_t *TitleMsg=MSG(Wipe?MDeleteWipeTitle:MDeleteTitle); + /* $ 05.01.2001 IS + ! Косметика в сообщениях - разные сообщения в зависимости от того, + какие и сколько элементов выделено. + */ + BOOL folder=(FileAttr & FILE_ATTRIBUTE_DIRECTORY); + + if (SelCount==1) + { + if (Wipe && !(FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)) + DelMsg=MSG(folder?MAskWipeFolder:MAskWipeFile); + else + { + if (Opt.DeleteToRecycleBin && !(FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)) + DelMsg=MSG(folder?MAskDeleteRecycleFolder:MAskDeleteRecycleFile); + else + DelMsg=MSG(folder?MAskDeleteFolder:MAskDeleteFile); + } + } + else + { + if (Wipe && !(FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)) + { + DelMsg=MSG(MAskWipe); + TitleMsg=MSG(MDeleteWipeTitle); + } + else if (Opt.DeleteToRecycleBin && !(FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)) + DelMsg=MSG(MAskDeleteRecycle); + else + DelMsg=MSG(MAskDelete); + } + + SetMessageHelp(L"DeleteFile"); + + if (Message(0,2,TitleMsg,DelMsg,strDeleteFilesMsg,MSG(Wipe?MDeleteWipe:Opt.DeleteToRecycleBin?MDeleteRecycle:MDelete),MSG(MCancel))) + { + NeedUpdate=FALSE; + goto done; + } + } + + if (Opt.Confirm.Delete && SelCount>1) + { + //SaveScreen SaveScr; + SetCursorType(FALSE,0); + SetMessageHelp(L"DeleteFile"); + + if (Message(MSG_WARNING,2,MSG(Wipe?MWipeFilesTitle:MDeleteFilesTitle),MSG(Wipe?MAskWipe:MAskDelete), + strDeleteFilesMsg,MSG(MDeleteFileAll),MSG(MDeleteFileCancel))) + { + NeedUpdate=FALSE; + goto done; + } + } + + if (UpdateDiz) + SrcPanel->ReadDiz(); + + SrcPanel->GetDizName(strDizName); + DizPresent=(!strDizName.IsEmpty() && apiGetFileAttributes(strDizName)!=INVALID_FILE_ATTRIBUTES); + DeleteTitle = new ConsoleTitle(MSG(MDeletingTitle)); + + if ((NeedSetUpADir=CheckUpdateAnotherPanel(SrcPanel,strSelName)) == -1) + goto done; + + if (SrcPanel->GetType()==TREE_PANEL) + FarChDir(L"/"); + + { + wakeful W; + bool Cancel=false; + //SaveScreen SaveScr; + SetCursorType(FALSE,0); + ReadOnlyDeleteMode=-1; + SkipMode=-1; + SkipWipeMode=-1; + SkipFoldersMode=-1; + ULONG ItemsCount=0; + ProcessedItems=0; + + if (Opt.DelOpt.DelShowTotal) + { + SrcPanel->GetSelNameCompat(nullptr,FileAttr); + DWORD StartTime=WINPORT(GetTickCount)(); + bool FirstTime=true; + + while (SrcPanel->GetSelNameCompat(&strSelName,FileAttr) && !Cancel) + { + if (!(FileAttr&FILE_ATTRIBUTE_REPARSE_POINT)) + { + if (FileAttr&FILE_ATTRIBUTE_DIRECTORY) + { + DWORD CurTime=WINPORT(GetTickCount)(); + + if (CurTime-StartTime>RedrawTimeout || FirstTime) + { + StartTime=CurTime; + FirstTime=false; + + if (CheckForEscSilent() && ConfirmAbortOp()) + { + Cancel=true; + break; + } + + ShellDeleteMsg(strSelName,Wipe,-1); + } + + uint32_t CurrentFileCount,CurrentDirCount,ClusterSize; + UINT64 FileSize,PhysicalSize; + + if (GetDirInfo(nullptr,strSelName,CurrentDirCount,CurrentFileCount,FileSize,PhysicalSize,ClusterSize,-1,nullptr,0)>0) + { + ItemsCount+=CurrentFileCount+CurrentDirCount+1; + } + else + { + Cancel=true; + } + } + else + { + ItemsCount++; + } + } + } + } + + SrcPanel->GetSelNameCompat(nullptr,FileAttr); + DWORD StartTime=WINPORT(GetTickCount)(); + bool FirstTime=true; + + while (SrcPanel->GetSelNameCompat(&strSelName,FileAttr) && !Cancel) + { + int Length=(int)strSelName.GetLength(); + + if (!Length) continue; + + DWORD CurTime=WINPORT(GetTickCount)(); + + if (CurTime-StartTime>RedrawTimeout || FirstTime) + { + StartTime=CurTime; + FirstTime=false; + + if (CheckForEscSilent() && ConfirmAbortOp()) + { + Cancel=true; + break; + } + + ShellDeleteMsg(strSelName,Wipe,Opt.DelOpt.DelShowTotal?(ItemsCount?(ProcessedItems*100/ItemsCount):0):-1); + } + + if (FileAttr & FILE_ATTRIBUTE_DIRECTORY) + { + if (!DeleteAllFolders) + { + ConvertNameToFull(strSelName, strFullName); + + if (TestFolder(strFullName) == TSTFLD_NOTEMPTY) + { + int MsgCode=0; + + // для symlink`а не нужно подтверждение + if (!(FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)) + MsgCode=Message(MSG_WARNING,4,MSG(Wipe?MWipeFolderTitle:MDeleteFolderTitle), + MSG(Wipe?MWipeFolderConfirm:MDeleteFolderConfirm),strFullName, + MSG(Wipe?MDeleteFileWipe:MDeleteFileDelete),MSG(MDeleteFileAll), + MSG(MDeleteFileSkip),MSG(MDeleteFileCancel)); + + if (MsgCode<0 || MsgCode==3) + { + NeedSetUpADir=FALSE; + break; + } + + if (MsgCode==1) + DeleteAllFolders=1; + + if (MsgCode==2) + continue; + } + } + + bool DirSymLink=(FileAttr&FILE_ATTRIBUTE_DIRECTORY && FileAttr&FILE_ATTRIBUTE_REPARSE_POINT); + + if (!DirSymLink && (!Opt.DeleteToRecycleBin || Wipe)) + { + FARString strFullName; + ScanTree ScTree(TRUE,TRUE,FALSE); + FARString strSelFullName; + + if (IsAbsolutePath(strSelName)) + { + strSelFullName=strSelName; + } + else + { + SrcPanel->GetCurDir(strSelFullName); + AddEndSlash(strSelFullName); + strSelFullName+=strSelName; + } + + ScTree.SetFindPath(strSelFullName,L"*", 0); + DWORD StartTime=WINPORT(GetTickCount)(); + + while (ScTree.GetNextName(&FindData,strFullName)) + { + DWORD CurTime=WINPORT(GetTickCount)(); + + if (CurTime-StartTime>RedrawTimeout) + { + StartTime=CurTime; + + if (CheckForEscSilent()) + { + int AbortOp = ConfirmAbortOp(); + + if (AbortOp) + { + Cancel=true; + break; + } + } + + ShellDeleteMsg(strFullName,Wipe,Opt.DelOpt.DelShowTotal?(ItemsCount?(ProcessedItems*100/ItemsCount):0):-1); + } + + if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (FindData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + { + if (FindData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + apiMakeWritable(strFullName); //apiSetFileAttributes(strFullName,FILE_ATTRIBUTE_NORMAL); + + int MsgCode=ERemoveDirectory(strFullName,Wipe); + + if (MsgCode==DELETE_CANCEL) + { + Cancel=true; + break; + } + else if (MsgCode==DELETE_SKIP) + { + ScTree.SkipDir(); + continue; + } + + TreeList::DelTreeName(strFullName); + + if (UpdateDiz) + SrcPanel->DeleteDiz(strFullName); + + continue; + } + + if (!DeleteAllFolders && !ScTree.IsDirSearchDone() && TestFolder(strFullName) == TSTFLD_NOTEMPTY) + { + int MsgCode=Message(MSG_WARNING,4,MSG(Wipe?MWipeFolderTitle:MDeleteFolderTitle), + MSG(Wipe?MWipeFolderConfirm:MDeleteFolderConfirm),strFullName, + MSG(Wipe?MDeleteFileWipe:MDeleteFileDelete),MSG(MDeleteFileAll), + MSG(MDeleteFileSkip),MSG(MDeleteFileCancel)); + + if (MsgCode<0 || MsgCode==3) + { + Cancel=true; + break; + } + + if (MsgCode==1) + DeleteAllFolders=1; + + if (MsgCode==2) + { + ScTree.SkipDir(); + continue; + } + } + + if (ScTree.IsDirSearchDone()) + { + if (FindData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + apiMakeWritable(strFullName); //apiSetFileAttributes(strFullName,FILE_ATTRIBUTE_NORMAL); + + int MsgCode=ERemoveDirectory(strFullName,Wipe); + + if (MsgCode==DELETE_CANCEL) + { + Cancel=true;; + break; + } + else if (MsgCode==DELETE_SKIP) + { + //ScTree.SkipDir(); + continue; + } + + TreeList::DelTreeName(strFullName); + } + } + else + { + if (ShellRemoveFile(strFullName,Wipe)==DELETE_CANCEL) + { + Cancel=true; + break; + } + } + } + } + + if (!Cancel) + { + if (FileAttr & FILE_ATTRIBUTE_READONLY) + apiMakeWritable(strSelName); //apiSetFileAttributes(strSelName,FILE_ATTRIBUTE_NORMAL); + + int DeleteCode; + + // нефига здесь выделываться, а надо учесть, что удаление + // симлинка в корзину чревато потерей оригинала. + if (DirSymLink || !Opt.DeleteToRecycleBin || Wipe) + { + DeleteCode=ERemoveDirectory(strSelName,Wipe); + + if (DeleteCode==DELETE_CANCEL) + break; + else if (DeleteCode==DELETE_SUCCESS) + { + TreeList::DelTreeName(strSelName); + + if (UpdateDiz) + SrcPanel->DeleteDiz(strSelName); + } + } + else + { + DeleteCode=RemoveToRecycleBin(strSelName); + + if (!DeleteCode) + Message(MSG_WARNING|MSG_ERRORTYPE,1,MSG(MError), + MSG(MCannotDeleteFolder),strSelName,MSG(MOk)); + else + { + TreeList::DelTreeName(strSelName); + + if (UpdateDiz) + SrcPanel->DeleteDiz(strSelName); + } + } + } + } + else + { + int DeleteCode=ShellRemoveFile(strSelName,Wipe); + + if (DeleteCode==DELETE_SUCCESS && UpdateDiz) + { + SrcPanel->DeleteDiz(strSelName); + } + + if (DeleteCode==DELETE_CANCEL) + break; + } + } + } + + if (UpdateDiz) + if (DizPresent==(!strDizName.IsEmpty() && apiGetFileAttributes(strDizName)!=INVALID_FILE_ATTRIBUTES)) + SrcPanel->FlushDiz(); + + delete DeleteTitle; +done: + Opt.DeleteToRecycleBin=Opt_DeleteToRecycleBin; + // Разрешить перерисовку фрейма + FrameFromLaunched->Unlock(); + + if (NeedUpdate) + { + ShellUpdatePanels(SrcPanel,NeedSetUpADir); + } +} + +static void PR_ShellDeleteMsg() +{ + PreRedrawItem preRedrawItem=PreRedraw.Peek(); + ShellDeleteMsg(static_cast<const wchar_t*>(preRedrawItem.Param.Param1),static_cast<int>(reinterpret_cast<INT_PTR>(preRedrawItem.Param.Param4)),static_cast<int>(preRedrawItem.Param.Param5)); +} + +void ShellDeleteMsg(const wchar_t *Name,int Wipe,int Percent) +{ + FARString strProgress; + size_t Width=52; + + if (Percent!=-1) + { + size_t Length=Width-5; // -5 под проценты + wchar_t *Progress=strProgress.GetBuffer(Length); + + if (Progress) + { + size_t CurPos=Min(Percent,100)*Length/100; + wmemset(Progress,BoxSymbols[BS_X_DB],CurPos); + wmemset(Progress+(CurPos),BoxSymbols[BS_X_B0],Length-CurPos); + strProgress.ReleaseBuffer(Length); + FormatString strTmp; + strTmp<<L" "<<fmt::Width(3)<<Percent<<L"%"; + strProgress+=strTmp; + DeleteTitle->Set(L"{%d%%} %ls",Percent,MSG(Wipe?MDeleteWipeTitle:MDeleteTitle)); + } + + } + + FARString strOutFileName(Name); + TruncPathStr(strOutFileName,static_cast<int>(Width)); + CenterStr(strOutFileName,strOutFileName,static_cast<int>(Width)); + Message(0,0,MSG(Wipe?MDeleteWipeTitle:MDeleteTitle),(Percent>=0||!Opt.DelOpt.DelShowTotal)?MSG(Wipe?MDeletingWiping:MDeleting):MSG(MScanningFolder),strOutFileName,strProgress.IsEmpty()?nullptr:strProgress.CPtr()); + PreRedrawItem preRedrawItem=PreRedraw.Peek(); + preRedrawItem.Param.Param1=static_cast<void*>(const_cast<wchar_t*>(Name)); + preRedrawItem.Param.Param4=(void *)(INT_PTR)Wipe; + preRedrawItem.Param.Param5=(int64_t)Percent; + PreRedraw.SetParam(preRedrawItem.Param); +} + +AskDeleteReadOnly::AskDeleteReadOnly(const wchar_t *Name,int Wipe) + : _r(DELETE_YES) +{ + int MsgCode; + _ump = apiMakeWritable(Name); + + if (!_ump)//(Attr & FILE_ATTRIBUTE_READONLY)) + return;//(DELETE_YES); + + if (!Opt.Confirm.RO) + ReadOnlyDeleteMode=1; + + if (ReadOnlyDeleteMode!=-1) + MsgCode=ReadOnlyDeleteMode; + else + { + MsgCode=Message(MSG_WARNING,5,MSG(MWarning),MSG(MDeleteRO),Name, + MSG(Wipe?MAskWipeRO:MAskDeleteRO),MSG(Wipe?MDeleteFileWipe:MDeleteFileDelete),MSG(MDeleteFileAll), + MSG(MDeleteFileSkip),MSG(MDeleteFileSkipAll), + MSG(MDeleteFileCancel)); + } + + switch (MsgCode) + { + case 1: + ReadOnlyDeleteMode=1; + break; + case 2: + _r = DELETE_SKIP; + return; + case 3: + ReadOnlyDeleteMode=3; + _r = DELETE_SKIP; + return; + case -1: + case -2: + case 4: + _r = DELETE_CANCEL; + return; + } + + //apiSetFileAttributes(Name,FILE_ATTRIBUTE_NORMAL); + //return(DELETE_YES); +} + + + +int ShellRemoveFile(const wchar_t *Name, int Wipe) +{ + ProcessedItems++; + int MsgCode=0; + std::unique_ptr<AskDeleteReadOnly> AskDeleteRO; + /* have to pretranslate to full path otherwise plain remove() + * below will malfunction if current directory requires sudo + */ + FARString strFullName; + ConvertNameToFull(Name, strFullName); + + if (Wipe || Opt.DeleteToRecycleBin) + { /* in case its a not a simple deletion - check/sanitize RO files prior any actions, + * cuz code that doing such things is not aware about such complications + */ + AskDeleteRO.reset(new AskDeleteReadOnly(strFullName, Wipe)); + if (AskDeleteRO->Choice() != DELETE_YES) + return AskDeleteRO->Choice(); + } + + for (;;) + { + if (Wipe) + { + if (SkipWipeMode!=-1) + { + MsgCode=SkipWipeMode; + } + else if (0) //todo if (GetNumberOfLinks(strFullName)>1) + { + /* + Файл + "имя файла" + Файл имеет несколько жестких ссылок. + Уничтожение файла приведет к обнулению всех ссылающихся на него файлов. + Уничтожать файл? + */ + MsgCode=Message(MSG_WARNING,5,MSG(MError),strFullName, + MSG(MDeleteHardLink1),MSG(MDeleteHardLink2),MSG(MDeleteHardLink3), + MSG(MDeleteFileWipe),MSG(MDeleteFileAll),MSG(MDeleteFileSkip),MSG(MDeleteFileSkipAll),MSG(MDeleteCancel)); + } + + switch (MsgCode) + { + case -1: + case -2: + case 4: + return DELETE_CANCEL; + case 3: + SkipWipeMode=2; + case 2: + return DELETE_SKIP; + case 1: + SkipWipeMode=0; + case 0: + + if (WipeFile(strFullName)) + return DELETE_SUCCESS; + } + } + else if (!Opt.DeleteToRecycleBin) + { + // first try simple removal, only if it will fail + // then fallback to AskDeleteRO and sdc_remove + const std::string &mbFullName = strFullName.GetMB(); + if (!AskDeleteRO) + { + if (remove(mbFullName.c_str()) == 0 || errno == ENOENT) { + break; + } + AskDeleteRO.reset(new AskDeleteReadOnly(strFullName, Wipe)); + if (AskDeleteRO->Choice() != DELETE_YES) + return AskDeleteRO->Choice(); + } + if (sdc_remove(mbFullName.c_str()) == 0 || errno == ENOENT) { + break; + } + } + else if (RemoveToRecycleBin(strFullName)) + break; + + if (SkipMode!=-1) + MsgCode=SkipMode; + else + { + MsgCode=Message(MSG_WARNING|MSG_ERRORTYPE,4,MSG(MError), + MSG(MCannotDeleteFile),strFullName,MSG(MDeleteRetry), + MSG(MDeleteSkip),MSG(MDeleteFileSkipAll),MSG(MDeleteCancel)); + } + + switch (MsgCode) + { + case -1: + case -2: + case 3: + return DELETE_CANCEL; + case 2: + SkipMode=1; + case 1: + return DELETE_SKIP; + } + } + + return DELETE_SUCCESS; +} + + +int ERemoveDirectory(const wchar_t *Name,int Wipe) +{ + ProcessedItems++; + + for (;;) + { + if (Wipe) + { + if (WipeDirectory(Name)) + break; + } else { + struct stat s = {}; + if (sdc_lstat(Wide2MB(Name).c_str(), &s)==0 && (s.st_mode & S_IFMT)==S_IFLNK ) + { + if (sdc_unlink(Wide2MB(Name).c_str()) == 0) //if (apiDeleteFile(Name)) + break; + } + if (apiRemoveDirectory(Name)) + break; + } + + int MsgCode; + + if (SkipFoldersMode!=-1) + MsgCode=SkipFoldersMode; + else + { + FARString strFullName; + ConvertNameToFull(Name,strFullName); + + MsgCode=Message(MSG_WARNING|MSG_ERRORTYPE,4,MSG(MError), + MSG(MCannotDeleteFolder),Name,MSG(MDeleteRetry), + MSG(MDeleteSkip),MSG(MDeleteFileSkipAll),MSG(MDeleteCancel)); + } + + switch (MsgCode) + { + case -1: + case -2: + case 3: + return DELETE_CANCEL; + case 1: + return DELETE_SKIP; + case 2: + SkipFoldersMode=2; + return DELETE_SKIP; + } + } + + return DELETE_SUCCESS; +} + +int RemoveToRecycleBin(const wchar_t *Name) +{ + std::string name_mb = Wide2MB(Name); + + unsigned int flags = EF_HIDEOUT; + if (sudo_client_is_required_for(name_mb.c_str(), true)) + flags|= EF_SUDO; + + QuoteCmdArgIfNeed(name_mb); + + std::string cmd = GetMyScriptQuoted("trash.sh"); + cmd+= ' '; + cmd+= name_mb; + + int r = farExecuteA(cmd.c_str(), flags); + if (r==0) + return TRUE; + + errno = r; + return FALSE; +} + +static FARString WipingRename(const wchar_t *Name) +{ + FARString strTempName = Name; + CutToSlash(strTempName, false); + for (size_t i = 0, ii = 3 + (rand() % 4); + (i < ii || apiGetFileAttributes(strTempName) != INVALID_FILE_ATTRIBUTES); ++i) + { + strTempName+= (wchar_t)'a' + (rand() % 26); + } + + if (!apiMoveFile(Name, strTempName)) + { + fprintf(stderr, "%s: error %u renaming '%ls' to '%ls'\n", + __FUNCTION__, errno, Name, strTempName.CPtr()); + return Name; + } + + fprintf(stderr, "%s: renamed '%ls' to '%ls'\n", + __FUNCTION__, Name, strTempName.CPtr()); + + return strTempName; +} + +int WipeFile(const wchar_t *Name) +{ + uint64_t FileSize; + apiMakeWritable(Name); //apiSetFileAttributes(Name,FILE_ATTRIBUTE_NORMAL); + File WipeFile; + if(!WipeFile.Open(Name, GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_WRITE_THROUGH|FILE_FLAG_SEQUENTIAL_SCAN)) + { + return FALSE; + } + + if (!WipeFile.GetSize(FileSize)) + { + WipeFile.Close(); + return FALSE; + } + + if(FileSize) + { + const int BufSize=65536; + LPBYTE Buf=new BYTE[BufSize]; + memset(Buf, Opt.WipeSymbol, BufSize); // используем символ заполнитель + DWORD Written; + while (FileSize>0) + { + DWORD WriteSize=(DWORD)Min((uint64_t)BufSize,FileSize); + WipeFile.Write(Buf,WriteSize,&Written); + FileSize-=WriteSize; + } + WipeFile.Write(Buf,BufSize,&Written); + delete[] Buf; + WipeFile.SetPointer(0,nullptr,FILE_BEGIN); + WipeFile.SetEnd(); + } + + WipeFile.Close(); + + FARString strRemoveName = WipingRename(Name); + return apiDeleteFile(strRemoveName); +} + + +int WipeDirectory(const wchar_t *Name) +{ + FARString strTempName, strPath; + + if (FirstSlash(Name)) + { + strPath = Name; + DeleteEndSlash(strPath); + CutToSlash(strPath); + } + + FARString strRemoveName = WipingRename(Name); + return apiRemoveDirectory(strRemoveName); +} + +int DeleteFileWithFolder(const wchar_t *FileName) +{ + SudoClientRegion scr; + FARString strFileOrFolderName, strParentFolder; + strFileOrFolderName = FileName; + Unquote(strFileOrFolderName); + + strParentFolder = strFileOrFolderName; + CutToSlash(strParentFolder, true); + if (!strParentFolder.IsEmpty()) + apiMakeWritable(strParentFolder); + apiMakeWritable(strFileOrFolderName); + /*BOOL Ret=apiSetFileAttributes(strFileOrFolderName,FILE_ATTRIBUTE_NORMAL); + + if (Ret)*/ + { + if (apiDeleteFile(strFileOrFolderName)) //BUGBUG + { + return apiRemoveDirectory(strParentFolder); + } + } + + WINPORT(SetLastError)((_localLastError = WINPORT(GetLastError)())); + return FALSE; +} + + +void DeleteDirTree(const wchar_t *Dir) +{ + if (!*Dir || (IsSlash(Dir[0]) && !Dir[1])) + return; + + SudoClientRegion scr; + FARString strFullName; + FAR_FIND_DATA_EX FindData; + ScanTree ScTree(TRUE,TRUE,FALSE); + ScTree.SetFindPath(Dir,L"*",0); + + while (ScTree.GetNextName(&FindData, strFullName)) + { + if (FindData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + apiMakeWritable(strFullName); +// apiSetFileAttributes(strFullName,FILE_ATTRIBUTE_NORMAL); + + if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (ScTree.IsDirSearchDone()) + apiRemoveDirectory(strFullName); + } + else + apiDeleteFile(strFullName); + } + apiMakeWritable(Dir); +// apiSetFileAttributes(Dir,FILE_ATTRIBUTE_NORMAL); + apiRemoveDirectory(Dir); +} |