sysuse.c 14 KB

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