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