URI: 
       archive.c - 9base - revived minimalist port of Plan 9 userland to Unix
  HTML git clone git://git.suckless.org/9base
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       archive.c (4689B)
       ---
            1 #include        "mk.h"
            2 #define        ARMAG        "!<arch>\n"
            3 #define        SARMAG        8
            4 
            5 #define        ARFMAG        "`\n"
            6 #define SARNAME        16
            7 
            8 struct        ar_hdr
            9 {
           10         char        name[SARNAME];
           11         char        date[12];
           12         char        uid[6];
           13         char        gid[6];
           14         char        mode[8];
           15         char        size[10];
           16         char        fmag[2];
           17 };
           18 #define        SAR_HDR        (SARNAME+44)
           19 
           20 static int dolong = 1;
           21 
           22 static void atimes(char *);
           23 static char *split(char*, char**);
           24 
           25 long
           26 readn(int f, void *av, long n)
           27 {
           28         char *a;
           29         long m, t;
           30 
           31         a = av;
           32         t = 0;
           33         while(t < n){
           34                 m = read(f, a+t, n-t);
           35                 if(m <= 0){
           36                         if(t == 0)
           37                                 return m;
           38                         break;
           39                 }
           40                 t += m;
           41         }
           42         return t;
           43 }
           44 long
           45 atimeof(int force, char *name)
           46 {
           47         Symtab *sym;
           48         long t;
           49         char *archive, *member, buf[512];
           50 
           51         archive = split(name, &member);
           52         if(archive == 0)
           53                 Exit();
           54 
           55         t = mtime(archive);
           56         sym = symlook(archive, S_AGG, 0);
           57         if(sym){
           58                 if(force || (t > sym->u.value)){
           59                         atimes(archive);
           60                         sym->u.value = t;
           61                 }
           62         }
           63         else{
           64                 atimes(archive);
           65                 /* mark the aggegate as having been done */
           66                 symlook(strdup(archive), S_AGG, "")->u.value = t;
           67         }
           68                 /* truncate long member name to sizeof of name field in archive header */
           69         if(dolong)
           70                 snprint(buf, sizeof(buf), "%s(%s)", archive, member);
           71         else
           72                 snprint(buf, sizeof(buf), "%s(%.*s)", archive, SARNAME, member);
           73         sym = symlook(buf, S_TIME, 0);
           74         if (sym)
           75                 return sym->u.value;
           76         return 0;
           77 }
           78 
           79 void
           80 atouch(char *name)
           81 {
           82         char *archive, *member;
           83         int fd, i;
           84         struct ar_hdr h;
           85         long t;
           86 
           87         archive = split(name, &member);
           88         if(archive == 0)
           89                 Exit();
           90 
           91         fd = open(archive, ORDWR);
           92         if(fd < 0){
           93                 fd = create(archive, OWRITE, 0666);
           94                 if(fd < 0){
           95                         fprint(2, "create %s: %r\n", archive);
           96                         Exit();
           97                 }
           98                 write(fd, ARMAG, SARMAG);
           99         }
          100         if(symlook(name, S_TIME, 0)){
          101                 /* hoon off and change it in situ */
          102                 LSEEK(fd, SARMAG, 0);
          103                 while(read(fd, (char *)&h, sizeof(h)) == sizeof(h)){
          104                         for(i = SARNAME-1; i > 0 && h.name[i] == ' '; i--)
          105                                         ;
          106                         h.name[i+1]=0;
          107                         if(strcmp(member, h.name) == 0){
          108                                 t = SARNAME-sizeof(h);        /* ughgghh */
          109                                 LSEEK(fd, t, 1);
          110                                 fprint(fd, "%-12ld", time(0));
          111                                 break;
          112                         }
          113                         t = atol(h.size);
          114                         if(t&01) t++;
          115                         LSEEK(fd, t, 1);
          116                 }
          117         }
          118         close(fd);
          119 }
          120 
          121 static void
          122 atimes(char *ar)
          123 {
          124         struct ar_hdr h;
          125         long t;
          126         int fd, i, namelen;
          127         char buf[2048], *p, *strings;
          128         char name[1024];
          129         Symtab *sym;
          130 
          131         strings = nil;
          132         fd = open(ar, OREAD);
          133         if(fd < 0)
          134                 return;
          135 
          136         if(read(fd, buf, SARMAG) != SARMAG){
          137                 close(fd);
          138                 return;
          139         }
          140         while(readn(fd, (char *)&h, sizeof(h)) == sizeof(h)){
          141                 t = atol(h.date);
          142                 if(t == 0)        /* as it sometimes happens; thanks ken */
          143                         t = 1;
          144                 namelen = 0;
          145                 if(memcmp(h.name, "#1/", 3) == 0){        /* BSD */
          146                         namelen = atoi(h.name+3);
          147                         if(namelen >= sizeof name){
          148                                 namelen = 0;
          149                                 goto skip;
          150                         }
          151                         if(readn(fd, name, namelen) != namelen)
          152                                 break;
          153                         name[namelen] = 0;
          154                 }else if(memcmp(h.name, "// ", 2) == 0){ /* GNU */
          155                         /* date, uid, gid, mode all ' ' */
          156                         for(i=2; i<16+12+6+6+8; i++)
          157                                 if(h.name[i] != ' ')
          158                                         goto skip;
          159                         t = atol(h.size);
          160                         if(t&01)
          161                                 t++;
          162                         free(strings);
          163                         strings = malloc(t+1);
          164                         if(strings){
          165                                 if(readn(fd, strings, t) != t){
          166                                         free(strings);
          167                                         strings = nil;
          168                                         break;
          169                                 }
          170                                 strings[t] = 0;
          171                                 continue;
          172                         }
          173                         goto skip;
          174                 }else if(strings && h.name[0]=='/' && isdigit((uchar)h.name[1])){
          175                         i = strtol(h.name+1, &p, 10);
          176                         if(*p != ' ' || i >= strlen(strings))
          177                                 goto skip;
          178                         p = strings+i;
          179                         for(; *p && *p != '/'; p++)
          180                                 ;
          181                         namelen = p-(strings+i);
          182                         if(namelen >= sizeof name){
          183                                 namelen = 0;
          184                                 goto skip;
          185                         }
          186                         memmove(name, strings+i, namelen);
          187                         name[namelen] = 0;
          188                         namelen = 0;
          189                 }else{
          190                         strncpy(name, h.name, sizeof(h.name));
          191                         for(i = sizeof(h.name)-1; i > 0 && name[i] == ' '; i--)
          192                                         ;
          193                         if(name[i] == '/')                /* system V bug */
          194                                 i--;
          195                         name[i+1]=0;
          196                 }
          197                 snprint(buf, sizeof buf, "%s(%s)", ar, name);
          198                 sym = symlook(strdup(buf), S_TIME, (void *)t);
          199                 sym->u.value = t;
          200         skip:
          201                 t = atol(h.size);
          202                 if(t&01) t++;
          203                 t -= namelen;
          204                 LSEEK(fd, t, 1);
          205         }
          206         close(fd);
          207         free(strings);
          208 }
          209 
          210 static int
          211 type(char *file)
          212 {
          213         int fd;
          214         char buf[SARMAG];
          215 
          216         fd = open(file, OREAD);
          217         if(fd < 0){
          218                 if(symlook(file, S_BITCH, 0) == 0){
          219                         if(strlen(file) < 2 || strcmp(file+strlen(file)-2, ".a") != 0)
          220                                 Bprint(&bout, "%s doesn't exist: assuming it will be an archive\n", file);
          221                         symlook(file, S_BITCH, (void *)file);
          222                 }
          223                 return 1;
          224         }
          225         if(read(fd, buf, SARMAG) != SARMAG){
          226                 close(fd);
          227                 return 0;
          228         }
          229         close(fd);
          230         return !strncmp(ARMAG, buf, SARMAG);
          231 }
          232 
          233 static char*
          234 split(char *name, char **member)
          235 {
          236         char *p, *q;
          237 
          238         p = strdup(name);
          239         q = utfrune(p, '(');
          240         if(q){
          241                 *q++ = 0;
          242                 if(member)
          243                         *member = q;
          244                 q = utfrune(q, ')');
          245                 if (q)
          246                         *q = 0;
          247                 if(type(p))
          248                         return p;
          249                 free(p);
          250                 fprint(2, "mk: '%s' is not an archive\n", name);
          251         }
          252         return 0;
          253 }