📄 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 + -