devar.c (3982B)
1 #include <os9/os9.h> 2 3 #include <errno.h> 4 #include <stdlib.h> 5 #include <string.h> 6 7 #include "dev.h" 8 9 #define NR_ARS 2 10 11 #define ARMAG "!<arch>\n" /* ar "magic number" */ 12 #define SARMAG 8 /* strlen(ARMAG); */ 13 #define ARFMAG "`\n" 14 #define SARNAM 16 15 16 17 struct ar_hdr { 18 char ar_name[SARNAM]; /* name */ 19 char ar_date[12]; /* modification time */ 20 char ar_uid[6]; /* user id */ 21 char ar_gid[6]; /* group id */ 22 char ar_mode[8]; /* octal file permissions */ 23 char ar_size[10]; /* size in bytes */ 24 char ar_fmag[2]; /* consistency check */ 25 }; 26 27 struct arfile { 28 Chan *c; 29 long offset[NR_FILES]; 30 long size[NR_FILES]; 31 }; 32 33 static struct arfile archives[NR_ARS]; 34 static int nars; 35 36 37 static int 38 gethdr(Chan *c, struct ar_hdr *hdr) 39 { 40 int n, ch, i; 41 42 n = devtab[c->type]->read(c, hdr, sizeof(*hdr)); 43 if (n <= 0) 44 return n; 45 46 if (n != sizeof(*hdr) || strncmp(hdr->ar_fmag, ARFMAG, 2) != 0) { 47 seterror(EINVAL); 48 return -1; 49 } 50 51 for (i = SARNAM-1; i >= 0; i--) { 52 ch = hdr->ar_name[i]; 53 if (ch != ' ' && ch != '/') 54 break; 55 hdr->ar_name[i] = '\0'; 56 } 57 58 return 1; 59 } 60 61 static int 62 argen(Chan *c, Dirtab *tab, int ntab, int n, Dir *dir) 63 { 64 int i, r, len; 65 long off; 66 Chan nc; 67 struct ar_hdr hdr; 68 struct arfile *ar; 69 70 if (c->dev >= nars) 71 panic("argen"); 72 clone(archives[c->dev].c, &nc); 73 ar = &archives[nc.dev]; 74 75 for (i = 0; i <= n; i++) { 76 if (ar->offset[i] == -1) 77 return -1; 78 off = ar->offset[i]; 79 if (devtab[c->type]->seek(&nc, off, SEEK_SET) < 0) 80 return -1; 81 if ((r = gethdr(&nc, &hdr)) <= 0) 82 return r; 83 } 84 85 if ((len = strlen(hdr.ar_name)) >= NAMELEN) { 86 seterror(ENAMETOOLONG); 87 return -1; 88 } 89 90 mkentry(c, dir, 91 hdr.ar_name, atol(hdr.ar_size), 92 QID(CHFILE, 0, n), 93 O_READ); 94 95 return 1; 96 } 97 98 static int 99 arwalk(Chan *c, char *name) 100 { 101 return devwalk(c, name, NULL, 0, argen); 102 } 103 104 static int 105 arstat(Chan *c, char *file, unsigned char *buf, int n) 106 { 107 return devstat(c, file, buf, n, NULL, 0, argen); 108 } 109 110 static int 111 arread(Chan *c, void *buf, int n) 112 { 113 long off; 114 Chan cs; 115 struct arfile *ar; 116 long size; 117 long long path; 118 119 if (c->qid.type == CHDIR) 120 return dirread(c, buf, n, NULL, 0, argen); 121 122 if (c->dev >= nars) 123 panic("arread1"); 124 ar = &archives[c->dev]; 125 126 path = c->qid.path; 127 if (path >= NR_FILES || ar->offset[path] == -1) 128 panic("arread2"); 129 clone(ar->c, &cs); 130 131 size = ar->size[path]; 132 if (c->offset >= size) 133 return 0; 134 135 if (n < 0) { 136 seterror(EINVAL); 137 return -1; 138 } 139 if (n > size - c->offset) 140 n = size - c->offset; 141 142 off = ar->offset[path] + c->offset + sizeof(struct ar_hdr); 143 if (devtab[cs.type]->seek(&cs, off, SEEK_SET) < 0) 144 return -1; 145 146 n = devtab[cs.type]->read(&cs, buf, n); 147 if (n > 0) 148 c->offset += n; 149 150 return n; 151 } 152 153 static Chan * 154 armount(Chan *c, char *spec) 155 { 156 int r, n, t; 157 long len, offhdr; 158 Chan *cspec; 159 char buf[SARMAG]; 160 struct ar_hdr hdr; 161 struct arfile *ar; 162 163 if (nars == NR_ARS) { 164 seterror(ENOMEM); 165 return NULL; 166 } 167 ar = &archives[nars]; 168 169 for (n = 0; n < NR_FILES; n++) 170 ar->offset[n] = -1; 171 172 if ((cspec = namec(spec, O_READ)) == NULL) 173 return NULL; 174 ar->c = cspec; 175 176 r = devtab[cspec->type]->read(cspec, buf, SARMAG); 177 if (r < 0) 178 goto err; 179 if (r != SARMAG || strncmp(buf, ARMAG, SARMAG)) { 180 seterror(EINVAL); 181 goto err; 182 } 183 184 for (n = 0; n < NR_FILES; n++) { 185 offhdr = cspec->offset; 186 switch (gethdr(cspec, &hdr)) { 187 case 0: 188 return attach('R', nars++); 189 case -1: 190 goto err; 191 default: 192 ar->offset[n] = offhdr; 193 len = atol(hdr.ar_size); 194 ar->size[n] = len; 195 if ((len % 2) != 0) 196 len++; 197 198 t = cspec->type; 199 if (devtab[t]->seek(cspec, len, SEEK_CUR) < 0) 200 goto err; 201 break; 202 } 203 } 204 seterror(ENOMEM); 205 206 err: 207 chanclose(cspec); 208 return NULL; 209 } 210 211 Dev ardevtab = { 212 .id = 'R', 213 .stat = arstat, 214 .clone = devclone, 215 .attach = devattach, 216 .walk = arwalk, 217 .read = arread, 218 .write = deverrwrite, 219 .mount = armount, 220 .seek = devseek, 221 .sync = devsync, 222 .close = devclose, 223 };