diff options
Diffstat (limited to '3rdparty/lzma/CPP/Windows/FileFind.cpp')
-rw-r--r-- | 3rdparty/lzma/CPP/Windows/FileFind.cpp | 696 |
1 files changed, 641 insertions, 55 deletions
diff --git a/3rdparty/lzma/CPP/Windows/FileFind.cpp b/3rdparty/lzma/CPP/Windows/FileFind.cpp index 05196f927bd..c562a909ce3 100644 --- a/3rdparty/lzma/CPP/Windows/FileFind.cpp +++ b/3rdparty/lzma/CPP/Windows/FileFind.cpp @@ -2,8 +2,13 @@ #include "StdAfx.h" -#ifndef _UNICODE -#include "../Common/StringConvert.h" +// #include <stdio.h> + +#ifndef _WIN32 +#include <fcntl.h> /* Definition of AT_* constants */ +#include "TimeUtils.h" +// for major +// #include <sys/sysmacros.h> #endif #include "FileFind.h" @@ -34,27 +39,62 @@ typedef struct WCHAR cStreamName[MAX_PATH + 36]; } MY_WIN32_FIND_STREAM_DATA, *MY_PWIN32_FIND_STREAM_DATA; -typedef WINBASEAPI HANDLE (WINAPI *FindFirstStreamW_Ptr)(LPCWSTR fileName, MY_STREAM_INFO_LEVELS infoLevel, +typedef HANDLE (WINAPI *Func_FindFirstStreamW)(LPCWSTR fileName, MY_STREAM_INFO_LEVELS infoLevel, LPVOID findStreamData, DWORD flags); -typedef WINBASEAPI BOOL (APIENTRY *FindNextStreamW_Ptr)(HANDLE findStream, LPVOID findStreamData); +typedef BOOL (APIENTRY *Func_FindNextStreamW)(HANDLE findStream, LPVOID findStreamData); EXTERN_C_END -#endif +#endif // defined(_WIN32) && !defined(UNDER_CE) + namespace NWindows { namespace NFile { -#ifdef SUPPORT_DEVICE_FILE + +#ifdef _WIN32 +#ifdef Z7_DEVICE_FILE namespace NSystem { bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); } #endif +#endif namespace NFind { +/* +#ifdef _WIN32 +#define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0; +#else +#define MY_CLEAR_FILETIME(ft) ft.tv_sec = 0; ft.tv_nsec = 0; +#endif +*/ + +void CFileInfoBase::ClearBase() throw() +{ + Size = 0; + FiTime_Clear(CTime); + FiTime_Clear(ATime); + FiTime_Clear(MTime); + + #ifdef _WIN32 + Attrib = 0; + // ReparseTag = 0; + IsAltStream = false; + IsDevice = false; + #else + dev = 0; + ino = 0; + mode = 0; + nlink = 0; + uid = 0; + gid = 0; + rdev = 0; + #endif +} + bool CFileInfo::IsDots() const throw() { if (!IsDir() || Name.IsEmpty()) @@ -64,12 +104,17 @@ bool CFileInfo::IsDots() const throw() return Name.Len() == 1 || (Name.Len() == 2 && Name[1] == '.'); } + +#ifdef _WIN32 + + #define WIN_FD_TO_MY_FI(fi, fd) \ fi.Attrib = fd.dwFileAttributes; \ fi.CTime = fd.ftCreationTime; \ fi.ATime = fd.ftLastAccessTime; \ fi.MTime = fd.ftLastWriteTime; \ fi.Size = (((UInt64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow; \ + /* fi.ReparseTag = fd.dwReserved0; */ \ fi.IsAltStream = false; \ fi.IsDevice = false; @@ -83,7 +128,7 @@ bool CFileInfo::IsDots() const throw() static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATAW &fd, CFileInfo &fi) { - WIN_FD_TO_MY_FI(fi, fd); + WIN_FD_TO_MY_FI(fi, fd) fi.Name = us2fs(fd.cFileName); #if defined(_WIN32) && !defined(UNDER_CE) // fi.ShortName = us2fs(fd.cAlternateFileName); @@ -91,10 +136,9 @@ static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATAW &fd, CFil } #ifndef _UNICODE - static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATA &fd, CFileInfo &fi) { - WIN_FD_TO_MY_FI(fi, fd); + WIN_FD_TO_MY_FI(fi, fd) fi.Name = fas2fs(fd.cFileName); #if defined(_WIN32) && !defined(UNDER_CE) // fi.ShortName = fas2fs(fd.cAlternateFileName); @@ -143,7 +187,8 @@ WinXP-64 FindFirstFile(): \\Server\Share_RootDrive - ERROR_INVALID_NAME \\Server\Share_RootDrive\ - ERROR_INVALID_NAME - c:\* - ERROR_FILE_NOT_FOUND, if thare are no item in that folder + e:\* - ERROR_FILE_NOT_FOUND, if there are no items in that root folder + w:\* - ERROR_PATH_NOT_FOUND, if there is no such drive w: */ bool CFindFile::FindFirst(CFSTR path, CFileInfo &fi) @@ -166,7 +211,7 @@ bool CFindFile::FindFirst(CFSTR path, CFileInfo &fi) IF_USE_MAIN_PATH _handle = ::FindFirstFileW(fs2us(path), &fd); - #ifdef WIN_LONG_PATH + #ifdef Z7_LONG_PATH if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH) { UString superPath; @@ -207,27 +252,32 @@ bool CFindFile::FindNext(CFileInfo &fi) //////////////////////////////// // AltStreams -static FindFirstStreamW_Ptr g_FindFirstStreamW; -static FindNextStreamW_Ptr g_FindNextStreamW; +static Func_FindFirstStreamW g_FindFirstStreamW; +static Func_FindNextStreamW g_FindNextStreamW; -struct CFindStreamLoader +static struct CFindStreamLoader { CFindStreamLoader() { - g_FindFirstStreamW = (FindFirstStreamW_Ptr)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "FindFirstStreamW"); - g_FindNextStreamW = (FindNextStreamW_Ptr)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "FindNextStreamW"); + const HMODULE hm = ::GetModuleHandleA("kernel32.dll"); + g_FindFirstStreamW = Z7_GET_PROC_ADDRESS( + Func_FindFirstStreamW, hm, + "FindFirstStreamW"); + g_FindNextStreamW = Z7_GET_PROC_ADDRESS( + Func_FindNextStreamW, hm, + "FindNextStreamW"); } } g_FindStreamLoader; bool CStreamInfo::IsMainStream() const throw() { return StringsAreEqualNoCase_Ascii(Name, "::$DATA"); -}; +} UString CStreamInfo::GetReducedName() const { // remove ":$DATA" postfix, but keep postfix, if Name is "::$DATA" - UString s = Name; + UString s (Name); if (s.Len() > 6 + 1 && StringsAreEqualNoCase_Ascii(s.RightPtr(6), ":$DATA")) s.DeleteFrom(s.Len() - 6); return s; @@ -245,7 +295,7 @@ UString CStreamInfo::GetReducedName2() const static void Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(const MY_WIN32_FIND_STREAM_DATA &sd, CStreamInfo &si) { - si.Size = sd.StreamSize.QuadPart; + si.Size = (UInt64)sd.StreamSize.QuadPart; si.Name = sd.cStreamName; } @@ -285,7 +335,7 @@ bool CFindStream::FindFirst(CFSTR path, CStreamInfo &si) if (::GetLastError() == ERROR_HANDLE_EOF) return false; // long name can be tricky for path like ".\dirName". - #ifdef WIN_LONG_PATH + #ifdef Z7_LONG_PATH if (USE_SUPER_PATH) { UString superPath; @@ -336,19 +386,6 @@ bool CStreamEnumerator::Next(CStreamInfo &si, bool &found) #endif -#define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0; - -void CFileInfoBase::ClearBase() throw() -{ - Size = 0; - MY_CLEAR_FILETIME(CTime); - MY_CLEAR_FILETIME(ATime); - MY_CLEAR_FILETIME(MTime); - Attrib = 0; - IsAltStream = false; - IsDevice = false; -} - /* WinXP-64 GetFileAttributes(): If the function fails, it returns INVALID_FILE_ATTRIBUTES and use GetLastError() to get error code @@ -381,7 +418,7 @@ DWORD GetFileAttrib(CFSTR path) if (dw != INVALID_FILE_ATTRIBUTES) return dw; } - #ifdef WIN_LONG_PATH + #ifdef Z7_LONG_PATH if (USE_SUPER_PATH) { UString superPath; @@ -416,9 +453,23 @@ also we support paths that are not supported by FindFirstFile: c::stream - Name = c::stream */ -bool CFileInfo::Find(CFSTR path) +bool CFileInfo::Find(CFSTR path, bool followLink) { - #ifdef SUPPORT_DEVICE_FILE + #ifdef Z7_DEVICE_FILE + + if (IS_PATH_SEPAR(path[0]) && + IS_PATH_SEPAR(path[1]) && + path[2] == '.' && + path[3] == 0) + { + // 22.00 : it's virtual directory for devices + // IsDevice = true; + ClearBase(); + Name = path + 2; + Attrib = FILE_ATTRIBUTE_DIRECTORY; + return true; + } + if (IsDevicePath(path)) { ClearBase(); @@ -449,12 +500,12 @@ bool CFileInfo::Find(CFSTR path) #if defined(_WIN32) && !defined(UNDER_CE) - int colonPos = FindAltStreamColon(path); + const int colonPos = FindAltStreamColon(path); if (colonPos >= 0 && path[(unsigned)colonPos + 1] != 0) { UString streamName = fs2us(path + (unsigned)colonPos); - FString filePath = path; - filePath.DeleteFrom(colonPos); + FString filePath (path); + filePath.DeleteFrom((unsigned)colonPos); /* we allow both cases: name:stream name:stream:$DATA @@ -462,12 +513,12 @@ bool CFileInfo::Find(CFSTR path) const unsigned kPostfixSize = 6; if (streamName.Len() <= kPostfixSize || !StringsAreEqualNoCase_Ascii(streamName.RightPtr(kPostfixSize), ":$DATA")) - streamName += L":$DATA"; + streamName += ":$DATA"; bool isOk = true; if (IsDrivePath2(filePath) && - (colonPos == 2 || colonPos == 3 && filePath[2] == '\\')) + (colonPos == 2 || (colonPos == 3 && filePath[2] == '\\'))) { // FindFirstFile doesn't work for "c:\" and for "c:" (if current dir is ROOT) ClearBase(); @@ -476,11 +527,11 @@ bool CFileInfo::Find(CFSTR path) Name = filePath; } else - isOk = Find(filePath); + isOk = Find(filePath, followLink); // check it (followLink) if (isOk) { - Attrib &= ~(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT); + Attrib &= ~(DWORD)(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT); Size = 0; CStreamEnumerator enumerator(filePath); for (;;) @@ -536,11 +587,15 @@ bool CFileInfo::Find(CFSTR path) ClearBase(); Attrib = attrib; Name = path + rootSize; - Name.DeleteFrom(2); // we don't need backslash (C:) + Name.DeleteFrom(2); + if (!Fill_From_ByHandleFileInfo(path)) + { + } return true; } } else if (IS_PATH_SEPAR(path[0])) + { if (path[1] == 0) { DWORD attrib = GetFileAttrib(path); @@ -559,10 +614,15 @@ bool CFileInfo::Find(CFSTR path) { if (NName::FindSepar(path + prefixSize) < 0) { - FString s = path; + if (Fill_From_ByHandleFileInfo(path)) + { + Name = path + prefixSize; + return true; + } + + FString s (path); s.Add_PathSepar(); - s += FCHAR_ANY_MASK; - + s += '*'; // CHAR_ANY_MASK bool isOK = false; if (finder.FindFirst(s, *this)) { @@ -577,7 +637,7 @@ bool CFileInfo::Find(CFSTR path) } { DWORD attrib = GetFileAttrib(path); - if (isOK || attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) + if (isOK || (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)) { ClearBase(); if (attrib != INVALID_FILE_ATTRIBUTES) @@ -592,23 +652,105 @@ bool CFileInfo::Find(CFSTR path) } } } + } } #endif - return finder.FindFirst(path, *this); + bool res = finder.FindFirst(path, *this); + if (!followLink + || !res + || !HasReparsePoint()) + return res; + + // return FollowReparse(path, IsDir()); + return Fill_From_ByHandleFileInfo(path); } +bool CFileInfoBase::Fill_From_ByHandleFileInfo(CFSTR path) +{ + BY_HANDLE_FILE_INFORMATION info; + if (!NIO::CFileBase::GetFileInformation(path, &info)) + return false; + { + Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; + CTime = info.ftCreationTime; + ATime = info.ftLastAccessTime; + MTime = info.ftLastWriteTime; + Attrib = info.dwFileAttributes; + return true; + } +} -bool DoesFileExist(CFSTR name) +/* +bool CFileInfo::FollowReparse(CFSTR path, bool isDir) +{ + if (isDir) + { + FString prefix = path; + prefix.Add_PathSepar(); + + // "folder/." refers to folder itself. So we can't use that path + // we must use enumerator and search "." item + CEnumerator enumerator; + enumerator.SetDirPrefix(prefix); + for (;;) + { + CFileInfo fi; + if (!enumerator.NextAny(fi)) + break; + if (fi.Name.IsEqualTo_Ascii_NoCase(".")) + { + // we can copy preperies; + CTime = fi.CTime; + ATime = fi.ATime; + MTime = fi.MTime; + Attrib = fi.Attrib; + Size = fi.Size; + return true; + } + break; + } + // LastError(lastError); + return false; + } + + { + NIO::CInFile inFile; + if (inFile.Open(path)) + { + BY_HANDLE_FILE_INFORMATION info; + if (inFile.GetFileInformation(&info)) + { + ClearBase(); + Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; + CTime = info.ftCreationTime; + ATime = info.ftLastAccessTime; + MTime = info.ftLastWriteTime; + Attrib = info.dwFileAttributes; + return true; + } + } + return false; + } +} +*/ + +bool DoesFileExist_Raw(CFSTR name) { CFileInfo fi; return fi.Find(name) && !fi.IsDir(); } -bool DoesDirExist(CFSTR name) +bool DoesFileExist_FollowLink(CFSTR name) +{ + CFileInfo fi; + return fi.Find_FollowLink(name) && !fi.IsDir(); +} + +bool DoesDirExist(CFSTR name, bool followLink) { CFileInfo fi; - return fi.Find(name) && fi.IsDir(); + return fi.Find(name, followLink) && fi.IsDir(); } bool DoesFileOrDirExist(CFSTR name) @@ -618,6 +760,12 @@ bool DoesFileOrDirExist(CFSTR name) } +void CEnumerator::SetDirPrefix(const FString &dirPrefix) +{ + _wildcard = dirPrefix; + _wildcard += '*'; +} + bool CEnumerator::NextAny(CFileInfo &fi) { if (_findFile.IsHandleAllocated()) @@ -639,15 +787,46 @@ bool CEnumerator::Next(CFileInfo &fi) bool CEnumerator::Next(CFileInfo &fi, bool &found) { + /* + for (;;) + { + if (!NextAny(fi)) + break; + if (!fi.IsDots()) + { + found = true; + return true; + } + } + */ + if (Next(fi)) { found = true; return true; } + found = false; - return (::GetLastError() == ERROR_NO_MORE_FILES); + DWORD lastError = ::GetLastError(); + if (_findFile.IsHandleAllocated()) + return (lastError == ERROR_NO_MORE_FILES); + // we support the case for empty root folder: FindFirstFile("c:\\*") returns ERROR_FILE_NOT_FOUND + if (lastError == ERROR_FILE_NOT_FOUND) + return true; + if (lastError == ERROR_ACCESS_DENIED) + { + // here we show inaccessible root system folder as empty folder to eliminate redundant user warnings + const char *s = "System Volume Information" STRING_PATH_SEPARATOR "*"; + const int len = (int)strlen(s); + const int delta = (int)_wildcard.Len() - len; + if (delta == 0 || (delta > 0 && IS_PATH_SEPAR(_wildcard[(unsigned)delta - 1]))) + if (StringsAreEqual_Ascii(_wildcard.Ptr((unsigned)delta), s)) + return true; + } + return false; } + //////////////////////////////// // CFindChangeNotification // FindFirstChangeNotification can return 0. MSDN doesn't tell about it. @@ -672,7 +851,7 @@ HANDLE CFindChangeNotification::FindFirst(CFSTR path, bool watchSubtree, DWORD n { IF_USE_MAIN_PATH _handle = ::FindFirstChangeNotificationW(fs2us(path), BoolToBOOL(watchSubtree), notifyFilter); - #ifdef WIN_LONG_PATH + #ifdef Z7_LONG_PATH if (!IsHandleAllocated()) { UString superPath; @@ -738,6 +917,413 @@ bool MyGetLogicalDriveStrings(CObjectVector<FString> &driveStrings) } } -#endif +#endif // UNDER_CE + + + +#else // _WIN32 + +// ---------- POSIX ---------- + +static int MY__lstat(CFSTR path, struct stat *st, bool followLink) +{ + memset(st, 0, sizeof(*st)); + int res; + // #ifdef ENV_HAVE_LSTAT + if (/* global_use_lstat && */ !followLink) + { + // printf("\nlstat\n"); + res = lstat(path, st); + } + else + // #endif + { + // printf("\nstat\n"); + res = stat(path, st); + } + /* + printf("\nres = %d\n", res); + printf("\n st_dev = %lld \n", (long long)(st->st_dev)); + printf("\n st_ino = %lld \n", (long long)(st->st_ino)); + printf("\n st_mode = %lld \n", (long long)(st->st_mode)); + printf("\n st_nlink = %lld \n", (long long)(st->st_nlink)); + printf("\n st_uid = %lld \n", (long long)(st->st_uid)); + printf("\n st_gid = %lld \n", (long long)(st->st_gid)); + printf("\n st_size = %lld \n", (long long)(st->st_size)); + printf("\n st_blksize = %lld \n", (long long)(st->st_blksize)); + printf("\n st_blocks = %lld \n", (long long)(st->st_blocks)); + */ + + return res; +} + + +static const char *Get_Name_from_Path(CFSTR path) throw() +{ + size_t len = strlen(path); + if (len == 0) + return path; + const char *p = path + len - 1; + { + if (p == path) + return path; + p--; + } + for (;;) + { + char c = *p; + if (IS_PATH_SEPAR(c)) + return p + 1; + if (p == path) + return path; + p--; + } +} + + +UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode) +{ + UInt32 attrib = S_ISDIR(mode) ? + FILE_ATTRIBUTE_DIRECTORY : + FILE_ATTRIBUTE_ARCHIVE; + if ((mode & 0222) == 0) // S_IWUSR in p7zip + attrib |= FILE_ATTRIBUTE_READONLY; + return attrib | FILE_ATTRIBUTE_UNIX_EXTENSION | ((mode & 0xFFFF) << 16); +} + +/* +UInt32 Get_WinAttrib_From_stat(const struct stat &st) +{ + UInt32 attrib = S_ISDIR(st.st_mode) ? + FILE_ATTRIBUTE_DIRECTORY : + FILE_ATTRIBUTE_ARCHIVE; + + if ((st.st_mode & 0222) == 0) // check it !!! + attrib |= FILE_ATTRIBUTE_READONLY; + + attrib |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((st.st_mode & 0xFFFF) << 16); + return attrib; +} +*/ + +void CFileInfo::SetFrom_stat(const struct stat &st) +{ + // IsDevice = false; + + if (S_ISDIR(st.st_mode)) + { + Size = 0; + } + else + { + Size = (UInt64)st.st_size; // for a symbolic link, size = size of filename + } + + // Attrib = Get_WinAttribPosix_From_PosixMode(st.st_mode); + + // NTime::UnixTimeToFileTime(st.st_ctime, CTime); + // NTime::UnixTimeToFileTime(st.st_mtime, MTime); + // NTime::UnixTimeToFileTime(st.st_atime, ATime); + #ifdef __APPLE__ + // #ifdef _DARWIN_FEATURE_64_BIT_INODE + /* + here we can use birthtime instead of st_ctimespec. + but we use st_ctimespec for compatibility with previous versions and p7zip. + st_birthtimespec in OSX + st_birthtim : at FreeBSD, NetBSD + */ + // timespec_To_FILETIME(st.st_birthtimespec, CTime); + // #else + // timespec_To_FILETIME(st.st_ctimespec, CTime); + // #endif + // timespec_To_FILETIME(st.st_mtimespec, MTime); + // timespec_To_FILETIME(st.st_atimespec, ATime); + CTime = st.st_ctimespec; + MTime = st.st_mtimespec; + ATime = st.st_atimespec; + + #else + // timespec_To_FILETIME(st.st_ctim, CTime, &CTime_ns100); + // timespec_To_FILETIME(st.st_mtim, MTime, &MTime_ns100); + // timespec_To_FILETIME(st.st_atim, ATime, &ATime_ns100); + CTime = st.st_ctim; + MTime = st.st_mtim; + ATime = st.st_atim; + + #endif + + dev = st.st_dev; + ino = st.st_ino; + mode = st.st_mode; + nlink = st.st_nlink; + uid = st.st_uid; + gid = st.st_gid; + rdev = st.st_rdev; + + /* + printf("\n sizeof timespec = %d", (int)sizeof(timespec)); + printf("\n sizeof st_rdev = %d", (int)sizeof(rdev)); + printf("\n sizeof st_ino = %d", (int)sizeof(ino)); + printf("\n sizeof mode_t = %d", (int)sizeof(mode_t)); + printf("\n sizeof nlink_t = %d", (int)sizeof(nlink_t)); + printf("\n sizeof uid_t = %d", (int)sizeof(uid_t)); + printf("\n"); + */ + /* + printf("\n st_rdev = %llx", (long long)rdev); + printf("\n st_dev = %llx", (long long)dev); + printf("\n dev : major = %5x minor = %5x", (unsigned)major(dev), (unsigned)minor(dev)); + printf("\n st_ino = %lld", (long long)(ino)); + printf("\n rdev : major = %5x minor = %5x", (unsigned)major(rdev), (unsigned)minor(rdev)); + printf("\n size = %lld \n", (long long)(Size)); + printf("\n"); + */ +} + +/* +int Uid_To_Uname(uid_t uid, AString &name) +{ + name.Empty(); + struct passwd *passwd; + + if (uid != 0 && uid == cached_no_such_uid) + { + *uname = xstrdup (""); + return; + } + + if (!cached_uname || uid != cached_uid) + { + passwd = getpwuid (uid); + if (passwd) + { + cached_uid = uid; + assign_string (&cached_uname, passwd->pw_name); + } + else + { + cached_no_such_uid = uid; + *uname = xstrdup (""); + return; + } + } + *uname = xstrdup (cached_uname); +} +*/ + +bool CFileInfo::Find_DontFill_Name(CFSTR path, bool followLink) +{ + struct stat st; + if (MY__lstat(path, &st, followLink) != 0) + return false; + // printf("\nFind_DontFill_Name : name=%s\n", path); + SetFrom_stat(st); + return true; +} + + +bool CFileInfo::Find(CFSTR path, bool followLink) +{ + // printf("\nCEnumerator::Find() name = %s\n", path); + if (!Find_DontFill_Name(path, followLink)) + return false; + + // printf("\nOK\n"); + + Name = Get_Name_from_Path(path); + if (!Name.IsEmpty()) + { + char c = Name.Back(); + if (IS_PATH_SEPAR(c)) + Name.DeleteBack(); + } + return true; +} + + +bool DoesFileExist_Raw(CFSTR name) +{ + // FIXME for symbolic links. + struct stat st; + if (MY__lstat(name, &st, false) != 0) + return false; + return !S_ISDIR(st.st_mode); +} + +bool DoesFileExist_FollowLink(CFSTR name) +{ + // FIXME for symbolic links. + struct stat st; + if (MY__lstat(name, &st, true) != 0) + return false; + return !S_ISDIR(st.st_mode); +} + +bool DoesDirExist(CFSTR name, bool followLink) +{ + struct stat st; + if (MY__lstat(name, &st, followLink) != 0) + return false; + return S_ISDIR(st.st_mode); +} + +bool DoesFileOrDirExist(CFSTR name) +{ + struct stat st; + if (MY__lstat(name, &st, false) != 0) + return false; + return true; +} + + +CEnumerator::~CEnumerator() +{ + if (_dir) + closedir(_dir); +} + +void CEnumerator::SetDirPrefix(const FString &dirPrefix) +{ + _wildcard = dirPrefix; +} + +bool CDirEntry::IsDots() const throw() +{ + /* some systems (like CentOS 7.x on XFS) have (Type == DT_UNKNOWN) + we can call fstatat() for that case, but we use only (Name) check here */ + + #if !defined(_AIX) + if (Type != DT_DIR && Type != DT_UNKNOWN) + return false; + #endif + + return Name.Len() != 0 + && Name.Len() <= 2 + && Name[0] == '.' + && (Name.Len() == 1 || Name[1] == '.'); +} + + +bool CEnumerator::NextAny(CDirEntry &fi, bool &found) +{ + found = false; + + if (!_dir) + { + const char *w = "./"; + if (!_wildcard.IsEmpty()) + w = _wildcard.Ptr(); + _dir = ::opendir((const char *)w); + if (_dir == NULL) + return false; + } + + // To distinguish end of stream from an error, we must set errno to zero before readdir() + errno = 0; + + struct dirent *de = readdir(_dir); + if (!de) + { + if (errno == 0) + return true; // it's end of stream, and we report it with (found = false) + // it's real error + return false; + } + + fi.iNode = de->d_ino; + + #if !defined(_AIX) + fi.Type = de->d_type; + /* some systems (like CentOS 7.x on XFS) have (Type == DT_UNKNOWN) + we can set (Type) from fstatat() in that case. + But (Type) is not too important. So we don't set it here with slow fstatat() */ + /* + // fi.Type = DT_UNKNOWN; // for debug + if (fi.Type == DT_UNKNOWN) + { + struct stat st; + if (fstatat(dirfd(_dir), de->d_name, &st, AT_SYMLINK_NOFOLLOW) == 0) + if (S_ISDIR(st.st_mode)) + fi.Type = DT_DIR; + } + */ + #endif + + /* + if (de->d_type == DT_DIR) + fi.Attrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_UNIX_EXTENSION | ((UInt32)(S_IFDIR) << 16); + else if (de->d_type < 16) + fi.Attrib = FILE_ATTRIBUTE_UNIX_EXTENSION | ((UInt32)(de->d_type) << (16 + 12)); + */ + fi.Name = de->d_name; + + /* + printf("\nCEnumerator::NextAny; len = %d %s \n", (int)fi.Name.Len(), fi.Name.Ptr()); + for (unsigned i = 0; i < fi.Name.Len(); i++) + printf (" %02x", (unsigned)(Byte)de->d_name[i]); + printf("\n"); + */ + + found = true; + return true; +} + + +bool CEnumerator::Next(CDirEntry &fi, bool &found) +{ + // printf("\nCEnumerator::Next()\n"); + // PrintName("Next", ""); + for (;;) + { + if (!NextAny(fi, found)) + return false; + if (!found) + return true; + if (!fi.IsDots()) + { + /* + if (!NeedFullStat) + return true; + // we silently skip error file here - it can be wrong link item + if (fi.Find_DontFill_Name(path)) + return true; + */ + return true; + } + } +} + +/* +bool CEnumerator::Next(CDirEntry &fileInfo, bool &found) +{ + bool found; + if (!Next(fi, found)) + return false; + return found; +} +*/ + +bool CEnumerator::Fill_FileInfo(const CDirEntry &de, CFileInfo &fileInfo, bool followLink) const +{ + // printf("\nCEnumerator::Fill_FileInfo()\n"); + struct stat st; + // probably it's OK to use fstatat() even if it changes file position dirfd(_dir) + int res = fstatat(dirfd(_dir), de.Name, &st, followLink ? 0 : AT_SYMLINK_NOFOLLOW); + // if fstatat() is not supported, we can use stat() / lstat() + + /* + const FString path = _wildcard + s; + int res = MY__lstat(path, &st, followLink); + */ + + if (res != 0) + return false; + // printf("\nname=%s\n", de.Name.Ptr()); + fileInfo.SetFrom_stat(st); + fileInfo.Name = de.Name; + return true; +} + +#endif // _WIN32 }}} |