diff options
author | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2021-12-27 00:00:00 +0000 |
---|---|---|
committer | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2022-03-18 15:35:13 +0500 |
commit | f19f813537c7aea1c20749c914e756b54a9c3cf5 (patch) | |
tree | 816ba62ca7c0fa19f2eb46d9e9d6f7dd7c3a744d /C/7zFile.c | |
parent | 98e06a519b63b81986abe76d28887f6984a7732b (diff) | |
download | 7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.tar.gz 7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.tar.bz2 7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.zip |
'21.07'21.07
Diffstat (limited to 'C/7zFile.c')
-rw-r--r-- | C/7zFile.c | 442 |
1 files changed, 442 insertions, 0 deletions
diff --git a/C/7zFile.c b/C/7zFile.c new file mode 100644 index 0000000..13d2efa --- /dev/null +++ b/C/7zFile.c | |||
@@ -0,0 +1,442 @@ | |||
1 | /* 7zFile.c -- File IO | ||
2 | 2021-04-29 : 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 = (void *)((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 | switch (origin) | ||
291 | { | ||
292 | case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break; | ||
293 | case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break; | ||
294 | case SZ_SEEK_END: moveMethod = FILE_END; break; | ||
295 | default: return ERROR_INVALID_PARAMETER; | ||
296 | } | ||
297 | low = SetFilePointer(p->handle, (LONG)low, &high, moveMethod); | ||
298 | if (low == (UInt32)0xFFFFFFFF) | ||
299 | { | ||
300 | WRes res = GetLastError(); | ||
301 | if (res != NO_ERROR) | ||
302 | return res; | ||
303 | } | ||
304 | *pos = ((Int64)high << 32) | low; | ||
305 | return 0; | ||
306 | |||
307 | #else | ||
308 | |||
309 | int moveMethod; // = origin; | ||
310 | |||
311 | switch (origin) | ||
312 | { | ||
313 | case SZ_SEEK_SET: moveMethod = SEEK_SET; break; | ||
314 | case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break; | ||
315 | case SZ_SEEK_END: moveMethod = SEEK_END; break; | ||
316 | default: return EINVAL; | ||
317 | } | ||
318 | |||
319 | #if defined(USE_FOPEN) | ||
320 | { | ||
321 | int res = fseek(p->file, (long)*pos, moveMethod); | ||
322 | if (res == -1) | ||
323 | return errno; | ||
324 | *pos = ftell(p->file); | ||
325 | if (*pos == -1) | ||
326 | return errno; | ||
327 | return 0; | ||
328 | } | ||
329 | #else | ||
330 | { | ||
331 | off_t res = lseek(p->fd, (off_t)*pos, moveMethod); | ||
332 | if (res == -1) | ||
333 | return errno; | ||
334 | *pos = res; | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | #endif // USE_FOPEN | ||
339 | #endif // USE_WINDOWS_FILE | ||
340 | } | ||
341 | |||
342 | |||
343 | WRes File_GetLength(CSzFile *p, UInt64 *length) | ||
344 | { | ||
345 | #ifdef USE_WINDOWS_FILE | ||
346 | |||
347 | DWORD sizeHigh; | ||
348 | DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); | ||
349 | if (sizeLow == 0xFFFFFFFF) | ||
350 | { | ||
351 | DWORD res = GetLastError(); | ||
352 | if (res != NO_ERROR) | ||
353 | return res; | ||
354 | } | ||
355 | *length = (((UInt64)sizeHigh) << 32) + sizeLow; | ||
356 | return 0; | ||
357 | |||
358 | #elif defined(USE_FOPEN) | ||
359 | |||
360 | long pos = ftell(p->file); | ||
361 | int res = fseek(p->file, 0, SEEK_END); | ||
362 | *length = ftell(p->file); | ||
363 | fseek(p->file, pos, SEEK_SET); | ||
364 | return res; | ||
365 | |||
366 | #else | ||
367 | |||
368 | off_t pos; | ||
369 | *length = 0; | ||
370 | pos = lseek(p->fd, 0, SEEK_CUR); | ||
371 | if (pos != -1) | ||
372 | { | ||
373 | const off_t len2 = lseek(p->fd, 0, SEEK_END); | ||
374 | const off_t res2 = lseek(p->fd, pos, SEEK_SET); | ||
375 | if (len2 != -1) | ||
376 | { | ||
377 | *length = (UInt64)len2; | ||
378 | if (res2 != -1) | ||
379 | return 0; | ||
380 | } | ||
381 | } | ||
382 | return errno; | ||
383 | |||
384 | #endif | ||
385 | } | ||
386 | |||
387 | |||
388 | /* ---------- FileSeqInStream ---------- */ | ||
389 | |||
390 | static SRes FileSeqInStream_Read(const ISeqInStream *pp, void *buf, size_t *size) | ||
391 | { | ||
392 | CFileSeqInStream *p = CONTAINER_FROM_VTBL(pp, CFileSeqInStream, vt); | ||
393 | WRes wres = File_Read(&p->file, buf, size); | ||
394 | p->wres = wres; | ||
395 | return (wres == 0) ? SZ_OK : SZ_ERROR_READ; | ||
396 | } | ||
397 | |||
398 | void FileSeqInStream_CreateVTable(CFileSeqInStream *p) | ||
399 | { | ||
400 | p->vt.Read = FileSeqInStream_Read; | ||
401 | } | ||
402 | |||
403 | |||
404 | /* ---------- FileInStream ---------- */ | ||
405 | |||
406 | static SRes FileInStream_Read(const ISeekInStream *pp, void *buf, size_t *size) | ||
407 | { | ||
408 | CFileInStream *p = CONTAINER_FROM_VTBL(pp, CFileInStream, vt); | ||
409 | WRes wres = File_Read(&p->file, buf, size); | ||
410 | p->wres = wres; | ||
411 | return (wres == 0) ? SZ_OK : SZ_ERROR_READ; | ||
412 | } | ||
413 | |||
414 | static SRes FileInStream_Seek(const ISeekInStream *pp, Int64 *pos, ESzSeek origin) | ||
415 | { | ||
416 | CFileInStream *p = CONTAINER_FROM_VTBL(pp, CFileInStream, vt); | ||
417 | WRes wres = File_Seek(&p->file, pos, origin); | ||
418 | p->wres = wres; | ||
419 | return (wres == 0) ? SZ_OK : SZ_ERROR_READ; | ||
420 | } | ||
421 | |||
422 | void FileInStream_CreateVTable(CFileInStream *p) | ||
423 | { | ||
424 | p->vt.Read = FileInStream_Read; | ||
425 | p->vt.Seek = FileInStream_Seek; | ||
426 | } | ||
427 | |||
428 | |||
429 | /* ---------- FileOutStream ---------- */ | ||
430 | |||
431 | static size_t FileOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size) | ||
432 | { | ||
433 | CFileOutStream *p = CONTAINER_FROM_VTBL(pp, CFileOutStream, vt); | ||
434 | WRes wres = File_Write(&p->file, data, &size); | ||
435 | p->wres = wres; | ||
436 | return size; | ||
437 | } | ||
438 | |||
439 | void FileOutStream_CreateVTable(CFileOutStream *p) | ||
440 | { | ||
441 | p->vt.Write = FileOutStream_Write; | ||
442 | } | ||