27 #define _LARGEFILE64_SOURCE 1
40 #pragma comment(lib, "shlwapi.lib")
45 #if _POSIX_C_SOURCE >= 200112L
48 #if _POSIX_MAPPED_FILES >= 200112L
67 HANDLE hFileMappingObject;
71 SIZE_T dwNumberOfBytesToMap;
72 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
111 void *ptr = malloc(
sizeof(
struct __fwbuf));
118 __fwbuf_free(
void *ptr)
139 char dir[MAX_PATH - 14];
140 strncpy(dir, buf->
filename, MAX_PATH - 14 - 1);
141 dir[MAX_PATH - 14 - 1] =
'\0';
142 PathRemoveFileSpecA(dir);
148 if (!GetTempFileNameA(dir,
"tmp", 0, buf->
tmpname)) {
149 dwErrCode = GetLastError();
150 goto error_GetTempFileNameA;
153 buf->hFile = CreateFileA(buf->
tmpname, GENERIC_READ | GENERIC_WRITE, 0,
154 NULL, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
155 if (buf->hFile == INVALID_HANDLE_VALUE) {
156 dwErrCode = GetLastError();
157 goto error_CreateFileA;
162 buf->hFileMappingObject = INVALID_HANDLE_VALUE;
163 buf->lpBaseAddress = NULL;
164 buf->dwNumberOfBytesToMap = 0;
170 error_GetTempFileNameA:
173 SetLastError(dwErrCode);
175 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
181 goto error_strdup_filename;
187 goto error_strdup_tmp;
189 char *dir = dirname(tmp);
190 size_t n = strlen(dir);
192 buf->
dirfd = open(dir, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
193 if (buf->
dirfd == -1) {
195 goto error_open_dirfd;
201 goto error_malloc_tmpname;
205 if (!n || buf->
tmpname[n - 1] !=
'/')
206 strcat(buf->
tmpname,
"/.tmp-XXXXXX");
208 strcat(buf->
tmpname,
".tmp-XXXXXX");
214 buf->
fd = mkostemp(buf->
tmpname, O_CLOEXEC);
224 if (fcntl(buf->
fd, F_SETFD, FD_CLOEXEC) == -1) {
232 buf->
addr = MAP_FAILED;
242 error_malloc_tmpname:
249 error_strdup_filename:
262 buf->stream = fopen(tmpnam(buf->
tmpname),
"w+b");
288 __fwbuf_fini(
struct __fwbuf *buf)
295 #if _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
306 fwbuf_t *buf = __fwbuf_alloc();
309 goto error_alloc_buf;
342 LARGE_INTEGER FileSize;
343 if (!GetFileSizeEx(buf->hFile, &FileSize)) {
344 buf->dwErrCode = GetLastError();
347 return FileSize.QuadPart;
348 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
351 if (fstat64(buf->
fd, &stat) == -1) {
354 if (fstat(buf->
fd, &stat) == -1) {
379 if (!SetEndOfFile(buf->hFile)) {
380 buf->dwErrCode = GetLastError();
388 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
390 if (ftruncate64(buf->
fd, size) == -1) {
393 if (ftruncate(buf->
fd, size) == -1) {
400 if (size < buf->last) {
418 LARGE_INTEGER li = { .QuadPart = 0 };
419 if (!SetFilePointerEx(buf->hFile, li, &li, FILE_CURRENT)) {
420 buf->dwErrCode = GetLastError();
424 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
426 intmax_t pos = lseek64(buf->
fd, 0, SEEK_CUR);
428 intmax_t pos = lseek(buf->
fd, 0, SEEK_CUR);
434 long pos = ftell(buf->stream);
450 LARGE_INTEGER li = { .QuadPart = pos };
451 if (!SetFilePointerEx(buf->hFile, li, &li, FILE_BEGIN)) {
452 buf->dwErrCode = GetLastError();
456 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
458 pos = lseek64(buf->
fd, pos, SEEK_SET);
460 pos = lseek(buf->
fd, pos, SEEK_SET);
470 if (pos > LONG_MAX) {
475 if (fseek(buf->stream, pos, SEEK_SET)) {
488 assert(ptr || !size);
497 DWORD nNumberOfBytesWritten;
498 if (!WriteFile(buf->hFile, ptr, size, &nNumberOfBytesWritten, NULL)) {
499 buf->dwErrCode = GetLastError();
502 return nNumberOfBytesWritten;
503 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
506 result = write(buf->
fd, ptr, size);
507 while (result == -1 && errno == EINTR);
516 size_t result = fwrite(ptr, 1, size, buf->stream);
517 if (result != size && ferror(buf->stream)) {
525 if (buf->map && pos < buf->pos + (intmax_t)buf->
len
526 && pos + (intmax_t)size > buf->pos) {
527 size_t begin =
MAX(pos - buf->pos, 0);
528 size_t end =
MIN(pos + size - buf->pos, buf->
len);
529 memmove((
char *)buf->map + begin, ptr, end - begin);
532 buf->last =
MAX(buf->last, pos + (intmax_t)result);
533 buf->size =
MAX(buf->size, buf->last);
542 assert(ptr || !size);
555 buf->dwErrCode = ERROR_INVALID_PARAMETER;
565 DWORD nNumberOfBytesWritten;
566 OVERLAPPED Overlapped = { 0 };
567 ULARGE_INTEGER uli = { .QuadPart = pos };
568 Overlapped.Offset = uli.LowPart;
569 Overlapped.OffsetHigh = uli.HighPart;
571 if (!WriteFile(buf->hFile, ptr, size, &nNumberOfBytesWritten,
575 buf->dwErrCode = GetLastError();
576 goto error_WriteFile;
579 result = nNumberOfBytesWritten;
585 SetLastError(buf->dwErrCode);
587 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
591 result = pwrite64(buf->
fd, ptr, size, pos);
594 result = pwrite(buf->
fd, ptr, size, pos);
596 while (result == -1 && errno == EINTR);
618 if (buf->last < pos) {
623 while (buf->last < pos) {
624 if (fputc(0, buf->stream) == EOF) {
630 buf->size =
MAX(buf->size, buf->last);
640 if (result == -1 || (
size_t)result != size)
665 SetLastError(buf->dwErrCode = ERROR_INVALID_PARAMETER);
666 #elif _POSIX_MAPPED_FILES >= 200112L
667 errno = buf->
errsv = EINVAL;
673 if (pos > (intmax_t)size) {
675 SetLastError(buf->dwErrCode = ERROR_INVALID_PARAMETER);
676 #elif _POSIX_MAPPED_FILES >= 200112L
677 errno = buf->
errsv = EOVERFLOW;
686 size =
MIN((uintmax_t)size, *psize);
689 SYSTEM_INFO SystemInfo;
690 GetSystemInfo(&SystemInfo);
691 DWORD off = pos % SystemInfo.dwAllocationGranularity;
692 if ((uintmax_t)size > (uintmax_t)(SIZE_MAX - off)) {
693 buf->dwErrCode = ERROR_INVALID_PARAMETER;
697 ULARGE_INTEGER MaximumSize = { .QuadPart = pos + size };
698 buf->hFileMappingObject = CreateFileMapping(buf->hFile, NULL,
699 PAGE_READWRITE, MaximumSize.HighPart,
700 MaximumSize.LowPart, NULL);
701 if (buf->hFileMappingObject == INVALID_HANDLE_VALUE) {
702 buf->dwErrCode = GetLastError();
703 goto error_CreateFileMapping;
706 ULARGE_INTEGER FileOffset = { .QuadPart = pos - off };
707 buf->lpBaseAddress = MapViewOfFile(buf->hFileMappingObject,
708 FILE_MAP_WRITE, FileOffset.HighPart, FileOffset.LowPart,
709 (SIZE_T)(off + size));
710 if (!buf->lpBaseAddress) {
711 buf->dwErrCode = GetLastError();
712 goto error_MapViewOfFile;
716 *psize = (size_t)size;
718 return (
char *)buf->lpBaseAddress + off;
721 CloseHandle(buf->hFileMappingObject);
722 buf->hFileMappingObject = INVALID_HANDLE_VALUE;
723 error_CreateFileMapping:
725 SetLastError(buf->dwErrCode);
727 #elif _POSIX_MAPPED_FILES >= 200112L
728 long page_size = sysconf(_SC_PAGE_SIZE);
729 if (page_size <= 0) {
733 intmax_t off = pos % page_size;
734 if ((uintmax_t)size > (uintmax_t)(SIZE_MAX - off)) {
735 errno = buf->
errsv = EOVERFLOW;
740 buf->
addr = mmap64(NULL, off + size, PROT_READ | PROT_WRITE, MAP_SHARED,
744 buf->
addr = mmap(NULL, off + size, PROT_READ | PROT_WRITE, MAP_SHARED,
747 if (buf->
addr == MAP_FAILED) {
751 buf->
len = off + size;
756 return (
char *)buf->
addr + off;
760 if ((uintmax_t)size > SIZE_MAX) {
765 buf->map = calloc(size, 1);
769 goto error_malloc_map;
775 if (pos < buf->last) {
787 size_t nitems =
MIN(size, buf->last - pos);
788 if (fread(buf->map, 1, nitems, buf->stream) != nitems
789 && ferror(buf->stream)) {
830 if (buf->dwErrCode) {
832 dwErrCode = buf->dwErrCode;
835 if (buf->hFileMappingObject != INVALID_HANDLE_VALUE) {
837 if (!FlushViewOfFile(buf->lpBaseAddress,
838 buf->dwNumberOfBytesToMap) && !result) {
841 dwErrCode = GetLastError();
843 if (!UnmapViewOfFile(buf->lpBaseAddress) && !result) {
845 dwErrCode = GetLastError();
847 if (!CloseHandle(buf->hFileMappingObject) && !result) {
849 dwErrCode = GetLastError();
852 buf->hFileMappingObject = INVALID_HANDLE_VALUE;
853 buf->lpBaseAddress = NULL;
854 buf->dwNumberOfBytesToMap = 0;
859 buf->dwErrCode = dwErrCode;
860 SetLastError(dwErrCode);
862 #elif _POSIX_MAPPED_FILES >= 200112L
869 if (buf->
addr != MAP_FAILED) {
870 if (msync(buf->
addr, buf->
len, MS_SYNC) == -1 && !result) {
874 if (munmap(buf->
addr, buf->
len) == -1 && !result) {
879 buf->
addr = MAP_FAILED;
899 void *map = buf->map;
930 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
944 SetLastError(buf->dwErrCode);
945 return !!buf->dwErrCode;
946 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
953 return !!buf->errnum;
964 buf->dwErrCode = ERROR_OPERATION_ABORTED;
965 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
967 buf->
errsv = ECANCELED;
981 DWORD dwErrCode = GetLastError();
983 if (buf->hFile == INVALID_HANDLE_VALUE)
987 if (!result && !FlushFileBuffers(buf->hFile)) {
989 dwErrCode = GetLastError();
992 if (!CloseHandle(buf->hFile) && !result) {
994 dwErrCode = GetLastError();
996 buf->hFile = INVALID_HANDLE_VALUE;
1000 MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) {
1004 dwErrCode = GetLastError();
1010 SetLastError(buf->dwErrCode = dwErrCode);
1012 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__)
1019 if (!result && fsync(buf->
fd) == -1) {
1024 if (close(buf->
fd) == -1 && !result) {
1038 if (!result && fsync(buf->
dirfd) == -1) {
1043 if (close(buf->
dirfd) == -1 && !result) {
1050 errno = buf->
errsv = errsv;
1059 if (!result && buf->last < buf->size) {
1064 while (!result && buf->last < buf->size) {
1065 if (fputc(0, buf->stream) == EOF) {
1075 if (!result && fflush(buf->stream) == EOF) {
1081 if (fclose(buf->stream) == EOF && !result) {