/* Open a file or directory via selection */ uint32 iso_open_select(const char *fn, int mode, uint32 session_base_select) { uint32 fd; iso_dirent_t *de; /* Make sure they don't want to open things as writeable */ if ((mode & O_MODE_MASK) != O_RDONLY) return 0; /* Find a free file handle */ for (fd=0; fd<MAX_ISO_FILES; fd++) if (fh[fd].first_extent == 0) { fh[fd].first_extent = -1; break; } if (fd >= MAX_ISO_FILES) return 0; /* For now we always do this, but it should eventually be set up to detect the CD tray having been opened. */ if (init_percd_select(session_base_select) < 0) return 0; /* Find the file we want */ de = find_object_path(fn, (mode & O_DIR)?1:0, &root_dirent); if (!de) return 0; /* Fill in the file handle and return the fd */ fh[fd].first_extent = iso_733(de->extent); fh[fd].dir = (mode & O_DIR)?1:0; fh[fd].ptr = 0; fh[fd].size = iso_733(de->size); return fd; }
/* Locate an ISO9660 object anywhere on the disc, starting at the root, and expecting a fully qualified path name. This is analogous to find_object but it searches with the path in mind. fn: object filename (relative to the passed directory) dir: 0 if looking for a file, 1 if looking for a dir dir_extent: directory extent to start with dir_size: directory size (in bytes) It will return a pointer to a transient dirent buffer (i.e., don't expect this buffer to stay around much longer than the call itself). */ static iso_dirent_t *find_object_path(const char *fn, int dir, iso_dirent_t *start) { char *cur; /* If the object is in a sub-tree, traverse the trees looking for the right directory */ while ((cur = strchr(fn, '/'))) { if (cur != fn) { /* Note: trailing path parts don't matter since find_object only compares based on the FN length on the disc. */ start = find_object(fn, 1, iso_733(start->extent), iso_733(start->size)); if (start == NULL) return NULL; } fn = cur + 1; } /* Locate the file in the resulting directory */ if (*fn) { start = find_object(fn, dir, iso_733(start->extent), iso_733(start->size)); return start; } else { if (!dir) return NULL; else return start; } }
/* Initialize for GD-ROM */ static int init_percd_gdrom() { int i; CDROM_TOC toc; /* Start off with no cached blocks */ bclear(); /* Locate the root session */ if ((i = cdrom_reinit()) != 0) return i; if ((i = cdrom_read_toc(&toc, 1)) != 0) return i; if (!(session_base = cdrom_locate_data_track(&toc, 1))) return -1; /* Grab and check the volume descriptor */ i = bread(session_base + 16 - 150); if (i < 0) return i; if (memcmp((char*)cache[i]->data, "\01CD001", 6)) { printf("fs_iso9660: disc is not iso9660\r\n"); return -1; } /* Locate the root directory */ memcpy(&root_dirent, cache[i]->data+156, sizeof(iso_dirent_t)); root_extent = iso_733(root_dirent.extent); root_size = iso_733(root_dirent.size); return 0; }
void read_dir(uint32 extent, uint32 size) { int i; iso_dirent_t *de; char fn[32]; while (size > 0) { int c = bread(extent); if (c < 0) return; for (i=0; i<2048 && i<size; ) { de = (iso_dirent_t*)(cache[c]->data + i); if (!de->length) break; strncpy(fn, de->name, de->name_len); fn[de->name_len] = 0; if (de->flags & 2) printf("%s\t\t<DIR>\n", fn); else printf("%s\t\t%d\n", fn, iso_733(de->size)); i += de->length; } extent++; size -= 2048; } }
/* Customized selective data location */ static int init_percd_select(uint32 session_base_select) { int i; /* Start off with no cached blocks */ bclear(); /* Grab and check the volume descriptor */ i = bread(session_base_select + 16 - 150); if (i < 0) return i; if (memcmp((char*)cache[i]->data, "\01CD001", 6)) { printf("fs_iso9660: disc is not iso9660\r\n"); return -1; } /* Locate the root directory */ memcpy(&root_dirent, cache[i]->data+156, sizeof(iso_dirent_t)); root_extent = iso_733(root_dirent.extent); root_size = iso_733(root_dirent.size); return 0; }
/* Read a directory entry */ dirent_t *iso_readdir(uint32 fd) { int c = 0; iso_dirent_t *de = NULL; if (fd>=MAX_ISO_FILES || fh[fd].first_extent==0 || !fh[fd].dir) return NULL; /* Scan forwards until we find the next valid entry, an end-of-entry mark, or run out of dir size. */ while(fh[fd].ptr < fh[fd].size) { /* Get the current dirent block */ c = bread(fh[fd].first_extent + fh[fd].ptr/2048); if (c < 0) return NULL; de = (iso_dirent_t *)(cache[c]->data + (fh[fd].ptr%2048)); if (de->length) break; /* Skip to the next sector */ fh[fd].ptr += 2048 - (fh[fd].ptr%2048); } if (fh[fd].ptr >= fh[fd].size) return NULL; /* If we're at the first, skip the two blank entries */ if (!de->name[0]) { fh[fd].ptr += de->length; de = (iso_dirent_t *)(cache[c]->data + (fh[fd].ptr%2048)); fh[fd].ptr += de->length; de = (iso_dirent_t *)(cache[c]->data + (fh[fd].ptr%2048)); if (!de->length) return NULL; } /* Fill out the VFS dirent */ strncpy(fh[fd].dirent.name, de->name, de->name_len); fh[fd].dirent.name[de->name_len] = 0; fn_postprocess(fh[fd].dirent.name); if (de->flags & 2) fh[fd].dirent.size = -1; else fh[fd].dirent.size = iso_733(de->size); fh[fd].ptr += de->length; return &fh[fd].dirent; }