inode.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,432 行 · 第 1/3 页
C
1,432 行
/* * 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/malloc.h>#include <linux/errno.h>#include <linux/cdrom.h>#include <linux/init.h>#include <linux/nls.h>#include <linux/ctype.h>#include <asm/system.h>#include <asm/uaccess.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_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);static int isofs_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_cmpi_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);static int isofs_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);#endifvoid 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 MOD_DEC_USE_COUNT; return;}static struct super_operations isofs_sops = { isofs_read_inode, NULL, /* write_inode */ NULL, /* put_inode */ NULL, /* delete_inode */ NULL, /* notify_change */ isofs_put_super, NULL, /* write_super */ isofs_statfs, NULL};static struct dentry_operations isofs_dentry_ops[] = { { NULL, /* d_revalidate */ isofs_hash, isofs_cmp, NULL /* d_delete */ }, { NULL, /* d_revalidate */ isofs_hashi, isofs_cmpi, NULL /* d_delete */ },#ifdef CONFIG_JOLIET { NULL, /* d_revalidate */ isofs_hash_ms, isofs_cmp_ms, NULL /* d_delete */ }, { NULL, /* d_revalidate */ isofs_hashi_ms, isofs_cmpi_ms, NULL /* d_delete */ }#endif};struct iso9660_options{ char map; char rock; char joliet; char cruft; char unhide; unsigned char check; unsigned int blocksize; mode_t mode; gid_t gid; uid_t uid; char *iocharset; unsigned char utf8;};/* * 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_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_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_cmp(struct dentry *dentry,struct qstr *a,struct qstr *b){ return isofs_cmp_common(dentry, a, b, 0);}static intisofs_cmpi(struct dentry *dentry,struct qstr *a,struct qstr *b){ return isofs_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_cmp_ms(struct dentry *dentry,struct qstr *a,struct qstr *b){ return isofs_cmp_common(dentry, a, b, 1);}static intisofs_cmpi_ms(struct dentry *dentry,struct qstr *a,struct qstr *b){ return isofs_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->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; 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;#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; } 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(kdev_t dev){#ifdef OSKIT return 0;#else /* not OSKIT */ struct cdrom_multisession ms_info; unsigned int vol_desc_start; struct inode inode_fake; struct file_operations *fops; extern struct file_operations * get_blkfops(unsigned int); int i; vol_desc_start=0; fops = get_blkfops(MAJOR(dev)); if (fops && fops->ioctl) { /* Whoops. We must save the old FS, since otherwise * we would destroy the kernels idea about FS on root * mount in read_super... [chexum] */ mm_segment_t 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 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;#endif /* OSKIT */}/* * 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. */struct super_block *isofs_read_super(struct super_block *s, void *data, int silent){ kdev_t dev = s->s_dev; struct buffer_head * bh = NULL, *pri_bh = NULL; struct hs_primary_descriptor * h_pri = NULL; struct iso_primary_descriptor * pri = NULL; struct iso_supplementary_descriptor *sec = NULL; struct iso_directory_record * rootp; int joliet_level = 0; int high_sierra; int iso_blknum, block; int orig_zonesize; int table; unsigned int blocksize, blocksize_bits; unsigned int vol_desc_start; unsigned long first_data_zone; struct inode * inode; struct iso9660_options opt;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?