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

📄 hpfs_fs.c

📁 Linux 1.0 内核C源代码 Linux最早版本代码 由Linus Torvalds亲自书写的
💻 C
📖 第 1 页 / 共 3 页
字号:
		else if (!strcmp(p, "case")) {
			if (!strcmp(rhs, "lower"))
				*lowercase = 1;
			else if (!strcmp(rhs, "asis"))
				*lowercase = 0;
			else
				return 0;
		}
		else if (!strcmp(p, "conv")) {
			if (!strcmp(rhs, "binary"))
				*conv = CONV_BINARY;
			else if (!strcmp(rhs, "text"))
				*conv = CONV_TEXT;
			else if (!strcmp(rhs, "auto"))
				*conv = CONV_AUTO;
			else
				return 0;
		}
		else
			return 0;
	}

	return 1;
}

/*
 * read_inode.  This is called with exclusive access to a new inode that
 * has only (i_dev,i_ino) set.  It is responsible for filling in the rest.
 * We leave the dates blank, to be filled in from the dir entry.
 *
 * NOTE that there must be no sleeping from the return in this routine
 * until lookup() finishes filling in the inode, otherwise the partly
 * completed inode would be visible during the sleep.
 *
 * It is done in this strange and sinful way because the alternative
 * is to read the fnode, find the dir pointer in it, read that fnode
 * to get the dnode pointer, search through that whole directory for
 * the ino we're reading, and get the dates.  It works that way, but
 * ls sounds like fsck.
 */

static void hpfs_read_inode(struct inode *inode)
{
	struct super_block *s = inode->i_sb;

	/* be ready to bail out */

	inode->i_op = 0;
	inode->i_mode = 0;

	if (inode->i_ino == 0
	    || ino_secno(inode->i_ino) >= inode->i_sb->s_hpfs_fs_size) {
		printk("HPFS: read_inode: bad ino\n");
		return;
	}

	/*
	 * canned stuff
	 */

	inode->i_uid = s->s_hpfs_uid;
	inode->i_gid = s->s_hpfs_gid;
	inode->i_mode = s->s_hpfs_mode;
	inode->i_hpfs_conv = s->s_hpfs_conv;

	inode->i_hpfs_dno = 0;
	inode->i_hpfs_n_secs = 0;
	inode->i_hpfs_file_sec = 0;
	inode->i_hpfs_disk_sec = 0;
	inode->i_hpfs_dpos = 0;
	inode->i_hpfs_dsubdno = 0;

	/*
	 * figure out whether we are looking at a directory or a file
	 */

	if (ino_is_dir(inode->i_ino))
		inode->i_mode |= S_IFDIR;
	else {
		inode->i_mode |= S_IFREG;
		inode->i_mode &= ~0111;
	}

	/*
	 * these fields must be filled in from the dir entry, which we don't
	 * have but lookup does.  It will fill them in before letting the
	 * inode out of its grasp.
	 */

	inode->i_atime = 0;
	inode->i_mtime = 0;
	inode->i_ctime = 0;
	inode->i_size = 0;

	/*
	 * fill in the rest
	 */

	if (S_ISREG(inode->i_mode)) {

		inode->i_op = (struct inode_operations *) &hpfs_file_iops;
		inode->i_nlink = 1;
		inode->i_blksize = 512;

	}
	else {
		unsigned n_dnodes, n_subdirs;
		struct buffer_head *bh0;
		struct fnode *fnode = map_fnode(inode->i_dev,
						inode->i_ino, &bh0);

		if (!fnode) {
			printk("HPFS: read_inode: no fnode\n");
			inode->i_mode = 0;
			return;
		}

		inode->i_hpfs_parent_dir = dir_ino(fnode->up);
		inode->i_hpfs_dno = fnode->u.external[0].disk_secno;

		brelse(bh0);

		n_dnodes = n_subdirs = 0;
		count_dnodes(inode, inode->i_hpfs_dno, &n_dnodes, &n_subdirs);

		inode->i_op = (struct inode_operations *) &hpfs_dir_iops;
		inode->i_blksize = 512;	/* 2048 here confuses ls & du & ... */
		inode->i_blocks = 4 * n_dnodes;
		inode->i_size = 512 * inode->i_blocks;
		inode->i_nlink = 2 + n_subdirs;
	}
}

/*
 * unmount.
 */

static void hpfs_put_super(struct super_block *s)
{
	lock_super(s);
	s->s_dev = 0;
	unlock_super(s);
}

/*
 * statfs.  For free inode counts we report the count of dnodes in the
 * directory band -- not exactly right but pretty analagous.
 */

static void hpfs_statfs(struct super_block *s, struct statfs *buf)
{
	/*
	 * count the bits in the bitmaps, unless we already have
	 */

	if (s->s_hpfs_n_free == -1) {
		s->s_hpfs_n_free = count_bitmap(s);
		s->s_hpfs_n_free_dnodes =
		    count_one_bitmap(s->s_dev, s->s_hpfs_dmap);
	}

	/*
	 * fill in the user statfs struct
	 */

	put_fs_long(s->s_magic, &buf->f_type);
	put_fs_long(512, &buf->f_bsize);
	put_fs_long(s->s_hpfs_fs_size, &buf->f_blocks);
	put_fs_long(s->s_hpfs_n_free, &buf->f_bfree);
	put_fs_long(s->s_hpfs_n_free, &buf->f_bavail);
	put_fs_long(s->s_hpfs_dirband_size, &buf->f_files);
	put_fs_long(s->s_hpfs_n_free_dnodes, &buf->f_ffree);
	put_fs_long(254, &buf->f_namelen);
}

/*
 * remount.  Don't let read only be turned off.
 */

static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
{
	if (!(*flags & MS_RDONLY))
		return -EINVAL;
	return 0;
}

/*
 * count the dnodes in a directory, and the subdirs.
 */

static void count_dnodes(struct inode *inode, dnode_secno dno,
			 unsigned *n_dnodes, unsigned *n_subdirs)
{
	struct quad_buffer_head qbh;
	struct dnode *dnode;
	struct hpfs_dirent *de;
	struct hpfs_dirent *de_end;

	dnode = map_dnode(inode->i_dev, dno, &qbh);
	if (!dnode)
		return;
	de = dnode_first_de(dnode);
	de_end = dnode_end_de(dnode);

	(*n_dnodes)++;

	for (; de < de_end; de = de_next_de(de)) {
		if (de->down)
			count_dnodes(inode, de_down_pointer(de),
				     n_dnodes, n_subdirs);
		if (de->directory && !de->first)
			(*n_subdirs)++;
		if (de->last || de->length == 0)
			break;
	}

	brelse4(&qbh);
}

/*
 * count the bits in the free space bit maps
 */

static unsigned count_bitmap(struct super_block *s)
{
	unsigned n, count, n_bands;
	secno *bitmaps;
	struct quad_buffer_head qbh;

	/*
	 * there is one bit map for each 16384 sectors
	 */
	n_bands = (s->s_hpfs_fs_size + 0x3fff) >> 14;

	/*
	 * their locations are given in an array pointed to by the super
	 * block
	 */
	bitmaps = map_4sectors(s->s_dev, s->s_hpfs_bitmaps, &qbh);
	if (!bitmaps)
		return 0;

	count = 0;

	/*
	 * map each one and count the free sectors
	 */
	for (n = 0; n < n_bands; n++)
		if (bitmaps[n] == 0)
			printk("HPFS: bit map pointer missing\n");
		else
			count += count_one_bitmap(s->s_dev, bitmaps[n]);

	brelse4(&qbh);
	return count;
}

/*
 * Read in one bit map, count the bits, return the count.
 */

static unsigned count_one_bitmap(dev_t dev, secno secno)
{
	struct quad_buffer_head qbh;
	char *bits;
	unsigned i, count;

	bits = map_4sectors(dev, secno, &qbh);
	if (!bits)
		return 0;

	count = 0;

	for (i = 0; i < 8 * 2048; i++)
		count += (test_bit(i, bits) != 0);
	brelse4(&qbh);

	return count;
}

