Added spec:commit task to commit changes to spec/ruby sources.
[rbx.git] / shotgun / lib / ar.c
blobcbb31d72d13936dc5abf85e00cc29d5e0b2457ec
1 #include <fcntl.h>
2 #include <string.h>
3 #include <strings.h>
4 #include <sys/types.h>
5 #include <sys/uio.h>
6 #include <unistd.h>
8 #include "shotgun/lib/shotgun.h"
9 #include "shotgun/lib/ar.h"
11 static int ar_validate(int fd) {
12 char data[8];
13 long bytes;
15 bzero(data, 8);
17 bytes = read(fd, data, 8);
19 if(bytes != 8 || strncmp(data, "!<arch>\n", 8)) {
20 return FALSE;
23 return TRUE;
26 static char *ar_file_name(int fd, char *name, long *size) {
27 long bytes, length;
28 char *ptr;
30 if(strncmp(name, "#1/", 3) != 0) {
31 ptr = strchr(name, ' ');
32 *ptr = (char)0;
33 return strdup(name);
34 } else {
35 length = atoi(name + 3);
37 ptr = (char *)calloc(length, sizeof(char));
38 if(ptr == NULL) return NULL;
40 bytes = read(fd, ptr, length);
42 if(bytes != length) {
43 free(ptr);
44 return NULL;
47 *size -= length;
49 return ptr;
54 * Retrieves each file from from ar(5) archive +path+ and processes it with
55 * +callback+.
57 int ar_each_file(machine m, const char *path, int(*callback)(machine, char *, uint8_t *, long)) {
58 int err;
59 long bytes, size;
60 char *name, data_size[11], name_data[17];
61 uint8_t *data;
62 int fd;
63 int ret = TRUE;
65 bzero(data_size, 11);
66 bzero(name_data, 17);
68 fd = open(path, O_RDONLY);
70 if(fd == -1) {
71 return FALSE;
74 if(!ar_validate(fd)) {
75 return FALSE;
78 for(;;) {
79 bytes = read(fd, name_data, 16);
80 if(bytes == 0) { /* end of file */
81 break;
82 } else if(bytes != 16) {
83 ret = FALSE;
84 break;
87 err = lseek(fd, 32, SEEK_CUR); /* mtime, uid, gid, mode */
88 if(err < 0) {
89 ret = FALSE;
90 break;
93 bytes = read(fd, data_size, 10);
94 if(bytes != 10) {
95 ret = FALSE;
96 break;
99 size = atoi(data_size);
101 err = lseek(fd, 2, SEEK_CUR);
102 if(err < 0) {
103 ret = FALSE;
104 break;
107 name = ar_file_name(fd, name_data, &size);
109 data = (uint8_t *)calloc(size, sizeof(uint8_t));
110 if(data == NULL) {
111 ret = FALSE;
112 break;
115 bytes = read(fd, data, size);
116 if(bytes != size) {
117 free(data);
118 ret = FALSE;
119 break;
122 ret = callback(m, name, data, bytes);
124 free(data);
126 if(!RTEST(ret)) {
127 break;
130 if(size % 2 == 1) {
131 lseek(fd, 1, SEEK_CUR);
132 if(err < 0) {
133 ret = FALSE;
134 break;
139 close(fd);
141 return ret;