1 |
#define _XOPEN_SOURCE 500 |
2 |
|
3 |
#include "uar.h" |
4 |
#include "malloc.h" |
5 |
|
6 |
#include <assert.h> |
7 |
#include <dirent.h> |
8 |
#include <errno.h> |
9 |
#include <fcntl.h> |
10 |
#include <stdbool.h> |
11 |
#include <stdint.h> |
12 |
#include <stdio.h> |
13 |
#include <stdlib.h> |
14 |
#include <string.h> |
15 |
#include <strings.h> |
16 |
#include <sys/stat.h> |
17 |
#include <sys/types.h> |
18 |
#include <time.h> |
19 |
#include <unistd.h> |
20 |
|
21 |
#if defined(__linux__) |
22 |
# include <linux/limits.h> |
23 |
#elif defined(__APPLE__) |
24 |
# include <sys/syslimits.h> |
25 |
#else |
26 |
# include <limits.h> |
27 |
#endif |
28 |
|
29 |
const unsigned char UAR_MAGIC[] = { 0x99, 'U', 'A', 'R' }; |
30 |
|
31 |
struct uar_header |
32 |
{ |
33 |
uint8_t magic[4]; |
34 |
uint16_t version; |
35 |
uint32_t flags; |
36 |
uint64_t nfiles; |
37 |
uint64_t size; |
38 |
} __attribute__ ((packed)); |
39 |
|
40 |
/* TODO: Fix alignment */ |
41 |
struct uar_file |
42 |
{ |
43 |
enum uar_file_type type; |
44 |
char *name; |
45 |
uint64_t namelen; |
46 |
uint64_t offset; |
47 |
union |
48 |
{ |
49 |
uint64_t size; |
50 |
struct |
51 |
{ |
52 |
char *loc; |
53 |
uint64_t loclen; |
54 |
} linkinfo; |
55 |
} data; |
56 |
mode_t mode; |
57 |
time_t mtime; |
58 |
uid_t uid; |
59 |
gid_t gid; |
60 |
}; |
61 |
|
62 |
struct uar_archive |
63 |
{ |
64 |
struct uar_header header; |
65 |
struct uar_file **files; |
66 |
struct uar_file *root; |
67 |
enum uar_error ecode; |
68 |
bool is_stream; |
69 |
uint8_t *buffer; /* Deprecated */ |
70 |
FILE *stream; |
71 |
int last_errno; |
72 |
char *err_file; |
73 |
uar_create_callback_t create_callback; |
74 |
}; |
75 |
|
76 |
void |
77 |
uar_set_create_callback (struct uar_archive *uar, |
78 |
uar_create_callback_t callback) |
79 |
{ |
80 |
uar->create_callback = callback; |
81 |
} |
82 |
|
83 |
static void |
84 |
uar_set_error (struct uar_archive *uar, enum uar_error ecode, |
85 |
const char *err_file) |
86 |
{ |
87 |
uar->ecode = ecode; |
88 |
uar->last_errno = errno; |
89 |
free (uar->err_file); |
90 |
uar->err_file = err_file == NULL ? NULL : strdup (err_file); |
91 |
} |
92 |
|
93 |
const char * |
94 |
uar_strerror (const struct uar_archive *restrict uar) |
95 |
{ |
96 |
switch (uar->ecode) |
97 |
{ |
98 |
case UAR_SUCCESS: |
99 |
return "success"; |
100 |
case UAR_INVALID_MAGIC: |
101 |
return "invalid archive magic"; |
102 |
case UAR_INVALID_FILE: |
103 |
return "invalid file"; |
104 |
case UAR_INVALID_PATH: |
105 |
return "invalid path string"; |
106 |
case UAR_IO_ERROR: |
107 |
return "archive I/O error"; |
108 |
case UAR_OUT_OF_MEMORY: |
109 |
return "out of memory"; |
110 |
case UAR_INVALID_ARGUMENT: |
111 |
return "invalid argument"; |
112 |
case UAR_INVALID_OPERATION: |
113 |
return "invalid operation"; |
114 |
case UAR_SYSTEM_ERROR: |
115 |
return "system error"; |
116 |
case UAR_SYSCALL_ERROR: |
117 |
return strerror (uar->last_errno); |
118 |
default: |
119 |
return "unknown error"; |
120 |
} |
121 |
} |
122 |
|
123 |
bool |
124 |
uar_has_error (const struct uar_archive *restrict uar) |
125 |
{ |
126 |
return uar->ecode != UAR_SUCCESS; |
127 |
} |
128 |
|
129 |
/* TODO: Use static storage for path */ |
130 |
static char * |
131 |
path_concat (const char *p1, const char *p2, size_t len1, size_t len2) |
132 |
{ |
133 |
char *path = malloc (len1 + len2 + 2); |
134 |
|
135 |
if (path == NULL) |
136 |
return NULL; |
137 |
|
138 |
strncpy (path, p1, len1); |
139 |
path[len1] = '/'; |
140 |
strncpy (path + len1 + 1, p2, len2); |
141 |
path[len1 + len2 + 1] = 0; |
142 |
return path; |
143 |
} |
144 |
|
145 |
struct uar_archive * |
146 |
uar_create (void) |
147 |
{ |
148 |
struct uar_archive *uar = malloc (sizeof (struct uar_archive)); |
149 |
|
150 |
if (uar == NULL) |
151 |
return NULL; |
152 |
|
153 |
uar->is_stream = false; |
154 |
uar->buffer = NULL; |
155 |
uar->ecode = UAR_SUCCESS; |
156 |
uar->header.size = 0; |
157 |
memcpy (uar->header.magic, UAR_MAGIC, 4); |
158 |
uar->header.version = 1; |
159 |
uar->header.flags = 0; |
160 |
uar->header.nfiles = 0; |
161 |
uar->files = NULL; |
162 |
uar->stream = NULL; |
163 |
uar->root = NULL; |
164 |
uar->last_errno = 0; |
165 |
uar->err_file = NULL; |
166 |
|
167 |
return uar; |
168 |
} |
169 |
|
170 |
static struct uar_file * |
171 |
uar_initialize_root (struct uar_archive *uar) |
172 |
{ |
173 |
struct uar_file *root = uar_file_create ("/", 1, 0, 0); |
174 |
|
175 |
if (root == NULL) |
176 |
{ |
177 |
uar_set_error (uar, UAR_OUT_OF_MEMORY, "/"); |
178 |
return NULL; |
179 |
} |
180 |
|
181 |
root->type = UF_DIR; |
182 |
root->mode = S_IFDIR | 0755; |
183 |
root->mtime = time (NULL); |
184 |
|
185 |
if (!uar_add_file_entry (uar, root)) |
186 |
{ |
187 |
uar_file_destroy (root); |
188 |
return NULL; |
189 |
} |
190 |
|
191 |
uar->root = root; |
192 |
|
193 |
return root; |
194 |
} |
195 |
|
196 |
static bool |
197 |
uar_initialize (struct uar_archive *uar) |
198 |
{ |
199 |
if (uar_initialize_root (uar) == NULL) |
200 |
return false; |
201 |
|
202 |
return true; |
203 |
} |
204 |
|
205 |
bool |
206 |
uar_stream_write (struct uar_archive *uar, const char *filename) |
207 |
{ |
208 |
if (uar == NULL || !uar->is_stream || uar->stream == NULL) |
209 |
return false; |
210 |
|
211 |
FILE *stream = fopen (filename, "wb"); |
212 |
|
213 |
if (fwrite (&uar->header, 1, sizeof (struct uar_header), stream) |
214 |
!= sizeof (struct uar_header)) |
215 |
{ |
216 |
uar_set_error (uar, UAR_SYSCALL_ERROR, NULL); |
217 |
fclose (stream); |
218 |
return false; |
219 |
} |
220 |
|
221 |
for (uint64_t i = 0; i < uar->header.nfiles; i++) |
222 |
{ |
223 |
struct uar_file *file = uar->files[i]; |
224 |
|
225 |
if (fwrite (file, 1, sizeof (struct uar_file), stream) |
226 |
!= sizeof (struct uar_file)) |
227 |
{ |
228 |
uar_set_error (uar, UAR_SYSCALL_ERROR, file->name); |
229 |
fclose (stream); |
230 |
return false; |
231 |
} |
232 |
|
233 |
if (fwrite (file->name, 1, file->namelen, stream) != file->namelen) |
234 |
{ |
235 |
uar_set_error (uar, UAR_SYSCALL_ERROR, file->name); |
236 |
fclose (stream); |
237 |
return false; |
238 |
} |
239 |
} |
240 |
|
241 |
uar->stream = freopen (NULL, "rb", uar->stream); |
242 |
|
243 |
if (uar->stream == NULL) |
244 |
{ |
245 |
uar_set_error (uar, UAR_SYSCALL_ERROR, NULL); |
246 |
fclose (stream); |
247 |
return false; |
248 |
} |
249 |
|
250 |
size_t buf_size |
251 |
= uar->header.size >= (1024 * 1024) ? 1024 * 1024 : uar->header.size; |
252 |
uint8_t *buf = malloc (buf_size); |
253 |
|
254 |
if (buf == NULL) |
255 |
{ |
256 |
uar_set_error (uar, UAR_OUT_OF_MEMORY, NULL); |
257 |
fclose (stream); |
258 |
return false; |
259 |
} |
260 |
|
261 |
uint64_t size = uar->header.size; |
262 |
|
263 |
while (size > 0 && !feof (uar->stream)) |
264 |
{ |
265 |
if (size < buf_size) |
266 |
buf_size = size; |
267 |
|
268 |
if (fread (buf, 1, buf_size, uar->stream) != buf_size) |
269 |
{ |
270 |
uar_set_error (uar, UAR_SYSCALL_ERROR, NULL); |
271 |
fclose (stream); |
272 |
free (buf); |
273 |
return false; |
274 |
} |
275 |
|
276 |
if (fwrite (buf, 1, buf_size, stream) != buf_size) |
277 |
{ |
278 |
uar_set_error (uar, UAR_SYSCALL_ERROR, NULL); |
279 |
fclose (stream); |
280 |
free (buf); |
281 |
return false; |
282 |
} |
283 |
|
284 |
if (size < buf_size) |
285 |
buf_size = size; |
286 |
else |
287 |
size -= buf_size; |
288 |
} |
289 |
|
290 |
fclose (stream); |
291 |
return true; |
292 |
} |
293 |
|
294 |
struct uar_archive * |
295 |
uar_create_stream (void) |
296 |
{ |
297 |
struct uar_archive *uar = uar_create (); |
298 |
int cerrno; |
299 |
|
300 |
if (uar == NULL) |
301 |
return NULL; |
302 |
|
303 |
uar->is_stream = true; |
304 |
uar->stream = tmpfile (); |
305 |
|
306 |
if (uar->stream == NULL) |
307 |
goto uar_create_stream_error; |
308 |
|
309 |
if (!uar_initialize (uar)) |
310 |
goto uar_create_stream_error; |
311 |
|
312 |
goto uar_create_stream_ret; |
313 |
|
314 |
uar_create_stream_error: |
315 |
cerrno = errno; |
316 |
uar_close (uar); |
317 |
errno = cerrno; |
318 |
uar_create_stream_ret: |
319 |
return uar; |
320 |
} |
321 |
|
322 |
struct uar_file * |
323 |
uar_stream_add_file (struct uar_archive *uar, const char *uar_filename, |
324 |
const char *fs_filename, struct stat *stinfo) |
325 |
{ |
326 |
assert (uar != NULL && "uar is NULL"); |
327 |
assert (uar->is_stream && "uar is not in stream mode"); |
328 |
assert (uar_filename != NULL && "uar_filename is NULL"); |
329 |
assert (fs_filename != NULL && "fs_filename is NULL"); |
330 |
|
331 |
if (uar->root == NULL) |
332 |
{ |
333 |
if (uar_initialize_root (uar) == NULL) |
334 |
return NULL; |
335 |
} |
336 |
|
337 |
struct stat custom_stinfo = { 0 }; |
338 |
enum uar_error ecode = UAR_SUCCESS; |
339 |
void *buffer = NULL; |
340 |
struct uar_file *file = NULL; |
341 |
|
342 |
if (stinfo == NULL) |
343 |
{ |
344 |
if (lstat (fs_filename, &custom_stinfo) != 0) |
345 |
{ |
346 |
uar_set_error (uar, UAR_SYSCALL_ERROR, fs_filename); |
347 |
|
348 |
if (uar->create_callback != NULL) |
349 |
uar->create_callback (uar, NULL, uar_filename, |
350 |
fs_filename, UAR_ELEVEL_WARNING, |
351 |
strerror (errno)); |
352 |
|
353 |
return NULL; |
354 |
} |
355 |
else |
356 |
stinfo = &custom_stinfo; |
357 |
} |
358 |
|
359 |
FILE *stream = fopen (fs_filename, "rb"); |
360 |
|
361 |
if (stream == NULL) |
362 |
{ |
363 |
uar_set_error (uar, UAR_SYSCALL_ERROR, fs_filename); |
364 |
|
365 |
if (uar->create_callback != NULL) |
366 |
uar->create_callback (uar, NULL, uar_filename, fs_filename, |
367 |
UAR_ELEVEL_WARNING, strerror (errno)); |
368 |
|
369 |
return NULL; |
370 |
} |
371 |
|
372 |
fseek (stream, 0, SEEK_END); |
373 |
long size = ftell (stream); |
374 |
|
375 |
if (size < 0) |
376 |
{ |
377 |
ecode = UAR_SYSCALL_ERROR; |
378 |
goto uar_stream_add_file_end; |
379 |
} |
380 |
|
381 |
fseek (stream, 0, SEEK_SET); |
382 |
|
383 |
file = uar_file_create (uar_filename, 0, size, uar->header.size); |
384 |
|
385 |
if (file == NULL) |
386 |
{ |
387 |
ecode = UAR_SYSCALL_ERROR; |
388 |
goto uar_stream_add_file_end; |
389 |
} |
390 |
|
391 |
file->mode = stinfo->st_mode; |
392 |
file->data.size = size; |
393 |
file->mtime = stinfo->st_mtime; |
394 |
uar->header.size += size; |
395 |
uar->root->data.size += size; |
396 |
|
397 |
if (!uar_add_file_entry (uar, file)) |
398 |
{ |
399 |
uar_file_destroy (file); |
400 |
fclose (stream); |
401 |
return NULL; |
402 |
} |
403 |
|
404 |
buffer = malloc (size); |
405 |
|
406 |
if (buffer == NULL) |
407 |
{ |
408 |
ecode = UAR_OUT_OF_MEMORY; |
409 |
goto uar_stream_add_file_end; |
410 |
} |
411 |
|
412 |
if (size != 0 && fread (buffer, 1, size, stream) != (size_t) size) |
413 |
{ |
414 |
ecode = UAR_SYSCALL_ERROR; |
415 |
goto uar_stream_add_file_end; |
416 |
} |
417 |
|
418 |
if (fwrite (buffer, 1, size, uar->stream) != (size_t) size) |
419 |
{ |
420 |
ecode = UAR_SYSCALL_ERROR; |
421 |
goto uar_stream_add_file_end; |
422 |
} |
423 |
|
424 |
if (ecode == UAR_SUCCESS && uar->create_callback != NULL) |
425 |
{ |
426 |
uar->create_callback (uar, file, uar_filename, fs_filename, |
427 |
UAR_ELEVEL_NONE, NULL); |
428 |
} |
429 |
|
430 |
uar_stream_add_file_end: |
431 |
if (ecode != UAR_SUCCESS && file != NULL) |
432 |
uar_file_destroy (file); |
433 |
|
434 |
if (buffer != NULL) |
435 |
free (buffer); |
436 |
|
437 |
uar_set_error (uar, ecode, fs_filename); |
438 |
fclose (stream); |
439 |
return ecode == UAR_SUCCESS ? file : NULL; |
440 |
} |
441 |
|
442 |
struct uar_file * |
443 |
uar_stream_add_dir (struct uar_archive *uar, const char *uar_dirname, |
444 |
const char *fs_dirname, struct stat *stinfo) |
445 |
{ |
446 |
struct stat custom_stinfo = { 0 }; |
447 |
enum uar_error ecode = UAR_SUCCESS; |
448 |
struct uar_file *file = NULL; |
449 |
uint64_t size = 0; |
450 |
DIR *dir = NULL; |
451 |
|
452 |
if (stinfo == NULL) |
453 |
{ |
454 |
if (lstat (fs_dirname, &custom_stinfo) != 0) |
455 |
{ |
456 |
uar_set_error (uar, UAR_SYSCALL_ERROR, fs_dirname); |
457 |
|
458 |
if (uar->create_callback != NULL) |
459 |
uar->create_callback (uar, NULL, uar_dirname, |
460 |
fs_dirname, UAR_ELEVEL_WARNING, |
461 |
strerror (errno)); |
462 |
|
463 |
return NULL; |
464 |
} |
465 |
else |
466 |
stinfo = &custom_stinfo; |
467 |
} |
468 |
|
469 |
file = uar_file_create (uar_dirname, 0, 0, uar->header.size); |
470 |
|
471 |
if (file == NULL) |
472 |
{ |
473 |
ecode = UAR_OUT_OF_MEMORY; |
474 |
goto uar_stream_add_dir_error; |
475 |
} |
476 |
|
477 |
file->type = UF_DIR; |
478 |
file->mode = stinfo->st_mode; |
479 |
file->mtime = stinfo->st_mtime; |
480 |
|
481 |
if (!uar_add_file_entry (uar, file)) |
482 |
{ |
483 |
ecode = UAR_OUT_OF_MEMORY; |
484 |
goto uar_stream_add_dir_error; |
485 |
} |
486 |
|
487 |
dir = opendir (fs_dirname); |
488 |
|
489 |
if (dir == NULL) |
490 |
{ |
491 |
if (uar->create_callback != NULL) |
492 |
uar->create_callback (uar, NULL, uar_dirname, fs_dirname, |
493 |
UAR_ELEVEL_WARNING, strerror (errno)); |
494 |
|
495 |
ecode = UAR_SYSCALL_ERROR; |
496 |
goto uar_stream_add_dir_error; |
497 |
} |
498 |
|
499 |
struct dirent *entry = NULL; |
500 |
|
501 |
while ((entry = readdir (dir)) != NULL) |
502 |
{ |
503 |
if (strcmp (entry->d_name, ".") == 0 |
504 |
|| strcmp (entry->d_name, "..") == 0) |
505 |
continue; |
506 |
|
507 |
size_t dname_len = strlen (entry->d_name); |
508 |
char *fs_fullpath = path_concat (fs_dirname, entry->d_name, |
509 |
strlen (fs_dirname), dname_len); |
510 |
char *uar_fullpath = path_concat (uar_dirname, entry->d_name, |
511 |
strlen (uar_dirname), dname_len); |
512 |
|
513 |
struct uar_file *entry_file |
514 |
= uar_stream_add_entry (uar, uar_fullpath, fs_fullpath, NULL); |
515 |
|
516 |
if (entry_file != NULL) |
517 |
size += entry_file->data.size; |
518 |
|
519 |
free (fs_fullpath); |
520 |
free (uar_fullpath); |
521 |
} |
522 |
|
523 |
file->data.size = size; |
524 |
|
525 |
if (ecode == UAR_SUCCESS && uar->create_callback != NULL) |
526 |
{ |
527 |
uar->create_callback (uar, file, uar_dirname, fs_dirname, |
528 |
UAR_ELEVEL_NONE, NULL); |
529 |
} |
530 |
|
531 |
goto uar_stream_add_dir_ret; |
532 |
uar_stream_add_dir_error: |
533 |
uar_set_error (uar, ecode, fs_dirname); |
534 |
uar_stream_add_dir_ret: |
535 |
if (dir != NULL) |
536 |
closedir (dir); |
537 |
|
538 |
if (ecode != UAR_SUCCESS && file != NULL) |
539 |
uar_file_destroy (file); |
540 |
|
541 |
return ecode == UAR_SUCCESS ? file : NULL; |
542 |
} |
543 |
|
544 |
struct uar_file * |
545 |
uar_stream_add_link (struct uar_archive *uar, const char *uar_name, |
546 |
const char *fs_name, struct stat *stinfo) |
547 |
{ |
548 |
struct stat custom_stinfo = { 0 }; |
549 |
struct uar_file *file = NULL; |
550 |
|
551 |
if (stinfo == NULL) |
552 |
{ |
553 |
if (lstat (fs_name, &custom_stinfo) != 0) |
554 |
{ |
555 |
uar_set_error (uar, UAR_SYSCALL_ERROR, fs_name); |
556 |
|
557 |
if (uar->create_callback != NULL) |
558 |
uar->create_callback (uar, NULL, uar_name, fs_name, |
559 |
UAR_ELEVEL_WARNING, |
560 |
strerror (errno)); |
561 |
|
562 |
return NULL; |
563 |
} |
564 |
else |
565 |
stinfo = &custom_stinfo; |
566 |
} |
567 |
|
568 |
file = uar_file_create (uar_name, 0, 0, uar->header.size); |
569 |
|
570 |
if (file == NULL) |
571 |
{ |
572 |
uar_set_error (uar, UAR_OUT_OF_MEMORY, fs_name); |
573 |
return NULL; |
574 |
} |
575 |
|
576 |
file->type = UF_LINK; |
577 |
file->mode = stinfo->st_mode; |
578 |
file->mtime = stinfo->st_mtime; |
579 |
|
580 |
char link_buf[PATH_MAX] = { 0 }; |
581 |
|
582 |
ssize_t link_len = readlink (fs_name, link_buf, PATH_MAX); |
583 |
|
584 |
if (link_len == -1) |
585 |
{ |
586 |
uar_set_error (uar, UAR_SYSCALL_ERROR, fs_name); |
587 |
uar_file_destroy (file); |
588 |
|
589 |
if (uar->create_callback != NULL) |
590 |
uar->create_callback (uar, NULL, uar_name, fs_name, |
591 |
UAR_ELEVEL_WARNING, strerror (errno)); |
592 |
|
593 |
return NULL; |
594 |
} |
595 |
|
596 |
file->data.linkinfo.loclen = link_len; |
597 |
file->data.linkinfo.loc = malloc (link_len + 1); |
598 |
|
599 |
if (file->data.linkinfo.loc == NULL) |
600 |
{ |
601 |
uar_set_error (uar, UAR_OUT_OF_MEMORY, fs_name); |
602 |
uar_file_destroy (file); |
603 |
return NULL; |
604 |
} |
605 |
|
606 |
memcpy (file->data.linkinfo.loc, link_buf, link_len); |
607 |
file->data.linkinfo.loc[link_len] = 0; |
608 |
|
609 |
if (!uar_add_file_entry (uar, file)) |
610 |
{ |
611 |
uar_file_destroy (file); |
612 |
return NULL; |
613 |
} |
614 |
|
615 |
if (uar->create_callback != NULL && file != NULL) |
616 |
uar->create_callback (uar, file, uar_name, fs_name, UAR_ELEVEL_NONE, |
617 |
NULL); |
618 |
|
619 |
return file; |
620 |
} |
621 |
|
622 |
struct uar_file * |
623 |
uar_stream_add_entry (struct uar_archive *uar, const char *uar_name, |
624 |
const char *fs_name, struct stat *stinfo) |
625 |
{ |
626 |
assert (uar != NULL && "uar is NULL"); |
627 |
assert (uar->is_stream && "uar is not in stream mode"); |
628 |
assert (uar_name != NULL && "uar_name is NULL"); |
629 |
assert (fs_name != NULL && "fs_name is NULL"); |
630 |
|
631 |
struct stat custom_stinfo = { 0 }; |
632 |
struct uar_file *file = NULL; |
633 |
|
634 |
if (stinfo == NULL) |
635 |
{ |
636 |
if (lstat (fs_name, &custom_stinfo) != 0) |
637 |
{ |
638 |
uar_set_error (uar, UAR_SYSCALL_ERROR, fs_name); |
639 |
return NULL; |
640 |
} |
641 |
else |
642 |
stinfo = &custom_stinfo; |
643 |
} |
644 |
|
645 |
if (S_ISREG (stinfo->st_mode)) |
646 |
{ |
647 |
file = uar_stream_add_file (uar, uar_name, fs_name, stinfo); |
648 |
|
649 |
if (file == NULL) |
650 |
{ |
651 |
return NULL; |
652 |
} |
653 |
} |
654 |
else if (S_ISDIR (stinfo->st_mode)) |
655 |
{ |
656 |
file = uar_stream_add_dir (uar, uar_name, fs_name, stinfo); |
657 |
} |
658 |
else |
659 |
{ |
660 |
file = uar_stream_add_link (uar, uar_name, fs_name, stinfo); |
661 |
} |
662 |
|
663 |
if (file != NULL) |
664 |
{ |
665 |
file->mode = stinfo->st_mode; |
666 |
file->mtime = stinfo->st_mtime; |
667 |
file->uid = stinfo->st_uid; |
668 |
file->gid = stinfo->st_gid; |
669 |
} |
670 |
|
671 |
return file; |
672 |
} |
673 |
|
674 |
struct uar_archive * |
675 |
uar_open (const char *filename) |
676 |
{ |
677 |
struct uar_archive *uar = NULL; |
678 |
FILE *stream = NULL; |
679 |
int cerrno; |
680 |
|
681 |
errno = 0; |
682 |
uar = uar_create (); |
683 |
|
684 |
if (uar == NULL) |
685 |
return NULL; |
686 |
|
687 |
stream = fopen (filename, "rb"); |
688 |
|
689 |
if (stream == NULL) |
690 |
{ |
691 |
uar_set_error (uar, UAR_IO_ERROR, NULL); |
692 |
goto uar_open_ret; |
693 |
} |
694 |
|
695 |
fseek (stream, 0, SEEK_END); |
696 |
size_t size = ftell (stream); |
697 |
fseek (stream, 0, SEEK_SET); |
698 |
|
699 |
if (fread (&uar->header, sizeof (struct uar_header), 1, stream) != 1) |
700 |
{ |
701 |
uar_set_error (uar, UAR_IO_ERROR, NULL); |
702 |
goto uar_open_ret; |
703 |
} |
704 |
|
705 |
if (memcmp (uar->header.magic, UAR_MAGIC, 4) != 0) |
706 |
{ |
707 |
uar_set_error (uar, UAR_INVALID_MAGIC, NULL); |
708 |
goto uar_open_ret; |
709 |
} |
710 |
|
711 |
uint64_t filearr_size = uar->header.nfiles * sizeof (struct uar_file); |
712 |
|
713 |
if (filearr_size > size) |
714 |
{ |
715 |
uar_set_error (uar, UAR_IO_ERROR, NULL); |
716 |
goto uar_open_ret; |
717 |
} |
718 |
|
719 |
if (uar->header.size > size) |
720 |
{ |
721 |
uar_set_error (uar, UAR_IO_ERROR, NULL); |
722 |
goto uar_open_ret; |
723 |
} |
724 |
|
725 |
uar->files = calloc (uar->header.nfiles, sizeof (struct uar_file *)); |
726 |
|
727 |
if (uar->files == NULL) |
728 |
{ |
729 |
uar_set_error (uar, UAR_OUT_OF_MEMORY, NULL); |
730 |
goto uar_open_ret; |
731 |
} |
732 |
|
733 |
for (uint64_t i = 0; i < uar->header.nfiles; i++) |
734 |
{ |
735 |
struct uar_file *file = malloc (sizeof (struct uar_file)); |
736 |
|
737 |
if (file == NULL) |
738 |
{ |
739 |
uar_set_error (uar, UAR_OUT_OF_MEMORY, NULL); |
740 |
goto uar_open_ret; |
741 |
} |
742 |
|
743 |
if (fread (file, sizeof (struct uar_file), 1, stream) != 1) |
744 |
{ |
745 |
uar_set_error (uar, UAR_IO_ERROR, NULL); |
746 |
goto uar_open_ret; |
747 |
} |
748 |
|
749 |
if (file->namelen > PATH_MAX) |
750 |
{ |
751 |
uar_set_error (uar, UAR_INVALID_PATH, NULL); |
752 |
goto uar_open_ret; |
753 |
} |
754 |
|
755 |
file->name = malloc (file->namelen + 1); |
756 |
|
757 |
if (file->name == NULL) |
758 |
{ |
759 |
uar_set_error (uar, UAR_OUT_OF_MEMORY, NULL); |
760 |
goto uar_open_ret; |
761 |
} |
762 |
|
763 |
if (fread (file->name, 1, file->namelen, stream) != file->namelen) |
764 |
{ |
765 |
uar_set_error (uar, UAR_IO_ERROR, file->name); |
766 |
goto uar_open_ret; |
767 |
} |
768 |
|
769 |
file->name[file->namelen] = 0; |
770 |
uar->files[i] = file; |
771 |
} |
772 |
|
773 |
uar->buffer = malloc (uar->header.size + 1); |
774 |
|
775 |
if (uar->buffer == NULL) |
776 |
{ |
777 |
uar_set_error (uar, UAR_OUT_OF_MEMORY, NULL); |
778 |
goto uar_open_ret; |
779 |
} |
780 |
|
781 |
if (fread (uar->buffer, 1, uar->header.size, stream) != uar->header.size) |
782 |
{ |
783 |
uar_set_error (uar, UAR_IO_ERROR, NULL); |
784 |
goto uar_open_ret; |
785 |
} |
786 |
|
787 |
uar_open_ret: |
788 |
cerrno = errno; |
789 |
fclose (stream); |
790 |
errno = cerrno; |
791 |
return uar; |
792 |
} |
793 |
|
794 |
void |
795 |
uar_file_destroy (struct uar_file *file) |
796 |
{ |
797 |
if (file == NULL) |
798 |
return; |
799 |
|
800 |
if (file->type == UF_LINK) |
801 |
free (file->data.linkinfo.loc); |
802 |
|
803 |
free (file->name); |
804 |
free (file); |
805 |
} |
806 |
|
807 |
void |
808 |
uar_close (struct uar_archive *uar) |
809 |
{ |
810 |
if (uar == NULL) |
811 |
return; |
812 |
|
813 |
if (uar->is_stream) |
814 |
fclose (uar->stream); |
815 |
else |
816 |
free (uar->buffer); |
817 |
|
818 |
for (uint64_t i = 0; i < uar->header.nfiles; i++) |
819 |
{ |
820 |
struct uar_file *file = uar->files[i]; |
821 |
uar_file_destroy (file); |
822 |
} |
823 |
|
824 |
free (uar->err_file); |
825 |
free (uar->files); |
826 |
free (uar); |
827 |
} |
828 |
|
829 |
bool |
830 |
uar_add_file_entry (struct uar_archive *restrict uar, struct uar_file *file) |
831 |
{ |
832 |
if (uar == NULL || file == NULL) |
833 |
{ |
834 |
uar_set_error (uar, UAR_INVALID_ARGUMENT, NULL); |
835 |
return false; |
836 |
} |
837 |
|
838 |
uar->files = realloc (uar->files, |
839 |
(uar->header.nfiles + 1) * sizeof (struct uar_file)); |
840 |
|
841 |
if (uar->files == NULL) |
842 |
{ |
843 |
uar_set_error (uar, UAR_OUT_OF_MEMORY, NULL); |
844 |
return false; |
845 |
} |
846 |
|
847 |
uar->files[uar->header.nfiles] = file; |
848 |
uar->header.nfiles++; |
849 |
|
850 |
return true; |
851 |
} |
852 |
|
853 |
struct uar_file * |
854 |
uar_file_create (const char *name, uint64_t namelen, uint64_t size, |
855 |
uint32_t offset) |
856 |
{ |
857 |
struct uar_file *file; |
858 |
int cerrno; |
859 |
bool abs = false; |
860 |
|
861 |
if (namelen == 0) |
862 |
namelen = strlen (name); |
863 |
|
864 |
if (namelen >= PATH_MAX) |
865 |
{ |
866 |
errno = ENAMETOOLONG; |
867 |
return NULL; |
868 |
} |
869 |
|
870 |
abs = name[0] == '/'; |
871 |
namelen += (abs ? 0 : 1); |
872 |
|
873 |
file = malloc (sizeof (struct uar_file)); |
874 |
|
875 |
if (file == NULL) |
876 |
return NULL; |
877 |
|
878 |
bzero (file, sizeof (struct uar_file)); |
879 |
|
880 |
file->type = UF_FILE; |
881 |
file->mode = 0644; |
882 |
file->mtime = 0; |
883 |
file->uid = 0; |
884 |
file->gid = 0; |
885 |
file->name = malloc (namelen + 1); |
886 |
|
887 |
if (file->name == NULL) |
888 |
{ |
889 |
cerrno = errno; |
890 |
free (file); |
891 |
errno = cerrno; |
892 |
return NULL; |
893 |
} |
894 |
|
895 |
if (!abs) |
896 |
file->name[0] = '/'; |
897 |
|
898 |
strncpy (file->name + (abs ? 0 : 1), name, namelen); |
899 |
file->name[namelen] = 0; |
900 |
file->namelen = namelen; |
901 |
file->data.size = size; |
902 |
file->offset = offset; |
903 |
|
904 |
return file; |
905 |
} |
906 |
|
907 |
struct uar_file * |
908 |
uar_add_file (struct uar_archive *restrict uar, const char *name, |
909 |
const char *path, struct stat *stinfo) |
910 |
{ |
911 |
assert (uar != NULL && "uar is NULL"); |
912 |
assert (name != NULL && "name is NULL"); |
913 |
assert (path != NULL && "path is NULL"); |
914 |
assert (!uar->is_stream && "uar in non-stream mode is not supported yet"); |
915 |
|
916 |
uint64_t namelen = strlen (name); |
917 |
struct stat *file_stinfo = stinfo, st_stinfo = { 0 }; |
918 |
|
919 |
if (namelen >= PATH_MAX) |
920 |
{ |
921 |
uar_set_error (uar, UAR_INVALID_PATH, path); |
922 |
return NULL; |
923 |
} |
924 |
|
925 |
if (file_stinfo == NULL) |
926 |
{ |
927 |
if (lstat (path, &st_stinfo) != 0) |
928 |
{ |
929 |
uar_set_error (uar, UAR_IO_ERROR, path); |
930 |
return NULL; |
931 |
} |
932 |
|
933 |
file_stinfo = &st_stinfo; |
934 |
} |
935 |
|
936 |
FILE *stream = fopen (path, "rb"); |
937 |
|
938 |
if (stream == NULL) |
939 |
{ |
940 |
uar_set_error (uar, UAR_IO_ERROR, path); |
941 |
return NULL; |
942 |
} |
943 |
|
944 |
fseek (stream, 0, SEEK_END); |
945 |
long size = ftell (stream); |
946 |
|
947 |
if (size < 0) |
948 |
{ |
949 |
uar_set_error (uar, UAR_IO_ERROR, path); |
950 |
fclose (stream); |
951 |
return NULL; |
952 |
} |
953 |
|
954 |
fseek (stream, 0, SEEK_SET); |
955 |
|
956 |
struct uar_file *file |
957 |
= uar_file_create (name, namelen, size, uar->header.size); |
958 |
|
959 |
if (file == NULL) |
960 |
{ |
961 |
uar_set_error (uar, UAR_OUT_OF_MEMORY, path); |
962 |
fclose (stream); |
963 |
return NULL; |
964 |
} |
965 |
|
966 |
file->mtime = file_stinfo->st_mtime; |
967 |
uar->header.size += size; |
968 |
|
969 |
if (!uar_add_file_entry (uar, file)) |
970 |
{ |
971 |
uar_file_destroy (file); |
972 |
fclose (stream); |
973 |
return NULL; |
974 |
} |
975 |
|
976 |
uar->buffer = realloc (uar->buffer, uar->header.size); |
977 |
|
978 |
if (uar->buffer == NULL) |
979 |
{ |
980 |
uar_set_error (uar, UAR_OUT_OF_MEMORY, path); |
981 |
fclose (stream); |
982 |
return NULL; |
983 |
} |
984 |
|
985 |
if (size != 0 && fread (uar->buffer + file->offset, size, 1, stream) != 1) |
986 |
{ |
987 |
uar_set_error (uar, UAR_IO_ERROR, path); |
988 |
fclose (stream); |
989 |
return NULL; |
990 |
} |
991 |
|
992 |
fclose (stream); |
993 |
return file; |
994 |
} |
995 |
|
996 |
struct uar_file * |
997 |
uar_add_dir (struct uar_archive *uar, const char *dname, const char *path, |
998 |
bool (*callback) (struct uar_file *file, const char *fullname, |
999 |
const char *fullpath)) |
1000 |
{ |
1001 |
assert (uar != NULL && "uar is NULL"); |
1002 |
assert (dname != NULL && "dname is NULL"); |
1003 |
assert (path != NULL && "path is NULL"); |
1004 |
assert (!uar->is_stream && "uar in non-stream mode is not supported yet"); |
1005 |
|
1006 |
char *name = (char *) dname; |
1007 |
bool free_name = false; |
1008 |
int cerrno; |
1009 |
uint64_t namelen; |
1010 |
|
1011 |
if (strcmp (name, ".") == 0) |
1012 |
{ |
1013 |
name = strdup ("/"); |
1014 |
free_name = true; |
1015 |
namelen = 1; |
1016 |
} |
1017 |
else |
1018 |
namelen = strlen (name); |
1019 |
|
1020 |
if (namelen >= PATH_MAX) |
1021 |
{ |
1022 |
uar_set_error (uar, UAR_INVALID_PATH, path); |
1023 |
return NULL; |
1024 |
} |
1025 |
|
1026 |
DIR *dir = opendir (path); |
1027 |
struct dirent *entry = NULL; |
1028 |
|
1029 |
if (dir == NULL) |
1030 |
{ |
1031 |
uar_set_error (uar, UAR_INVALID_FILE, path); |
1032 |
return NULL; |
1033 |
} |
1034 |
|
1035 |
struct uar_file *dir_file |
1036 |
= uar_file_create (name, namelen, 0, uar->header.size); |
1037 |
uint64_t dir_size = 0; |
1038 |
|
1039 |
dir_file->type = UF_DIR; |
1040 |
|
1041 |
if (callback != NULL && !callback (dir_file, name, path)) |
1042 |
{ |
1043 |
uar_set_error (uar, UAR_SUCCESS, NULL); |
1044 |
uar_file_destroy (dir_file); |
1045 |
return NULL; |
1046 |
} |
1047 |
|
1048 |
if (!uar_add_file_entry (uar, dir_file)) |
1049 |
{ |
1050 |
uar_file_destroy (dir_file); |
1051 |
return NULL; |
1052 |
} |
1053 |
|
1054 |
while ((entry = readdir (dir)) != NULL) |
1055 |
{ |
1056 |
if (strcmp (entry->d_name, ".") == 0 |
1057 |
|| strcmp (entry->d_name, "..") == 0) |
1058 |
continue; |
1059 |
|
1060 |
struct stat stinfo = { 0 }; |
1061 |
|
1062 |
if (256 + namelen >= PATH_MAX) |
1063 |
{ |
1064 |
uar_set_error (uar, UAR_INVALID_PATH, path); |
1065 |
uar_file_destroy (dir_file); |
1066 |
closedir (dir); |
1067 |
return NULL; |
1068 |
} |
1069 |
|
1070 |
uint64_t dnamelen = strlen (entry->d_name); |
1071 |
|
1072 |
char *fullpath |
1073 |
= path_concat (path, entry->d_name, strlen (path), dnamelen); |
1074 |
assert (fullpath != NULL); |
1075 |
|
1076 |
char *fullname |
1077 |
= path_concat (name, entry->d_name, namelen, dnamelen); |
1078 |
assert (fullname != NULL); |
1079 |
|
1080 |
if (lstat (fullpath, &stinfo) != 0) |
1081 |
{ |
1082 |
uar_set_error (uar, UAR_IO_ERROR, fullpath); |
1083 |
goto uar_add_dir_error; |
1084 |
} |
1085 |
|
1086 |
if (S_ISREG (stinfo.st_mode)) |
1087 |
{ |
1088 |
struct uar_file *file |
1089 |
= uar_add_file (uar, fullname, fullpath, &stinfo); |
1090 |
|
1091 |
if (file == NULL) |
1092 |
{ |
1093 |
goto uar_add_dir_error; |
1094 |
} |
1095 |
|
1096 |
if (callback != NULL |
1097 |
&& !callback (file, fullname, fullpath)) |
1098 |
{ |
1099 |
uar_set_error (uar, UAR_SUCCESS, NULL); |
1100 |
goto uar_add_dir_error; |
1101 |
} |
1102 |
|
1103 |
file->mode = stinfo.st_mode; |
1104 |
dir_size += file->data.size; |
1105 |
} |
1106 |
else if (S_ISDIR (stinfo.st_mode)) |
1107 |
{ |
1108 |
struct uar_file *direntry |
1109 |
= uar_add_dir (uar, fullname, fullpath, callback); |
1110 |
|
1111 |
if (direntry == NULL) |
1112 |
{ |
1113 |
goto uar_add_dir_error; |
1114 |
} |
1115 |
|
1116 |
direntry->mode = stinfo.st_mode; |
1117 |
dir_size += direntry->data.size; |
1118 |
} |
1119 |
else |
1120 |
assert (false && "Not supported"); |
1121 |
|
1122 |
free (fullpath); |
1123 |
free (fullname); |
1124 |
|
1125 |
continue; |
1126 |
|
1127 |
uar_add_dir_error: |
1128 |
cerrno = errno; |
1129 |
uar_file_destroy (dir_file); |
1130 |
free (fullpath); |
1131 |
free (fullname); |
1132 |
errno = cerrno; |
1133 |
goto uar_add_dir_end; |
1134 |
} |
1135 |
|
1136 |
dir_file->data.size = dir_size; |
1137 |
|
1138 |
uar_add_dir_end: |
1139 |
cerrno = errno; |
1140 |
closedir (dir); |
1141 |
|
1142 |
if (free_name) |
1143 |
free (name); |
1144 |
|
1145 |
errno = cerrno; |
1146 |
return dir_file; |
1147 |
} |
1148 |
|
1149 |
void |
1150 |
uar_file_set_mode (struct uar_file *file, mode_t mode) |
1151 |
{ |
1152 |
file->mode = mode; |
1153 |
} |
1154 |
|
1155 |
static void |
1156 |
uar_debug_print_file_contents (const struct uar_archive *uar, |
1157 |
struct uar_file *file) |
1158 |
{ |
1159 |
printf (" contents:\n"); |
1160 |
printf ("==================\n"); |
1161 |
fflush (stdout); |
1162 |
|
1163 |
ssize_t size |
1164 |
= write (STDOUT_FILENO, uar->buffer + file->offset, file->data.size); |
1165 |
|
1166 |
if (size == -1 || ((uint64_t) size) != file->data.size) |
1167 |
{ |
1168 |
perror ("write"); |
1169 |
return; |
1170 |
} |
1171 |
|
1172 |
putchar ('\n'); |
1173 |
printf ("==================\n"); |
1174 |
} |
1175 |
|
1176 |
void |
1177 |
uar_debug_print (const struct uar_archive *uar, bool print_file_contents) |
1178 |
{ |
1179 |
printf ("uar_archive:\n"); |
1180 |
printf (" magic: %02x %02x %02x %02x\n", uar->header.magic[0], |
1181 |
uar->header.magic[1], uar->header.magic[2], uar->header.magic[3]); |
1182 |
printf (" version: %u\n", uar->header.version); |
1183 |
printf (" flags: %u\n", uar->header.flags); |
1184 |
printf (" nfiles: %lu\n", uar->header.nfiles); |
1185 |
printf (" size: %lu\n", uar->header.size); |
1186 |
printf (" stream?: %i\n", uar->is_stream); |
1187 |
|
1188 |
for (uint64_t i = 0; i < uar->header.nfiles; i++) |
1189 |
{ |
1190 |
struct uar_file *file = uar->files[i]; |
1191 |
|
1192 |
printf (" %s[%lu]:\n", |
1193 |
file->type == UF_FILE ? "file" |
1194 |
: file->type == UF_DIR ? "directory" |
1195 |
: "link", |
1196 |
i); |
1197 |
printf (" name: \033[1m%s%s\033[0m\n", uar_file_get_name (file), |
1198 |
file->type == UF_DIR |
1199 |
? file->name[0] == '/' && file->namelen == 1 ? "" : "/" |
1200 |
: file->type == UF_LINK ? "@" |
1201 |
: ""); |
1202 |
printf (" offset: %lu\n", file->offset); |
1203 |
printf (" mode: %04o\n", file->mode); |
1204 |
|
1205 |
if (file->type == UF_LINK) |
1206 |
printf (" points to: %s\n", file->data.linkinfo.loc); |
1207 |
else |
1208 |
printf (" size: %lu\n", file->data.size); |
1209 |
|
1210 |
if (file->type == UF_FILE && print_file_contents) |
1211 |
uar_debug_print_file_contents (uar, file); |
1212 |
} |
1213 |
} |
1214 |
|
1215 |
bool |
1216 |
uar_write (struct uar_archive *uar, const char *filename) |
1217 |
{ |
1218 |
FILE *stream = fopen (filename, "wb"); |
1219 |
|
1220 |
if (stream == NULL) |
1221 |
{ |
1222 |
uar_set_error (uar, UAR_IO_ERROR, filename); |
1223 |
return false; |
1224 |
} |
1225 |
|
1226 |
if (fwrite (&uar->header, sizeof (struct uar_header), 1, stream) != 1) |
1227 |
{ |
1228 |
uar_set_error (uar, UAR_IO_ERROR, filename); |
1229 |
fclose (stream); |
1230 |
return false; |
1231 |
} |
1232 |
|
1233 |
for (uint64_t i = 0; i < uar->header.nfiles; i++) |
1234 |
{ |
1235 |
struct uar_file *file = uar->files[i]; |
1236 |
|
1237 |
if (fwrite (file, sizeof (struct uar_file), 1, stream) != 1) |
1238 |
{ |
1239 |
uar_set_error (uar, UAR_IO_ERROR, file->name); |
1240 |
fclose (stream); |
1241 |
return false; |
1242 |
} |
1243 |
|
1244 |
if (fwrite (file->name, 1, file->namelen, stream) != file->namelen) |
1245 |
{ |
1246 |
uar_set_error (uar, UAR_IO_ERROR, file->name); |
1247 |
fclose (stream); |
1248 |
return false; |
1249 |
} |
1250 |
} |
1251 |
|
1252 |
if (fwrite (uar->buffer, 1, uar->header.size, stream) != uar->header.size) |
1253 |
{ |
1254 |
uar_set_error (uar, UAR_IO_ERROR, NULL); |
1255 |
fclose (stream); |
1256 |
return false; |
1257 |
} |
1258 |
|
1259 |
fclose (stream); |
1260 |
return true; |
1261 |
} |
1262 |
|
1263 |
bool |
1264 |
uar_extract (struct uar_archive *uar, const char *cwd, |
1265 |
bool (*callback) (struct uar_file *file)) |
1266 |
{ |
1267 |
if (cwd != NULL && chdir (cwd) != 0) |
1268 |
{ |
1269 |
uar_set_error (uar, UAR_SYSTEM_ERROR, NULL); |
1270 |
return false; |
1271 |
} |
1272 |
|
1273 |
for (uint64_t i = 0; i < uar->header.nfiles; i++) |
1274 |
{ |
1275 |
struct uar_file *file = uar->files[i]; |
1276 |
|
1277 |
if (callback != NULL && !callback (file)) |
1278 |
return false; |
1279 |
|
1280 |
char *name = file->name; |
1281 |
|
1282 |
if (name[0] == '/') |
1283 |
name += 2; |
1284 |
|
1285 |
switch (file->type) |
1286 |
{ |
1287 |
case UF_FILE: |
1288 |
{ |
1289 |
FILE *stream = fopen (name, "wb"); |
1290 |
|
1291 |
if (stream == NULL) |
1292 |
{ |
1293 |
uar_set_error (uar, UAR_IO_ERROR, name); |
1294 |
return false; |
1295 |
} |
1296 |
|
1297 |
if (fwrite (uar->buffer + file->offset, 1, |
1298 |
file->data.size, stream) |
1299 |
!= file->data.size) |
1300 |
{ |
1301 |
uar_set_error (uar, UAR_IO_ERROR, name); |
1302 |
return false; |
1303 |
} |
1304 |
|
1305 |
fchmod (fileno (stream), file->mode & 07777); |
1306 |
fclose (stream); |
1307 |
} |
1308 |
break; |
1309 |
|
1310 |
case UF_DIR: |
1311 |
if (file->namelen == 1 && file->name[0] == '/') |
1312 |
continue; |
1313 |
|
1314 |
if (mkdir (name, file->mode) != 0) |
1315 |
{ |
1316 |
uar_set_error (uar, UAR_SYSTEM_ERROR, name); |
1317 |
return false; |
1318 |
} |
1319 |
|
1320 |
break; |
1321 |
|
1322 |
default: |
1323 |
assert (false && "unknown file type"); |
1324 |
return false; |
1325 |
} |
1326 |
} |
1327 |
|
1328 |
return true; |
1329 |
} |
1330 |
|
1331 |
bool |
1332 |
uar_iterate (struct uar_archive *uar, |
1333 |
bool (*callback) (struct uar_file *file, void *data), void *data) |
1334 |
{ |
1335 |
for (uint64_t i = 0; i < uar->header.nfiles; i++) |
1336 |
{ |
1337 |
struct uar_file *file = uar->files[i]; |
1338 |
|
1339 |
if (!callback (file, data)) |
1340 |
return false; |
1341 |
} |
1342 |
|
1343 |
return true; |
1344 |
} |
1345 |
|
1346 |
const char * |
1347 |
uar_file_get_name (const struct uar_file *file) |
1348 |
{ |
1349 |
return file->name; |
1350 |
} |
1351 |
|
1352 |
enum uar_file_type |
1353 |
uar_file_get_type (const struct uar_file *file) |
1354 |
{ |
1355 |
return file->type; |
1356 |
} |
1357 |
|
1358 |
mode_t |
1359 |
uar_file_get_mode (const struct uar_file *file) |
1360 |
{ |
1361 |
return file->mode; |
1362 |
} |
1363 |
|
1364 |
uint64_t |
1365 |
uar_file_get_size (const struct uar_file *file) |
1366 |
{ |
1367 |
if (file->type == UF_LINK) |
1368 |
return 0; |
1369 |
|
1370 |
return file->data.size; |
1371 |
} |
1372 |
|
1373 |
uint64_t |
1374 |
uar_file_get_namelen (const struct uar_file *file) |
1375 |
{ |
1376 |
return file->namelen; |
1377 |
} |
1378 |
|
1379 |
uint64_t |
1380 |
uar_get_file_count (const struct uar_archive *restrict uar) |
1381 |
{ |
1382 |
return uar->header.nfiles; |
1383 |
} |
1384 |
|
1385 |
time_t |
1386 |
uar_file_get_mtime (const struct uar_file *file) |
1387 |
{ |
1388 |
return file->mtime; |
1389 |
} |
1390 |
|
1391 |
const char * |
1392 |
uar_get_error_file (const struct uar_archive *uar) |
1393 |
{ |
1394 |
return uar->err_file; |
1395 |
} |