URI:
       tsysuse.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
       ---
       tsysuse.c (13953B)
       ---
            1 /*
            2  * To understand this code, see Rock Ridge Interchange Protocol
            3  * standard 1.12 and System Use Sharing Protocol version 1.12
            4  * (search for rrip112.ps and susp112.ps on the web).
            5  *
            6  * Even better, go read something else.
            7  */
            8 
            9 #include <u.h>
           10 #include <libc.h>
           11 #include <bio.h>
           12 #include <libsec.h>
           13 #include "iso9660.h"
           14 
           15 static long mode(Direc*, int);
           16 static long nlink(Direc*);
           17 static ulong suspdirflags(Direc*, int);
           18 static ulong CputsuspCE(Cdimg *cd, ulong offset);
           19 static int CputsuspER(Cdimg*, int);
           20 static int CputsuspRR(Cdimg*, int, int);
           21 static int CputsuspSP(Cdimg*, int);
           22 /*static int CputsuspST(Cdimg*, int); */
           23 static int Cputrripname(Cdimg*, char*, int, char*, int);
           24 static int CputrripSL(Cdimg*, int, int, char*, int);
           25 static int CputrripPX(Cdimg*, Direc*, int, int);
           26 static int CputrripTF(Cdimg*, Direc*, int, int);
           27 
           28 /*
           29  * Patch the length field in a CE record.
           30  */
           31 static void
           32 setcelen(Cdimg *cd, ulong woffset, ulong len)
           33 {
           34         ulong o;
           35 
           36         o = Cwoffset(cd);
           37         Cwseek(cd, woffset);
           38         Cputn(cd, len, 4);
           39         Cwseek(cd, o);
           40 }
           41 
           42 /*
           43  * Rock Ridge data is put into little blockettes, which can be
           44  * at most 256 bytes including a one-byte length.  Some number
           45  * of blockettes get packed together into a normal 2048-byte block.
           46  * Blockettes cannot cross block boundaries.
           47  *
           48  * A Cbuf is a blockette buffer.  Len contains
           49  * the length of the buffer written so far, and we can
           50  * write up to 254-28.
           51  *
           52  * We only have one active Cbuf at a time; cdimg.rrcontin is the byte
           53  * offset of the beginning of that Cbuf.
           54  *
           55  * The blockette can be at most 255 bytes.  The last 28
           56  * will be (in the worst case) a CE record pointing at
           57  * a new blockette.  If we do write 255 bytes though,
           58  * we'll try to pad it out to be even, and overflow.
           59  * So the maximum is 254-28.
           60  *
           61  * Ceoffset contains the offset to be used with setcelen
           62  * to patch the CE pointing at the Cbuf once we know how
           63  * long the Cbuf is.
           64  */
           65 typedef struct Cbuf Cbuf;
           66 struct Cbuf {
           67         int len;        /* written so far, of 254-28 */
           68         ulong ceoffset;
           69 };
           70 
           71 static int
           72 freespace(Cbuf *cp)
           73 {
           74         return (254-28) - cp->len;
           75 }
           76 
           77 static Cbuf*
           78 ensurespace(Cdimg *cd, int n, Cbuf *co, Cbuf *cn, int dowrite)
           79 {
           80         ulong end;
           81 
           82         if(co->len+n <= 254-28) {
           83                 co->len += n;
           84                 return co;
           85         }
           86 
           87         co->len += 28;
           88         assert(co->len <= 254);
           89 
           90         if(dowrite == 0) {
           91                 cn->len = n;
           92                 return cn;
           93         }
           94 
           95         /*
           96          * the current blockette is full; update cd->rrcontin and then
           97           * write a CE record to finish it.  Unfortunately we need to
           98          * figure out which block will be next before we write the CE.
           99          */
          100         end = Cwoffset(cd)+28;
          101 
          102         /*
          103          * if we're in a continuation blockette, update rrcontin.
          104          * also, write our length into the field of the CE record
          105          * that points at us.
          106          */
          107         if(cd->rrcontin+co->len == end) {
          108                 assert(cd->rrcontin != 0);
          109                 assert(co == cn);
          110                 cd->rrcontin += co->len;
          111                 setcelen(cd, co->ceoffset, co->len);
          112         } else
          113                 assert(co != cn);
          114 
          115         /*
          116          * if the current continuation block can't fit another
          117          * blockette, then start a new continuation block.
          118          * rrcontin = 0 (mod Blocksize) means we just finished
          119          * one, not that we've just started one.
          120          */
          121         if(cd->rrcontin%Blocksize == 0
          122         || cd->rrcontin/Blocksize != (cd->rrcontin+256)/Blocksize) {
          123                 cd->rrcontin = cd->nextblock*Blocksize;
          124                 cd->nextblock++;
          125         }
          126 
          127         cn->ceoffset = CputsuspCE(cd, cd->rrcontin);
          128 
          129         assert(Cwoffset(cd) == end);
          130 
          131         cn->len = n;
          132         Cwseek(cd, cd->rrcontin);
          133         assert(cd->rrcontin != 0);
          134 
          135         return cn;
          136 }
          137 
          138 /*
          139  * Put down the name, but we might need to break it
          140  * into chunks so that each chunk fits in 254-28-5 bytes.
          141  * What a crock.
          142  *
          143  * The new Plan 9 format uses strings of this form too,
          144  * since they're already there.
          145  */
          146 Cbuf*
          147 Cputstring(Cdimg *cd, Cbuf *cp, Cbuf *cn, char *nm, char *p, int flags, int dowrite)
          148 {
          149         char buf[256], *q;
          150         int free;
          151 
          152         for(; p[0] != '\0'; p = q) {
          153                 cp = ensurespace(cd, 5+1, cp, cn, dowrite);
          154                 cp->len -= 5+1;
          155                 free = freespace(cp);
          156                 assert(5+1 <= free && free < 256);
          157 
          158                 strncpy(buf, p, free-5);
          159                 buf[free-5] = '\0';
          160                 q = p+strlen(buf);
          161                 p = buf;
          162 
          163                 ensurespace(cd, 5+strlen(p), cp, nil, dowrite);        /* nil: better not use this. */
          164                 Cputrripname(cd, nm, flags | (q[0] ? NMcontinue : 0), p, dowrite);
          165         }
          166         return cp;
          167 }
          168 
          169 /*
          170  * Write a Rock Ridge SUSP set of records for a directory entry.
          171  */
          172 int
          173 Cputsysuse(Cdimg *cd, Direc *d, int dot, int dowrite, int initlen)
          174 {
          175         char buf[256], buf0[256], *nextpath, *p, *path, *q;
          176         int flags, free, m, what;
          177         ulong o;
          178         Cbuf cn, co, *cp;
          179 
          180         assert(cd != nil);
          181         assert((initlen&1) == 0);
          182 
          183         if(dot == DTroot)
          184                 return 0;
          185 
          186         co.len = initlen;
          187 
          188         o = Cwoffset(cd);
          189 
          190         assert(dowrite==0 || Cwoffset(cd) == o+co.len-initlen);
          191         cp = &co;
          192 
          193         if (dot == DTrootdot) {
          194                 m = CputsuspSP(cd, 0);
          195                 cp = ensurespace(cd, m, cp, &cn, dowrite);
          196                 CputsuspSP(cd, dowrite);
          197 
          198                 m = CputsuspER(cd, 0);
          199                 cp = ensurespace(cd, m, cp, &cn, dowrite);
          200                 CputsuspER(cd, dowrite);
          201         }
          202 
          203         /*
          204          * In a perfect world, we'd be able to omit the NM
          205          * entries when our name was all lowercase and conformant,
          206          * but OpenBSD insists on uppercasing (really, not lowercasing)
          207          * the ISO9660 names.
          208          */
          209         what = RR_PX | RR_TF | RR_NM;
          210         if(d != nil && (d->mode & CHLINK))
          211                 what |= RR_SL;
          212 
          213         m = CputsuspRR(cd, what, 0);
          214         cp = ensurespace(cd, m, cp, &cn, dowrite);
          215         CputsuspRR(cd, what, dowrite);
          216 
          217         if(what & RR_PX) {
          218                 m = CputrripPX(cd, d, dot, 0);
          219                 cp = ensurespace(cd, m, cp, &cn, dowrite);
          220                 CputrripPX(cd, d, dot, dowrite);
          221         }
          222 
          223         if(what & RR_NM) {
          224                 if(dot == DTiden)
          225                         p = d->name;
          226                 else if(dot == DTdotdot)
          227                         p = "..";
          228                 else
          229                         p = ".";
          230 
          231                 flags = suspdirflags(d, dot);
          232                 assert(dowrite==0 || cp != &co || Cwoffset(cd) == o+co.len-initlen);
          233                 cp = Cputstring(cd, cp, &cn, "NM", p, flags, dowrite);
          234         }
          235 
          236         /*
          237          * Put down the symbolic link.  This is even more of a crock.
          238          * Not only are the individual elements potentially split,
          239          * but the whole path itself can be split across SL blocks.
          240          * To keep the code simple as possible (really), we write
          241          * only one element per SL block, wasting 6 bytes per element.
          242          */
          243         if(what & RR_SL) {
          244                 for(path=d->symlink; path[0] != '\0'; path=nextpath) {
          245                         /* break off one component */
          246                         if((nextpath = strchr(path, '/')) == nil)
          247                                 nextpath = path+strlen(path);
          248                         strncpy(buf0, path, nextpath-path);
          249                         buf0[nextpath-path] = '\0';
          250                         if(nextpath[0] == '/')
          251                                 nextpath++;
          252                         p = buf0;
          253 
          254                         /* write the name, perhaps broken into pieces */
          255                         if(strcmp(p, "") == 0)
          256                                 flags = NMroot;
          257                         else if(strcmp(p, ".") == 0)
          258                                 flags = NMcurrent;
          259                         else if(strcmp(p, "..") == 0)
          260                                 flags = NMparent;
          261                         else
          262                                 flags = 0;
          263 
          264                         /* the do-while handles the empty string properly */
          265                         do {
          266                                 /* must have room for at least 1 byte of name */
          267                                 cp = ensurespace(cd, 7+1, cp, &cn, dowrite);
          268                                 cp->len -= 7+1;
          269                                 free = freespace(cp);
          270                                 assert(7+1 <= free && free < 256);
          271 
          272                                 strncpy(buf, p, free-7);
          273                                 buf[free-7] = '\0';
          274                                 q = p+strlen(buf);
          275                                 p = buf;
          276 
          277                                 /* nil: better not need to expand */
          278                                 assert(7+strlen(p) <= free);
          279                                 ensurespace(cd, 7+strlen(p), cp, nil, dowrite);
          280                                 CputrripSL(cd, nextpath[0], flags | (q[0] ? NMcontinue : 0), p, dowrite);
          281                                 p = q;
          282                         } while(p[0] != '\0');
          283                 }
          284         }
          285 
          286         assert(dowrite==0 || cp != &co || Cwoffset(cd) == o+co.len-initlen);
          287 
          288         if(what & RR_TF) {
          289                 m = CputrripTF(cd, d, TFcreation|TFmodify|TFaccess|TFattributes, 0);
          290                 cp = ensurespace(cd, m, cp, &cn, dowrite);
          291                 CputrripTF(cd, d, TFcreation|TFmodify|TFaccess|TFattributes, dowrite);
          292         }
          293         assert(dowrite==0 || cp != &co || Cwoffset(cd) == o+co.len-initlen);
          294 
          295         if(cp == &cn && dowrite) {
          296                 /* seek out of continuation, but mark our place */
          297                 cd->rrcontin = Cwoffset(cd);
          298                 setcelen(cd, cn.ceoffset, cn.len);
          299                 Cwseek(cd, o+co.len-initlen);
          300         }
          301 
          302         if(co.len & 1) {
          303                 co.len++;
          304                 if(dowrite)
          305                         Cputc(cd, 0);
          306         }
          307 
          308         if(dowrite) {
          309                 if(Cwoffset(cd) != o+co.len-initlen)
          310                         fprint(2, "offset %lud o+co.len-initlen %lud\n", Cwoffset(cd), o+co.len-initlen);
          311                 assert(Cwoffset(cd) == o+co.len-initlen);
          312         } else
          313                 assert(Cwoffset(cd) == o);
          314 
          315         assert(co.len <= 255);
          316         return co.len - initlen;
          317 }
          318 
          319 static char SUSPrrip[10] = "RRIP_1991A";
          320 static char SUSPdesc[84] = "RRIP <more garbage here>";
          321 static char SUSPsrc[135] = "RRIP <more garbage here>";
          322 
          323 static ulong
          324 CputsuspCE(Cdimg *cd, ulong offset)
          325 {
          326         ulong o, x;
          327 
          328         chat("writing SUSP CE record pointing to %ld, %ld\n", offset/Blocksize, offset%Blocksize);
          329         o = Cwoffset(cd);
          330         Cputc(cd, 'C');
          331         Cputc(cd, 'E');
          332         Cputc(cd, 28);
          333         Cputc(cd, 1);
          334         Cputn(cd, offset/Blocksize, 4);
          335         Cputn(cd, offset%Blocksize, 4);
          336         x = Cwoffset(cd);
          337         Cputn(cd, 0, 4);
          338         assert(Cwoffset(cd) == o+28);
          339 
          340         return x;
          341 }
          342 
          343 static int
          344 CputsuspER(Cdimg *cd, int dowrite)
          345 {
          346         assert(cd != nil);
          347 
          348         if(dowrite) {
          349                 chat("writing SUSP ER record\n");
          350                 Cputc(cd, 'E');           /* ER field marker */
          351                 Cputc(cd, 'R');
          352                 Cputc(cd, 26);            /* Length          */
          353                 Cputc(cd, 1);             /* Version         */
          354                 Cputc(cd, 10);            /* LEN_ID          */
          355                 Cputc(cd, 4);             /* LEN_DESC        */
          356                 Cputc(cd, 4);             /* LEN_SRC         */
          357                 Cputc(cd, 1);             /* EXT_VER         */
          358                 Cputs(cd, SUSPrrip, 10);  /* EXT_ID          */
          359                 Cputs(cd, SUSPdesc, 4);   /* EXT_DESC        */
          360                 Cputs(cd, SUSPsrc, 4);    /* EXT_SRC         */
          361         }
          362         return 8+10+4+4;
          363 }
          364 
          365 static int
          366 CputsuspRR(Cdimg *cd, int what, int dowrite)
          367 {
          368         assert(cd != nil);
          369 
          370         if(dowrite) {
          371                 Cputc(cd, 'R');           /* RR field marker */
          372                 Cputc(cd, 'R');
          373                 Cputc(cd, 5);             /* Length          */
          374                 Cputc(cd, 1);                  /* Version number  */
          375                 Cputc(cd, what);          /* Flags           */
          376         }
          377         return 5;
          378 }
          379 
          380 static int
          381 CputsuspSP(Cdimg *cd, int dowrite)
          382 {
          383         assert(cd!=0);
          384 
          385         if(dowrite) {
          386 chat("writing SUSP SP record\n");
          387                 Cputc(cd, 'S');           /* SP field marker */
          388                 Cputc(cd, 'P');
          389                 Cputc(cd, 7);             /* Length          */
          390                 Cputc(cd, 1);             /* Version         */
          391                 Cputc(cd, 0xBE);          /* Magic           */
          392                 Cputc(cd, 0xEF);
          393                 Cputc(cd, 0);
          394         }
          395 
          396         return 7;
          397 }
          398 
          399 #ifdef NOTUSED
          400 static int
          401 CputsuspST(Cdimg *cd, int dowrite)
          402 {
          403         assert(cd!=0);
          404 
          405         if(dowrite) {
          406                 Cputc(cd, 'S');           /* ST field marker */
          407                 Cputc(cd, 'T');
          408                 Cputc(cd, 4);             /* Length          */
          409                 Cputc(cd, 1);             /* Version         */
          410         }
          411         return 4;
          412 }
          413 #endif
          414 
          415 static ulong
          416 suspdirflags(Direc *d, int dot)
          417 {
          418         uchar flags;
          419 
          420         USED(d);
          421         flags = 0;
          422         switch(dot) {
          423         default:
          424                 assert(0);
          425         case DTdot:
          426         case DTrootdot:
          427                 flags |= NMcurrent;
          428                 break;
          429         case DTdotdot:
          430                 flags |= NMparent;
          431                 break;
          432         case DTroot:
          433                 flags |= NMvolroot;
          434                 break;
          435         case DTiden:
          436                 break;
          437         }
          438         return flags;
          439 }
          440 
          441 static int
          442 Cputrripname(Cdimg *cd, char *nm, int flags, char *name, int dowrite)
          443 {
          444         int l;
          445 
          446         l = strlen(name);
          447         if(dowrite) {
          448                 Cputc(cd, nm[0]);                   /* NM field marker */
          449                 Cputc(cd, nm[1]);
          450                 Cputc(cd, l+5);        /* Length          */
          451                 Cputc(cd, 1);                     /* Version         */
          452                 Cputc(cd, flags);                 /* Flags           */
          453                 Cputs(cd, name, l);    /* Alternate name  */
          454         }
          455         return 5+l;
          456 }
          457 
          458 static int
          459 CputrripSL(Cdimg *cd, int contin, int flags, char *name, int dowrite)
          460 {
          461         int l;
          462 
          463         l = strlen(name);
          464         if(dowrite) {
          465                 Cputc(cd, 'S');
          466                 Cputc(cd, 'L');
          467                 Cputc(cd, l+7);
          468                 Cputc(cd, 1);
          469                 Cputc(cd, contin ? 1 : 0);
          470                 Cputc(cd, flags);
          471                 Cputc(cd, l);
          472                 Cputs(cd, name, l);
          473         }
          474         return 7+l;
          475 }
          476 
          477 static int
          478 CputrripPX(Cdimg *cd, Direc *d, int dot, int dowrite)
          479 {
          480         assert(cd!=0);
          481 
          482         if(dowrite) {
          483                 Cputc(cd, 'P');             /* PX field marker */
          484                 Cputc(cd, 'X');
          485                 Cputc(cd, 36);              /* Length          */
          486                 Cputc(cd, 1);               /* Version         */
          487 
          488                 Cputn(cd, mode(d, dot), 4); /* POSIX File mode */
          489                 Cputn(cd, nlink(d), 4);     /* POSIX st_nlink  */
          490                 Cputn(cd, d?d->uidno:0, 4);  /* POSIX st_uid    */
          491                 Cputn(cd, d?d->gidno:0, 4);  /* POSIX st_gid    */
          492         }
          493 
          494         return 36;
          495 }
          496 
          497 static int
          498 CputrripTF(Cdimg *cd, Direc *d, int type, int dowrite)
          499 {
          500         int i, length;
          501 
          502         assert(cd!=0);
          503         assert(!(type & TFlongform));
          504 
          505         length = 0;
          506         for(i=0; i<7; i++)
          507                 if (type & (1<<i))
          508                         length++;
          509         assert(length == 4);
          510 
          511         if(dowrite) {
          512                 Cputc(cd, 'T');                                /* TF field marker */
          513                 Cputc(cd, 'F');
          514                 Cputc(cd, 5+7*length);                /* Length                 */
          515                 Cputc(cd, 1);                                /* Version                 */
          516                 Cputc(cd, type);                                        /* Flags (types)         */
          517 
          518                 if (type & TFcreation)
          519                         Cputdate(cd, d?d->ctime:0);
          520                 if (type & TFmodify)
          521                         Cputdate(cd, d?d->mtime:0);
          522                 if (type & TFaccess)
          523                         Cputdate(cd, d?d->atime:0);
          524                 if (type & TFattributes)
          525                         Cputdate(cd, d?d->ctime:0);
          526 
          527         /*        if (type & TFbackup) */
          528         /*                Cputdate(cd, 0); */
          529         /*        if (type & TFexpiration) */
          530         /*                Cputdate(cd, 0); */
          531         /*        if (type & TFeffective) */
          532         /*                Cputdate(cd, 0); */
          533         }
          534         return 5+7*length;
          535 }
          536 
          537 
          538 #define NONPXMODES  (DMDIR & DMAPPEND & DMEXCL & DMMOUNT)
          539 #define POSIXMODEMASK (0177777)
          540 #ifndef S_IFMT
          541 #define S_IFMT  (0170000)
          542 #endif
          543 #ifndef S_IFDIR
          544 #define S_IFDIR (0040000)
          545 #endif
          546 #ifndef S_IFREG
          547 #define S_IFREG (0100000)
          548 #endif
          549 #ifndef S_IFLNK
          550 #define S_IFLNK (0120000)
          551 #endif
          552 #undef  ISTYPE
          553 #define ISTYPE(mode, mask)  (((mode) & S_IFMT) == (mask))
          554 #ifndef S_ISDIR
          555 #define S_ISDIR(mode) ISTYPE(mode, S_IFDIR)
          556 #endif
          557 #ifndef S_ISREG
          558 #define S_ISREG(mode) ISTYPE(mode, S_IREG)
          559 #endif
          560 #ifndef S_ISLNK
          561 #define S_ISLNK(mode) ISTYPE(mode, S_ILNK)
          562 #endif
          563 
          564 
          565 static long
          566 mode(Direc *d, int dot)
          567 {
          568         long mode;
          569 
          570         if (!d)
          571                 return 0;
          572 
          573         if ((dot != DTroot) && (dot != DTrootdot)) {
          574                 mode = (d->mode & ~(NONPXMODES));
          575                 if (d->mode & DMDIR)
          576                         mode |= S_IFDIR;
          577                 else if (d->mode & CHLINK)
          578                         mode |= S_IFLNK;
          579                 else
          580                         mode |= S_IFREG;
          581         } else
          582                 mode = S_IFDIR | (0755);
          583 
          584         mode &= POSIXMODEMASK;
          585 
          586         /* Botch: not all POSIX types supported yet */
          587         assert(mode & (S_IFDIR|S_IFREG));
          588 
          589 chat("writing PX record mode field %ulo with dot %d and name \"%s\"\n", mode, dot, d->name);
          590 
          591         return mode;
          592 }
          593 
          594 static long
          595 nlink(Direc *d)   /* Trump up the nlink field for POSIX compliance */
          596 {
          597         int i;
          598         long n;
          599 
          600         if (!d)
          601                 return 0;
          602 
          603         n = 1;
          604         if (d->mode & DMDIR)   /* One for "." and one more for ".." */
          605                 n++;
          606 
          607         for(i=0; i<d->nchild; i++)
          608                 if (d->child[i].mode & DMDIR)
          609                         n++;
          610 
          611         return n;
          612 }