12 |
#include <stdio.h> |
#include <stdio.h> |
13 |
#include <stdlib.h> |
#include <stdlib.h> |
14 |
#include <string.h> |
#include <string.h> |
15 |
|
#include <strings.h> |
16 |
#include <sys/stat.h> |
#include <sys/stat.h> |
17 |
#include <sys/types.h> |
#include <sys/types.h> |
18 |
#include <unistd.h> |
#include <unistd.h> |
25 |
# include <limits.h> |
# include <limits.h> |
26 |
#endif |
#endif |
27 |
|
|
28 |
|
#define UAR_ROOT_DIR_NAME 0x01 |
29 |
|
|
30 |
const unsigned char UAR_MAGIC[] = { 0x99, 'U', 'A', 'R' }; |
const unsigned char UAR_MAGIC[] = { 0x99, 'U', 'A', 'R' }; |
31 |
|
|
32 |
struct uar_header |
struct uar_header |
48 |
struct uar_file |
struct uar_file |
49 |
{ |
{ |
50 |
enum uar_file_type type; |
enum uar_file_type type; |
51 |
|
int __pad1; |
52 |
char *name; |
char *name; |
53 |
uint64_t namelen; |
uint64_t namelen; |
54 |
uint32_t offset; |
uint64_t offset; |
55 |
union |
union |
56 |
{ |
{ |
57 |
uint64_t size; |
uint64_t size; |
62 |
} linkinfo; |
} linkinfo; |
63 |
} data; |
} data; |
64 |
mode_t mode; |
mode_t mode; |
65 |
|
int __pad2; |
66 |
}; |
}; |
67 |
|
|
68 |
struct uar_archive |
struct uar_archive |
114 |
} |
} |
115 |
|
|
116 |
struct uar_archive * |
struct uar_archive * |
117 |
|
uar_create (void) |
118 |
|
{ |
119 |
|
struct uar_archive *uar = malloc (sizeof (struct uar_archive)); |
120 |
|
|
121 |
|
if (uar == NULL) |
122 |
|
return NULL; |
123 |
|
|
124 |
|
uar->is_stream = false; |
125 |
|
uar->buffer = NULL; |
126 |
|
uar->ecode = UAR_SUCCESS; |
127 |
|
uar->header.size = 0; |
128 |
|
memcpy (uar->header.magic, UAR_MAGIC, 4); |
129 |
|
uar->header.version = 1; |
130 |
|
uar->header.flags = 0; |
131 |
|
uar->header.nfiles = 0; |
132 |
|
uar->files = NULL; |
133 |
|
|
134 |
|
return uar; |
135 |
|
} |
136 |
|
|
137 |
|
struct uar_archive * |
138 |
uar_open (const char *filename) |
uar_open (const char *filename) |
139 |
{ |
{ |
140 |
struct uar_archive *uar = NULL; |
struct uar_archive *uar = NULL; |
142 |
int cerrno; |
int cerrno; |
143 |
|
|
144 |
errno = 0; |
errno = 0; |
145 |
uar = malloc (sizeof (struct uar_archive)); |
uar = uar_create (); |
146 |
|
|
147 |
if (uar == NULL) |
if (uar == NULL) |
148 |
return NULL; |
return NULL; |
215 |
goto uar_open_ret; |
goto uar_open_ret; |
216 |
} |
} |
217 |
|
|
218 |
file->name = malloc (file->namelen); |
file->name = malloc (file->namelen + 1); |
219 |
|
|
220 |
if (file->name == NULL) |
if (file->name == NULL) |
221 |
{ |
{ |
229 |
goto uar_open_ret; |
goto uar_open_ret; |
230 |
} |
} |
231 |
|
|
232 |
|
file->name[file->namelen] = 0; |
233 |
uar->files[i] = file; |
uar->files[i] = file; |
234 |
} |
} |
235 |
|
|
255 |
} |
} |
256 |
|
|
257 |
void |
void |
258 |
uar_close (struct uar_archive *uar) |
uar_file_destroy (struct uar_file *file) |
259 |
{ |
{ |
260 |
if (uar == NULL) |
if (file == NULL) |
261 |
return; |
return; |
262 |
|
|
263 |
free (uar->buffer); |
free (file->name); |
264 |
free (uar->files); |
free (file); |
|
free (uar); |
|
265 |
} |
} |
266 |
|
|
267 |
struct uar_archive * |
void |
268 |
uar_create () |
uar_close (struct uar_archive *uar) |
269 |
{ |
{ |
|
struct uar_archive *uar = malloc (sizeof (struct uar_archive)); |
|
|
|
|
270 |
if (uar == NULL) |
if (uar == NULL) |
271 |
return NULL; |
return; |
272 |
|
|
273 |
uar->is_stream = false; |
free (uar->buffer); |
|
uar->buffer = NULL; |
|
|
uar->header.size = sizeof (struct uar_header); |
|
|
memcpy (uar->header.magic, UAR_MAGIC, 4); |
|
|
uar->header.version = 1; |
|
|
uar->header.flags = 0; |
|
|
uar->header.nfiles = 0; |
|
274 |
|
|
275 |
return uar; |
for (uint64_t i = 0; i < uar->header.nfiles; i++) |
276 |
|
{ |
277 |
|
struct uar_file *file = uar->files[i]; |
278 |
|
uar_file_destroy (file); |
279 |
|
} |
280 |
|
|
281 |
|
free (uar->files); |
282 |
|
free (uar); |
283 |
} |
} |
284 |
|
|
285 |
bool |
bool |
310 |
uint32_t offset) |
uint32_t offset) |
311 |
{ |
{ |
312 |
struct uar_file *file; |
struct uar_file *file; |
313 |
|
int cerrno; |
314 |
assert (namelen < PATH_MAX); |
assert (namelen < PATH_MAX); |
315 |
|
|
316 |
file = malloc (sizeof (struct uar_file)); |
file = malloc (sizeof (struct uar_file)); |
318 |
if (file == NULL) |
if (file == NULL) |
319 |
return NULL; |
return NULL; |
320 |
|
|
321 |
|
bzero (file, sizeof (struct uar_file)); |
322 |
|
|
323 |
file->type = UF_FILE; |
file->type = UF_FILE; |
324 |
file->mode = 0644; |
file->mode = 0644; |
325 |
file->name = malloc (namelen + 1); |
file->name = malloc (namelen + 1); |
326 |
|
|
327 |
if (file->name == NULL) |
if (file->name == NULL) |
328 |
{ |
{ |
329 |
|
cerrno = errno; |
330 |
free (file); |
free (file); |
331 |
|
errno = cerrno; |
332 |
return NULL; |
return NULL; |
333 |
} |
} |
334 |
|
|
341 |
return file; |
return file; |
342 |
} |
} |
343 |
|
|
|
void |
|
|
uar_file_destroy (struct uar_file *file) |
|
|
{ |
|
|
if (file == NULL) |
|
|
return; |
|
|
|
|
|
free (file->name); |
|
|
free (file); |
|
|
} |
|
|
|
|
344 |
struct uar_file * |
struct uar_file * |
345 |
uar_add_file (struct uar_archive *restrict uar, const char *name, |
uar_add_file (struct uar_archive *restrict uar, const char *name, |
346 |
const char *path) |
const char *path) |
367 |
} |
} |
368 |
|
|
369 |
fseek (stream, 0, SEEK_END); |
fseek (stream, 0, SEEK_END); |
370 |
uint64_t size = ftell (stream); |
long size = ftell (stream); |
371 |
|
|
372 |
|
if (size < 0) |
373 |
|
{ |
374 |
|
uar_set_error (uar, UAR_IO_ERROR); |
375 |
|
fclose (stream); |
376 |
|
return NULL; |
377 |
|
} |
378 |
|
|
379 |
fseek (stream, 0, SEEK_SET); |
fseek (stream, 0, SEEK_SET); |
380 |
|
|
381 |
struct uar_file *file |
struct uar_file *file |
406 |
return NULL; |
return NULL; |
407 |
} |
} |
408 |
|
|
409 |
if (fread (uar->buffer + file->offset, size, 1, stream) != 1) |
if (size != 0 && fread (uar->buffer + file->offset, size, 1, stream) != 1) |
410 |
{ |
{ |
411 |
uar_set_error (uar, UAR_IO_ERROR); |
uar_set_error (uar, UAR_IO_ERROR); |
412 |
fclose (stream); |
fclose (stream); |
433 |
} |
} |
434 |
|
|
435 |
struct uar_file * |
struct uar_file * |
436 |
uar_add_dir (struct uar_archive *uar, const char *name, const char *path) |
uar_add_dir (struct uar_archive *uar, const char *dname, const char *path) |
437 |
{ |
{ |
438 |
assert (uar != NULL && "uar is NULL"); |
assert (uar != NULL && "uar is NULL"); |
439 |
assert (name != NULL && "name is NULL"); |
assert (dname != NULL && "dname is NULL"); |
440 |
assert (path != NULL && "path is NULL"); |
assert (path != NULL && "path is NULL"); |
441 |
assert (!uar->is_stream && "uar in non-stream mode is not supported yet"); |
assert (!uar->is_stream && "uar in non-stream mode is not supported yet"); |
442 |
|
|
443 |
uint64_t namelen = strlen (name); |
char *name = (char *) dname; |
444 |
|
bool free_name = false; |
445 |
|
int cerrno; |
446 |
|
uint64_t namelen; |
447 |
|
|
448 |
|
if (strcmp (name, ".") == 0) |
449 |
|
{ |
450 |
|
name = malloc (2); |
451 |
|
name[0] = UAR_ROOT_DIR_NAME; |
452 |
|
name[1] = 0; |
453 |
|
free_name = true; |
454 |
|
namelen = 1; |
455 |
|
} |
456 |
|
else |
457 |
|
namelen = strlen (name); |
458 |
|
|
459 |
if (namelen >= PATH_MAX) |
if (namelen >= PATH_MAX) |
460 |
{ |
{ |
509 |
|
|
510 |
if (stat (fullpath, &stinfo) != 0) |
if (stat (fullpath, &stinfo) != 0) |
511 |
{ |
{ |
|
int current_errno = errno; |
|
512 |
uar_set_error (uar, UAR_IO_ERROR); |
uar_set_error (uar, UAR_IO_ERROR); |
513 |
uar_file_destroy (dir_file); |
goto uar_add_dir_error; |
|
closedir (dir); |
|
|
free (fullpath); |
|
|
free (fullname); |
|
|
errno = current_errno; |
|
|
return NULL; |
|
514 |
} |
} |
515 |
|
|
516 |
if (S_ISREG (stinfo.st_mode)) |
if (S_ISREG (stinfo.st_mode)) |
520 |
|
|
521 |
if (file == NULL) |
if (file == NULL) |
522 |
{ |
{ |
523 |
int current_errno = errno; |
goto uar_add_dir_error; |
|
uar_file_destroy (dir_file); |
|
|
closedir (dir); |
|
|
free (fullpath); |
|
|
free (fullname); |
|
|
errno = current_errno; |
|
|
return NULL; |
|
524 |
} |
} |
525 |
|
|
526 |
file->mode = stinfo.st_mode & 07777; |
file->mode = stinfo.st_mode & 07777; |
533 |
|
|
534 |
if (direntry == NULL) |
if (direntry == NULL) |
535 |
{ |
{ |
536 |
int current_errno = errno; |
goto uar_add_dir_error; |
|
uar_file_destroy (dir_file); |
|
|
closedir (dir); |
|
|
free (fullpath); |
|
|
free (fullname); |
|
|
errno = current_errno; |
|
|
return NULL; |
|
537 |
} |
} |
538 |
|
|
539 |
direntry->mode = stinfo.st_mode & 07777; |
direntry->mode = stinfo.st_mode & 07777; |
543 |
assert (false && "Not supported"); |
assert (false && "Not supported"); |
544 |
|
|
545 |
free (fullpath); |
free (fullpath); |
546 |
} |
free (fullname); |
547 |
|
|
548 |
closedir (dir); |
continue; |
549 |
|
|
550 |
|
uar_add_dir_error: |
551 |
|
cerrno = errno; |
552 |
|
uar_file_destroy (dir_file); |
553 |
|
free (fullpath); |
554 |
|
free (fullname); |
555 |
|
errno = cerrno; |
556 |
|
goto uar_add_dir_end; |
557 |
|
} |
558 |
|
|
559 |
dir_file->type = UF_DIR; |
dir_file->type = UF_DIR; |
560 |
dir_file->data.size = dir_size; |
dir_file->data.size = dir_size; |
561 |
|
|
562 |
|
uar_add_dir_end: |
563 |
|
cerrno = errno; |
564 |
|
closedir (dir); |
565 |
|
|
566 |
|
if (free_name) |
567 |
|
free (name); |
568 |
|
|
569 |
|
errno = cerrno; |
570 |
return dir_file; |
return dir_file; |
571 |
} |
} |
572 |
|
|
623 |
: file->type == UF_DIR ? "directory" |
: file->type == UF_DIR ? "directory" |
624 |
: "link", |
: "link", |
625 |
i); |
i); |
626 |
printf (" name: \033[1m%s%s\033[0m\n", file->name, |
printf (" name: \033[1m%s%s%s\033[0m\n", |
627 |
|
file->name[0] == UAR_ROOT_DIR_NAME ? "/" : "", |
628 |
|
file->name[0] == UAR_ROOT_DIR_NAME ? file->name + 2 |
629 |
|
: file->name, |
630 |
file->type == UF_DIR ? "/" |
file->type == UF_DIR ? "/" |
631 |
: file->type == UF_LINK ? "@" |
: file->type == UF_LINK ? "@" |
632 |
: ""); |
: ""); |
633 |
printf (" offset: %u\n", file->offset); |
printf (" offset: %lu\n", file->offset); |
634 |
printf (" mode: %04o\n", file->mode); |
printf (" mode: %04o\n", file->mode); |
635 |
|
|
636 |
switch (file->type) |
switch (file->type) |
687 |
} |
} |
688 |
} |
} |
689 |
|
|
690 |
if (fwrite (uar->buffer, uar->header.size, 1, stream) != 1) |
if (fwrite (uar->buffer, 1, uar->header.size, stream) != uar->header.size) |
691 |
{ |
{ |
692 |
uar_set_error (uar, UAR_IO_ERROR); |
uar_set_error (uar, UAR_IO_ERROR); |
693 |
fclose (stream); |
fclose (stream); |
701 |
const char * |
const char * |
702 |
uar_get_file_name (const struct uar_file *file) |
uar_get_file_name (const struct uar_file *file) |
703 |
{ |
{ |
704 |
return file->name; |
return file->name[0] == UAR_ROOT_DIR_NAME |
705 |
|
? file->namelen == 1 ? "/" : file->name + 1 |
706 |
|
: file->name; |
707 |
} |
} |
708 |
|
|
709 |
bool |
bool |
723 |
if (callback != NULL && !callback (file)) |
if (callback != NULL && !callback (file)) |
724 |
return false; |
return false; |
725 |
|
|
726 |
|
char *name = file->name; |
727 |
|
|
728 |
|
if (name[0] == UAR_ROOT_DIR_NAME) |
729 |
|
name += 2; |
730 |
|
|
731 |
switch (file->type) |
switch (file->type) |
732 |
{ |
{ |
733 |
case UF_FILE: |
case UF_FILE: |
734 |
{ |
{ |
735 |
FILE *stream = fopen (file->name, "wb"); |
FILE *stream = fopen (name, "wb"); |
736 |
|
|
737 |
if (stream == NULL) |
if (stream == NULL) |
738 |
{ |
{ |
754 |
break; |
break; |
755 |
|
|
756 |
case UF_DIR: |
case UF_DIR: |
757 |
if (mkdir (file->name, file->mode) != 0) |
if (file->namelen == 1 |
758 |
|
&& file->name[0] == UAR_ROOT_DIR_NAME) |
759 |
|
continue; |
760 |
|
|
761 |
|
if (mkdir (name, file->mode) != 0) |
762 |
{ |
{ |
763 |
uar_set_error (uar, UAR_SYSTEM_ERROR); |
uar_set_error (uar, UAR_SYSTEM_ERROR); |
764 |
return false; |
return false; |