|
|
1.1 root 1: /*
2: * ISO 9660 filesystem backend for GRUB (GRand Unified Bootloader)
3: * including Rock Ridge Extensions support
4: *
5: * Copyright (C) 1998, 1999 Kousuke Takai <[email protected]>
6: *
7: * This program is free software; you can redistribute it and/or modify
8: * it under the terms of the GNU General Public License as published by
9: * the Free Software Foundation; either version 2 of the License, or
10: * (at your option) any later version.
11: *
12: * This program is distributed in the hope that it will be useful,
13: * but WITHOUT ANY WARRANTY; without even the implied warranty of
14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: * GNU General Public License for more details.
16: *
17: * You should have received a copy of the GNU General Public License
18: * along with this program; if not, write to the Free Software
19: * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20: * MA 02110-1301, USA.
21: */
22: /*
23: * References:
24: * linux/fs/isofs/rock.[ch]
25: * mkisofs-1.11.1/diag/isoinfo.c
26: * mkisofs-1.11.1/iso9660.h
27: * (all are written by Eric Youngdale)
28: *
29: * Modifications by:
30: * Leonid Lisovskiy <[email protected]> 2003
31: */
32:
33: /*
34: * Modified to make it work with FILO
35: * 2003-10 by SONE Takeshi
36: */
37:
38: #ifdef FSYS_ISO9660
39:
40: #include "shared.h"
41: #include "filesys.h"
42: #include "iso9660.h"
43: #include "debug.h"
44:
45: #if defined(__sparc__) || defined(__PPC__)
46: #define ENDIAN b
47: #else
48: #define ENDIAN l
49: #endif
50:
51: struct iso_superblock {
52: unsigned long vol_sector;
53:
54: unsigned long file_start;
55: };
56:
57: #define ISO_SUPER ((struct iso_superblock *)(FSYS_BUF))
58: #define PRIMDESC ((struct iso_primary_descriptor *)(FSYS_BUF + 2048))
59: #define DIRREC ((struct iso_directory_record *)(FSYS_BUF + 4096))
60: #define RRCONT_BUF ((unsigned char *)(FSYS_BUF + 6144))
61: #define NAME_BUF ((unsigned char *)(FSYS_BUF + 8192))
62:
63: static int
64: iso9660_devread (int sector, int byte_offset, int byte_len, char *buf)
65: {
66: /* FILO uses 512-byte "soft" sector, and ISO-9660 uses 2048-byte
67: * CD-ROM sector */
68: return devread(sector<<2, byte_offset, byte_len, buf);
69: }
70:
71: int
72: iso9660_mount (void)
73: {
74: unsigned int sector;
75:
76: /*
77: * Because there is no defined slice type ID for ISO-9660 filesystem,
78: * this test will pass only either (1) if entire disk is used, or
79: * (2) if current partition is BSD style sub-partition whose ID is
80: * ISO-9660.
81: */
82: /*if ((current_partition != 0xFFFFFF)
83: && !IS_PC_SLICE_TYPE_BSD_WITH_FS(current_slice, FS_ISO9660))
84: return 0;*/
85:
86: /*
87: * Currently, only FIRST session of MultiSession disks are supported !!!
88: */
89: for (sector = 16 ; sector < 32 ; sector++)
90: {
91: if (!iso9660_devread(sector, 0, sizeof(*PRIMDESC), (char *)PRIMDESC))
92: break;
93: /* check ISO_VD_PRIMARY and ISO_STANDARD_ID */
94: if (CHECK4(&PRIMDESC->type, ISO_VD_PRIMARY, 'C', 'D', '0')
95: && CHECK2(PRIMDESC->id + 3, '0', '1'))
96: {
97: ISO_SUPER->vol_sector = sector;
98: ISO_SUPER->file_start = 0;
99: fsmax = PRIMDESC->volume_space_size.ENDIAN;
100: return 1;
101: }
102: }
103:
104: return 0;
105: }
106:
107: int
108: iso9660_dir (char *dirname)
109: {
110: struct iso_directory_record *idr;
111: RR_ptr_t rr_ptr;
112: struct rock_ridge *ce_ptr;
113: unsigned int pathlen;
114: int size;
115: unsigned int extent;
116: unsigned int rr_len;
117: unsigned char file_type;
118: unsigned char rr_flag;
119:
120: idr = &PRIMDESC->root_directory_record;
121: ISO_SUPER->file_start = 0;
122:
123: do
124: {
125: while (*dirname == '/') /* skip leading slashes */
126: dirname++;
127: /* pathlen = strcspn(dirname, "/\n\t "); */
128: for (pathlen = 0 ;
129: dirname[pathlen]
130: && !isspace(dirname[pathlen]) && dirname[pathlen] != '/' ;
131: pathlen++)
132: ;
133:
134: size = idr->size.ENDIAN;
135: extent = idr->extent.ENDIAN;
136:
137: while (size > 0)
138: {
139: if (!iso9660_devread(extent, 0, ISO_SECTOR_SIZE, (char *)DIRREC))
140: {
141: errnum = ERR_FSYS_CORRUPT;
142: return 0;
143: }
144: extent++;
145:
146: idr = (struct iso_directory_record *)DIRREC;
147: for (; idr->length.ENDIAN > 0;
148: idr = (struct iso_directory_record *)((char *)idr + idr->length.ENDIAN) )
149: {
150: const char *name = (char *)idr->name;
151: unsigned int name_len = idr->name_len.ENDIAN;
152:
153: file_type = (idr->flags.ENDIAN & 2) ? ISO_DIRECTORY : ISO_REGULAR;
154: if (name_len == 1)
155: {
156: if ((name[0] == 0) || /* self */
157: (name[0] == 1)) /* parent */
158: continue;
159: }
160: if (name_len > 2 && CHECK2(name + name_len - 2, ';', '1'))
161: {
162: name_len -= 2; /* truncate trailing file version */
163: if (name_len > 1 && name[name_len - 1] == '.')
164: name_len--; /* truncate trailing dot */
165: }
166:
167: /*
168: * Parse Rock-Ridge extension
169: */
170: rr_len = (idr->length.ENDIAN - idr->name_len.ENDIAN
171: - (unsigned char)sizeof(struct iso_directory_record)
172: + (unsigned char)sizeof(idr->name));
173: rr_ptr.ptr = ((char *)idr + idr->name_len.ENDIAN
174: + sizeof(struct iso_directory_record)
175: - sizeof(idr->name));
176: if (rr_len & 1)
177: rr_ptr.ptr++, rr_len--;
178: ce_ptr = NULL;
179: rr_flag = RR_FLAG_NM | RR_FLAG_PX;
180:
181: while (rr_len >= 4)
182: {
183: if (rr_ptr.rr->version != 1)
184: {
185: #ifndef STAGE1_5
186: if (debug)
187: printf(
188: "Non-supported version (%d) RockRidge chunk "
189: "`%c%c'\n", rr_ptr.rr->version,
190: rr_ptr.rr->signature & 0xFF,
191: rr_ptr.rr->signature >> 8);
192: #endif
193: }
194: else if (CHECK2(&rr_ptr.rr->signature, 'R', 'R')
195: && rr_ptr.rr->len >= 5)
196: rr_flag &= rr_ptr.rr->u.rr.flags.ENDIAN;
197: else if (CHECK2(&rr_ptr.rr->signature, 'N', 'M'))
198: {
199: name = (char *)rr_ptr.rr->u.nm.name;
200: name_len = rr_ptr.rr->len - 5;
201: rr_flag &= ~RR_FLAG_NM;
202: }
203: else if (CHECK2(&rr_ptr.rr->signature, 'P', 'X')
204: && rr_ptr.rr->len >= 36)
205: {
206: file_type = ((rr_ptr.rr->u.px.mode.ENDIAN & POSIX_S_IFMT)
207: == POSIX_S_IFREG
208: ? ISO_REGULAR
209: : ((rr_ptr.rr->u.px.mode.ENDIAN & POSIX_S_IFMT)
210: == POSIX_S_IFDIR
211: ? ISO_DIRECTORY : ISO_OTHER));
212: rr_flag &= ~RR_FLAG_PX;
213: }
214: else if (CHECK2(&rr_ptr.rr->signature, 'C', 'E')
215: && rr_ptr.rr->len >= 28)
216: ce_ptr = rr_ptr.rr;
217: if (!rr_flag)
218: /*
219: * There is no more extension we expects...
220: */
221: break;
222: rr_len -= rr_ptr.rr->len;
223: rr_ptr.ptr += rr_ptr.rr->len;
224: if (rr_len < 4 && ce_ptr != NULL)
225: {
226: /* preserve name before loading new extent. */
227: if( RRCONT_BUF <= (unsigned char *)name
228: && (unsigned char *)name < RRCONT_BUF + ISO_SECTOR_SIZE )
229: {
230: memcpy(NAME_BUF, name, name_len);
231: name = (char *)NAME_BUF;
232: }
233: rr_ptr.ptr = (char *)(RRCONT_BUF + ce_ptr->u.ce.offset.ENDIAN);
234: rr_len = ce_ptr->u.ce.size.ENDIAN;
235: if (!iso9660_devread(ce_ptr->u.ce.extent.ENDIAN, 0,
236: ISO_SECTOR_SIZE, (char *)RRCONT_BUF))
237: {
238: errnum = 0; /* this is not fatal. */
239: break;
240: }
241: ce_ptr = NULL;
242: }
243: } /* rr_len >= 4 */
244:
245: filemax = MAXINT;
246: if (name_len >= pathlen
247: && !strnicmp(name, dirname, pathlen))
248: {
249: if (dirname[pathlen] == '/' || !print_possibilities)
250: {
251: /*
252: * DIRNAME is directory component of pathname,
253: * or we are to open a file.
254: */
255: if (pathlen == name_len)
256: {
257: if (dirname[pathlen] == '/')
258: {
259: if (file_type != ISO_DIRECTORY)
260: {
261: errnum = ERR_BAD_FILETYPE;
262: return 0;
263: }
264: goto next_dir_level;
265: }
266: if (file_type != ISO_REGULAR)
267: {
268: errnum = ERR_BAD_FILETYPE;
269: return 0;
270: }
271: ISO_SUPER->file_start = idr->extent.ENDIAN;
272: filepos = 0;
273: filemax = idr->size.ENDIAN;
274: return 1;
275: }
276: }
277: else /* Completion */
278: {
279: #ifndef STAGE1_5
280: if (print_possibilities > 0)
281: print_possibilities = -print_possibilities;
282: memcpy(NAME_BUF, name, name_len);
283: NAME_BUF[name_len] = '\0';
284: print_a_completion (NAME_BUF);
285: #endif
286: }
287: }
288: } /* for */
289:
290: size -= ISO_SECTOR_SIZE;
291: } /* size>0 */
292:
293: if (dirname[pathlen] == '/' || print_possibilities >= 0)
294: {
295: errnum = ERR_FILE_NOT_FOUND;
296: return 0;
297: }
298:
299: next_dir_level:
300: dirname += pathlen;
301:
302: } while (*dirname == '/');
303:
304: return 1;
305: }
306:
307: int
308: iso9660_read (char *buf, int len)
309: {
310: int sector, blkoffset, size, ret;
311:
312: if (ISO_SUPER->file_start == 0)
313: return 0;
314:
315: ret = 0;
316: blkoffset = filepos & (ISO_SECTOR_SIZE - 1);
317: sector = filepos >> ISO_SECTOR_BITS;
318: while (len > 0)
319: {
320: size = ISO_SECTOR_SIZE - blkoffset;
321: if (size > len)
322: size = len;
323:
324: disk_read_func = disk_read_hook;
325:
326: if (!iso9660_devread(ISO_SUPER->file_start + sector, blkoffset, size, buf))
327: return 0;
328:
329: disk_read_func = NULL;
330:
331: len -= size;
332: buf += size;
333: ret += size;
334: filepos += size;
335: sector++;
336: blkoffset = 0;
337: }
338:
339: return ret;
340: }
341:
342: #endif /* FSYS_ISO9660 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.