aboutsummaryrefslogtreecommitdiff
path: root/CPP/Windows/FileDir.cpp
diff options
context:
space:
mode:
authorIgor Pavlov <87184205+ip7z@users.noreply.github.com>2021-12-27 00:00:00 +0000
committerIgor Pavlov <87184205+ip7z@users.noreply.github.com>2022-03-18 15:35:13 +0500
commitf19f813537c7aea1c20749c914e756b54a9c3cf5 (patch)
tree816ba62ca7c0fa19f2eb46d9e9d6f7dd7c3a744d /CPP/Windows/FileDir.cpp
parent98e06a519b63b81986abe76d28887f6984a7732b (diff)
download7zip-21.07.tar.gz
7zip-21.07.tar.bz2
7zip-21.07.zip
'21.07'21.07
Diffstat (limited to 'CPP/Windows/FileDir.cpp')
-rw-r--r--CPP/Windows/FileDir.cpp1129
1 files changed, 1129 insertions, 0 deletions
diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp
new file mode 100644
index 0000000..8a33fc8
--- /dev/null
+++ b/CPP/Windows/FileDir.cpp
@@ -0,0 +1,1129 @@
1// Windows/FileDir.cpp
2
3#include "StdAfx.h"
4
5
6#ifndef _WIN32
7#include <stdio.h>
8#include <stdlib.h>
9#include <errno.h>
10#include <limits.h>
11#include <unistd.h>
12#include <time.h>
13#include <utime.h>
14#include <fcntl.h>
15#include <sys/stat.h>
16#include <sys/types.h>
17
18#include "../Common/StringConvert.h"
19#include "../Common/C_FileIO.h"
20#include "TimeUtils.h"
21#endif
22
23#include "FileDir.h"
24#include "FileFind.h"
25#include "FileName.h"
26
27#ifndef _UNICODE
28extern bool g_IsNT;
29#endif
30
31using namespace NWindows;
32using namespace NFile;
33using namespace NName;
34
35namespace NWindows {
36namespace NFile {
37namespace NDir {
38
39#ifdef _WIN32
40
41#ifndef UNDER_CE
42
43bool GetWindowsDir(FString &path)
44{
45 UINT needLength;
46 #ifndef _UNICODE
47 if (!g_IsNT)
48 {
49 TCHAR s[MAX_PATH + 2];
50 s[0] = 0;
51 needLength = ::GetWindowsDirectory(s, MAX_PATH + 1);
52 path = fas2fs(s);
53 }
54 else
55 #endif
56 {
57 WCHAR s[MAX_PATH + 2];
58 s[0] = 0;
59 needLength = ::GetWindowsDirectoryW(s, MAX_PATH + 1);
60 path = us2fs(s);
61 }
62 return (needLength > 0 && needLength <= MAX_PATH);
63}
64
65bool GetSystemDir(FString &path)
66{
67 UINT needLength;
68 #ifndef _UNICODE
69 if (!g_IsNT)
70 {
71 TCHAR s[MAX_PATH + 2];
72 s[0] = 0;
73 needLength = ::GetSystemDirectory(s, MAX_PATH + 1);
74 path = fas2fs(s);
75 }
76 else
77 #endif
78 {
79 WCHAR s[MAX_PATH + 2];
80 s[0] = 0;
81 needLength = ::GetSystemDirectoryW(s, MAX_PATH + 1);
82 path = us2fs(s);
83 }
84 return (needLength > 0 && needLength <= MAX_PATH);
85}
86#endif // UNDER_CE
87
88
89bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime)
90{
91 #ifndef _UNICODE
92 if (!g_IsNT)
93 {
94 ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
95 return false;
96 }
97 #endif
98
99 HANDLE hDir = INVALID_HANDLE_VALUE;
100 IF_USE_MAIN_PATH
101 hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
102 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
103 #ifdef WIN_LONG_PATH
104 if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH)
105 {
106 UString superPath;
107 if (GetSuperPath(path, superPath, USE_MAIN_PATH))
108 hDir = ::CreateFileW(superPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
109 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
110 }
111 #endif
112
113 bool res = false;
114 if (hDir != INVALID_HANDLE_VALUE)
115 {
116 res = BOOLToBool(::SetFileTime(hDir, cTime, aTime, mTime));
117 ::CloseHandle(hDir);
118 }
119 return res;
120}
121
122
123
124bool SetFileAttrib(CFSTR path, DWORD attrib)
125{
126 #ifndef _UNICODE
127 if (!g_IsNT)
128 {
129 if (::SetFileAttributes(fs2fas(path), attrib))
130 return true;
131 }
132 else
133 #endif
134 {
135 IF_USE_MAIN_PATH
136 if (::SetFileAttributesW(fs2us(path), attrib))
137 return true;
138 #ifdef WIN_LONG_PATH
139 if (USE_SUPER_PATH)
140 {
141 UString superPath;
142 if (GetSuperPath(path, superPath, USE_MAIN_PATH))
143 return BOOLToBool(::SetFileAttributesW(superPath, attrib));
144 }
145 #endif
146 }
147 return false;
148}
149
150
151bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib)
152{
153 #ifdef _WIN32
154 if ((attrib & 0xF0000000) != 0)
155 attrib &= 0x3FFF;
156 #endif
157 return SetFileAttrib(path, attrib);
158}
159
160
161bool RemoveDir(CFSTR path)
162{
163 #ifndef _UNICODE
164 if (!g_IsNT)
165 {
166 if (::RemoveDirectory(fs2fas(path)))
167 return true;
168 }
169 else
170 #endif
171 {
172 IF_USE_MAIN_PATH
173 if (::RemoveDirectoryW(fs2us(path)))
174 return true;
175 #ifdef WIN_LONG_PATH
176 if (USE_SUPER_PATH)
177 {
178 UString superPath;
179 if (GetSuperPath(path, superPath, USE_MAIN_PATH))
180 return BOOLToBool(::RemoveDirectoryW(superPath));
181 }
182 #endif
183 }
184 return false;
185}
186
187
188bool MyMoveFile(CFSTR oldFile, CFSTR newFile)
189{
190 #ifndef _UNICODE
191 if (!g_IsNT)
192 {
193 if (::MoveFile(fs2fas(oldFile), fs2fas(newFile)))
194 return true;
195 }
196 else
197 #endif
198 {
199 IF_USE_MAIN_PATH_2(oldFile, newFile)
200 {
201 if (::MoveFileW(fs2us(oldFile), fs2us(newFile)))
202 return true;
203 }
204 #ifdef WIN_LONG_PATH
205 if (USE_SUPER_PATH_2)
206 {
207 UString d1, d2;
208 if (GetSuperPaths(oldFile, newFile, d1, d2, USE_MAIN_PATH_2))
209 return BOOLToBool(::MoveFileW(d1, d2));
210 }
211 #endif
212 }
213 return false;
214}
215
216#ifndef UNDER_CE
217EXTERN_C_BEGIN
218typedef BOOL (WINAPI *Func_CreateHardLinkW)(
219 LPCWSTR lpFileName,
220 LPCWSTR lpExistingFileName,
221 LPSECURITY_ATTRIBUTES lpSecurityAttributes
222 );
223EXTERN_C_END
224#endif // UNDER_CE
225
226bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName)
227{
228 #ifndef _UNICODE
229 if (!g_IsNT)
230 {
231 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
232 return false;
233 /*
234 if (::CreateHardLink(fs2fas(newFileName), fs2fas(existFileName), NULL))
235 return true;
236 */
237 }
238 else
239 #endif
240 {
241 Func_CreateHardLinkW my_CreateHardLinkW = (Func_CreateHardLinkW)
242 (void *)::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW");
243 if (!my_CreateHardLinkW)
244 return false;
245 IF_USE_MAIN_PATH_2(newFileName, existFileName)
246 {
247 if (my_CreateHardLinkW(fs2us(newFileName), fs2us(existFileName), NULL))
248 return true;
249 }
250 #ifdef WIN_LONG_PATH
251 if (USE_SUPER_PATH_2)
252 {
253 UString d1, d2;
254 if (GetSuperPaths(newFileName, existFileName, d1, d2, USE_MAIN_PATH_2))
255 return BOOLToBool(my_CreateHardLinkW(d1, d2, NULL));
256 }
257 #endif
258 }
259 return false;
260}
261
262
263/*
264WinXP-64 CreateDir():
265 "" - ERROR_PATH_NOT_FOUND
266 \ - ERROR_ACCESS_DENIED
267 C:\ - ERROR_ACCESS_DENIED, if there is such drive,
268
269 D:\folder - ERROR_PATH_NOT_FOUND, if there is no such drive,
270 C:\nonExistent\folder - ERROR_PATH_NOT_FOUND
271
272 C:\existFolder - ERROR_ALREADY_EXISTS
273 C:\existFolder\ - ERROR_ALREADY_EXISTS
274
275 C:\folder - OK
276 C:\folder\ - OK
277
278 \\Server\nonExistent - ERROR_BAD_NETPATH
279 \\Server\Share_Readonly - ERROR_ACCESS_DENIED
280 \\Server\Share - ERROR_ALREADY_EXISTS
281
282 \\Server\Share_NTFS_drive - ERROR_ACCESS_DENIED
283 \\Server\Share_FAT_drive - ERROR_ALREADY_EXISTS
284*/
285
286bool CreateDir(CFSTR path)
287{
288 #ifndef _UNICODE
289 if (!g_IsNT)
290 {
291 if (::CreateDirectory(fs2fas(path), NULL))
292 return true;
293 }
294 else
295 #endif
296 {
297 IF_USE_MAIN_PATH
298 if (::CreateDirectoryW(fs2us(path), NULL))
299 return true;
300 #ifdef WIN_LONG_PATH
301 if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH)
302 {
303 UString superPath;
304 if (GetSuperPath(path, superPath, USE_MAIN_PATH))
305 return BOOLToBool(::CreateDirectoryW(superPath, NULL));
306 }
307 #endif
308 }
309 return false;
310}
311
312/*
313 CreateDir2 returns true, if directory can contain files after the call (two cases):
314 1) the directory already exists
315 2) the directory was created
316 path must be WITHOUT trailing path separator.
317
318 We need CreateDir2, since fileInfo.Find() for reserved names like "com8"
319 returns FILE instead of DIRECTORY. And we need to use SuperPath */
320
321static bool CreateDir2(CFSTR path)
322{
323 #ifndef _UNICODE
324 if (!g_IsNT)
325 {
326 if (::CreateDirectory(fs2fas(path), NULL))
327 return true;
328 }
329 else
330 #endif
331 {
332 IF_USE_MAIN_PATH
333 if (::CreateDirectoryW(fs2us(path), NULL))
334 return true;
335 #ifdef WIN_LONG_PATH
336 if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH)
337 {
338 UString superPath;
339 if (GetSuperPath(path, superPath, USE_MAIN_PATH))
340 {
341 if (::CreateDirectoryW(superPath, NULL))
342 return true;
343 if (::GetLastError() != ERROR_ALREADY_EXISTS)
344 return false;
345 NFind::CFileInfo fi;
346 if (!fi.Find(us2fs(superPath)))
347 return false;
348 return fi.IsDir();
349 }
350 }
351 #endif
352 }
353 if (::GetLastError() != ERROR_ALREADY_EXISTS)
354 return false;
355 NFind::CFileInfo fi;
356 if (!fi.Find(path))
357 return false;
358 return fi.IsDir();
359}
360
361#endif // _WIN32
362
363static bool CreateDir2(CFSTR path);
364
365bool CreateComplexDir(CFSTR _path)
366{
367 #ifdef _WIN32
368
369 {
370 DWORD attrib = NFind::GetFileAttrib(_path);
371 if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
372 return true;
373 }
374
375 #ifndef UNDER_CE
376
377 if (IsDriveRootPath_SuperAllowed(_path))
378 return false;
379
380 const unsigned prefixSize = GetRootPrefixSize(_path);
381
382 #endif // UNDER_CE
383
384 #else // _WIN32
385
386 // Posix
387 NFind::CFileInfo fi;
388 if (fi.Find(_path))
389 {
390 if (fi.IsDir())
391 return true;
392 }
393
394 #endif // _WIN32
395
396 FString path (_path);
397
398 int pos = path.ReverseFind_PathSepar();
399 if (pos >= 0 && (unsigned)pos == path.Len() - 1)
400 {
401 if (path.Len() == 1)
402 return true;
403 path.DeleteBack();
404 }
405
406 const FString path2 (path);
407 pos = (int)path.Len();
408
409 for (;;)
410 {
411 if (CreateDir2(path))
412 break;
413 if (::GetLastError() == ERROR_ALREADY_EXISTS)
414 return false;
415 pos = path.ReverseFind_PathSepar();
416 if (pos < 0 || pos == 0)
417 return false;
418
419 #if defined(_WIN32) && !defined(UNDER_CE)
420 if (pos == 1 && IS_PATH_SEPAR(path[0]))
421 return false;
422 if (prefixSize >= (unsigned)pos + 1)
423 return false;
424 #endif
425
426 path.DeleteFrom((unsigned)pos);
427 }
428
429 while (pos < (int)path2.Len())
430 {
431 int pos2 = NName::FindSepar(path2.Ptr((unsigned)pos + 1));
432 if (pos2 < 0)
433 pos = (int)path2.Len();
434 else
435 pos += 1 + pos2;
436 path.SetFrom(path2, (unsigned)pos);
437 if (!CreateDir(path))
438 return false;
439 }
440
441 return true;
442}
443
444
445#ifdef _WIN32
446
447bool DeleteFileAlways(CFSTR path)
448{
449 /* If alt stream, we also need to clear READ-ONLY attribute of main file before delete.
450 SetFileAttrib("name:stream", ) changes attributes of main file. */
451 {
452 DWORD attrib = NFind::GetFileAttrib(path);
453 if (attrib != INVALID_FILE_ATTRIBUTES
454 && (attrib & FILE_ATTRIBUTE_DIRECTORY) == 0
455 && (attrib & FILE_ATTRIBUTE_READONLY) != 0)
456 {
457 if (!SetFileAttrib(path, attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY))
458 return false;
459 }
460 }
461
462 #ifndef _UNICODE
463 if (!g_IsNT)
464 {
465 if (::DeleteFile(fs2fas(path)))
466 return true;
467 }
468 else
469 #endif
470 {
471 /* DeleteFile("name::$DATA") deletes all alt streams (same as delete DeleteFile("name")).
472 Maybe it's better to open "name::$DATA" and clear data for unnamed stream? */
473 IF_USE_MAIN_PATH
474 if (::DeleteFileW(fs2us(path)))
475 return true;
476 #ifdef WIN_LONG_PATH
477 if (USE_SUPER_PATH)
478 {
479 UString superPath;
480 if (GetSuperPath(path, superPath, USE_MAIN_PATH))
481 return BOOLToBool(::DeleteFileW(superPath));
482 }
483 #endif
484 }
485 return false;
486}
487
488
489
490bool RemoveDirWithSubItems(const FString &path)
491{
492 bool needRemoveSubItems = true;
493 {
494 NFind::CFileInfo fi;
495 if (!fi.Find(path))
496 return false;
497 if (!fi.IsDir())
498 {
499 ::SetLastError(ERROR_DIRECTORY);
500 return false;
501 }
502 if (fi.HasReparsePoint())
503 needRemoveSubItems = false;
504 }
505
506 if (needRemoveSubItems)
507 {
508 FString s (path);
509 s.Add_PathSepar();
510 const unsigned prefixSize = s.Len();
511 NFind::CEnumerator enumerator;
512 enumerator.SetDirPrefix(s);
513 NFind::CDirEntry fi;
514 bool isError = false;
515 DWORD lastError = 0;
516 while (enumerator.Next(fi))
517 {
518 s.DeleteFrom(prefixSize);
519 s += fi.Name;
520 if (fi.IsDir())
521 {
522 if (!RemoveDirWithSubItems(s))
523 {
524 lastError = GetLastError();
525 isError = true;
526 }
527 }
528 else if (!DeleteFileAlways(s))
529 {
530 lastError = GetLastError();
531 isError = false;
532 }
533 }
534 if (isError)
535 {
536 SetLastError(lastError);
537 return false;
538 }
539 }
540
541 // we clear read-only attrib to remove read-only dir
542 if (!SetFileAttrib(path, 0))
543 return false;
544 return RemoveDir(path);
545}
546
547#endif // _WIN32
548
549#ifdef UNDER_CE
550
551bool MyGetFullPathName(CFSTR path, FString &resFullPath)
552{
553 resFullPath = path;
554 return true;
555}
556
557#else
558
559bool MyGetFullPathName(CFSTR path, FString &resFullPath)
560{
561 return GetFullPath(path, resFullPath);
562}
563
564#ifdef _WIN32
565
566bool SetCurrentDir(CFSTR path)
567{
568 // SetCurrentDirectory doesn't support \\?\ prefix
569 #ifndef _UNICODE
570 if (!g_IsNT)
571 {
572 return BOOLToBool(::SetCurrentDirectory(fs2fas(path)));
573 }
574 else
575 #endif
576 {
577 return BOOLToBool(::SetCurrentDirectoryW(fs2us(path)));
578 }
579}
580
581
582bool GetCurrentDir(FString &path)
583{
584 path.Empty();
585
586 DWORD needLength;
587 #ifndef _UNICODE
588 if (!g_IsNT)
589 {
590 TCHAR s[MAX_PATH + 2];
591 s[0] = 0;
592 needLength = ::GetCurrentDirectory(MAX_PATH + 1, s);
593 path = fas2fs(s);
594 }
595 else
596 #endif
597 {
598 WCHAR s[MAX_PATH + 2];
599 s[0] = 0;
600 needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, s);
601 path = us2fs(s);
602 }
603 return (needLength > 0 && needLength <= MAX_PATH);
604}
605
606#endif // _WIN32
607#endif // UNDER_CE
608
609
610bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName)
611{
612 bool res = MyGetFullPathName(path, resDirPrefix);
613 if (!res)
614 resDirPrefix = path;
615 int pos = resDirPrefix.ReverseFind_PathSepar();
616 pos++;
617 resFileName = resDirPrefix.Ptr((unsigned)pos);
618 resDirPrefix.DeleteFrom((unsigned)pos);
619 return res;
620}
621
622bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix)
623{
624 FString resFileName;
625 return GetFullPathAndSplit(path, resDirPrefix, resFileName);
626}
627
628bool MyGetTempPath(FString &path)
629{
630 #ifdef _WIN32
631 path.Empty();
632 DWORD needLength;
633 #ifndef _UNICODE
634 if (!g_IsNT)
635 {
636 TCHAR s[MAX_PATH + 2];
637 s[0] = 0;
638 needLength = ::GetTempPath(MAX_PATH + 1, s);
639 path = fas2fs(s);
640 }
641 else
642 #endif
643 {
644 WCHAR s[MAX_PATH + 2];
645 s[0] = 0;
646 needLength = ::GetTempPathW(MAX_PATH + 1, s);;
647 path = us2fs(s);
648 }
649 return (needLength > 0 && needLength <= MAX_PATH);
650
651 #else
652
653 // FIXME: improve that code
654 path = "/tmp/";
655 if (!NFind::DoesDirExist_FollowLink(path))
656 path = "./";
657 return true;
658 #endif
659}
660
661
662static bool CreateTempFile(CFSTR prefix, bool addRandom, FString &path, NIO::COutFile *outFile)
663{
664 UInt32 d =
665 #ifdef _WIN32
666 (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId();
667 #else
668 (UInt32)(time(NULL) << 12) ^ ((UInt32)getppid() << 14) ^ (UInt32)(getpid());
669 #endif
670
671 for (unsigned i = 0; i < 100; i++)
672 {
673 path = prefix;
674 if (addRandom)
675 {
676 char s[16];
677 UInt32 val = d;
678 unsigned k;
679 for (k = 0; k < 8; k++)
680 {
681 unsigned t = val & 0xF;
682 val >>= 4;
683 s[k] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
684 }
685 s[k] = '\0';
686 if (outFile)
687 path += '.';
688 path += s;
689 UInt32 step = GetTickCount() + 2;
690 if (step == 0)
691 step = 1;
692 d += step;
693 }
694 addRandom = true;
695 if (outFile)
696 path += ".tmp";
697 if (NFind::DoesFileOrDirExist(path))
698 {
699 SetLastError(ERROR_ALREADY_EXISTS);
700 continue;
701 }
702 if (outFile)
703 {
704 if (outFile->Create(path, false))
705 return true;
706 }
707 else
708 {
709 if (CreateDir(path))
710 return true;
711 }
712 DWORD error = GetLastError();
713 if (error != ERROR_FILE_EXISTS &&
714 error != ERROR_ALREADY_EXISTS)
715 break;
716 }
717 path.Empty();
718 return false;
719}
720
721bool CTempFile::Create(CFSTR prefix, NIO::COutFile *outFile)
722{
723 if (!Remove())
724 return false;
725 if (!CreateTempFile(prefix, false, _path, outFile))
726 return false;
727 _mustBeDeleted = true;
728 return true;
729}
730
731bool CTempFile::CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile)
732{
733 if (!Remove())
734 return false;
735 FString tempPath;
736 if (!MyGetTempPath(tempPath))
737 return false;
738 if (!CreateTempFile(tempPath + namePrefix, true, _path, outFile))
739 return false;
740 _mustBeDeleted = true;
741 return true;
742}
743
744bool CTempFile::Remove()
745{
746 if (!_mustBeDeleted)
747 return true;
748 _mustBeDeleted = !DeleteFileAlways(_path);
749 return !_mustBeDeleted;
750}
751
752bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore)
753{
754 // DWORD attrib = 0;
755 if (deleteDestBefore)
756 {
757 if (NFind::DoesFileExist_Raw(name))
758 {
759 // attrib = NFind::GetFileAttrib(name);
760 if (!DeleteFileAlways(name))
761 return false;
762 }
763 }
764 DisableDeleting();
765 return MyMoveFile(_path, name);
766
767 /*
768 if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY))
769 {
770 DWORD attrib2 = NFind::GetFileAttrib(name);
771 if (attrib2 != INVALID_FILE_ATTRIBUTES)
772 SetFileAttrib(name, attrib2 | FILE_ATTRIBUTE_READONLY);
773 }
774 */
775}
776
777#ifdef _WIN32
778bool CTempDir::Create(CFSTR prefix)
779{
780 if (!Remove())
781 return false;
782 FString tempPath;
783 if (!MyGetTempPath(tempPath))
784 return false;
785 if (!CreateTempFile(tempPath + prefix, true, _path, NULL))
786 return false;
787 _mustBeDeleted = true;
788 return true;
789}
790
791bool CTempDir::Remove()
792{
793 if (!_mustBeDeleted)
794 return true;
795 _mustBeDeleted = !RemoveDirWithSubItems(_path);
796 return !_mustBeDeleted;
797}
798#endif
799
800
801
802#ifndef _WIN32
803
804bool RemoveDir(CFSTR path)
805{
806 return (rmdir(path) == 0);
807}
808
809
810static BOOL My__CopyFile(CFSTR oldFile, CFSTR newFile)
811{
812 NWindows::NFile::NIO::COutFile outFile;
813 if (!outFile.Create(newFile, false))
814 return FALSE;
815
816 NWindows::NFile::NIO::CInFile inFile;
817 if (!inFile.Open(oldFile))
818 return FALSE;
819
820 char buf[1 << 14];
821
822 for (;;)
823 {
824 const ssize_t num = inFile.read_part(buf, sizeof(buf));
825 if (num == 0)
826 return TRUE;
827 if (num < 0)
828 return FALSE;
829 size_t processed;
830 const ssize_t num2 = outFile.write_full(buf, (size_t)num, processed);
831 if (num2 != num || processed != (size_t)num)
832 return FALSE;
833 }
834}
835
836
837bool MyMoveFile(CFSTR oldFile, CFSTR newFile)
838{
839 int res = rename(oldFile, newFile);
840 if (res == 0)
841 return true;
842 if (errno != EXDEV) // (oldFile and newFile are not on the same mounted filesystem)
843 return false;
844
845 if (My__CopyFile(oldFile, newFile) == FALSE)
846 return false;
847
848 struct stat info_file;
849 res = stat(oldFile, &info_file);
850 if (res != 0)
851 return false;
852
853 /*
854 ret = chmod(dst,info_file.st_mode & g_umask.mask);
855 */
856 return (unlink(oldFile) == 0);
857}
858
859
860bool CreateDir(CFSTR path)
861{
862 return (mkdir(path, 0777) == 0); // change it
863}
864
865static bool CreateDir2(CFSTR path)
866{
867 return (mkdir(path, 0777) == 0); // change it
868}
869
870
871bool DeleteFileAlways(CFSTR path)
872{
873 return (remove(path) == 0);
874}
875
876bool SetCurrentDir(CFSTR path)
877{
878 return (chdir(path) == 0);
879}
880
881
882bool GetCurrentDir(FString &path)
883{
884 path.Empty();
885
886 #define MY__PATH_MAX PATH_MAX
887 // #define MY__PATH_MAX 1024
888
889 char s[MY__PATH_MAX + 1];
890 char *res = getcwd(s, MY__PATH_MAX);
891 if (res)
892 {
893 path = fas2fs(s);
894 return true;
895 }
896 {
897 // if (errno != ERANGE) return false;
898 #if defined(__GLIBC__) || defined(__APPLE__)
899 /* As an extension to the POSIX.1-2001 standard, glibc's getcwd()
900 allocates the buffer dynamically using malloc(3) if buf is NULL. */
901 res = getcwd(NULL, 0);
902 if (res)
903 {
904 path = fas2fs(res);
905 ::free(res);
906 return true;
907 }
908 #endif
909 return false;
910 }
911}
912
913
914
915// #undef UTIME_OMIT // to debug
916
917#ifndef UTIME_OMIT
918 /* we can define UTIME_OMIT for debian and another systems.
919 Is it OK to define UTIME_OMIT to -2 here, if UTIME_OMIT is not defined? */
920 // #define UTIME_OMIT -2
921#endif
922
923static bool FILETME_To_timespec(const FILETIME *ft, timespec &ts)
924{
925 if (ft)
926 {
927 const Int64 sec = NTime::FileTimeToUnixTime64(*ft);
928 // time_t is long
929 const time_t sec2 = (time_t)sec;
930 if (sec2 == sec)
931 {
932 ts.tv_sec = sec2;
933 const UInt64 winTime = (((UInt64)ft->dwHighDateTime) << 32) + ft->dwLowDateTime;
934 ts.tv_nsec = (long)((winTime % 10000000) * 100);
935 return true;
936 }
937 }
938 // else
939 {
940 ts.tv_sec = 0;
941 ts.tv_nsec =
942 #ifdef UTIME_OMIT
943 UTIME_OMIT; // keep old timesptamp
944 #else
945 // UTIME_NOW; // set to the current time
946 0;
947 #endif
948 return false;
949 }
950}
951
952
953
954
955bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime)
956{
957 // need testing
958 /*
959 struct utimbuf buf;
960 struct stat st;
961 UNUSED_VAR(cTime)
962
963 printf("\nstat = %s\n", path);
964 int ret = stat(path, &st);
965
966 if (ret == 0)
967 {
968 buf.actime = st.st_atime;
969 buf.modtime = st.st_mtime;
970 }
971 else
972 {
973 time_t cur_time = time(0);
974 buf.actime = cur_time;
975 buf.modtime = cur_time;
976 }
977
978 if (aTime)
979 {
980 UInt32 ut;
981 if (NTime::FileTimeToUnixTime(*aTime, ut))
982 buf.actime = ut;
983 }
984
985 if (mTime)
986 {
987 UInt32 ut;
988 if (NTime::FileTimeToUnixTime(*mTime, ut))
989 buf.modtime = ut;
990 }
991
992 return utime(path, &buf) == 0;
993 */
994
995 // if (!aTime && !mTime) return true;
996
997 struct timespec times[2];
998 UNUSED_VAR(cTime)
999
1000 bool needChange;
1001 needChange = FILETME_To_timespec(aTime, times[0]);
1002 needChange |= FILETME_To_timespec(mTime, times[1]);
1003
1004 if (!needChange)
1005 return true;
1006
1007 const int flags = 0; // follow link
1008 // = AT_SYMLINK_NOFOLLOW; // don't follow link
1009 return utimensat(AT_FDCWD, path, times, flags) == 0;
1010}
1011
1012
1013
1014struct C_umask
1015{
1016 mode_t mask;
1017
1018 C_umask()
1019 {
1020 /* by security reasons we restrict attributes according
1021 with process's file mode creation mask (umask) */
1022 const mode_t um = umask(0); // octal :0022 is expected
1023 mask = 0777 & (~um); // octal: 0755 is expected
1024 umask(um); // restore the umask
1025 // printf("\n umask = 0%03o mask = 0%03o\n", um, mask);
1026
1027 // mask = 0777; // debug we can disable the restriction:
1028 }
1029};
1030
1031static C_umask g_umask;
1032
1033// #define PRF(x) x;
1034#define PRF(x)
1035
1036#define TRACE_SetFileAttrib(msg) \
1037 PRF(printf("\nSetFileAttrib(%s, %x) : %s\n", (const char *)path, attrib, msg));
1038
1039#define TRACE_chmod(s, mode) \
1040 PRF(printf("\n chmod(%s, %o)\n", (const char *)path, (unsigned)(mode)));
1041
1042
1043bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib)
1044{
1045 TRACE_SetFileAttrib("");
1046
1047 struct stat st;
1048
1049 bool use_lstat = true;
1050 if (use_lstat)
1051 {
1052 if (lstat(path, &st) != 0)
1053 {
1054 TRACE_SetFileAttrib("bad lstat()");
1055 return false;
1056 }
1057 // TRACE_chmod("lstat", st.st_mode);
1058 }
1059 else
1060 {
1061 if (stat(path, &st) != 0)
1062 {
1063 TRACE_SetFileAttrib("bad stat()");
1064 return false;
1065 }
1066 }
1067
1068 if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION)
1069 {
1070 TRACE_SetFileAttrib("attrib & FILE_ATTRIBUTE_UNIX_EXTENSION");
1071 st.st_mode = attrib >> 16;
1072 if (S_ISDIR(st.st_mode))
1073 {
1074 // user/7z must be able to create files in this directory
1075 st.st_mode |= (S_IRUSR | S_IWUSR | S_IXUSR);
1076 }
1077 else if (!S_ISREG(st.st_mode))
1078 return true;
1079 }
1080 else if (S_ISLNK(st.st_mode))
1081 {
1082 /* for most systems: permissions for symlinks are fixed to rwxrwxrwx.
1083 so we don't need chmod() for symlinks. */
1084 return true;
1085 // SetLastError(ENOSYS);
1086 // return false;
1087 }
1088 else
1089 {
1090 TRACE_SetFileAttrib("Only Windows Attributes");
1091 // Only Windows Attributes
1092 if (S_ISDIR(st.st_mode)
1093 || (attrib & FILE_ATTRIBUTE_READONLY) == 0)
1094 return true;
1095 st.st_mode &= ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions
1096 }
1097
1098 int res;
1099 /*
1100 if (S_ISLNK(st.st_mode))
1101 {
1102 printf("\nfchmodat()\n");
1103 TRACE_chmod(path, (st.st_mode) & g_umask.mask);
1104 // AT_SYMLINK_NOFOLLOW is not implemted still in Linux.
1105 res = fchmodat(AT_FDCWD, path, (st.st_mode) & g_umask.mask,
1106 S_ISLNK(st.st_mode) ? AT_SYMLINK_NOFOLLOW : 0);
1107 }
1108 else
1109 */
1110 {
1111 TRACE_chmod(path, (st.st_mode) & g_umask.mask);
1112 res = chmod(path, (st.st_mode) & g_umask.mask);
1113 }
1114 // TRACE_SetFileAttrib("End")
1115 return (res == 0);
1116}
1117
1118
1119bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName)
1120{
1121 PRF(printf("\nhard link() %s -> %s\n", newFileName, existFileName));
1122 return (link(existFileName, newFileName) == 0);
1123}
1124
1125#endif // !_WIN32
1126
1127// #endif
1128
1129}}}