📄 inode.c
字号:
/* * linux/fs/isofs/inode.c * * (C) 1991 Linus Torvalds - minix filesystem * 1992, 1993, 1994 Eric Youngdale Modified for ISO 9660 filesystem. * 1994 Eberhard Moenkeberg - multi session handling. * 1995 Mark Dobie - allow mounting of some weird VideoCDs and PhotoCDs. * 1997 Gordon Chaffee - Joliet CDs * 1998 Eric Lammerts - ISO 9660 Level 3 */#include <linux/config.h>#include <linux/module.h>#include <linux/stat.h>#include <linux/sched.h>#include <linux/iso_fs.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/locks.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/cdrom.h>#include <linux/init.h>#include <linux/nls.h>#include <linux/ctype.h>#include <linux/smp_lock.h>#include <linux/blkdev.h>#include <asm/system.h>#include <asm/uaccess.h>#include "zisofs.h"/* * We have no support for "multi volume" CDs, but more and more disks carry * wrong information within the volume descriptors. */#define IGNORE_WRONG_MULTI_VOLUME_SPECS#define BEQUIET#ifdef LEAK_CHECKstatic int check_malloc = 0;static int check_bread = 0;#endifstatic int isofs_hashi(struct dentry *parent, struct qstr *qstr);static int isofs_hash(struct dentry *parent, struct qstr *qstr);static int isofs_dentry_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);static int isofs_dentry_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b);#ifdef CONFIG_JOLIETstatic int isofs_hashi_ms(struct dentry *parent, struct qstr *qstr);static int isofs_hash_ms(struct dentry *parent, struct qstr *qstr);static int isofs_dentry_cmpi_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);static int isofs_dentry_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);#endifstatic void isofs_put_super(struct super_block *sb){#ifdef CONFIG_JOLIET if (sb->u.isofs_sb.s_nls_iocharset) { unload_nls(sb->u.isofs_sb.s_nls_iocharset); sb->u.isofs_sb.s_nls_iocharset = NULL; }#endif#ifdef LEAK_CHECK printk("Outstanding mallocs:%d, outstanding buffers: %d\n", check_malloc, check_bread);#endif return;}static void isofs_read_inode(struct inode *);static int isofs_statfs (struct super_block *, struct statfs *);static struct super_operations isofs_sops = { read_inode: isofs_read_inode, put_super: isofs_put_super, statfs: isofs_statfs,};static struct dentry_operations isofs_dentry_ops[] = { { d_hash: isofs_hash, d_compare: isofs_dentry_cmp, }, { d_hash: isofs_hashi, d_compare: isofs_dentry_cmpi, },#ifdef CONFIG_JOLIET { d_hash: isofs_hash_ms, d_compare: isofs_dentry_cmp_ms, }, { d_hash: isofs_hashi_ms, d_compare: isofs_dentry_cmpi_ms, }#endif};struct iso9660_options{ char map; char rock; char joliet; char cruft; char unhide; char nocompress; unsigned char check; unsigned int blocksize; mode_t mode; gid_t gid; uid_t uid; char *iocharset; unsigned char utf8; /* LVE */ s32 session; s32 sbsector;};/* * Compute the hash for the isofs name corresponding to the dentry. */static intisofs_hash_common(struct dentry *dentry, struct qstr *qstr, int ms){ const char *name; int len; len = qstr->len; name = qstr->name; if (ms) { while (len && name[len-1] == '.') len--; } qstr->hash = full_name_hash(name, len); return 0;}/* * Compute the hash for the isofs name corresponding to the dentry. */static intisofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms){ const char *name; int len; char c; unsigned long hash; len = qstr->len; name = qstr->name; if (ms) { while (len && name[len-1] == '.') len--; } hash = init_name_hash(); while (len--) { c = tolower(*name++); hash = partial_name_hash(tolower(c), hash); } qstr->hash = end_name_hash(hash); return 0;}/* * Case insensitive compare of two isofs names. */static intisofs_dentry_cmpi_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int ms){ int alen, blen; /* A filename cannot end in '.' or we treat it like it has none */ alen = a->len; blen = b->len; if (ms) { while (alen && a->name[alen-1] == '.') alen--; while (blen && b->name[blen-1] == '.') blen--; } if (alen == blen) { if (strnicmp(a->name, b->name, alen) == 0) return 0; } return 1;}/* * Case sensitive compare of two isofs names. */static intisofs_dentry_cmp_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int ms){ int alen, blen; /* A filename cannot end in '.' or we treat it like it has none */ alen = a->len; blen = b->len; if (ms) { while (alen && a->name[alen-1] == '.') alen--; while (blen && b->name[blen-1] == '.') blen--; } if (alen == blen) { if (strncmp(a->name, b->name, alen) == 0) return 0; } return 1;}static intisofs_hash(struct dentry *dentry, struct qstr *qstr){ return isofs_hash_common(dentry, qstr, 0);}static intisofs_hashi(struct dentry *dentry, struct qstr *qstr){ return isofs_hashi_common(dentry, qstr, 0);}static intisofs_dentry_cmp(struct dentry *dentry,struct qstr *a,struct qstr *b){ return isofs_dentry_cmp_common(dentry, a, b, 0);}static intisofs_dentry_cmpi(struct dentry *dentry,struct qstr *a,struct qstr *b){ return isofs_dentry_cmpi_common(dentry, a, b, 0);}#ifdef CONFIG_JOLIETstatic intisofs_hash_ms(struct dentry *dentry, struct qstr *qstr){ return isofs_hash_common(dentry, qstr, 1);}static intisofs_hashi_ms(struct dentry *dentry, struct qstr *qstr){ return isofs_hashi_common(dentry, qstr, 1);}static intisofs_dentry_cmp_ms(struct dentry *dentry,struct qstr *a,struct qstr *b){ return isofs_dentry_cmp_common(dentry, a, b, 1);}static intisofs_dentry_cmpi_ms(struct dentry *dentry,struct qstr *a,struct qstr *b){ return isofs_dentry_cmpi_common(dentry, a, b, 1);}#endifstatic int parse_options(char *options, struct iso9660_options * popt){ char *this_char,*value; popt->map = 'n'; popt->rock = 'y'; popt->joliet = 'y'; popt->cruft = 'n'; popt->unhide = 'n'; popt->check = 'u'; /* unset */ popt->nocompress = 0; popt->blocksize = 1024; popt->mode = S_IRUGO | S_IXUGO; /* r-x for all. The disc could be shared with DOS machines so virtually anything could be a valid executable. */ popt->gid = 0; popt->uid = 0; popt->iocharset = NULL; popt->utf8 = 0; popt->session=-1; popt->sbsector=-1; if (!options) return 1; for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) { if (strncmp(this_char,"norock",6) == 0) { popt->rock = 'n'; continue; } if (strncmp(this_char,"nojoliet",8) == 0) { popt->joliet = 'n'; continue; } if (strncmp(this_char,"unhide",6) == 0) { popt->unhide = 'y'; continue; } if (strncmp(this_char,"cruft",5) == 0) { popt->cruft = 'y'; continue; } if (strncmp(this_char,"utf8",4) == 0) { popt->utf8 = 1; continue; } if (strncmp(this_char,"nocompress",10) == 0) { popt->nocompress = 1; continue; } if ((value = strchr(this_char,'=')) != NULL) *value++ = 0;#ifdef CONFIG_JOLIET if (!strcmp(this_char,"iocharset") && value) { popt->iocharset = value; while (*value && *value != ',') value++; if (value == popt->iocharset) return 0; *value = 0; } else#endif if (!strcmp(this_char,"map") && value) { if (value[0] && !value[1] && strchr("ano",*value)) popt->map = *value; else if (!strcmp(value,"off")) popt->map = 'o'; else if (!strcmp(value,"normal")) popt->map = 'n'; else if (!strcmp(value,"acorn")) popt->map = 'a'; else return 0; } if (!strcmp(this_char,"session") && value) { char * vpnt = value; unsigned int ivalue = simple_strtoul(vpnt, &vpnt, 0); if(ivalue < 0 || ivalue >99) return 0; popt->session=ivalue+1; } if (!strcmp(this_char,"sbsector") && value) { char * vpnt = value; unsigned int ivalue = simple_strtoul(vpnt, &vpnt, 0); if(ivalue < 0 || ivalue >660*512) return 0; popt->sbsector=ivalue; } else if (!strcmp(this_char,"check") && value) { if (value[0] && !value[1] && strchr("rs",*value)) popt->check = *value; else if (!strcmp(value,"relaxed")) popt->check = 'r'; else if (!strcmp(value,"strict")) popt->check = 's'; else return 0; } else if (!strcmp(this_char,"conv") && value) { /* no conversion is done anymore; we still accept the same mount options, but ignore them */ if (value[0] && !value[1] && strchr("btma",*value)) ; else if (!strcmp(value,"binary")) ; else if (!strcmp(value,"text")) ; else if (!strcmp(value,"mtext")) ; else if (!strcmp(value,"auto")) ; else return 0; } else if (value && (!strcmp(this_char,"block") || !strcmp(this_char,"mode") || !strcmp(this_char,"uid") || !strcmp(this_char,"gid"))) { char * vpnt = value; unsigned int ivalue = simple_strtoul(vpnt, &vpnt, 0); if (*vpnt) return 0; switch(*this_char) { case 'b': if ( ivalue != 512 && ivalue != 1024 && ivalue != 2048) return 0; popt->blocksize = ivalue; break; case 'u': popt->uid = ivalue; break; case 'g': popt->gid = ivalue; break; case 'm': popt->mode = ivalue; break; } } else return 1; } return 1;}/* * look if the driver can tell the multi session redirection value * * don't change this if you don't know what you do, please! * Multisession is legal only with XA disks. * A non-XA disk with more than one volume descriptor may do it right, but * usually is written in a nowhere standardized "multi-partition" manner. * Multisession uses absolute addressing (solely the first frame of the whole * track is #0), multi-partition uses relative addressing (each first frame of * each track is #0), and a track is not a session. * * A broken CDwriter software or drive firmware does not set new standards, * at least not if conflicting with the existing ones. * * emoenke@gwdg.de */#define WE_OBEY_THE_WRITTEN_STANDARDS 1static unsigned int isofs_get_last_session(struct super_block *sb,s32 session ){ struct cdrom_multisession ms_info; unsigned int vol_desc_start; struct block_device *bdev = sb->s_bdev; int i; vol_desc_start=0; ms_info.addr_format=CDROM_LBA; if(session >= 0 && session <= 99) { struct cdrom_tocentry Te; Te.cdte_track=session; Te.cdte_format=CDROM_LBA; i = ioctl_by_bdev(bdev, CDROMREADTOCENTRY, (unsigned long) &Te); if (!i) { printk(KERN_DEBUG "Session %d start %d type %d\n", session, Te.cdte_addr.lba, Te.cdte_ctrl&CDROM_DATA_TRACK); if ((Te.cdte_ctrl&CDROM_DATA_TRACK) == 4) return Te.cdte_addr.lba; } printk(KERN_ERR "Invalid session number or type of track\n"); } i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info); if(session > 0) printk(KERN_ERR "Invalid session number\n");#if 0 printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i); if (i==0) { printk("isofs.inode: XA disk: %s\n",ms_info.xa_flag?"yes":"no"); printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba); }#endif if (i==0)#if WE_OBEY_THE_WRITTEN_STANDARDS if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */#endif vol_desc_start=ms_info.addr.lba; return vol_desc_start;}/* * Initialize the superblock and read the root inode. * * Note: a check_disk_change() has been done immediately prior * to this call, so we don't need to check again. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -