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