void Cupdatebootcat(Cdimg *cd) { ulong o; if(cd->bootdirec == nil) return; o = Cwoffset(cd); Cwseek(cd, cd->bootimageptr); Cputc(cd, 0x88); switch(cd->bootdirec->length){ default: fprint(2, "warning: boot image is not 1.44MB or 2.88MB; pretending 1.44MB\n"); case 1440*1024: Cputc(cd, 0x02); /* 1.44MB disk */ break; case 2880*1024: Cputc(cd, 0x03); /* 2.88MB disk */ break; } Cputnl(cd, 0, 2); /* load segment */ Cputc(cd, 0); /* system type */ Cputc(cd, 0); /* unused */ Cputnl(cd, 1, 2); /* 512-byte sector count for load */ Cputnl(cd, cd->bootdirec->block, 4); /* ptr to disk image */ Cwseek(cd, o); }
void Cputnm(Cdimg *cd, uvlong val, int size) { switch(size) { default: sysfatal("bad size %d in Cputnm", size); case 2: if(val >= (1<<16)) sysfatal("value %llud too big for size %d in Cputnl", val, size); Cputc(cd, val>>8); Cputc(cd, val); break; case 4: if(val >= (1ULL<<32)) sysfatal("value %llud too big for size %d in Cputnl", val, size); Cputc(cd, val>>24); Cputc(cd, val>>16); Cputc(cd, val>>8); Cputc(cd, val); break; case 8: Cputc(cd, val>>56); Cputc(cd, val>>48); Cputc(cd, val>>40); Cputc(cd, val>>32); Cputc(cd, val>>24); Cputc(cd, val>>16); Cputc(cd, val>>8); Cputc(cd, val); break; } }
void Cputisopvd(Cdimg *cd, Cdinfo info) { char buf[130]; Cputc(cd, 1); /* primary volume descriptor */ Cputs(cd, "CD001", 5); /* standard identifier */ Cputc(cd, 1); /* volume descriptor version */ Cputc(cd, 0); /* unused */ assert(~info.flags & (CDplan9|CDrockridge)); /* system identifier */ strcpy(buf, ""); if(info.flags & CDplan9) strcat(buf, "plan 9 "); if(info.flags & CDrockridge) strcat(buf, "rrip "); if(info.flags & CDbootable) strcat(buf, "boot "); if(info.flags & CDconform) strcat(buf, "iso9660"); else strcat(buf, "utf8"); struprcpy(buf, buf); Cputs(cd, buf, 32); Cputs(cd, mkisostring(buf, 32, info.volumename), 32); /* volume identifier */ Crepeat(cd, 0, 8); /* unused */ Cputn(cd, 0, 4); /* volume space size */ Crepeat(cd, 0, 32); /* unused */ Cputn(cd, 1, 2); /* volume set size */ Cputn(cd, 1, 2); /* volume sequence number */ Cputn(cd, Blocksize, 2); /* logical block size */ Cputn(cd, 0, 4); /* path table size */ Cputnl(cd, 0, 4); /* location of Lpath */ Cputnl(cd, 0, 4); /* location of optional Lpath */ Cputnm(cd, 0, 4); /* location of Mpath */ Cputnm(cd, 0, 4); /* location of optional Mpath */ Cputisodir(cd, nil, DTroot, 1, Cwoffset(cd)); /* root directory */ Cputs(cd, mkisostring(buf, 128, info.volumeset), 128); /* volume set identifier */ Cputs(cd, mkisostring(buf, 128, info.publisher), 128); /* publisher identifier */ Cputs(cd, mkisostring(buf, 128, info.preparer), 128); /* data preparer identifier */ Cputs(cd, mkisostring(buf, 128, info.application), 128); /* application identifier */ Cputs(cd, "", 37); /* copyright notice */ Cputs(cd, "", 37); /* abstract */ Cputs(cd, "", 37); /* bibliographic file */ Cputdate1(cd, now); /* volume creation date */ Cputdate1(cd, now); /* volume modification date */ Cputdate1(cd, 0); /* volume expiration date */ Cputdate1(cd, 0); /* volume effective date */ Cputc(cd, 1); /* file structure version */ Cpadblock(cd); }
void Cputbootvol(Cdimg *cd) { Cputc(cd, 0x00); Cputs(cd, "CD001", 5); Cputc(cd, 0x01); Cputs(cd, "EL TORITO SPECIFICATION", 2+1+6+1+13); Crepeat(cd, 0, 2+16+16+7); cd->bootcatptr = Cwoffset(cd); Cpadblock(cd); }
static int CputsuspST(Cdimg *cd, int dowrite) { assert(cd!=0); if(dowrite) { Cputc(cd, 'S'); /* ST field marker */ Cputc(cd, 'T'); Cputc(cd, 4); /* Length */ Cputc(cd, 1); /* Version */ } return 4; }
static int CputsuspRR(Cdimg *cd, int what, int dowrite) { assert(cd != nil); if(dowrite) { Cputc(cd, 'R'); /* RR field marker */ Cputc(cd, 'R'); Cputc(cd, 5); /* Length */ Cputc(cd, 1); /* Version number */ Cputc(cd, what); /* Flags */ } return 5; }
static int Cputrripname(Cdimg *cd, char *nm, int flags, char *name, int dowrite) { int l; l = strlen(name); if(dowrite) { Cputc(cd, nm[0]); /* NM field marker */ Cputc(cd, nm[1]); Cputc(cd, l+5); /* Length */ Cputc(cd, 1); /* Version */ Cputc(cd, flags); /* Flags */ Cputs(cd, name, l); /* Alternate name */ } return 5+l; }
void Cputnm(Cdimg *cd, ulong val, int size) { switch(size) { default: sysfatal("bad size %d in bputnl", size); case 2: Cputc(cd, val>>8); Cputc(cd, val); break; case 4: Cputc(cd, val>>24); Cputc(cd, val>>16); Cputc(cd, val>>8); Cputc(cd, val); break; } }
static int CputrripPX(Cdimg *cd, Direc *d, int dot, int dowrite) { assert(cd!=0); if(dowrite) { Cputc(cd, 'P'); /* PX field marker */ Cputc(cd, 'X'); Cputc(cd, 36); /* Length */ Cputc(cd, 1); /* Version */ Cputn(cd, mode(d, dot), 4); /* POSIX File mode */ Cputn(cd, nlink(d), 4); /* POSIX st_nlink */ Cputn(cd, d?d->uidno:0, 4); /* POSIX st_uid */ Cputn(cd, d?d->gidno:0, 4); /* POSIX st_gid */ } return 36; }
static ulong CputsuspCE(Cdimg *cd, vlong offset) { vlong o, x; chat("writing SUSP CE record pointing to %ld, %ld\n", offset/Blocksize, offset%Blocksize); o = Cwoffset(cd); Cputc(cd, 'C'); Cputc(cd, 'E'); Cputc(cd, 28); Cputc(cd, 1); Cputn(cd, offset/Blocksize, 4); Cputn(cd, offset%Blocksize, 4); x = Cwoffset(cd); Cputn(cd, 0, 4); assert(Cwoffset(cd) == o+28); return x; }
static int CputrripTF(Cdimg *cd, Direc *d, int type, int dowrite) { int i, length; assert(cd!=0); assert(!(type & TFlongform)); length = 0; for(i=0; i<7; i++) if (type & (1<<i)) length++; assert(length == 4); if(dowrite) { Cputc(cd, 'T'); /* TF field marker */ Cputc(cd, 'F'); Cputc(cd, 5+7*length); /* Length */ Cputc(cd, 1); /* Version */ Cputc(cd, type); /* Flags (types) */ if (type & TFcreation) Cputdate(cd, d?d->ctime:0); if (type & TFmodify) Cputdate(cd, d?d->mtime:0); if (type & TFaccess) Cputdate(cd, d?d->atime:0); if (type & TFattributes) Cputdate(cd, d?d->ctime:0); // if (type & TFbackup) // Cputdate(cd, 0); // if (type & TFexpiration) // Cputdate(cd, 0); // if (type & TFeffective) // Cputdate(cd, 0); } return 5+7*length; }
void Cputs(Cdimg *cd, char *s, int size) { int n; if(s == nil) { Crepeat(cd, ' ', size); return; } for(n=0; n<size && *s; n++) Cputc(cd, *s++); if(n<size) Crepeat(cd, ' ', size-n); }
static int CputsuspER(Cdimg *cd, int dowrite) { assert(cd != nil); if(dowrite) { chat("writing SUSP ER record\n"); Cputc(cd, 'E'); /* ER field marker */ Cputc(cd, 'R'); Cputc(cd, 26); /* Length */ Cputc(cd, 1); /* Version */ Cputc(cd, 10); /* LEN_ID */ Cputc(cd, 4); /* LEN_DESC */ Cputc(cd, 4); /* LEN_SRC */ Cputc(cd, 1); /* EXT_VER */ Cputs(cd, SUSPrrip, 10); /* EXT_ID */ Cputs(cd, SUSPdesc, 4); /* EXT_DESC */ Cputs(cd, SUSPsrc, 4); /* EXT_SRC */ } return 8+10+4+4; }
static int CputrripSL(Cdimg *cd, int contin, int flags, char *name, int dowrite) { int l; l = strlen(name); if(dowrite) { Cputc(cd, 'S'); Cputc(cd, 'L'); Cputc(cd, l+7); Cputc(cd, 1); Cputc(cd, contin ? 1 : 0); Cputc(cd, flags); Cputc(cd, l); Cputs(cd, name, l); } return 7+l; }
static int CputsuspSP(Cdimg *cd, int dowrite) { assert(cd!=0); if(dowrite) { chat("writing SUSP SP record\n"); Cputc(cd, 'S'); /* SP field marker */ Cputc(cd, 'P'); Cputc(cd, 7); /* Length */ Cputc(cd, 1); /* Version */ Cputc(cd, 0xBE); /* Magic */ Cputc(cd, 0xEF); Cputc(cd, 0); } return 7; }
void Cputbootcat(Cdimg *cd) { cd->bootcatblock = Cwoffset(cd) / Blocksize; Cputc(cd, 0x01); Cputc(cd, 0x00); Cputc(cd, 0x00); Cputc(cd, 0x00); Crepeat(cd, 0, 12+12); /* * either the checksum doesn't include the header word * or it just doesn't matter. */ Cputc(cd, 0xAA); Cputc(cd, 0x55); Cputc(cd, 0x55); Cputc(cd, 0xAA); cd->bootimageptr = Cwoffset(cd); Cpadblock(cd); }
/* * Write a Joliet secondary volume descriptor. */ void Cputjolietsvd(Cdimg *cd, Cdinfo info) { Cputc(cd, 2); /* secondary volume descriptor */ Cputs(cd, "CD001", 5); /* standard identifier */ Cputc(cd, 1); /* volume descriptor version */ Cputc(cd, 0); /* unused */ Cputrscvt(cd, "Joliet Plan 9", 32); /* system identifier */ Cputrscvt(cd, info.volumename, 32); /* volume identifier */ Crepeat(cd, 0, 8); /* unused */ Cputn(cd, 0, 4); /* volume space size */ Cputc(cd, 0x25); /* escape sequences: UCS-2 Level 2 */ Cputc(cd, 0x2F); Cputc(cd, 0x43); Crepeat(cd, 0, 29); Cputn(cd, 1, 2); /* volume set size */ Cputn(cd, 1, 2); /* volume sequence number */ Cputn(cd, Blocksize, 2); /* logical block size */ Cputn(cd, 0, 4); /* path table size */ Cputnl(cd, 0, 4); /* location of Lpath */ Cputnl(cd, 0, 4); /* location of optional Lpath */ Cputnm(cd, 0, 4); /* location of Mpath */ Cputnm(cd, 0, 4); /* location of optional Mpath */ Cputjolietdir(cd, nil, DTroot, 1, Cwoffset(cd)); /* root directory */ Cputrscvt(cd, info.volumeset, 128); /* volume set identifier */ Cputrscvt(cd, info.publisher, 128); /* publisher identifier */ Cputrscvt(cd, info.preparer, 128); /* data preparer identifier */ Cputrscvt(cd, info.application, 128); /* application identifier */ Cputrscvt(cd, "", 37); /* copyright notice */ Cputrscvt(cd, "", 37); /* abstract */ Cputrscvt(cd, "", 37); /* bibliographic file */ Cputdate1(cd, now); /* volume creation date */ Cputdate1(cd, now); /* volume modification date */ Cputdate1(cd, 0); /* volume expiration date */ Cputdate1(cd, 0); /* volume effective date */ Cputc(cd, 1); /* file structure version */ Cpadblock(cd); }
/* * ASCII/UTF string writing */ void Crepeat(Cdimg *cd, int c, int n) { while(n-- > 0) Cputc(cd, c); }
/* * Write a Rock Ridge SUSP set of records for a directory entry. */ int Cputsysuse(Cdimg *cd, Direc *d, int dot, int dowrite, int initlen) { char buf[256], buf0[256], *nextpath, *p, *path, *q; int flags, free, m, what; uvlong o; Cbuf cn, co, *cp; assert(cd != nil); assert((initlen&1) == 0); if(dot == DTroot) return 0; co.len = initlen; o = Cwoffset(cd); assert(dowrite==0 || Cwoffset(cd) == o+co.len-initlen); cp = &co; if (dot == DTrootdot) { m = CputsuspSP(cd, 0); cp = ensurespace(cd, m, cp, &cn, dowrite); CputsuspSP(cd, dowrite); m = CputsuspER(cd, 0); cp = ensurespace(cd, m, cp, &cn, dowrite); CputsuspER(cd, dowrite); } /* * In a perfect world, we'd be able to omit the NM * entries when our name was all lowercase and conformant, * but OpenBSD insists on uppercasing (really, not lowercasing) * the ISO9660 names. */ what = RR_PX | RR_TF | RR_NM; if(d != nil && (d->mode & CHLINK)) what |= RR_SL; m = CputsuspRR(cd, what, 0); cp = ensurespace(cd, m, cp, &cn, dowrite); CputsuspRR(cd, what, dowrite); if(what & RR_PX) { m = CputrripPX(cd, d, dot, 0); cp = ensurespace(cd, m, cp, &cn, dowrite); CputrripPX(cd, d, dot, dowrite); } if(what & RR_NM) { if(dot == DTiden) p = d->name; else if(dot == DTdotdot) p = ".."; else p = "."; flags = suspdirflags(d, dot); assert(dowrite==0 || cp != &co || Cwoffset(cd) == o+co.len-initlen); cp = Cputstring(cd, cp, &cn, "NM", p, flags, dowrite); } /* * Put down the symbolic link. This is even more of a crock. * Not only are the individual elements potentially split, * but the whole path itself can be split across SL blocks. * To keep the code simple as possible (really), we write * only one element per SL block, wasting 6 bytes per element. */ if(what & RR_SL) { for(path=d->symlink; path[0] != '\0'; path=nextpath) { /* break off one component */ if((nextpath = strchr(path, '/')) == nil) nextpath = path+strlen(path); strncpy(buf0, path, nextpath-path); buf0[nextpath-path] = '\0'; if(nextpath[0] == '/') nextpath++; p = buf0; /* write the name, perhaps broken into pieces */ if(strcmp(p, "") == 0) flags = NMroot; else if(strcmp(p, ".") == 0) flags = NMcurrent; else if(strcmp(p, "..") == 0) flags = NMparent; else flags = 0; /* the do-while handles the empty string properly */ do { /* must have room for at least 1 byte of name */ cp = ensurespace(cd, 7+1, cp, &cn, dowrite); cp->len -= 7+1; free = freespace(cp); assert(7+1 <= free && free < 256); strncpy(buf, p, free-7); buf[free-7] = '\0'; q = p+strlen(buf); p = buf; /* nil: better not need to expand */ assert(7+strlen(p) <= free); ensurespace(cd, 7+strlen(p), cp, nil, dowrite); CputrripSL(cd, nextpath[0], flags | (q[0] ? NMcontinue : 0), p, dowrite); p = q; } while(p[0] != '\0'); } } assert(dowrite==0 || cp != &co || Cwoffset(cd) == o+co.len-initlen); if(what & RR_TF) { m = CputrripTF(cd, d, TFcreation|TFmodify|TFaccess|TFattributes, 0); cp = ensurespace(cd, m, cp, &cn, dowrite); CputrripTF(cd, d, TFcreation|TFmodify|TFaccess|TFattributes, dowrite); } assert(dowrite==0 || cp != &co || Cwoffset(cd) == o+co.len-initlen); if(cp == &cn && dowrite) { /* seek out of continuation, but mark our place */ cd->rrcontin = Cwoffset(cd); setcelen(cd, cn.ceoffset, cn.len); Cwseek(cd, o+co.len-initlen); } if(co.len & 1) { co.len++; if(dowrite) Cputc(cd, 0); } if(dowrite) { if(Cwoffset(cd) != o+co.len-initlen) fprint(2, "offset %llud o+co.len-initlen %llud\n", Cwoffset(cd), o+co.len-initlen); assert(Cwoffset(cd) == o+co.len-initlen); } else assert(Cwoffset(cd) == o); assert(co.len <= 255); return co.len - initlen; }