rock.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. /*
  2. * File rock.c - generate RRIP records for iso9660 filesystems.
  3. Written by Eric Youngdale (1993).
  4. Copyright 1993 Yggdrasil Computing, Incorporated
  5. Copyright (C) 2009,2010 Free Software Foundation, Inc.
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 3, or (at your option)
  9. any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <stdlib.h>
  18. #include "config.h"
  19. #ifndef VMS
  20. #if defined(MAJOR_IN_SYSMACROS)
  21. #include <sys/sysmacros.h>
  22. #endif
  23. #ifdef HAVE_UNISTD_H
  24. #include <unistd.h>
  25. #endif
  26. #endif
  27. #if defined(MAJOR_IN_MKDEV)
  28. #include <sys/types.h>
  29. #include <sys/mkdev.h>
  30. #endif
  31. #include "mkisofs.h"
  32. #include "iso9660.h"
  33. #include <string.h>
  34. #include <errno.h>
  35. #ifdef DOESNT_WORK
  36. #ifdef NON_UNIXFS
  37. #define S_ISLNK(m) (0)
  38. #else
  39. #ifndef S_ISLNK
  40. #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
  41. #endif
  42. #endif
  43. #else
  44. #include <statdefs.h>
  45. #endif
  46. #define SU_VERSION 1
  47. #define SL_ROOT 8
  48. #define SL_PARENT 4
  49. #define SL_CURRENT 2
  50. #define SL_CONTINUE 1
  51. #define CE_SIZE 28
  52. #define CL_SIZE 12
  53. #define ER_SIZE 8
  54. #define NM_SIZE 5
  55. #define PL_SIZE 12
  56. #define PN_SIZE 20
  57. #define PX_SIZE 36
  58. #define RE_SIZE 4
  59. #define SL_SIZE 20
  60. #define ZZ_SIZE 15
  61. #ifdef __QNX__
  62. #define TF_SIZE (5 + 4 * 7)
  63. #else
  64. #define TF_SIZE (5 + 3 * 7)
  65. #endif
  66. /* If we need to store this number of bytes, make sure we
  67. do not box ourselves in so that we do not have room for
  68. a CE entry for the continuation record */
  69. #define MAYBE_ADD_CE_ENTRY(BYTES) \
  70. ((unsigned) ((BYTES) + CE_SIZE + currlen + ipnt) > (unsigned) (recstart + reclimit) ? 1 : 0)
  71. /*
  72. * Buffer to build RR attributes
  73. */
  74. static unsigned char Rock[16384];
  75. static unsigned char symlink_buff[256];
  76. static int ipnt = 0;
  77. static int recstart = 0;
  78. static int currlen = 0;
  79. static int mainrec = 0;
  80. static int reclimit;
  81. static void add_CE_entry __PR((void));
  82. static void add_CE_entry(){
  83. if(recstart)
  84. set_733((char*)Rock + recstart - 8, ipnt + 28 - recstart);
  85. Rock[ipnt++] ='C';
  86. Rock[ipnt++] ='E';
  87. Rock[ipnt++] = CE_SIZE;
  88. Rock[ipnt++] = SU_VERSION;
  89. set_733((char*)Rock + ipnt, 0);
  90. ipnt += 8;
  91. set_733((char*)Rock + ipnt, 0);
  92. ipnt += 8;
  93. set_733((char*)Rock + ipnt, 0);
  94. ipnt += 8;
  95. recstart = ipnt;
  96. currlen = 0;
  97. if(!mainrec) mainrec = ipnt;
  98. reclimit = SECTOR_SIZE - 8; /* Limit to one sector */
  99. }
  100. #ifdef __STDC__
  101. int generate_rock_ridge_attributes (char * whole_name, char * name,
  102. struct directory_entry * s_entry,
  103. struct stat * statbuf,
  104. struct stat * lstatbuf,
  105. int deep_opt)
  106. #else
  107. int generate_rock_ridge_attributes (whole_name, name,
  108. s_entry,
  109. statbuf,
  110. lstatbuf,
  111. deep_opt)
  112. char * whole_name; char * name; struct directory_entry * s_entry;
  113. struct stat * statbuf, *lstatbuf;
  114. int deep_opt;
  115. #endif
  116. {
  117. int flagpos, flagval;
  118. int need_ce;
  119. statbuf = statbuf; /* this shuts up unreferenced compiler warnings */
  120. mainrec = recstart = ipnt = 0;
  121. reclimit = 0xf8;
  122. /* no need to fill in the RR stuff if we won't see the file */
  123. if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
  124. return 0;
  125. /* Obtain the amount of space that is currently used for the directory
  126. record. Assume max for name, since name conflicts may cause us
  127. to rename the file later on */
  128. currlen = sizeof(s_entry->isorec);
  129. /* Identify that we are using the SUSP protocol */
  130. if(deep_opt & NEED_SP){
  131. Rock[ipnt++] ='S';
  132. Rock[ipnt++] ='P';
  133. Rock[ipnt++] = 7;
  134. Rock[ipnt++] = SU_VERSION;
  135. Rock[ipnt++] = 0xbe;
  136. Rock[ipnt++] = 0xef;
  137. Rock[ipnt++] = 0;
  138. };
  139. /* First build the posix name field */
  140. Rock[ipnt++] ='R';
  141. Rock[ipnt++] ='R';
  142. Rock[ipnt++] = 5;
  143. Rock[ipnt++] = SU_VERSION;
  144. flagpos = ipnt;
  145. flagval = 0;
  146. Rock[ipnt++] = 0; /* We go back and fix this later */
  147. if(strcmp(name,".") && strcmp(name,"..")){
  148. char * npnt;
  149. int remain, use;
  150. remain = strlen(name);
  151. npnt = name;
  152. while(remain){
  153. use = remain;
  154. need_ce = 0;
  155. /* Can we fit this SUSP and a CE entry? */
  156. if(use + currlen + CE_SIZE + (ipnt - recstart) > reclimit) {
  157. use = reclimit - currlen - CE_SIZE - (ipnt - recstart);
  158. need_ce++;
  159. }
  160. /* Only room for 256 per SUSP field */
  161. if(use > 0xf8) use = 0xf8;
  162. /* First build the posix name field */
  163. Rock[ipnt++] ='N';
  164. Rock[ipnt++] ='M';
  165. Rock[ipnt++] = NM_SIZE + use;
  166. Rock[ipnt++] = SU_VERSION;
  167. Rock[ipnt++] = (remain != use ? 1 : 0);
  168. flagval |= (1<<3);
  169. strncpy((char *)&Rock[ipnt], npnt, use);
  170. npnt += use;
  171. ipnt += use;
  172. remain -= use;
  173. if(remain && need_ce) add_CE_entry();
  174. };
  175. };
  176. /*
  177. * Add the posix modes
  178. */
  179. if(MAYBE_ADD_CE_ENTRY(PX_SIZE)) add_CE_entry();
  180. Rock[ipnt++] ='P';
  181. Rock[ipnt++] ='X';
  182. Rock[ipnt++] = PX_SIZE;
  183. Rock[ipnt++] = SU_VERSION;
  184. flagval |= (1<<0);
  185. set_733((char*)Rock + ipnt, lstatbuf->st_mode);
  186. ipnt += 8;
  187. set_733((char*)Rock + ipnt, lstatbuf->st_nlink);
  188. ipnt += 8;
  189. set_733((char*)Rock + ipnt, lstatbuf->st_uid);
  190. ipnt += 8;
  191. set_733((char*)Rock + ipnt, lstatbuf->st_gid);
  192. ipnt += 8;
  193. /*
  194. * Check for special devices
  195. */
  196. #ifndef NON_UNIXFS
  197. if (S_ISCHR(lstatbuf->st_mode) || S_ISBLK(lstatbuf->st_mode)) {
  198. if(MAYBE_ADD_CE_ENTRY(PN_SIZE)) add_CE_entry();
  199. Rock[ipnt++] ='P';
  200. Rock[ipnt++] ='N';
  201. Rock[ipnt++] = PN_SIZE;
  202. Rock[ipnt++] = SU_VERSION;
  203. flagval |= (1<<1);
  204. #if defined(MAJOR_IN_SYSMACROS) || defined(MAJOR_IN_MKDEV)
  205. set_733((char*)Rock + ipnt, major(lstatbuf->st_rdev ));
  206. ipnt += 8;
  207. set_733((char*)Rock + ipnt, minor(lstatbuf->st_rdev));
  208. ipnt += 8;
  209. #else
  210. /*
  211. * If we don't have sysmacros.h, then we have to guess as to how
  212. * best to pick apart the device number for major/minor.
  213. * Note: this may very well be wrong for many systems, so
  214. * it is always best to use the major/minor macros if the
  215. * system supports it.
  216. */
  217. if(sizeof(dev_t) <= 2) {
  218. set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 8));
  219. ipnt += 8;
  220. set_733((char*)Rock + ipnt, lstatbuf->st_rdev & 0xff);
  221. ipnt += 8;
  222. }
  223. else if(sizeof(dev_t) <= 4) {
  224. set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 8) >> 8);
  225. ipnt += 8;
  226. set_733((char*)Rock + ipnt, lstatbuf->st_rdev & 0xffff);
  227. ipnt += 8;
  228. }
  229. else {
  230. set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 16) >> 16);
  231. ipnt += 8;
  232. set_733((char*)Rock + ipnt, lstatbuf->st_rdev);
  233. ipnt += 8;
  234. }
  235. #endif
  236. };
  237. #endif
  238. /*
  239. * Check for and symbolic links. VMS does not have these.
  240. */
  241. if (S_ISLNK(lstatbuf->st_mode)){
  242. int lenpos, lenval, j0, j1;
  243. int nchar;
  244. unsigned char * cpnt, *cpnt1;
  245. nchar = readlink(whole_name, (char *)symlink_buff, sizeof(symlink_buff));
  246. symlink_buff[nchar < 0 ? 0 : nchar] = 0;
  247. nchar = strlen((char *) symlink_buff);
  248. set_733(s_entry->isorec.size, 0);
  249. cpnt = &symlink_buff[0];
  250. flagval |= (1<<2);
  251. if (! split_SL_field)
  252. {
  253. int sl_bytes = 0;
  254. for (cpnt1 = cpnt; *cpnt1 != '\0'; cpnt1++)
  255. {
  256. if (*cpnt1 == '/')
  257. {
  258. sl_bytes += 4;
  259. }
  260. else
  261. {
  262. sl_bytes += 1;
  263. }
  264. }
  265. if (sl_bytes > 250)
  266. {
  267. /*
  268. * the symbolic link won't fit into one SL System Use Field
  269. * print an error message and continue with splited one
  270. */
  271. fprintf (stderr, _("symbolic link `%s' too long for one SL System Use Field, splitting"), cpnt);
  272. }
  273. if(MAYBE_ADD_CE_ENTRY(SL_SIZE + sl_bytes)) add_CE_entry();
  274. }
  275. while(nchar){
  276. if(MAYBE_ADD_CE_ENTRY(SL_SIZE)) add_CE_entry();
  277. Rock[ipnt++] ='S';
  278. Rock[ipnt++] ='L';
  279. lenpos = ipnt;
  280. Rock[ipnt++] = SL_SIZE;
  281. Rock[ipnt++] = SU_VERSION;
  282. Rock[ipnt++] = 0; /* Flags */
  283. lenval = 5;
  284. while(*cpnt){
  285. cpnt1 = (unsigned char *) strchr((char *) cpnt, '/');
  286. if(cpnt1) {
  287. nchar--;
  288. *cpnt1 = 0;
  289. };
  290. /* We treat certain components in a special way. */
  291. if(cpnt[0] == '.' && cpnt[1] == '.' && cpnt[2] == 0){
  292. if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
  293. Rock[ipnt++] = SL_PARENT;
  294. Rock[ipnt++] = 0; /* length is zero */
  295. lenval += 2;
  296. nchar -= 2;
  297. } else if(cpnt[0] == '.' && cpnt[1] == 0){
  298. if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
  299. Rock[ipnt++] = SL_CURRENT;
  300. Rock[ipnt++] = 0; /* length is zero */
  301. lenval += 2;
  302. nchar -= 1;
  303. } else if(cpnt[0] == 0){
  304. if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
  305. Rock[ipnt++] = SL_ROOT;
  306. Rock[ipnt++] = 0; /* length is zero */
  307. lenval += 2;
  308. } else {
  309. /* If we do not have enough room for a component, start
  310. a new continuations segment now */
  311. if(split_SL_component ? MAYBE_ADD_CE_ENTRY(6) :
  312. MAYBE_ADD_CE_ENTRY(6 + strlen ((char *) cpnt)))
  313. {
  314. add_CE_entry();
  315. if(cpnt1)
  316. {
  317. *cpnt1 = '/';
  318. nchar++;
  319. cpnt1 = NULL; /* A kluge so that we can restart properly */
  320. }
  321. break;
  322. }
  323. j0 = strlen((char *) cpnt);
  324. while(j0) {
  325. j1 = j0;
  326. if(j1 > 0xf8) j1 = 0xf8;
  327. need_ce = 0;
  328. if(j1 + currlen + CE_SIZE + (ipnt - recstart) > reclimit) {
  329. j1 = reclimit - currlen - CE_SIZE - (ipnt - recstart);
  330. need_ce++;
  331. }
  332. Rock[ipnt++] = (j1 != j0 ? SL_CONTINUE : 0);
  333. Rock[ipnt++] = j1;
  334. strncpy((char *) Rock + ipnt, (char *) cpnt, j1);
  335. ipnt += j1;
  336. lenval += j1 + 2;
  337. cpnt += j1;
  338. nchar -= j1; /* Number we processed this time */
  339. j0 -= j1;
  340. if(need_ce) {
  341. add_CE_entry();
  342. if(cpnt1) {
  343. *cpnt1 = '/';
  344. nchar++;
  345. cpnt1 = NULL; /* A kluge so that we can restart properly */
  346. }
  347. break;
  348. }
  349. }
  350. };
  351. if(cpnt1) {
  352. cpnt = cpnt1 + 1;
  353. } else
  354. break;
  355. }
  356. Rock[lenpos] = lenval;
  357. if(nchar) Rock[lenpos + 2] = SL_CONTINUE; /* We need another SL entry */
  358. } /* while nchar */
  359. } /* Is a symbolic link */
  360. /*
  361. * Add in the Rock Ridge TF time field
  362. */
  363. if(MAYBE_ADD_CE_ENTRY(TF_SIZE)) add_CE_entry();
  364. Rock[ipnt++] ='T';
  365. Rock[ipnt++] ='F';
  366. Rock[ipnt++] = TF_SIZE;
  367. Rock[ipnt++] = SU_VERSION;
  368. #ifdef __QNX__
  369. Rock[ipnt++] = 0x0f;
  370. #else
  371. Rock[ipnt++] = 0x0e;
  372. #endif
  373. flagval |= (1<<7);
  374. #ifdef __QNX__
  375. iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ftime);
  376. ipnt += 7;
  377. #endif
  378. iso9660_date((char *) &Rock[ipnt], lstatbuf->st_mtime);
  379. ipnt += 7;
  380. iso9660_date((char *) &Rock[ipnt], lstatbuf->st_atime);
  381. ipnt += 7;
  382. iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ctime);
  383. ipnt += 7;
  384. /*
  385. * Add in the Rock Ridge RE time field
  386. */
  387. if(deep_opt & NEED_RE){
  388. if(MAYBE_ADD_CE_ENTRY(RE_SIZE)) add_CE_entry();
  389. Rock[ipnt++] ='R';
  390. Rock[ipnt++] ='E';
  391. Rock[ipnt++] = RE_SIZE;
  392. Rock[ipnt++] = SU_VERSION;
  393. flagval |= (1<<6);
  394. };
  395. /*
  396. * Add in the Rock Ridge PL record, if required.
  397. */
  398. if(deep_opt & NEED_PL){
  399. if(MAYBE_ADD_CE_ENTRY(PL_SIZE)) add_CE_entry();
  400. Rock[ipnt++] ='P';
  401. Rock[ipnt++] ='L';
  402. Rock[ipnt++] = PL_SIZE;
  403. Rock[ipnt++] = SU_VERSION;
  404. set_733((char*)Rock + ipnt, 0);
  405. ipnt += 8;
  406. flagval |= (1<<5);
  407. };
  408. /*
  409. * Add in the Rock Ridge CL field, if required.
  410. */
  411. if(deep_opt & NEED_CL){
  412. if(MAYBE_ADD_CE_ENTRY(CL_SIZE)) add_CE_entry();
  413. Rock[ipnt++] ='C';
  414. Rock[ipnt++] ='L';
  415. Rock[ipnt++] = CL_SIZE;
  416. Rock[ipnt++] = SU_VERSION;
  417. set_733((char*)Rock + ipnt, 0);
  418. ipnt += 8;
  419. flagval |= (1<<4);
  420. };
  421. #ifndef VMS
  422. /* If transparent compression was requested, fill in the correct
  423. field for this file */
  424. if(transparent_compression &&
  425. S_ISREG(lstatbuf->st_mode) &&
  426. strlen(name) > 3 &&
  427. strcmp(name + strlen(name) - 3,".gZ") == 0){
  428. FILE * zipfile;
  429. char * checkname;
  430. unsigned int file_size;
  431. unsigned char header[8];
  432. int OK_flag;
  433. /* First open file and verify that the correct algorithm was used */
  434. file_size = 0;
  435. OK_flag = 1;
  436. zipfile = fopen(whole_name, "rb");
  437. if (fread (header, 1, sizeof (header), zipfile) != sizeof(header))
  438. error (1, errno, "fread");
  439. /* Check some magic numbers from gzip. */
  440. if(header[0] != 0x1f || header[1] != 0x8b || header[2] != 8) OK_flag = 0;
  441. /* Make sure file was blocksized. */
  442. if(((header[3] & 0x40) == 0)) OK_flag = 0;
  443. /* OK, now go to the end of the file and get some more info */
  444. if(OK_flag){
  445. int status;
  446. status = (long)lseek(fileno(zipfile), (off_t)(-8), SEEK_END);
  447. if(status == -1) OK_flag = 0;
  448. }
  449. if(OK_flag){
  450. if(read(fileno(zipfile), (char*)header, sizeof(header)) != sizeof(header))
  451. OK_flag = 0;
  452. else {
  453. int blocksize;
  454. blocksize = (header[3] << 8) | header[2];
  455. file_size = ((unsigned int)header[7] << 24) |
  456. ((unsigned int)header[6] << 16) |
  457. ((unsigned int)header[5] << 8) | header[4];
  458. #if 0
  459. fprintf(stderr,"Blocksize = %d %d\n", blocksize, file_size);
  460. #endif
  461. if(blocksize != SECTOR_SIZE) OK_flag = 0;
  462. }
  463. }
  464. fclose(zipfile);
  465. checkname = strdup(whole_name);
  466. checkname[strlen(whole_name)-3] = 0;
  467. zipfile = fopen(checkname, "rb");
  468. if(zipfile) {
  469. OK_flag = 0;
  470. fprintf (stderr, _("Unable to insert transparent compressed file - name conflict\n"));
  471. fclose(zipfile);
  472. }
  473. free(checkname);
  474. if(OK_flag){
  475. if(MAYBE_ADD_CE_ENTRY(ZZ_SIZE)) add_CE_entry();
  476. Rock[ipnt++] ='Z';
  477. Rock[ipnt++] ='Z';
  478. Rock[ipnt++] = ZZ_SIZE;
  479. Rock[ipnt++] = SU_VERSION;
  480. Rock[ipnt++] = 'g'; /* Identify compression technique used */
  481. Rock[ipnt++] = 'z';
  482. Rock[ipnt++] = 3;
  483. set_733((char*)Rock + ipnt, file_size); /* Real file size */
  484. ipnt += 8;
  485. };
  486. }
  487. #endif
  488. /*
  489. * Add in the Rock Ridge CE field, if required. We use this for the
  490. * extension record that is stored in the root directory.
  491. */
  492. if(deep_opt & NEED_CE) add_CE_entry();
  493. /*
  494. * Done filling in all of the fields. Now copy it back to a buffer for the
  495. * file in question.
  496. */
  497. /* Now copy this back to the buffer for the file */
  498. Rock[flagpos] = flagval;
  499. /* If there was a CE, fill in the size field */
  500. if(recstart)
  501. set_733((char*)Rock + recstart - 8, ipnt - recstart);
  502. s_entry->rr_attributes = (unsigned char *) e_malloc(ipnt);
  503. s_entry->total_rr_attr_size = ipnt;
  504. s_entry->rr_attr_size = (mainrec ? mainrec : ipnt);
  505. memcpy(s_entry->rr_attributes, Rock, ipnt);
  506. return ipnt;
  507. }
  508. /* Guaranteed to return a single sector with the relevant info */
  509. char * FDECL4(generate_rr_extension_record, char *, id, char *, descriptor,
  510. char *, source, int *, size){
  511. int lipnt = 0;
  512. char * pnt;
  513. int len_id, len_des, len_src;
  514. len_id = strlen(id);
  515. len_des = strlen(descriptor);
  516. len_src = strlen(source);
  517. Rock[lipnt++] ='E';
  518. Rock[lipnt++] ='R';
  519. Rock[lipnt++] = ER_SIZE + len_id + len_des + len_src;
  520. Rock[lipnt++] = 1;
  521. Rock[lipnt++] = len_id;
  522. Rock[lipnt++] = len_des;
  523. Rock[lipnt++] = len_src;
  524. Rock[lipnt++] = 1;
  525. memcpy(Rock + lipnt, id, len_id);
  526. lipnt += len_id;
  527. memcpy(Rock + lipnt, descriptor, len_des);
  528. lipnt += len_des;
  529. memcpy(Rock + lipnt, source, len_src);
  530. lipnt += len_src;
  531. if(lipnt > SECTOR_SIZE)
  532. error (1, 0, _("Extension record too long\n"));
  533. pnt = (char *) e_malloc(SECTOR_SIZE);
  534. memset(pnt, 0, SECTOR_SIZE);
  535. memcpy(pnt, Rock, lipnt);
  536. *size = lipnt;
  537. return pnt;
  538. }