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

📄 hpfs_fs.c

📁 Linux 1.0 内核C源代码 Linux最早版本代码 由Linus Torvalds亲自书写的
💻 C
📖 第 1 页 / 共 3 页
字号:
		goto bail1;

	/*
	 * Fill in the info from the directory if this is a newly created
	 * inode.
	 */

	if (!inode->i_atime) {
		inode->i_atime = local_to_gmt(de->read_date);
		inode->i_mtime = local_to_gmt(de->write_date);
		inode->i_ctime = local_to_gmt(de->creation_date);
		if (de->read_only)
			inode->i_mode &= ~0222;
		if (!de->directory) {
			inode->i_size = de->file_size;
			/*
			 * i_blocks should count the fnode and any anodes.
			 * We count 1 for the fnode and don't bother about
			 * anodes -- the disk heads are on the directory band
			 * and we want them to stay there.
			 */
			inode->i_blocks = 1 + ((inode->i_size + 511) >> 9);
		}
	}

	brelse4(&qbh);

	/*
	 * Made it.
	 */

	*result = inode;
	iput(dir);
	return 0;

	/*
	 * Didn't.
	 */
 bail1:
	brelse4(&qbh);
 bail:
	iput(dir);
	return -ENOENT;
}

/*
 * Compare two counted strings ignoring case.
 * HPFS directory order sorts letters as if they're upper case.
 */

static inline int memcasecmp(const unsigned char *s1, const unsigned char *s2,
			     unsigned n)
{
	int t;

	if (n != 0)
		do {
			unsigned c1 = *s1++;
			unsigned c2 = *s2++;
			if (c1 - 'a' < 26)
				c1 -= 040;
			if (c2 - 'a' < 26)
				c2 -= 040;
			if ((t = c1 - c2) != 0)
				return t;
		} while (--n != 0);

	return 0;
}

/*
 * Search a directory for the given name, return a pointer to its dir entry
 * and a pointer to the buffer containing it.
 */

static struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno,
				      const unsigned char *name, unsigned len,
				      struct quad_buffer_head *qbh)
{
	struct dnode *dnode;
	struct hpfs_dirent *de;
	struct hpfs_dirent *de_end;
	int t, l;

	/*
	 * read the dnode at the root of our subtree
	 */
	dnode = map_dnode(inode->i_dev, dno, qbh);
	if (!dnode)
		return 0;

	/*
	 * get pointers to start and end+1 of dir entries
	 */
	de = dnode_first_de(dnode);
	de_end = dnode_end_de(dnode);

	/*
	 * look through the entries for the name we're after
	 */
	for ( ; de < de_end; de = de_next_de(de)) {

		/*
		 * compare names
		 */
		l = len < de->namelen ? len : de->namelen;
		t = memcasecmp(name, de->name, l);

		/*
		 * initial substring matches, compare lengths
		 */
		if (t == 0) {
			t = len - de->namelen;
			/* bingo */
			if (t == 0)
				return de;
		}

		/*
		 * wanted name .lt. dir name => not present.
		 */
		if (t < 0) {
			/*
			 * if there is a subtree, search it.
			 */
			if (de->down) {
				dnode_secno sub_dno = de_down_pointer(de);
				brelse4(qbh);
				return map_dirent(inode, sub_dno,
						  name, len, qbh);
			}
			else
				break;
		}

		/*
		 * de->last is set on the last name in the dnode (it's always
		 * a "\377" pseudo entry).  de->length == 0 means we're about
		 * to infinite loop. This test does nothing in a well-formed
		 * dnode.
		 */
		if (de->last || de->length == 0)
			break;
	}

	/*
	 * name not found.
	 */

	return 0;
}

/*
 * readdir.  Return exactly 1 dirent.  (I tried and tried, but currently
 * the interface with libc just does not permit more than 1.  If it gets
 * fixed, throw this out and just walk the tree and write records into
 * the user buffer.)
 *
 * We keep track of our position in the dnode tree with a sort of
 * dewey-decimal record of subtree locations.  Like so:
 *
 *   (1 (1.1 1.2 1.3) 2 3 (3.1 (3.1.1 3.1.2) 3.2 3.3 (3.3.1)) 4)
 *
 * Subtrees appear after their file, out of lexical order,
 * which would be before their file.  It's easier.
 *
 * A directory can't hold more than 56 files, so 6 bits are used for
 * position numbers.  If the tree is so deep that the position encoding
 * doesn't fit, I'm sure something absolutely fascinating happens.
 *
 * The actual sequence of f_pos values is
 *     0 => .   -1 => ..   1 1.1 ... 8.9 9 => files  -2 => eof
 *
 * The directory inode caches one position-to-dnode correspondence so
 * we won't have to repeatedly scan the top levels of the tree. 
 */

static int hpfs_readdir(struct inode *inode, struct file *filp,
			struct dirent *dirent, int likely_story)
{
	struct quad_buffer_head qbh;
	struct hpfs_dirent *de;
	int namelen, lc;
	ino_t ino;

	if (inode == 0
	    || inode->i_sb == 0
	    || !S_ISDIR(inode->i_mode))
		return -EBADF;

	lc = inode->i_sb->s_hpfs_lowercase;

	switch (filp->f_pos) {
	case 0:
		write_one_dirent(dirent, ".", 1, inode->i_ino, lc);
		filp->f_pos = -1;
		return 1;

	case -1:
		write_one_dirent(dirent, "..", 2,
				 inode->i_hpfs_parent_dir, lc);
		filp->f_pos = 1;
		return 2;

	case -2:
		return 0;

	default:
		de = map_pos_dirent(inode, &filp->f_pos, &qbh);
		if (!de) {
			filp->f_pos = -2;
			return 0;
		}

		namelen = de->namelen;
		if (de->directory)
			ino = dir_ino(de->fnode);
		else
			ino = file_ino(de->fnode);
		write_one_dirent(dirent, de->name, namelen, ino, lc);
		brelse4(&qbh);

		return namelen;
	}
}

/*
 * Send the given name and ino off to the user dirent struct at *dirent.
 * Blam it to lowercase if the mount option said to.
 *
 * Note that Linux d_reclen is the length of the file name, and has nothing
 * to do with the length of the dirent record.
 */

static void write_one_dirent(struct dirent *dirent, const unsigned char *name,
			     unsigned namelen, ino_t ino, int lowercase)
{
	unsigned n;

	put_fs_long(ino, &dirent->d_ino);
	put_fs_word(namelen, &dirent->d_reclen);

	if (lowercase)
		for (n = namelen; n != 0;) {
			unsigned t = name[--n];
			if (t - 'A' < 26)
				t += 040;
			put_fs_byte(t, &dirent->d_name[n]);
		}
	else
		memcpy_tofs(dirent->d_name, name, namelen);

	put_fs_byte(0, &dirent->d_name[namelen]);
}

/*
 * Map the dir entry at subtree coordinates given by *posp, and
 * increment *posp to point to the following dir entry. 
 */

static struct hpfs_dirent *map_pos_dirent(struct inode *inode, off_t *posp,
					  struct quad_buffer_head *qbh)
{
	unsigned pos, q, r;
	dnode_secno dno;
	struct hpfs_dirent *de;

	/*
	 * Get the position code and split off the rightmost index r
	 */

	pos = *posp;
	q = pos >> 6;
	r = pos & 077;

	/*
	 * Get the sector address of the dnode
	 * pointed to by the leading part q
	 */

	dno = dir_subdno(inode, q);
	if (!dno)
		return 0;

	/*
	 * Get the entry at index r in dnode q
	 */

	de = map_nth_dirent(inode->i_dev, dno, r, qbh);

	/*
	 * If none, we're out of files in this dnode.  Ascend.
	 */

	if (!de) {
		if (q == 0)
			return 0;
		*posp = q + 1;
		return map_pos_dirent(inode, posp, qbh);
	}

	/*
	 * If a subtree is here, descend.
	 */

	if (de->down)
		*posp = pos << 6 | 1;
	else
		*posp = pos + 1;

	/*
	 * Don't return the ^A^A and \377 entries.
	 */

	if (de->first || de->last) {
		brelse4(qbh);
		return map_pos_dirent(inode, posp, qbh);
	}
	else
		return de;
}

/*
 * Return the address of the dnode with subtree coordinates given by pos.
 */

static dnode_secno dir_subdno(struct inode *inode, unsigned pos)
{
	struct hpfs_dirent *de;
	struct quad_buffer_head qbh;

	/*
	 * 0 is the root dnode
	 */

	if (pos == 0)
		return inode->i_hpfs_dno;

	/*
	 * we have one pos->dnode translation cached in the inode
	 */

	else if (pos == inode->i_hpfs_dpos)
		return inode->i_hpfs_dsubdno;

	/*
	 * otherwise go look
	 */

	else {
		unsigned q = pos >> 6;
		unsigned r = pos & 077;
		dnode_secno dno;

		/*
		 * dnode at position q
		 */
		dno = dir_subdno(inode, q);
		if (dno == 0)
			return 0;

		/*
		 * entry at index r
		 */
		de = map_nth_dirent(inode->i_dev, dno, r, &qbh);
		if (!de || !de->down)
			return 0;

		/*
		 * get the dnode down pointer
		 */
		dno = de_down_pointer(de);
		brelse4(&qbh);

		/*
		 * cache it for next time
		 */
		inode->i_hpfs_dpos = pos;
		inode->i_hpfs_dsubdno = dno;
		return dno;
	}
}

/*
 * Return the dir entry at index n in dnode dno, or 0 if there isn't one
 */

static struct hpfs_dirent *map_nth_dirent(dev_t dev, dnode_secno dno,
					  int n,
					  struct quad_buffer_head *qbh)
{
	int i;
	struct hpfs_dirent *de, *de_end;
	struct dnode *dnode = map_dnode(dev, dno, qbh);

