-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFile.h
More file actions
277 lines (243 loc) · 12.8 KB
/
Copy pathFile.h
File metadata and controls
277 lines (243 loc) · 12.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
/* Copyright (C) 2020-2026 Stuart Calder
* See accompanying LICENSE file for licensing information. */
#ifndef SSC_FILE_H
#define SSC_FILE_H
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Macro.h"
#include "Error.h"
#include "Typedef.h"
#define SSC_FILE_DEFAULT_NEWFILE_SIZE 0
#if defined(SSC_OS_UNIXLIKE)
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
/* On Unix-like systems, files are managed through integer handles, "file descriptors". */
typedef int SSC_File_t;
#define SSC_FILE_IS_INT
#define SSC_FILE_NULL_LITERAL (-1) /* -1 is an invalid file descriptor representing failure. */
#ifdef __linux__
/* Assume that memfd_secret() is supported if no Linux kernel version is specified. */
#if !SSC_LINUX_VERSION_VALUE_ISDEFINED || (SSC_LINUX_VERSION_VALUE >= SSC_LINUX_VERSION(5, 14, 0))
#define SSC_FILE_HAS_CREATESECRET
#endif
#endif
#elif defined(SSC_OS_WINDOWS)
#include <windows.h>
#include <direct.h>
/* On Windows systems, files are managed through HANDLEs. */
typedef HANDLE SSC_File_t;
#define SSC_FILE_NULL_LITERAL INVALID_HANDLE_VALUE
#else
#error "Unsupported operating system."
#endif /* ~ if defined (SSC_OS_UNIXLIKE) or defined (SSC_OS_WINDOWS) */
#define R_ SSC_RESTRICT
SSC_BEGIN_C_DECLS
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Get the size of a file in bytes. */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API SSC_Error_t
SSC_File_getSize(SSC_File_t file, size_t* R_ storesize);
SSC_INLINE size_t
SSC_File_getSizeOrDie(SSC_File_t file)
{
size_t s;
#ifdef SSC_FILE_IS_INT
SSC_assertMsg(SSC_File_getSize(file, &s) == SSC_OK, "Error: SSC_File_getSize() failed to store the size of file %d at %p!", file, (void*)&s);
#else
SSC_assertMsg(SSC_File_getSize(file, &s) == SSC_OK, "Error: SSC_File_getSize() failed to store the size of a file at %p!", (void*)&s);
#endif
return s;
}
/*==========================================================================================*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Get the size of a file at a specified filepath in bytes. */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API SSC_Error_t
SSC_FilePath_getSize(const char* R_ fpath, size_t* R_ storesize);
SSC_INLINE size_t
SSC_FilePath_getSizeOrDie(const char* fpath)
{
size_t s;
SSC_assertMsg(SSC_FilePath_getSize(fpath, &s) == SSC_OK, "Error: SSC_FilePath_getSize() failed to obtain the size of %s!\n", fpath);
return s;
}
/*==========================================================================================*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Is there a file at a specified filepath? */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API bool
SSC_FilePath_exists(const char* fpath);
/* ->true : There is a file.
* ->false: There is not a file. */
/*==========================================================================================*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* If @control is true, force a file to exist at @fpath; otherwise force a file to NOT exist at @fpath. */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API void
SSC_FilePath_forceExistOrDie(const char* R_ fpath, bool control);
/*==========================================================================================*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Open the file at a specified filepath. */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API SSC_Error_t
SSC_FilePath_open(const char* R_ fpath, bool ronly, SSC_File_t* R_ file);
SSC_INLINE SSC_File_t
SSC_FilePath_openOrDie(const char* R_ fpath, bool ronly)
{
SSC_File_t f;
SSC_assertMsg(
SSC_FilePath_open(fpath, ronly, &f) == SSC_OK,
"Error: SSC_FilePath_open() failed to open %s as %s!\n",
fpath,
ronly ? "ReadOnly" : "ReadWrite");
return f;
}
/*==========================================================================================*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Create a file at a specified filepath. */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API SSC_Error_t
SSC_FilePath_create(const char* R_ fpath, SSC_File_t* R_ file);
SSC_INLINE SSC_File_t
SSC_FilePath_createOrDie(const char* fpath)
{
SSC_File_t f;
SSC_assertMsg(SSC_FilePath_create(fpath, &f) == SSC_OK, "Error: SSC_FilePath_create() failed to create %s!\n", fpath);
return f;
}
/*==========================================================================================*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Open an existing file for appending. The file pointer is positioned at end-of-file so that all writes occur after existing content, without affecting other readers or writers (on systems that support atomic append). */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API SSC_Error_t
SSC_FilePath_openAppend(const char* R_ fpath, SSC_File_t* R_ storefile);
SSC_INLINE SSC_File_t
SSC_FilePath_openAppendOrDie(const char* R_ fpath)
{
SSC_File_t f;
SSC_assertMsg(SSC_FilePath_openAppend(fpath, &f) == SSC_OK, "Error: SSC_FilePath_openAppend() failed to open %s for appending!\n", fpath);
return f;
}
/*==========================================================================================*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Create a new file at @fpath if it does not already exist. If the file already exists, truncate it to zero bytes. Always opens read-write. */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API SSC_Error_t
SSC_FilePath_createOrTruncate(const char* R_ fpath, SSC_File_t* R_ storefile);
SSC_INLINE SSC_File_t
SSC_FilePath_createOrTruncateOrDie(const char* R_ fpath)
{
SSC_File_t f;
SSC_assertMsg(SSC_FilePath_createOrTruncate(fpath, &f) == SSC_OK, "Error: SSC_FilePath_createOrTruncate() failed to create or truncate %s!\n", fpath);
return f;
}
/*==========================================================================================*/
#ifdef SSC_FILE_HAS_CREATESECRET
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Create a "secret" file, with more protections than usually afforded by RAM-backed
* filesytems. */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API SSC_Error_t
SSC_File_createSecret(SSC_File_t* file);
/*==========================================================================================*/
#endif /* ! SSC_FILE_HAS_CREATESECRET */
SSC_API bool
SSC_File_createSecretIsAvailable(void);
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Close the file associed with a specified file handle. */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API SSC_Error_t
SSC_File_close(SSC_File_t file);
SSC_INLINE void
SSC_File_closeOrDie(SSC_File_t file)
{
#ifdef SSC_FILE_IS_INT
SSC_assertMsg(SSC_File_close(file) == SSC_OK, "Error: SSC_File_close() failed to close file %d!\n", file);
#else
SSC_assertMsg(SSC_File_close(file) == SSC_OK, SSC_ERR_S_FAILED_IN("SSC_File_close()"));
#endif
}
/*==========================================================================================*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Set the size of a file in bytes. */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API SSC_Error_t
SSC_File_setSize(SSC_File_t file, size_t size);
SSC_INLINE void
SSC_File_setSizeOrDie(SSC_File_t file, size_t size)
{
#ifdef SSC_FILE_IS_INT
SSC_assertMsg(SSC_File_setSize(file, size) == SSC_OK, "Error: SSC_File_setSize() failed to set file %d to size %zu!\n", file, size);
#else
SSC_assertMsg(SSC_File_setSize(file, size) == SSC_OK, "Error: SSC_File_setSize() failed to set a file to size %zu!\n", size);
#endif
}
/*==========================================================================================*/
enum {
/* Read */
SSC_FILE_READ_OK = 0, /* All @count bytes read successfully */
SSC_FILE_READ_EOF = -1, /* EOF reached before all bytes transferred; *stored_count holds partial count */
SSC_FILE_READ_ERR = -2, /* I/O error (no bytes read) */
/* Write */
SSC_FILE_WRITE_OK = 0, /* All @count bytes written successfully */
SSC_FILE_WRITE_PARTIAL = -1, /* Write error mid-stream; *stored_count holds partial count */
SSC_FILE_WRITE_ERR = -2, /* General write failure. */
/* Seek */
SSC_FILE_SEEK_ERR = -3, /* lseek/SetFilePointerEx failed */
};
/* Seek to end-of-file. */
#define SSC_FILE_SEEK_END ((SSC_ssize_t)-1)
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Read up to @count bytes from @file into @buf. Returns:
* SSC_FILE_READ_OK : All @count bytes successfully read.
* SSC_FILE_READ_EOF : EOF reached before all bytes transferred; *stored_count holds partial count. */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API SSC_CodeError_t
SSC_File_read(SSC_File_t file, void* R_ buf, size_t count, SSC_ssize_t* R_ stored_count);
/*==========================================================================================*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Write up to @count bytes from @buf to @file. Returns:
* SSC_FILE_WRITE_OK : All @count bytes successfully written.
* SSC_FILE_WRITE_PARTIAL: Write error mid-stream; *stored_count holds partial count. */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API SSC_CodeError_t
SSC_File_write(SSC_File_t file, const void* R_ buf, size_t count, SSC_ssize_t* R_ stored_count);
/*==========================================================================================*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Seek to @offset within @file. Pass @SSC_FILE_SEEK_END for end-of-file (negative offsets are treated as SEEK_END). */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API SSC_Error_t
SSC_File_seek(SSC_File_t file, SSC_ssize_t offset);
/*==========================================================================================*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Seek to @offset within @file and read up to @count bytes into @buf. Returns:
* SSC_FILE_READ_OK : All @count bytes successfully read after seek.
* SSC_FILE_READ_EOF : EOF reached before all bytes transferred; *stored_count holds partial count.
* SSC_FILE_SEEK_ERR : Seek failed (no read attempted). */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API SSC_CodeError_t
SSC_File_seekRead(SSC_File_t file, SSC_ssize_t offset, void* R_ buf, size_t count, SSC_ssize_t* R_ stored_count);
/*==========================================================================================*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Seek to @offset within @file and write up to @count bytes from @buf. Returns:
* SSC_FILE_WRITE_OK : All @count bytes successfully written after seek.
* SSC_FILE_WRITE_PARTIAL: Write error mid-stream; *stored_count holds partial count.
* SSC_FILE_SEEK_ERR : Seek failed (no write attempted). */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API SSC_CodeError_t
SSC_File_seekWrite(SSC_File_t file, SSC_ssize_t offset, const void* R_ buf, size_t count, SSC_ssize_t* R_ stored_count);
/*==========================================================================================*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* Change the current working directory to @path. */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
SSC_API SSC_Error_t
SSC_chdir(const char* path);
/*==========================================================================================*/
SSC_END_C_DECLS
#undef R_
#endif /* ~ SSC_FILE_H */