4 #include <sys/dirent.h>
10 #include "iso9660_fs.h"
13 /* Convert to lower case string */
14 static inline char iso_tolower(char c
)
16 if (c
>= 'A' && c
<= 'Z')
22 static struct inode
*new_iso_inode(struct fs_info
*fs
)
24 return alloc_inode(fs
, 0, sizeof(struct iso9660_pvt_inode
));
27 static inline struct iso_sb_info
*ISO_SB(struct fs_info
*fs
)
32 static size_t iso_convert_name(char *dst
, const char *src
, int len
)
51 while (len
-- && (c
= *src
++)) {
52 if (c
== ';') /* Remove any filename version suffix */
54 *p
++ = iso_tolower(c
);
57 /* Then remove any terminal dots */
58 while (p
> dst
+1 && p
[-1] == '.')
67 * Unlike strcmp, it does return 1 on match, or reutrn 0 if not match.
69 static bool iso_compare_name(const char *de_name
, size_t len
,
70 const char *file_name
)
72 char iso_file_name
[256];
73 char *p
= iso_file_name
;
77 i
= iso_convert_name(iso_file_name
, de_name
, len
);
79 dprintf("Compare: \"%s\" to \"%s\" (len %zu)\n",
80 file_name
, iso_file_name
, i
);
84 c2
= iso_tolower(*file_name
++);
86 /* compare equal except for case? */
95 * Find a entry in the specified dir with name _dname_.
97 static const struct iso_dir_entry
*
98 iso_find_entry(const char *dname
, struct inode
*inode
)
100 struct fs_info
*fs
= inode
->fs
;
101 block_t dir_block
= PVT(inode
)->lba
;
102 int i
= 0, offset
= 0;
104 int de_name_len
, de_len
, rr_name_len
, ret
;
105 const struct iso_dir_entry
*de
;
106 const char *data
= NULL
;
107 char *rr_name
= NULL
;
109 dprintf("iso_find_entry: \"%s\"\n", dname
);
113 dprintf("Getting block %d from block %llu\n", i
, dir_block
);
114 if (++i
> inode
->blocks
)
115 return NULL
; /* End of directory */
116 data
= get_cache(fs
->fs_dev
, dir_block
++);
120 de
= (const struct iso_dir_entry
*)(data
+ offset
);
124 /* Make sure we have a full directory entry */
125 if (de_len
< 33 || offset
> BLOCK_SIZE(fs
)) {
127 * Zero = end of sector, or corrupt directory entry
129 * ECMA-119:1987 6.8.1.1: "Each Directory Record shall end
130 * in the Logical Sector in which it begins.
136 /* Try to get Rock Ridge name */
137 ret
= susp_rr_get_nm(fs
, (char *) de
, &rr_name
, &rr_name_len
);
139 if (strcmp(rr_name
, dname
) == 0) {
140 dprintf("Found (by RR name).\n");
146 continue; /* Rock Ridge was valid and did not match */
149 /* Fall back to ISO name */
150 de_name_len
= de
->name_len
;
152 if (iso_compare_name(de_name
, de_name_len
, dname
)) {
153 dprintf("Found (by ISO name).\n");
159 static inline enum dirent_type
get_inode_mode(uint8_t flags
)
161 return (flags
& 0x02) ? DT_DIR
: DT_REG
;
164 static struct inode
*iso_get_inode(struct fs_info
*fs
,
165 const struct iso_dir_entry
*de
)
167 struct inode
*inode
= new_iso_inode(fs
);
168 int blktosec
= BLOCK_SHIFT(fs
) - SECTOR_SHIFT(fs
);
173 dprintf("Getting inode for: %.*s\n", de
->name_len
, de
->name
);
175 inode
->mode
= get_inode_mode(de
->flags
);
176 inode
->size
= de
->size_le
;
177 PVT(inode
)->lba
= de
->extent_le
;
178 inode
->blocks
= (inode
->size
+ BLOCK_SIZE(fs
) - 1) >> BLOCK_SHIFT(fs
);
180 /* We have a single extent for all data */
181 inode
->next_extent
.pstart
= (sector_t
)de
->extent_le
<< blktosec
;
182 inode
->next_extent
.len
= (sector_t
)inode
->blocks
<< blktosec
;
187 static struct inode
*iso_iget_root(struct fs_info
*fs
)
189 const struct iso_dir_entry
*root
= &ISO_SB(fs
)->root
;
191 return iso_get_inode(fs
, root
);
194 static struct inode
*iso_iget(const char *dname
, struct inode
*parent
)
196 const struct iso_dir_entry
*de
;
198 dprintf("iso_iget %p %s\n", parent
, dname
);
200 de
= iso_find_entry(dname
, parent
);
204 return iso_get_inode(parent
->fs
, de
);
207 static int iso_readdir(struct file
*file
, struct dirent
*dirent
)
209 struct fs_info
*fs
= file
->fs
;
210 struct inode
*inode
= file
->inode
;
211 const struct iso_dir_entry
*de
;
212 const char *data
= NULL
;
213 char *rr_name
= NULL
;
217 size_t offset
= file
->offset
& (BLOCK_SIZE(fs
) - 1);
220 uint32_t i
= file
->offset
>> BLOCK_SHIFT(fs
);
221 if (i
>= inode
->blocks
)
223 data
= get_cache(fs
->fs_dev
, PVT(inode
)->lba
+ i
);
225 de
= (const struct iso_dir_entry
*)(data
+ offset
);
227 if (de
->length
< 33 || offset
+ de
->length
> BLOCK_SIZE(fs
)) {
228 file
->offset
= (file
->offset
+ BLOCK_SIZE(fs
))
229 & ~(BLOCK_SIZE(fs
) - 1); /* Start of the next block */
236 dirent
->d_ino
= 0; /* Inode number is invalid to ISO fs */
237 dirent
->d_off
= file
->offset
;
238 dirent
->d_type
= get_inode_mode(de
->flags
);
240 /* Try to get Rock Ridge name */
241 ret
= susp_rr_get_nm(fs
, (char *) de
, &rr_name
, &name_len
);
243 memcpy(dirent
->d_name
, rr_name
, name_len
+ 1);
247 name_len
= iso_convert_name(dirent
->d_name
, de
->name
, de
->name_len
);
250 dirent
->d_reclen
= offsetof(struct dirent
, d_name
) + 1 + name_len
;
252 file
->offset
+= de
->length
; /* Update for next reading */
257 /* Load the config file, return 1 if failed, or 0 */
258 static int iso_open_config(struct com32_filedata
*filedata
)
260 static const char *search_directories
[] = {
268 static const char *filenames
[] = {
274 return search_dirs(filedata
, search_directories
, filenames
, ConfigName
);
277 static int iso_fs_init(struct fs_info
*fs
)
279 struct iso_sb_info
*sbi
;
280 char pvd
[2048]; /* Primary Volume Descriptor */
282 struct disk
*disk
= fs
->fs_dev
->disk
;
285 sbi
= malloc(sizeof(*sbi
));
287 malloc_error("iso_sb_info structure");
293 * XXX: handling iso9660 in hybrid mode on top of a 4K-logical disk
294 * will really, really hurt...
296 fs
->sector_shift
= fs
->fs_dev
->disk
->sector_shift
;
297 fs
->block_shift
= 11; /* A CD-ROM block is always 2K */
298 fs
->sector_size
= 1 << fs
->sector_shift
;
299 fs
->block_size
= 1 << fs
->block_shift
;
300 blktosec
= fs
->block_shift
- fs
->sector_shift
;
302 pvd_lba
= iso_boot_info
.pvd
;
304 pvd_lba
= 16; /* Default if not otherwise defined */
306 disk
->rdwr_sectors(disk
, pvd
, (sector_t
)pvd_lba
<< blktosec
,
307 1 << blktosec
, false);
308 memcpy(&sbi
->root
, pvd
+ ROOT_DIR_OFFSET
, sizeof(sbi
->root
));
310 /* Initialize the cache */
311 cache_init(fs
->fs_dev
, fs
->block_shift
);
313 /* Check for SP and ER in the first directory record of the root directory.
314 Set sbi->susp_skip and enable sbi->do_rr as appropriate.
316 susp_rr_check_signatures(fs
, 1);
318 return fs
->block_shift
;
322 const struct fs_ops iso_fs_ops
= {
324 .fs_flags
= FS_USEMEM
| FS_THISIND
,
325 .fs_init
= iso_fs_init
,
327 .getfssec
= generic_getfssec
,
328 .close_file
= generic_close_file
,
329 .mangle_name
= generic_mangle_name
,
330 .open_config
= iso_open_config
,
331 .iget_root
= iso_iget_root
,
333 .readdir
= iso_readdir
,
334 .next_extent
= no_next_extent
,