	de = dnode_first_de(dnode);
	de_end = dnode_end_de(dnode);

	for (i = 1; de < de_end; i++, de = de_next_de(de)) {
		if (i == n)
			return de;
		if (de->last || de->length == 0)
			break;
	}

	brelse4(qbh);
	return 0;
}

static int hpfs_dir_read(struct inode *inode, struct file *filp,
			 char *buf, int count)
{
	return -EISDIR;
}

/* Return the dnode pointer in a directory fnode */

static dnode_secno fnode_dno(dev_t dev, ino_t ino)
{
	struct buffer_head *bh;
	struct fnode *fnode;
	dnode_secno dno;

	fnode = map_fnode(dev, ino, &bh);
	if (!fnode)
		return 0;

	dno = fnode->u.external[0].disk_secno;
	brelse(bh);
	return dno;
}

/* Map an fnode into a buffer and return pointers to it and to the buffer. */

static struct fnode *map_fnode(dev_t dev, ino_t ino, struct buffer_head **bhp)
{
	struct fnode *fnode;

	if (ino == 0) {
		printk("HPFS: missing fnode\n");
		return 0;
	}

	fnode = map_sector(dev, ino_secno(ino), bhp);
	if (fnode)
		if (fnode->magic != FNODE_MAGIC) {
			printk("HPFS: map_fnode: bad fnode pointer\n");
			brelse(*bhp);
			return 0;
		}
	return fnode;
}

/* Map an anode into a buffer and return pointers to it and to the buffer. */

static struct anode *map_anode(dev_t dev, unsigned secno,
			       struct buffer_head **bhp)
{
	struct anode *anode;

	if (secno == 0) {
		printk("HPFS: missing anode\n");
		return 0;
	}

	anode = map_sector(dev, secno, bhp);
	if (anode)
		if (anode->magic != ANODE_MAGIC || anode->self != secno) {
			printk("HPFS: map_anode: bad anode pointer\n");
			brelse(*bhp);
			return 0;
		}
	return anode;
}

/* Map a dnode into a buffer and return pointers to it and to the buffer. */

static struct dnode *map_dnode(dev_t dev, unsigned secno,
			       struct quad_buffer_head *qbh)
{
	struct dnode *dnode;

	if (secno == 0) {
		printk("HPFS: missing dnode\n");
		return 0;
	}

	dnode = map_4sectors(dev, secno, qbh);
	if (dnode)
		if (dnode->magic != DNODE_MAGIC || dnode->self != secno) {
			printk("HPFS: map_dnode: bad dnode pointer\n");
			brelse4(qbh);
			return 0;
		}
	return dnode;
}

/* Map a sector into a buffer and return pointers to it and to the buffer. */

static void *map_sector(dev_t dev, unsigned secno, struct buffer_head **bhp)
{
	struct buffer_head *bh;

	if ((*bhp = bh = bread(dev, secno, 512)) != 0)
		return bh->b_data;
	else {
		printk("HPFS: map_sector: read error\n");
		return 0;
	}
}

/* Map 4 sectors into a 4buffer and return pointers to it and to the buffer. */

static void *map_4sectors(dev_t dev, unsigned secno,
			  struct quad_buffer_head *qbh)
{
	struct buffer_head *bh;
	char *data;

	if (secno & 3) {
		printk("HPFS: map_4sectors: unaligned read\n");
		return 0;
	}

	qbh->data = data = kmalloc(2048, GFP_KERNEL);
	if (!data)
		goto bail;

	qbh->bh[0] = bh = breada(dev,
				 secno, secno + 1, secno + 2, secno + 3, -1);
	if (!bh)
		goto bail0;
	memcpy(data, bh->b_data, 512);

	qbh->bh[1] = bh = bread(dev, secno + 1, 512);
	if (!bh)
		goto bail1;
	memcpy(data + 512, bh->b_data, 512);

	qbh->bh[2] = bh = bread(dev, secno + 2, 512);
	if (!bh)
		goto bail2;
	memcpy(data + 2 * 512, bh->b_data, 512);

	qbh->bh[3] = bh = bread(dev, secno + 3, 512);
	if (!bh)
		goto bail3;
	memcpy(data + 3 * 512, bh->b_data, 512);

	return data;

 bail3:
	brelse(qbh->bh[2]);
 bail2:
	brelse(qbh->bh[1]);
 bail1:
	brelse(qbh->bh[0]);
 bail0:
	kfree_s(data, 2048);
 bail:
	printk("HPFS: map_4sectors: read error\n");
	return 0;
}

/* Deallocate a 4-buffer block */

static void brelse4(struct quad_buffer_head *qbh)
{
	brelse(qbh->bh[3]);
	brelse(qbh->bh[2]);
	brelse(qbh->bh[1]);
	brelse(qbh->bh[0]);
	kfree_s(qbh->data, 2048);
}

⌨️ 快捷键说明

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