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:
261 buf->stream = fopen(tmpnam(buf->
tmpname),
"w+b");
287 __fwbuf_fini(
struct __fwbuf *buf)
294 #if _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__) 305 fwbuf_t *buf = __fwbuf_alloc();
308 goto error_alloc_buf;
341 LARGE_INTEGER FileSize;
342 if (!GetFileSizeEx(buf->hFile, &FileSize)) {
343 buf->dwErrCode = GetLastError();
346 return FileSize.QuadPart;
347 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__) 350 if (fstat64(buf->
fd, &stat) == -1) {
353 if (fstat(buf->
fd, &stat) == -1) {
378 if (!SetEndOfFile(buf->hFile)) {
379 buf->dwErrCode = GetLastError();
387 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__) 389 if (ftruncate64(buf->
fd, size) == -1) {
392 if (ftruncate(buf->
fd, size) == -1) {
399 if (size < buf->last) {
417 LARGE_INTEGER li = { .QuadPart = 0 };
418 if (!SetFilePointerEx(buf->hFile, li, &li, FILE_CURRENT)) {
419 buf->dwErrCode = GetLastError();
423 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__) 425 intmax_t pos = lseek64(buf->
fd, 0, SEEK_CUR);
427 intmax_t pos = lseek(buf->
fd, 0, SEEK_CUR);
433 long pos = ftell(buf->stream);
449 LARGE_INTEGER li = { .QuadPart = pos };
450 if (!SetFilePointerEx(buf->hFile, li, &li, FILE_BEGIN)) {
451 buf->dwErrCode = GetLastError();
455 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__) 457 pos = lseek64(buf->
fd, pos, SEEK_SET);
459 pos = lseek(buf->
fd, pos, SEEK_SET);
469 if (pos > LONG_MAX) {
474 if (fseek(buf->stream, pos, SEEK_SET)) {
487 assert(ptr || !size);
496 DWORD nNumberOfBytesWritten;
497 if (!WriteFile(buf->hFile, ptr, size, &nNumberOfBytesWritten, NULL)) {
498 buf->dwErrCode = GetLastError();
501 return nNumberOfBytesWritten;
502 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__) 505 result = write(buf->
fd, ptr, size);
506 while (result == -1 && errno == EINTR);
515 size_t result = fwrite(ptr, 1, size, buf->stream);
516 if (result != size && ferror(buf->stream)) {
524 if (buf->map && pos < buf->pos + (intmax_t)buf->
len 525 && pos + (intmax_t)size > buf->pos) {
526 size_t begin =
MAX(pos - buf->pos, 0);
527 size_t end =
MIN(pos + size - buf->pos, buf->
len);
528 memmove((
char *)buf->map + begin, ptr, end - begin);
531 buf->last =
MAX(buf->last, pos + (intmax_t)result);
532 buf->size =
MAX(buf->size, buf->last);
541 assert(ptr || !size);
554 buf->dwErrCode = ERROR_INVALID_PARAMETER;
564 DWORD nNumberOfBytesWritten;
565 OVERLAPPED Overlapped = { 0 };
566 ULARGE_INTEGER uli = { .QuadPart = pos };
567 Overlapped.Offset = uli.LowPart;
568 Overlapped.OffsetHigh = uli.HighPart;
570 if (!WriteFile(buf->hFile, ptr, size, &nNumberOfBytesWritten,
574 buf->dwErrCode = GetLastError();
575 goto error_WriteFile;
578 result = nNumberOfBytesWritten;
584 SetLastError(buf->dwErrCode);
586 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__) 590 result = pwrite64(buf->
fd, ptr, size, pos);
593 result = pwrite(buf->
fd, ptr, size, pos);
595 while (result == -1 && errno == EINTR);
617 if (buf->last < pos) {
622 while (buf->last < pos) {
623 if (fputc(0, buf->stream) == EOF) {
629 buf->size =
MAX(buf->size, buf->last);
639 if (result == -1 || (
size_t)result != size)
664 SetLastError(buf->dwErrCode = ERROR_INVALID_PARAMETER);
665 #elif _POSIX_MAPPED_FILES >= 200112L 666 errno = buf->
errsv = EINVAL;
672 if (pos > (intmax_t)size) {
674 SetLastError(buf->dwErrCode = ERROR_INVALID_PARAMETER);
675 #elif _POSIX_MAPPED_FILES >= 200112L 676 errno = buf->
errsv = EOVERFLOW;
685 size =
MIN((uintmax_t)size, *psize);
688 SYSTEM_INFO SystemInfo;
689 GetSystemInfo(&SystemInfo);
690 DWORD off = pos % SystemInfo.dwAllocationGranularity;
691 if ((uintmax_t)size > (uintmax_t)(SIZE_MAX - off)) {
692 buf->dwErrCode = ERROR_INVALID_PARAMETER;
696 ULARGE_INTEGER MaximumSize = { .QuadPart = pos + size };
697 buf->hFileMappingObject = CreateFileMapping(buf->hFile, NULL,
698 PAGE_READWRITE, MaximumSize.HighPart,
699 MaximumSize.LowPart, NULL);
700 if (buf->hFileMappingObject == INVALID_HANDLE_VALUE) {
701 buf->dwErrCode = GetLastError();
702 goto error_CreateFileMapping;
705 ULARGE_INTEGER FileOffset = { .QuadPart = pos - off };
706 buf->lpBaseAddress = MapViewOfFile(buf->hFileMappingObject,
707 FILE_MAP_WRITE, FileOffset.HighPart, FileOffset.LowPart,
708 (SIZE_T)(off + size));
709 if (!buf->lpBaseAddress) {
710 buf->dwErrCode = GetLastError();
711 goto error_MapViewOfFile;
715 *psize = (size_t)size;
717 return (
char *)buf->lpBaseAddress + off;
720 CloseHandle(buf->hFileMappingObject);
721 buf->hFileMappingObject = INVALID_HANDLE_VALUE;
722 error_CreateFileMapping:
724 SetLastError(buf->dwErrCode);
726 #elif _POSIX_MAPPED_FILES >= 200112L 727 long page_size = sysconf(_SC_PAGE_SIZE);
728 if (page_size <= 0) {
732 intmax_t off = pos % page_size;
733 if ((uintmax_t)size > (uintmax_t)(SIZE_MAX - off)) {
734 errno = buf->
errsv = EOVERFLOW;
739 buf->
addr = mmap64(NULL, off + size, PROT_READ | PROT_WRITE, MAP_SHARED,
743 buf->
addr = mmap(NULL, off + size, PROT_READ | PROT_WRITE, MAP_SHARED,
746 if (buf->
addr == MAP_FAILED) {
750 buf->
len = off + size;
755 return (
char *)buf->
addr + off;
759 if ((uintmax_t)size > SIZE_MAX) {
764 buf->map = calloc(size, 1);
768 goto error_malloc_map;
774 if (pos < buf->last) {
786 size_t nitems =
MIN(size, buf->last - pos);
787 if (fread(buf->map, 1, nitems, buf->stream) != nitems
788 && ferror(buf->stream)) {
829 if (buf->dwErrCode) {
831 dwErrCode = buf->dwErrCode;
834 if (buf->hFileMappingObject != INVALID_HANDLE_VALUE) {
836 if (!FlushViewOfFile(buf->lpBaseAddress,
837 buf->dwNumberOfBytesToMap) && !result) {
840 dwErrCode = GetLastError();
842 if (!UnmapViewOfFile(buf->lpBaseAddress) && !result) {
844 dwErrCode = GetLastError();
846 if (!CloseHandle(buf->hFileMappingObject) && !result) {
848 dwErrCode = GetLastError();
851 buf->hFileMappingObject = INVALID_HANDLE_VALUE;
852 buf->lpBaseAddress = NULL;
853 buf->dwNumberOfBytesToMap = 0;
858 buf->dwErrCode = dwErrCode;
859 SetLastError(dwErrCode);
861 #elif _POSIX_MAPPED_FILES >= 200112L 868 if (buf->
addr != MAP_FAILED) {
869 if (msync(buf->
addr, buf->
len, MS_SYNC) == -1 && !result) {
873 if (munmap(buf->
addr, buf->
len) == -1 && !result) {
878 buf->
addr = MAP_FAILED;
898 void *map = buf->map;
929 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__) 943 SetLastError(buf->dwErrCode);
944 return !!buf->dwErrCode;
945 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__) 952 return !!buf->errnum;
963 buf->dwErrCode = ERROR_OPERATION_ABORTED;
964 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__) 966 buf->
errsv = ECANCELED;
980 DWORD dwErrCode = GetLastError();
982 if (buf->hFile == INVALID_HANDLE_VALUE)
986 if (!result && !FlushFileBuffers(buf->hFile)) {
988 dwErrCode = GetLastError();
991 if (!CloseHandle(buf->hFile) && !result) {
993 dwErrCode = GetLastError();
995 buf->hFile = INVALID_HANDLE_VALUE;
999 MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) {
1003 dwErrCode = GetLastError();
1009 SetLastError(buf->dwErrCode = dwErrCode);
1011 #elif _POSIX_C_SOURCE >= 200112L && !defined(__NEWLIB__) 1018 if (!result && fsync(buf->
fd) == -1) {
1023 if (close(buf->
fd) == -1 && !result) {
1037 if (!result && fsync(buf->
dirfd) == -1) {
1042 if (close(buf->
dirfd) == -1 && !result) {
1049 errno = buf->
errsv = errsv;
1058 if (!result && buf->last < buf->size) {
1063 while (!result && buf->last < buf->size) {
1064 if (fputc(0, buf->stream) == EOF) {
1074 if (!result && fflush(buf->stream) == EOF) {
1080 if (fclose(buf->stream) == EOF && !result) {
void * fwbuf_map(fwbuf_t *buf, intmax_t pos, size_t *psize)
Maps (part of) the contents of a write file buffer to memory.
This header file is part of the C11 and POSIX compatibility library; it includes <string.h> and defines any missing functionality.
int errsv
The number of the first error that occurred during a file operation.
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
void fwbuf_destroy(fwbuf_t *buf)
Destroys a write file buffer.
int fwbuf_error(fwbuf_t *buf)
Returns 1 if the error indicator of a write file buffer is set, and 0 if not.
#define MIN(a, b)
Returns the minimum of a and b.
void fwbuf_clearerr(fwbuf_t *buf)
Clears the error indicator of a write file buffer, allowing fwbuf_commit() to write the file to disk...
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
This header file is part of the utilities library; it contains the native and platform-independent er...
This is the internal header file of the utilities library.
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function...
#define MAX(a, b)
Returns the maximum of a and b.
intmax_t fwbuf_set_pos(fwbuf_t *buf, intmax_t pos)
Sets the current offset (in bytes) of a write file buffer with respect to the beginning of the file...
char * tmpname
A pointer to the name of the temporary file.
errnum_t errno2num(int errnum)
Transforms a standard C error number to a platform-independent error number.
ssize_t fwbuf_pwrite(fwbuf_t *buf, const void *ptr, size_t size, intmax_t pos)
Writes bytes to the specified position in a write file buffer.
fwbuf_t * fwbuf_create(const char *filename)
Creates a new (atomic) write file buffer.
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
errnum
The platform-independent error numbers.
int dirfd
The file descriptor of the directory containing the temporary file.
An (atomic) write file buffer struct.
errnum_t errc2num(int errc)
Transforms a native error code to a platform-independent error number.
char * filename
A pointer to the name of the file.
This header file is part of the C11 and POSIX compatibility library; it includes <stdio.h> and defines any missing functionality.
void fwbuf_cancel(fwbuf_t *buf)
Cancels any further file operations by setting the error indicator of a write file buffer to ERRNUM_C...
void * addr
The base address of the current file mapping.
int fwbuf_commit(fwbuf_t *buf)
Commits all changes to a write file buffer to disk if all previous file operations were successful...
int fd
The file descriptor.
This header file is part of the utilities library; it contains the (atomic) write file buffer declara...
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib.h> and defines any missing functionality.
ssize_t fwbuf_write(fwbuf_t *buf, const void *ptr, size_t size)
Writes bytes to the current position in a write file buffer.
intmax_t fwbuf_get_pos(fwbuf_t *buf)
Returns the current offset (in bytes) of a write file buffer with respect to the beginning of the fil...
int fwbuf_unmap(fwbuf_t *buf)
Unmaps the current memory map of a write file buffer, if it exists, and writes the changes to disk...
intmax_t fwbuf_get_size(fwbuf_t *buf)
Returns the current size (in bytes) of the a write file buffer, or -1 on error.
int fwbuf_set_size(fwbuf_t *buf, intmax_t size)
Sets the new size (in bytes) of the a write file buffer.
size_t len
The length (in bytes) of the mapping at addr.
Value too large to be stored in data type.