/* file ops */

/*
 * read.  Read the bytes, put them in buf, return the count.
 */

static int hpfs_file_read(struct inode *inode, struct file *filp,
			  char *buf, int count)
{
	unsigned q, r, n, n0;
	struct buffer_head *bh;
	char *block;
	char *start;

	if (inode == 0 || !S_ISREG(inode->i_mode))
		return -EINVAL;

	/*
	 * truncate count at EOF
	 */
	if (count > inode->i_size - filp->f_pos)
		count = inode->i_size - filp->f_pos;

	start = buf;
	while (count > 0) {
		/*
		 * get file sector number, offset in sector, length to end of
		 * sector
		 */
		q = filp->f_pos >> 9;
		r = filp->f_pos & 511;
		n = 512 - r;

		/*
		 * get length to copy to user buffer
		 */
		if (n > count)
			n = count;

		/*
		 * read the sector, copy to user
		 */
		block = map_sector(inode->i_dev, hpfs_bmap(inode, q), &bh);
		if (!block)
			return -EIO;

		/*
		 * but first decide if it has \r\n, if the mount option said
		 * to do that
		 */
		if (inode->i_hpfs_conv == CONV_AUTO)
			inode->i_hpfs_conv = choose_conv(block + r, n);

		if (inode->i_hpfs_conv == CONV_BINARY) {
			/*
			 * regular copy, output length is same as input
			 * length
			 */
			memcpy_tofs(buf, block + r, n);
			n0 = n;
		}
		else {
			/*
			 * squeeze out \r, output length varies
			 */
			n0 = convcpy_tofs(buf, block + r, n);
			if (count > inode->i_size - filp->f_pos - n + n0)
				count = inode->i_size - filp->f_pos - n + n0;
		}

		brelse(bh);

		/*
		 * advance input n bytes, output n0 bytes
		 */
		filp->f_pos += n;
		buf += n0;
		count -= n0;
	}

	return buf - start;
}

/*
 * This routine implements conv=auto.  Return CONV_BINARY or CONV_TEXT.
 */

static unsigned choose_conv(unsigned char *p, unsigned len)
{
	unsigned tvote, bvote;
	unsigned c;

	tvote = bvote = 0;

	while (len--) {
		c = *p++;
		if (c < ' ')
			if (c == '\r' && len && *p == '\n')
				tvote += 10;
			else if (c == '\t' || c == '\n');
			else
				bvote += 5;
		else if (c < '\177')
			tvote++;
		else
			bvote += 5;
	}

	if (tvote > bvote)
		return CONV_TEXT;
	else
		return CONV_BINARY;
}

/*
 * This routine implements conv=text.  :s/crlf/nl/
 */

static unsigned convcpy_tofs(unsigned char *out, unsigned char *in,
			     unsigned len)
{
	unsigned char *start = out;

	while (len--) {
		unsigned c = *in++;
		if (c == '\r' && (len == 0 || *in == '\n'));
		else
			put_fs_byte(c, out++);
	}

	return out - start;
}

/*
 * Return the disk sector number containing a file sector.
 */

static secno hpfs_bmap(struct inode *inode, unsigned file_secno)
{
	unsigned n, disk_secno;
	struct fnode *fnode;
	struct buffer_head *bh;

	/*
	 * There is one sector run cached in the inode. See if the sector is
	 * in it.
	 */

	n = file_secno - inode->i_hpfs_file_sec;
	if (n < inode->i_hpfs_n_secs)
		return inode->i_hpfs_disk_sec + n;

	/*
	 * No, read the fnode and go find the sector.
	 */

	else {
		fnode = map_fnode(inode->i_dev, inode->i_ino, &bh);
		if (!fnode)
			return 0;
		disk_secno = bplus_lookup(inode, &fnode->btree,
					  file_secno, &bh);
		brelse(bh);
		return disk_secno;
	}
}

