📄 hpfs_fs.c
字号:
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 + -