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 + -
显示快捷键?