sysuse.c 14 KB

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