📄 inode.c
字号:
/* * linux/fs/isofs/inode.c * * (C) 1991 Linus Torvalds - minix filesystem * 1992, 1993, 1994 Eric Youngdale Modified for ISO9660 filesystem. * 1994 Eberhard Moenkeberg - multi session handling. * 1995 Mark Dobie - allow mounting of some weird VideoCDs and PhotoCDs. * */#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/malloc.h>#include <linux/errno.h>#include <linux/cdrom.h>#include <linux/nls.h>#include <asm/system.h>#include <asm/segment.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#ifdef LEAK_CHECKstatic int check_malloc = 0;static int check_bread = 0;#endifvoid isofs_put_super(struct super_block *sb){ 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; } lock_super(sb);#ifdef LEAK_CHECK printk("Outstanding mallocs:%d, outstanding buffers: %d\n", check_malloc, check_bread);#endif sb->s_dev = 0; unlock_super(sb); MOD_DEC_USE_COUNT; return;}static struct super_operations isofs_sops = { isofs_read_inode, NULL, /* notify_change */ NULL, /* write_inode */ NULL, /* put_inode */ isofs_put_super, NULL, /* write_super */ isofs_statfs, NULL};struct iso9660_options{ char map; char rock; char joliet; char cruft; char unhide; unsigned char check; unsigned char conversion; unsigned int blocksize; mode_t mode; gid_t gid; uid_t uid; char *iocharset; unsigned char utf8;};static int parse_options(char *options, struct iso9660_options * popt){ char *this_char,*value,*p; int len; popt->map = 'n'; popt->rock = 'y'; popt->joliet = 'y'; popt->cruft = 'n'; popt->unhide = 'n'; popt->check = 's'; /* default: strict */ popt->conversion = 'b'; /* default: no conversion */ popt->blocksize = 1024; popt->mode = S_IRUGO; popt->gid = 0; popt->uid = 0; popt->iocharset = NULL; popt->utf8 = 0; 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 ((value = strchr(this_char,'=')) != NULL) *value++ = 0; if (!strcmp(this_char,"iocharset")) { p = value; while (*value && *value != ',') value++; len = value - p; if (len) { popt->iocharset = kmalloc(len+1, GFP_KERNEL); memcpy(popt->iocharset, p, len); popt->iocharset[len] = 0; } else { popt->iocharset = NULL; return 0; } } else if (!strcmp(this_char,"map") && value) { if (value[0] && !value[1] && strchr("on",*value)) popt->map = *value; else if (!strcmp(value,"off")) popt->map = 'o'; else if (!strcmp(value,"normal")) popt->map = 'n'; else return 0; } 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) { if (value[0] && !value[1] && strchr("btma",*value)) popt->conversion = *value; else if (!strcmp(value,"binary")) popt->conversion = 'b'; else if (!strcmp(value,"text")) popt->conversion = 't'; else if (!strcmp(value,"mtext")) popt->conversion = 'm'; else if (!strcmp(value,"auto")) popt->conversion = 'a'; 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(kdev_t dev){ struct cdrom_multisession ms_info; unsigned int vol_desc_start; struct inode inode_fake; extern struct file_operations * get_blkfops(unsigned int); int i; vol_desc_start=0; if (get_blkfops(MAJOR(dev))->ioctl!=NULL) { /* Whoops. We must save the old FS, since otherwise * we would destroy the kernels idea about FS on root * mount in read_super... [chexum] */ unsigned long old_fs=get_fs(); inode_fake.i_rdev=dev; ms_info.addr_format=CDROM_LBA; set_fs(KERNEL_DS); i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake, NULL, CDROMMULTISESSION, (unsigned long) &ms_info); set_fs(old_fs);#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 0 if (i==0)#if WE_OBEY_THE_WRITTEN_STANDARDS if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */#endif WE_OBEY_THE_WRITTEN_STANDARDS vol_desc_start=ms_info.addr.lba; } return vol_desc_start;}struct super_block *isofs_read_super(struct super_block *s,void *data, int silent){ struct buffer_head *bh=NULL; int iso_blknum; unsigned int blocksize_bits; int high_sierra; kdev_t dev = s->s_dev; unsigned int vol_desc_start; int orig_zonesize; char *p; int joliet_level = 0; struct iso_volume_descriptor *vdp; struct hs_volume_descriptor *hdp; struct iso_primary_descriptor *pri = NULL; struct iso_supplementary_descriptor *sec = NULL; struct hs_primary_descriptor *h_pri = NULL; struct iso_directory_record *rootp; struct iso9660_options opt; MOD_INC_USE_COUNT; if (!parse_options((char *) data,&opt)) { s->s_dev = 0; MOD_DEC_USE_COUNT; return NULL; }#if 0 printk("map = %c\n", opt.map); printk("rock = %c\n", opt.rock); printk("joliet = %c\n", opt.joliet); printk("check = %c\n", opt.check); printk("cruft = %c\n", opt.cruft); printk("unhide = %c\n", opt.unhide); printk("conversion = %c\n", opt.conversion); printk("blocksize = %d\n", opt.blocksize); printk("gid = %d\n", opt.gid); printk("uid = %d\n", opt.uid);#endif blocksize_bits = 0; { int i = opt.blocksize; while (i != 1){ blocksize_bits++; i >>=1; } } set_blocksize(dev, opt.blocksize); lock_super(s); s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */ vol_desc_start = isofs_get_last_session(dev); for (iso_blknum = vol_desc_start+16; iso_blknum < vol_desc_start+100; iso_blknum++) { int b = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits); if (!(bh = bread(dev,b,opt.blocksize))) { s->s_dev = 0; printk("isofs_read_super: bread failed, dev " "%s iso_blknum %d block %d\n", kdevname(dev), iso_blknum, b); unlock_super(s); MOD_DEC_USE_COUNT; return NULL; } vdp = (struct iso_volume_descriptor *)bh->b_data; hdp = (struct hs_volume_descriptor *)bh->b_data; if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) { if (isonum_711 (hdp->type) != ISO_VD_PRIMARY) goto out; if (isonum_711 (hdp->type) == ISO_VD_END) goto out; s->u.isofs_sb.s_high_sierra = 1; high_sierra = 1; opt.rock = 'n'; h_pri = (struct hs_primary_descriptor *)vdp; break; } if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) { if (isonum_711 (vdp->type) == ISO_VD_END) break; if (isonum_711 (vdp->type) == ISO_VD_PRIMARY) { if (pri == NULL) { pri = (struct iso_primary_descriptor *)vdp; } } else if (isonum_711 (vdp->type) == ISO_VD_SUPPLEMENTARY) { sec = (struct iso_supplementary_descriptor *)vdp; if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) { if (opt.joliet == 'y') { if (sec->escape[2] == 0x40) { joliet_level = 1; } else if (sec->escape[2] == 0x43) { joliet_level = 2; } else if (sec->escape[2] == 0x45) { joliet_level = 3; } printk("ISO9660 Extensions: Microsoft Joliet Level %d\n", joliet_level); } break; } else { /* Unknown supplementary volume descriptor */ sec = NULL; } } /* Just skip any volume descriptors we don't recognize */ } brelse(bh); } if ((pri == NULL) && (sec == NULL) && (h_pri == NULL)) { if (!silent) printk("Unable to identify CD-ROM format.\n"); s->s_dev = 0; unlock_super(s); MOD_DEC_USE_COUNT; return NULL; } s->u.isofs_sb.s_joliet_level = joliet_level; if (joliet_level && opt.rock == 'n') { /* This is the case of Joliet with the norock mount flag. * A disc with both Joliet and Rock Ridge is handled later */ pri = (struct iso_primary_descriptor *) sec; } if(high_sierra){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -