9660srv.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <fcall.h>
  5. #include "dat.h"
  6. #include "fns.h"
  7. #include "iso9660.h"
  8. static void ireset(void);
  9. static int iattach(Xfile*);
  10. static void iclone(Xfile*, Xfile*);
  11. static void iwalkup(Xfile*);
  12. static void iwalk(Xfile*, char*);
  13. static void iopen(Xfile*, int);
  14. static void icreate(Xfile*, char*, long, int);
  15. static long ireaddir(Xfile*, uchar*, long, long);
  16. static long iread(Xfile*, char*, vlong, long);
  17. static long iwrite(Xfile*, char*, vlong, long);
  18. static void iclunk(Xfile*);
  19. static void iremove(Xfile*);
  20. static void istat(Xfile*, Dir*);
  21. static void iwstat(Xfile*, Dir*);
  22. static char* nstr(uchar*, int);
  23. static char* rdate(uchar*, int);
  24. static int getcontin(Xdata*, uchar*, uchar**);
  25. static int getdrec(Xfile*, void*);
  26. static void ungetdrec(Xfile*);
  27. static int opendotdot(Xfile*, Xfile*);
  28. static int showdrec(int, int, void*);
  29. static long gtime(uchar*);
  30. static long l16(void*);
  31. static long l32(void*);
  32. static void newdrec(Xfile*, Drec*);
  33. static int rzdir(Xfs*, Dir*, int, Drec*);
  34. Xfsub isosub =
  35. {
  36. ireset, iattach, iclone, iwalkup, iwalk, iopen, icreate,
  37. ireaddir, iread, iwrite, iclunk, iremove, istat, iwstat
  38. };
  39. static void
  40. ireset(void)
  41. {}
  42. static int
  43. iattach(Xfile *root)
  44. {
  45. Xfs *cd = root->xf;
  46. Iobuf *p; Voldesc *v; Isofile *fp; Drec *dp;
  47. int fmt, blksize, i, n, l, haveplan9;
  48. Iobuf *dirp;
  49. uchar dbuf[256];
  50. Drec *rd = (Drec *)dbuf;
  51. uchar *q, *s;
  52. dirp = nil;
  53. blksize = 0;
  54. fmt = 0;
  55. dp = nil;
  56. haveplan9 = 0;
  57. for(i=VOLDESC;i<VOLDESC+100; i++){ /* +100 for sanity */
  58. p = getbuf(cd->d, i);
  59. v = (Voldesc*)(p->iobuf);
  60. if(memcmp(v->byte, "\01CD001\01", 7) == 0){ /* iso */
  61. if(dirp)
  62. putbuf(dirp);
  63. dirp = p;
  64. fmt = 'z';
  65. dp = (Drec*)v->z.desc.rootdir;
  66. blksize = l16(v->z.desc.blksize);
  67. chat("iso, blksize=%d...", blksize);
  68. v = (Voldesc*)(dirp->iobuf);
  69. haveplan9 = (strncmp((char*)v->z.boot.sysid, "PLAN 9", 6)==0);
  70. if(haveplan9){
  71. if(noplan9) {
  72. chat("ignoring plan9");
  73. haveplan9 = 0;
  74. } else {
  75. fmt = '9';
  76. chat("plan9 iso...");
  77. }
  78. }
  79. continue;
  80. }
  81. if(memcmp(&v->byte[8], "\01CDROM\01", 7) == 0){ /* high sierra */
  82. if(dirp)
  83. putbuf(dirp);
  84. dirp = p;
  85. fmt = 'r';
  86. dp = (Drec*)v->r.desc.rootdir;
  87. blksize = l16(v->r.desc.blksize);
  88. chat("high sierra, blksize=%d...", blksize);
  89. continue;
  90. }
  91. if(haveplan9==0 && !nojoliet
  92. && memcmp(v->byte, "\02CD001\01", 7) == 0){
  93. chat("%d %d\n", haveplan9, nojoliet);
  94. /*
  95. * The right thing to do is walk the escape sequences looking
  96. * for one of 25 2F 4[035], but Microsoft seems to not honor
  97. * the format, which makes it hard to walk over.
  98. */
  99. q = v->z.desc.escapes;
  100. if(q[0] == 0x25 && q[1] == 0x2F && (q[2] == 0x40 || q[2] == 0x43 || q[2] == 0x45)){ /* Joliet, it appears */
  101. if(dirp)
  102. putbuf(dirp);
  103. dirp = p;
  104. fmt = 'J';
  105. dp = (Drec*)v->z.desc.rootdir;
  106. if(blksize != l16(v->z.desc.blksize))
  107. fprint(2, "warning: suspicious Joliet blocksize\n");
  108. chat("joliet...");
  109. continue;
  110. }
  111. }
  112. putbuf(p);
  113. if(v->byte[0] == 0xFF)
  114. break;
  115. }
  116. if(fmt == 0){
  117. if(dirp)
  118. putbuf(dirp);
  119. return -1;
  120. }
  121. assert(dirp != nil);
  122. if(chatty)
  123. showdrec(2, fmt, dp);
  124. if(blksize > Sectorsize){
  125. chat("blksize too big...");
  126. putbuf(dirp);
  127. return -1;
  128. }
  129. if(waserror()){
  130. putbuf(dirp);
  131. nexterror();
  132. }
  133. root->len = sizeof(Isofile) - sizeof(Drec) + dp->reclen;
  134. root->ptr = fp = ealloc(root->len);
  135. if(haveplan9)
  136. root->xf->isplan9 = 1;
  137. fp->fmt = fmt;
  138. fp->blksize = blksize;
  139. fp->offset = 0;
  140. fp->doffset = 0;
  141. memmove(&fp->d, dp, dp->reclen);
  142. root->qid.path = l32(dp->addr);
  143. root->qid.type = QTDIR;
  144. putbuf(dirp);
  145. poperror();
  146. if(getdrec(root, rd) >= 0){
  147. n = rd->reclen-(34+rd->namelen);
  148. s = (uchar*)rd->name + rd->namelen;
  149. if((uintptr)s & 1){
  150. s++;
  151. n--;
  152. }
  153. if(n >= 7 && s[0] == 'S' && s[1] == 'P' && s[2] == 7 &&
  154. s[3] == 1 && s[4] == 0xBE && s[5] == 0xEF){
  155. root->xf->issusp = 1;
  156. root->xf->suspoff = s[6];
  157. n -= root->xf->suspoff;
  158. s += root->xf->suspoff;
  159. for(; n >= 4; s += l, n -= l){
  160. l = s[2];
  161. if(s[0] == 'E' && s[1] == 'R'){
  162. if(!norock && s[4] == 10 && memcmp(s+8, "RRIP_1991A", 10) == 0)
  163. root->xf->isrock = 1;
  164. break;
  165. } else if(s[0] == 'C' && s[1] == 'E' && s[2] >= 28){
  166. n = getcontin(root->xf->d, s, &s);
  167. continue;
  168. } else if(s[0] == 'R' && s[1] == 'R'){
  169. if(!norock)
  170. root->xf->isrock = 1;
  171. break;
  172. } else if(s[0] == 'S' && s[1] == 'T')
  173. break;
  174. }
  175. }
  176. }
  177. if(root->xf->isrock)
  178. chat("Rock Ridge...");
  179. fp->offset = 0;
  180. fp->doffset = 0;
  181. return 0;
  182. }
  183. static void
  184. iclone(Xfile *of, Xfile *nf)
  185. {
  186. USED(of, nf);
  187. }
  188. static void
  189. iwalkup(Xfile *f)
  190. {
  191. long paddr;
  192. uchar dbuf[256];
  193. Drec *d = (Drec *)dbuf;
  194. Xfile pf, ppf;
  195. Isofile piso, ppiso;
  196. memset(&pf, 0, sizeof pf);
  197. memset(&ppf, 0, sizeof ppf);
  198. pf.ptr = &piso;
  199. ppf.ptr = &ppiso;
  200. if(opendotdot(f, &pf) < 0)
  201. error("can't open pf");
  202. paddr = l32(pf.ptr->d.addr);
  203. if(l32(f->ptr->d.addr) == paddr)
  204. return;
  205. if(opendotdot(&pf, &ppf) < 0)
  206. error("can't open ppf");
  207. while(getdrec(&ppf, d) >= 0){
  208. if(l32(d->addr) == paddr){
  209. newdrec(f, d);
  210. f->qid.path = paddr;
  211. f->qid.type = QTDIR;
  212. return;
  213. }
  214. }
  215. error("can't find addr of ..");
  216. }
  217. static int
  218. casestrcmp(int isplan9, char *a, char *b)
  219. {
  220. int ca, cb;
  221. if(isplan9)
  222. return strcmp(a, b);
  223. for(;;) {
  224. ca = *a++;
  225. cb = *b++;
  226. if(ca >= 'A' && ca <= 'Z')
  227. ca += 'a' - 'A';
  228. if(cb >= 'A' && cb <= 'Z')
  229. cb += 'a' - 'A';
  230. if(ca != cb) {
  231. if(ca > cb)
  232. return 1;
  233. return -1;
  234. }
  235. if(ca == 0)
  236. return 0;
  237. }
  238. }
  239. static void
  240. iwalk(Xfile *f, char *name)
  241. {
  242. Isofile *ip = f->ptr;
  243. uchar dbuf[256];
  244. char nbuf[4*Maxname];
  245. Drec *d = (Drec*)dbuf;
  246. Dir dir;
  247. char *p;
  248. int len, vers, dvers;
  249. vers = -1;
  250. if(p = strchr(name, ';')) { /* assign = */
  251. len = p-name;
  252. if(len >= Maxname)
  253. len = Maxname-1;
  254. memmove(nbuf, name, len);
  255. vers = strtoul(p+1, 0, 10);
  256. name = nbuf;
  257. }
  258. /*
  259. len = strlen(name);
  260. if(len >= Maxname){
  261. len = Maxname-1;
  262. if(name != nbuf){
  263. memmove(nbuf, name, len);
  264. name = nbuf;
  265. }
  266. name[len] = 0;
  267. }
  268. */
  269. chat("%d \"%s\"...", strlen(name), name);
  270. ip->offset = 0;
  271. setnames(&dir, nbuf);
  272. while(getdrec(f, d) >= 0) {
  273. dvers = rzdir(f->xf, &dir, ip->fmt, d);
  274. if(casestrcmp(f->xf->isplan9||f->xf->isrock, name, dir.name) != 0)
  275. continue;
  276. newdrec(f, d);
  277. f->qid.path = dir.qid.path;
  278. f->qid.type = dir.qid.type;
  279. USED(dvers);
  280. return;
  281. }
  282. USED(vers);
  283. error(Enonexist);
  284. }
  285. static void
  286. iopen(Xfile *f, int mode)
  287. {
  288. mode &= ~OCEXEC;
  289. if(mode != OREAD && mode != OEXEC)
  290. error(Eperm);
  291. f->ptr->offset = 0;
  292. f->ptr->doffset = 0;
  293. }
  294. static void
  295. icreate(Xfile *f, char *name, long perm, int mode)
  296. {
  297. USED(f, name, perm, mode);
  298. error(Eperm);
  299. }
  300. static long
  301. ireaddir(Xfile *f, uchar *buf, long offset, long count)
  302. {
  303. Isofile *ip = f->ptr;
  304. Dir d;
  305. char names[4*Maxname];
  306. uchar dbuf[256];
  307. Drec *drec = (Drec *)dbuf;
  308. int n, rcnt;
  309. if(offset==0){
  310. ip->offset = 0;
  311. ip->doffset = 0;
  312. }else if(offset != ip->doffset)
  313. error("seek in directory not allowed");
  314. rcnt = 0;
  315. setnames(&d, names);
  316. while(rcnt < count && getdrec(f, drec) >= 0){
  317. if(drec->namelen == 1){
  318. if(drec->name[0] == 0)
  319. continue;
  320. if(drec->name[0] == 1)
  321. continue;
  322. }
  323. rzdir(f->xf, &d, ip->fmt, drec);
  324. d.qid.vers = f->qid.vers;
  325. if((n = convD2M(&d, buf+rcnt, count-rcnt)) <= BIT16SZ){
  326. ungetdrec(f);
  327. break;
  328. }
  329. rcnt += n;
  330. }
  331. ip->doffset += rcnt;
  332. return rcnt;
  333. }
  334. static long
  335. iread(Xfile *f, char *buf, vlong offset, long count)
  336. {
  337. int n, o, rcnt = 0;
  338. long size;
  339. vlong addr;
  340. Isofile *ip = f->ptr;
  341. Iobuf *p;
  342. size = l32(ip->d.size);
  343. if(offset >= size)
  344. return 0;
  345. if(offset+count > size)
  346. count = size - offset;
  347. addr = ((vlong)l32(ip->d.addr) + ip->d.attrlen)*ip->blksize + offset;
  348. o = addr % Sectorsize;
  349. addr /= Sectorsize;
  350. /*chat("d.addr=%ld, addr=%lld, o=%d...", l32(ip->d.addr), addr, o);*/
  351. n = Sectorsize - o;
  352. while(count > 0){
  353. if(n > count)
  354. n = count;
  355. p = getbuf(f->xf->d, addr);
  356. memmove(&buf[rcnt], &p->iobuf[o], n);
  357. putbuf(p);
  358. count -= n;
  359. rcnt += n;
  360. ++addr;
  361. o = 0;
  362. n = Sectorsize;
  363. }
  364. return rcnt;
  365. }
  366. static long
  367. iwrite(Xfile *f, char *buf, vlong offset, long count)
  368. {
  369. USED(f, buf, offset, count);
  370. error(Eperm);
  371. return 0;
  372. }
  373. static void
  374. iclunk(Xfile *f)
  375. {
  376. USED(f);
  377. }
  378. static void
  379. iremove(Xfile *f)
  380. {
  381. USED(f);
  382. error(Eperm);
  383. }
  384. static void
  385. istat(Xfile *f, Dir *d)
  386. {
  387. Isofile *ip = f->ptr;
  388. rzdir(f->xf, d, ip->fmt, &ip->d);
  389. d->qid.vers = f->qid.vers;
  390. if(d->qid.path==f->xf->rootqid.path){
  391. d->qid.path = 0;
  392. d->qid.type = QTDIR;
  393. }
  394. }
  395. static void
  396. iwstat(Xfile *f, Dir *d)
  397. {
  398. USED(f, d);
  399. error(Eperm);
  400. }
  401. static int
  402. showdrec(int fd, int fmt, void *x)
  403. {
  404. Drec *d = (Drec *)x;
  405. int namelen;
  406. int syslen;
  407. if(d->reclen == 0)
  408. return 0;
  409. fprint(fd, "%d %d %ld %ld ",
  410. d->reclen, d->attrlen, l32(d->addr), l32(d->size));
  411. fprint(fd, "%s 0x%2.2x %d %d %ld ",
  412. rdate(d->date, fmt), (fmt=='z' ? d->flags : d->r_flags),
  413. d->unitsize, d->gapsize, l16(d->vseqno));
  414. fprint(fd, "%d %s", d->namelen, nstr(d->name, d->namelen));
  415. if(fmt != 'J'){
  416. namelen = d->namelen + (1-(d->namelen&1));
  417. syslen = d->reclen - 33 - namelen;
  418. if(syslen != 0)
  419. fprint(fd, " %s", nstr(&d->name[namelen], syslen));
  420. }
  421. fprint(fd, "\n");
  422. return d->reclen + (d->reclen&1);
  423. }
  424. static void
  425. newdrec(Xfile *f, Drec *dp)
  426. {
  427. Isofile *x = f->ptr;
  428. Isofile *n;
  429. int len;
  430. len = sizeof(Isofile) - sizeof(Drec) + dp->reclen;
  431. n = ealloc(len);
  432. n->fmt = x->fmt;
  433. n->blksize = x->blksize;
  434. n->offset = 0;
  435. n->doffset = 0;
  436. memmove(&n->d, dp, dp->reclen);
  437. free(x);
  438. f->ptr = n;
  439. f->len = len;
  440. }
  441. static void
  442. ungetdrec(Xfile *f)
  443. {
  444. Isofile *ip = f->ptr;
  445. if(ip->offset >= ip->odelta){
  446. ip->offset -= ip->odelta;
  447. ip->odelta = 0;
  448. }
  449. }
  450. static int
  451. getdrec(Xfile *f, void *buf)
  452. {
  453. Isofile *ip = f->ptr;
  454. int len = 0, boff = 0;
  455. ulong size;
  456. vlong addr;
  457. Iobuf *p = 0;
  458. if(!ip)
  459. return -1;
  460. size = l32(ip->d.size);
  461. while(ip->offset < size){
  462. addr = (l32(ip->d.addr)+ip->d.attrlen)*ip->blksize + ip->offset;
  463. boff = addr % Sectorsize;
  464. if(boff > Sectorsize-34){
  465. ip->offset += Sectorsize-boff;
  466. continue;
  467. }
  468. p = getbuf(f->xf->d, addr/Sectorsize);
  469. len = p->iobuf[boff];
  470. if(len >= 34)
  471. break;
  472. putbuf(p);
  473. p = 0;
  474. ip->offset += Sectorsize-boff;
  475. }
  476. if(p) {
  477. memmove(buf, &p->iobuf[boff], len);
  478. putbuf(p);
  479. ip->odelta = len + (len&1);
  480. ip->offset += ip->odelta;
  481. return 0;
  482. }
  483. return -1;
  484. }
  485. static int
  486. opendotdot(Xfile *f, Xfile *pf)
  487. {
  488. uchar dbuf[256];
  489. Drec *d = (Drec *)dbuf;
  490. Isofile *ip = f->ptr, *pip = pf->ptr;
  491. ip->offset = 0;
  492. if(getdrec(f, d) < 0){
  493. chat("opendotdot: getdrec(.) failed...");
  494. return -1;
  495. }
  496. if(d->namelen != 1 || d->name[0] != 0){
  497. chat("opendotdot: no . entry...");
  498. return -1;
  499. }
  500. if(l32(d->addr) != l32(ip->d.addr)){
  501. chat("opendotdot: bad . address...");
  502. return -1;
  503. }
  504. if(getdrec(f, d) < 0){
  505. chat("opendotdot: getdrec(..) failed...");
  506. return -1;
  507. }
  508. if(d->namelen != 1 || d->name[0] != 1){
  509. chat("opendotdot: no .. entry...");
  510. return -1;
  511. }
  512. pf->xf = f->xf;
  513. pip->fmt = ip->fmt;
  514. pip->blksize = ip->blksize;
  515. pip->offset = 0;
  516. pip->doffset = 0;
  517. pip->d = *d;
  518. return 0;
  519. }
  520. enum {
  521. Hname = 1,
  522. Hmode = 2,
  523. };
  524. static int
  525. rzdir(Xfs *fs, Dir *d, int fmt, Drec *dp)
  526. {
  527. int n, flags, i, j, lj, nl, vers, sysl, mode, l, have;
  528. uchar *s;
  529. char *p;
  530. char buf[Maxname+UTFmax+1];
  531. uchar *q;
  532. Rune r;
  533. enum { ONAMELEN = 28 }; /* old Plan 9 directory name length */
  534. have = 0;
  535. flags = 0;
  536. vers = -1;
  537. d->qid.path = l32(dp->addr);
  538. d->qid.type = 0;
  539. d->qid.vers = 0;
  540. n = dp->namelen;
  541. memset(d->name, 0, Maxname);
  542. if(n == 1) {
  543. switch(dp->name[0]){
  544. case 1:
  545. d->name[1] = '.';
  546. /* fall through */
  547. case 0:
  548. d->name[0] = '.';
  549. have = Hname;
  550. break;
  551. default:
  552. d->name[0] = tolower(dp->name[0]);
  553. }
  554. } else {
  555. if(fmt == 'J'){ /* Joliet, 16-bit Unicode */
  556. q = (uchar*)dp->name;
  557. for(i=j=lj=0; i<n && j<Maxname; i+=2){
  558. lj = j;
  559. r = (q[i]<<8)|q[i+1];
  560. j += runetochar(buf+j, &r);
  561. }
  562. if(j >= Maxname)
  563. j = lj;
  564. memmove(d->name, buf, j);
  565. }else{
  566. if(n >= Maxname)
  567. n = Maxname-1;
  568. for(i=0; i<n; i++)
  569. d->name[i] = tolower(dp->name[i]);
  570. }
  571. }
  572. sysl = dp->reclen-(34+dp->namelen);
  573. s = (uchar*)dp->name + dp->namelen;
  574. if(((uintptr)s) & 1) {
  575. s++;
  576. sysl--;
  577. }
  578. if(fs->isplan9 && sysl > 0) {
  579. /*
  580. * get gid, uid, mode and possibly name
  581. * from plan9 directory extension
  582. */
  583. nl = *s;
  584. if(nl >= ONAMELEN)
  585. nl = ONAMELEN-1;
  586. if(nl) {
  587. memset(d->name, 0, ONAMELEN);
  588. memmove(d->name, s+1, nl);
  589. }
  590. s += 1 + *s;
  591. nl = *s;
  592. if(nl >= ONAMELEN)
  593. nl = ONAMELEN-1;
  594. memset(d->uid, 0, ONAMELEN);
  595. memmove(d->uid, s+1, nl);
  596. s += 1 + *s;
  597. nl = *s;
  598. if(nl >= ONAMELEN)
  599. nl = ONAMELEN-1;
  600. memset(d->gid, 0, ONAMELEN);
  601. memmove(d->gid, s+1, nl);
  602. s += 1 + *s;
  603. if(((uintptr)s) & 1)
  604. s++;
  605. d->mode = l32(s);
  606. if(d->mode & DMDIR)
  607. d->qid.type |= QTDIR;
  608. } else {
  609. d->mode = 0444;
  610. switch(fmt) {
  611. case 'z':
  612. if(fs->isrock)
  613. strcpy(d->gid, "ridge");
  614. else
  615. strcpy(d->gid, "iso9660");
  616. flags = dp->flags;
  617. break;
  618. case 'r':
  619. strcpy(d->gid, "sierra");
  620. flags = dp->r_flags;
  621. break;
  622. case 'J':
  623. strcpy(d->gid, "joliet");
  624. flags = dp->flags;
  625. break;
  626. case '9':
  627. strcpy(d->gid, "plan9");
  628. flags = dp->flags;
  629. break;
  630. }
  631. if(flags & 0x02){
  632. d->qid.type |= QTDIR;
  633. d->mode |= DMDIR|0111;
  634. }
  635. strcpy(d->uid, "cdrom");
  636. if(fmt!='9' && !(d->mode&DMDIR)){
  637. /*
  638. * ISO 9660 actually requires that you always have a . and a ;,
  639. * even if there is no version and no extension. Very few writers
  640. * do this. If the version is present, we use it for qid.vers.
  641. * If there is no extension but there is a dot, we strip it off.
  642. * (VMS heads couldn't comprehend the dot as a file name character
  643. * rather than as just a separator between name and extension.)
  644. *
  645. * We don't do this for directory names because directories are
  646. * not allowed to have extensions and versions.
  647. */
  648. if((p=strchr(d->name, ';')) != nil){
  649. vers = strtoul(p+1, 0, 0);
  650. d->qid.vers = vers;
  651. *p = '\0';
  652. }
  653. if((p=strchr(d->name, '.')) != nil && *(p+1)=='\0')
  654. *p = '\0';
  655. }
  656. if(fs->issusp){
  657. nl = 0;
  658. s += fs->suspoff;
  659. sysl -= fs->suspoff;
  660. for(; sysl >= 4 && have != (Hname|Hmode); sysl -= l, s += l){
  661. if(s[0] == 0 && ((uintptr)s & 1)){
  662. /* MacOS pads individual entries, contrary to spec */
  663. s++;
  664. sysl--;
  665. }
  666. l = s[2];
  667. if(s[0] == 'P' && s[1] == 'X' && s[3] == 1){
  668. /* posix file attributes */
  669. mode = l32(s+4);
  670. d->mode = mode & 0777;
  671. if((mode & 0170000) == 040000){
  672. d->mode |= DMDIR;
  673. d->qid.type |= QTDIR;
  674. }
  675. have |= Hmode;
  676. } else if(s[0] == 'N' && s[1] == 'M' && s[3] == 1){
  677. /* alternative name */
  678. if((s[4] & ~1) == 0){
  679. i = nl+l-5;
  680. if(i >= Maxname)
  681. i = Maxname-1;
  682. if((i -= nl) > 0){
  683. memmove(d->name+nl, s+5, i);
  684. nl += i;
  685. }
  686. if(s[4] == 0)
  687. have |= Hname;
  688. }
  689. } else if(s[0] == 'C' && s[1] == 'E' && s[2] >= 28){
  690. sysl = getcontin(fs->d, s, &s);
  691. continue;
  692. } else if(s[0] == 'S' && s[1] == 'T')
  693. break;
  694. }
  695. }
  696. }
  697. d->length = 0;
  698. if((d->mode & DMDIR) == 0)
  699. d->length = l32(dp->size);
  700. d->type = 0;
  701. d->dev = 0;
  702. d->atime = gtime(dp->date);
  703. d->mtime = d->atime;
  704. return vers;
  705. }
  706. static int
  707. getcontin(Xdata *dev, uchar *p, uchar **s)
  708. {
  709. long bn, off, len;
  710. Iobuf *b;
  711. bn = l32(p+4);
  712. off = l32(p+12);
  713. len = l32(p+20);
  714. chat("getcontin %d...", bn);
  715. b = getbuf(dev, bn);
  716. if(b == 0){
  717. *s = 0;
  718. return 0;
  719. }
  720. *s = b->iobuf+off;
  721. putbuf(b);
  722. return len;
  723. }
  724. static char *
  725. nstr(uchar *p, int n)
  726. {
  727. static char buf[132];
  728. char *q = buf;
  729. while(--n >= 0){
  730. if(*p == '\\')
  731. *q++ = '\\';
  732. if(' ' <= *p && *p <= '~')
  733. *q++ = *p++;
  734. else
  735. q += sprint(q, "\\%2.2ux", *p++);
  736. }
  737. *q = 0;
  738. return buf;
  739. }
  740. static char *
  741. rdate(uchar *p, int fmt)
  742. {
  743. static char buf[64];
  744. int htz, s, n;
  745. n = sprint(buf, "%2.2d.%2.2d.%2.2d %2.2d:%2.2d:%2.2d",
  746. p[0], p[1], p[2], p[3], p[4], p[5]);
  747. if(fmt == 'z'){
  748. htz = p[6];
  749. if(htz >= 128){
  750. htz = 256-htz;
  751. s = '-';
  752. }else
  753. s = '+';
  754. sprint(&buf[n], " (%c%.1f)", s, (float)htz/2);
  755. }
  756. return buf;
  757. }
  758. static char
  759. dmsize[12] =
  760. {
  761. 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
  762. };
  763. static int
  764. dysize(int y)
  765. {
  766. if((y%4) == 0)
  767. return 366;
  768. return 365;
  769. }
  770. static long
  771. gtime(uchar *p) /* yMdhmsz */
  772. {
  773. long t;
  774. int i, y, M, d, h, m, s, tz;
  775. y=p[0]; M=p[1]; d=p[2];
  776. h=p[3]; m=p[4]; s=p[5]; tz=p[6];
  777. USED(tz);
  778. y += 1900;
  779. if (y < 1970)
  780. return 0;
  781. if (M < 1 || M > 12)
  782. return 0;
  783. if (d < 1 || d > dmsize[M-1])
  784. if (!(M == 2 && d == 29 && dysize(y) == 366))
  785. return 0;
  786. if (h > 23)
  787. return 0;
  788. if (m > 59)
  789. return 0;
  790. if (s > 59)
  791. return 0;
  792. t = 0;
  793. for(i=1970; i<y; i++)
  794. t += dysize(i);
  795. if (dysize(y)==366 && M >= 3)
  796. t++;
  797. while(--M)
  798. t += dmsize[M-1];
  799. t += d-1;
  800. t = 24*t + h;
  801. t = 60*t + m;
  802. t = 60*t + s;
  803. return t;
  804. }
  805. #define p ((uchar*)arg)
  806. static long
  807. l16(void *arg)
  808. {
  809. long v;
  810. v = ((long)p[1]<<8)|p[0];
  811. if (v >= 0x8000L)
  812. v -= 0x10000L;
  813. return v;
  814. }
  815. static long
  816. l32(void *arg)
  817. {
  818. return ((((((long)p[3]<<8)|p[2])<<8)|p[1])<<8)|p[0];
  819. }
  820. #undef p