1 /***************************************************************************
2 * Copyright (c) 2005, 2006 by Dmitry Morozhnikov <dmiceman@mail.ru > *
3 * Copyright (c) 2005-10 Simon Peter *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) 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. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 // for struct tm->tm_gmtoff
35 #include <sys/statfs.h>
40 static isofs_context context
;
41 static GHashTable
*lookup_table
;
42 static GHashTable
*negative_lookup_table
;
43 static char *negative_value
= "does not exist";
44 static pthread_mutex_t fd_mutex
= PTHREAD_MUTEX_INITIALIZER
;
46 static int isofs_check_rr(struct iso_directory_record
*root_record
);
47 static int isofs_read_raw_block(int block
, char *buf
);
49 extern char* iocharset
;
51 // locally implement g_strv_length, this is missing in glib2 for rhel3/rhel4
52 // -- Chandan Dutta Chowdhury 2007-07-06
53 guint
local_g_strv_length (gchar
**str_array
) {
55 g_return_val_if_fail (str_array
!= NULL
, 0);
61 int isofs_real_preinit( char* imagefile
, int fd
) {
63 memset(& context
, 0, sizeof(isofs_context
));
65 context
.imagefile
= imagefile
;
68 // trying to read all volume descriptors
69 struct iso_volume_descriptor
*vd
=
70 (struct iso_volume_descriptor
*) malloc(sizeof(struct iso_volume_descriptor
));
72 // perror("Can`t malloc: ");
78 context
.block_size
= 2048;
79 context
.data_size
= 2048;
80 context
.block_offset
= 0;
81 context
.file_offset
= 0;
84 IDOFF_ISO_2048
= 2048 * 16,
85 IDOFF_MODE1_2352
= 2352 * 16 + 16,
86 IDOFF_MODE2_2352_RAW
= 2352 * 16,
87 IDOFF_MODE2_2352
= 2352 * 16 + 24,
88 IDOFF_MODE2_2336
= 2336 * 16 + 16,
89 IDOFF_NRG
= 2048 * 16 + 307200,
91 int iso_offsets
[] = {IDOFF_ISO_2048
, IDOFF_MODE2_2336
, IDOFF_MODE2_2352_RAW
, IDOFF_NRG
};
92 // try to find CD001 identifier
94 for(i
= 0; i
< 4; i
++) {
95 if(lseek(fd
, iso_offsets
[i
], SEEK_SET
) == -1) {
96 // perror("can`t lseek() to next possible data start position; is it really supported file?");
97 perror("Unsupported file");
100 ssize_t size
= read(fd
, vd
, sizeof(struct iso_volume_descriptor
));
101 if(size
!= sizeof(struct iso_volume_descriptor
)) {
102 // fprintf(stderr, "only %d bytes read from position %d, %d required; is it really supported file?\n",
103 // size, iso_offsets[i], sizeof(struct iso_volume_descriptor));
104 perror("Unsupported file");
107 char *vd_id
= (char *) vd
->id
;
108 if(strncmp("CD001", vd_id
, 5) == 0) {
110 // fill context with information about block size and block offsets
111 context
.id_offset
= iso_offsets
[i
];
112 switch(iso_offsets
[i
]) {
117 case IDOFF_MODE2_2352_RAW
:
118 context
.block_size
= 2352;
120 case IDOFF_MODE2_2336
:
121 context
.block_size
= 2336;
122 context
.block_offset
= 16;
125 context
.file_offset
= 307200;
131 } else if(strncmp("CD001", vd_id
+ 16, 5) == 0) {
132 context
.id_offset
= iso_offsets
[i
] + 16;
133 context
.block_size
= 2352;
134 context
.block_offset
= 16;
136 } else if(strncmp("CD001", vd_id
+ 24, 5) == 0) {
137 context
.id_offset
= iso_offsets
[i
] + 24;
138 context
.block_size
= 2352;
139 context
.block_offset
= 24;
144 /* printf("CD001 found at %d, bs %d, boff %d, ds %d\n",
145 context.id_offset, context.block_size, context.block_offset, context.data_size);*/
147 if(lseek(fd
, context
.block_size
* (16 + vd_num
) +
148 context
.block_offset
+ context
.file_offset
, SEEK_SET
) == -1) {
149 // perror("can`t lseek() to next volume descriptor");
152 ssize_t size
= read(fd
, vd
, sizeof(struct iso_volume_descriptor
));
153 if(size
!= sizeof(struct iso_volume_descriptor
)) {
154 // fprintf(stderr, "only %d bytes read from volume descriptor %d, %d required\n",
155 // size, vd_num, sizeof(struct iso_volume_descriptor));
159 int vd_type
= isonum_711((unsigned char *)vd
->type
);
160 // printf("init: found volume descriptor type %d, vd_num %d\n", vd_type, vd_num);
162 if(strncmp("CD001", vd
->id
, 5) != 0) {
165 // fprintf(stderr, "init: wrong standard identifier in volume descriptor %d, exiting..\n", vd_num);
169 // fprintf(stderr, "init: wrong standard identifier in volume descriptor %d, skipping..\n", vd_num);
174 // check if this is only primary descriptor found
175 if(context
.pd
.type
[0]) {
176 // fprintf(stderr, "init: primary volume descriptor already found, skipping..\n");
178 memcpy(& context
.pd
, vd
, sizeof(struct iso_volume_descriptor
));
179 context
.root
= (struct iso_directory_record
*)& context
.pd
.root_directory_record
;
180 context
.data_size
= isonum_723(context
.pd
.logical_block_size
);
182 if(!context
.block_size
) {
183 // fprintf(stderr, "init: wrong block data size %d, using default 2048\n", context.data_size);
184 context
.data_size
= 2048;
187 if(context
.block_size
!= 2048) {
188 // report unusual data block size
190 // printf("Data block size: %d\n", context.block_size);
193 if(isofs_check_rr(context
.root
)) {
194 context
.pd_have_rr
= 1;
199 case ISO_VD_SUPPLEMENTARY
:
201 struct iso_supplementary_descriptor
*sd
= (struct iso_supplementary_descriptor
*) vd
;
203 if(!context
.pd
.type
[0]) {
204 // fprintf(stderr, "init: supplementary volume descriptor found, but no primary descriptor!\n");
207 int joliet_level
= 0;
209 if(sd
->escape
[0] == 0x25 && sd
->escape
[1] == 0x2f) {
210 switch(sd
->escape
[2]) {
224 isofs_check_rr((struct iso_directory_record
*) sd
->root_directory_record
);
226 // switch to SVD only if it contain RRIP or if PVD have no RRIP
227 // in other words, prefer VD with RRIP
228 if((joliet_level
&& have_rr
) ||
229 (have_rr
&& !context
.pd_have_rr
) ||
230 (joliet_level
&& !context
.pd_have_rr
)) {
232 context
.joliet_level
= joliet_level
;
233 memcpy(& context
.sd
, vd
, sizeof(struct iso_volume_descriptor
));
234 context
.supplementary
= 1;
236 context
.root
= (struct iso_directory_record
*) context
.sd
.root_directory_record
;
238 // printf("init: switching to supplementary descriptor %d, joliet_level %d, have_rr %d\n",
239 // vd_num, context.joliet_level, have_rr);
241 context
.joliet_level
= 0;
242 // printf("init: found supplementary descriptor %d, flags %d\n",
243 // vd_num, isonum_711(sd->flags));
250 // boot record, not intresting..
259 // fprintf(stderr, "init: unsupported volume descriptor type %d, vd_num %d\n",
269 if(!context
.pd
.type
[0]) {
270 // fprintf(stderr, "init: primary volume descriptor not found! exiting..\n");
275 context
.susp_skip
= 0;
277 lookup_table
= g_hash_table_new(g_str_hash
, g_str_equal
);
278 negative_lookup_table
= g_hash_table_new(g_str_hash
, g_str_equal
);
280 isofs_inode
*inode
= (isofs_inode
*) malloc(sizeof(isofs_inode
));
282 // perror("Can`t malloc: ");
285 memset(inode
, 0, sizeof(isofs_inode
));
286 inode
->record
= context
.root
;
287 context
.last_ino
++; // set to 1
288 inode
->st_ino
= context
.last_ino
;
291 g_hash_table_insert(lookup_table
, "/", inode
);
296 static char* dstr(char* str
, const char* src
, int len
) {
298 strncpy(str
, src
, len
);
300 for(i
= len
- 1; i
>= 0; --i
) {
301 if(str
[i
] == '\0' || str
[i
] == ' ' || str
[i
] == '\t' || str
[i
] == '\r' || str
[i
] == '\n') {
310 void* isofs_real_init() {
311 /* if(context.file_offset == 307200) {
312 printf("NRG image found\n");
313 } else if(context.block_size == 2048) {
314 printf("ISO9660 image found\n");
315 } else if(context.block_size == 2352 && context.block_offset == 0) {
316 printf("MODE2 RAW BIN image found\n");
317 } else if(context.block_size == 2352 && context.block_offset == 16) {
318 printf("MODE1 BIN image found (or CCD MODE1 image, or MDF image)\n");
319 } else if(context.block_size == 2352 && context.block_offset == 24) {
320 printf("MODE2 BIN image found (or CCD MODE2 image)\n");
321 } else if(context.block_size == 2336 && context.block_offset == 16) {
322 printf("MODE2/2336 BIN image found\n");
324 printf("UNKNOWN image found; probably will not work\n");
327 if(context.block_size != 2048) {
328 // report unusual data block size
329 printf("Data block size: %d\n", context.block_size);
334 printf("System Identifier : %s\n", dstr(buf, context.pd.system_id, 32));
335 printf("Volume Identifier : %.32s\n", dstr(buf, context.pd.volume_id, 32));
336 printf("Volume Set Identifier : %.128s\n", dstr(buf, context.pd.volume_set_id, 128));
337 printf("Publisher Identifier : %.128s\n", dstr(buf, context.pd.publisher_id, 128));
338 printf("Data Preparer Identifier : %.128s\n", dstr(buf, context.pd.preparer_id, 128));
339 printf("Application Identifier : %.128s\n", dstr(buf, context.pd.application_id, 128));
340 printf("Copyright File Identifier : %.37s\n", dstr(buf, context.pd.copyright_file_id, 37));
341 printf("Abstract File Identifier : %.37s\n", dstr(buf, context.pd.abstract_file_id, 37));
342 printf("Bibliographic File Identifier : %.37s\n", dstr(buf, context.pd.bibliographic_file_id, 37));
343 printf("Volume Creation Date and Time : %.17s\n", dstr(buf, context.pd.creation_date, 17));
344 printf("Volume Modification Date and Time : %.17s\n", dstr(buf, context.pd.modification_date, 17));
345 printf("Volume Expiration Date and Time : %.17s\n", dstr(buf, context.pd.expiration_date, 17));
346 printf("Volume Effective Date and Time : %.17s\n", dstr(buf, context.pd.effective_date, 17));
348 return (void*) &context
;
351 static int isofs_check_rr(struct iso_directory_record
*root_record
) {
352 int extent
= isonum_733(root_record
->extent
);
353 char *buf
= (char *) malloc(context
.data_size
); // can we use "standard" 2048 there?
355 // perror("Can`t malloc: ");
359 int rc
= isofs_read_raw_block(extent
, buf
);
365 struct iso_directory_record
*record
= (struct iso_directory_record
*) buf
;
366 size_t record_length
= isonum_711((unsigned char*) record
->length
);
367 size_t name_len
= isonum_711(record
->name_len
);
368 size_t pad_len
= ((name_len
& 1) ? 0 : 1); // padding byte if name_len is even
369 size_t sa_len
= record_length
- name_len
- sizeof(struct iso_directory_record
) - pad_len
;
370 if(record_length
< sizeof(struct iso_directory_record
)) {
371 // fprintf(stderr, "check_rr: directory record length too small: %d\n", record_length);
376 // fprintf(stderr, "check_rr: file name length too big for . record: %d\n", name_len);
381 // probably something wrong with name_len
382 // fprintf(stderr, "check_rr: wrong name_len in directory entry: %d, record_length %d\n",
383 // name_len, record_length);
390 struct rock_ridge
*sue
= (struct rock_ridge
*) (((char *) record
) +
391 sizeof(struct iso_directory_record
) +
394 int sue_sig
= SIG(sue
->signature
[0], sue
->signature
[1]);
395 int sue_len
= sue
->len
;
396 int sue_version
= sue
->version
;
398 if(sue_sig
== SIG('S', 'P')) {
399 if(sue_len
!= 7 || sue_version
!= 1 || sue
->u
.SP
.magic
[0] != 0xbe || sue
->u
.SP
.magic
[1] != 0xef) {
400 // incorrect SP entry
414 // no space for SP record
424 static isofs_inode
*isofs_lookup(const char *path
) {
425 if(path
[0] == '\0') {
428 isofs_inode
*inode
= g_hash_table_lookup(lookup_table
, path
);
432 if(g_hash_table_lookup(negative_lookup_table
, path
)) {
435 // printf("start search for %s\n", path);
436 gchar
**parts
= g_strsplit(path
, "/", -1);
437 guint parts_len
= local_g_strv_length(parts
);
439 gchar
*rpath
= g_strdup("/");
441 gchar
*part
= parts
[partno
];
442 while(part
&& partno
< parts_len
) {
443 rpath1
= g_strconcat(rpath1
, "/", part
, NULL
);
444 // printf("looking for %s in %s...\n", rpath1, rpath);
445 inode
= g_hash_table_lookup(lookup_table
, rpath1
);
447 // printf("trying to load %s...\n", rpath);
448 int rc
= isofs_real_readdir(rpath
, NULL
, NULL
);
450 // fprintf(stderr, "lookup: error %d from readdir: %s\n", rc, strerror(-rc));
457 part
= parts
[partno
];
463 inode
= g_hash_table_lookup(lookup_table
, path
);
465 g_hash_table_insert(negative_lookup_table
, g_strdup(path
), negative_value
);
470 static int isofs_read_raw_block(int block
, char *buf
) {
471 off_t off
= block
* context
.block_size
+ context
.block_offset
+ context
.file_offset
;
472 if(pthread_mutex_lock(& fd_mutex
)) {
474 // perror("isofs_read_raw_block: can`l lock fd_mutex");
477 if(lseek(context
.fd
, off
, SEEK_SET
) == -1) {
478 // perror("isofs_read_raw_block: can`t lseek()");
479 pthread_mutex_unlock(& fd_mutex
);
482 size_t len
= read(context
.fd
, buf
, context
.data_size
);
483 if(len
!= context
.data_size
) {
484 // fprintf(stderr, "isofs_read_raw_block: can`t read full block, read only %d bytes from offset %d, %d required; errno %d, message %s\n",
485 // len, (int) off, context.data_size, errno, strerror(errno));
486 // fprintf(stderr, "isofs_read_raw_block: huh? reading zeros beyond file end? someone want to save a penny?\n");
487 // memset(buf + len, 0, context.data_size - len);
488 // pthread_mutex_unlock(& fd_mutex);
491 pthread_mutex_unlock(& fd_mutex
);
492 // printf("block %d, offset %d, read %d\n", block, (int) off, len);
496 static time_t isofs_date(char *stamp
, int stamp_len
) {
498 memset(& tm
, 0, sizeof(struct tm
));
500 if(stamp_len
== 7) { // ISO9660:9.1.5
501 tm
.tm_year
= stamp
[0];
502 tm
.tm_mon
= stamp
[1] - 1;
503 tm
.tm_mday
= stamp
[2];
504 tm
.tm_hour
= stamp
[3];
505 tm
.tm_min
= stamp
[4];
506 tm
.tm_sec
= stamp
[5];
508 tm
.tm_gmtoff
= stamp
[6] * 15 * 60;
509 } else if(stamp_len
== 17) { // ISO9660:8.4.26.1
510 // fprintf(stderr, "isofs_date: 17 byte date isn`t supported for the moment, sorry\n");
513 // fprintf(stderr, "isofs_date: unsupported date format, stamp_len %d\n", stamp_len);
518 // fprintf(stderr, "direntry2stat: non-zero timezone offset: %d\n", tm.tm_gmtoff);
520 time_t time
= mktime(& tm
);
525 static int isofs_direntry2stat(struct stat
*st
, isofs_inode
*inode
) {
526 struct iso_directory_record
*record
= inode
->record
;
528 // fill st_ino from block number where file start
529 // since there is no files begin in the same block
530 // st->st_ino = isonum_733(record->extent);
531 // but some iso images save space by sharing content between several files
532 // so it is better to save it unique
533 st
->st_ino
= inode
->st_ino
;
535 if(inode
->ZF
) { // compressed file, report real (uncompressed) size
536 st
->st_size
= inode
->real_size
;
537 } else { // no zisofs compression
538 st
->st_size
= isonum_733(record
->size
);
541 st
->st_blocks
= st
->st_size
/ context
.data_size
; // should not be to meaningful even for zisofs compression
542 st
->st_blksize
= context
.data_size
;
543 st
->st_nlink
= 1; // always, even if rrip PX entry found
545 if(inode
->PX
) { // rrip PX entry found and in effect
546 st
->st_mode
= inode
->st
.st_mode
;
547 st
->st_uid
= inode
->st
.st_uid
;
548 st
->st_gid
= inode
->st
.st_gid
;
550 /// TODO use hidden flag?
551 if(ISO_FLAGS_DIR(record
->flags
)) {
552 st
->st_mode
= S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
|
553 S_IXUSR
| S_IXGRP
| S_IXOTH
; // dir, readabale and browsable by everyone
555 st
->st_mode
= S_IFREG
| S_IRUSR
| S_IRGRP
| S_IROTH
; // regular, read by everyone
559 if(inode
->TF
) { // rrip TF entry found and in effect
560 st
->st_atime
= inode
->st
.st_atime
;
561 st
->st_ctime
= inode
->st
.st_ctime
;
562 st
->st_mtime
= inode
->st
.st_mtime
;
565 inode
->ctime
= isofs_date(record
->date
, 7);
568 st
->st_atime
= inode
->ctime
;
569 st
->st_ctime
= inode
->ctime
;
570 st
->st_mtime
= inode
->ctime
;
576 static char *isofs_fix_entry(char *entry
, size_t len
) {
577 if(!context
.joliet_level
) { // iso9660 names
578 char *sep2
= index(entry
, ';'); // find SEPARATOR2
579 if(sep2
) { // remove remaining part
582 char *sep1
= rindex(entry
, '.'); // find SEPARATOR1
583 if(sep1
&& sep1
[1] == '\0') { // check if SEPARATOR1 is a last symbol in string
584 *sep1
= '\0'; // remove it
587 // this part is borrowed from linux kernel code
588 // convert remaining ';' and '/' characters to dots
589 // and lowercase characters in range A-Z
592 if(*p
== ';' || *p
== '/') {
594 } else if(*p
>= 'A' && *p
<= 'Z') {
603 // initialize iconv descriptor
604 iconv_t cd
= iconv_open(iocharset
, "UCS-2BE");
611 size_t inbytesleft
= len
;
613 char *outbuf
= (char *) malloc(NAME_MAX
); // this should be sufficient for our purposes
615 // perror("Can`t malloc: ");
618 char *outentry
= outbuf
;
619 size_t outbytesleft
= NAME_MAX
;
621 int rc
= iconv(cd
, & inbuf
, & inbytesleft
, & outbuf
, & outbytesleft
);
622 size_t outlen
= NAME_MAX
- outbytesleft
;
623 outentry
[outlen
] = '\0';
625 // incorrect multibyte char or other iconv error -- return as much as possible anyway
626 // fprintf(stderr, "iconv on '%s': %s\n", outentry, strerror(errno));
636 // printf("outlen %d, outbytesleft %d, rc %d, outbuf %s\n", outlen, outbytesleft, rc, outentry);
638 // borrowed from linux kernel isofs joliet code
639 if(outlen
> 2 && outentry
[outlen
- 2] == ';' && outentry
[outlen
- 1] == '1') {
640 outentry
[outlen
- 2] = '\0';
642 if(outlen
>= 2 && outentry
[outlen
- 1] == '.') {
643 outentry
[outlen
- 1] = '\0';
653 static void isofs_free_inode(isofs_inode
*inode
) {
654 if(inode
->SL
&& inode
->sl
) {
657 if(inode
->NM
&& inode
->nm
) {
660 if(inode
->zf_blockptr
) {
661 free(inode
->zf_blockptr
);
669 // borrowed from zisofs-tools
670 static const unsigned char zisofs_magic
[8] = {
671 0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07
674 static int isofs_parse_zisofs_header(isofs_inode
*inode
) {
675 char *buf
= (char *) malloc(context
.block_size
);
677 // perror("Can`t malloc: ");
681 int block_num
= isonum_733(inode
->record
->extent
);
682 int len
= isofs_read_raw_block(block_num
, buf
);
687 if(len
< inode
->zf_header_size
) {
688 // fprintf(stderr, "isofs_parse_zisofs_header: too small block len %d\n", len);
693 zf_file_header
*zf_header
= (zf_file_header
*) buf
;
695 if(memcmp(zf_header
->magic
, zisofs_magic
, sizeof(zisofs_magic
))) {
696 // invalid compressed file header
701 size_t block_size
= 1 << inode
->zf_block_shift
;
703 inode
->zf_nblocks
= ((inode
->real_size
+ inode
->zf_header_size
- 1) / block_size
) + 1;
705 size_t block_table_size
= (inode
->zf_nblocks
+ 1) * 4;
706 if(!inode
->zf_blockptr
) {
707 inode
->zf_blockptr
= (int *) malloc(block_table_size
);
708 if(!inode
->zf_blockptr
) {
709 // perror("Can`t malloc: ");
714 // copy offset table into memory buffer, maintaining iso9660 block boundaries
716 int block_table_left
= block_table_size
;
717 int block_table_total
= 0;
718 int block_table_shift
= inode
->zf_header_size
;
720 while(block_table_left
) {
721 size_t block_table_chunk
=
722 (block_table_left
< context
.data_size
- block_table_shift
?
723 block_table_left
: context
.data_size
- block_table_shift
);
725 /* printf("isofs_parse_sa: block_table_size: %d, block_table_left: %d, block_table_total %d, block_table_shift %d, block_table_chunk %d\n",
726 block_table_size, block_table_left, block_table_total, block_table_shift, block_table_chunk);*/
728 memcpy(((char *) inode
->zf_blockptr
) + block_table_total
, buf
+ block_table_shift
, block_table_chunk
);
730 block_table_left
-= block_table_chunk
;
731 block_table_total
+= block_table_chunk
;
732 block_table_shift
= 0;
736 len
= isofs_read_raw_block(block_num
, buf
);
742 /* printf("isofs_parse_sa: block_num: %d, len: %d\n",
746 /* printf("isofs_parse_zisofs_header: real size %d, header size %d, nblocks %d, block size %d\n",
747 inode->real_size, inode->zf_header_size,
748 inode->zf_nblocks, block_size);
750 for(i = 0; i <= inode->zf_nblocks; i++) {
751 printf("zf block table entry %d have value %d\n", i, inode->zf_blockptr[i]);
754 // all information for compressed file we have already in ZF entry
755 // so just signal what this is really compressed file
760 static int isofs_parse_sa(isofs_inode
*inode
, char *sa
, size_t sa_len
) {
765 int remaining
= sa_len
;
766 while(remaining
> 4) { // susp 4.
767 // printf("parse_sa: sa offset %d, remaining %d\n", sa_len - remaining, remaining);
768 struct rock_ridge
*sue
= (struct rock_ridge
*) (sa
+ sa_len
- remaining
);
769 int sue_sig
= SIG(sue
->signature
[0], sue
->signature
[1]);
770 int sue_len
= sue
->len
;
771 int sue_version
= sue
->version
;
772 /* printf("parse_sa: signature %c%c, sue_len %d, sue_version %d\n",
773 sue->signature[0], sue->signature[1], sue_len, sue_version);*/
778 case SIG('S', 'P'): // susp 5.3
779 if(sue_len
!= 7 || sue_version
!= 1 || sue
->u
.SP
.magic
[0] != 0xbe || sue
->u
.SP
.magic
[1] != 0xef) {
780 // incorrect SP entry
782 "parse_sa: incorrect SP entry: sue_len %d, sue_version %d, magic %c%c\n",
783 sue_len, sue_version, sue->u.SP.magic[0], sue->u.SP.magic[1]);*/
788 context
.susp_skip
= sue
->u
.SP
.skip
;
790 // printf("parse_sa: SP entry, skip %d\n", sue->u.SP.skip);
792 case SIG('C', 'E'): // susp 5.1
793 if(sue_len
!= 28 || sue_version
!= 1) {
794 // incorrect entry, skip
796 "parse_sa: incorrect CE entry: sue_len %d, sue_version %d\n",
797 sue_len, sue_version);*/
798 } else if(cont_block
!= 0) { // CE entry already found
800 "parse_sa: duplicate CE entry, skipping, sue_len %d, sue_version %d\n",
801 sue_len, sue_version);*/
803 cont_block
= isonum_733(sue
->u
.CE
.extent
);
804 cont_offset
= isonum_733(sue
->u
.CE
.offset
);
805 cont_size
= isonum_733(sue
->u
.CE
.size
);
807 if(cont_block
< 16) {
808 // continuation area can`t be there
810 "parse_sa: wrong continuation area extent: %d, cont_offset %d, cont_size %d\n",
811 cont_block, cont_offset, cont_size);*/
812 cont_block
= 0; // do not process it
813 } else if(cont_offset
+ cont_size
> context
.data_size
) {
814 // something wrong with continuation area offset and/or size
816 "parse_sa: wrong continuation area: extent %d, cont_offset %d, cont_size %d\n",
817 cont_block, cont_offset, cont_size);'/
818 cont_block = 0; // do not process it
820 /* printf("parse_sa: CE entry, extent %d, offset %d, size %d\n",
821 cont_block, cont_offset, cont_size);*/
825 case SIG('E', 'R'): // susp 5.5
826 if(sue_version
!= 1) {
827 // incorrect entry, skip
829 "parse_sa: incorrect ER entry: sue_len %d, sue_version %d\n",
830 sue_len, sue_version);*/
832 int len_id
= sue
->u
.ER
.len_id
;
833 int len_des
= sue
->u
.ER
.len_des
;
834 int len_src
= sue
->u
.ER
.len_src
;
835 int ext_ver
= sue
->u
.ER
.ext_ver
;
836 if(len_id
+ len_des
+ len_src
+ 8 > sue_len
) {
838 "parse_sa: incorrect ER entry: sue_len %d, sue_version %d, len_id %d, len_des %d, len_src %d, ext_ver %d\n",
839 sue_len, sue_version, len_id, len_des, len_src, ext_ver);*/
845 strncpy(id
, sue
->u
.ER
.data
, len_id
);
847 strncpy(des
, sue
->u
.ER
.data
+ len_id
, len_des
);
849 strncpy(src
, sue
->u
.ER
.data
+ len_id
+ len_des
, len_src
);
852 /* printf("parse_sa: ER entry:\n\t id: %s\n\tdes: %s\n\tsrc: %s\n\tver: %d\n",
853 id, des, src, ext_ver);*/
860 isonum_711((unsigned char *) sue
->u
.RR
.flags
);
861 /* printf("parse_sa: RR entry, sue_version %d, sue_len %d, flags %d\n",
862 sue_version, sue_len, rr_flags);*/
865 case SIG('P', 'X'): // rrip 4.1.1
866 // according to rrip 4.1.1, length of PX record should be exactly 44
867 // but linux kernel and mkisofs seems to be happy with length 36,
868 // where 'serial number' are not presented
869 // (or i`m looking at outdated draft.. :-)
870 if((sue_len
!= 44 && sue_len
!= 36) || sue_version
!= 1) {
871 // incorrect entry, skip
873 "parse_sa: incorrect PX entry: sue_len %d, sue_version %d\n",
874 sue_len, sue_version);*/
876 mode_t mode
= isonum_733(sue
->u
.PX
.mode
);
877 nlink_t nlink
= isonum_733(sue
->u
.PX
.n_links
);
878 uid_t uid
= isonum_733(sue
->u
.PX
.uid
);
879 gid_t gid
= isonum_733(sue
->u
.PX
.gid
);
880 /* printf("parse_sa: PX entry, sue_version %d, sue_len %d, mode %d, nlinks %d, uid %d, gid %d\n",
881 sue_version, sue_len, mode, nlink, uid, gid);*/
882 inode
->st
.st_mode
= mode
;
883 inode
->st
.st_nlink
= nlink
;
884 inode
->st
.st_uid
= uid
;
885 inode
->st
.st_gid
= gid
;
887 /// TODO check if entry length == 44 and set st_ino field from 'file serial number'?
890 case SIG('S', 'L'): // rrip 4.1.3
891 if(sue_version
!= 1) {
892 // incorrect entry, skip
894 "parse_sa: incorrect SL entry: sue_len %d, sue_version %d\n",
895 sue_len, sue_version);*/
896 } else if(inode
->SL
) {
898 "parse_sa: SL entry already in effect, sue_len %d, sue_version %d\n",
899 sue_len, sue_version);*/
901 int sl_flags
= sue
->u
.SL
.flags
;
902 int max_components
= (sue_len
- 5) / sizeof(struct SL_component
);
904 if(max_components
< 1) {
906 "parse_sa: SL entry found, but no components: sue_len %d, sue_version %d\n",
907 sue_len, sue_version);*/
912 for(c
= 0; c
< max_components
; c
++) {
913 struct SL_component
*comp
=
914 (struct SL_component
*)
915 (((char *) & sue
->u
.SL
.link
) + c_offset
);
917 int sl_c_flags
= comp
->flags
;
918 int sl_c_len
= comp
->len
;
920 if(c_offset
+ 5 >= sue_len
) {
921 // according to rrip, we must stop if CONTINUE flag isn`t set
922 // according to linux kernel isofs code and images produced witj mkisofs
923 // we need to continue while there is space in SL entry for next component
928 // "parse_sa: invalid SL component: sue_len %d, sue_version %d, sl_flags %d, sl_c_flags %d, sl_c_len %d\n",
929 // sue_len, sue_version, sl_flags, sl_c_flags, sl_c_len);
933 /// TODO find _working_ rrip specification
937 char c_separator
= 0;
938 if(!inode
->sl_len
) { // nothing found previoustly
939 } else if(inode
->sl_len
== 1 && inode
->sl
[0] == '/') { // previous SL component was ROOT
940 // no need for separator after ROOT component
942 c_len
+= 1; // place for '/' separator
945 if(sl_c_flags
& (1 << 1)) { // CURRENT component
946 c_len
+= 1; // place for '.' character
947 } else if(sl_c_flags
& (1 << 2)) { // PARENT component
948 c_len
+= 2; // place for ".." characters
953 if(c_len
+ inode
->sl_len
+ 1 > PATH_MAX
) {
955 "parse_sa: too long symlink found: sue_len %d, sue_version %d, sl_flags %d, sl_c_flags %d, sl_c_len %d, c_len %d\n",
956 sue_len, sue_version, sl_flags, sl_c_flags, sl_c_len, c_len);*/
962 inode
->sl
= (char *) malloc(PATH_MAX
);
964 // perror("Can`t malloc: ");
970 inode
->sl
[inode
->sl_len
] = c_separator
;
974 if(sl_c_flags
& (1 << 1)) { // CURRENT component
975 inode
->sl
[inode
->sl_len
] = '.';
977 inode
->sl
[inode
->sl_len
] = '\0';
978 /* printf("parse_sa: SL CURRENT component, sl_c_flags %d, sl_c_len %d, sl_len %d, sl %s\n",
979 sl_c_flags, sl_c_len, inode->sl_len, inode->sl);*/
980 } else if(sl_c_flags
& (1 << 2)) { // PARENT component
981 inode
->sl
[inode
->sl_len
] = '.';
983 inode
->sl
[inode
->sl_len
] = '.';
985 inode
->sl
[inode
->sl_len
] = '\0';
986 /* printf("parse_sa: SL PARENT component, sl_c_flags %d, sl_c_len %d, sl_len %d, sl %s\n",
987 sl_c_len, inode->sl_len, inode->sl);*/
988 } else if(sl_c_flags
& (1 << 3)) { // ROOT component (?! does not documented at all)
989 inode
->sl
[inode
->sl_len
] = '/';
991 inode
->sl
[inode
->sl_len
] = '\0';
992 /* printf("parse_sa: SL ROOT component, sl_c_flags %d, sl_c_len %d, sl_len %d, sl %s\n",
993 sl_c_len, inode->sl_len, inode->sl);*/
995 strncpy(inode
->sl
+ inode
->sl_len
, comp
->text
, sl_c_len
);
996 inode
->sl_len
+= sl_c_len
;
997 inode
->sl
[inode
->sl_len
] = '\0';
998 /* printf("parse_sa: SL component, sl_c_flags %d, sl_c_len %d, sl_len %d, sl %s\n",
999 sl_c_flags, sl_c_len, inode->sl_len, inode->sl);*/
1002 // according to rrip, we must stop if CONTINUE flag isn`t set
1003 // according to linux kernel isofs code and images produced witj mkisofs
1004 // we need to continue while there is space in SL entry for next component
1005 c_offset
+= (2 + sl_c_len
);
1007 // strict rrip code:
1008 // if(sl_c_flags & 1) { // CONTINUE
1009 // c_offset += 2 + sl_c_len;
1011 // printf("parse_sa: SL final component, sl_c_len %d, sl_c_flags %d, sl_len %d, sl %s\n",
1012 // sl_c_len, sl_c_flags, inode->sl_len, inode->sl);
1018 // printf("parse_sa: errors found while processing SL components, cleaning\n");
1024 } else if(!(sl_flags
& 1) && inode
->sl
) {
1025 /* printf("parse_sa: SL entry (final), sue_len %d, sue_version %d, sl_len %d, sl %s\n",
1026 sue_len, sue_version, inode->sl_len, inode->sl);*/
1028 } else if(!(sl_flags
& 1) && !inode
->sl
) {
1029 /* fprintf(stderr, "parse_sa: final SL entry found, but no SL components, cleaning\n");*/
1035 } else if(inode
->sl
) {
1036 /* printf("parse_sa: SL entry, sue_len %d, sue_version %d, sl_len %d, sl %s\n",
1037 sue_len, sue_version, inode->sl_len, inode->sl);*/
1039 /* fprintf(stderr, "parse_sa: empty SL entry?\n");*/
1044 case SIG('N', 'M'): // rrip 4.1.4
1045 if(sue_version
!= 1) {
1046 // incorrect entry, skip
1048 "parse_sa: incorrect NM entry: sue_len %d, sue_version %d\n",
1049 sue_len, sue_version);*/
1051 int nm_flags
= sue
->u
.NM
.flags
;
1052 if(nm_flags
& (1 << 1)) { // CURRENT bit
1053 /* printf("parse_sa: NM CURRENT entry, sue_version %d, sue_len %d, flags %d\n",
1054 sue_version, sue_len, nm_flags);*/
1055 } else if(nm_flags
& (1 << 2)) { // PARENT bit
1056 /* printf("parse_sa: NM PARENT entry, sue_version %d, sue_len %d, flags %d\n",
1057 sue_version, sue_len, nm_flags);*/
1059 if(sue_len
- 5 + inode
->nm_len
> NAME_MAX
- 1) {
1061 /* "parse_sa: too long NM entry: %d\n",
1062 sue_len - 5 + inode->nm_len);
1063 } else if(inode->NM) {
1065 "parse_sa: NM entry already in effect, sue_len %d, sue_version %d\n", */
1066 sue_len
, sue_version
);
1069 inode
->nm
= (char *) malloc(NAME_MAX
);
1071 // perror("Can`t malloc: ");
1076 strncpy(inode
->nm
+ inode
->nm_len
, sue
->u
.NM
.name
, sue_len
- 5);
1077 inode
->nm_len
+= sue_len
- 5;
1078 inode
->nm
[inode
->nm_len
] = '\0';
1080 if(!nm_flags
& 1) { // CONTINUE bit
1082 /* printf("parse_sa: NM entry (final), flags %d, len %d, name %s\n",
1083 nm_flags, sue_len - 5, inode->nm);*/
1085 /* printf("parse_sa: NM entry (part), flags %d, len %d, name %s\n",
1086 nm_flags, sue_len - 5, inode->nm);*/
1092 case SIG('C', 'L'): // rrip 4.1.5.1
1093 if(sue_version
!= 1 || sue_len
!= 12) {
1094 // incorrect entry, skip
1096 "parse_sa: incorrect CL entry: sue_len %d, sue_version %d\n",
1097 sue_len, sue_version);*/
1099 int cl_block
= isonum_733(sue
->u
.CL
.location
);
1100 /* printf("parse_sa: CL entry, block %d\n",
1103 inode
->cl_block
= cl_block
;
1105 // read block pointed by CL record and process first directory entry
1106 char *buf
= (char *) malloc(context
.data_size
);
1108 // perror("Can`t malloc: ");
1111 int rc
= isofs_read_raw_block(inode
->cl_block
, buf
);
1117 struct iso_directory_record
*record
= (struct iso_directory_record
*) buf
;
1118 size_t record_length
= isonum_711((unsigned char *) record
->length
);
1119 size_t name_len
= isonum_711(record
->name_len
);
1120 size_t pad_len
= ((name_len
& 1) ? 0 : 1); // padding byte if name_len is even
1121 size_t sa_len
= record_length
- name_len
- sizeof(struct iso_directory_record
) - pad_len
;
1122 /* printf("boff %d, record length %d, name_len %d, pad_len %d, sa_len %d\n",
1123 (int) boff, record_length, name_len, pad_len, sa_len);*/
1124 if(record_length
< sizeof(struct iso_directory_record
)) {
1125 /* fprintf(stderr, "parse_sa: CL entry: directory record length too small: %d\n", record_length);*/
1130 /* fprintf(stderr, "parse_sa: file name length too big for . record: %d\n", name_len);*/
1135 // probably something wrong with name_len
1136 /* fprintf(stderr, "parse_sa: CL record: wrong name_len in directory entry: %d, record_length %d\n",
1137 name_len, record_length);*/
1142 // ignoring anything from original record
1143 struct iso_directory_record
*cl_record
=
1144 (struct iso_directory_record
*) malloc(sizeof(struct iso_directory_record
));
1146 // perror("Can`t malloc: ");
1149 memcpy(cl_record
, record
, sizeof(struct iso_directory_record
));
1151 // drop existing record
1153 free(inode
->record
);
1156 // replace record with new one
1157 inode
->record
= cl_record
;
1159 // parse sa entries from relocated directory . record
1160 rc
= isofs_parse_sa(inode
,
1162 sizeof(struct iso_directory_record
) +
1163 name_len
+ pad_len
+ context
.susp_skip
,
1173 case SIG('P', 'L'): // rrip 4.1.5.2
1174 if(sue_version
!= 1 || sue_len
!= 12) {
1175 // incorrect entry, skip
1177 "parse_sa: incorrect PL entry: sue_len %d, sue_version %d\n",
1178 sue_len, sue_version);*/
1180 int pl_block
= isonum_733(sue
->u
.PL
.location
);
1181 /* printf("parse_sa: PL entry, block %d\n",
1183 // probably we don`t need process PL record with FUSE
1185 inode
->pl_block
= pl_block
;
1188 case SIG('R', 'E'): // rrip 4.1.5.3
1189 if(sue_version
!= 1 || sue_len
!= 4) {
1190 // incorrect entry, skip
1192 "parse_sa: incorrect RE entry: sue_len %d, sue_version %d\n",
1193 sue_len, sue_version);*/
1195 // printf("parse_sa: RE entry\n");
1199 case SIG('T', 'F'): // rrip 4.1.6
1200 if(sue_version
!= 1) {
1201 // incorrect entry, skip
1203 "parse_sa: incorrect TF entry: sue_len %d, sue_version %d\n",
1204 sue_len, sue_version);*/
1206 int tf_flags
= sue
->u
.TF
.flags
;
1208 if(tf_flags
& TF_LONG_FORM
) {
1209 // iso9660:8.4.26.1 format
1212 // iso9660:9.1.5 format
1221 // ctime can be stored as CREATION time
1222 if(tf_flags
& TF_CREATE
) {
1223 ctime
= isofs_date(((char *) sue
) + 5 + stamp_length
* stamp_no
, stamp_length
);
1226 if(tf_flags
& TF_MODIFY
) {
1227 mtime
= isofs_date(((char *) sue
) + 5 + stamp_length
* stamp_no
, stamp_length
);
1230 if(tf_flags
& TF_ACCESS
) {
1231 atime
= isofs_date(((char *) sue
) + 5 + stamp_length
* stamp_no
, stamp_length
);
1234 // ctime should be stored in ATTRIBUTES stamp according to rrip 4.1.6
1235 if(tf_flags
& TF_ATTRIBUTES
) {
1236 ctime
= isofs_date(((char *) sue
) + 5 + stamp_length
* stamp_no
, stamp_length
);
1239 // other fields have no meaning for us
1241 /* printf("parse_sa: TF entry, sue_version %d, sue_len %d, ctime %d, mtime %d, atime %d\n",
1242 sue_version, sue_len, ctime, mtime, atime);*/
1243 inode
->st
.st_ctime
= ctime
;
1244 inode
->st
.st_mtime
= mtime
;
1245 inode
->st
.st_atime
= atime
;
1249 case SIG('S', 'F'): // rrip 4.1.7
1250 if(sue_version
!= 1 || sue_len
!= 21) {
1251 // incorrect entry, skip
1253 "parse_sa: incorrect SF entry: sue_len %d, sue_version %d\n",
1254 sue_len, sue_version);*/
1256 /// TODO does anyone support SF entries? linux isofs code does not..
1258 "parse_sa: SF entries (sparse files) are unsupported in this version, sorry..\n");*/
1261 case SIG('Z', 'F'): // non-standard linux extension (zisofs)
1262 if(sue_version
!= 1 || sue_len
!= 16) {
1263 // incorrect entry, skip
1265 "parse_sa: incorrect ZF entry: sue_len %d, sue_version %d\n",
1266 sue_len, sue_version);*/
1267 } else if(SIG(sue
->u
.ZF
.algorithm
[0], sue
->u
.ZF
.algorithm
[1]) == SIG('p', 'z')) {
1268 inode
->zf_algorithm
[0] = sue
->u
.ZF
.algorithm
[0];
1269 inode
->zf_algorithm
[1] = sue
->u
.ZF
.algorithm
[1];
1270 inode
->zf_header_size
= ((unsigned char) sue
->u
.ZF
.parms
[0]) << 2;
1271 inode
->zf_block_shift
= (unsigned char) sue
->u
.ZF
.parms
[1];
1272 inode
->zf_size
= (inode
->st
.st_size
? inode
->st
.st_size
: isonum_733(inode
->record
->size
));
1273 inode
->real_size
= isonum_733(sue
->u
.ZF
.real_size
);
1274 // check if file is really compressed, ignore ZF entry otherwise
1275 int rc
= isofs_parse_zisofs_header(inode
);
1277 // printf("parse_sa: ZF entry found, algorithm %02x%02x, header size %d, block shift %d, compressed size %d, real size %d\n",
1278 // inode->zf_algorithm[0], inode->zf_algorithm[1],
1279 // inode->zf_header_size, inode->zf_block_shift,
1280 // inode->zf_size, inode->real_size);
1283 /* fprintf(stderr, "parse_sa: ZF entry found, but file is not really compressed\n");*/
1284 } else { // some error occur
1289 "parse_sa: unknown ZF compression algorithm %c%c, sorry..\n",
1290 sue->u.ZF.algorithm[0], sue->u.ZF.algorithm[1]);*/
1295 /* fprintf(stderr, "parse_sa: unknown entry '%c%c', sue_sig %d, sue_version %d, sue_len %d\n",
1296 sue->signature[0], sue->signature[1],
1297 sue_sig, sue_version, sue_len);*/
1301 if(sue_len
>= 4 && known_sue
) {
1302 remaining
-= sue_len
;
1303 } else if(known_sue
) {
1304 /* fprintf(stderr, "parse_sa: inappropriate susp entry length: %d, signature %c%c\n",
1305 sue_len, sue->signature[0], sue->signature[1]);*/
1307 } else { // probably there are no more susp entries
1312 // process continuation area if found
1314 char *buf
= (char *) malloc(context
.data_size
);
1316 // perror("Can`t malloc: ");
1319 int rc
= isofs_read_raw_block(cont_block
, buf
);
1324 /* printf("parse_sa: deep into CE, extent %d, offset %d, size %d\n",
1325 cont_block, cont_offset, cont_size);*/
1326 rc
= isofs_parse_sa(inode
, buf
+ cont_offset
, cont_size
);
1338 int isofs_real_opendir(const char *path
) {
1339 isofs_inode
*inode
= isofs_lookup(path
);
1341 // fprintf(stderr, "opendir: know nothing about %s\n", path);
1344 if(!ISO_FLAGS_DIR(inode
->record
->flags
)) {
1345 // fprintf(stderr, "opendir: %s not a dir\n", path);
1351 int isofs_real_readdir(const char *path
, void *filler_buf
, isofs_dir_fill_t filler
) {
1352 if(path
[0] == '\0') {
1353 // fprintf(stderr, "readdir: attempt to read empty path name\n");
1356 isofs_inode
*current_inode
= isofs_lookup(path
);
1357 if(!current_inode
) {
1358 // fprintf(stderr, "readdir: know nothing about %s\n", path);
1361 struct iso_directory_record
*current
= current_inode
->record
;
1362 if(!ISO_FLAGS_DIR(current
->flags
)) {
1363 // fprintf(stderr, "readdir: %s not a dir\n", path);
1367 size_t current_size
= isonum_733(current
->size
);
1369 int block
= isonum_733(current
->extent
);
1370 char *buf
= (char *) malloc(context
.data_size
);
1372 // perror("Can`t malloc: ");
1376 // printf("path %s, current_size %d, block %d\n", path, current_size, block);
1378 size_t total_size
= 0;
1380 int block_count
= 0;
1383 while(total_size
<= current_size
- sizeof(struct iso_directory_record
)) {
1384 rc
= isofs_read_raw_block(block
, buf
);
1388 if(rc
!= context
.data_size
) {
1390 // fprintf(stderr, "readdir: can`t read whole block, read only %d bytes, block %d\n", rc, block);
1397 total_size
+= (context
.data_size
- boff
);
1401 while(boff
+ sizeof(struct iso_directory_record
) <= context
.data_size
&&
1402 total_size
<= current_size
- sizeof(struct iso_directory_record
)) {
1404 struct iso_directory_record
*record
= (struct iso_directory_record
*) (buf
+ boff
);
1405 size_t record_length
= isonum_711((unsigned char *) record
->length
);
1406 size_t name_len
= isonum_711(record
->name_len
);
1407 size_t pad_len
= ((name_len
& 1) ? 0 : 1); // padding byte if name_len is even
1408 size_t sa_len
= record_length
- name_len
- sizeof(struct iso_directory_record
) - pad_len
;
1410 // printf("block %d, boff %d, total_size %d, current_size %d, record length %d, name_len %d, pad_len %d, sa_len %d\n",
1411 // block, (int) boff, total_size, current_size, record_length, name_len, pad_len, sa_len);
1412 if(record_length
== 0) {
1413 // possible end of directory or end of block
1414 total_size
+= (context
.data_size
- boff
);
1418 if(record_length
< sizeof(struct iso_directory_record
)) {
1419 if(count
> 2) { // check if . and .. is already read
1420 // possible end of directory
1421 // at least mkisofs does not set iso_directory_record.size correct
1422 // (this is much possible it was my fault and misunderstanding -- dmiceman)
1423 // but we need to try next block to be sure
1424 /// TODO this is not clear: what to do if next block not contain next directory?
1425 total_size
+= (context
.data_size
- boff
);
1429 // fprintf(stderr, "readdir: directory record length too small: %d\n", record_length);
1434 if(name_len
> NAME_MAX
- 1) {
1435 // fprintf(stderr, "readdir: file name length too big: %d\n", name_len);
1440 // probably something wrong with name_len
1441 // fprintf(stderr, "readdir: wrong name_len in directory entry: %d, record_length %d\n",
1442 // name_len, record_length);
1446 if(count
> 2 && name_len
== 1 && record
->name
[0] == 0) {
1447 // looks like this is normal situation to meet another directory because
1448 // there is no clear way to find directory end
1449 // fprintf(stderr, "readdir: next directory found while processing another directory! boff %d, total_size %d, current_size %d, block %d, count %d\n",
1450 // (int) boff, total_size, current_size, block, count);
1454 isofs_inode
*inode
= (isofs_inode
*) malloc(sizeof(isofs_inode
));
1456 // perror("Can`t malloc: ");
1459 memset(inode
, 0, sizeof(isofs_inode
));
1460 inode
->st_ino
= context
.last_ino
;
1463 struct iso_directory_record
*n_rec
=
1464 (struct iso_directory_record
*) malloc (sizeof(struct iso_directory_record
));
1466 // perror("Can`t malloc: ");
1469 memcpy(n_rec
, record
, sizeof(struct iso_directory_record
));
1470 inode
->record
= n_rec
;
1472 if(context
.susp
|| path
[1] == '\0') { // if susp is known to be present or this is a root dir ("/")
1473 /* printf("sa offset %d, sa_len %d\n",
1474 sizeof(struct iso_directory_record) + name_len + pad_len, sa_len);*/
1475 rc
= isofs_parse_sa(inode
,
1476 ((char *) record
) + sizeof(struct iso_directory_record
) + name_len
+ pad_len
+ context
.susp_skip
,
1480 isofs_free_inode(inode
);
1485 char *entry
= (char *) malloc(NAME_MAX
);
1487 // perror("Can`t malloc: ");
1490 if(count
== 1) { // . entry ('\0' on disk)
1492 } else if(count
== 2) { // .. entry ('\1' on disk)
1493 strcpy(entry
, "..");
1494 } else { // regular entry
1495 if(inode
->NM
) { // rrip NM entry present and in effect
1496 // printf("readdir: NM entry is in effect\n");
1497 strncpy(entry
, inode
->nm
, inode
->nm_len
);
1498 entry
[inode
->nm_len
] = '\0';
1499 } else { // regular ISO9660 filename
1500 // printf("readdir: no NM entry found, name len %d\n", name_len);
1501 // because there can be '\0' characters because using of UCS-2 encoding we need to use memcpy
1502 memcpy(entry
, (char *) record
->name
, name_len
);
1503 entry
[name_len
] = '\0';
1505 // fixup entry -- lowercase, strip leading ';', etc..
1506 entry
= isofs_fix_entry(entry
, name_len
);
1508 // fprintf(stderr, "readdir: error during entry fixup\n");
1509 isofs_free_inode(inode
);
1516 // fprintf(stderr, "%d -- %s\n\n", count, entry);
1520 memset(& st
, '\0', sizeof(struct stat
));
1521 isofs_direntry2stat(& st
, inode
);
1522 rc
= filler(filler_buf
, entry
, & st
, 0);
1524 // printf("readdir: filler return with %d, entry %s\n", rc, entry);
1525 isofs_free_inode(inode
);
1532 char absolute_entry
[PATH_MAX
];
1533 strcpy(absolute_entry
, path
);
1534 if(path
[1] != '\0') { // not root dir
1535 strcat(absolute_entry
, "/");
1537 strcat(absolute_entry
, entry
);
1538 if(g_hash_table_lookup(lookup_table
, absolute_entry
)) {
1539 // already in lookup cache
1540 isofs_free_inode(inode
);
1542 g_hash_table_insert(lookup_table
, g_strdup(absolute_entry
), inode
);
1547 boff
+= record_length
;
1548 total_size
+= record_length
;
1562 int isofs_real_getattr(const char *path
, struct stat
*stbuf
) {
1563 isofs_inode
*inode
= isofs_lookup(path
);
1565 // this error occur too often when browsing mounted tree with konqueror --
1566 // it check existence of .directory file with stat()
1567 // fprintf(stderr, "getattr: know nothing about %s\n", path);
1570 // printf("getattr: found %s, size %d\n", path, isonum_733(inode->record->size));
1572 memset(stbuf
, 0, sizeof(struct stat
));
1573 isofs_direntry2stat(stbuf
, inode
);
1574 /* if(ISO_FLAGS_DIR(inode->record->flags)) {
1575 printf("%s %i %i\n", path, (int) stbuf->st_size, stbuf->st_mode);
1580 int isofs_real_readlink(const char *path
, char *target
, size_t size
) {
1581 isofs_inode
*inode
= isofs_lookup(path
);
1583 // fprintf(stderr, "readlink: know nothing about %s\n", path);
1586 if(!inode
->PX
|| !inode
->SL
|| !S_ISLNK(inode
->st
.st_mode
)) {
1587 // fprintf(stderr, "readlink: %s not a link\n", path);
1590 strncpy(target
, inode
->sl
, size
- 1);
1591 target
[size
- 1] = '\0';
1595 int isofs_real_open(const char *path
) {
1596 isofs_inode
*inode
= isofs_lookup(path
);
1598 // fprintf(stderr, "open: know nothing about %s\n", path);
1601 if(ISO_FLAGS_DIR(inode
->record
->flags
)) {
1602 // fprintf(stderr, "open: %s not a file\n", path);
1605 if(ISO_FLAGS_HIDDEN(inode
->record
->flags
)) {
1606 // fprintf(stderr, "open: %s is a hidden file\n", path);
1612 static int isofs_real_read_zf(isofs_inode
*inode
, char *out_buf
, size_t size
, off_t offset
) {
1613 int zf_block_size
= 1 << inode
->zf_block_shift
;
1614 int zf_start
= offset
/ zf_block_size
;
1615 int zf_end
= (offset
+ size
) / zf_block_size
;
1616 // protection against cornercase when read request is exactly equal to the uncompressed file size.
1617 // -- Ryan Thomas 2007-06-13
1618 if( (offset
+ size
) % zf_block_size
== 0 ) {
1621 int shift
= offset
% zf_block_size
;
1623 // printf("zf_start %d, zf_end %d, size %d, offset %d, shift %d\n",
1624 // zf_start, zf_end, size, (int) offset, shift);
1626 // protection against some ununderstandable errors
1627 if(zf_start
>= inode
->zf_nblocks
) {
1628 zf_start
= inode
->zf_nblocks
- 1;
1630 if(zf_end
>= inode
->zf_nblocks
) {
1631 zf_end
= inode
->zf_nblocks
- 1;
1633 if(zf_end
< 0 || zf_start
< 0) {
1637 unsigned char *cbuf
= (unsigned char *) malloc(zf_block_size
* 2);
1639 // perror("Can`t malloc: ");
1642 unsigned char *ubuf
= (unsigned char *) malloc(zf_block_size
);
1644 // perror("Can`t malloc: ");
1648 size_t total_size
= 0;
1649 size_t size_left
= size
;
1651 int base_offset
= isonum_733(inode
->record
->extent
) * context
.data_size
;
1654 for(i
= zf_start
; i
<= zf_end
; i
++) {
1655 int block_offset
= isonum_731((char *) (& inode
->zf_blockptr
[i
]));
1656 int block_end
= isonum_731((char *) (& inode
->zf_blockptr
[i
+ 1]));
1657 int block_size
= block_end
- block_offset
;
1659 if(block_size
== 0) { // sort of sparce file block
1660 size_t payload_size
= (zf_block_size
- shift
< size_left
? zf_block_size
- shift
: size_left
);
1661 memset(out_buf
+ total_size
, 0, payload_size
);
1663 total_size
+= payload_size
;
1664 size_left
-= payload_size
;
1665 } else if(block_size
> zf_block_size
* 2) {
1666 /* fprintf(stderr, "isofs_real_read_zf: compressed block size bigger than uncompressed block size * 2, something is wrong there.. block size %d, uncompressed block size %d\n",
1667 block_size, zf_block_size);*/
1672 // we do not use isofs_read_raw_block() there because it is simpler to access
1673 // compressed blocks directly
1675 int image_off
= base_offset
+ block_offset
;
1677 if(pthread_mutex_lock(& fd_mutex
)) {
1679 // perror("isofs_real_read_zf: can`l lock fd_mutex");
1684 if(lseek(context
.fd
, image_off
, SEEK_SET
) == -1) {
1685 // perror("isofs_real_read_zf: can`t lseek()");
1686 pthread_mutex_unlock(& fd_mutex
);
1691 size_t len
= read(context
.fd
, cbuf
, block_size
);
1692 if(len
!= block_size
) {
1693 /* fprintf(stderr, "isofs_real_read_zf: can`t read full block, errno %d, message %s\n",
1694 errno, strerror(errno));*/
1695 pthread_mutex_unlock(& fd_mutex
);
1700 pthread_mutex_unlock(& fd_mutex
);
1702 // compressed block is read from disk, now uncompress() it
1704 uLongf usize
= zf_block_size
;
1705 int rc
= uncompress(ubuf
, &usize
, cbuf
, block_size
);
1709 // fprintf(stderr, "isofs_real_read_zf: uncompress() error %i: %s\n", rc, strerror(rc));
1713 // ubuf contain uncompressed data, usize contain uncompressed block size
1715 size_t payload_size
= (usize
- shift
< size_left
? usize
- shift
: size_left
);
1716 memcpy(out_buf
+ total_size
, ubuf
+ shift
, payload_size
);
1718 total_size
+= payload_size
;
1719 size_left
-= payload_size
;
1722 // shift is only meaningful for first block
1729 // printf("total size %d\n", total_size);
1734 int isofs_real_read(const char *path
, char *out_buf
, size_t size
, off_t offset
) {
1735 isofs_inode
*inode
= isofs_lookup(path
);
1737 // fprintf(stderr, "read: know nothing about %s\n", path);
1740 struct iso_directory_record
*record
= inode
->record
;
1741 if(ISO_FLAGS_DIR(record
->flags
)) {
1742 // fprintf(stderr, "read: %s not a file\n", path);
1745 if(ISO_FLAGS_HIDDEN(record
->flags
)) {
1746 // fprintf(stderr, "read: %s is a hidden file\n", path);
1750 if(inode
->ZF
) { // this file is compressed, handle it specially
1751 return isofs_real_read_zf(inode
, out_buf
, size
, offset
);
1754 size_t fsize
= isonum_733(record
->size
);
1755 if(offset
+ size
> fsize
) {
1756 size
= fsize
- offset
;
1762 int start_block
= isonum_733(record
->extent
);
1763 if(start_block
== 0) { // empty file
1767 int start
= offset
/ context
.data_size
;
1768 int end
= (offset
+ size
) / context
.data_size
;
1769 int shift
= offset
% context
.data_size
;
1770 int block
= start_block
+ start
;
1771 // printf("read: path %s, size %d, offset %d, fsize %d, start %d, end %d, shift %d\n",
1772 // path, size, (int) offset, fsize, start, end, shift);
1774 char *buf
= (char *) malloc(context
.data_size
);
1776 // perror("Can't malloc: ");
1781 size_t total_size
= 0;
1782 size_t size_left
= size
;
1785 for(i
= start
; i
<= end
; i
++) {
1786 int len
= isofs_read_raw_block(block
, buf
);
1791 // printf("read: block %d, len %d, size_left %d\n", block, len, size_left);
1793 if(len
> size_left
) {
1799 memcpy(out_buf
+ count
* context
.data_size
, buf
+ shift
, len
- shift
);
1811 int isofs_real_statfs(struct statfs
*stbuf
) {
1812 stbuf
->f_type
= ISOFS_SUPER_MAGIC
;
1813 stbuf
->f_bsize
= context
.data_size
; // or PAGE_CACHE_SIZE?
1814 stbuf
->f_blocks
= 0; // while it is possible to calculate this, i see no reasons to do so
1816 stbuf
->f_bavail
= 0;
1819 stbuf
->f_namelen
= NAME_MAX
- 1; // ? not sure..