// Windows/FileDir.cpp
#include "StdAfx.h"
#ifndef _UNICODE
#include "../Common/StringConvert.h"
#endif
#include "FileDir.h"
#include "FileFind.h"
#include "FileName.h"
#ifndef _UNICODE
extern bool g_IsNT;
#endif
using namespace NWindows;
using namespace NFile;
using namespace NName;
namespace NWindows {
namespace NFile {
namespace NDir {
#ifndef UNDER_CE
bool GetWindowsDir(FString &path)
{
UINT needLength;
#ifndef _UNICODE
if (!g_IsNT)
{
TCHAR s[MAX_PATH + 2 ];
s[0 ] = 0 ;
needLength = ::GetWindowsDirectory(s, MAX_PATH + 1 );
path = fas2fs(s);
}
else
#endif
{
WCHAR s[MAX_PATH + 2 ];
s[0 ] = 0 ;
needLength = ::GetWindowsDirectoryW(s, MAX_PATH + 1 );
path = us2fs(s);
}
return (needLength > 0 && needLength <= MAX_PATH);
}
bool GetSystemDir(FString &path)
{
UINT needLength;
#ifndef _UNICODE
if (!g_IsNT)
{
TCHAR s[MAX_PATH + 2 ];
s[0 ] = 0 ;
needLength = ::GetSystemDirectory(s, MAX_PATH + 1 );
path = fas2fs(s);
}
else
#endif
{
WCHAR s[MAX_PATH + 2 ];
s[0 ] = 0 ;
needLength = ::GetSystemDirectoryW(s, MAX_PATH + 1 );
path = us2fs(s);
}
return (needLength > 0 && needLength <= MAX_PATH);
}
#endif
bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime)
{
#ifndef _UNICODE
if (!g_IsNT)
{
::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return false ;
}
#endif
HANDLE hDir = INVALID_HANDLE_VALUE;
IF_USE_MAIN_PATH
hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
#ifdef WIN_LONG_PATH
if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH)
{
UString superPath;
if (GetSuperPath(path, superPath, USE_MAIN_PATH))
hDir = ::CreateFileW(superPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
}
#endif
bool res = false ;
if (hDir != INVALID_HANDLE_VALUE)
{
res = BOOLToBool(::SetFileTime(hDir, cTime, aTime, mTime));
::CloseHandle(hDir);
}
return res;
}
bool SetFileAttrib(CFSTR path, DWORD attrib)
{
#ifndef _UNICODE
if (!g_IsNT)
{
if (::SetFileAttributes(fs2fas(path), attrib))
return true ;
}
else
#endif
{
IF_USE_MAIN_PATH
if (::SetFileAttributesW(fs2us(path), attrib))
return true ;
#ifdef WIN_LONG_PATH
if (USE_SUPER_PATH)
{
UString superPath;
if (GetSuperPath(path, superPath, USE_MAIN_PATH))
return BOOLToBool(::SetFileAttributesW(superPath, attrib));
}
#endif
}
return false ;
}
bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib)
{
if ((attrib & 0 xF0000000) != 0 )
attrib &= 0 x3FFF;
return SetFileAttrib(path, attrib);
}
bool RemoveDir(CFSTR path)
{
#ifndef _UNICODE
if (!g_IsNT)
{
if (::RemoveDirectory(fs2fas(path)))
return true ;
}
else
#endif
{
IF_USE_MAIN_PATH
if (::RemoveDirectoryW(fs2us(path)))
return true ;
#ifdef WIN_LONG_PATH
if (USE_SUPER_PATH)
{
UString superPath;
if (GetSuperPath(path, superPath, USE_MAIN_PATH))
return BOOLToBool(::RemoveDirectoryW(superPath));
}
#endif
}
return false ;
}
bool MyMoveFile(CFSTR oldFile, CFSTR newFile)
{
#ifndef _UNICODE
if (!g_IsNT)
{
if (::MoveFile(fs2fas(oldFile), fs2fas(newFile)))
return true ;
}
else
#endif
{
IF_USE_MAIN_PATH_2(oldFile, newFile)
if (::MoveFileW(fs2us(oldFile), fs2us(newFile)))
return true ;
#ifdef WIN_LONG_PATH
if (USE_SUPER_PATH_2)
{
UString d1, d2;
if (GetSuperPaths(oldFile, newFile, d1, d2, USE_MAIN_PATH_2))
return BOOLToBool(::MoveFileW(d1, d2));
}
#endif
}
return false ;
}
#ifndef UNDER_CE
EXTERN_C_BEGIN
typedef BOOL (WINAPI *Func_CreateHardLinkW)(
LPCWSTR lpFileName,
LPCWSTR lpExistingFileName,
LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
EXTERN_C_END
bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName)
{
#ifndef _UNICODE
if (!g_IsNT)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return false ;
/*
if ( : : CreateHardLink ( fs2fas ( newFileName ) , fs2fas ( existFileName ) , NULL ) )
return true ;
*/
}
else
#endif
{
Func_CreateHardLinkW my_CreateHardLinkW = (Func_CreateHardLinkW)
::GetProcAddress(::GetModuleHandleW(L"kernel32.dll" ), "CreateHardLinkW" );
if (!my_CreateHardLinkW)
return false ;
IF_USE_MAIN_PATH_2(newFileName, existFileName)
if (my_CreateHardLinkW(fs2us(newFileName), fs2us(existFileName), NULL))
return true ;
#ifdef WIN_LONG_PATH
if (USE_SUPER_PATH_2)
{
UString d1, d2;
if (GetSuperPaths(newFileName, existFileName, d1, d2, USE_MAIN_PATH_2))
return BOOLToBool(my_CreateHardLinkW(d1, d2, NULL));
}
#endif
}
return false ;
}
#endif
/*
WinXP - 64 CreateDir ( ) :
" " - ERROR_PATH_NOT_FOUND
\ - ERROR_ACCESS_DENIED
C : \ - ERROR_ACCESS_DENIED , if there is such drive ,
D : \ folder - ERROR_PATH_NOT_FOUND , if there is no such drive ,
C : \ nonExistent \ folder - ERROR_PATH_NOT_FOUND
C : \ existFolder - ERROR_ALREADY_EXISTS
C : \ existFolder \ - ERROR_ALREADY_EXISTS
C : \ folder - OK
C : \ folder \ - OK
\ \ Server \ nonExistent - ERROR_BAD_NETPATH
\ \ Server \ Share_Readonly - ERROR_ACCESS_DENIED
\ \ Server \ Share - ERROR_ALREADY_EXISTS
\ \ Server \ Share_NTFS_drive - ERROR_ACCESS_DENIED
\ \ Server \ Share_FAT_drive - ERROR_ALREADY_EXISTS
*/
bool CreateDir(CFSTR path)
{
#ifndef _UNICODE
if (!g_IsNT)
{
if (::CreateDirectory(fs2fas(path), NULL))
return true ;
}
else
#endif
{
IF_USE_MAIN_PATH
if (::CreateDirectoryW(fs2us(path), NULL))
return true ;
#ifdef WIN_LONG_PATH
if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH)
{
UString superPath;
if (GetSuperPath(path, superPath, USE_MAIN_PATH))
return BOOLToBool(::CreateDirectoryW(superPath, NULL));
}
#endif
}
return false ;
}
/*
CreateDir2 returns true , if directory can contain files after the call ( two cases ) :
1 ) the directory already exists
2 ) the directory was created
path must be WITHOUT trailing path separator .
We need CreateDir2 , since fileInfo . Find ( ) for reserved names like " com8 "
returns FILE instead of DIRECTORY. And we need to use SuperPath */
static bool CreateDir2(CFSTR path)
{
#ifndef _UNICODE
if (!g_IsNT)
{
if (::CreateDirectory(fs2fas(path), NULL))
return true ;
}
else
#endif
{
IF_USE_MAIN_PATH
if (::CreateDirectoryW(fs2us(path), NULL))
return true ;
#ifdef WIN_LONG_PATH
if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH)
{
UString superPath;
if (GetSuperPath(path, superPath, USE_MAIN_PATH))
{
if (::CreateDirectoryW(superPath, NULL))
return true ;
if (::GetLastError() != ERROR_ALREADY_EXISTS)
return false ;
NFind::CFileInfo fi;
if (!fi.Find(us2fs(superPath)))
return false ;
return fi.IsDir();
}
}
#endif
}
if (::GetLastError() != ERROR_ALREADY_EXISTS)
return false ;
NFind::CFileInfo fi;
if (!fi.Find(path))
return false ;
return fi.IsDir();
}
bool CreateComplexDir(CFSTR _path)
{
#ifdef _WIN32
{
DWORD attrib = NFind::GetFileAttrib(_path);
if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 )
return true ;
}
#ifndef UNDER_CE
if (IsDriveRootPath_SuperAllowed(_path))
return false ;
unsigned prefixSize = GetRootPrefixSize(_path);
#endif
#endif
FString path (_path);
int pos = path.ReverseFind_PathSepar();
if (pos >= 0 && (unsigned )pos == path.Len() - 1 )
{
if (path.Len() == 1 )
return true ;
path.DeleteBack();
}
const FString path2 (path);
pos = path.Len();
for (;;)
{
if (CreateDir2(path))
break ;
if (::GetLastError() == ERROR_ALREADY_EXISTS)
return false ;
pos = path.ReverseFind_PathSepar();
if (pos < 0 || pos == 0 )
return false ;
#if defined (_WIN32) && !defined (UNDER_CE)
if (pos == 1 && IS_PATH_SEPAR(path[0 ]))
return false ;
if (prefixSize >= (unsigned )pos + 1 )
return false ;
#endif
path.DeleteFrom(pos);
}
while (pos < (int )path2.Len())
{
int pos2 = NName::FindSepar(path2.Ptr(pos + 1 ));
if (pos2 < 0 )
pos = path2.Len();
else
pos += 1 + pos2;
path.SetFrom(path2, pos);
if (!CreateDir(path))
return false ;
}
return true ;
}
bool DeleteFileAlways(CFSTR path)
{
/* If alt stream, we also need to clear READ-ONLY attribute of main file before delete.
SetFileAttrib("name:stream", ) changes attributes of main file. */
{
DWORD attrib = NFind::GetFileAttrib(path);
if (attrib != INVALID_FILE_ATTRIBUTES
&& (attrib & FILE_ATTRIBUTE_DIRECTORY) == 0
&& (attrib & FILE_ATTRIBUTE_READONLY) != 0 )
{
if (!SetFileAttrib(path, attrib & ~FILE_ATTRIBUTE_READONLY))
return false ;
}
}
#ifndef _UNICODE
if (!g_IsNT)
{
if (::DeleteFile(fs2fas(path)))
return true ;
}
else
#endif
{
/* DeleteFile("name::$DATA") deletes all alt streams (same as delete DeleteFile("name")).
Maybe it's better to open "name::$DATA" and clear data for unnamed stream? */
IF_USE_MAIN_PATH
if (::DeleteFileW(fs2us(path)))
return true ;
#ifdef WIN_LONG_PATH
if (USE_SUPER_PATH)
{
UString superPath;
if (GetSuperPath(path, superPath, USE_MAIN_PATH))
return BOOLToBool(::DeleteFileW(superPath));
}
#endif
}
return false ;
}
bool RemoveDirWithSubItems(const FString &path)
{
bool needRemoveSubItems = true ;
{
NFind::CFileInfo fi;
if (!fi.Find(path))
return false ;
if (!fi.IsDir())
{
::SetLastError(ERROR_DIRECTORY);
return false ;
}
if (fi.HasReparsePoint())
needRemoveSubItems = false ;
}
if (needRemoveSubItems)
{
FString s (path);
s.Add_PathSepar();
const unsigned prefixSize = s.Len();
NFind::CEnumerator enumerator;
enumerator.SetDirPrefix(s);
NFind::CFileInfo fi;
while (enumerator.Next(fi))
{
s.DeleteFrom(prefixSize);
s += fi.Name;
if (fi.IsDir())
{
if (!RemoveDirWithSubItems(s))
return false ;
}
else if (!DeleteFileAlways(s))
return false ;
}
}
if (!SetFileAttrib(path, 0 ))
return false ;
return RemoveDir(path);
}
#ifdef UNDER_CE
bool MyGetFullPathName(CFSTR path, FString &resFullPath)
{
resFullPath = path;
return true ;
}
#else
bool MyGetFullPathName(CFSTR path, FString &resFullPath)
{
return GetFullPath(path, resFullPath);
}
bool SetCurrentDir(CFSTR path)
{
// SetCurrentDirectory doesn't support \\?\ prefix
#ifndef _UNICODE
if (!g_IsNT)
{
return BOOLToBool(::SetCurrentDirectory(fs2fas(path)));
}
else
#endif
{
return BOOLToBool(::SetCurrentDirectoryW(fs2us(path)));
}
}
bool GetCurrentDir(FString &path)
{
path.Empty();
DWORD needLength;
#ifndef _UNICODE
if (!g_IsNT)
{
TCHAR s[MAX_PATH + 2 ];
s[0 ] = 0 ;
needLength = ::GetCurrentDirectory(MAX_PATH + 1 , s);
path = fas2fs(s);
}
else
#endif
{
WCHAR s[MAX_PATH + 2 ];
s[0 ] = 0 ;
needLength = ::GetCurrentDirectoryW(MAX_PATH + 1 , s);
path = us2fs(s);
}
return (needLength > 0 && needLength <= MAX_PATH);
}
#endif
bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName)
{
bool res = MyGetFullPathName(path, resDirPrefix);
if (!res)
resDirPrefix = path;
int pos = resDirPrefix.ReverseFind_PathSepar();
resFileName = resDirPrefix.Ptr(pos + 1 );
resDirPrefix.DeleteFrom(pos + 1 );
return res;
}
bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix)
{
FString resFileName;
return GetFullPathAndSplit(path, resDirPrefix, resFileName);
}
bool MyGetTempPath(FString &path)
{
path.Empty();
DWORD needLength;
#ifndef _UNICODE
if (!g_IsNT)
{
TCHAR s[MAX_PATH + 2 ];
s[0 ] = 0 ;
needLength = ::GetTempPath(MAX_PATH + 1 , s);
path = fas2fs(s);
}
else
#endif
{
WCHAR s[MAX_PATH + 2 ];
s[0 ] = 0 ;
needLength = ::GetTempPathW(MAX_PATH + 1 , s);;
path = us2fs(s);
}
return (needLength > 0 && needLength <= MAX_PATH);
}
static bool CreateTempFile(CFSTR prefix, bool addRandom, FString &path, NIO::COutFile *outFile)
{
UInt32 d = (GetTickCount() << 12 ) ^ (GetCurrentThreadId() << 14 ) ^ GetCurrentProcessId();
for (unsigned i = 0 ; i < 100 ; i++)
{
path = prefix;
if (addRandom)
{
char s[16 ];
UInt32 val = d;
unsigned k;
for (k = 0 ; k < 8 ; k++)
{
unsigned t = val & 0 xF;
val >>= 4 ;
s[k] = (char )((t < 10 ) ? ('0' + t) : ('A' + (t - 10 )));
}
s[k] = '\0' ;
if (outFile)
path += '.' ;
path += s;
UInt32 step = GetTickCount() + 2 ;
if (step == 0 )
step = 1 ;
d += step;
}
addRandom = true ;
if (outFile)
path += ".tmp" ;
if (NFind::DoesFileOrDirExist(path))
{
SetLastError(ERROR_ALREADY_EXISTS);
continue ;
}
if (outFile)
{
if (outFile->Create(path, false ))
return true ;
}
else
{
if (CreateDir(path))
return true ;
}
DWORD error = GetLastError();
if (error != ERROR_FILE_EXISTS &&
error != ERROR_ALREADY_EXISTS)
break ;
}
path.Empty();
return false ;
}
bool CTempFile::Create(CFSTR prefix, NIO::COutFile *outFile)
{
if (!Remove())
return false ;
if (!CreateTempFile(prefix, false , _path, outFile))
return false ;
_mustBeDeleted = true ;
return true ;
}
bool CTempFile::CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile)
{
if (!Remove())
return false ;
FString tempPath;
if (!MyGetTempPath(tempPath))
return false ;
if (!CreateTempFile(tempPath + namePrefix, true , _path, outFile))
return false ;
_mustBeDeleted = true ;
return true ;
}
bool CTempFile::Remove()
{
if (!_mustBeDeleted)
return true ;
_mustBeDeleted = !DeleteFileAlways(_path);
return !_mustBeDeleted;
}
bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore)
{
// DWORD attrib = 0;
if (deleteDestBefore)
{
if (NFind::DoesFileExist(name))
{
// attrib = NFind::GetFileAttrib(name);
if (!DeleteFileAlways(name))
return false ;
}
}
DisableDeleting();
return MyMoveFile(_path, name);
/*
if ( attrib ! = INVALID_FILE_ATTRIBUTES & & ( attrib & FILE_ATTRIBUTE_READONLY ) )
{
DWORD attrib2 = NFind : : GetFileAttrib ( name ) ;
if ( attrib2 ! = INVALID_FILE_ATTRIBUTES )
SetFileAttrib ( name , attrib2 | FILE_ATTRIBUTE_READONLY ) ;
}
*/
}
bool CTempDir::Create(CFSTR prefix)
{
if (!Remove())
return false ;
FString tempPath;
if (!MyGetTempPath(tempPath))
return false ;
if (!CreateTempFile(tempPath + prefix, true , _path, NULL))
return false ;
_mustBeDeleted = true ;
return true ;
}
bool CTempDir::Remove()
{
if (!_mustBeDeleted)
return true ;
_mustBeDeleted = !RemoveDirWithSubItems(_path);
return !_mustBeDeleted;
}
}}}
Messung V0.5 in Prozent C=99 H=98 G=98
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-10-04)
¤
*© Formatika GbR, Deutschland