static int rrip_check(struct open_file *f, struct iso_directory_record *dp, int *lenskip) { ISO_SUSP_PRESENT *sp; ISO_RRIP_EXTREF *er; char *p; /* First, see if we can find a SP field. */ p = dp->name + isonum_711(dp->name_len); if (p > (char *)dp + isonum_711(dp->length)) return (0); sp = (ISO_SUSP_PRESENT *)p; if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0) return (0); if (isonum_711(sp->h.length) != sizeof(ISO_SUSP_PRESENT)) return (0); if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef) return (0); *lenskip = isonum_711(sp->len_skp); /* * Now look for an ER field. If RRIP is present, then there must * be at least one of these. It would be more pedantic to walk * through the list of fields looking for a Rock Ridge ER field. */ er = (ISO_RRIP_EXTREF *)susp_lookup_record(f, SUSP_EXTREF, dp, 0); if (er == NULL) return (0); return (1); }
static struct dentry *isofs_export_get_parent(struct dentry *child) { unsigned long parent_block = 0; unsigned long parent_offset = 0; struct inode *child_inode = child->d_inode; struct iso_inode_info *e_child_inode = ISOFS_I(child_inode); struct iso_directory_record *de = NULL; struct buffer_head * bh = NULL; struct dentry *rv = NULL; if (!S_ISDIR(child_inode->i_mode)) { printk(KERN_ERR "isofs: isofs_export_get_parent(): " "child is not a directory!\n"); rv = ERR_PTR(-EACCES); goto out; } if (e_child_inode->i_iget5_offset != 0) { printk(KERN_ERR "isofs: isofs_export_get_parent(): " "child directory not normalized!\n"); rv = ERR_PTR(-EACCES); goto out; } parent_block = e_child_inode->i_iget5_block; bh = sb_bread(child_inode->i_sb, parent_block); if (bh == NULL) { rv = ERR_PTR(-EACCES); goto out; } de = (struct iso_directory_record*)bh->b_data; parent_offset = (unsigned long)isonum_711(de->length); de = (struct iso_directory_record*)(bh->b_data + parent_offset); if ((isonum_711(de->name_len) != 1) || (de->name[0] != 1)) { printk(KERN_ERR "isofs: Unable to find the \"..\" " "directory for NFS.\n"); rv = ERR_PTR(-EACCES); goto out; } isofs_normalize_block_and_offset(de, &parent_block, &parent_offset); rv = d_obtain_alias(isofs_iget(child_inode->i_sb, parent_block, parent_offset)); out: if (bh) brelse(bh); return rv; }
static int cdfs_find_in_dir(struct cdfs *cdfs, int dir, char *name, int len, struct buf **dirbuf, struct iso_directory_record **dirrec) { struct buf *buf; char *p; struct iso_directory_record *rec; int blk; int left; int reclen; int namelen; // The first two directory records are . (current) and .. (parent) blk = cdfs->path_table[dir]->extent; buf = get_buffer(cdfs->cache, blk++); if (!buf) return -EIO; // Get length of directory from the first record p = buf->data; rec = (struct iso_directory_record *) p; left = isonum_733(rec->size); // Find named entry in directory while (left > 0) { // Read next block if all records in current block has been read // Directory records never cross block boundaries if (p >= buf->data + CDFS_BLOCKSIZE) { release_buffer(cdfs->cache, buf); if (p > buf->data + CDFS_BLOCKSIZE) return -EIO; buf = get_buffer(cdfs->cache, blk++); if (!buf) return -EIO; p = buf->data; } // Check for match rec = (struct iso_directory_record *) p; reclen = isonum_711(rec->length); namelen = isonum_711(rec->name_len); if (reclen > 0) { if (cdfs_fnmatch(cdfs, name, len, (char *) rec->name, namelen)) { *dirrec = rec; *dirbuf = buf; return 0; } // Skip to next record p += reclen; left -= reclen; } else { // Skip to next block left -= (buf->data + CDFS_BLOCKSIZE) - p; p = buf->data + CDFS_BLOCKSIZE; } } release_buffer(cdfs->cache, buf); return -ENOENT; }
/* * Extension reference */ static int cd9660_rrip_extref(ISO_RRIP_EXTREF *p, ISO_RRIP_ANALYZE *ana) { if (isonum_711(p->len_id) != 10 || bcmp((char *)p + 8,"RRIP_1991A",10) || isonum_711(p->version) != 1) return 0; ana->fields &= ~ISO_SUSP_EXTREF; return ISO_SUSP_EXTREF; }
int cdfs_opendir(struct file *filp, char *name) { struct cdfs *cdfs = (struct cdfs *) filp->fs->data; struct iso_directory_record *rec; struct cdfs_file *cdfile; struct buf *buf; time_t date; int size; int extent; int flags; int rc; // Locate directory rc = cdfs_find_file(cdfs, name, strlen(name), &buf, &rec); if (rc < 0) return rc; flags = isonum_711(rec->flags); extent = isonum_733(rec->extent); date = cdfs_isodate(rec->date); size = isonum_733(rec->size); release_buffer(cdfs->cache, buf); if (!(flags & 2)) return -ENOTDIR; // Allocate and initialize file block cdfile = (struct cdfs_file *) kmalloc(sizeof(struct cdfs_file)); if (!cdfile) return -ENOMEM; cdfile->extent = extent; cdfile->date = date; cdfile->size = size; filp->data = cdfile; filp->mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; return 0; }
/* * Alternate name */ static int cd9660_rrip_altname(ISO_RRIP_ALTNAME *p, ISO_RRIP_ANALYZE *ana) { char *inbuf; int wlen; int cont; inbuf = ".."; wlen = 0; cont = 0; switch (*p->flags) { case ISO_SUSP_CFLAG_CURRENT: /* Inserting Current */ wlen = 1; break; case ISO_SUSP_CFLAG_PARENT: /* Inserting Parent */ wlen = 2; break; case ISO_SUSP_CFLAG_HOST: /* Inserting hostname i.e. "kurt.tools.de" */ inbuf = hostname; wlen = strlen(hostname); break; case ISO_SUSP_CFLAG_CONTINUE: cont = 1; /* fall thru */ case 0: /* Inserting component */ wlen = isonum_711(p->h.length) - 5; inbuf = (char *)p + 5; break; default: kprintf("RRIP with incorrect NM flags?\n"); wlen = ana->maxlen + 1; break; } if ((*ana->outlen += wlen) > ana->maxlen) { /* treat as no name field */ ana->fields &= ~ISO_SUSP_ALTNAME; ana->outbuf -= *ana->outlen - wlen; *ana->outlen = 0; return 0; } bcopy(inbuf,ana->outbuf,wlen); ana->outbuf += wlen; if (!cont) { ana->fields &= ~ISO_SUSP_ALTNAME; return ISO_SUSP_ALTNAME; } return 0; }
static char * rrip_lookup_name(struct open_file *f, struct iso_directory_record *dp, int lenskip, size_t *len) { ISO_RRIP_ALTNAME *p; if (len == NULL) return (NULL); p = (ISO_RRIP_ALTNAME *)susp_lookup_record(f, RRIP_NAME, dp, lenskip); if (p == NULL) return (NULL); switch (*p->flags) { case ISO_SUSP_CFLAG_CURRENT: *len = 1; return ("."); case ISO_SUSP_CFLAG_PARENT: *len = 2; return (".."); case 0: *len = isonum_711(p->h.length) - 5; return ((char *)p + 5); default: /* * We don't handle hostnames or continued names as they are * too hard, so just bail and use the default name. */ return (NULL); } }
/* * Make a mount point from a volume descriptor */ static int iso_makemp(struct iso_mnt *isomp, struct buf *bp, int *ea_len) { struct iso_primary_descriptor *pri; int logical_block_size; struct iso_directory_record *rootp; pri = (struct iso_primary_descriptor *)bp->b_data; logical_block_size = isonum_723 (pri->logical_block_size); if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE || (logical_block_size & (logical_block_size - 1)) != 0) return -1; rootp = (struct iso_directory_record *)pri->root_directory_record; isomp->logical_block_size = logical_block_size; isomp->volume_space_size = isonum_733 (pri->volume_space_size); memcpy(isomp->root, rootp, sizeof(isomp->root)); isomp->root_extent = isonum_733 (rootp->extent); isomp->root_size = isonum_733 (rootp->size); isomp->im_joliet_level = 0; isomp->im_bmask = logical_block_size - 1; isomp->im_bshift = 0; while ((1 << isomp->im_bshift) < isomp->logical_block_size) isomp->im_bshift++; if (ea_len != NULL) *ea_len = isonum_711(rootp->ext_attr_length); return 0; }
int cd9660_rrip_getname(struct iso_directory_record *isodir, char *outbuf, u_short *outlen, ino_t *inump, struct iso_mnt *imp) { ISO_RRIP_ANALYZE analyze; RRIP_TABLE *tab; u_short c; analyze.outbuf = outbuf; analyze.outlen = outlen; analyze.maxlen = NAME_MAX; analyze.inump = inump; analyze.imp = imp; analyze.fields = ISO_SUSP_ALTNAME|ISO_SUSP_RELDIR|ISO_SUSP_CLINK|ISO_SUSP_PLINK; *outlen = 0; isochar(isodir->name, isodir->name + isonum_711(isodir->name_len), imp->joliet_level, &c, NULL, imp->im_flags, imp->im_d2l); tab = rrip_table_getname; if (c == 0 || c == 1) { cd9660_rrip_defname(isodir,&analyze); analyze.fields &= ~ISO_SUSP_ALTNAME; tab++; } return cd9660_rrip_loop(isodir,&analyze,tab); }
static int dirmatch(const char *path, struct iso_directory_record *dp) { char *cp; int i; /* This needs to be a regular file */ if (dp->flags[0] & 6) return 0; cp = dp->name; for (i = isonum_711(dp->name_len); --i >= 0; path++, cp++) { if (!*path) break; if (toupper(*path) == *cp) continue; return 0; } if (*path) return 0; /* * Allow stripping of trailing dots and the version number. * Note that this will find the first instead of the last version * of a file. */ if (i >= 0 && (*cp == ';' || *cp == '.')) { /* This is to prevent matching of numeric extensions */ if (*cp == '.' && cp[1] != ';') return 0; while (--i >= 0) if (*++cp != ';' && (*cp < '0' || *cp > '9')) return 0; } return 1; }
/* * cdfs_get_extnd_attrs - read the input file's extended attribute data. */ long cdfs_get_extnd_attrs(struct cdfs_file *file, struct iso_extended_attributes *attrs) { void *bp, *data; long status = CDFS_SUCCESS; int lbn, length; static char *myname = "cdfs_read_attrs"; CDFS_DEBUG_FCN_ENTRY(myname); if((length = isonum_711(file->node.ext_attr_length)) == 0) status = CDFS_ENOENT; else { if(length > 1) cdfs_error(0, myname, "multi-block extents not supported"); /* * Get the next block from the directory. */ lbn = cdfs_bmap(file, -(length * file->cdfs->lbsize)); if((bp = cdfs_getblk(file->cdfs, lbn, 1, &data)) == NULL) { status = CDFS_EIO; } else { bcopy(data, attrs, sizeof(*attrs)); } cdfs_relblk(file->cdfs, bp); } CDFS_DEBUG_FCN_EXIT(myname, status); return(status); }
/* * cdfs_get_dirname - extract a file name from a directory entry. */ static int cdfs_get_fname(struct cdfs_file *file, struct iso_directory_record *dp, char *buffer, int buflen) { char *rripname; int name_len; name_len = isonum_711(dp->name_len); /* * Try for a RRIP alternate name. */ rripname = NULL; if(file->cdfs->flags & CDFS_RRIP) cdfs_get_altname(dp, &rripname, &name_len); /* * Room left in the current buffer? */ if((name_len + 2) > buflen) return(FALSE); /* * Copy the current entry's name. */ if(rripname != NULL) strncat(buffer, rripname, name_len); else cdfs_fncvt(dp->name, buffer, name_len); buffer[name_len] = '\0'; strcat(buffer, "\n"); return(TRUE); }
static ISO_SUSP_HEADER * susp_lookup_record(struct open_file *f, const char *identifier, struct iso_directory_record *dp, int lenskip) { static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE]; ISO_SUSP_HEADER *sh; ISO_RRIP_CONT *shc; char *p, *end; int error; size_t read; p = dp->name + isonum_711(dp->name_len) + lenskip; /* Names of even length have a padding byte after the name. */ if ((isonum_711(dp->name_len) & 1) == 0) p++; end = (char *)dp + isonum_711(dp->length); while (p + 3 < end) { sh = (ISO_SUSP_HEADER *)p; if (bcmp(sh->type, identifier, 2) == 0) return (sh); if (bcmp(sh->type, SUSP_STOP, 2) == 0) return (NULL); if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) { shc = (ISO_RRIP_CONT *)sh; error = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(isonum_733(shc->location)), ISO_DEFAULT_BLOCK_SIZE, susp_buffer, &read); /* Bail if it fails. */ if (error != 0 || read != ISO_DEFAULT_BLOCK_SIZE) return (NULL); p = susp_buffer + isonum_733(shc->offset); end = p + isonum_733(shc->length); } else { /* Ignore this record and skip to the next. */ p += isonum_711(sh->length); /* Avoid infinite loops with corrupted file systems */ if (isonum_711(sh->length) == 0) return (NULL); } } return (NULL); }
/* * Flag indicating */ static int cd9660_rrip_idflag(ISO_RRIP_IDFLAG *p, ISO_RRIP_ANALYZE *ana) { ana->fields &= isonum_711(p->flags)|~0xff; /* don't touch high bits */ /* special handling of RE field */ if (ana->fields&ISO_SUSP_RELDIR) return cd9660_rrip_reldir(/* XXX */ (ISO_RRIP_RELDIR *)p,ana); return ISO_SUSP_IDFLAG; }
static void cd9660_rrip_defname(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana) { isofntrans(isodir->name,isonum_711(isodir->name_len), ana->outbuf,ana->outlen, 1,isonum_711(isodir->flags)&4, ana->imp->joliet_level, ana->imp->im_flags, ana->imp->im_d2l); switch (*ana->outbuf) { default: break; case 1: *ana->outlen = 2; /* FALL THROUGH */ case 0: /* outlen is 1 already */ strcpy(ana->outbuf,".."); break; } }
/* * Extension reference */ static int cd9660_rrip_extref(void *v, ISO_RRIP_ANALYZE *ana) { ISO_RRIP_EXTREF *p = v; if (isonum_711(p->version) != 1) return 0; if (isonum_711(p->len_id) != 9 && isonum_711(p->len_id) != 10) return 0; if (isonum_711(p->len_id) == 9 && memcmp((char *)p + 8, "IEEE_1282", 9)) return 0; if (isonum_711(p->len_id) == 10 && memcmp((char *)p + 8, "IEEE_P1282", 10) && memcmp((char *)p + 8, "RRIP_1991A", 10)) return 0; ana->fields &= ~ISO_SUSP_EXTREF; return ISO_SUSP_EXTREF; }
static void cd9660_rrip_defname(void *v, ISO_RRIP_ANALYZE *ana) { struct iso_directory_record *isodir = v; isofntrans(isodir->name, isonum_711(isodir->name_len), ana->outbuf, ana->outlen, 1, 0, isonum_711(isodir->flags) & 4, ana->imp->im_joliet_level); switch (ana->outbuf[0]) { default: break; case 0: ana->outbuf[0] = '.'; *ana->outlen = 1; break; case 1: strlcpy(ana->outbuf, "..", ana->maxlen - *ana->outlen); *ana->outlen = 2; break; } }
static int pnmatch(const char *path, struct ptable_ent *pp) { char *cp; int i; cp = pp->name; for (i = isonum_711(pp->namlen); --i >= 0; path++, cp++) { if (toupper(*path) == *cp) continue; return 0; } if (*path != '/') return 0; return 1; }
main(int argc, char * argv[]){ int file_addr, file_size; char c; int nbyte; struct iso_primary_descriptor ipd; struct iso_directory_record * idr; int typel_extent, typem_extent; int path_table_size; int i,j; if(argc < 2) return 0; infile = fopen(argv[1],"rb"); file_addr = 32768; lseek(fileno(infile), file_addr, 0); read(fileno(infile), &ipd, sizeof(ipd)); idr = (struct iso_directory_record *) &ipd.root_directory_record; blocksize = isonum_723((char *)ipd.logical_block_size); if( blocksize != 512 && blocksize != 1024 && blocksize != 2048 ) { blocksize = 2048; } file_addr = isonum_733(idr->extent) + isonum_711((char *)idr->ext_attr_length); file_size = isonum_733(idr->size); printf("Root at extent %x, %d bytes\n", file_addr, file_size); file_addr = file_addr * blocksize; check_tree(file_addr, file_size, file_addr); typel_extent = isonum_731((char *)ipd.type_l_path_table); typem_extent = isonum_732((char *)ipd.type_m_path_table); path_table_size = isonum_733(ipd.path_table_size); /* Enable this to get the dump of the path tables */ #if 0 check_path_tables(typel_extent, typem_extent, path_table_size); #endif fclose(infile); if(!ngoof) printf("No errors found\n"); }
static int dirmatch(struct open_file *f, const char *path, struct iso_directory_record *dp, int use_rrip, int lenskip) { size_t len; char *cp; int i, icase; if (use_rrip) cp = rrip_lookup_name(f, dp, lenskip, &len); else cp = NULL; if (cp == NULL) { len = isonum_711(dp->name_len); cp = dp->name; icase = 1; } else icase = 0; for (i = len; --i >= 0; path++, cp++) { if (!*path || *path == '/') break; if (*path == *cp) continue; if (!icase && toupper(*path) == *cp) continue; return 0; } if (*path && *path != '/') return 0; /* * Allow stripping of trailing dots and the version number. * Note that this will find the first instead of the last version * of a file. */ if (i >= 0 && (*cp == ';' || *cp == '.')) { /* This is to prevent matching of numeric extensions */ if (*cp == '.' && cp[1] != ';') return 0; while (--i >= 0) if (*++cp != ';' && (*cp < '0' || *cp > '9')) return 0; } return 1; }
/* * Check for Rock Ridge Extension and return offset of its fields. * Note: We insist on the ER field. */ int cd9660_rrip_offset(struct iso_directory_record *isodir, struct iso_mnt *imp) { ISO_RRIP_OFFSET *p; ISO_RRIP_ANALYZE analyze; imp->rr_skip0 = 0; p = (ISO_RRIP_OFFSET *)(isodir->name + 1); if (bcmp(p,"SP\7\1\276\357",6)) { /* Maybe, it's a CDROM XA disc? */ imp->rr_skip0 = 15; p = (ISO_RRIP_OFFSET *)((char *)p + 15); if (bcmp(p,"SP\7\1\276\357",6)) return -1; } analyze.imp = imp; analyze.fields = ISO_SUSP_EXTREF; if (!(cd9660_rrip_loop(isodir,&analyze,rrip_table_extref)&ISO_SUSP_EXTREF)) return -1; return isonum_711(p->skip); }
/* * cdfs_get_other_attrs - try to get extended and/or POSIX file * attributes. */ static void cdfs_get_other_attrs(struct cdfs_file *file, struct iso_directory_record *dp) { long status; file->flags &= ~CDFS_ALL_ATTRS; /* * Try to get extended attributes. */ if(isonum_711(file->node.ext_attr_length) > 0) { status = cdfs_get_extnd_attrs(file, &file->extnd_attrs); if(status == CDFS_SUCCESS) file->flags |= CDFS_EXTND_ATTRS; } /* * Try to get POSIX attributes. */ if(file->cdfs->flags & CDFS_RRIP) { status = cdfs_get_posix_attrs(dp, &file->posix_attrs); if(status == CDFS_SUCCESS) file->flags |= CDFS_POSIX_ATTRS; } }
void KIso::addBoot(struct el_torito_boot_descriptor* bootdesc) { KISOFUNC; int i; long long size; boot_head boot; boot_entry *be; QString path; KIsoFile *entry; path = "Catalog"; entry = new KIsoFile(this, path, dirent->permissions() & ~S_IFDIR, dirent->date(), dirent->adate(), dirent->cdate(), dirent->user(), dirent->group(), QString(), (long long)isonum_731(bootdesc->boot_catalog) << (long long)11, (long long)2048); dirent->addEntry(entry); if (!ReadBootTable(&readf, isonum_731(bootdesc->boot_catalog), &boot, this)) { i = 1; be = boot.defentry; while (be) { size = BootImageSize(isonum_711(be->data.d_e.media), isonum_721(be->data.d_e.seccount)); path = "Default Image"; if (i > 1) path += " (" + QString::number(i) + ')'; entry = new KIsoFile(this, path, dirent->permissions() & ~S_IFDIR, dirent->date(), dirent->adate(), dirent->cdate(), dirent->user(), dirent->group(), QString(), (long long)isonum_731(be->data.d_e.start) << (long long)11, size << (long long)9); dirent->addEntry(entry); be = be->next; i++; } FreeBootTable(&boot); } }
void K3b::Iso9660::addBoot(struct el_torito_boot_descriptor* bootdesc) { int i,size; boot_head boot; boot_entry *be; QString path; K3b::Iso9660File *entry; entry=new K3b::Iso9660File( this, "Catalog", "Catalog", dirent->permissions() & ~S_IFDIR, dirent->date(), dirent->adate(), dirent->cdate(), dirent->user(), dirent->group(), QString(), isonum_731(bootdesc->boot_catalog), 2048 ); dirent->addEntry(entry); if (!ReadBootTable(&K3b::Iso9660::read_callback,isonum_731(bootdesc->boot_catalog),&boot,this)) { i=1; be=boot.defentry; while (be) { size=BootImageSize(&K3b::Iso9660::read_callback, isonum_711(((struct default_entry*) be->data)->media), isonum_731(((struct default_entry*) be->data)->start), isonum_721(((struct default_entry*) be->data)->seccount), this); path="Default Image"; if (i>1) path += " (" + QString::number(i) + ')'; entry=new K3b::Iso9660File( this, path, path, dirent->permissions() & ~S_IFDIR, dirent->date(), dirent->adate(), dirent->cdate(), dirent->user(), dirent->group(), QString(), isonum_731(((struct default_entry*) be->data)->start), size<<9 ); dirent->addEntry(entry); be=be->next; i++; } FreeBootTable(&boot); } }
static int parse_rock_ridge_inode_internal(struct iso_directory_record *de, struct inode *inode, int regard_xa) { int symlink_len = 0; int cnt, sig; struct inode *reloc; struct rock_ridge *rr; int rootflag; struct rock_state rs; int ret = 0; if (!ISOFS_SB(inode->i_sb)->s_rock) return 0; init_rock_state(&rs, inode); setup_rock_ridge(de, inode, &rs); if (regard_xa) { rs.chr += 14; rs.len -= 14; if (rs.len < 0) rs.len = 0; } repeat: while (rs.len > 2) { /* There may be one byte for padding somewhere */ rr = (struct rock_ridge *)rs.chr; /* * Ignore rock ridge info if rr->len is out of range, but * don't return -EIO because that would make the file * invisible. */ if (rr->len < 3) goto out; /* Something got screwed up here */ sig = isonum_721(rs.chr); if (rock_check_overflow(&rs, sig)) goto eio; rs.chr += rr->len; rs.len -= rr->len; /* * As above, just ignore the rock ridge info if rr->len * is bogus. */ if (rs.len < 0) goto out; /* Something got screwed up here */ switch (sig) { #ifndef CONFIG_ZISOFS /* No flag for SF or ZF */ case SIG('R', 'R'): if ((rr->u.RR.flags[0] & (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) goto out; break; #endif case SIG('S', 'P'): if (check_sp(rr, inode)) goto out; break; case SIG('C', 'E'): rs.cont_extent = isonum_733(rr->u.CE.extent); rs.cont_offset = isonum_733(rr->u.CE.offset); rs.cont_size = isonum_733(rr->u.CE.size); break; case SIG('E', 'R'): ISOFS_SB(inode->i_sb)->s_rock = 1; printk(KERN_DEBUG "ISO 9660 Extensions: "); { int p; for (p = 0; p < rr->u.ER.len_id; p++) printk("%c", rr->u.ER.data[p]); } printk("\n"); break; case SIG('P', 'X'): inode->i_mode = isonum_733(rr->u.PX.mode); set_nlink(inode, isonum_733(rr->u.PX.n_links)); inode->i_uid = isonum_733(rr->u.PX.uid); inode->i_gid = isonum_733(rr->u.PX.gid); break; case SIG('P', 'N'): { int high, low; high = isonum_733(rr->u.PN.dev_high); low = isonum_733(rr->u.PN.dev_low); /* * The Rock Ridge standard specifies that if * sizeof(dev_t) <= 4, then the high field is * unused, and the device number is completely * stored in the low field. Some writers may * ignore this subtlety, * and as a result we test to see if the entire * device number is * stored in the low field, and use that. */ if ((low & ~0xff) && high == 0) { inode->i_rdev = MKDEV(low >> 8, low & 0xff); } else { inode->i_rdev = MKDEV(high, low); } } break; case SIG('T', 'F'): /* * Some RRIP writers incorrectly place ctime in the * TF_CREATE field. Try to handle this correctly for * either case. */ /* Rock ridge never appears on a High Sierra disk */ cnt = 0; if (rr->u.TF.flags & TF_CREATE) { inode->i_ctime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0); inode->i_ctime.tv_nsec = 0; } if (rr->u.TF.flags & TF_MODIFY) { inode->i_mtime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0); inode->i_mtime.tv_nsec = 0; } if (rr->u.TF.flags & TF_ACCESS) { inode->i_atime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0); inode->i_atime.tv_nsec = 0; } if (rr->u.TF.flags & TF_ATTRIBUTES) { inode->i_ctime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0); inode->i_ctime.tv_nsec = 0; } break; case SIG('S', 'L'): { int slen; struct SL_component *slp; struct SL_component *oldslp; slen = rr->len - 5; slp = &rr->u.SL.link; inode->i_size = symlink_len; while (slen > 1) { rootflag = 0; switch (slp->flags & ~1) { case 0: inode->i_size += slp->len; break; case 2: inode->i_size += 1; break; case 4: inode->i_size += 2; break; case 8: rootflag = 1; inode->i_size += 1; break; default: printk("Symlink component flag " "not implemented\n"); } slen -= slp->len + 2; oldslp = slp; slp = (struct SL_component *) (((char *)slp) + slp->len + 2); if (slen < 2) { if (((rr->u.SL. flags & 1) != 0) && ((oldslp-> flags & 1) == 0)) inode->i_size += 1; break; } /* * If this component record isn't * continued, then append a '/'. */ if (!rootflag && (oldslp->flags & 1) == 0) inode->i_size += 1; } } symlink_len = inode->i_size; break; case SIG('R', 'E'): printk(KERN_WARNING "Attempt to read inode for " "relocated directory\n"); goto out; case SIG('C', 'L'): ISOFS_I(inode)->i_first_extent = isonum_733(rr->u.CL.location); reloc = isofs_iget(inode->i_sb, ISOFS_I(inode)->i_first_extent, 0); if (IS_ERR(reloc)) { ret = PTR_ERR(reloc); goto out; } inode->i_mode = reloc->i_mode; set_nlink(inode, reloc->i_nlink); inode->i_uid = reloc->i_uid; inode->i_gid = reloc->i_gid; inode->i_rdev = reloc->i_rdev; inode->i_size = reloc->i_size; inode->i_blocks = reloc->i_blocks; inode->i_atime = reloc->i_atime; inode->i_ctime = reloc->i_ctime; inode->i_mtime = reloc->i_mtime; iput(reloc); break; #ifdef CONFIG_ZISOFS case SIG('Z', 'F'): { int algo; if (ISOFS_SB(inode->i_sb)->s_nocompress) break; algo = isonum_721(rr->u.ZF.algorithm); if (algo == SIG('p', 'z')) { int block_shift = isonum_711(&rr->u.ZF.parms[1]); if (block_shift > 17) { printk(KERN_WARNING "isofs: " "Can't handle ZF block " "size of 2^%d\n", block_shift); } else { /* * Note: we don't change * i_blocks here */ ISOFS_I(inode)->i_file_format = isofs_file_compressed; /* * Parameters to compression * algorithm (header size, * block size) */ ISOFS_I(inode)->i_format_parm[0] = isonum_711(&rr->u.ZF.parms[0]); ISOFS_I(inode)->i_format_parm[1] = isonum_711(&rr->u.ZF.parms[1]); inode->i_size = isonum_733(rr->u.ZF. real_size); } } else { printk(KERN_WARNING "isofs: Unknown ZF compression " "algorithm: %c%c\n", rr->u.ZF.algorithm[0], rr->u.ZF.algorithm[1]); } break; } #endif default: break; }
/* This function is surprisingly simple. The trick is understanding * that "child" is always a directory. So, to find its parent, you * simply need to find its ".." entry, normalize its block and offset, * and return the underlying inode. See the comments for * isofs_normalize_block_and_offset(). */ static struct dentry *isofs_export_get_parent(struct dentry *child) { unsigned long parent_block = 0; unsigned long parent_offset = 0; struct inode *child_inode = child->d_inode; struct iso_inode_info *e_child_inode = ISOFS_I(child_inode); struct iso_directory_record *de = NULL; struct buffer_head * bh = NULL; struct dentry *rv = NULL; /* "child" must always be a directory. */ if (!S_ISDIR(child_inode->i_mode)) { printk(KERN_ERR "isofs: isofs_export_get_parent(): " "child is not a directory!\n"); rv = ERR_PTR(-EACCES); goto out; } /* It is an invariant that the directory offset is zero. If * it is not zero, it means the directory failed to be * normalized for some reason. */ if (e_child_inode->i_iget5_offset != 0) { printk(KERN_ERR "isofs: isofs_export_get_parent(): " "child directory not normalized!\n"); rv = ERR_PTR(-EACCES); goto out; } /* The child inode has been normalized such that its * i_iget5_block value points to the "." entry. Fortunately, * the ".." entry is located in the same block. */ parent_block = e_child_inode->i_iget5_block; /* Get the block in question. */ bh = sb_bread(child_inode->i_sb, parent_block); if (bh == NULL) { rv = ERR_PTR(-EACCES); goto out; } /* This is the "." entry. */ de = (struct iso_directory_record*)bh->b_data; /* The ".." entry is always the second entry. */ parent_offset = (unsigned long)isonum_711(de->length); de = (struct iso_directory_record*)(bh->b_data + parent_offset); /* Verify it is in fact the ".." entry. */ if ((isonum_711(de->name_len) != 1) || (de->name[0] != 1)) { printk(KERN_ERR "isofs: Unable to find the \"..\" " "directory for NFS.\n"); rv = ERR_PTR(-EACCES); goto out; } /* Normalize */ isofs_normalize_block_and_offset(de, &parent_block, &parent_offset); rv = d_obtain_alias(isofs_iget(child_inode->i_sb, parent_block, parent_offset)); out: if (bh) brelse(bh); return rv; }
static int cd9660_open(const char *path, struct open_file *f) { struct file *fp = NULL; void *buf; struct iso_primary_descriptor *vd; size_t buf_size, read, dsize, off; daddr_t bno, boff; struct iso_directory_record rec; struct iso_directory_record *dp = NULL; int rc, first, use_rrip, lenskip; /* First find the volume descriptor */ buf = malloc(buf_size = ISO_DEFAULT_BLOCK_SIZE); vd = buf; for (bno = 16;; bno++) { twiddle(1); rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), ISO_DEFAULT_BLOCK_SIZE, buf, &read); if (rc) goto out; if (read != ISO_DEFAULT_BLOCK_SIZE) { rc = EIO; goto out; } rc = EINVAL; if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0) goto out; if (isonum_711(vd->type) == ISO_VD_END) goto out; if (isonum_711(vd->type) == ISO_VD_PRIMARY) break; } if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE) goto out; rec = *(struct iso_directory_record *) vd->root_directory_record; if (*path == '/') path++; /* eat leading '/' */ first = 1; use_rrip = 0; while (*path) { bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); dsize = isonum_733(rec.size); off = 0; boff = 0; while (off < dsize) { if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) { twiddle(1); rc = f->f_dev->dv_strategy (f->f_devdata, F_READ, cdb2devb(bno + boff), ISO_DEFAULT_BLOCK_SIZE, buf, &read); if (rc) goto out; if (read != ISO_DEFAULT_BLOCK_SIZE) { rc = EIO; goto out; } boff++; dp = (struct iso_directory_record *) buf; } if (isonum_711(dp->length) == 0) { /* skip to next block, if any */ off = boff * ISO_DEFAULT_BLOCK_SIZE; continue; } /* See if RRIP is in use. */ if (first) use_rrip = rrip_check(f, dp, &lenskip); if (dirmatch(f, path, dp, use_rrip, first ? 0 : lenskip)) { first = 0; break; } else first = 0; dp = (struct iso_directory_record *) ((char *) dp + isonum_711(dp->length)); /* If the new block has zero length, it is padding. */ if (isonum_711(dp->length) == 0) { /* Skip to next block, if any. */ off = boff * ISO_DEFAULT_BLOCK_SIZE; continue; } off += isonum_711(dp->length); } if (off >= dsize) { rc = ENOENT; goto out; } rec = *dp; while (*path && *path != '/') /* look for next component */ path++; if (*path) path++; /* skip '/' */ } /* allocate file system specific data structure */ fp = malloc(sizeof(struct file)); bzero(fp, sizeof(struct file)); f->f_fsdata = (void *)fp; if ((isonum_711(rec.flags) & 2) != 0) { fp->f_flags = F_ISDIR; } if (first) { fp->f_flags |= F_ROOTDIR; /* Check for Rock Ridge since we didn't in the loop above. */ bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); twiddle(1); rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), ISO_DEFAULT_BLOCK_SIZE, buf, &read); if (rc) goto out; if (read != ISO_DEFAULT_BLOCK_SIZE) { rc = EIO; goto out; } dp = (struct iso_directory_record *)buf; use_rrip = rrip_check(f, dp, &lenskip); } if (use_rrip) { fp->f_flags |= F_RR; fp->f_susp_skip = lenskip; } fp->f_off = 0; fp->f_bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); fp->f_size = isonum_733(rec.size); free(buf); return 0; out: if (fp) free(fp); free(buf); return rc; }
static int cd9660_rrip_loop(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana, RRIP_TABLE *table) { RRIP_TABLE *ptable; ISO_SUSP_HEADER *phead; ISO_SUSP_HEADER *pend; struct buf *bp = NULL; char *pwhead; u_short c; int result; /* * Note: If name length is odd, * it will be padding 1 byte after the name */ pwhead = isodir->name + isonum_711(isodir->name_len); if (!(isonum_711(isodir->name_len)&1)) pwhead++; isochar(isodir->name, pwhead, ana->imp->joliet_level, &c, NULL, ana->imp->im_flags, ana->imp->im_d2l); /* If it's not the '.' entry of the root dir obey SP field */ if (c != 0 || isonum_733(isodir->extent) != ana->imp->root_extent) pwhead += ana->imp->rr_skip; else pwhead += ana->imp->rr_skip0; phead = (ISO_SUSP_HEADER *)pwhead; pend = (ISO_SUSP_HEADER *)((char *)isodir + isonum_711(isodir->length)); result = 0; while (1) { ana->iso_ce_len = 0; /* * Note: "pend" should be more than one SUSP header */ while (pend >= phead + 1) { if (isonum_711(phead->version) == 1) { for (ptable = table; ptable->func; ptable++) { if (*phead->type == *ptable->type && phead->type[1] == ptable->type[1]) { result |= ptable->func(phead,ana); break; } } if (!ana->fields) break; } if (result&ISO_SUSP_STOP) { result &= ~ISO_SUSP_STOP; break; } /* plausibility check */ if (isonum_711(phead->length) < sizeof(*phead)) break; /* * move to next SUSP * Hopefully this works with newer versions, too */ phead = (ISO_SUSP_HEADER *)((char *)phead + isonum_711(phead->length)); } if (ana->fields && ana->iso_ce_len) { if (ana->iso_ce_blk >= ana->imp->volume_space_size || ana->iso_ce_off + ana->iso_ce_len > ana->imp->logical_block_size || bread(ana->imp->im_devvp, lblktooff(ana->imp, ana->iso_ce_blk), ana->imp->logical_block_size, &bp)) /* what to do now? */ break; phead = (ISO_SUSP_HEADER *)(bp->b_data + ana->iso_ce_off); pend = (ISO_SUSP_HEADER *) ((char *)phead + ana->iso_ce_len); } else break; } if (bp) brelse(bp); /* * If we don't find the Basic SUSP stuffs, just set default value * (attribute/time stamp) */ for (ptable = table; ptable->func2; ptable++) if (!(ptable->result&result)) ptable->func2(isodir,ana); return result; }
static int cd9660_readdir(struct open_file *f, struct dirent *d) { struct file *fp = (struct file *)f->f_fsdata; struct iso_directory_record *ep; size_t buf_size, reclen, namelen; int error = 0; int lenskip; char *buf, *name; again: if (fp->f_off >= fp->f_size) return (ENOENT); error = buf_read_file(f, &buf, &buf_size); if (error) return (error); ep = (struct iso_directory_record *)buf; if (isonum_711(ep->length) == 0) { daddr_t blkno; /* skip to next block, if any */ blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE; fp->f_off = (blkno + 1) * ISO_DEFAULT_BLOCK_SIZE; goto again; } if (fp->f_flags & F_RR) { if (fp->f_flags & F_ROOTDIR && fp->f_off == 0) lenskip = 0; else lenskip = fp->f_susp_skip; name = rrip_lookup_name(f, ep, lenskip, &namelen); } else name = NULL; if (name == NULL) { namelen = isonum_711(ep->name_len); name = ep->name; if (namelen == 1) { if (ep->name[0] == 0) name = "."; else if (ep->name[0] == 1) { namelen = 2; name = ".."; } } } reclen = sizeof(struct dirent) - (MAXNAMLEN+1) + namelen + 1; reclen = (reclen + 3) & ~3; d->d_fileno = isonum_733(ep->extent); d->d_reclen = reclen; if (isonum_711(ep->flags) & 2) d->d_type = DT_DIR; else d->d_type = DT_REG; d->d_namlen = namelen; bcopy(name, d->d_name, d->d_namlen); d->d_name[d->d_namlen] = 0; fp->f_off += isonum_711(ep->length); return (0); }
/* * Symbolic Links */ static int cd9660_rrip_slink(ISO_RRIP_SLINK *p, ISO_RRIP_ANALYZE *ana) { ISO_RRIP_SLINK_COMPONENT *pcomp; ISO_RRIP_SLINK_COMPONENT *pcompe; int error, len, wlen, cont; char *outbuf, *inbuf, *freebuf; pcomp = (ISO_RRIP_SLINK_COMPONENT *)p->component; pcompe = (ISO_RRIP_SLINK_COMPONENT *)((char *)p + isonum_711(p->h.length)); len = *ana->outlen; outbuf = ana->outbuf; cont = ana->cont; freebuf = NULL; /* * Gathering a Symbolic name from each component with path */ for (; pcomp < pcompe; pcomp = (ISO_RRIP_SLINK_COMPONENT *)((char *)pcomp + ISO_RRIP_SLSIZ + isonum_711(pcomp->clen))) { if (!cont) { if (len < ana->maxlen) { len++; *outbuf++ = '/'; } } cont = 0; inbuf = ".."; wlen = 0; switch (*pcomp->cflag) { case ISO_SUSP_CFLAG_CURRENT: /* Inserting Current */ wlen = 1; break; case ISO_SUSP_CFLAG_PARENT: /* Inserting Parent */ wlen = 2; break; case ISO_SUSP_CFLAG_ROOT: /* Inserting slash for ROOT */ /* start over from beginning(?) */ outbuf -= len; len = 0; break; case ISO_SUSP_CFLAG_VOLROOT: /* Inserting a mount point i.e. "/cdrom" */ /* same as above */ outbuf -= len; len = 0; error = cache_fullpath(NULL, &ana->imp->im_mountp->mnt_ncmountpt, &inbuf, &freebuf, 0); if (error) goto bad; wlen = strlen(inbuf); break; case ISO_SUSP_CFLAG_HOST: /* Inserting hostname i.e. "kurt.tools.de" */ inbuf = hostname; wlen = strlen(hostname); break; case ISO_SUSP_CFLAG_CONTINUE: cont = 1; /* fall thru */ case 0: /* Inserting component */ wlen = isonum_711(pcomp->clen); inbuf = pcomp->name; break; default: kprintf("RRIP with incorrect flags?"); wlen = ana->maxlen + 1; break; } if (len + wlen > ana->maxlen) goto bad; bcopy(inbuf,outbuf,wlen); outbuf += wlen; len += wlen; if (freebuf != NULL) { kfree(freebuf, M_TEMP); freebuf = NULL; } } ana->outbuf = outbuf; *ana->outlen = len; ana->cont = cont; if (!isonum_711(p->flags)) { ana->fields &= ~ISO_SUSP_SLINK; return ISO_SUSP_SLINK; } return 0; bad: if (freebuf != NULL) kfree(freebuf, M_TEMP); ana->cont = 1; ana->fields = 0; ana->outbuf -= *ana->outlen; *ana->outlen = 0; return 0; }