9660srv.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883
  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*, long, long);
  17. static long iwrite(Xfile*, char*, long, 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, long offset, long count)
  336. {
  337. Isofile *ip = f->ptr;
  338. long size, addr, o, n;
  339. int rcnt = 0;
  340. Iobuf *p;
  341. size = l32(ip->d.size);
  342. if(offset >= size)
  343. return 0;
  344. if(offset+count > size)
  345. count = size - offset;
  346. addr = (l32(ip->d.addr)+ip->d.attrlen)*ip->blksize + offset;
  347. o = (ulong)addr % Sectorsize;
  348. addr = (ulong)addr / Sectorsize;
  349. /*chat("d.addr=0x%x, addr=0x%x, o=0x%x...", l32(ip->d.addr), addr, o);*/
  350. n = Sectorsize - o;
  351. while(count > 0){
  352. if(n > count)
  353. n = count;
  354. p = getbuf(f->xf->d, addr);
  355. memmove(&buf[rcnt], &p->iobuf[o], n);
  356. putbuf(p);
  357. count -= n;
  358. rcnt += n;
  359. ++addr;
  360. o = 0;
  361. n = Sectorsize;
  362. }
  363. return rcnt;
  364. }
  365. static long
  366. iwrite(Xfile *f, char *buf, long offset, long count)
  367. {
  368. USED(f, buf, offset, count);
  369. error(Eperm);
  370. return 0;
  371. }
  372. static void
  373. iclunk(Xfile *f)
  374. {
  375. USED(f);
  376. }
  377. static void
  378. iremove(Xfile *f)
  379. {
  380. USED(f);
  381. error(Eperm);
  382. }
  383. static void
  384. istat(Xfile *f, Dir *d)
  385. {
  386. Isofile *ip = f->ptr;
  387. rzdir(f->xf, d, ip->fmt, &ip->d);
  388. d->qid.vers = f->qid.vers;
  389. if(d->qid.path==f->xf->rootqid.path){
  390. d->qid.path = 0;
  391. d->qid.type = QTDIR;
  392. }
  393. }
  394. static void
  395. iwstat(Xfile *f, Dir *d)
  396. {
  397. USED(f, d);
  398. error(Eperm);
  399. }
  400. static int
  401. showdrec(int fd, int fmt, void *x)
  402. {
  403. Drec *d = (Drec *)x;
  404. int namelen;
  405. int syslen;
  406. if(d->reclen == 0)
  407. return 0;
  408. fprint(fd, "%d %d %ld %ld ",
  409. d->reclen, d->attrlen, l32(d->addr), l32(d->size));
  410. fprint(fd, "%s 0x%2.2x %d %d %ld ",
  411. rdate(d->date, fmt), (fmt=='z' ? d->flags : d->r_flags),
  412. d->unitsize, d->gapsize, l16(d->vseqno));
  413. fprint(fd, "%d %s", d->namelen, nstr(d->name, d->namelen));
  414. if(fmt != 'J'){
  415. namelen = d->namelen + (1-(d->namelen&1));
  416. syslen = d->reclen - 33 - namelen;
  417. if(syslen != 0)
  418. fprint(fd, " %s", nstr(&d->name[namelen], syslen));
  419. }
  420. fprint(fd, "\n");
  421. return d->reclen + (d->reclen&1);
  422. }
  423. static void
  424. newdrec(Xfile *f, Drec *dp)
  425. {
  426. Isofile *x = f->ptr;
  427. Isofile *n;
  428. int len;
  429. len = sizeof(Isofile) - sizeof(Drec) + dp->reclen;
  430. n = ealloc(len);
  431. n->fmt = x->fmt;
  432. n->blksize = x->blksize;
  433. n->offset = 0;
  434. n->doffset = 0;
  435. memmove(&n->d, dp, dp->reclen);
  436. free(x);
  437. f->ptr = n;
  438. f->len = len;
  439. }
  440. static void
  441. ungetdrec(Xfile *f)
  442. {
  443. Isofile *ip = f->ptr;
  444. if(ip->offset >= ip->odelta){
  445. ip->offset -= ip->odelta;
  446. ip->odelta = 0;
  447. }
  448. }
  449. static int
  450. getdrec(Xfile *f, void *buf)
  451. {
  452. Isofile *ip = f->ptr;
  453. int len = 0, boff = 0;
  454. long size, addr;
  455. Iobuf *p = 0;
  456. if(!ip)
  457. return -1;
  458. size = l32(ip->d.size);
  459. while(ip->offset<size){
  460. addr = (l32(ip->d.addr)+ip->d.attrlen)*ip->blksize + ip->offset;
  461. boff = (ulong)addr % Sectorsize;
  462. if(boff > Sectorsize-34){
  463. ip->offset += Sectorsize-boff;
  464. continue;
  465. }
  466. p = getbuf(f->xf->d, (ulong)addr/Sectorsize);
  467. len = p->iobuf[boff];
  468. if(len >= 34)
  469. break;
  470. putbuf(p);
  471. p = 0;
  472. ip->offset += Sectorsize-boff;
  473. }
  474. if(p) {
  475. memmove(buf, &p->iobuf[boff], len);
  476. putbuf(p);
  477. ip->odelta = len + (len&1);
  478. ip->offset += ip->odelta;
  479. }
  480. if(p)
  481. return 0;
  482. return -1;
  483. }
  484. static int
  485. opendotdot(Xfile *f, Xfile *pf)
  486. {
  487. uchar dbuf[256];
  488. Drec *d = (Drec *)dbuf;
  489. Isofile *ip = f->ptr, *pip = pf->ptr;
  490. ip->offset = 0;
  491. if(getdrec(f, d) < 0){
  492. chat("opendotdot: getdrec(.) failed...");
  493. return -1;
  494. }
  495. if(d->namelen != 1 || d->name[0] != 0){
  496. chat("opendotdot: no . entry...");
  497. return -1;
  498. }
  499. if(l32(d->addr) != l32(ip->d.addr)){
  500. chat("opendotdot: bad . address...");
  501. return -1;
  502. }
  503. if(getdrec(f, d) < 0){
  504. chat("opendotdot: getdrec(..) failed...");
  505. return -1;
  506. }
  507. if(d->namelen != 1 || d->name[0] != 1){
  508. chat("opendotdot: no .. entry...");
  509. return -1;
  510. }
  511. pf->xf = f->xf;
  512. pip->fmt = ip->fmt;
  513. pip->blksize = ip->blksize;
  514. pip->offset = 0;
  515. pip->doffset = 0;
  516. pip->d = *d;
  517. return 0;
  518. }
  519. enum {
  520. Hname = 1,
  521. Hmode = 2,
  522. };
  523. static int
  524. rzdir(Xfs *fs, Dir *d, int fmt, Drec *dp)
  525. {
  526. int n, flags, i, j, lj, nl, vers, sysl, mode, l, have;
  527. uchar *s;
  528. char *p;
  529. char buf[Maxname+UTFmax+1];
  530. uchar *q;
  531. Rune r;
  532. enum { ONAMELEN = 28 }; /* old Plan 9 directory name length */
  533. have = 0;
  534. flags = 0;
  535. vers = -1;
  536. d->qid.path = l32(dp->addr);
  537. d->qid.type = 0;
  538. d->qid.vers = 0;
  539. n = dp->namelen;
  540. memset(d->name, 0, Maxname);
  541. if(n == 1) {
  542. switch(dp->name[0]){
  543. case 1:
  544. d->name[1] = '.';
  545. /* fall through */
  546. case 0:
  547. d->name[0] = '.';
  548. have = Hname;
  549. break;
  550. default:
  551. d->name[0] = tolower(dp->name[0]);
  552. }
  553. } else {
  554. if(fmt == 'J'){ /* Joliet, 16-bit Unicode */
  555. q = (uchar*)dp->name;
  556. for(i=j=lj=0; i<n && j<Maxname; i+=2){
  557. lj = j;
  558. r = (q[i]<<8)|q[i+1];
  559. j += runetochar(buf+j, &r);
  560. }
  561. if(j >= Maxname)
  562. j = lj;
  563. memmove(d->name, buf, j);
  564. }else{
  565. if(n >= Maxname)
  566. n = Maxname-1;
  567. for(i=0; i<n; i++)
  568. d->name[i] = tolower(dp->name[i]);
  569. }
  570. }
  571. sysl = dp->reclen-(34+dp->namelen);
  572. s = (uchar*)dp->name + dp->namelen;
  573. if(((uintptr)s) & 1) {
  574. s++;
  575. sysl--;
  576. }
  577. if(fs->isplan9 && sysl > 0) {
  578. /*
  579. * get gid, uid, mode and possibly name
  580. * from plan9 directory extension
  581. */
  582. nl = *s;
  583. if(nl >= ONAMELEN)
  584. nl = ONAMELEN-1;
  585. if(nl) {
  586. memset(d->name, 0, ONAMELEN);
  587. memmove(d->name, s+1, nl);
  588. }
  589. s += 1 + *s;
  590. nl = *s;
  591. if(nl >= ONAMELEN)
  592. nl = ONAMELEN-1;
  593. memset(d->uid, 0, ONAMELEN);
  594. memmove(d->uid, s+1, nl);
  595. s += 1 + *s;
  596. nl = *s;
  597. if(nl >= ONAMELEN)
  598. nl = ONAMELEN-1;
  599. memset(d->gid, 0, ONAMELEN);
  600. memmove(d->gid, s+1, nl);
  601. s += 1 + *s;
  602. if(((uintptr)s) & 1)
  603. s++;
  604. d->mode = l32(s);
  605. if(d->mode & DMDIR)
  606. d->qid.type |= QTDIR;
  607. } else {
  608. d->mode = 0444;
  609. switch(fmt) {
  610. case 'z':
  611. if(fs->isrock)
  612. strcpy(d->gid, "ridge");
  613. else
  614. strcpy(d->gid, "iso9660");
  615. flags = dp->flags;
  616. break;
  617. case 'r':
  618. strcpy(d->gid, "sierra");
  619. flags = dp->r_flags;
  620. break;
  621. case 'J':
  622. strcpy(d->gid, "joliet");
  623. flags = dp->flags;
  624. break;
  625. case '9':
  626. strcpy(d->gid, "plan9");
  627. flags = dp->flags;
  628. break;
  629. }
  630. if(flags & 0x02){
  631. d->qid.type |= QTDIR;
  632. d->mode |= DMDIR|0111;
  633. }
  634. strcpy(d->uid, "cdrom");
  635. if(fmt!='9' && !(d->mode&DMDIR)){
  636. /*
  637. * ISO 9660 actually requires that you always have a . and a ;,
  638. * even if there is no version and no extension. Very few writers
  639. * do this. If the version is present, we use it for qid.vers.
  640. * If there is no extension but there is a dot, we strip it off.
  641. * (VMS heads couldn't comprehend the dot as a file name character
  642. * rather than as just a separator between name and extension.)
  643. *
  644. * We don't do this for directory names because directories are
  645. * not allowed to have extensions and versions.
  646. */
  647. if((p=strchr(d->name, ';')) != nil){
  648. vers = strtoul(p+1, 0, 0);
  649. d->qid.vers = vers;
  650. *p = '\0';
  651. }
  652. if((p=strchr(d->name, '.')) != nil && *(p+1)=='\0')
  653. *p = '\0';
  654. }
  655. if(fs->issusp){
  656. nl = 0;
  657. s += fs->suspoff;
  658. sysl -= fs->suspoff;
  659. for(; sysl >= 4 && have != (Hname|Hmode); sysl -= l, s += l){
  660. if(s[0] == 0 && ((uintptr)s & 1)){
  661. /* MacOS pads individual entries, contrary to spec */
  662. s++;
  663. sysl--;
  664. }
  665. l = s[2];
  666. if(s[0] == 'P' && s[1] == 'X' && s[3] == 1){
  667. /* posix file attributes */
  668. mode = l32(s+4);
  669. d->mode = mode & 0777;
  670. if((mode & 0170000) == 040000){
  671. d->mode |= DMDIR;
  672. d->qid.type |= QTDIR;
  673. }
  674. have |= Hmode;
  675. } else if(s[0] == 'N' && s[1] == 'M' && s[3] == 1){
  676. /* alternative name */
  677. if((s[4] & ~1) == 0){
  678. i = nl+l-5;
  679. if(i >= Maxname)
  680. i = Maxname-1;
  681. if((i -= nl) > 0){
  682. memmove(d->name+nl, s+5, i);
  683. nl += i;
  684. }
  685. if(s[4] == 0)
  686. have |= Hname;
  687. }
  688. } else if(s[0] == 'C' && s[1] == 'E' && s[2] >= 28){
  689. sysl = getcontin(fs->d, s, &s);
  690. continue;
  691. } else if(s[0] == 'S' && s[1] == 'T')
  692. break;
  693. }
  694. }
  695. }
  696. d->length = 0;
  697. if((d->mode & DMDIR) == 0)
  698. d->length = l32(dp->size);
  699. d->type = 0;
  700. d->dev = 0;
  701. d->atime = gtime(dp->date);
  702. d->mtime = d->atime;
  703. return vers;
  704. }
  705. static int
  706. getcontin(Xdata *dev, uchar *p, uchar **s)
  707. {
  708. long bn, off, len;
  709. Iobuf *b;
  710. bn = l32(p+4);
  711. off = l32(p+12);
  712. len = l32(p+20);
  713. chat("getcontin %d...", bn);
  714. b = getbuf(dev, bn);
  715. if(b == 0){
  716. *s = 0;
  717. return 0;
  718. }
  719. *s = b->iobuf+off;
  720. putbuf(b);
  721. return len;
  722. }
  723. static char *
  724. nstr(uchar *p, int n)
  725. {
  726. static char buf[132];
  727. char *q = buf;
  728. while(--n >= 0){
  729. if(*p == '\\')
  730. *q++ = '\\';
  731. if(' ' <= *p && *p <= '~')
  732. *q++ = *p++;
  733. else
  734. q += sprint(q, "\\%2.2ux", *p++);
  735. }
  736. *q = 0;
  737. return buf;
  738. }
  739. static char *
  740. rdate(uchar *p, int fmt)
  741. {
  742. static char buf[64];
  743. int htz, s, n;
  744. n = sprint(buf, "%2.2d.%2.2d.%2.2d %2.2d:%2.2d:%2.2d",
  745. p[0], p[1], p[2], p[3], p[4], p[5]);
  746. if(fmt == 'z'){
  747. htz = p[6];
  748. if(htz >= 128){
  749. htz = 256-htz;
  750. s = '-';
  751. }else
  752. s = '+';
  753. sprint(&buf[n], " (%c%.1f)", s, (float)htz/2);
  754. }
  755. return buf;
  756. }
  757. static char
  758. dmsize[12] =
  759. {
  760. 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
  761. };
  762. static int
  763. dysize(int y)
  764. {
  765. if((y%4) == 0)
  766. return 366;
  767. return 365;
  768. }
  769. static long
  770. gtime(uchar *p) /* yMdhmsz */
  771. {
  772. long t;
  773. int i, y, M, d, h, m, s, tz;
  774. y=p[0]; M=p[1]; d=p[2];
  775. h=p[3]; m=p[4]; s=p[5]; tz=p[6];
  776. USED(tz);
  777. if (y < 70)
  778. return 0;
  779. if (M < 1 || M > 12)
  780. return 0;
  781. if (d < 1 || d > dmsize[M-1])
  782. return 0;
  783. if (h > 23)
  784. return 0;
  785. if (m > 59)
  786. return 0;
  787. if (s > 59)
  788. return 0;
  789. y += 1900;
  790. t = 0;
  791. for(i=1970; i<y; i++)
  792. t += dysize(i);
  793. if (dysize(y)==366 && M >= 3)
  794. t++;
  795. while(--M)
  796. t += dmsize[M-1];
  797. t += d-1;
  798. t = 24*t + h;
  799. t = 60*t + m;
  800. t = 60*t + s;
  801. return t;
  802. }
  803. #define p ((uchar*)arg)
  804. static long
  805. l16(void *arg)
  806. {
  807. long v;
  808. v = ((long)p[1]<<8)|p[0];
  809. if (v >= 0x8000L)
  810. v -= 0x10000L;
  811. return v;
  812. }
  813. static long
  814. l32(void *arg)
  815. {
  816. return ((((((long)p[3]<<8)|p[2])<<8)|p[1])<<8)|p[0];
  817. }
  818. #undef p