#include "urlib.h" #include #ifdef _WIN32 #include //#include #include #include #include static DWORD dword; #define u_handle HANDLE #define u_invalid_handle 0 #define u_valid(handle) (!!handle) #define u_setenv(name,value) SetEnvironmentVariable (name, value) #define u_mkdir(path) !CreateDirectory (path, NULL) #define u_chdir(path) !SetCurrentDirectory (path) #define u_rename(fr,to) !MoveFile (fr, to) #define u_open(path) CreateFile (path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL) #define u_creat(path,exec) CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL) #define u_creat(path,exec) CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL) #define u_close(handle) CloseHandle (handle) #define u_append(path,add) PathAppend (path, add) #define u_write(handle,data,len) (WriteFile (handle, data, len, &dword, 0) ? dword : -1) #define u_fsync(handle) FlushFileBuffers (handle) #define u_sync() #define u_lockfile(path) CreateFile (path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) #define u_cloexec(handle) #else #define _GNU_SOURCE 1 #define _BSD_SOURCE 1 // the above increases our chances of getting MAP_ANONYMOUS #include #include #include #include #include #if defined (MAP_ANON) && !defined (MAP_ANONYMOUS) #define MAP_ANONYMOUS MAP_ANON #endif #ifdef PATH_MAX #define MAX_PATH (PATH_MAX < 4096 ? 4096 : PATH_MAX) #else #define MAX_PATH 4096 #endif #define u_handle int #define u_invalid_handle -1 #define u_valid(fd) ((fd) >= 0) #define u_setenv(name,value) setenv (name, value, 1) #define u_mkdir(path) mkdir (path, 0777) #define u_chdir(path) chdir (path) #define u_rename(fr,to) rename (fr, to) #define u_open(path) open (path, O_RDONLY) #define u_creat(path,exec) open (path, O_WRONLY | O_CREAT | O_TRUNC, (exec) ? 0777 : 0666) #define u_close(handle) close (handle) #define u_append(path,add) strcat (strcat (path, "/"), add) #define u_write(handle,data,len) write (handle, data, len) // on a mostly idle system, a sync at the end is certainly faster, hope for the best #define u_fsync(handle) #define u_sync() sync () #define u_lockfile(path) open (path, O_RDWR | O_CREAT, 0666) #define u_cloexec(handle) fcntl (handle, F_SETFD, FD_CLOEXEC) #endif #define u_16(ptr) (((ptr)[0] << 8) | (ptr)[1]) #define u_32(ptr) (((ptr)[0] << 24) | ((ptr)[1] << 16) | ((ptr)[2] << 8) | (ptr)[3]) static void * u_malloc (unsigned int size) { void *addr; #ifdef _WIN32 HANDLE handle = CreateFileMapping (0, 0, PAGE_READWRITE, 0, size, NULL); if (!handle) return 0; addr = MapViewOfFile (handle, FILE_MAP_WRITE, 0, 0, size); CloseHandle (handle); #elif defined (MAP_ANONYMOUS) addr = mmap (0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (addr == (void *)-1) addr = 0; #else addr = malloc (size); #endif return addr; } static void u_free (void *addr, unsigned int size) { #ifdef _WIN32 UnmapViewOfFile (addr); #elif defined (MAP_ANONYMOUS) munmap (addr, size); #else free (addr); #endif } static void * u_mmap (u_handle h, unsigned int size) { void *addr; #ifdef _WIN32 HANDLE handle = CreateFileMapping (h, 0, PAGE_READONLY, 0, size, NULL); if (!handle) return 0; addr = MapViewOfFile (handle, FILE_MAP_READ, 0, 0, size); CloseHandle (handle); #else addr = mmap (0, size, PROT_READ, MAP_SHARED, h, 0); if (addr == (void *)-1) addr = 0; #endif return addr; } static void u_munmap (void *addr, unsigned int len) { #ifdef _WIN32 UnmapViewOfFile (addr); #else munmap (addr, len); #endif } static u_handle u_lock (const char *path, int excl, int dowait) { u_handle h; h = u_lockfile (path); if (!u_valid (h)) return h; u_cloexec (h); for (;;) { int success; // acquire the lock #ifdef _WIN32 OVERLAPPED ov = { 0 }; success = LockFileEx (h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | (dowait ? 0 : LOCKFILE_FAIL_IMMEDIATELY), 0, 1, 0, &ov); #else struct flock lck = { 0 }; lck.l_type = excl ? F_WRLCK : F_RDLCK; lck.l_whence = SEEK_SET; lck.l_len = 1; success = !fcntl (h, dowait ? F_SETLKW : F_SETLK, &lck); #endif if (!success) break; // we have the lock, now verify that the lockfile still exists #ifdef _WIN32 // apparently, we have to open the file to get its info :( BY_HANDLE_FILE_INFORMATION s1, s2; u_handle h2 = u_lockfile (path); if (!u_valid (h)) break; success = GetFileInformationByHandle (h, &s1) && GetFileInformationByHandle (h2, &s2); u_close (h2); if (!success) break; success = s1.dwVolumeSerialNumber == s2.dwVolumeSerialNumber && s1.nFileIndexHigh == s2.nFileIndexHigh && s1.nFileIndexLow == s2.nFileIndexLow; #else struct stat s1, s2; if (fstat (h, &s1) || stat (path, &s2)) break; success = s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino; #endif if (success) return h; // lock successfully acquired // files differ, close and retry - should be very rare u_close (h); } // failure u_close (h); return u_invalid_handle; }