home *** CD-ROM | disk | FTP | other *** search
/ Dream 49 / Amiga_Dream_49.iso / beos / utils / mkisofs-1.000 / mkisofs-1.11-beos / rock.c < prev    next >
C/C++ Source or Header  |  1998-01-25  |  15KB  |  557 lines

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