hpfs_fs.c
来自「elinux jffs初始版本 具体了解JFFS的文件系统!」· C语言 代码 · 共 1,773 行 · 第 1/3 页
C
1,773 行
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 = linux_char_to_upper_linux (*s1++); unsigned c2 = hpfs_char_to_upper_linux (*s2++); 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. */ brelse4(qbh); 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 now can handle multiple dirents, although the current libc doesn't * use that. The way hpfs does this is pretty strange, as we need to do * the name translation etc before calling "filldir()". This is untested, * as I don't have any hpfs partitions to test against. Linus ] * * 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. *//* * Translate the given name: Blam it to lowercase if the mount option said to. */static void translate_hpfs_name(const unsigned char * from, int len, char * to, int lowercase){ while (len > 0) { unsigned t = *from; len--; if (lowercase) t = hpfs_char_to_lower_linux (t); else t = hpfs_char_to_linux (t); *to = t; from++; to++; }}static int hpfs_readdir(struct inode *inode, struct file *filp, void * dirent, filldir_t filldir){ struct quad_buffer_head qbh; struct hpfs_dirent *de; int namelen, lc; ino_t ino; char * tempname; long old_pos; if (inode == 0 || inode->i_sb == 0 || !S_ISDIR(inode->i_mode)) return -EBADF; tempname = (char *) __get_free_page(GFP_KERNEL); if (!tempname) return -ENOMEM; lc = inode->i_sb->s_hpfs_lowercase; switch ((long) filp->f_pos) { case -2: break; case 0: if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0) break; filp->f_pos = -1; /* fall through */ case -1: if (filldir(dirent, "..", 2, filp->f_pos, inode->i_hpfs_parent_dir) < 0) break; filp->f_pos = 1; /* fall through */ default: for (;;) { old_pos = filp->f_pos; de = map_pos_dirent(inode, &filp->f_pos, &qbh); if (!de) { filp->f_pos = -2; break; } namelen = de->namelen; translate_hpfs_name(de->name, namelen, tempname, lc); if (de->directory) ino = dir_ino(de->fnode); else ino = file_ino(de->fnode); brelse4(&qbh); if (filldir(dirent, tempname, namelen, old_pos, ino) < 0) { filp->f_pos = old_pos; break; } } } free_page((unsigned long) tempname); return 0;}/* * 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, loff_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(kdev_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(kdev_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(kdev_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(kdev_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(kdev_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(kdev_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(kdev_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, 512, 0, UINT_MAX); 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);}static struct file_system_type hpfs_fs_type = { hpfs_read_super, "hpfs", 1, NULL};int init_hpfs_fs(void){ return register_filesystem(&hpfs_fs_type);}#ifdef MODULEint init_module(void){ int status; if ((status = init_hpfs_fs()) == 0) register_symtab(0); return status;}void cleanup_module(void){ unregister_filesystem(&hpfs_fs_type);}#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?