VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_iso9660.c@ 46284

Last change on this file since 46284 was 44529, checked in by vboxsync, 12 years ago

header (C) fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.2 KB
Line 
1/* $Id: fsw_iso9660.c 44529 2013-02-04 15:54:15Z vboxsync $ */
2/** @file
3 * fsw_iso9660.c - ISO9660 file system driver code.
4 *
5 * Current limitations:
6 * - Files must be in one extent (i.e. Level 2)
7 * - No Joliet or Rock Ridge extensions
8 * - No interleaving
9 * - inode number generation strategy fails on volumes > 2 GB
10 * - No blocksizes != 2048
11 * - No High Sierra or anything else != 'CD001'
12 * - No volume sets with directories pointing at other volumes
13 * - No extended attribute records
14 */
15
16/*
17 * Copyright (C) 2010-2012 Oracle Corporation
18 *
19 * This file is part of VirtualBox Open Source Edition (OSE), as
20 * available from http://www.virtualbox.org. This file is free software;
21 * you can redistribute it and/or modify it under the terms of the GNU
22 * General Public License (GPL) as published by the Free Software
23 * Foundation, in version 2 as it comes in the "COPYING" file of the
24 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
25 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
26 */
27
28/*-
29 * This code is based on:
30 *
31 * Copyright (c) 2006 Christoph Pfisterer
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions are
35 * met:
36 *
37 * * Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 *
40 * * Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the
43 * distribution.
44 *
45 * * Neither the name of Christoph Pfisterer nor the names of the
46 * contributors may be used to endorse or promote products derived
47 * from this software without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
50 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
51 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
52 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
53 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
55 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
59 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60 */
61
62#include "fsw_iso9660.h"
63
64
65// functions
66
67static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol);
68static void fsw_iso9660_volume_free(struct fsw_iso9660_volume *vol);
69static fsw_status_t fsw_iso9660_volume_stat(struct fsw_iso9660_volume *vol, struct fsw_volume_stat *sb);
70
71static fsw_status_t fsw_iso9660_dnode_fill(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno);
72static void fsw_iso9660_dnode_free(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno);
73static fsw_status_t fsw_iso9660_dnode_stat(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
74 struct fsw_dnode_stat *sb);
75static fsw_status_t fsw_iso9660_get_extent(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
76 struct fsw_extent *extent);
77
78static fsw_status_t fsw_iso9660_dir_lookup(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
79 struct fsw_string *lookup_name, struct fsw_iso9660_dnode **child_dno);
80static fsw_status_t fsw_iso9660_dir_read(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
81 struct fsw_shandle *shand, struct fsw_iso9660_dnode **child_dno);
82static fsw_status_t fsw_iso9660_read_dirrec(struct fsw_iso9660_volume *vol, struct fsw_shandle *shand, struct iso9660_dirrec_buffer *dirrec_buffer);
83
84static fsw_status_t fsw_iso9660_readlink(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
85 struct fsw_string *link);
86
87static fsw_status_t rr_find_sp(struct iso9660_dirrec *dirrec, struct fsw_rock_ridge_susp_sp **psp);
88static fsw_status_t rr_find_nm(struct fsw_iso9660_volume *vol, struct iso9660_dirrec *dirrec, int off, struct fsw_string *str);
89static fsw_status_t rr_read_ce(struct fsw_iso9660_volume *vol, union fsw_rock_ridge_susp_ce *ce, fsw_u8 *begin);
90//
91// Dispatch Table
92//
93
94struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(iso9660) = {
95 { FSW_STRING_TYPE_ISO88591, 4, 4, "iso9660" },
96 sizeof(struct fsw_iso9660_volume),
97 sizeof(struct fsw_iso9660_dnode),
98
99 fsw_iso9660_volume_mount,
100 fsw_iso9660_volume_free,
101 fsw_iso9660_volume_stat,
102 fsw_iso9660_dnode_fill,
103 fsw_iso9660_dnode_free,
104 fsw_iso9660_dnode_stat,
105 fsw_iso9660_get_extent,
106 fsw_iso9660_dir_lookup,
107 fsw_iso9660_dir_read,
108 fsw_iso9660_readlink,
109};
110
111static fsw_status_t rr_find_sp(struct iso9660_dirrec *dirrec, struct fsw_rock_ridge_susp_sp **psp)
112{
113 fsw_u8 *r;
114 int off = 0;
115 struct fsw_rock_ridge_susp_sp *sp;
116 r = (fsw_u8 *)((fsw_u8 *)dirrec + sizeof(*dirrec) + dirrec->file_identifier_length);
117 off = (int)(r - (fsw_u8 *)dirrec);
118 while(off < dirrec->dirrec_length)
119 {
120 if (*r == 'S')
121 {
122 sp = (struct fsw_rock_ridge_susp_sp *)r;
123 if( sp->e.sig[0] == 'S'
124 && sp->e.sig[1] == 'P'
125 && sp->magic[0] == 0xbe
126 && sp->magic[1] == 0xef)
127 {
128 *psp = sp;
129 return FSW_SUCCESS;
130 }
131 }
132 r++;
133 off = (int)(r - (fsw_u8 *)dirrec);
134 }
135 *psp = NULL;
136 return FSW_NOT_FOUND;
137}
138
139static fsw_status_t rr_find_nm(struct fsw_iso9660_volume *vol, struct iso9660_dirrec *dirrec, int off, struct fsw_string *str)
140{
141 fsw_u8 *r, *begin;
142 int fCe = 0;
143 struct fsw_rock_ridge_susp_nm *nm;
144 int limit = dirrec->dirrec_length;
145 begin = (fsw_u8 *)dirrec;
146 r = (fsw_u8 *)dirrec + off;
147 str->data = NULL;
148 str->len = 0;
149 str->size = 0;
150 str->type = 0;
151 while(off < limit)
152 {
153 if (r[0] == 'C' && r[1] == 'E' && r[2] == 28)
154 {
155 int rc;
156 int ce_off;
157 union fsw_rock_ridge_susp_ce *ce;
158 if (fCe == 0)
159 fsw_alloc_zero(ISO9660_BLOCKSIZE, (void *)&begin);
160 fCe = 1;
161 DEBUG((DEBUG_WARN, "%a:%d we found CE before NM or its continuation\n", __FILE__, __LINE__));
162 ce = (union fsw_rock_ridge_susp_ce *)r;
163 limit = ISOINT(ce->X.len);
164 ce_off = ISOINT(ce->X.offset);
165 rc = rr_read_ce(vol, ce, begin);
166 if (rc != FSW_SUCCESS)
167 {
168 fsw_free(begin);
169 return rc;
170 }
171 begin += ce_off;
172 r = begin;
173 }
174 if (r[0] == 'N' && r[1] == 'M')
175 {
176 nm = (struct fsw_rock_ridge_susp_nm *)r;
177 if( nm->e.sig[0] == 'N'
178 && nm->e.sig[1] == 'M')
179 {
180 int len = 0;
181 fsw_u8 *tmp = NULL;
182 if (nm->flags & RR_NM_CURR)
183 {
184 fsw_memdup(str->data, ".", 1);
185 str->len = 1;
186 goto done;
187 }
188 if (nm->flags & RR_NM_PARE)
189 {
190 fsw_memdup(str->data, "..", 2);
191 str->len = 2;
192 goto done;
193 }
194 len = nm->e.len - sizeof(struct fsw_rock_ridge_susp_nm) + 1;
195 fsw_alloc_zero(str->len + len, (void **)&tmp);
196 if (str->data != NULL)
197 {
198 fsw_memcpy(tmp, str->data, str->len);
199 fsw_free(str->data);
200 }
201 DEBUG((DEBUG_INFO, "dst:%p src:%p len:%d\n", tmp + str->len, &nm->name[0], len));
202 fsw_memcpy(tmp + str->len, &nm->name[0], len);
203 str->data = tmp;
204 str->len += len;
205
206 if ((nm->flags & RR_NM_CONT) == 0);
207 goto done;
208 }
209 }
210 r++;
211 off = (int)(r - (fsw_u8 *)begin);
212 }
213 if(fCe == 1)
214 fsw_free(begin);
215 return FSW_NOT_FOUND;
216done:
217 str->type = FSW_STRING_TYPE_ISO88591;
218 str->size = str->len;
219 if(fCe == 1)
220 fsw_free(begin);
221 return FSW_SUCCESS;
222}
223
224static fsw_status_t rr_read_ce(struct fsw_iso9660_volume *vol, union fsw_rock_ridge_susp_ce *ce, fsw_u8 *begin)
225{
226 int rc;
227 rc = vol->g.host_table->read_block(&vol->g, ISOINT(ce->X.block_loc), begin);
228 if (rc != FSW_SUCCESS)
229 return rc;
230 return FSW_SUCCESS;
231}
232/**
233 * Mount an ISO9660 volume. Reads the superblock and constructs the
234 * root directory dnode.
235 */
236
237static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol)
238{
239 fsw_status_t status;
240 void *buffer;
241 fsw_u32 blockno;
242 struct iso9660_volume_descriptor *voldesc;
243 struct iso9660_primary_volume_descriptor *pvoldesc;
244 fsw_u32 voldesc_type;
245 int i;
246 struct fsw_string s;
247 struct iso9660_dirrec rootdir;
248 int sua_pos;
249 char *sig;
250 int skip;
251 struct fsw_rock_ridge_susp_entry *entry;
252
253 // read through the Volume Descriptor Set
254 fsw_set_blocksize(vol, ISO9660_BLOCKSIZE, ISO9660_BLOCKSIZE);
255 blockno = ISO9660_SUPERBLOCK_BLOCKNO;
256
257 do {
258 status = fsw_block_get(vol, blockno, 0, &buffer);
259 if (status)
260 return status;
261
262 voldesc = (struct iso9660_volume_descriptor *)buffer;
263 voldesc_type = voldesc->volume_descriptor_type;
264 if (fsw_memeq(voldesc->standard_identifier, "CD001", 5)) {
265 // descriptor follows ISO 9660 standard
266 if (voldesc_type == 1 && voldesc->volume_descriptor_version == 1) {
267 // suitable Primary Volume Descriptor found
268 if (vol->primary_voldesc) {
269 fsw_free(vol->primary_voldesc);
270 vol->primary_voldesc = NULL;
271 }
272 status = fsw_memdup((void **)&vol->primary_voldesc, voldesc, ISO9660_BLOCKSIZE);
273 }
274 } else if (!fsw_memeq(voldesc->standard_identifier, "CD", 2)) {
275 // completely alien standard identifier, stop reading
276 voldesc_type = 255;
277 }
278
279 fsw_block_release(vol, blockno, buffer);
280 blockno++;
281 } while (!status && voldesc_type != 255);
282 if (status)
283 return status;
284
285 // get information from Primary Volume Descriptor
286 if (vol->primary_voldesc == NULL)
287 return FSW_UNSUPPORTED;
288 pvoldesc = vol->primary_voldesc;
289 if (ISOINT(pvoldesc->logical_block_size) != 2048)
290 return FSW_UNSUPPORTED;
291
292 // get volume name
293 for (i = 32; i > 0; i--)
294 if (pvoldesc->volume_identifier[i-1] != ' ')
295 break;
296 s.type = FSW_STRING_TYPE_ISO88591;
297 s.size = s.len = i;
298 s.data = pvoldesc->volume_identifier;
299 status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
300 if (status)
301 return status;
302
303 // setup the root dnode
304 status = fsw_dnode_create_root(vol, ISO9660_SUPERBLOCK_BLOCKNO << ISO9660_BLOCKSIZE_BITS, &vol->g.root);
305 if (status)
306 return status;
307 fsw_memcpy(&vol->g.root->dirrec, &pvoldesc->root_directory, sizeof(struct iso9660_dirrec));
308
309 if ( pvoldesc->escape[0] == 0x25
310 && pvoldesc->escape[1] == 0x2f
311 && ( pvoldesc->escape[2] == 0x40
312 || pvoldesc->escape[2] == 0x43
313 || pvoldesc->escape[2] == 0x45))
314 {
315 FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (joliet!!!)\n")));
316 vol->fJoliet = 1;
317 }
318
319
320 rootdir = pvoldesc->root_directory;
321 sua_pos = (sizeof(struct iso9660_dirrec)) + rootdir.file_identifier_length + (rootdir.file_identifier_length % 2) - 2;
322 //int sua_size = rootdir.dirrec_length - rootdir.file_identifier_length;
323 //FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (SUA(pos:%x, sz:%d)!!!)\n"), sua_pos, sua_size));
324
325#if 1
326 status = fsw_block_get(vol, ISOINT(rootdir.extent_location), 0, &buffer);
327 sig = (char *)buffer + sua_pos;
328 skip = 0;
329 entry = (struct fsw_rock_ridge_susp_entry *)sig;
330 if ( entry->sig[0] == 'S'
331 && entry->sig[1] == 'P')
332 {
333 struct fsw_rock_ridge_susp_sp *sp = (struct fsw_rock_ridge_susp_sp *)entry;
334 if (sp->magic[0] == 0xbe && sp->magic[1] == 0xef)
335 {
336 vol->fRockRidge = 1;
337 } else {
338 FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: SP magic isn't valid\n")));
339 }
340 skip = sp->skip;
341 }
342#endif
343 // release volume descriptors
344 fsw_free(vol->primary_voldesc);
345 vol->primary_voldesc = NULL;
346
347
348 FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success\n")));
349
350 return FSW_SUCCESS;
351}
352
353/**
354 * Free the volume data structure. Called by the core after an unmount or after
355 * an unsuccessful mount to release the memory used by the file system type specific
356 * part of the volume structure.
357 */
358
359static void fsw_iso9660_volume_free(struct fsw_iso9660_volume *vol)
360{
361 if (vol->primary_voldesc)
362 fsw_free(vol->primary_voldesc);
363}
364
365/**
366 * Get in-depth information on a volume.
367 */
368
369static fsw_status_t fsw_iso9660_volume_stat(struct fsw_iso9660_volume *vol, struct fsw_volume_stat *sb)
370{
371 sb->total_bytes = 0; //(fsw_u64)vol->sb->s_blocks_count * vol->g.log_blocksize;
372 sb->free_bytes = 0;
373 return FSW_SUCCESS;
374}
375
376/**
377 * Get full information on a dnode from disk. This function is called by the core
378 * whenever it needs to access fields in the dnode structure that may not
379 * be filled immediately upon creation of the dnode. In the case of iso9660, we
380 * delay fetching of the inode structure until dnode_fill is called. The size and
381 * type fields are invalid until this function has been called.
382 */
383
384static fsw_status_t fsw_iso9660_dnode_fill(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno)
385{
386 // get info from the directory record
387 dno->g.size = ISOINT(dno->dirrec.data_length);
388 if (dno->dirrec.file_flags & 0x02)
389 dno->g.type = FSW_DNODE_TYPE_DIR;
390 else
391 dno->g.type = FSW_DNODE_TYPE_FILE;
392
393 return FSW_SUCCESS;
394}
395
396/**
397 * Free the dnode data structure. Called by the core when deallocating a dnode
398 * structure to release the memory used by the file system type specific part
399 * of the dnode structure.
400 */
401
402static void fsw_iso9660_dnode_free(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno)
403{
404}
405
406/**
407 * Get in-depth information on a dnode. The core makes sure that fsw_iso9660_dnode_fill
408 * has been called on the dnode before this function is called. Note that some
409 * data is not directly stored into the structure, but passed to a host-specific
410 * callback that converts it to the host-specific format.
411 */
412
413static fsw_status_t fsw_iso9660_dnode_stat(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
414 struct fsw_dnode_stat *sb)
415{
416 sb->used_bytes = (dno->g.size + (ISO9660_BLOCKSIZE-1)) & ~(ISO9660_BLOCKSIZE-1);
417 /*
418 sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime);
419 sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime);
420 sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime);
421 sb->store_attr_posix(sb, dno->raw->i_mode);
422 */
423
424 return FSW_SUCCESS;
425}
426
427/**
428 * Retrieve file data mapping information. This function is called by the core when
429 * fsw_shandle_read needs to know where on the disk the required piece of the file's
430 * data can be found. The core makes sure that fsw_iso9660_dnode_fill has been called
431 * on the dnode before. Our task here is to get the physical disk block number for
432 * the requested logical block number.
433 */
434
435static fsw_status_t fsw_iso9660_get_extent(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
436 struct fsw_extent *extent)
437{
438 // Preconditions: The caller has checked that the requested logical block
439 // is within the file's size. The dnode has complete information, i.e.
440 // fsw_iso9660_dnode_read_info was called successfully on it.
441
442 extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
443 extent->phys_start = ISOINT(dno->dirrec.extent_location);
444 extent->log_start = 0;
445 extent->log_count = (ISOINT(dno->dirrec.data_length) + (ISO9660_BLOCKSIZE-1)) >> ISO9660_BLOCKSIZE_BITS;
446 return FSW_SUCCESS;
447}
448
449/**
450 * Lookup a directory's child dnode by name. This function is called on a directory
451 * to retrieve the directory entry with the given name. A dnode is constructed for
452 * this entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called
453 * and the dnode is actually a directory.
454 */
455
456static fsw_status_t fsw_iso9660_dir_lookup(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
457 struct fsw_string *lookup_name, struct fsw_iso9660_dnode **child_dno_out)
458{
459 fsw_status_t status;
460 struct fsw_shandle shand;
461 struct iso9660_dirrec_buffer dirrec_buffer;
462 struct iso9660_dirrec *dirrec = &dirrec_buffer.dirrec;
463
464 // Preconditions: The caller has checked that dno is a directory node.
465
466 // setup handle to read the directory
467 status = fsw_shandle_open(dno, &shand);
468 if (status)
469 return status;
470
471 // scan the directory for the file
472 while (1) {
473 // read next entry
474 status = fsw_iso9660_read_dirrec(vol, &shand, &dirrec_buffer);
475 if (status)
476 goto errorexit;
477 if (dirrec->dirrec_length == 0) {
478 // end of directory reached
479 status = FSW_NOT_FOUND;
480 goto errorexit;
481 }
482
483 // skip . and ..
484 if (dirrec->file_identifier_length == 1 &&
485 (dirrec->file_identifier[0] == 0 || dirrec->file_identifier[0] == 1))
486 continue;
487
488 // compare name
489 if (fsw_streq(lookup_name, &dirrec_buffer.name)) // TODO: compare case-insensitively
490 break;
491 }
492
493 // setup a dnode for the child item
494 status = fsw_dnode_create(dno, dirrec_buffer.ino, FSW_DNODE_TYPE_UNKNOWN, &dirrec_buffer.name, child_dno_out);
495 if (status == FSW_SUCCESS)
496 fsw_memcpy(&(*child_dno_out)->dirrec, dirrec, sizeof(struct iso9660_dirrec));
497
498errorexit:
499 fsw_shandle_close(&shand);
500 return status;
501}
502
503/**
504 * Get the next directory entry when reading a directory. This function is called during
505 * directory iteration to retrieve the next directory entry. A dnode is constructed for
506 * the entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called
507 * and the dnode is actually a directory. The shandle provided by the caller is used to
508 * record the position in the directory between calls.
509 */
510
511static fsw_status_t fsw_iso9660_dir_read(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
512 struct fsw_shandle *shand, struct fsw_iso9660_dnode **child_dno_out)
513{
514 fsw_status_t status;
515 struct iso9660_dirrec_buffer dirrec_buffer;
516 struct iso9660_dirrec *dirrec = &dirrec_buffer.dirrec;
517
518 // Preconditions: The caller has checked that dno is a directory node. The caller
519 // has opened a storage handle to the directory's storage and keeps it around between
520 // calls.
521 /* (vasily) directory nodes are 4096 bytes that is two logical blocks so read dir operation
522 * should read both blocks.
523 */
524
525 while (1) {
526 // read next entry
527 if (shand->pos >= dno->g.size)
528 return FSW_NOT_FOUND; // end of directory
529 status = fsw_iso9660_read_dirrec(vol, shand, &dirrec_buffer);
530 if (status)
531 return status;
532 if (dirrec->dirrec_length == 0)
533 {
534 // try the next block
535 shand->pos =(shand->pos & ~(vol->g.log_blocksize - 1)) + vol->g.log_blocksize;
536 continue;
537 }
538
539 // skip . and ..
540 if (dirrec->file_identifier_length == 1 &&
541 (dirrec->file_identifier[0] == 0 || dirrec->file_identifier[0] == 1))
542 continue;
543 break;
544 }
545
546 // setup a dnode for the child item
547 status = fsw_dnode_create(dno, dirrec_buffer.ino, FSW_DNODE_TYPE_UNKNOWN, &dirrec_buffer.name, child_dno_out);
548 if (status == FSW_SUCCESS)
549 fsw_memcpy(&(*child_dno_out)->dirrec, dirrec, sizeof(struct iso9660_dirrec));
550
551 return status;
552}
553
554/**
555 * Read a directory entry from the directory's raw data. This internal function is used
556 * to read a raw iso9660 directory entry into memory. The shandle's position pointer is adjusted
557 * to point to the next entry.
558 */
559
560static fsw_status_t fsw_iso9660_read_dirrec(struct fsw_iso9660_volume *vol, struct fsw_shandle *shand, struct iso9660_dirrec_buffer *dirrec_buffer)
561{
562 fsw_status_t status;
563 fsw_u32 i, buffer_size, remaining_size, name_len;
564 struct fsw_rock_ridge_susp_sp *sp = NULL;
565 struct iso9660_dirrec *dirrec = &dirrec_buffer->dirrec;
566 int sp_off;
567 int rc;
568
569 dirrec_buffer->ino = (ISOINT(((struct fsw_iso9660_dnode *)shand->dnode)->dirrec.extent_location)
570 << ISO9660_BLOCKSIZE_BITS)
571 + (fsw_u32)shand->pos;
572
573 // read fixed size part of directory record
574 buffer_size = 33;
575 status = fsw_shandle_read(shand, &buffer_size, dirrec);
576 if (status)
577 {
578 DEBUG((DEBUG_INFO, "%a:%d \n", __FILE__, __LINE__));
579 return status;
580 }
581
582 if (buffer_size < 33 || dirrec->dirrec_length == 0) {
583 // end of directory reached
584 fsw_u8 *r;
585 r = (fsw_u8 *)dirrec;
586 DEBUG((DEBUG_INFO, "%a:%d bs:%d dl:%d\n", __FILE__, __LINE__, buffer_size, dirrec->dirrec_length));
587 for(i = 0; i < buffer_size; ++i)
588 {
589 DEBUG((DEBUG_INFO, "r[%d]:%c", i, r[i]));
590 }
591 dirrec->dirrec_length = 0;
592 return FSW_SUCCESS;
593 }
594 if (dirrec->dirrec_length < 33 ||
595 dirrec->dirrec_length < 33 + dirrec->file_identifier_length)
596 return FSW_VOLUME_CORRUPTED;
597
598 DEBUG((DEBUG_INFO, "%a:%d, dirrec_length: %d\n", __FILE__, __LINE__, dirrec->dirrec_length));
599
600 // read variable size part of directory record
601 buffer_size = remaining_size = dirrec->dirrec_length - 33;
602 status = fsw_shandle_read(shand, &buffer_size, dirrec->file_identifier);
603 if (status)
604 return status;
605 if (buffer_size < remaining_size)
606 return FSW_VOLUME_CORRUPTED;
607
608 if (vol->fRockRidge)
609 {
610 sp_off = sizeof(*dirrec) + dirrec->file_identifier_length;
611 rc = rr_find_sp(dirrec, &sp);
612 if ( rc == FSW_SUCCESS
613 && sp != NULL)
614 {
615 sp_off = (fsw_u8 *)&sp[1] - (fsw_u8*)dirrec + sp->skip;
616 }
617 rc = rr_find_nm(vol, dirrec, sp_off, &dirrec_buffer->name);
618 if (rc == FSW_SUCCESS)
619 return FSW_SUCCESS;
620 }
621
622 // setup name
623 name_len = dirrec->file_identifier_length;
624 for (i = name_len - 1; i > 0; i--) {
625 if (dirrec->file_identifier[i] == ';') {
626 name_len = i; // cut the ISO9660 version number off
627 break;
628 }
629 }
630 if (name_len > 0 && dirrec->file_identifier[name_len-1] == '.')
631 name_len--; // also cut the extension separator if the extension is empty
632 dirrec_buffer->name.type = FSW_STRING_TYPE_ISO88591;
633 dirrec_buffer->name.len = dirrec_buffer->name.size = name_len;
634 dirrec_buffer->name.data = dirrec->file_identifier;
635 DEBUG((DEBUG_INFO, "%a:%d: dirrec_buffer->name.data:%a\n", __FILE__, __LINE__, dirrec_buffer->name.data));
636 return FSW_SUCCESS;
637}
638
639/**
640 * Get the target path of a symbolic link. This function is called when a symbolic
641 * link needs to be resolved. The core makes sure that the fsw_iso9660_dnode_fill has been
642 * called on the dnode and that it really is a symlink.
643 *
644 * For iso9660, the target path can be stored inline in the inode structure (in the space
645 * otherwise occupied by the block pointers) or in the inode's data. There is no flag
646 * indicating this, only the number of blocks entry (i_blocks) can be used as an
647 * indication. The check used here comes from the Linux kernel.
648 */
649
650static fsw_status_t fsw_iso9660_readlink(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
651 struct fsw_string *link_target)
652{
653 fsw_status_t status;
654
655 if (dno->g.size > FSW_PATH_MAX)
656 return FSW_VOLUME_CORRUPTED;
657
658 status = fsw_dnode_readlink_data(dno, link_target);
659
660 return status;
661}
662
663// EOF
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette