Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/lzma/src/7zFile.c
4253 views
1
/* 7zFile.c -- File IO
2
2023-04-02 : Igor Pavlov : Public domain */
3
4
#include "Precomp.h"
5
6
#include "7zFile.h"
7
8
#ifndef USE_WINDOWS_FILE
9
10
#include <errno.h>
11
12
#ifndef USE_FOPEN
13
#include <stdio.h>
14
#include <fcntl.h>
15
#ifdef _WIN32
16
#include <io.h>
17
typedef int ssize_t;
18
typedef int off_t;
19
#else
20
#include <unistd.h>
21
#endif
22
#endif
23
24
#else
25
26
/*
27
ReadFile and WriteFile functions in Windows have BUG:
28
If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
29
from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
30
(Insufficient system resources exist to complete the requested service).
31
Probably in some version of Windows there are problems with other sizes:
32
for 32 MB (maybe also for 16 MB).
33
And message can be "Network connection was lost"
34
*/
35
36
#endif
37
38
#define kChunkSizeMax (1 << 22)
39
40
void File_Construct(CSzFile *p)
41
{
42
#ifdef USE_WINDOWS_FILE
43
p->handle = INVALID_HANDLE_VALUE;
44
#elif defined(USE_FOPEN)
45
p->file = NULL;
46
#else
47
p->fd = -1;
48
#endif
49
}
50
51
#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
52
53
static WRes File_Open(CSzFile *p, const char *name, int writeMode)
54
{
55
#ifdef USE_WINDOWS_FILE
56
57
p->handle = CreateFileA(name,
58
writeMode ? GENERIC_WRITE : GENERIC_READ,
59
FILE_SHARE_READ, NULL,
60
writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
61
FILE_ATTRIBUTE_NORMAL, NULL);
62
return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
63
64
#elif defined(USE_FOPEN)
65
66
p->file = fopen(name, writeMode ? "wb+" : "rb");
67
return (p->file != 0) ? 0 :
68
#ifdef UNDER_CE
69
2; /* ENOENT */
70
#else
71
errno;
72
#endif
73
74
#else
75
76
int flags = (writeMode ? (O_CREAT | O_EXCL | O_WRONLY) : O_RDONLY);
77
#ifdef O_BINARY
78
flags |= O_BINARY;
79
#endif
80
p->fd = open(name, flags, 0666);
81
return (p->fd != -1) ? 0 : errno;
82
83
#endif
84
}
85
86
WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); }
87
88
WRes OutFile_Open(CSzFile *p, const char *name)
89
{
90
#if defined(USE_WINDOWS_FILE) || defined(USE_FOPEN)
91
return File_Open(p, name, 1);
92
#else
93
p->fd = creat(name, 0666);
94
return (p->fd != -1) ? 0 : errno;
95
#endif
96
}
97
98
#endif
99
100
101
#ifdef USE_WINDOWS_FILE
102
static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode)
103
{
104
p->handle = CreateFileW(name,
105
writeMode ? GENERIC_WRITE : GENERIC_READ,
106
FILE_SHARE_READ, NULL,
107
writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
108
FILE_ATTRIBUTE_NORMAL, NULL);
109
return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
110
}
111
WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); }
112
WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); }
113
#endif
114
115
WRes File_Close(CSzFile *p)
116
{
117
#ifdef USE_WINDOWS_FILE
118
119
if (p->handle != INVALID_HANDLE_VALUE)
120
{
121
if (!CloseHandle(p->handle))
122
return GetLastError();
123
p->handle = INVALID_HANDLE_VALUE;
124
}
125
126
#elif defined(USE_FOPEN)
127
128
if (p->file != NULL)
129
{
130
int res = fclose(p->file);
131
if (res != 0)
132
{
133
if (res == EOF)
134
return errno;
135
return res;
136
}
137
p->file = NULL;
138
}
139
140
#else
141
142
if (p->fd != -1)
143
{
144
if (close(p->fd) != 0)
145
return errno;
146
p->fd = -1;
147
}
148
149
#endif
150
151
return 0;
152
}
153
154
155
WRes File_Read(CSzFile *p, void *data, size_t *size)
156
{
157
size_t originalSize = *size;
158
*size = 0;
159
if (originalSize == 0)
160
return 0;
161
162
#ifdef USE_WINDOWS_FILE
163
164
do
165
{
166
const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
167
DWORD processed = 0;
168
const BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL);
169
data = (void *)((Byte *)data + processed);
170
originalSize -= processed;
171
*size += processed;
172
if (!res)
173
return GetLastError();
174
// debug : we can break here for partial reading mode
175
if (processed == 0)
176
break;
177
}
178
while (originalSize > 0);
179
180
#elif defined(USE_FOPEN)
181
182
do
183
{
184
const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
185
const size_t processed = fread(data, 1, curSize, p->file);
186
data = (void *)((Byte *)data + (size_t)processed);
187
originalSize -= processed;
188
*size += processed;
189
if (processed != curSize)
190
return ferror(p->file);
191
// debug : we can break here for partial reading mode
192
if (processed == 0)
193
break;
194
}
195
while (originalSize > 0);
196
197
#else
198
199
do
200
{
201
const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
202
const ssize_t processed = read(p->fd, data, curSize);
203
if (processed == -1)
204
return errno;
205
if (processed == 0)
206
break;
207
data = (void *)((Byte *)data + (size_t)processed);
208
originalSize -= (size_t)processed;
209
*size += (size_t)processed;
210
// debug : we can break here for partial reading mode
211
// break;
212
}
213
while (originalSize > 0);
214
215
#endif
216
217
return 0;
218
}
219
220
221
WRes File_Write(CSzFile *p, const void *data, size_t *size)
222
{
223
size_t originalSize = *size;
224
*size = 0;
225
if (originalSize == 0)
226
return 0;
227
228
#ifdef USE_WINDOWS_FILE
229
230
do
231
{
232
const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
233
DWORD processed = 0;
234
const BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL);
235
data = (const void *)((const Byte *)data + processed);
236
originalSize -= processed;
237
*size += processed;
238
if (!res)
239
return GetLastError();
240
if (processed == 0)
241
break;
242
}
243
while (originalSize > 0);
244
245
#elif defined(USE_FOPEN)
246
247
do
248
{
249
const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
250
const size_t processed = fwrite(data, 1, curSize, p->file);
251
data = (void *)((Byte *)data + (size_t)processed);
252
originalSize -= processed;
253
*size += processed;
254
if (processed != curSize)
255
return ferror(p->file);
256
if (processed == 0)
257
break;
258
}
259
while (originalSize > 0);
260
261
#else
262
263
do
264
{
265
const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
266
const ssize_t processed = write(p->fd, data, curSize);
267
if (processed == -1)
268
return errno;
269
if (processed == 0)
270
break;
271
data = (const void *)((const Byte *)data + (size_t)processed);
272
originalSize -= (size_t)processed;
273
*size += (size_t)processed;
274
}
275
while (originalSize > 0);
276
277
#endif
278
279
return 0;
280
}
281
282
283
WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin)
284
{
285
#ifdef USE_WINDOWS_FILE
286
287
DWORD moveMethod;
288
UInt32 low = (UInt32)*pos;
289
LONG high = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */
290
// (int) to eliminate clang warning
291
switch ((int)origin)
292
{
293
case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break;
294
case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break;
295
case SZ_SEEK_END: moveMethod = FILE_END; break;
296
default: return ERROR_INVALID_PARAMETER;
297
}
298
low = SetFilePointer(p->handle, (LONG)low, &high, moveMethod);
299
if (low == (UInt32)0xFFFFFFFF)
300
{
301
WRes res = GetLastError();
302
if (res != NO_ERROR)
303
return res;
304
}
305
*pos = ((Int64)high << 32) | low;
306
return 0;
307
308
#else
309
310
int moveMethod; // = origin;
311
312
switch ((int)origin)
313
{
314
case SZ_SEEK_SET: moveMethod = SEEK_SET; break;
315
case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break;
316
case SZ_SEEK_END: moveMethod = SEEK_END; break;
317
default: return EINVAL;
318
}
319
320
#if defined(USE_FOPEN)
321
{
322
int res = fseek(p->file, (long)*pos, moveMethod);
323
if (res == -1)
324
return errno;
325
*pos = ftell(p->file);
326
if (*pos == -1)
327
return errno;
328
return 0;
329
}
330
#else
331
{
332
off_t res = lseek(p->fd, (off_t)*pos, moveMethod);
333
if (res == -1)
334
return errno;
335
*pos = res;
336
return 0;
337
}
338
339
#endif // USE_FOPEN
340
#endif // USE_WINDOWS_FILE
341
}
342
343
344
WRes File_GetLength(CSzFile *p, UInt64 *length)
345
{
346
#ifdef USE_WINDOWS_FILE
347
348
DWORD sizeHigh;
349
DWORD sizeLow = GetFileSize(p->handle, &sizeHigh);
350
if (sizeLow == 0xFFFFFFFF)
351
{
352
DWORD res = GetLastError();
353
if (res != NO_ERROR)
354
return res;
355
}
356
*length = (((UInt64)sizeHigh) << 32) + sizeLow;
357
return 0;
358
359
#elif defined(USE_FOPEN)
360
361
long pos = ftell(p->file);
362
int res = fseek(p->file, 0, SEEK_END);
363
*length = ftell(p->file);
364
fseek(p->file, pos, SEEK_SET);
365
return res;
366
367
#else
368
369
off_t pos;
370
*length = 0;
371
pos = lseek(p->fd, 0, SEEK_CUR);
372
if (pos != -1)
373
{
374
const off_t len2 = lseek(p->fd, 0, SEEK_END);
375
const off_t res2 = lseek(p->fd, pos, SEEK_SET);
376
if (len2 != -1)
377
{
378
*length = (UInt64)len2;
379
if (res2 != -1)
380
return 0;
381
}
382
}
383
return errno;
384
385
#endif
386
}
387
388
389
/* ---------- FileSeqInStream ---------- */
390
391
static SRes FileSeqInStream_Read(ISeqInStreamPtr pp, void *buf, size_t *size)
392
{
393
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileSeqInStream)
394
const WRes wres = File_Read(&p->file, buf, size);
395
p->wres = wres;
396
return (wres == 0) ? SZ_OK : SZ_ERROR_READ;
397
}
398
399
void FileSeqInStream_CreateVTable(CFileSeqInStream *p)
400
{
401
p->vt.Read = FileSeqInStream_Read;
402
}
403
404
405
/* ---------- FileInStream ---------- */
406
407
static SRes FileInStream_Read(ISeekInStreamPtr pp, void *buf, size_t *size)
408
{
409
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileInStream)
410
const WRes wres = File_Read(&p->file, buf, size);
411
p->wres = wres;
412
return (wres == 0) ? SZ_OK : SZ_ERROR_READ;
413
}
414
415
static SRes FileInStream_Seek(ISeekInStreamPtr pp, Int64 *pos, ESzSeek origin)
416
{
417
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileInStream)
418
const WRes wres = File_Seek(&p->file, pos, origin);
419
p->wres = wres;
420
return (wres == 0) ? SZ_OK : SZ_ERROR_READ;
421
}
422
423
void FileInStream_CreateVTable(CFileInStream *p)
424
{
425
p->vt.Read = FileInStream_Read;
426
p->vt.Seek = FileInStream_Seek;
427
}
428
429
430
/* ---------- FileOutStream ---------- */
431
432
static size_t FileOutStream_Write(ISeqOutStreamPtr pp, const void *data, size_t size)
433
{
434
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileOutStream)
435
const WRes wres = File_Write(&p->file, data, &size);
436
p->wres = wres;
437
return size;
438
}
439
440
void FileOutStream_CreateVTable(CFileOutStream *p)
441
{
442
p->vt.Write = FileOutStream_Write;
443
}
444
445