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 <tak (at) kmc.kyoto-u.ac.jp> 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., 675 Mass Ave, Cambridge, MA 02139, USA. 20 */ 21 /* 22 * References: 23 * linux/fs/isofs/rock.[ch] 24 * mkisofs-1.11.1/diag/isoinfo.c 25 * mkisofs-1.11.1/iso9660.h 26 * (all are written by Eric Youngdale) 27 * 28 * Modifications by: 29 * Leonid Lisovskiy <lly (at) pisem.net> 2003 30 */ 31 32 #ifdef FSYS_ISO9660 33 34 #include "shared.h" 35 #include "filesys.h" 36 #include "iso9660.h" 37 38 /* iso9660 super-block data in memory */ 39 struct iso_sb_info { 40 unsigned long vol_sector; 41 42 }; 43 44 /* iso fs inode data in memory */ 45 struct iso_inode_info { 46 unsigned long file_start; 47 }; 48 49 #define ISO_SUPER \ 50 ((struct iso_sb_info *)(FSYS_BUF)) 51 #define INODE \ 52 ((struct iso_inode_info *)(FSYS_BUF+sizeof(struct iso_sb_info))) 53 #define PRIMDESC ((struct iso_primary_descriptor *)(FSYS_BUF + 2048)) 54 #define DIRREC ((struct iso_directory_record *)(FSYS_BUF + 4096)) 55 #define RRCONT_BUF ((unsigned char *)(FSYS_BUF + 6144)) 56 #define NAME_BUF ((unsigned char *)(FSYS_BUF + 8192)) 57 58 59 static inline unsigned long 60 log2 (unsigned long word) 61 { 62 asm volatile ("bsfl %1,%0" 63 : "=r" (word) 64 : "r" (word)); 65 return word; 66 } 67 68 static int 69 iso9660_devread (int sector, int byte_offset, int byte_len, char *buf) 70 { 71 unsigned short sector_size_lg2 = log2(buf_geom.sector_size); 72 73 /* 74 * We have to use own devread() function since BIOS return wrong geometry 75 */ 76 if (sector < 0) 77 { 78 errnum = ERR_OUTSIDE_PART; 79 return 0; 80 } 81 if (byte_len <= 0) 82 return 1; 83 84 sector += (byte_offset >> sector_size_lg2); 85 byte_offset &= (buf_geom.sector_size - 1); 86 asm volatile ("shl%L0 %1,%0" 87 : "=r"(sector) 88 : "Ic"((int8_t)(ISO_SECTOR_BITS - sector_size_lg2)), 89 "0"(sector)); 90 91 #if !defined(STAGE1_5) 92 if (disk_read_hook && debug) 93 printf ("<%d, %d, %d>", sector, byte_offset, byte_len); 94 #endif /* !STAGE1_5 */ 95 96 return rawread(current_drive, part_start + sector, byte_offset, byte_len, buf); 97 } 98 99 int 100 iso9660_mount (void) 101 { 102 unsigned int sector; 103 104 /* 105 * Because there is no defined slice type ID for ISO-9660 filesystem, 106 * this test will pass only either (1) if entire disk is used, or 107 * (2) if current partition is BSD style sub-partition whose ID is 108 * ISO-9660. 109 */ 110 if ((current_partition != 0xFFFFFF) 111 && !IS_PC_SLICE_TYPE_BSD_WITH_FS(current_slice, FS_ISO9660)) 112 return 0; 113 114 /* 115 * Currently, only FIRST session of MultiSession disks are supported !!! 116 */ 117 for (sector = 16 ; sector < 32 ; sector++) 118 { 119 if (!iso9660_devread(sector, 0, sizeof(*PRIMDESC), (char *)PRIMDESC)) 120 break; 121 /* check ISO_VD_PRIMARY and ISO_STANDARD_ID */ 122 if (PRIMDESC->type.l == ISO_VD_PRIMARY 123 && !memcmp(PRIMDESC->id, ISO_STANDARD_ID, sizeof(PRIMDESC->id))) 124 { 125 ISO_SUPER->vol_sector = sector; 126 INODE->file_start = 0; 127 fsmax = PRIMDESC->volume_space_size.l; 128 return 1; 129 } 130 } 131 132 return 0; 133 } 134 135 int 136 iso9660_dir (char *dirname) 137 { 138 struct iso_directory_record *idr; 139 RR_ptr_t rr_ptr; 140 struct rock_ridge *ce_ptr; 141 unsigned int pathlen; 142 int size; 143 unsigned int extent; 144 unsigned char file_type; 145 unsigned int rr_len; 146 unsigned char rr_flag; 147 148 idr = &PRIMDESC->root_directory_record; 149 INODE->file_start = 0; 150 151 do 152 { 153 while (*dirname == '/') /* skip leading slashes */ 154 dirname++; 155 /* pathlen = strcspn(dirname, "/\n\t "); */ 156 for (pathlen = 0 ; 157 dirname[pathlen] 158 && !isspace(dirname[pathlen]) && dirname[pathlen] != '/' ; 159 pathlen++) 160 ; 161 162 size = idr->size.l; 163 extent = idr->extent.l; 164 165 while (size > 0) 166 { 167 if (!iso9660_devread(extent, 0, ISO_SECTOR_SIZE, (char *)DIRREC)) 168 { 169 errnum = ERR_FSYS_CORRUPT; 170 return 0; 171 } 172 extent++; 173 174 idr = (struct iso_directory_record *)DIRREC; 175 for (; idr->length.l > 0; 176 idr = (struct iso_directory_record *)((char *)idr + idr->length.l) ) 177 { 178 const char *name = idr->name; 179 unsigned int name_len = idr->name_len.l; 180 181 file_type = (idr->flags.l & 2) ? ISO_DIRECTORY : ISO_REGULAR; 182 if (name_len == 1) 183 { 184 if ((name[0] == 0) || /* self */ 185 (name[0] == 1)) /* parent */ 186 continue; 187 } 188 if (name_len > 2 && CHECK2(name + name_len - 2, ';', '1')) 189 { 190 name_len -= 2; /* truncate trailing file version */ 191 if (name_len > 1 && name[name_len - 1] == '.') 192 name_len--; /* truncate trailing dot */ 193 } 194 195 /* 196 * Parse Rock-Ridge extension 197 */ 198 rr_len = (idr->length.l - idr->name_len.l 199 - sizeof(struct iso_directory_record) 200 + sizeof(idr->name)); 201 rr_ptr.ptr = ((unsigned char *)idr + idr->name_len.l 202 + sizeof(struct iso_directory_record) 203 - sizeof(idr->name)); 204 if (rr_ptr.i & 1) 205 rr_ptr.i++, rr_len--; 206 ce_ptr = NULL; 207 rr_flag = RR_FLAG_NM | RR_FLAG_PX /*| RR_FLAG_SL*/; 208 209 while (rr_len >= 4) 210 { 211 if (rr_ptr.rr->version != 1) 212 { 213 #ifndef STAGE1_5 214 if (debug) 215 printf( 216 "Non-supported version (%d) RockRidge chunk " 217 "`%c%c'\n", rr_ptr.rr->version, 218 rr_ptr.rr->signature & 0xFF, 219 rr_ptr.rr->signature >> 8); 220 #endif 221 } 222 else 223 { 224 switch (rr_ptr.rr->signature) 225 { 226 case RRMAGIC('R', 'R'): 227 if ( rr_ptr.rr->len >= (4+sizeof(struct RR))) 228 rr_flag &= rr_ptr.rr->u.rr.flags.l; 229 break; 230 case RRMAGIC('N', 'M'): 231 name = rr_ptr.rr->u.nm.name; 232 name_len = rr_ptr.rr->len - (4+sizeof(struct NM)); 233 rr_flag &= ~RR_FLAG_NM; 234 break; 235 case RRMAGIC('P', 'X'): 236 if (rr_ptr.rr->len >= (4+sizeof(struct PX))) 237 { 238 file_type = ((rr_ptr.rr->u.px.mode.l & POSIX_S_IFMT) 239 == POSIX_S_IFREG 240 ? ISO_REGULAR 241 : ((rr_ptr.rr->u.px.mode.l & POSIX_S_IFMT) 242 == POSIX_S_IFDIR 243 ? ISO_DIRECTORY : ISO_OTHER)); 244 rr_flag &= ~RR_FLAG_PX; 245 } 246 break; 247 case RRMAGIC('C', 'E'): 248 if (rr_ptr.rr->len >= (4+sizeof(struct CE))) 249 ce_ptr = rr_ptr.rr; 250 break; 251 #if 0 // RockRidge symlinks are not supported yet 252 case RRMAGIC('S', 'L'): 253 { 254 int slen; 255 unsigned char rootflag, prevflag; 256 char *rpnt = NAME_BUF+1024; 257 struct SL_component *slp; 258 259 slen = rr_ptr.rr->len - (4+1); 260 slp = &rr_ptr.rr->u.sl.link; 261 while (slen > 1) 262 { 263 rootflag = 0; 264 switch (slp->flags.l) 265 { 266 case 0: 267 memcpy(rpnt, slp->text, slp->len); 268 rpnt += slp->len; 269 break; 270 case 4: 271 *rpnt++ = '.'; 272 /* fallthru */ 273 case 2: 274 *rpnt++ = '.'; 275 break; 276 case 8: 277 rootflag = 1; 278 *rpnt++ = '/'; 279 break; 280 default: 281 printf("Symlink component flag not implemented (%d)\n", 282 slp->flags.l); 283 slen = 0; 284 break; 285 } 286 slen -= slp->len + 2; 287 prevflag = slp->flags.l; 288 slp = (struct SL_component *) ((char *) slp + slp->len + 2); 289 290 if (slen < 2) 291 { 292 /* 293 * If there is another SL record, and this component 294 * record isn't continued, then add a slash. 295 */ 296 if ((!rootflag) && (rr_ptr.rr->u.sl.flags.l & 1) && !(prevflag & 1)) 297 *rpnt++='/'; 298 break; 299 } 300 301 /* 302 * If this component record isn't continued, then append a '/'. 303 */ 304 if (!rootflag && !(prevflag & 1)) 305 *rpnt++ = '/'; 306 } 307 *rpnt++ = '\0'; 308 grub_putstr(NAME_BUF+1024);// debug print! 309 } 310 rr_flag &= ~RR_FLAG_SL; 311 break; 312 #endif 313 default: 314 break; 315 } 316 } 317 if (!rr_flag) 318 /* 319 * There is no more extension we expects... 320 */ 321 break; 322 323 rr_len -= rr_ptr.rr->len; 324 rr_ptr.ptr += rr_ptr.rr->len; 325 if (rr_len < 4 && ce_ptr != NULL) 326 { 327 /* preserve name before loading new extent. */ 328 if( RRCONT_BUF <= (unsigned char *)name 329 && (unsigned char *)name < RRCONT_BUF + ISO_SECTOR_SIZE ) 330 { 331 memcpy(NAME_BUF, name, name_len); 332 name = NAME_BUF; 333 } 334 rr_ptr.ptr = RRCONT_BUF + ce_ptr->u.ce.offset.l; 335 rr_len = ce_ptr->u.ce.size.l; 336 if (!iso9660_devread(ce_ptr->u.ce.extent.l, 0, ISO_SECTOR_SIZE, RRCONT_BUF)) 337 { 338 errnum = 0; /* this is not fatal. */ 339 break; 340 } 341 ce_ptr = NULL; 342 } 343 } /* rr_len >= 4 */ 344 345 filemax = MAXINT; 346 if (name_len >= pathlen 347 && !memcmp(name, dirname, pathlen)) 348 { 349 if (dirname[pathlen] == '/' || !print_possibilities) 350 { 351 /* 352 * DIRNAME is directory component of pathname, 353 * or we are to open a file. 354 */ 355 if (pathlen == name_len) 356 { 357 if (dirname[pathlen] == '/') 358 { 359 if (file_type != ISO_DIRECTORY) 360 { 361 errnum = ERR_BAD_FILETYPE; 362 return 0; 363 } 364 goto next_dir_level; 365 } 366 if (file_type != ISO_REGULAR) 367 { 368 errnum = ERR_BAD_FILETYPE; 369 return 0; 370 } 371 INODE->file_start = idr->extent.l; 372 filepos = 0; 373 filemax = idr->size.l; 374 return 1; 375 } 376 } 377 else /* Completion */ 378 { 379 #ifndef STAGE1_5 380 if (print_possibilities > 0) 381 print_possibilities = -print_possibilities; 382 memcpy(NAME_BUF, name, name_len); 383 NAME_BUF[name_len] = '\0'; 384 print_a_completion (NAME_BUF); 385 #endif 386 } 387 } 388 } /* for */ 389 390 size -= ISO_SECTOR_SIZE; 391 } /* size>0 */ 392 393 if (dirname[pathlen] == '/' || print_possibilities >= 0) 394 { 395 errnum = ERR_FILE_NOT_FOUND; 396 return 0; 397 } 398 399 next_dir_level: 400 dirname += pathlen; 401 402 } while (*dirname == '/'); 403 404 return 1; 405 } 406 407 int 408 iso9660_read (char *buf, int len) 409 { 410 int sector, blkoffset, size, ret; 411 412 if (INODE->file_start == 0) 413 return 0; 414 415 ret = 0; 416 blkoffset = filepos & (ISO_SECTOR_SIZE - 1); 417 sector = filepos >> ISO_SECTOR_BITS; 418 while (len > 0) 419 { 420 size = ISO_SECTOR_SIZE - blkoffset; 421 if (size > len) 422 size = len; 423 424 disk_read_func = disk_read_hook; 425 426 if (!iso9660_devread(INODE->file_start + sector, blkoffset, size, buf)) 427 return 0; 428 429 disk_read_func = NULL; 430 431 len -= size; 432 buf += size; 433 ret += size; 434 filepos += size; 435 sector++; 436 blkoffset = 0; 437 } 438 439 return ret; 440 } 441 442 #endif /* FSYS_ISO9660 */ 443