URI:
       tmkext.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tmkext.c (5827B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 
            5 #define mkdir plan9mkdir
            6 
            7 enum{
            8         LEN        = 8*1024,
            9         NFLDS        = 6,                /* filename, modes, uid, gid, mtime, bytes */
           10 };
           11 
           12 int        selected(char*, int, char*[]);
           13 void        mkdirs(char*, char*);
           14 void        mkdir(char*, ulong, ulong, char*, char*);
           15 void        extract(char*, ulong, ulong, char*, char*, uvlong);
           16 void        seekpast(uvlong);
           17 void        error(char*, ...);
           18 void        warn(char*, ...);
           19 void        usage(void);
           20 #pragma varargck argpos warn 1
           21 #pragma varargck argpos error 1
           22 
           23 Biobuf        bin;
           24 uchar        binbuf[2*LEN];
           25 char        linebuf[LEN];
           26 int        uflag;
           27 int        hflag;
           28 int        vflag;
           29 int        Tflag;
           30 
           31 void
           32 main(int argc, char **argv)
           33 {
           34         Biobuf bout;
           35         char *fields[NFLDS], name[2*LEN], *p, *namep;
           36         char *uid, *gid;
           37         ulong mode, mtime;
           38         uvlong bytes;
           39 
           40         quotefmtinstall();
           41         namep = name;
           42         ARGBEGIN{
           43         case 'd':
           44                 p = ARGF();
           45                 if(strlen(p) >= LEN)
           46                         error("destination fs name too long\n");
           47                 strcpy(name, p);
           48                 namep = name + strlen(name);
           49                 break;
           50         case 'h':
           51                 hflag = 1;
           52                 Binit(&bout, 1, OWRITE);
           53                 break;
           54         case 'u':
           55                 uflag = 1;
           56                 Tflag = 1;
           57                 break;
           58         case 'T':
           59                 Tflag = 1;
           60                 break;
           61         case 'v':
           62                 vflag = 1;
           63                 break;
           64         default:
           65                 usage();
           66         }ARGEND
           67 
           68         Binits(&bin, 0, OREAD, binbuf, sizeof binbuf);
           69         while(p = Brdline(&bin, '\n')){
           70                 p[Blinelen(&bin)-1] = '\0';
           71                 strcpy(linebuf, p);
           72                 p = linebuf;
           73                 if(strcmp(p, "end of archive") == 0){
           74                         Bterm(&bout);
           75                         fprint(2, "done\n");
           76                         exits(0);
           77                 }
           78                 if (gettokens(p, fields, NFLDS, " \t") != NFLDS){
           79                         warn("too few fields in file header");
           80                         continue;
           81                 }
           82                 p = unquotestrdup(fields[0]);
           83                 strcpy(namep, p);
           84                 free(p);
           85                 mode = strtoul(fields[1], 0, 8);
           86                 uid = fields[2];
           87                 gid = fields[3];
           88                 mtime = strtoul(fields[4], 0, 10);
           89                 bytes = strtoull(fields[5], 0, 10);
           90                 if(argc){
           91                         if(!selected(namep, argc, argv)){
           92                                 if(bytes)
           93                                         seekpast(bytes);
           94                                 continue;
           95                         }
           96                         mkdirs(name, namep);
           97                 }
           98                 if(hflag){
           99                         Bprint(&bout, "%q %luo %q %q %lud %llud\n",
          100                                 name, mode, uid, gid, mtime, bytes);
          101                         if(bytes)
          102                                 seekpast(bytes);
          103                         continue;
          104                 }
          105                 if(mode & DMDIR)
          106                         mkdir(name, mode, mtime, uid, gid);
          107                 else
          108                         extract(name, mode, mtime, uid, gid, bytes);
          109         }
          110         fprint(2, "premature end of archive\n");
          111         exits("premature end of archive");
          112 }
          113 
          114 int
          115 fileprefix(char *prefix, char *s)
          116 {
          117         while(*prefix)
          118                 if(*prefix++ != *s++)
          119                         return 0;
          120         if(*s && *s != '/')
          121                 return 0;
          122         return 1;
          123 }
          124 
          125 int
          126 selected(char *s, int argc, char *argv[])
          127 {
          128         int i;
          129 
          130         for(i=0; i<argc; i++)
          131                 if(fileprefix(argv[i], s))
          132                         return 1;
          133         return 0;
          134 }
          135 
          136 void
          137 mkdirs(char *name, char *namep)
          138 {
          139         char buf[2*LEN], *p;
          140         int fd;
          141 
          142         strcpy(buf, name);
          143         for(p = &buf[namep - name]; p = utfrune(p, '/'); p++){
          144                 if(p[1] == '\0')
          145                         return;
          146                 *p = 0;
          147                 fd = create(buf, OREAD, 0775|DMDIR);
          148                 close(fd);
          149                 *p = '/';
          150         }
          151 }
          152 
          153 void
          154 mkdir(char *name, ulong mode, ulong mtime, char *uid, char *gid)
          155 {
          156         Dir *d, xd;
          157         int fd;
          158         char *p;
          159         char olderr[256];
          160 
          161         fd = create(name, OREAD, mode);
          162         if(fd < 0){
          163                 rerrstr(olderr, sizeof(olderr));
          164                 if((d = dirstat(name)) == nil || !(d->mode & DMDIR)){
          165                         free(d);
          166                         warn("can't make directory %q, mode %luo: %s", name, mode, olderr);
          167                         return;
          168                 }
          169                 free(d);
          170         }
          171         close(fd);
          172 
          173         d = &xd;
          174         nulldir(d);
          175         p = utfrrune(name, L'/');
          176         if(p)
          177                 p++;
          178         else
          179                 p = name;
          180         d->name = p;
          181         if(uflag){
          182                 d->uid = uid;
          183                 d->gid = gid;
          184         }
          185         if(Tflag)
          186                 d->mtime = mtime;
          187         d->mode = mode;
          188         if(dirwstat(name, d) < 0)
          189                 warn("can't set modes for %q: %r", name);
          190 
          191         if(uflag||Tflag){
          192                 if((d = dirstat(name)) == nil){
          193                         warn("can't reread modes for %q: %r", name);
          194                         return;
          195                 }
          196                 if(Tflag && d->mtime != mtime)
          197                         warn("%q: time mismatch %lud %lud\n", name, mtime, d->mtime);
          198                 if(uflag && strcmp(uid, d->uid))
          199                         warn("%q: uid mismatch %q %q", name, uid, d->uid);
          200                 if(uflag && strcmp(gid, d->gid))
          201                         warn("%q: gid mismatch %q %q", name, gid, d->gid);
          202         }
          203 }
          204 
          205 void
          206 extract(char *name, ulong mode, ulong mtime, char *uid, char *gid, uvlong bytes)
          207 {
          208         Dir d, *nd;
          209         Biobuf *b;
          210         char buf[LEN];
          211         char *p;
          212         ulong n;
          213         uvlong tot;
          214 
          215         if(vflag)
          216                 print("x %q %llud bytes\n", name, bytes);
          217 
          218         b = Bopen(name, OWRITE);
          219         if(!b){
          220                 warn("can't make file %q: %r", name);
          221                 seekpast(bytes);
          222                 return;
          223         }
          224         for(tot = 0; tot < bytes; tot += n){
          225                 n = sizeof buf;
          226                 if(tot + n > bytes)
          227                         n = bytes - tot;
          228                 n = Bread(&bin, buf, n);
          229                 if(n <= 0)
          230                         error("premature eof reading %q", name);
          231                 if(Bwrite(b, buf, n) != n)
          232                         warn("error writing %q: %r", name);
          233         }
          234 
          235         nulldir(&d);
          236         p = utfrrune(name, '/');
          237         if(p)
          238                 p++;
          239         else
          240                 p = name;
          241         d.name = p;
          242         if(uflag){
          243                 d.uid = uid;
          244                 d.gid = gid;
          245         }
          246         if(Tflag)
          247                 d.mtime = mtime;
          248         d.mode = mode;
          249         Bflush(b);
          250         if(dirfwstat(Bfildes(b), &d) < 0)
          251                 warn("can't set modes for %q: %r", name);
          252         if(uflag||Tflag){
          253                 if((nd = dirfstat(Bfildes(b))) == nil)
          254                         warn("can't reread modes for %q: %r", name);
          255                 else{
          256                         if(Tflag && nd->mtime != mtime)
          257                                 warn("%q: time mismatch %lud %lud\n",
          258                                         name, mtime, nd->mtime);
          259                         if(uflag && strcmp(uid, nd->uid))
          260                                 warn("%q: uid mismatch %q %q",
          261                                         name, uid, nd->uid);
          262                         if(uflag && strcmp(gid, nd->gid))
          263                                 warn("%q: gid mismatch %q %q",
          264                                         name, gid, nd->gid);
          265                         free(nd);
          266                 }
          267         }
          268         Bterm(b);
          269 }
          270 
          271 void
          272 seekpast(uvlong bytes)
          273 {
          274         char buf[LEN];
          275         long n;
          276         uvlong tot;
          277 
          278         for(tot = 0; tot < bytes; tot += n){
          279                 n = sizeof buf;
          280                 if(tot + n > bytes)
          281                         n = bytes - tot;
          282                 n = Bread(&bin, buf, n);
          283                 if(n < 0)
          284                         error("premature eof");
          285         }
          286 }
          287 
          288 void
          289 error(char *fmt, ...)
          290 {
          291         char buf[1024];
          292         va_list arg;
          293 
          294         sprint(buf, "%q: ", argv0);
          295         va_start(arg, fmt);
          296         vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
          297         va_end(arg);
          298         fprint(2, "%s\n", buf);
          299         exits(0);
          300 }
          301 
          302 void
          303 warn(char *fmt, ...)
          304 {
          305         char buf[1024];
          306         va_list arg;
          307 
          308         sprint(buf, "%q: ", argv0);
          309         va_start(arg, fmt);
          310         vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
          311         va_end(arg);
          312         fprint(2, "%s\n", buf);
          313 }
          314 
          315 void
          316 usage(void)
          317 {
          318         fprint(2, "usage: mkext [-h] [-u] [-v] [-d dest-fs] [file ...]\n");
          319         exits("usage");
          320 }