10 #if defined(__GNUC__) || defined(__WATCOMC__) || defined(__WIN32__)
12 #include <sys/types.h>
17 #if defined(__unix__) || defined(__APPLE__)
21 #if defined(__WIN32__)
22 #define WIN32_LEAN_AND_MEAN
32 typedef unsigned char byte;
33 typedef unsigned short uint16;
34 typedef unsigned int uint;
35 typedef unsigned int FileSize;
36 typedef long long int64;
37 typedef unsigned long long uint64;
42 #define null ((void *)0)
44 #define MAX_LOCATION 797
45 #define MAX_FILENAME 274
47 void __ecereNameSpace__ecere__com__eSystem_Delete(void * memory);
48 void * __ecereNameSpace__ecere__com__eSystem_New0(unsigned int size);
49 void * __ecereNameSpace__ecere__com__eSystem_Renew(void * memory, unsigned int size);
50 void * __ecereNameSpace__ecere__com__eSystem_Renew0(void * memory, unsigned int size);
51 unsigned short * __ecereNameSpace__ecere__sys__UTF8toUTF16(const char * source, int * wordCount);
52 unsigned short * __ecereNameSpace__ecere__sys__UTF8toUTF16Buffer(const char * source, uint16 * dest, int max);
53 char * __ecereNameSpace__ecere__sys__UTF16toUTF8(const uint16 * source);
54 void __ecereNameSpace__ecere__sys__ChangeCh(char * string, char ch1, char ch2);
56 #if defined(__WIN32__) || defined(__WATCOMC__)
58 __declspec(dllimport) BOOL WINAPI GetVolumePathName(LPCTSTR lpszFileName,LPTSTR lpszVolumePathName,DWORD cchBufferLength);
63 typedef unsigned int FileAttribs;
64 typedef int64 SecSince1970;
65 typedef SecSince1970 TimeStamp;
79 unlocked = 0, // LOCK_UN _SH_DENYNO
80 shared = 1, // LOCK_SH _SH_DENYWR
81 exclusive = 2 // LOCK_EX _SH_DENYRW
85 #define isArchive 0x0002
86 #define isHidden 0x0004
87 #define isReadOnly 0x0008
88 #define isSystem 0x0010
89 #define isTemporary 0x0020
90 #define isDirectory 0x0040
91 #define isDrive 0x0080
92 #define isCDROM 0x0100
93 #define isRemote 0x0200
94 #define isRemovable 0x0400
95 #define isServer 0x0800
96 #define isShare 0x1000
102 SecSince1970 accessed;
103 SecSince1970 modified;
104 SecSince1970 created;
107 char * __ecereNameSpace__ecere__sys__GetLastDirectory(const char * string, char * output);
108 bool __ecereNameSpace__ecere__sys__SplitArchivePath(const char * fileName, char * archiveName, char ** archiveFile);
110 #if defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
111 void __ecereMethod___ecereNameSpace__ecere__sys__EARFileSystem_FixCase(const char * archive, char * name);
113 static BOOL CALLBACK EnumThreadWindowsProc(HWND hwnd, LPARAM lParam)
116 if(IsWindowVisible(hwnd) && GetWindowThreadProcessId(hwnd, &pid) && pid == GetCurrentProcessId())
118 *(void **)lParam = hwnd;
123 bool WinReviveNetworkResource(uint16 * _wfileName)
126 HWND windowHandle = null;
127 NETRESOURCE nr = { 0 };
128 nr.dwType = RESOURCETYPE_DISK;
129 nr.lpRemoteName = _wfileName;
130 if(_wfileName[0] != '\\' || _wfileName[1] == '\\')
132 uint16 volumePathName[MAX_LOCATION];
133 if(GetVolumePathName(_wfileName, volumePathName, MAX_LOCATION))
135 uint16 remoteName[MAX_LOCATION];
136 DWORD size = MAX_LOCATION;
137 volumePathName[wcslen(volumePathName)-1] = 0;
138 if(WNetGetConnection(volumePathName, remoteName, &size) == ERROR_CONNECTION_UNAVAIL)
140 nr.lpRemoteName = remoteName;
141 nr.lpLocalName = volumePathName;
149 EnumThreadWindows(GetCurrentThreadId(), EnumThreadWindowsProc, (LPARAM)&windowHandle);
152 EnumWindows(EnumThreadWindowsProc, (LPARAM)&windowHandle);
155 if(WNetAddConnection3(windowHandle, &nr, null, null, CONNECT_INTERACTIVE|CONNECT_PROMPT) == NO_ERROR)
160 TimeStamp Win32FileTimeToTimeStamp(FILETIME * fileTime);
161 void TimeStampToWin32FileTime(TimeStamp t, FILETIME * fileTime);
165 uint FILE_GetSize(FILE * input)
170 int fd = fileno(input);
177 bool FILE_Lock(FILE * input, FILE * output, FileLock type, uint64 start, uint64 length, bool wait)
179 if(!output && !input)
183 #if defined(__WIN32__)
184 int handle = fileno(output ? output : input);
185 HANDLE hFile = (HANDLE)_get_osfhandle(handle);
186 OVERLAPPED overlapped = { 0 };
187 overlapped.Offset = (uint)(start & 0xFFFFFFFF);
188 overlapped.OffsetHigh = (uint)((start & 0xFFFFFFFF00000000LL) >> 32);
190 return UnlockFileEx(hFile, 0,
191 (uint)(length ? (length & 0xFFFFFFFF) : 0xFFFFFFFF),
192 (uint)(length ? ((length & 0xFFFFFFFF00000000LL) >> 32) : 0xFFFFFFFF),
195 return LockFileEx(hFile, ((type == exclusive) ? LOCKFILE_EXCLUSIVE_LOCK : 0) | (wait ? 0 : LOCKFILE_FAIL_IMMEDIATELY), 0,
196 (uint)(length ? (length & 0xFFFFFFFF) : 0xFFFFFFFF),
197 (uint)(length ? ((length & 0xFFFFFFFF00000000LL) >> 32) : 0xFFFFFFFF),
203 fl.l_type = (type == unlocked) ? F_UNLCK : ((type == exclusive) ? F_WRLCK : F_RDLCK);
204 fl.l_whence = SEEK_SET;
209 fd = fileno(output ? output : input);
210 return fcntl(fd, wait ? F_SETLKW : F_SETLK, &fl) != -1;
215 void FILE_set_buffered(FILE * input, FILE * output, bool value)
217 #if !defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
219 setvbuf(input, null, value ? _IOFBF : _IONBF, 0);
220 if(output && output != input)
221 setvbuf(output, null, value ? _IOFBF : _IONBF, 0);
225 FileAttribs FILE_FileExists(const char * fileName)
228 FileAttribs result = 0;
229 uint attribute = 0; // Initialization isn't actually required here but GCC complains about it.
230 uint16 * _wfileName = __ecereNameSpace__ecere__sys__UTF8toUTF16(fileName, null);
231 if(!strcmp(fileName, "/") || !strcmp(fileName, "\\\\"))
233 result = (FileAttribs)(isDirectory);
236 attribute = GetFileAttributes(_wfileName);
237 #if !defined(ECERE_BOOTSTRAP)
238 if(!result && attribute == 0xFFFFFFFF)
240 if(WinReviveNetworkResource(_wfileName))
241 attribute = GetFileAttributes(_wfileName);
242 if(attribute == 0xFFFFFFFF)
244 if(fileName[0] == '\\' && fileName[1] == '\\')
246 NETRESOURCE nr = { 0 };
247 NETRESOURCE * buffer = null;
248 unsigned int size = sizeof(NETRESOURCE);
251 nr.dwScope = RESOURCE_GLOBALNET;
252 nr.dwType = RESOURCETYPE_DISK;
253 nr.lpRemoteName = _wfileName;
254 nr.lpProvider = L"Microsoft Windows Network";
256 buffer = (NETRESOURCE *)__ecereNameSpace__ecere__com__eSystem_New0(size);
259 int returnCode = WNetGetResourceInformationW(&nr, buffer, (DWORD *)&size, &dir);
260 if(returnCode == WN_MORE_DATA)
261 buffer = (NETRESOURCE *)__ecereNameSpace__ecere__com__eSystem_Renew0(buffer, size);
264 if(returnCode == WN_SUCCESS)
266 if(!_wcsicmp(buffer->lpRemoteName, _wfileName))
267 result = (FileAttribs)( isDirectory | isServer );
272 __ecereNameSpace__ecere__com__eSystem_Delete(buffer);
277 if(!result && attribute != 0xFFFFFFFF)
279 if(attribute & FILE_ATTRIBUTE_DIRECTORY)
280 result = (FileAttribs)( isDirectory );
282 result = (FileAttribs)(isFile);
284 __ecereNameSpace__ecere__com__eSystem_Delete(_wfileName);
287 if(!access(fileName, F_OK))
291 return S_ISDIR(s.st_mode) ? (FileAttribs) ( isDirectory ) : (FileAttribs) ( isFile );
296 return (FileAttribs) 0;
301 bool FILE_FileGetSize(const char * fileName, FileSize * size)
304 #if defined(__WIN32__)
306 uint16 * _wfileName = __ecereNameSpace__ecere__sys__UTF8toUTF16(fileName, null);
307 if(!_wstat(_wfileName, &s))
310 if(!stat(fileName, &s))
316 #if defined(__WIN32__)
317 __ecereNameSpace__ecere__com__eSystem_Delete(_wfileName);
322 bool FILE_FileGetStats(const char * fileName, FileStats * stats)
325 #if defined(__WIN32__)
326 uint16 * _wfileName = __ecereNameSpace__ecere__sys__UTF8toUTF16(fileName, null);
328 if(!_wstat(_wfileName, &s))
331 if(!stat(fileName, &s))
334 stats->size = s.st_size;
335 stats->attribs = (s.st_mode & S_IFDIR) ? ((FileAttribs) (isDirectory)): ((FileAttribs) 0);
337 #if defined(__WIN32__)
339 HANDLE hFile = CreateFile(_wfileName, 0, FILE_SHARE_READ, null,
340 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, null);
341 if(hFile != INVALID_HANDLE_VALUE)
343 #if defined(ECERE_BOOTSTRAP)
349 GetFileTime(hFile, &c, &a, &m);
350 stats->created = Win32FileTimeToTimeStamp(&c);
351 stats->accessed = Win32FileTimeToTimeStamp(&a);
352 stats->modified = Win32FileTimeToTimeStamp(&m);
359 stats->accessed = s.st_atime;
360 // UNIX st_ctime is 'status change' time, not creation time
361 // Marking created as 0, as ctime changes cause unreproducible builds
363 stats->modified = s.st_mtime;
366 stats->attribs.isArchive = (winFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ? true : false;
367 stats->attribs.isHidden = (winFile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? true : false;
368 stats->attribs.isReadOnly = (winFile.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? true : false;
369 stats->attribs.isSystem = (winFile.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? true : false;
370 stats->attribs.isTemporary = (winFile.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) ? true : false;
371 stats->attribs.isDirectory = (winFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false;
375 #if defined(__WIN32__)
376 __ecereNameSpace__ecere__com__eSystem_Delete(_wfileName);
381 void FILE_FileFixCase(char * file)
383 #if defined(__WIN32__)
384 #ifndef ECERE_BOOTSTRAP
385 char archive[MAX_LOCATION], * name;
386 if(__ecereNameSpace__ecere__sys__SplitArchivePath(file, archive, &name))
388 char fileName[MAX_LOCATION];
389 strcpy(fileName, name);
390 __ecereMethod___ecereNameSpace__ecere__sys__EARFileSystem_FixCase(archive, fileName);
391 if(archive[0] != ':')
392 FILE_FileFixCase(archive);
393 sprintf(file, "<%s>%s", archive, fileName);
399 char parent[MAX_LOCATION] = "";
401 // Skip network protocols
402 if(strstr(file, "http://") == file) return;
404 // Copy drive letter to new path
405 if(file[0] && file[1] == ':')
407 parent[0] = (char)toupper(file[0]);
412 // Copy Microsoft Network string to new path
413 else if(file[0] == '\\' && file[1] == '\\')
415 parent[0] = parent[1] = '\\';
419 else if(file[0] == '/' && file[1] == '/')
421 parent[0] = parent[1] = '\\';
425 // Copy Entire Computer to new path
426 else if(file[0] == '/' && !file[1])
436 // Get next directory
437 char directory[MAX_FILENAME];
440 for(;(ch = file[c]) && (ch == '/' || ch == '\\'); c++);
441 for(;(ch = file[c]) && (ch != '/' && ch != '\\'); c++)
443 if(len < MAX_FILENAME)
444 directory[len++] = ch;
446 directory[len] = '\0';
449 if(parent[0] != '\\' || parent[1] != '\\' || strstr(parent+2, "\\"))
451 if(strcmp(directory, "..") && strcmp(directory, "."))
453 WIN32_FIND_DATA winFile;
454 uint16 dir[MAX_PATH];
457 __ecereNameSpace__ecere__sys__UTF8toUTF16Buffer(parent, dir, MAX_PATH);
458 if(dir[0]) wcscat(dir, L"\\");
460 uint16 * _wdirectory = __ecereNameSpace__ecere__sys__UTF8toUTF16(directory, null);
461 wcscat(dir, _wdirectory);
462 __ecereNameSpace__ecere__com__eSystem_Delete(_wdirectory);
465 handle = FindFirstFile(dir, &winFile);
466 if(parent[0] || (file[0] == '\\' || file[0] == '/'))
467 strcat(parent, "\\");
468 if(handle != INVALID_HANDLE_VALUE)
470 char * utf8 = __ecereNameSpace__ecere__sys__UTF16toUTF8(winFile.cFileName);
471 strcat(parent, utf8);
472 __ecereNameSpace__ecere__com__eSystem_Delete(utf8);
476 strcat(parent, directory);
480 if(parent[0] || (file[0] == '\\' || file[0] == '/'))
481 strcat(parent, "\\");
483 strcat(parent, directory);
486 #ifndef ECERE_BOOTSTRAP
493 DWORD count = 0xFFFFFFFF;
494 DWORD size = 512 * sizeof(NETRESOURCE);
495 NETRESOURCE * buffer = (NETRESOURCE *)__ecereNameSpace__ecere__com__eSystem_New0(size);
496 NETRESOURCE nr = {0};
499 nr.dwScope = RESOURCE_GLOBALNET;
500 nr.dwType = RESOURCETYPE_DISK;
502 nr.lpRemoteName = __ecereNameSpace__ecere__sys__UTF8toUTF16(parent, null);
503 nr.lpProvider = L"Microsoft Windows Network";
506 WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, &nr, &handle);
511 int returnCode = WNetEnumResource(handle, &count, buffer, &size);
512 if(returnCode != ERROR_MORE_DATA)
515 buffer = (NETRESOURCE *)__ecereNameSpace__ecere__com__eSystem_Renew0(buffer, size);
517 WNetCloseEnum(handle);
522 for(c = 0; c<count; c++)
524 char shareName[MAX_FILENAME];
525 char * remoteName = __ecereNameSpace__ecere__sys__UTF16toUTF8(buffer[c].lpRemoteName);
526 __ecereNameSpace__ecere__sys__GetLastDirectory(remoteName, shareName);
527 __ecereNameSpace__ecere__com__eSystem_Delete(remoteName);
528 if(!strcmpi(directory, shareName))
530 strcpy(directory, shareName);
537 __ecereNameSpace__ecere__com__eSystem_Delete(nr.lpRemoteName);
538 __ecereNameSpace__ecere__com__eSystem_Delete(buffer);
540 strcat(parent, "\\");
541 strcat(parent, directory);
547 directory[0] = (char)toupper(directory[0]);
548 strcat(parent, directory);
553 strcpy(file, parent);
556 __ecereNameSpace__ecere__sys__ChangeCh(file, '\\', '/');
560 void FILE_FileOpen(const char * fileName, FileOpenMode mode, FILE ** input, FILE **output)
562 #if defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
563 uint16 * _wfileName = __ecereNameSpace__ecere__sys__UTF8toUTF16(fileName, null);
565 file.handle = CreateFile(_wfileName,
566 ((mode == FOM_read || mode == FOM_readWrite || mode == FOM_writeRead || mode == FOM_appendRead) ? GENERIC_READ : 0) |
567 ((mode == FOM_write || mode == FOM_append || mode == FOM_readWrite || mode == FOM_writeRead || mode == FOM_appendRead) ? GENERIC_WRITE: 0),
568 FILE_SHARE_READ|FILE_SHARE_WRITE,
570 (mode == write || mode == writeRead) ? TRUNCATE_EXISTING : ((mode == read || mode == readWrite) ? OPEN_EXISTING : OPEN_ALWAYS), 0, null);
577 case FOM_read: handle = _open_osfhandle((int)file.handle, _O_RDONLY); break;
578 case FOM_write: handle = _open_osfhandle((int)file.handle, _O_WRONLY | _O_CREAT | _O_TRUNC); break;
579 case FOM_append: handle = _open_osfhandle((int)file.handle, _O_WRONLY | _O_CREAT | _O_APPEND); break;
580 case FOM_readWrite: handle = _open_osfhandle((int)file.handle, _O_RDWR); break;
581 case FOM_writeRead: handle = _open_osfhandle((int)file.handle, _O_RDWR | _O_CREAT | _O_TRUNC); break;
582 case FOM_appendRead: handle = _open_osfhandle((int)file.handle, _O_RDWR | _O_APPEND | _O_CREAT); break;
588 case FOM_read: *input = _fdopen(handle, "rb"); break;
589 case FOM_write: *output = _fdopen(handle, "wb"); break;
590 case FOM_append: *output = _fdopen(handle, "ab"); break;
591 case FOM_readWrite: *input = *output = _fdopen(handle, "r+b"); break;
592 case FOM_writeRead: *input = *output = _fdopen(handle, "w+b"); break;
593 case FOM_appendRead: *input = *output = _fdopen(handle, "a+b"); break;
600 case FOM_read: *input = _wfopen(_wfileName, L"rb"); break;
601 case FOM_write: *output = _wfopen(_wfileName, L"wb"); break;
602 case FOM_append: *output = _wfopen(_wfileName, L"ab"); break;
603 case FOM_readWrite: *input = *output = _wfopen(_wfileName, L"r+b"); break;
604 case FOM_writeRead: *input = *output = _wfopen(_wfileName, L"w+b"); break;
605 case FOM_appendRead: *input = *output = _wfopen(_wfileName, L"a+b"); break;
607 if(!mode && WinReviveNetworkResource(_wfileName))
611 case FOM_read: *input = _wfopen(_wfileName, L"rb"); break;
612 case FOM_write: *output = _wfopen(_wfileName, L"wb"); break;
613 case FOM_append: *output = _wfopen(_wfileName, L"ab"); break;
614 case FOM_readWrite: *input = *output = _wfopen(_wfileName, L"r+b"); break;
615 case FOM_writeRead: *input = *output = _wfopen(_wfileName, L"w+b"); break;
616 case FOM_appendRead: *input = *output = _wfopen(_wfileName, L"a+b"); break;
619 __ecereNameSpace__ecere__com__eSystem_Delete(_wfileName);
623 case FOM_read: *input = fopen(fileName, "rb"); break;
624 case FOM_write: *output = fopen(fileName, "wb"); break;
625 case FOM_append: *output = fopen(fileName, "ab"); break;
626 case FOM_readWrite: *input = *output = fopen(fileName, "r+b"); break;
627 case FOM_writeRead: *input = *output = fopen(fileName, "w+b"); break;
628 case FOM_appendRead: *input = *output = fopen(fileName, "a+b"); break;