/*
 * Search allocation tree *b for the given file sector number and return
 * the disk sector number.  Buffer *bhp has the tree in it, and can be
 * reused for subtrees when access to *b is no longer needed.
 * *bhp is busy on entry and exit. 
 */

static secno bplus_lookup(struct inode *inode, struct bplus_header *b,
			  secno file_secno, struct buffer_head **bhp)
{
	int i;

	/*
	 * A leaf-level tree gives a list of sector runs.  Find the one
	 * containing the file sector we want, cache the map info in the
	 * inode for later, and return the corresponding disk sector.
	 */

	if (!b->internal) {
		struct bplus_leaf_node *n = b->u.external;
		for (i = 0; i < b->n_used_nodes; i++) {
			unsigned t = file_secno - n[i].file_secno;
			if (t < n[i].length) {
				inode->i_hpfs_file_sec = n[i].file_secno;
				inode->i_hpfs_disk_sec = n[i].disk_secno;
				inode->i_hpfs_n_secs = n[i].length;
				return n[i].disk_secno + t;
			}
		}
	}

	/*
	 * A non-leaf tree gives a list of subtrees.  Find the one containing
	 * the file sector we want, read it in, and recurse to search it.
	 */

	else {
		struct bplus_internal_node *n = b->u.internal;
		for (i = 0; i < b->n_used_nodes; i++) {
			if (file_secno < n[i].file_secno) {
				struct anode *anode;
				anode_secno ano = n[i].down;
				brelse(*bhp);
				anode = map_anode(inode->i_dev, ano, bhp);
				if (!anode)
					break;
				return bplus_lookup(inode, &anode->btree,
						    file_secno, bhp);
			}
		}
	}

	/*
	 * If we get here there was a hole in the file.  As far as I know we
	 * never do get here, but falling off the end would be indelicate. So
	 * return a pointer to a handy all-zero sector.  This is not a
	 * reasonable way to handle files with holes if they really do
	 * happen.
	 */

	printk("HPFS: bplus_lookup: sector not found\n");
	return 15;
}

/* directory ops */

/*
 * lookup.  Search the specified directory for the specified name, set
 * *result to the corresponding inode.
 *
 * lookup uses the inode number to tell read_inode whether it is reading
 * the inode of a directory or a file -- file ino's are odd, directory
 * ino's are even.  read_inode avoids i/o for file inodes; everything
 * needed is up here in the directory.  (And file fnodes are out in
 * the boondocks.)
 */

static int hpfs_lookup(struct inode *dir, const char *name, int len,
		       struct inode **result)
{
	struct quad_buffer_head qbh;
	struct hpfs_dirent *de;
	struct inode *inode;
	ino_t ino;

	/* In case of madness */

	*result = 0;
	if (dir == 0)
		return -ENOENT;
	if (!S_ISDIR(dir->i_mode))
		goto bail;

	/*
	 * Read in the directory entry. "." is there under the name ^A^A .
	 * Always read the dir even for . and .. in case we need the dates.
	 */

	if (name[0] == '.' && len == 1)
		de = map_dirent(dir, dir->i_hpfs_dno, "\001\001", 2, &qbh);
	else if (name[0] == '.' && name[1] == '.' && len == 2)
		de = map_dirent(dir,
				fnode_dno(dir->i_dev, dir->i_hpfs_parent_dir),
				"\001\001", 2, &qbh);
	else
		de = map_dirent(dir, dir->i_hpfs_dno, name, len, &qbh);

	/*
	 * This is not really a bailout, just means file not found.
	 */

	if (!de)
		goto bail;

	/*
	 * Get inode number, what we're after.
	 */

	if (de->directory)
		ino = dir_ino(de->fnode);
	else
		ino = file_ino(de->fnode);

	/*
	 * Go find or make an inode.
	 */

	if (!(inode = iget(dir->i_sb, ino)))

⌨️ 快捷键说明

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