static bool DeleteEmptyFolderAndEmptySubFolders(const FString &path) { NFind::CFileInfo fileInfo; FString pathPrefix = path; pathPrefix.Add_PathSepar(); { NFind::CEnumerator enumerator; enumerator.SetDirPrefix(pathPrefix); while (enumerator.Next(fileInfo)) { if (fileInfo.IsDir()) if (!DeleteEmptyFolderAndEmptySubFolders(pathPrefix + fileInfo.Name)) return false; } } /* // we don't need clear readonly for folders if (!SetFileAttrib(path, 0)) return false; */ return RemoveDir(path); }
bool CFileInfo::Find(CFSTR path) { #ifdef SUPPORT_DEVICE_FILE if (IsDevicePath(path)) { ClearBase(); Name = path + 4; IsDevice = true; if (NName::IsDrivePath2(path + 4) && path[6] == 0) { FChar drive[4] = { path[4], ':', '\\', 0 }; UInt64 clusterSize, totalSize, freeSize; if (NSystem::MyGetDiskFreeSpace(drive, clusterSize, totalSize, freeSize)) { Size = totalSize; return true; } } NIO::CInFile inFile; // ::OutputDebugStringW(path); if (!inFile.Open(path)) return false; // ::OutputDebugStringW(L"---"); if (inFile.SizeDefined) Size = inFile.Size; return true; } #endif #if defined(_WIN32) && !defined(UNDER_CE) int colonPos = FindAltStreamColon(path); if (colonPos >= 0 && path[(unsigned)colonPos + 1] != 0) { UString streamName = fs2us(path + (unsigned)colonPos); FString filePath = path; filePath.DeleteFrom(colonPos); /* we allow both cases: name:stream name:stream:$DATA */ const unsigned kPostfixSize = 6; if (streamName.Len() <= kPostfixSize || !StringsAreEqualNoCase_Ascii(streamName.RightPtr(kPostfixSize), ":$DATA")) streamName += L":$DATA"; bool isOk = true; if (IsDrivePath2(filePath) && (colonPos == 2 || colonPos == 3 && filePath[2] == '\\')) { // FindFirstFile doesn't work for "c:\" and for "c:" (if current dir is ROOT) ClearBase(); Name.Empty(); if (colonPos == 2) Name = filePath; } else isOk = Find(filePath); if (isOk) { Attrib &= ~(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT); Size = 0; CStreamEnumerator enumerator(filePath); for (;;) { CStreamInfo si; bool found; if (!enumerator.Next(si, found)) return false; if (!found) { ::SetLastError(ERROR_FILE_NOT_FOUND); return false; } if (si.Name.IsEqualTo_NoCase(streamName)) { // we delete postfix, if alt stream name is not "::$DATA" if (si.Name.Len() > kPostfixSize + 1) si.Name.DeleteFrom(si.Name.Len() - kPostfixSize); Name += us2fs(si.Name); Size = si.Size; IsAltStream = true; return true; } } } } #endif CFindFile finder; #if defined(_WIN32) && !defined(UNDER_CE) { /* DWORD lastError = GetLastError(); if (lastError == ERROR_FILE_NOT_FOUND || lastError == ERROR_BAD_NETPATH // XP64: "\\Server\Share" || lastError == ERROR_BAD_NET_NAME // Win7: "\\Server\Share" || lastError == ERROR_INVALID_NAME // XP64: "\\?\UNC\Server\Share" || lastError == ERROR_BAD_PATHNAME // Win7: "\\?\UNC\Server\Share" ) */ unsigned rootSize = 0; if (IsSuperPath(path)) rootSize = kSuperPathPrefixSize; if (NName::IsDrivePath(path + rootSize) && path[rootSize + 3] == 0) { DWORD attrib = GetFileAttrib(path); if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) { ClearBase(); Attrib = attrib; Name = path + rootSize; Name.DeleteFrom(2); // we don't need backslash (C:) return true; } } else if (IS_PATH_SEPAR(path[0])) if (path[1] == 0) { DWORD attrib = GetFileAttrib(path); if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) { ClearBase(); Name.Empty(); Attrib = attrib; return true; } } else { const unsigned prefixSize = GetNetworkServerPrefixSize(path); if (prefixSize > 0 && path[prefixSize] != 0) { if (NName::FindSepar(path + prefixSize) < 0) { FString s = path; s.Add_PathSepar(); s += FCHAR_ANY_MASK; bool isOK = false; if (finder.FindFirst(s, *this)) { if (Name == FTEXT(".")) { Name = path + prefixSize; return true; } isOK = true; /* if "\\server\share" maps to root folder "d:\", there is no "." item. But it's possible that there are another items */ } { DWORD attrib = GetFileAttrib(path); if (isOK || attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) { ClearBase(); if (attrib != INVALID_FILE_ATTRIBUTES) Attrib = attrib; else SetAsDir(); Name = path + prefixSize; return true; } } // ::SetLastError(lastError); } } } } #endif return finder.FindFirst(path, *this); }
DWORD CDirEnumerator::GetNextFile(NFind::CFileInfo &fi, bool &filled, FString &resPath) { filled = false; resPath.Empty(); for (;;) { #if defined(_WIN32) && !defined(UNDER_CE) bool isRootPrefix = (BasePrefix.IsEmpty() || (NName::IsSuperPath(BasePrefix) && BasePrefix[NName::kSuperPathPrefixSize] == 0)); #endif if (Enumerators.IsEmpty()) { if (Index >= FilePaths.Size()) return S_OK; const FString &path = FilePaths[Index++]; int pos = path.ReverseFind_PathSepar(); if (pos >= 0) resPath.SetFrom(path, pos + 1); #if defined(_WIN32) && !defined(UNDER_CE) if (isRootPrefix && path.Len() == 2 && NName::IsDrivePath2(path)) { // we use "c:" item as directory item fi.ClearBase(); fi.Name = path; fi.SetAsDir(); fi.Size = 0; } else #endif if (!fi.Find(BasePrefix + path)) { DWORD error = GetNormalizedError(); resPath = path; return error; } break; } bool found; if (Enumerators.Back().Next(fi, found)) { if (found) { resPath = Prefixes.Back(); break; } } else { DWORD error = GetNormalizedError(); resPath = Prefixes.Back(); Enumerators.DeleteBack(); Prefixes.DeleteBack(); return error; } Enumerators.DeleteBack(); Prefixes.DeleteBack(); } resPath += fi.Name; if (EnterToDirs && fi.IsDir()) { FString s = resPath; s.Add_PathSepar(); Prefixes.Add(s); s += FCHAR_ANY_MASK; Enumerators.Add(NFind::CEnumerator(BasePrefix + s)); } filled = true; return S_OK; }