path.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <libsec.h>
  5. #include "iso9660.h"
  6. /*
  7. * Add the requisite path tables to the CD image.
  8. * They get put on the end once everything else is done.
  9. * We use the path table itself as a queue in the breadth-first
  10. * traversal of the tree.
  11. *
  12. * The only problem with this is that the path table does not
  13. * store the lengths of the directories. So we keep an explicit
  14. * map in an array in memory.
  15. */
  16. enum {
  17. Big,
  18. Little
  19. };
  20. static void
  21. Crdpath(Cdimg *cd, Cpath *p)
  22. {
  23. p->namelen = Cgetc(cd);
  24. if(p->namelen == 0) {
  25. Crseek(cd, (Croffset(cd)+Blocksize-1)/Blocksize * Blocksize);
  26. p->namelen = Cgetc(cd);
  27. assert(p->namelen != 0);
  28. }
  29. p->xlen = Cgetc(cd);
  30. assert(p->xlen == 0); /* sanity, might not be true if we start using the extended fields */
  31. Cread(cd, p->dloc, 4);
  32. Cread(cd, p->parent, 2);
  33. p->name[0] = '\0';
  34. Crseek(cd, Croffset(cd)+p->namelen+p->xlen+(p->namelen&1)); /* skip name, ext data */
  35. }
  36. static void
  37. writepath(Cdimg *cd, Cdir *c, int parent, int size)
  38. {
  39. /*
  40. DO NOT UNCOMMENT THIS CODE.
  41. This commented-out code is here only so that no one comes
  42. along and adds it later.
  43. The ISO 9660 spec is silent about whether path table entries
  44. need to be padded so that they never cross block boundaries.
  45. It would be reasonable to assume that they are like every other
  46. data structure in the bloody spec; this code pads them out.
  47. Empirically, though, they're NOT padded. Windows NT and
  48. derivatives are the only known current operating systems
  49. that actually read these things.
  50. int l;
  51. l = 1+1+4+2+c->namelen;
  52. if(Cwoffset(cd)/Blocksize != (Cwoffset(cd)+l)/Blocksize)
  53. Cpadblock(cd);
  54. */
  55. Cputc(cd, c->namelen);
  56. Cputc(cd, 0);
  57. Cwrite(cd, c->dloc + (size==Little ? 0 : 4), 4);
  58. (size==Little ? Cputnl : Cputnm)(cd, parent, 2);
  59. Cwrite(cd, c->name, c->namelen);
  60. if(c->namelen & 1)
  61. Cputc(cd, 0);
  62. }
  63. static ulong*
  64. addlength(ulong *a, ulong x, int n)
  65. {
  66. if(n%128==0)
  67. a = erealloc(a, (n+128)*sizeof a[0]);
  68. a[n] = x;
  69. return a;
  70. }
  71. static ulong
  72. writepathtable(Cdimg *cd, ulong vdblock, int size)
  73. {
  74. int rp, wp;
  75. uchar buf[Blocksize];
  76. ulong bk, i, *len, n;
  77. uvlong start, end, rdoff;
  78. Cdir *c;
  79. Cpath p;
  80. Creadblock(cd, buf, vdblock, Blocksize);
  81. c = (Cdir*)(buf + offsetof(Cvoldesc, rootdir[0]));
  82. rp = 0;
  83. wp = 0;
  84. len = nil;
  85. start = (vlong)cd->nextblock * Blocksize;
  86. Cwseek(cd, start);
  87. Crseek(cd, start);
  88. writepath(cd, c, 1, size);
  89. len = addlength(len, little(c->dlen, 4), wp);
  90. wp++;
  91. while(rp < wp) {
  92. Crdpath(cd, &p);
  93. n = (len[rp]+Blocksize-1)/Blocksize;
  94. rp++;
  95. bk = (size==Big ? big : little)(p.dloc, 4);
  96. rdoff = Croffset(cd);
  97. for(i=0; i<n; i++) {
  98. Creadblock(cd, buf, bk+i, Blocksize);
  99. c = (Cdir*)buf;
  100. if(i != 0 && c->namelen == 1 && c->name[0] == '\0')
  101. break; /* hit another directory; stop */
  102. while(c->len && c->namelen &&
  103. (uchar*)c + c->len < buf + Blocksize) {
  104. if(c->flags & 0x02 &&
  105. (c->namelen > 1 || c->name[0] > '\001')) {
  106. /* directory */
  107. writepath(cd, c, rp, size);
  108. len = addlength(len, little(c->dlen, 4), wp);
  109. wp++;
  110. }
  111. c = (Cdir*)((uchar*)c+c->len);
  112. }
  113. }
  114. Crseek(cd, rdoff);
  115. }
  116. end = Cwoffset(cd);
  117. Cpadblock(cd);
  118. return end-start;
  119. }
  120. static void
  121. writepathtablepair(Cdimg *cd, ulong vdblock)
  122. {
  123. ulong bloc, lloc, sz, sz2;
  124. lloc = cd->nextblock;
  125. sz = writepathtable(cd, vdblock, Little);
  126. bloc = cd->nextblock;
  127. sz2 = writepathtable(cd, vdblock, Big);
  128. assert(sz == sz2);
  129. setpathtable(cd, vdblock, sz, lloc, bloc);
  130. }
  131. void
  132. writepathtables(Cdimg *cd)
  133. {
  134. cd->pathblock = cd->nextblock;
  135. writepathtablepair(cd, cd->iso9660pvd);
  136. if(cd->flags & CDjoliet)
  137. writepathtablepair(cd, cd->jolietsvd);
  138. }