9os

Experimental kernel using plan9 ideas for embedded device
git clone git://git.simple-cc.org/9os
Log | Files | Refs | README | LICENSE

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 };