27 #define _LARGEFILE64_SOURCE 1
43 #pragma comment(lib, "shlwapi.lib")
48 #if _POSIX_C_SOURCE >= 200112L
51 #if _POSIX_MAPPED_FILES >= 200112L
70 HANDLE hFileMappingObject;
74 SIZE_T dwNumberOfBytesToMap;
75 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
114 void *ptr = malloc(
sizeof(
struct __fwbuf));
121 __fwbuf_free(
void *ptr)
142 char dir[MAX_PATH - 14];
143 strncpy(dir, buf->
filename, MAX_PATH - 14 - 1);
144 dir[MAX_PATH - 14 - 1] =
'\0';
145 PathRemoveFileSpecA(dir);
151 if (!GetTempFileNameA(dir,
"tmp", 0, buf->
tmpname)) {
152 dwErrCode = GetLastError();
153 goto error_GetTempFileNameA;
156 buf->hFile = CreateFileA(buf->
tmpname, GENERIC_READ | GENERIC_WRITE, 0,
157 NULL, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
158 if (buf->hFile == INVALID_HANDLE_VALUE) {
159 dwErrCode = GetLastError();
160 goto error_CreateFileA;
165 buf->hFileMappingObject = INVALID_HANDLE_VALUE;
166 buf->lpBaseAddress = NULL;
167 buf->dwNumberOfBytesToMap = 0;
173 error_GetTempFileNameA:
176 SetLastError(dwErrCode);
178 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
184 goto error_strdup_filename;
190 goto error_strdup_tmp;
192 char *dir = dirname(tmp);
193 size_t n = strlen(dir);
195 buf->
dirfd = open(dir, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
196 if (buf->
dirfd == -1) {
198 goto error_open_dirfd;
204 goto error_malloc_tmpname;
208 if (!n || buf->
tmpname[n - 1] !=
'/')
209 strcat(buf->
tmpname,
"/.tmp-XXXXXX");
211 strcat(buf->
tmpname,
".tmp-XXXXXX");
217 buf->
fd = mkostemp(buf->
tmpname, O_CLOEXEC);
227 if (fcntl(buf->
fd, F_SETFD, FD_CLOEXEC) == -1) {
235 buf->
addr = MAP_FAILED;
245 error_malloc_tmpname:
252 error_strdup_filename:
265 buf->stream = fopen(tmpnam(buf->
tmpname),
"w+b");
291 __fwbuf_fini(
struct __fwbuf *buf)
298 #if _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
309 fwbuf_t *buf = __fwbuf_alloc();
312 goto error_alloc_buf;
345 LARGE_INTEGER FileSize;
346 if (!GetFileSizeEx(buf->hFile, &FileSize)) {
347 buf->dwErrCode = GetLastError();
350 return FileSize.QuadPart;
351 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
354 if (fstat64(buf->
fd, &stat) == -1) {
357 if (fstat(buf->
fd, &stat) == -1) {
382 if (!SetEndOfFile(buf->hFile)) {
383 buf->dwErrCode = GetLastError();
391 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
393 if (ftruncate64(buf->
fd, size) == -1) {
396 if (ftruncate(buf->
fd, size) == -1) {
403 if (size < buf->last) {
421 LARGE_INTEGER li = { .QuadPart = 0 };
422 if (!SetFilePointerEx(buf->hFile, li, &li, FILE_CURRENT)) {
423 buf->dwErrCode = GetLastError();
427 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
429 intmax_t pos = lseek64(buf->
fd, 0, SEEK_CUR);
431 intmax_t pos = lseek(buf->
fd, 0, SEEK_CUR);
437 long pos = ftell(buf->stream);
453 LARGE_INTEGER li = { .QuadPart = pos };
454 if (!SetFilePointerEx(buf->hFile, li, &li, FILE_BEGIN)) {
455 buf->dwErrCode = GetLastError();
459 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
461 pos = lseek64(buf->
fd, pos, SEEK_SET);
463 pos = lseek(buf->
fd, pos, SEEK_SET);
473 if (pos > LONG_MAX) {
478 if (fseek(buf->stream, pos, SEEK_SET)) {
491 assert(ptr || !size);
500 DWORD nNumberOfBytesWritten;
501 if (!WriteFile(buf->hFile, ptr, size, &nNumberOfBytesWritten, NULL)) {
502 buf->dwErrCode = GetLastError();
505 return nNumberOfBytesWritten;
506 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
509 result = write(buf->
fd, ptr, size);
510 while (result == -1 && errno == EINTR);
519 size_t result = fwrite(ptr, 1, size, buf->stream);
520 if (result != size && ferror(buf->stream)) {
528 if (buf->map && pos < buf->pos + (intmax_t)buf->
len
529 && pos + (intmax_t)size > buf->pos) {
530 size_t begin =
MAX(pos - buf->pos, 0);
531 size_t end =
MIN(pos + size - buf->pos, buf->
len);
532 memmove((
char *)buf->map + begin, ptr, end - begin);
535 buf->last =
MAX(buf->last, pos + (intmax_t)result);
536 buf->size =
MAX(buf->size, buf->last);
545 assert(ptr || !size);
558 buf->dwErrCode = ERROR_INVALID_PARAMETER;
568 DWORD nNumberOfBytesWritten;
569 OVERLAPPED Overlapped = { 0 };
570 ULARGE_INTEGER uli = { .QuadPart = pos };
571 Overlapped.Offset = uli.LowPart;
572 Overlapped.OffsetHigh = uli.HighPart;
574 if (!WriteFile(buf->hFile, ptr, size, &nNumberOfBytesWritten,
578 buf->dwErrCode = GetLastError();
579 goto error_WriteFile;
582 result = nNumberOfBytesWritten;
588 SetLastError(buf->dwErrCode);
590 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
594 result = pwrite64(buf->
fd, ptr, size, pos);
597 result = pwrite(buf->
fd, ptr, size, pos);
599 while (result == -1 && errno == EINTR);
621 if (buf->last < pos) {
626 while (buf->last < pos) {
627 if (fputc(0, buf->stream) == EOF) {
633 buf->size =
MAX(buf->size, buf->last);
643 if (result == -1 || (
size_t)result != size)
668 SetLastError(buf->dwErrCode = ERROR_INVALID_PARAMETER);
669 #elif _POSIX_MAPPED_FILES >= 200112L
670 errno = buf->
errsv = EINVAL;
676 if (pos > (intmax_t)size) {
678 SetLastError(buf->dwErrCode = ERROR_INVALID_PARAMETER);
679 #elif _POSIX_MAPPED_FILES >= 200112L
680 errno = buf->
errsv = EOVERFLOW;
689 size =
MIN((uintmax_t)size, *psize);
692 SYSTEM_INFO SystemInfo;
694 GetSystemInfo(&SystemInfo);
695 DWORD off = pos % SystemInfo.dwAllocationGranularity;
696 if ((uintmax_t)size > (uintmax_t)(SIZE_MAX - off)) {
697 buf->dwErrCode = ERROR_INVALID_PARAMETER;
701 ULARGE_INTEGER MaximumSize = { .QuadPart = pos + size };
702 buf->hFileMappingObject = CreateFileMapping(buf->hFile, NULL,
703 PAGE_READWRITE, MaximumSize.HighPart,
704 MaximumSize.LowPart, NULL);
705 if (buf->hFileMappingObject == INVALID_HANDLE_VALUE) {
706 buf->dwErrCode = GetLastError();
707 goto error_CreateFileMapping;
710 ULARGE_INTEGER FileOffset = { .QuadPart = pos - off };
711 buf->lpBaseAddress = MapViewOfFile(buf->hFileMappingObject,
712 FILE_MAP_WRITE, FileOffset.HighPart, FileOffset.LowPart,
713 (SIZE_T)(off + size));
714 if (!buf->lpBaseAddress) {
715 buf->dwErrCode = GetLastError();
716 goto error_MapViewOfFile;
720 *psize = (size_t)size;
722 return (
char *)buf->lpBaseAddress + off;
725 CloseHandle(buf->hFileMappingObject);
726 buf->hFileMappingObject = INVALID_HANDLE_VALUE;
727 error_CreateFileMapping:
729 SetLastError(buf->dwErrCode);
731 #elif _POSIX_MAPPED_FILES >= 200112L
732 long page_size = sysconf(_SC_PAGE_SIZE);
733 if (page_size <= 0) {
737 intmax_t off = pos % page_size;
738 if ((uintmax_t)size > (uintmax_t)(SIZE_MAX - off)) {
739 errno = buf->
errsv = EOVERFLOW;
744 buf->
addr = mmap64(NULL, off + size, PROT_READ | PROT_WRITE, MAP_SHARED,
748 buf->
addr = mmap(NULL, off + size, PROT_READ | PROT_WRITE, MAP_SHARED,
751 if (buf->
addr == MAP_FAILED) {
755 buf->
len = off + size;
760 return (
char *)buf->
addr + off;
764 if ((uintmax_t)size > SIZE_MAX) {
769 buf->map = calloc(size, 1);
773 goto error_malloc_map;
779 if (pos < buf->last) {
791 size_t nitems =
MIN(size, buf->last - pos);
792 if (fread(buf->map, 1, nitems, buf->stream) != nitems
793 && ferror(buf->stream)) {
834 if (buf->dwErrCode) {
836 dwErrCode = buf->dwErrCode;
839 if (buf->hFileMappingObject != INVALID_HANDLE_VALUE) {
841 if (!FlushViewOfFile(buf->lpBaseAddress,
842 buf->dwNumberOfBytesToMap) && !result) {
845 dwErrCode = GetLastError();
847 if (!UnmapViewOfFile(buf->lpBaseAddress) && !result) {
849 dwErrCode = GetLastError();
851 if (!CloseHandle(buf->hFileMappingObject) && !result) {
853 dwErrCode = GetLastError();
856 buf->hFileMappingObject = INVALID_HANDLE_VALUE;
857 buf->lpBaseAddress = NULL;
858 buf->dwNumberOfBytesToMap = 0;
863 buf->dwErrCode = dwErrCode;
864 SetLastError(dwErrCode);
866 #elif _POSIX_MAPPED_FILES >= 200112L
873 if (buf->
addr != MAP_FAILED) {
874 if (msync(buf->
addr, buf->
len, MS_SYNC) == -1 && !result) {
878 if (munmap(buf->
addr, buf->
len) == -1 && !result) {
883 buf->
addr = MAP_FAILED;
903 void *map = buf->map;
934 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
948 SetLastError(buf->dwErrCode);
949 return !!buf->dwErrCode;
950 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
957 return !!buf->errnum;
968 buf->dwErrCode = ERROR_OPERATION_ABORTED;
969 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
971 buf->
errsv = ECANCELED;
985 DWORD dwErrCode = GetLastError();
987 if (buf->hFile == INVALID_HANDLE_VALUE)
991 if (!result && !FlushFileBuffers(buf->hFile)) {
993 dwErrCode = GetLastError();
996 if (!CloseHandle(buf->hFile) && !result) {
998 dwErrCode = GetLastError();
1000 buf->hFile = INVALID_HANDLE_VALUE;
1004 MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) {
1008 dwErrCode = GetLastError();
1014 SetLastError(buf->dwErrCode = dwErrCode);
1016 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
1023 if (!result && fsync(buf->
fd) == -1) {
1028 if (close(buf->
fd) == -1 && !result) {
1042 if (!result && fsync(buf->
dirfd) == -1) {
1047 if (close(buf->
dirfd) == -1 && !result) {
1054 errno = buf->
errsv = errsv;
1063 if (!result && buf->last < buf->size) {
1068 while (!result && buf->last < buf->size) {
1069 if (fputc(0, buf->stream) == EOF) {
1079 if (!result && fflush(buf->stream) == EOF) {
1085 if (fclose(buf->stream) == EOF && !result) {
1110 #endif // !LELY_NO_STDIO