int CommandData::IsProcessFile(FileHeader &NewLhd,bool *ExactMatch,int MatchType) { if (strlen(NewLhd.FileName)>=NM || wcslen(NewLhd.FileNameW)>=NM) return(0); bool Dir=(NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY; if (ExclCheck(NewLhd.FileName,Dir,false,true)) return(0); #ifndef SFX_MODULE if (TimeCheck(NewLhd.mtime)) return(0); if ((NewLhd.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (NewLhd.FileAttr & InclFileAttr)==0) return(0); if (!Dir && SizeCheck(NewLhd.FullUnpSize)) return(0); #endif char *ArgName; wchar *ArgNameW; FileArgs->Rewind(); for (int StringCount=1;FileArgs->GetString(&ArgName,&ArgNameW);StringCount++) { #ifndef SFX_MODULE bool Unicode=(NewLhd.Flags & LHD_UNICODE) || ArgNameW!=NULL && *ArgNameW!=0; if (Unicode) { wchar NameW[NM],ArgW[NM],*NamePtr=NewLhd.FileNameW; bool CorrectUnicode=true; if (ArgNameW==NULL || *ArgNameW==0) { if (!CharToWide(ArgName,ArgW) || *ArgW==0) CorrectUnicode=false; ArgNameW=ArgW; } if ((NewLhd.Flags & LHD_UNICODE)==0) { if (!CharToWide(NewLhd.FileName,NameW) || *NameW==0) CorrectUnicode=false; NamePtr=NameW; } if (CmpName(ArgNameW,NamePtr,MatchType)) { if (ExactMatch!=NULL) *ExactMatch=wcsicompc(ArgNameW,NamePtr)==0; return(StringCount); } if (CorrectUnicode) continue; } #endif if (CmpName(ArgName,NewLhd.FileName,MatchType)) { if (ExactMatch!=NULL) *ExactMatch=stricompc(ArgName,NewLhd.FileName)==0; return(StringCount); } } return(0); }
int CommandData::IsProcessFile(FileHeader &NewLhd,bool *ExactMatch,int MatchType) { if (strlen(NewLhd.FileName)>=NM || strlenw(NewLhd.FileNameW)>=NM) return(0); if (ExclCheck(NewLhd.FileName,false)) return(0); #ifndef SFX_MODULE if (TimeCheck(NewLhd.mtime)) return(0); #endif char *ArgName; wchar *ArgNameW; FileArgs->Rewind(); for (int StringCount=1;FileArgs->GetString(&ArgName,&ArgNameW);StringCount++) { #ifndef SFX_MODULE bool Unicode=(NewLhd.Flags & LHD_UNICODE) || ArgNameW!=NULL; if (Unicode) { wchar NameW[NM],ArgW[NM],*NamePtr=NewLhd.FileNameW; if (ArgNameW==NULL) { CharToWide(ArgName,ArgW); ArgNameW=ArgW; } if ((NewLhd.Flags & LHD_UNICODE)==0) { CharToWide(NewLhd.FileName,NameW); NamePtr=NameW; } if (CmpName(ArgNameW,NamePtr,MatchType)) { if (ExactMatch!=NULL) *ExactMatch=stricompcw(ArgNameW,NamePtr)==0; return(StringCount); } continue; } #endif if (CmpName(ArgName,NewLhd.FileName,MatchType)) { if (ExactMatch!=NULL) *ExactMatch=stricompc(ArgName,NewLhd.FileName)==0; return(StringCount); } } return(0); }
/* сравнить имя файла со списком масок Возвращает TRUE в случае успеха. Путь к файлу в FileName НЕ игнорируется */ bool FileMasksProcessor::Compare(const wchar_t *FileName) { if (bRE) { int i = n; int len = StrLength(FileName); bool ret = re->Search(FileName,FileName+len,m,i) ? TRUE : FALSE; //Освободим память если большая строка, чтоб не накапливалось. if (len > 1024) re->CleanStack(); return ret; } Masks.Reset(); while (nullptr!=(MaskPtr=Masks.GetNext())) { // SkipPath=FALSE, т.к. в CFileMask вызывается PointToName if (CmpName(MaskPtr,FileName, false)) return true; } return false; }
int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType, wchar *MatchedArg,uint MatchedArgSize) { if (MatchedArg!=NULL && MatchedArgSize>0) *MatchedArg=0; // if (wcslen(FileHead.FileName)>=NM) // return 0; bool Dir=FileHead.Dir; if (ExclCheck(FileHead.FileName,Dir,false,true)) return 0; #ifndef SFX_MODULE if (TimeCheck(FileHead.mtime)) return 0; if ((FileHead.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0) return 0; if (!Dir && SizeCheck(FileHead.UnpSize)) return 0; #endif wchar *ArgName; FileArgs.Rewind(); for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++) if (CmpName(ArgName,FileHead.FileName,MatchType)) { if (ExactMatch!=NULL) *ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0; if (MatchedArg!=NULL) wcsncpyz(MatchedArg,ArgName,MatchedArgSize); return StringCount; } return 0; }
bool CommandData::ExclCheckArgs(StringList *Args,char *CheckName,bool CheckFullPath) { char *Name=ConvertPath(CheckName,NULL); char FullName[NM],*CurName; *FullName=0; Args->Rewind(); while ((CurName=Args->GetString())!=NULL) #ifndef SFX_MODULE if (CheckFullPath && IsFullPath(CurName)) { if (*FullName==0) ConvertNameToFull(CheckName,FullName); if (CmpName(CurName,FullName,MATCH_WILDSUBPATH)) return(true); } else #endif if (CmpName(ConvertPath(CurName,NULL),Name,MATCH_WILDSUBPATH)) return(true); return(false); }
// VISITORS virtual void visit(AstNetlist* nodep, AstNUser*) { // Collect list of scopes nodep->iterateChildren(*this); varsExpand(); // Sort by names, so line/process order matters less stable_sort(m_scopes.begin(), m_scopes.end(), CmpName()); stable_sort(m_dpis.begin(), m_dpis.end(), CmpDpi()); // Output emitSymHdr(); emitSymImp(); if (v3Global.dpi()) { emitDpiHdr(); emitDpiImp(); } }
bool NativePluginModel::IsPlugin(const string& filename) { if (!CmpName(L"*.dll", filename.data(), false)) return false; bool Result = false; if (const auto ModuleFile = os::handle(os::CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING))) { if (const auto ModuleMapping = os::handle(CreateFileMapping(ModuleFile.native_handle(), nullptr, PAGE_READONLY, 0, 0, nullptr))) { if (const auto Data = MapViewOfFile(ModuleMapping.native_handle(), FILE_MAP_READ, 0, 0, 0)) { Result = IsPlugin2(Data); UnmapViewOfFile(Data); } } } return Result; }
// Return 'true' if we need to exclude the directory from archiving as result // of -x switch. We do not want -x*. switch to exclude all directories, // so when archiving we process exclusion arguments for directories specially. bool CommandData::ExclCheckDir(char *CheckName) { // If exclusion mask and directory name match exactly, return true. if (ExclCheckArgs(ExclArgs,CheckName,true,MATCH_EXACT)) return(true); // Now we want to allow wildcards in exclusion mask only if it has // '\' at the end. So 'dir*\' will exclude all dir* directories. // We append '\' to directory name, so it will match only masks having // '\' at the end. char DirName[NM+1]; ConvertPath(CheckName,DirName); AddEndSlash(DirName); char *CurMask; ExclArgs->Rewind(); while ((CurMask=ExclArgs->GetString())!=NULL) if (IsPathDiv(*PointToLastChar(CurMask))) if (CmpName(CurMask,DirName,MATCH_SUBPATH)) return(true); return(false); }
SCAN_CODE ScanTree::FindProc(FindData *FD) { if (*CurMask==0) return SCAN_NEXT; bool FastFindFile=false; if (FindStack[Depth]==NULL) // No FindFile object for this depth yet. { bool Wildcards=IsWildcard(CurMask); // If we have a file name without wildcards, we can try to use // FastFind to optimize speed. For example, in Unix it results in // stat call instead of opendir/readdir/closedir. bool FindCode=!Wildcards && FindFile::FastFind(CurMask,FD,GetLinks); // Link check is important for NTFS, where links can have "Directory" // attribute, but we do not want to recurse to them in "get links" mode. bool IsDir=FindCode && FD->IsDir && (!GetLinks || !FD->IsLink); // SearchAll means that we'll use "*" mask for search, so we'll find // subdirectories and will be able to recurse into them. // We do not use "*" for directories at any level or for files // at top level in recursion mode. We always comrpess the entire directory // if folder wildcard is specified. bool SearchAll=!IsDir && (Depth>0 || Recurse==RECURSE_ALWAYS || FolderWildcards && Recurse!=RECURSE_DISABLE || Wildcards && Recurse==RECURSE_WILDCARDS || ScanEntireDisk && Recurse!=RECURSE_DISABLE); if (Depth==0) SearchAllInRoot=SearchAll; if (SearchAll || Wildcards) { // Create the new FindFile object for wildcard based search. FindStack[Depth]=new FindFile; wchar SearchMask[NM]; wcsncpyz(SearchMask,CurMask,ASIZE(SearchMask)); if (SearchAll) SetName(SearchMask,MASKALL,ASIZE(SearchMask)); FindStack[Depth]->SetMask(SearchMask); } else { // Either we failed to fast find or we found a file or we found // a directory in RECURSE_DISABLE mode, so we do not need to scan it. // We can return here and do not need to process further. // We need to process further only if we fast found a directory. if (!FindCode || !IsDir || Recurse==RECURSE_DISABLE) { // Return SCAN_SUCCESS if we found a file. SCAN_CODE RetCode=SCAN_SUCCESS; if (!FindCode) { // Return SCAN_ERROR if problem is more serious than just // "file not found". RetCode=FD->Error ? SCAN_ERROR:SCAN_NEXT; // If we failed to find an object, but our current mask is excluded, // we skip this object and avoid indicating an error. if (Cmd!=NULL && Cmd->ExclCheck(CurMask,false,true,true)) RetCode=SCAN_NEXT; else { ErrHandler.OpenErrorMsg(ErrArcName,CurMask); // User asked to return RARX_NOFILES and not RARX_OPEN here. ErrHandler.SetErrorCode(RARX_NOFILES); } } // If we searched only for one file or directory in "fast find" // (without a wildcard) mode, let's set masks to zero, // so calling function will know that current mask is used // and next one must be read from mask list for next call. // It is not necessary for directories, because even in "fast find" // mode, directory recursing will quit by (Depth < 0) condition, // which returns SCAN_DONE to calling function. *CurMask=0; return RetCode; } // We found a directory using only FindFile::FastFind function. FastFindFile=true; } } if (!FastFindFile && !FindStack[Depth]->Next(FD,GetLinks)) { // We cannot find anything more in directory either because of // some error or just as result of all directory entries already read. bool Error=FD->Error; if (Error) ScanError(Error); wchar DirName[NM]; *DirName=0; // Going to at least one directory level higher. delete FindStack[Depth]; FindStack[Depth--]=NULL; while (Depth>=0 && FindStack[Depth]==NULL) Depth--; if (Depth < 0) { // Directories scanned both in normal and FastFindFile mode, // finally exit from scan here, by (Depth < 0) condition. if (Error) Errors++; return SCAN_DONE; } wchar *Slash=wcsrchr(CurMask,CPATHDIVIDER); if (Slash!=NULL) { wchar Mask[NM]; wcsncpyz(Mask,Slash,ASIZE(Mask)); if (Depth<SetAllMaskDepth) wcsncpyz(Mask+1,PointToName(OrigCurMask),ASIZE(Mask)-1); *Slash=0; wcsncpyz(DirName,CurMask,ASIZE(DirName)); wchar *PrevSlash=wcsrchr(CurMask,CPATHDIVIDER); if (PrevSlash==NULL) wcsncpyz(CurMask,Mask+1,ASIZE(CurMask)); else { *(PrevSlash+1)=0; wcsncatz(CurMask,Mask,ASIZE(CurMask)); } } if (GetDirs==SCAN_GETDIRSTWICE && FindFile::FastFind(DirName,FD,GetLinks) && FD->IsDir) { FD->Flags|=FDDF_SECONDDIR; return Error ? SCAN_ERROR:SCAN_SUCCESS; } return Error ? SCAN_ERROR:SCAN_NEXT; } // Link check is required for NTFS links, not for Unix. if (FD->IsDir && (!GetLinks || !FD->IsLink)) { // If we found the directory in top (Depth==0) directory // and if we are not in "fast find" (directory name only as argument) // or in recurse (SearchAll was set when opening the top directory) mode, // we do not recurse into this directory. We either return it by itself // or skip it. if (!FastFindFile && Depth==0 && !SearchAllInRoot) return GetDirs==SCAN_GETCURDIRS ? SCAN_SUCCESS:SCAN_NEXT; // Let's check if directory name is excluded, so we do not waste // time searching in directory, which will be excluded anyway. if (Cmd!=NULL && (Cmd->ExclCheck(FD->Name,true,false,false) || Cmd->ExclDirByAttr(FD->FileAttr))) { // If we are here in "fast find" mode, it means that entire directory // specified in command line is excluded. Then we need to return // SCAN_DONE to go to next mask and avoid the infinite loop // in GetNext() function. Such loop would be possible in case of // SCAN_NEXT code and "rar a arc dir -xdir" command. return FastFindFile ? SCAN_DONE:SCAN_NEXT; } wchar Mask[NM]; wcsncpyz(Mask,FastFindFile ? MASKALL:PointToName(CurMask),ASIZE(Mask)); wcsncpyz(CurMask,FD->Name,ASIZE(CurMask)); if (wcslen(CurMask)+wcslen(Mask)+1>=NM || Depth>=MAXSCANDEPTH-1) { uiMsg(UIERROR_PATHTOOLONG,CurMask,SPATHDIVIDER,Mask); return SCAN_ERROR; } AddEndSlash(CurMask,ASIZE(CurMask)); wcsncatz(CurMask,Mask,ASIZE(CurMask)); Depth++; // We need to use OrigCurMask for depths less than SetAllMaskDepth // and "*" for depths equal or larger than SetAllMaskDepth. // It is important when "fast finding" directories at Depth > 0. // For example, if current directory is RootFolder and we compress // the following directories structure: // RootFolder // +--Folder1 // | +--Folder2 // | +--Folder3 // +--Folder4 // with 'rar a -r arcname Folder2' command, rar could add not only // Folder1\Folder2 contents, but also Folder1\Folder3 if we were using // "*" mask at all levels. We need to use "*" mask inside of Folder2, // but return to "Folder2" mask when completing scanning Folder2. // We can rewrite SearchAll expression above to avoid fast finding // directories at Depth > 0, but then 'rar a -r arcname Folder2' // will add the empty Folder2 and do not add its contents. if (FastFindFile) SetAllMaskDepth=Depth; } if (!FastFindFile && !CmpName(CurMask,FD->Name,MATCH_NAMES)) return SCAN_NEXT; return SCAN_SUCCESS; }
bool FindFile::Next(struct FindData *fd,bool GetSymLink) { fd->Error=false; if (*FindMask==0) return(false); #ifdef _WIN_32 if (FirstCall) { if ((hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,FindMaskW,fd))==INVALID_HANDLE_VALUE) return(false); } else if (Win32Find(hFind,FindMask,FindMaskW,fd)==INVALID_HANDLE_VALUE) return(false); #else if (FirstCall) { char DirName[NM]; strcpy(DirName,FindMask); RemoveNameFromPath(DirName); if (*DirName==0) strcpy(DirName,"."); /* else { int Length=strlen(DirName); if (Length>1 && DirName[Length-1]==CPATHDIVIDER && (Length!=3 || !IsDriveDiv(DirName[1]))) DirName[Length-1]=0; } */ if ((dirp=opendir(DirName))==NULL) { fd->Error=(errno!=ENOENT); return(false); } } while (1) { struct dirent *ent=readdir(dirp); if (ent==NULL) return(false); if (strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0) continue; if (CmpName(FindMask,ent->d_name,MATCH_NAMES)) { char FullName[NM]; strcpy(FullName,FindMask); *PointToName(FullName)=0; if (strlen(FullName)+strlen(ent->d_name)>=ASIZE(FullName)-1) { #ifndef SILENT Log(NULL,"\n%s%s",FullName,ent->d_name); Log(NULL,St(MPathTooLong)); #endif return(false); } strcat(FullName,ent->d_name); if (!FastFind(FullName,NULL,fd,GetSymLink)) { ErrHandler.OpenErrorMsg(FullName); continue; } strcpy(fd->Name,FullName); break; } } *fd->NameW=0; #ifdef _APPLE if (!LowAscii(fd->Name)) UtfToWide(fd->Name,fd->NameW,sizeof(fd->NameW)); #elif defined(UNICODE_SUPPORTED) if (!LowAscii(fd->Name) && UnicodeEnabled()) CharToWide(fd->Name,fd->NameW); #endif #endif fd->Flags=0; fd->IsDir=IsDir(fd->FileAttr); FirstCall=false; char *Name=PointToName(fd->Name); if (strcmp(Name,".")==0 || strcmp(Name,"..")==0) return(Next(fd)); return(true); }
bool CommandData::ExclCheckArgs(StringList *Args,bool Dir,char *CheckName,bool CheckFullPath,int MatchMode) { char *Name=ConvertPath(CheckName,NULL); char FullName[NM]; char CurMask[NM+1]; // We reserve the space to append "*" to mask. *FullName=0; Args->Rewind(); while (Args->GetString(CurMask,ASIZE(CurMask)-1)) { char *LastMaskChar=PointToLastChar(CurMask); bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only. if (Dir) { // CheckName is a directory. if (DirMask) { // We process the directory and have the directory exclusion mask. // So let's convert "mask\" to "mask" and process it normally. *LastMaskChar=0; } else { // If mask has wildcards in name part and does not have the trailing // '\' character, we cannot use it for directories. if (IsWildcard(PointToName(CurMask))) continue; } } else { // If we process a file inside of directory excluded by "dirmask\". // we want to exclude such file too. So we convert "dirmask\" to // "dirmask\*". It is important for operations other than archiving. // When archiving, directory matched by "dirmask\" is excluded // from further scanning. if (DirMask) strcat(CurMask,"*"); } #ifndef SFX_MODULE if (CheckFullPath && IsFullPath(CurMask)) { // We do not need to do the special "*\" processing here, because // onlike the "else" part of this "if", now we convert names to full // format, so they all include the path, which is matched by "*\" // correctly. Moreover, removing "*\" from mask would break // the comparison, because now all names have the path. if (*FullName==0) ConvertNameToFull(CheckName,FullName); if (CmpName(CurMask,FullName,MatchMode)) return(true); } else #endif { char NewName[NM+2],*CurName=Name; if (CurMask[0]=='*' && IsPathDiv(CurMask[1])) { // We want "*\name" to match 'name' not only in subdirectories, // but also in the current directory. We convert the name // from 'name' to '.\name' to be matched by "*\" part even if it is // in current directory. NewName[0]='.'; NewName[1]=CPATHDIVIDER; strncpyz(NewName+2,Name,ASIZE(NewName)-2); CurName=NewName; } if (CmpName(ConvertPath(CurMask,NULL),CurName,MatchMode)) return(true); } } return(false); }
// IS: это реальное тело функции сравнения с маской, но использовать // IS: "снаружи" нужно не эту функцию, а CmpName (ее тело расположено // IS: после CmpName_Body) static int CmpName_Body(const wchar_t *pattern,const wchar_t *str, bool CmpNameSearchMode) { for (;; ++str) { /* $ 01.05.2001 DJ используем инлайновые версии */ wchar_t stringc=ToUpper(*str); wchar_t patternc=ToUpper(*pattern++); switch (patternc) { case 0: return !stringc; case L'?': if (!stringc) return FALSE; break; case L'*': if (!*pattern) return TRUE; /* $ 01.05.2001 DJ оптимизированная ветка работает и для имен с несколькими точками */ if (*pattern==L'.') { if (pattern[1]==L'*' && !pattern[2]) return TRUE; if (!wcspbrk(pattern, L"*?[")) { const wchar_t *dot = wcsrchr(str, L'.'); if (!pattern[1]) return !dot || !dot[1]; const wchar_t *patdot = wcschr(pattern+1, L'.'); if (patdot && !dot) return FALSE; if (!patdot && dot ) return !StrCmpI(pattern+1,dot+1); } } do { if(CmpName(pattern,str,false,CmpNameSearchMode)) return TRUE; } while (*str++); return FALSE; case L'[': { if (!wcschr(pattern,L']')) { if (patternc != stringc) return FALSE; break; } if (*pattern && *(pattern+1)==L']') { if (*pattern!=*str) return FALSE; pattern+=2; break; } int match = 0; wchar_t rangec; while ((rangec = ToUpper(*pattern++)) != 0) { if (rangec == L']') { if (match) break; else return FALSE; } if (match) continue; if (rangec == L'-' && *(pattern - 2) != L'[' && *pattern != L']') { match = (stringc <= ToUpper(*pattern) && ToUpper(*(pattern - 2)) <= stringc); pattern++; } else match = (stringc == rangec); } if (!rangec) return FALSE; } break; default: if (patternc != stringc) { if (patternc==L'.' && !stringc && !CmpNameSearchMode) return *pattern != L'.' && CmpName(pattern, str, true, CmpNameSearchMode); else return FALSE; } break; } } }
int ScanTree::FindProc(FindData *FindData) { if (*CurMask==0) return(SCAN_NEXT); FastFindFile=false; if (FindStack[Depth]==NULL) { bool Wildcards=IsWildcard(CurMask,CurMaskW); bool FindCode=!Wildcards && FindFile::FastFind(CurMask,CurMaskW,FindData,GetLinks); bool IsDir=FindCode && FindData->IsDir; bool SearchAll=!IsDir && (Depth>0 || Recurse==RECURSE_ALWAYS || Wildcards && Recurse==RECURSE_WILDCARDS); if (Depth==0) SearchAllInRoot=SearchAll; if (SearchAll || Wildcards) { FindStack[Depth]=new FindFile; char SearchMask[NM]; strcpy(SearchMask,CurMask); if (SearchAll) strcpy(PointToName(SearchMask),MASKALL); FindStack[Depth]->SetMask(SearchMask); if (*CurMaskW) { wchar SearchMaskW[NM]; strcpyw(SearchMaskW,CurMaskW); if (SearchAll) strcpyw(PointToName(SearchMaskW),MASKALLW); FindStack[Depth]->SetMaskW(SearchMaskW); } } else { FastFindFile=true; if (!FindCode) { if (Cmd!=NULL && Cmd->ExclCheck(CurMask,true)) return(SCAN_NEXT); ErrHandler.OpenErrorMsg(ErrArcName,CurMask); return(FindData->Error ? SCAN_ERROR:SCAN_NEXT); } } } if (!FastFindFile && !FindStack[Depth]->Next(FindData,GetLinks)) { bool Error=FindData->Error; #ifdef _WIN_32 if (Error) { // Do not display an error if we cannot scan contents of reparse // point. Vista contains a lot of reparse (or junction) points, // which are not accessible. if ((FindData->FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0) Error=false; // Do not display an error if we cannot scan contents of // "System Volume Information" folder. Normally it is not accessible. if (strstr(CurMask,"System Volume Information\\")!=NULL) Error=false; } #endif if (Cmd!=NULL && Cmd->ExclCheck(CurMask,true)) Error=false; #ifndef SILENT if (Error) { Log(NULL,St(MScanError),CurMask); } #endif char DirName[NM]; wchar DirNameW[NM]; *DirName=0; *DirNameW=0; delete FindStack[Depth]; FindStack[Depth--]=NULL; while (Depth>=0 && FindStack[Depth]==NULL) Depth--; if (Depth < 0) { if (Error) Errors++; return(SCAN_DONE); } char *Slash=strrchrd(CurMask,CPATHDIVIDER); if (Slash!=NULL) { char Mask[NM]; strcpy(Mask,Slash); if (Depth<SetAllMaskDepth) strcpy(Mask+1,PointToName(OrigCurMask)); *Slash=0; strcpy(DirName,CurMask); char *PrevSlash=strrchrd(CurMask,CPATHDIVIDER); if (PrevSlash==NULL) strcpy(CurMask,Mask+1); else strcpy(PrevSlash,Mask); } if (*CurMaskW!=0) { wchar *Slash=strrchrw(CurMaskW,CPATHDIVIDER); if (Slash!=NULL) { wchar Mask[NM]; strcpyw(Mask,Slash); if (Depth<SetAllMaskDepth) strcpyw(Mask+1,PointToName(OrigCurMaskW)); *Slash=0; strcpyw(DirNameW,CurMaskW); wchar *PrevSlash=strrchrw(CurMaskW,CPATHDIVIDER); if (PrevSlash==NULL) strcpyw(CurMaskW,Mask+1); else strcpyw(PrevSlash,Mask); } #ifndef _WIN_CE if (LowAscii(CurMaskW)) *CurMaskW=0; #endif } if (GetDirs==SCAN_GETDIRSTWICE && FindFile::FastFind(DirName,DirNameW,FindData,GetLinks) && FindData->IsDir) return(Error ? SCAN_ERROR:SCAN_SUCCESS); return(Error ? SCAN_ERROR:SCAN_NEXT); } if (FindData->IsDir) { if (!FastFindFile && Depth==0 && !SearchAllInRoot) return(GetDirs==SCAN_GETCURDIRS ? SCAN_SUCCESS:SCAN_NEXT); // if (GetDirs==SCAN_GETCURDIRS && Depth==0 && !SearchAllInRoot) // return(SCAN_SUCCESS); char Mask[NM]; bool MaskAll=FastFindFile; // bool MaskAll=CmpName(CurMask,FindData->Name,MATCH_NAMES); strcpy(Mask,MaskAll ? MASKALL:PointToName(CurMask)); strcpy(CurMask,FindData->Name); if (strlen(CurMask)+strlen(Mask)+1>=NM || Depth>=MAXSCANDEPTH-1) { #ifndef SILENT Log(NULL,"\n%s%c%s",CurMask,CPATHDIVIDER,Mask); Log(NULL,St(MPathTooLong)); #endif return(SCAN_ERROR); } AddEndSlash(CurMask); strcat(CurMask,Mask); if (*CurMaskW && *FindData->NameW==0) CharToWide(FindData->Name,FindData->NameW); if (*FindData->NameW!=0) { wchar Mask[NM]; if (FastFindFile) strcpyw(Mask,MASKALLW); else if (*CurMaskW) strcpyw(Mask,PointToName(CurMaskW)); else CharToWide(PointToName(CurMask),Mask); strcpyw(CurMaskW,FindData->NameW); AddEndSlash(CurMaskW); strcatw(CurMaskW,Mask); } Depth++; if (MaskAll) SetAllMaskDepth=Depth; } if (!FastFindFile && !CmpName(CurMask,FindData->Name,MATCH_NAMES)) return(SCAN_NEXT); return(SCAN_SUCCESS); }
int ScanTree::FindProc(FindData *FindData) { if (*CurMask==0) return(SCAN_NEXT); FastFindFile=false; if (FindStack[Depth]==NULL) { bool Wildcards=IsWildcard(CurMask,CurMaskW); bool FindCode=!Wildcards && FindFile::FastFind(CurMask,CurMaskW,FindData,GetLinks); bool IsDir=FindCode && FindData->IsDir; bool SearchAll=!IsDir && (Depth>0 || Recurse==RECURSE_ALWAYS || Wildcards && Recurse==RECURSE_WILDCARDS); if (Depth==0) SearchAllInRoot=SearchAll; if (SearchAll || Wildcards) { FindStack[Depth]=new FindFile; char SearchMask[NM]; strcpy(SearchMask,CurMask); if (SearchAll) strcpy(PointToName(SearchMask),MASKALL); FindStack[Depth]->SetMask(SearchMask); if (*CurMaskW) { wchar SearchMaskW[NM]; strcpyw(SearchMaskW,CurMaskW); if (SearchAll) strcpyw(PointToName(SearchMaskW),MASKALLW); FindStack[Depth]->SetMaskW(SearchMaskW); } } else { FastFindFile=true; if (!FindCode) { ErrHandler.OpenErrorMsg(CurMask); return(FindData->Error ? SCAN_ERROR:SCAN_NEXT); } } } if (!FastFindFile && !FindStack[Depth]->Next(FindData,GetLinks)) { bool Error=FindData->Error; #ifdef _WIN_32 if (Error && strstr(CurMask,"System Volume Information\\")!=NULL) Error=false; #endif #ifndef SILENT if (Error) { Log(NULL,St(MScanError),CurMask); } #endif char DirName[NM]; wchar DirNameW[NM]; *DirName=0; *DirNameW=0; delete FindStack[Depth]; FindStack[Depth--]=NULL; while (Depth>=0 && FindStack[Depth]==NULL) Depth--; if (Depth < 0) return(SCAN_DONE); char *Slash=strrchrd(CurMask,CPATHDIVIDER); if (Slash!=NULL) { char Mask[NM]; strcpy(Mask,Slash); *Slash=0; strcpy(DirName,CurMask); char *PrevSlash=strrchrd(CurMask,CPATHDIVIDER); if (PrevSlash==NULL) strcpy(CurMask,Mask+1); else strcpy(PrevSlash,Mask); } if (*CurMaskW!=0) { wchar *Slash=strrchrw(CurMaskW,CPATHDIVIDER); if (Slash!=NULL) { wchar Mask[NM]; strcpyw(Mask,Slash); *Slash=0; strcpyw(DirNameW,CurMaskW); wchar *PrevSlash=strrchrw(CurMaskW,CPATHDIVIDER); if (PrevSlash==NULL) strcpyw(CurMaskW,Mask+1); else strcpyw(PrevSlash,Mask); } if (LowAscii(CurMaskW)) *CurMaskW=0; } if (GetDirs==SCAN_GETDIRSTWICE && FindFile::FastFind(DirName,DirNameW,FindData,GetLinks) && FindData->IsDir) return(Error ? SCAN_ERROR:SCAN_SUCCESS); return(Error ? SCAN_ERROR:SCAN_NEXT); } if (FindData->IsDir) { if (!FastFindFile && Depth==0 && !SearchAllInRoot) return(GetDirs==SCAN_GETCURDIRS ? SCAN_SUCCESS:SCAN_NEXT); char Mask[NM]; strcpy(Mask,FastFindFile ? MASKALL:PointToName(CurMask)); strcpy(CurMask,FindData->Name); if (strlen(CurMask)+strlen(Mask)+1>=NM || Depth>=MAXSCANDEPTH-1) { #ifndef SILENT Log(NULL,"\n%s%c%s",CurMask,CPATHDIVIDER,Mask); Log(NULL,St(MPathTooLong)); #endif return(SCAN_ERROR); } AddEndSlash(CurMask); strcat(CurMask,Mask); if (*CurMaskW && *FindData->NameW==0) CharToWide(FindData->Name,FindData->NameW); if (*FindData->NameW!=0) { wchar Mask[NM]; if (FastFindFile) strcpyw(Mask,MASKALLW); else if (*CurMaskW) strcpyw(Mask,PointToName(CurMaskW)); else CharToWide(PointToName(CurMask),Mask); strcpyw(CurMaskW,FindData->NameW); AddEndSlash(CurMaskW); strcatw(CurMaskW,Mask); } Depth++; } if (!FastFindFile && !CmpName(CurMask,FindData->Name,MATCH_NAMES)) return(SCAN_NEXT); return(SCAN_SUCCESS); }
SCAN_CODE ScanTree::FindProc(FindData *FD) { if (*CurMask==0) return(SCAN_NEXT); bool FastFindFile=false; if (FindStack[Depth]==NULL) // No FindFile object for this depth yet. { bool Wildcards=IsWildcard(CurMask,CurMaskW); // If we have a file name without wildcards, we can try to use // FastFind to optimize speed. For example, in Unix it results in // stat call instead of opendir/readdir/closedir. bool FindCode=!Wildcards && FindFile::FastFind(CurMask,CurMaskW,FD,GetLinks); bool IsDir=FindCode && FD->IsDir; // SearchAll means that we'll use "*" mask for search, so we'll find // subdirectories and will be able to recurse into them. // We do not use "*" for directories at any level or for files // at top level in recursion mode. bool SearchAll=!IsDir && (Depth>0 || Recurse==RECURSE_ALWAYS || Wildcards && Recurse==RECURSE_WILDCARDS || ScanEntireDisk && Recurse!=RECURSE_DISABLE); if (Depth==0) SearchAllInRoot=SearchAll; if (SearchAll || Wildcards) { // Create the new FindFile object for wildcard based search. FindStack[Depth].reset(new FindFile); char SearchMask[NM]; strcpy(SearchMask,CurMask); if (SearchAll) strcpy(PointToName(SearchMask),MASKALL); FindStack[Depth]->SetMask(SearchMask); if (*CurMaskW!=0) { wchar SearchMaskW[NM]; wcscpy(SearchMaskW,CurMaskW); if (SearchAll) wcscpy(PointToName(SearchMaskW),MASKALLW); FindStack[Depth]->SetMaskW(SearchMaskW); } } else { // Either we failed to fast find or we found a file or we found // a directory in RECURSE_DISABLE mode, so we do not need to scan it. // We can return here and do not need to process further. // We need to process further only if we fast found a directory. if (!FindCode || !FD->IsDir || Recurse==RECURSE_DISABLE) { // Return SCAN_SUCCESS if we found a file. SCAN_CODE RetCode=SCAN_SUCCESS; if (!FindCode) { // Return SCAN_ERROR if problem is more serious than just // "file not found". RetCode=FD->Error ? SCAN_ERROR:SCAN_NEXT; // If we failed to find an object, but our current mask is excluded, // we skip this object and avoid indicating an error. if (Cmd!=NULL && Cmd->ExclCheck(CurMask,false,true,true)) RetCode=SCAN_NEXT; else ErrHandler.OpenErrorMsg(ErrArcName,NULL,CurMask,CurMaskW); } // If we searched only for one file or directory in "fast find" // (without a wildcard) mode, let's set masks to zero, // so calling function will know that current mask is used // and next one must be read from mask list for next call. // It is not necessary for directories, because even in "fast find" // mode, directory recursing will quit by (Depth < 0) condition, // which returns SCAN_DONE to calling function. *CurMask=0; *CurMaskW=0; return(RetCode); } // We found a directory using only FindFile::FastFind function. FastFindFile=true; } } if (!FastFindFile && !FindStack[Depth]->Next(FD,GetLinks)) { // We cannot find anything more in directory either because of // some error or just as result of all directory entries already read. bool Error=FD->Error; #ifdef _WIN_ALL if (Error) { // Do not display an error if we cannot scan contents of reparse // point. Vista contains a lot of reparse (or junction) points, // which are not accessible. if ((FD->FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0) Error=false; // Do not display an error if we cannot scan contents of // "System Volume Information" folder. Normally it is not accessible. if (strstr(CurMask,"System Volume Information\\")!=NULL) Error=false; } #endif if (Error && Cmd!=NULL && Cmd->ExclCheck(CurMask,false,true,true)) Error=false; #ifndef SILENT if (Error) { Log(NULL,St(MScanError),CurMask); ErrHandler.SysErrMsg(); } #endif char DirName[NM]; wchar DirNameW[NM]; *DirName=0; *DirNameW=0; // Going to at least one directory level higher. FindStack[Depth--].reset(); while (Depth>=0 && FindStack[Depth]==NULL) Depth--; if (Depth < 0) { // Directories scanned both in normal and FastFindFile mode, // finally exit from scan here, by (Depth < 0) condition. if (Error) Errors++; return(SCAN_DONE); } char *Slash=strrchrd(CurMask,CPATHDIVIDER); if (Slash!=NULL) { char Mask[NM]; strcpy(Mask,Slash); if (Depth<SetAllMaskDepth) strcpy(Mask+1,PointToName(OrigCurMask)); *Slash=0; strcpy(DirName,CurMask); char *PrevSlash=strrchrd(CurMask,CPATHDIVIDER); if (PrevSlash==NULL) strcpy(CurMask,Mask+1); else strcpy(PrevSlash,Mask); } if (*CurMaskW!=0) { wchar *Slash=wcsrchr(CurMaskW,CPATHDIVIDER); if (Slash!=NULL) { wchar Mask[NM]; wcscpy(Mask,Slash); if (Depth<SetAllMaskDepth) wcscpy(Mask+1,PointToName(OrigCurMaskW)); *Slash=0; wcscpy(DirNameW,CurMaskW); wchar *PrevSlash=wcsrchr(CurMaskW,CPATHDIVIDER); if (PrevSlash==NULL) wcscpy(CurMaskW,Mask+1); else wcscpy(PrevSlash,Mask); } #ifndef _WIN_CE // if (LowAscii(CurMaskW)) // *CurMaskW=0; #endif } if (GetDirs==SCAN_GETDIRSTWICE && FindFile::FastFind(DirName,DirNameW,FD,GetLinks) && FD->IsDir) { FD->Flags|=FDDF_SECONDDIR; return(Error ? SCAN_ERROR:SCAN_SUCCESS); } return(Error ? SCAN_ERROR:SCAN_NEXT); } if (FD->IsDir) { // If we found the directory in top (Depth==0) directory // and if we are not in "fast find" (directory name only as argument) // or in recurse (SearchAll was set when opening the top directory) mode, // we do not recurse into this directory. We either return it by itself // or skip it. if (!FastFindFile && Depth==0 && !SearchAllInRoot) return(GetDirs==SCAN_GETCURDIRS ? SCAN_SUCCESS:SCAN_NEXT); // Let's check if directory name is excluded, so we do not waste // time searching in directory, which will be excluded anyway. if (Cmd!=NULL && (Cmd->ExclCheck(FD->Name,true,false,false) || Cmd->ExclDirByAttr(FD->FileAttr))) { // If we are here in "fast find" mode, it means that entire directory // specified in command line is excluded. Then we need to return // SCAN_DONE to go to next mask and avoid the infinite loop // in GetNext() function. Such loop would be possible in case of // SCAN_NEXT code and "rar a arc dir -xdir" command. return(FastFindFile ? SCAN_DONE:SCAN_NEXT); } char Mask[NM]; strcpy(Mask,FastFindFile ? MASKALL:PointToName(CurMask)); strcpy(CurMask,FD->Name); if (strlen(CurMask)+strlen(Mask)+1>=NM || Depth>=MAXSCANDEPTH-1) { #ifndef SILENT Log(NULL,"\n%s%c%s",CurMask,CPATHDIVIDER,Mask); Log(NULL,St(MPathTooLong)); #endif return(SCAN_ERROR); } AddEndSlash(CurMask); strcat(CurMask,Mask); if (*CurMaskW && *FD->NameW==0) CharToWide(FD->Name,FD->NameW); if (*FD->NameW!=0) { wchar Mask[NM]; if (FastFindFile) wcscpy(Mask,MASKALLW); else if (*CurMaskW) wcscpy(Mask,PointToName(CurMaskW)); else CharToWide(PointToName(CurMask),Mask); wcscpy(CurMaskW,FD->NameW); AddEndSlash(CurMaskW); wcscat(CurMaskW,Mask); } Depth++; // We need to use OrigCurMask for depths less than SetAllMaskDepth // and "*" for depths equal or larger than SetAllMaskDepth. // It is important when "fast finding" directories at Depth > 0. // For example, if current directory is RootFolder and we compress // the following directories structure: // RootFolder // +--Folder1 // | +--Folder2 // | +--Folder3 // +--Folder4 // with 'rar a -r arcname Folder2' command, rar could add not only // Folder1\Folder2 contents, but also Folder1\Folder3 if we were using // "*" mask at all levels. We need to use "*" mask inside of Folder2, // but return to "Folder2" mask when completing scanning Folder2. // We can rewrite SearchAll expression above to avoid fast finding // directories at Depth > 0, but then 'rar a -r arcname Folder2' // will add the empty Folder2 and do not add its contents. if (FastFindFile) SetAllMaskDepth=Depth; } if (!FastFindFile && !CmpName(CurMask,FD->Name,MATCH_NAMES)) return(SCAN_NEXT); return(SCAN_SUCCESS); }
bool FindFile::Next(FindData *fd,bool GetSymLink) { fd->Error=false; if (*FindMask==0) return false; #ifdef _WIN_ALL if (FirstCall) { if ((hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,fd))==INVALID_HANDLE_VALUE) return false; } else if (Win32Find(hFind,FindMask,fd)==INVALID_HANDLE_VALUE) return false; #else if (FirstCall) { wchar DirName[NM]; wcsncpyz(DirName,FindMask,ASIZE(DirName)); RemoveNameFromPath(DirName); if (*DirName==0) wcscpy(DirName,L"."); char DirNameA[NM]; WideToChar(DirName,DirNameA,ASIZE(DirNameA)); if ((dirp=opendir(DirNameA))==NULL) { fd->Error=(errno!=ENOENT); return false; } } while (1) { struct dirent *ent=readdir(dirp); if (ent==NULL) return false; if (strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0) continue; wchar Name[NM]; if (!CharToWide(ent->d_name,Name,ASIZE(Name))) Log(NULL,St(MInvalidName),Name); if (CmpName(FindMask,Name,MATCH_NAMES)) { wchar FullName[NM]; wcscpy(FullName,FindMask); *PointToName(FullName)=0; if (wcslen(FullName)+wcslen(Name)>=ASIZE(FullName)-1) { #ifndef SILENT Log(NULL,L"\n%ls%ls",FullName,Name); Log(NULL,St(MPathTooLong)); #endif return false; } wcscat(FullName,Name); if (!FastFind(FullName,fd,GetSymLink)) { ErrHandler.OpenErrorMsg(NULL,FullName); continue; } wcscpy(fd->Name,FullName); break; } } #endif fd->Flags=0; fd->IsDir=IsDir(fd->FileAttr); fd->IsLink=IsLink(fd->FileAttr); FirstCall=false; wchar *NameOnly=PointToName(fd->Name); if (wcscmp(NameOnly,L".")==0 || wcscmp(NameOnly,L"..")==0) return Next(fd); return true; }