home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / cdrom / mkisofs.105 / source / rock.c < prev    next >
C/C++ Source or Header  |  1977-12-31  |  14KB  |  539 lines

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