#include "rar.hpp" FindFile::FindFile() { *FindMask=0; FirstCall=true; #ifdef _WIN_ALL hFind=INVALID_HANDLE_VALUE; #else dirp=NULL; #endif } FindFile::~FindFile() { #ifdef _WIN_ALL if (hFind!=INVALID_HANDLE_VALUE) FindClose(hFind); #else if (dirp!=NULL) closedir(dirp); #endif } void FindFile::SetMask(const wchar *Mask) { wcscpy(FindMask,Mask); FirstCall=true; } 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))) uiMsg(UIERROR_INVALIDNAME,UINULL,Name); if (CmpName(FindMask,Name,MATCH_NAMES)) { wchar FullName[NM]; wcscpy(FullName,FindMask); *PointToName(FullName)=0; if (wcslen(FullName)+wcslen(Name)>=ASIZE(FullName)-1) { uiMsg(UIERROR_PATHTOOLONG,FullName,L"",Name); return false; } wcscat(FullName,Name); if (!FastFind(FullName,fd,GetSymLink)) { ErrHandler.OpenErrorMsg(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; } bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink) { fd->Error=false; #ifndef _UNIX if (IsWildcard(FindMask)) return false; #endif #ifdef _WIN_ALL HANDLE hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,fd); if (hFind==INVALID_HANDLE_VALUE) return false; FindClose(hFind); #else char FindMaskA[NM]; WideToChar(FindMask,FindMaskA,ASIZE(FindMaskA)); struct stat st; if (GetSymLink) { #ifdef SAVE_LINKS if (lstat(FindMaskA,&st)!=0) #else if (stat(FindMaskA,&st)!=0) #endif { fd->Error=(errno!=ENOENT); return false; } } else if (stat(FindMaskA,&st)!=0) { fd->Error=(errno!=ENOENT); return false; } fd->FileAttr=st.st_mode; fd->Size=st.st_size; #ifdef UNIX_TIME_NS fd->mtime.SetUnixNS(st.st_mtim.tv_sec*(uint64)1000000000+st.st_mtim.tv_nsec); fd->atime.SetUnixNS(st.st_atim.tv_sec*(uint64)1000000000+st.st_atim.tv_nsec); fd->ctime.SetUnixNS(st.st_ctim.tv_sec*(uint64)1000000000+st.st_ctim.tv_nsec); #else fd->mtime.SetUnix(st.st_mtime); fd->atime.SetUnix(st.st_atime); fd->ctime.SetUnix(st.st_ctime); #endif wcsncpyz(fd->Name,FindMask,ASIZE(fd->Name)); #endif fd->Flags=0; fd->IsDir=IsDir(fd->FileAttr); fd->IsLink=IsLink(fd->FileAttr); return true; } #ifdef _WIN_ALL HANDLE FindFile::Win32Find(HANDLE hFind,const wchar *Mask,FindData *fd) { WIN32_FIND_DATA FindData; if (hFind==INVALID_HANDLE_VALUE) { hFind=FindFirstFile(Mask,&FindData); if (hFind==INVALID_HANDLE_VALUE) { wchar LongMask[NM]; if (GetWinLongPath(Mask,LongMask,ASIZE(LongMask))) hFind=FindFirstFile(LongMask,&FindData); } if (hFind==INVALID_HANDLE_VALUE) { int SysErr=GetLastError(); // We must not issue an error for "file not found" and "path not found", // because it is normal to not find anything for wildcard mask when // archiving. Also searching for non-existent file is normal in some // other modules, like WinRAR scanning for winrar_theme_description.txt // to check if any themes are available. fd->Error=SysErr!=ERROR_FILE_NOT_FOUND && SysErr!=ERROR_PATH_NOT_FOUND && SysErr!=ERROR_NO_MORE_FILES; } } else if (!FindNextFile(hFind,&FindData)) { hFind=INVALID_HANDLE_VALUE; fd->Error=GetLastError()!=ERROR_NO_MORE_FILES; } if (hFind!=INVALID_HANDLE_VALUE) { wcsncpyz(fd->Name,Mask,ASIZE(fd->Name)); SetName(fd->Name,FindData.cFileName,ASIZE(fd->Name)); fd->Size=INT32TO64(FindData.nFileSizeHigh,FindData.nFileSizeLow); fd->FileAttr=FindData.dwFileAttributes; fd->ftCreationTime=FindData.ftCreationTime; fd->ftLastAccessTime=FindData.ftLastAccessTime; fd->ftLastWriteTime=FindData.ftLastWriteTime; fd->mtime.SetWinFT(&FindData.ftLastWriteTime); fd->ctime.SetWinFT(&FindData.ftCreationTime); fd->atime.SetWinFT(&FindData.ftLastAccessTime); } fd->Flags=0; return hFind; } #endif