⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rock.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/fs/isofs/rock.c * *  (C) 1992, 1993  Eric Youngdale * *  Rock Ridge Extensions to iso9660 */#include <linux/slab.h>#include <linux/pagemap.h>#include <linux/smp_lock.h>#include "isofs.h"#include "rock.h"/* * These functions are designed to read the system areas of a directory record * and extract relevant information.  There are different functions provided * depending upon what information we need at the time.  One function fills * out an inode structure, a second one extracts a filename, a third one * returns a symbolic link name, and a fourth one returns the extent number * for the file. */#define SIG(A,B) ((A) | ((B) << 8))	/* isonum_721() */struct rock_state {	void *buffer;	unsigned char *chr;	int len;	int cont_size;	int cont_extent;	int cont_offset;	struct inode *inode;};/* * This is a way of ensuring that we have something in the system * use fields that is compatible with Rock Ridge.  Return zero on success. */static int check_sp(struct rock_ridge *rr, struct inode *inode){	if (rr->u.SP.magic[0] != 0xbe)		return -1;	if (rr->u.SP.magic[1] != 0xef)		return -1;	ISOFS_SB(inode->i_sb)->s_rock_offset = rr->u.SP.skip;	return 0;}static void setup_rock_ridge(struct iso_directory_record *de,			struct inode *inode, struct rock_state *rs){	rs->len = sizeof(struct iso_directory_record) + de->name_len[0];	if (rs->len & 1)		(rs->len)++;	rs->chr = (unsigned char *)de + rs->len;	rs->len = *((unsigned char *)de) - rs->len;	if (rs->len < 0)		rs->len = 0;	if (ISOFS_SB(inode->i_sb)->s_rock_offset != -1) {		rs->len -= ISOFS_SB(inode->i_sb)->s_rock_offset;		rs->chr += ISOFS_SB(inode->i_sb)->s_rock_offset;		if (rs->len < 0)			rs->len = 0;	}}static void init_rock_state(struct rock_state *rs, struct inode *inode){	memset(rs, 0, sizeof(*rs));	rs->inode = inode;}/* * Returns 0 if the caller should continue scanning, 1 if the scan must end * and -ve on error. */static int rock_continue(struct rock_state *rs){	int ret = 1;	int blocksize = 1 << rs->inode->i_blkbits;	const int min_de_size = offsetof(struct rock_ridge, u);	kfree(rs->buffer);	rs->buffer = NULL;	if ((unsigned)rs->cont_offset > blocksize - min_de_size ||	    (unsigned)rs->cont_size > blocksize ||	    (unsigned)(rs->cont_offset + rs->cont_size) > blocksize) {		printk(KERN_NOTICE "rock: corrupted directory entry. "			"extent=%d, offset=%d, size=%d\n",			rs->cont_extent, rs->cont_offset, rs->cont_size);		ret = -EIO;		goto out;	}	if (rs->cont_extent) {		struct buffer_head *bh;		rs->buffer = kmalloc(rs->cont_size, GFP_KERNEL);		if (!rs->buffer) {			ret = -ENOMEM;			goto out;		}		ret = -EIO;		bh = sb_bread(rs->inode->i_sb, rs->cont_extent);		if (bh) {			memcpy(rs->buffer, bh->b_data + rs->cont_offset,					rs->cont_size);			put_bh(bh);			rs->chr = rs->buffer;			rs->len = rs->cont_size;			rs->cont_extent = 0;			rs->cont_size = 0;			rs->cont_offset = 0;			return 0;		}		printk("Unable to read rock-ridge attributes\n");	}out:	kfree(rs->buffer);	rs->buffer = NULL;	return ret;}/* * We think there's a record of type `sig' at rs->chr.  Parse the signature * and make sure that there's really room for a record of that type. */static int rock_check_overflow(struct rock_state *rs, int sig){	int len;	switch (sig) {	case SIG('S', 'P'):		len = sizeof(struct SU_SP_s);		break;	case SIG('C', 'E'):		len = sizeof(struct SU_CE_s);		break;	case SIG('E', 'R'):		len = sizeof(struct SU_ER_s);		break;	case SIG('R', 'R'):		len = sizeof(struct RR_RR_s);		break;	case SIG('P', 'X'):		len = sizeof(struct RR_PX_s);		break;	case SIG('P', 'N'):		len = sizeof(struct RR_PN_s);		break;	case SIG('S', 'L'):		len = sizeof(struct RR_SL_s);		break;	case SIG('N', 'M'):		len = sizeof(struct RR_NM_s);		break;	case SIG('C', 'L'):		len = sizeof(struct RR_CL_s);		break;	case SIG('P', 'L'):		len = sizeof(struct RR_PL_s);		break;	case SIG('T', 'F'):		len = sizeof(struct RR_TF_s);		break;	case SIG('Z', 'F'):		len = sizeof(struct RR_ZF_s);		break;	default:		len = 0;		break;	}	len += offsetof(struct rock_ridge, u);	if (len > rs->len) {		printk(KERN_NOTICE "rock: directory entry would overflow "				"storage\n");		printk(KERN_NOTICE "rock: sig=0x%02x, size=%d, remaining=%d\n",				sig, len, rs->len);		return -EIO;	}	return 0;}/* * return length of name field; 0: not found, -1: to be ignored */int get_rock_ridge_filename(struct iso_directory_record *de,			    char *retname, struct inode *inode){	struct rock_state rs;	struct rock_ridge *rr;	int sig;	int retnamlen = 0;	int truncate = 0;	int ret = 0;	if (!ISOFS_SB(inode->i_sb)->s_rock)		return 0;	*retname = 0;	init_rock_state(&rs, inode);	setup_rock_ridge(de, inode, &rs);repeat:	while (rs.len > 2) { /* There may be one byte for padding somewhere */		rr = (struct rock_ridge *)rs.chr;		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;		if (rs.len < 0)			goto eio;	/* corrupted isofs */		switch (sig) {		case SIG('R', 'R'):			if ((rr->u.RR.flags[0] & RR_NM) == 0)				goto out;			break;		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('N', 'M'):			if (truncate)				break;			if (rr->len < 5)				break;			/*			 * If the flags are 2 or 4, this indicates '.' or '..'.			 * We don't want to do anything with this, because it			 * screws up the code that calls us.  We don't really			 * care anyways, since we can just use the non-RR			 * name.			 */			if (rr->u.NM.flags & 6)				break;			if (rr->u.NM.flags & ~1) {				printk("Unsupported NM flag settings (%d)\n",					rr->u.NM.flags);				break;			}			if ((strlen(retname) + rr->len - 5) >= 254) {				truncate = 1;				break;			}			strncat(retname, rr->u.NM.name, rr->len - 5);			retnamlen += rr->len - 5;			break;		case SIG('R', 'E'):			kfree(rs.buffer);			return -1;		default:			break;		}	}	ret = rock_continue(&rs);	if (ret == 0)		goto repeat;	if (ret == 1)		return retnamlen; /* If 0, this file did not have a NM field */out:	kfree(rs.buffer);	return ret;eio:	ret = -EIO;	goto out;}static intparse_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;		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;		if (rs.len < 0)			goto eio;	/* corrupted isofs */		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);			inode->i_nlink = 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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -