static int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { int r; secno s; hpfs_lock(inode->i_sb); s = hpfs_bmap(inode, iblock); if (s) { map_bh(bh_result, inode->i_sb, s); goto ret_0; } if (!create) goto ret_0; if (iblock<<9 != hpfs_i(inode)->mmu_private) { BUG(); r = -EIO; goto ret_r; } if ((s = hpfs_add_sector_to_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1)) == -1) { hpfs_truncate_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1); r = -ENOSPC; goto ret_r; } inode->i_blocks++; hpfs_i(inode)->mmu_private += 512; set_buffer_new(bh_result); map_bh(bh_result, inode->i_sb, s); ret_0: r = 0; ret_r: hpfs_unlock(inode->i_sb); return r; }
static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) { const unsigned char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; struct quad_buffer_head qbh; struct hpfs_dirent *de; struct inode *inode = dentry->d_inode; dnode_secno dno; int n_items = 0; int err; int r; hpfs_adjust_length(name, &len); hpfs_lock(dir->i_sb); err = -ENOENT; de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh); if (!de) goto out; err = -EPERM; if (de->first) goto out1; err = -ENOTDIR; if (!de->directory) goto out1; hpfs_count_dnodes(dir->i_sb, hpfs_i(inode)->i_dno, NULL, NULL, &n_items); err = -ENOTEMPTY; if (n_items) goto out1; r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); switch (r) { case 1: hpfs_error(dir->i_sb, "there was error when removing dirent"); err = -EFSERROR; break; case 2: err = -ENOSPC; break; default: drop_nlink(dir); clear_nlink(inode); err = 0; } goto out; out1: hpfs_brelse4(&qbh); out: if (!err) hpfs_update_directory_times(dir); hpfs_unlock(dir->i_sb); return err; }
static void hpfs_truncate(struct inode *i) { if (IS_IMMUTABLE(i)) return /*-EPERM*/; lock_kernel(); hpfs_i(i)->i_n_secs = 0; i->i_blocks = 1 + ((i->i_size + 511) >> 9); hpfs_i(i)->mmu_private = i->i_size; hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9)); hpfs_write_inode(i); hpfs_i(i)->i_n_secs = 0; unlock_kernel(); }
static secno hpfs_bmap(struct inode *inode, unsigned file_secno) { struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); unsigned n, disk_secno; struct fnode *fnode; struct buffer_head *bh; if (BLOCKS(hpfs_i(inode)->mmu_private) <= file_secno) return 0; n = file_secno - hpfs_inode->i_file_sec; if (n < hpfs_inode->i_n_secs) return hpfs_inode->i_disk_sec + n; if (!(fnode = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) return 0; disk_secno = hpfs_bplus_lookup(inode->i_sb, inode, &fnode->btree, file_secno, bh); if (disk_secno == -1) return 0; if (hpfs_chk_sectors(inode->i_sb, disk_secno, 1, "bmap")) return 0; return disk_secno; }
void hpfs_write_if_changed(struct inode *inode) { struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); if (hpfs_inode->i_dirty) hpfs_write_inode(inode); }
void hpfs_write_inode(struct inode *i) { struct hpfs_inode_info *hpfs_inode = hpfs_i(i); struct inode *parent; if (i->i_ino == hpfs_sb(i->i_sb)->sb_root) return; if (hpfs_inode->i_rddir_off && !atomic_read(&i->i_count)) { if (*hpfs_inode->i_rddir_off) printk("HPFS: write_inode: some position still there\n"); kfree(hpfs_inode->i_rddir_off); hpfs_inode->i_rddir_off = NULL; } if (!i->i_nlink) { return; } parent = iget_locked(i->i_sb, hpfs_inode->i_parent_dir); if (parent) { hpfs_inode->i_dirty = 0; if (parent->i_state & I_NEW) { hpfs_init_inode(parent); hpfs_read_inode(parent); unlock_new_inode(parent); } hpfs_write_inode_nolock(i); iput(parent); } }
static void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode) { struct hpfs_inode_info *hpfs_inode = hpfs_i(i); /* */ if (hpfs_sb(i->i_sb)->sb_eas >= 2) { __le32 ea; if ((i->i_uid != hpfs_sb(i->i_sb)->sb_uid) || hpfs_inode->i_ea_uid) { ea = cpu_to_le32(i->i_uid); hpfs_set_ea(i, fnode, "UID", (char*)&ea, 2); hpfs_inode->i_ea_uid = 1; } if ((i->i_gid != hpfs_sb(i->i_sb)->sb_gid) || hpfs_inode->i_ea_gid) { ea = cpu_to_le32(i->i_gid); hpfs_set_ea(i, fnode, "GID", (char *)&ea, 2); hpfs_inode->i_ea_gid = 1; } if (!S_ISLNK(i->i_mode)) if ((i->i_mode != ((hpfs_sb(i->i_sb)->sb_mode & ~(S_ISDIR(i->i_mode) ? 0 : 0111)) | (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG)) && i->i_mode != ((hpfs_sb(i->i_sb)->sb_mode & ~(S_ISDIR(i->i_mode) ? 0222 : 0333)) | (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG))) || hpfs_inode->i_ea_mode) { ea = cpu_to_le32(i->i_mode); /* */ hpfs_set_ea(i, fnode, "MODE", (char *)&ea, 2); hpfs_inode->i_ea_mode = 1; } if (S_ISBLK(i->i_mode) || S_ISCHR(i->i_mode)) { ea = cpu_to_le32(new_encode_dev(i->i_rdev)); hpfs_set_ea(i, fnode, "DEV", (char *)&ea, 4); } } }
void hpfs_init_inode(struct inode *i) { struct super_block *sb = i->i_sb; struct hpfs_inode_info *hpfs_inode = hpfs_i(i); i->i_uid = hpfs_sb(sb)->sb_uid; i->i_gid = hpfs_sb(sb)->sb_gid; i->i_mode = hpfs_sb(sb)->sb_mode; i->i_size = -1; i->i_blocks = -1; hpfs_inode->i_dno = 0; hpfs_inode->i_n_secs = 0; hpfs_inode->i_file_sec = 0; hpfs_inode->i_disk_sec = 0; hpfs_inode->i_dpos = 0; hpfs_inode->i_dsubdno = 0; hpfs_inode->i_ea_mode = 0; hpfs_inode->i_ea_uid = 0; hpfs_inode->i_ea_gid = 0; hpfs_inode->i_ea_size = 0; hpfs_inode->i_rddir_off = NULL; hpfs_inode->i_dirty = 0; i->i_ctime.tv_sec = i->i_ctime.tv_nsec = 0; i->i_mtime.tv_sec = i->i_mtime.tv_nsec = 0; i->i_atime.tv_sec = i->i_atime.tv_nsec = 0; }
static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence) { loff_t new_off = off + (whence == 1 ? filp->f_pos : 0); loff_t pos; struct quad_buffer_head qbh; struct inode *i = filp->f_dentry->d_inode; struct hpfs_inode_info *hpfs_inode = hpfs_i(i); struct super_block *s = i->i_sb; lock_kernel(); /*printk("dir lseek\n");*/ if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok; mutex_lock(&i->i_mutex); pos = ((loff_t) hpfs_de_as_down_as_possible(s, hpfs_inode->i_dno) << 4) + 1; while (pos != new_off) { if (map_pos_dirent(i, &pos, &qbh)) hpfs_brelse4(&qbh); else goto fail; if (pos == 12) goto fail; } mutex_unlock(&i->i_mutex); ok: unlock_kernel(); return filp->f_pos = new_off; fail: mutex_unlock(&i->i_mutex); /*printk("illegal lseek: %016llx\n", new_off);*/ unlock_kernel(); return -ESPIPE; }
void hpfs_read_inode(struct inode *i) { struct buffer_head *bh; struct fnode *fnode; struct super_block *sb = i->i_sb; struct hpfs_inode_info *hpfs_inode = hpfs_i(i); void *ea; int ea_size; if (!(fnode = hpfs_map_fnode(sb, i->i_ino, &bh))) { /*i->i_mode |= S_IFREG; i->i_mode &= ~0111; i->i_op = &hpfs_file_iops; i->i_fop = &hpfs_file_ops; <<<<<<< HEAD clear_nlink(i);*/ ======= <<<<<<< HEAD clear_nlink(i);*/ ======= i->i_nlink = 0;*/ >>>>>>> 58a75b6a81be54a8b491263ca1af243e9d8617b9 >>>>>>> ae1773bb70f3d7cf73324ce8fba787e01d8fa9f2 make_bad_inode(i); return; }
static void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode) { struct hpfs_inode_info *hpfs_inode = hpfs_i(i); /*if (le32_to_cpu(fnode->acl_size_l) || le16_to_cpu(fnode->acl_size_s)) { Some unknown structures like ACL may be in fnode, we'd better not overwrite them hpfs_error(i->i_sb, "fnode %08x has some unknown HPFS386 structures", i->i_ino); } else*/ if (hpfs_sb(i->i_sb)->sb_eas >= 2) { __le32 ea; if (!uid_eq(i->i_uid, hpfs_sb(i->i_sb)->sb_uid) || hpfs_inode->i_ea_uid) { ea = cpu_to_le32(i_uid_read(i)); hpfs_set_ea(i, fnode, "UID", (char*)&ea, 2); hpfs_inode->i_ea_uid = 1; } if (!gid_eq(i->i_gid, hpfs_sb(i->i_sb)->sb_gid) || hpfs_inode->i_ea_gid) { ea = cpu_to_le32(i_gid_read(i)); hpfs_set_ea(i, fnode, "GID", (char *)&ea, 2); hpfs_inode->i_ea_gid = 1; } if (!S_ISLNK(i->i_mode)) if ((i->i_mode != ((hpfs_sb(i->i_sb)->sb_mode & ~(S_ISDIR(i->i_mode) ? 0 : 0111)) | (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG)) && i->i_mode != ((hpfs_sb(i->i_sb)->sb_mode & ~(S_ISDIR(i->i_mode) ? 0222 : 0333)) | (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG))) || hpfs_inode->i_ea_mode) { ea = cpu_to_le32(i->i_mode); /* sick, but legal */ hpfs_set_ea(i, fnode, "MODE", (char *)&ea, 2); hpfs_inode->i_ea_mode = 1; } if (S_ISBLK(i->i_mode) || S_ISCHR(i->i_mode)) { ea = cpu_to_le32(new_encode_dev(i->i_rdev)); hpfs_set_ea(i, fnode, "DEV", (char *)&ea, 4); } } }
static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence) { loff_t new_off = off + (whence == 1 ? filp->f_pos : 0); loff_t pos; struct quad_buffer_head qbh; struct inode *i = filp->f_path.dentry->d_inode; struct hpfs_inode_info *hpfs_inode = hpfs_i(i); struct super_block *s = i->i_sb; /* Somebody else will have to figure out what to do here */ if (whence == SEEK_DATA || whence == SEEK_HOLE) return -EINVAL; hpfs_lock(s); /*printk("dir lseek\n");*/ if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok; mutex_lock(&i->i_mutex); pos = ((loff_t) hpfs_de_as_down_as_possible(s, hpfs_inode->i_dno) << 4) + 1; while (pos != new_off) { if (map_pos_dirent(i, &pos, &qbh)) hpfs_brelse4(&qbh); else goto fail; if (pos == 12) goto fail; } mutex_unlock(&i->i_mutex); ok: hpfs_unlock(s); return filp->f_pos = new_off; fail: mutex_unlock(&i->i_mutex); /*printk("illegal lseek: %016llx\n", new_off);*/ hpfs_unlock(s); return -ESPIPE; }
static int hpfs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { *pagep = NULL; return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, hpfs_get_block, &hpfs_i(mapping->host)->mmu_private); }
static ssize_t hpfs_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { ssize_t retval; retval = do_sync_write(file, buf, count, ppos); if (retval > 0) hpfs_i(file->f_path.dentry->d_inode)->i_dirty = 1; return retval; }
static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) { const char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; struct quad_buffer_head qbh; struct hpfs_dirent *de; struct inode *inode = dentry->d_inode; dnode_secno dno; fnode_secno fno; int n_items = 0; int err; int r; hpfs_adjust_length((char *)name, &len); lock_kernel(); mutex_lock(&hpfs_i(inode)->i_parent_mutex); mutex_lock(&hpfs_i(dir)->i_mutex); err = -ENOENT; de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh); if (!de) goto out; err = -EPERM; if (de->first) goto out1; err = -ENOTDIR; if (!de->directory) goto out1; hpfs_count_dnodes(dir->i_sb, hpfs_i(inode)->i_dno, NULL, NULL, &n_items); err = -ENOTEMPTY; if (n_items) goto out1; fno = de->fnode; r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); switch (r) { case 1: hpfs_error(dir->i_sb, "there was error when removing dirent"); err = -EFSERROR; break; case 2: err = -ENOSPC; break; default: dir->i_nlink--; inode->i_nlink = 0; err = 0; } goto out; out1: hpfs_brelse4(&qbh); out: mutex_unlock(&hpfs_i(dir)->i_mutex); mutex_unlock(&hpfs_i(inode)->i_parent_mutex); unlock_kernel(); return err; }
void hpfs_write_inode_nolock(struct inode *i) { struct hpfs_inode_info *hpfs_inode = hpfs_i(i); struct buffer_head *bh; struct fnode *fnode; struct quad_buffer_head qbh; struct hpfs_dirent *de; if (i->i_ino == hpfs_sb(i->i_sb)->sb_root) return; if (!(fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) return; if (i->i_ino != hpfs_sb(i->i_sb)->sb_root && i->i_nlink) { if (!(de = map_fnode_dirent(i->i_sb, i->i_ino, fnode, &qbh))) { brelse(bh); return; } } else de = NULL; if (S_ISREG(i->i_mode)) { fnode->file_size = cpu_to_le32(i->i_size); if (de) de->file_size = cpu_to_le32(i->i_size); } else if (S_ISDIR(i->i_mode)) { fnode->file_size = cpu_to_le32(0); if (de) de->file_size = cpu_to_le32(0); } hpfs_write_inode_ea(i, fnode); if (de) { de->write_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_mtime.tv_sec)); de->read_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_atime.tv_sec)); de->creation_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_ctime.tv_sec)); de->read_only = !(i->i_mode & 0222); de->ea_size = cpu_to_le32(hpfs_inode->i_ea_size); hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); } if (S_ISDIR(i->i_mode)) { if ((de = map_dirent(i, hpfs_inode->i_dno, "\001\001", 2, NULL, &qbh))) { de->write_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_mtime.tv_sec)); de->read_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_atime.tv_sec)); de->creation_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_ctime.tv_sec)); de->read_only = !(i->i_mode & 0222); de->ea_size = cpu_to_le32(/* */0); de->file_size = cpu_to_le32(0); hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); } else hpfs_error(i->i_sb, "directory %08lx doesn't have '.' entry", (unsigned long)i->i_ino); } mark_buffer_dirty(bh); brelse(bh); }
static int hpfs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { int ret; *pagep = NULL; ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, hpfs_get_block, &hpfs_i(mapping->host)->mmu_private); if (unlikely(ret)) hpfs_write_failed(mapping, pos + len); return ret; }
static int hpfs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { int ret; *pagep = NULL; ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, hpfs_get_block, &hpfs_i(mapping->host)->mmu_private); if (unlikely(ret)) { loff_t isize; hpfs_lock(mapping->host->i_sb); isize = mapping->host->i_size; if (pos + len > isize) vmtruncate(mapping->host, isize); hpfs_unlock(mapping->host->i_sb); } return ret; }
void hpfs_decide_conv(struct inode *inode, unsigned char *name, unsigned len) { struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); int i; if (hpfs_inode->i_conv != CONV_AUTO) return; for (i = 0; *text_postfix[i]; i++) { int l = strlen(text_postfix[i]); if (l <= len) if (!hpfs_compare_names(inode->i_sb, text_postfix[i], l, name + len - l, l, 0)) goto text; } for (i = 0; *text_prefix[i]; i++) { int l = strlen(text_prefix[i]); if (l <= len) if (!hpfs_compare_names(inode->i_sb, text_prefix[i], l, name, l, 0)) goto text; } hpfs_inode->i_conv = CONV_BINARY; return; text: hpfs_inode->i_conv = CONV_TEXT; return; }
static int hpfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { const unsigned char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; struct buffer_head *bh; struct fnode *fnode; fnode_secno fno; int r; struct hpfs_dirent dee; struct inode *result = NULL; int err; if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err; if (hpfs_sb(dir->i_sb)->sb_eas < 2) return -EPERM; if (!new_valid_dev(rdev)) return -EINVAL; hpfs_lock(dir->i_sb); err = -ENOSPC; fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); if (!fnode) goto bail; memset(&dee, 0, sizeof dee); if (!(mode & 0222)) dee.read_only = 1; dee.archive = 1; dee.hidden = name[0] == '.'; dee.fnode = cpu_to_le32(fno); dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds())); result = new_inode(dir->i_sb); if (!result) goto bail1; hpfs_init_inode(result); result->i_ino = fno; hpfs_i(result)->i_parent_dir = dir->i_ino; result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date)); result->i_ctime.tv_nsec = 0; result->i_mtime.tv_nsec = 0; result->i_atime.tv_nsec = 0; hpfs_i(result)->i_ea_size = 0; result->i_uid = current_fsuid(); result->i_gid = current_fsgid(); set_nlink(result, 1); result->i_size = 0; result->i_blocks = 1; init_special_inode(result, mode, rdev); r = hpfs_add_dirent(dir, name, len, &dee); if (r == 1) goto bail2; if (r == -1) { err = -EEXIST; goto bail2; } fnode->len = len; memcpy(fnode->name, name, len > 15 ? 15 : len); fnode->up = cpu_to_le32(dir->i_ino); mark_buffer_dirty(bh); insert_inode_hash(result); hpfs_write_inode_nolock(result); hpfs_update_directory_times(dir); d_instantiate(dentry, result); brelse(bh); hpfs_unlock(dir->i_sb); return 0; bail2: iput(result); bail1: brelse(bh); hpfs_free_sectors(dir->i_sb, fno, 1); bail: hpfs_unlock(dir->i_sb); return err; }
static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { const unsigned char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; struct quad_buffer_head qbh0; struct buffer_head *bh; struct hpfs_dirent *de; struct fnode *fnode; struct dnode *dnode; struct inode *result; fnode_secno fno; dnode_secno dno; int r; struct hpfs_dirent dee; int err; if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err; hpfs_lock(dir->i_sb); err = -ENOSPC; fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); if (!fnode) goto bail; dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0); if (!dnode) goto bail1; memset(&dee, 0, sizeof dee); dee.directory = 1; if (!(mode & 0222)) dee.read_only = 1; /*dee.archive = 0;*/ dee.hidden = name[0] == '.'; dee.fnode = cpu_to_le32(fno); dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds())); result = new_inode(dir->i_sb); if (!result) goto bail2; hpfs_init_inode(result); result->i_ino = fno; hpfs_i(result)->i_parent_dir = dir->i_ino; hpfs_i(result)->i_dno = dno; result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date)); result->i_ctime.tv_nsec = 0; result->i_mtime.tv_nsec = 0; result->i_atime.tv_nsec = 0; hpfs_i(result)->i_ea_size = 0; result->i_mode |= S_IFDIR; result->i_op = &hpfs_dir_iops; result->i_fop = &hpfs_dir_ops; result->i_blocks = 4; result->i_size = 2048; set_nlink(result, 2); if (dee.read_only) result->i_mode &= ~0222; r = hpfs_add_dirent(dir, name, len, &dee); if (r == 1) goto bail3; if (r == -1) { err = -EEXIST; goto bail3; } fnode->len = len; memcpy(fnode->name, name, len > 15 ? 15 : len); fnode->up = cpu_to_le32(dir->i_ino); fnode->flags |= FNODE_dir; fnode->btree.n_free_nodes = 7; fnode->btree.n_used_nodes = 1; fnode->btree.first_free = cpu_to_le16(0x14); fnode->u.external[0].disk_secno = cpu_to_le32(dno); fnode->u.external[0].file_secno = cpu_to_le32(-1); dnode->root_dnode = 1; dnode->up = cpu_to_le32(fno); de = hpfs_add_de(dir->i_sb, dnode, "\001\001", 2, 0); de->creation_date = de->write_date = de->read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds())); if (!(mode & 0222)) de->read_only = 1; de->first = de->directory = 1; /*de->hidden = de->system = 0;*/ de->fnode = cpu_to_le32(fno); mark_buffer_dirty(bh); brelse(bh); hpfs_mark_4buffers_dirty(&qbh0); hpfs_brelse4(&qbh0); inc_nlink(dir); insert_inode_hash(result); if (!uid_eq(result->i_uid, current_fsuid()) || !gid_eq(result->i_gid, current_fsgid()) || result->i_mode != (mode | S_IFDIR)) { result->i_uid = current_fsuid(); result->i_gid = current_fsgid(); result->i_mode = mode | S_IFDIR; hpfs_write_inode_nolock(result); } hpfs_update_directory_times(dir); d_instantiate(dentry, result); hpfs_unlock(dir->i_sb); return 0; bail3: iput(result); bail2: hpfs_brelse4(&qbh0); hpfs_free_dnode(dir->i_sb, dno); bail1: brelse(bh); hpfs_free_sectors(dir->i_sb, fno, 1); bail: hpfs_unlock(dir->i_sb); return err; }
static int hpfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { const unsigned char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; struct inode *result = NULL; struct buffer_head *bh; struct fnode *fnode; fnode_secno fno; int r; struct hpfs_dirent dee; int err; if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err; hpfs_lock(dir->i_sb); err = -ENOSPC; fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); if (!fnode) goto bail; memset(&dee, 0, sizeof dee); if (!(mode & 0222)) dee.read_only = 1; dee.archive = 1; dee.hidden = name[0] == '.'; dee.fnode = cpu_to_le32(fno); dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds())); result = new_inode(dir->i_sb); if (!result) goto bail1; hpfs_init_inode(result); result->i_ino = fno; result->i_mode |= S_IFREG; result->i_mode &= ~0111; result->i_op = &hpfs_file_iops; result->i_fop = &hpfs_file_ops; set_nlink(result, 1); hpfs_i(result)->i_parent_dir = dir->i_ino; result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date)); result->i_ctime.tv_nsec = 0; result->i_mtime.tv_nsec = 0; result->i_atime.tv_nsec = 0; hpfs_i(result)->i_ea_size = 0; if (dee.read_only) result->i_mode &= ~0222; result->i_blocks = 1; result->i_size = 0; result->i_data.a_ops = &hpfs_aops; hpfs_i(result)->mmu_private = 0; r = hpfs_add_dirent(dir, name, len, &dee); if (r == 1) goto bail2; if (r == -1) { err = -EEXIST; goto bail2; } fnode->len = len; memcpy(fnode->name, name, len > 15 ? 15 : len); fnode->up = cpu_to_le32(dir->i_ino); mark_buffer_dirty(bh); brelse(bh); insert_inode_hash(result); if (!uid_eq(result->i_uid, current_fsuid()) || !gid_eq(result->i_gid, current_fsgid()) || result->i_mode != (mode | S_IFREG)) { result->i_uid = current_fsuid(); result->i_gid = current_fsgid(); result->i_mode = mode | S_IFREG; hpfs_write_inode_nolock(result); } hpfs_update_directory_times(dir); d_instantiate(dentry, result); hpfs_unlock(dir->i_sb); return 0; bail2: iput(result); bail1: brelse(bh); hpfs_free_sectors(dir->i_sb, fno, 1); bail: hpfs_unlock(dir->i_sb); return err; }
static void hpfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode)); }
static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct inode *inode = filp->f_path.dentry->d_inode; struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); struct quad_buffer_head qbh; struct hpfs_dirent *de; int lc; long old_pos; unsigned char *tempname; int c1, c2 = 0; int ret = 0; hpfs_lock(inode->i_sb); if (hpfs_sb(inode->i_sb)->sb_chk) { if (hpfs_chk_sectors(inode->i_sb, inode->i_ino, 1, "dir_fnode")) { ret = -EFSERROR; goto out; } if (hpfs_chk_sectors(inode->i_sb, hpfs_inode->i_dno, 4, "dir_dnode")) { ret = -EFSERROR; goto out; } } if (hpfs_sb(inode->i_sb)->sb_chk >= 2) { struct buffer_head *bh; struct fnode *fno; int e = 0; if (!(fno = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) { ret = -EIOERROR; goto out; } if (!fno->dirflag) { e = 1; hpfs_error(inode->i_sb, "not a directory, fnode %08lx", (unsigned long)inode->i_ino); } if (hpfs_inode->i_dno != le32_to_cpu(fno->u.external[0].disk_secno)) { e = 1; hpfs_error(inode->i_sb, "corrupted inode: i_dno == %08x, fnode -> dnode == %08x", hpfs_inode->i_dno, le32_to_cpu(fno->u.external[0].disk_secno)); } brelse(bh); if (e) { ret = -EFSERROR; goto out; } } lc = hpfs_sb(inode->i_sb)->sb_lowercase; if (filp->f_pos == 12) { /* diff -r requires this (note, that diff -r */ filp->f_pos = 13; /* also fails on msdos filesystem in 2.0) */ goto out; } if (filp->f_pos == 13) { ret = -ENOENT; goto out; } while (1) { again: /* This won't work when cycle is longer than number of dirents accepted by filldir, but what can I do? maybe killall -9 ls helps */ if (hpfs_sb(inode->i_sb)->sb_chk) if (hpfs_stop_cycles(inode->i_sb, filp->f_pos, &c1, &c2, "hpfs_readdir")) { ret = -EFSERROR; goto out; } if (filp->f_pos == 12) goto out; if (filp->f_pos == 3 || filp->f_pos == 4 || filp->f_pos == 5) { printk("HPFS: warning: pos==%d\n",(int)filp->f_pos); goto out; } if (filp->f_pos == 0) { if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) goto out; filp->f_pos = 11; } if (filp->f_pos == 11) { if (filldir(dirent, "..", 2, filp->f_pos, hpfs_inode->i_parent_dir, DT_DIR) < 0) goto out; filp->f_pos = 1; } if (filp->f_pos == 1) { filp->f_pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, hpfs_inode->i_dno) << 4) + 1; hpfs_add_pos(inode, &filp->f_pos); filp->f_version = inode->i_version; } old_pos = filp->f_pos; if (!(de = map_pos_dirent(inode, &filp->f_pos, &qbh))) { ret = -EIOERROR; goto out; } if (de->first || de->last) { if (hpfs_sb(inode->i_sb)->sb_chk) { if (de->first && !de->last && (de->namelen != 2 || de ->name[0] != 1 || de->name[1] != 1)) hpfs_error(inode->i_sb, "hpfs_readdir: bad ^A^A entry; pos = %08lx", old_pos); if (de->last && (de->namelen != 1 || de ->name[0] != 255)) hpfs_error(inode->i_sb, "hpfs_readdir: bad \\377 entry; pos = %08lx", old_pos); } hpfs_brelse4(&qbh); goto again; } tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3); if (filldir(dirent, tempname, de->namelen, old_pos, le32_to_cpu(de->fnode), DT_UNKNOWN) < 0) { filp->f_pos = old_pos; if (tempname != de->name) kfree(tempname); hpfs_brelse4(&qbh); goto out; } if (tempname != de->name) kfree(tempname); hpfs_brelse4(&qbh); } out: hpfs_unlock(inode->i_sb); return ret; }
static int hpfs_fill_super(struct super_block *s, void *options, int silent) { struct buffer_head *bh0, *bh1, *bh2; struct hpfs_boot_block *bootblock; struct hpfs_super_block *superblock; struct hpfs_spare_block *spareblock; struct hpfs_sb_info *sbi; struct inode *root; uid_t uid; gid_t gid; umode_t umask; int lowercase, eas, chk, errs, chkdsk, timeshift; dnode_secno root_dno; struct hpfs_dirent *de = NULL; struct quad_buffer_head qbh; int o; save_mount_options(s, options); sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) { return -ENOMEM; } s->s_fs_info = sbi; sbi->sb_bmp_dir = NULL; sbi->sb_cp_table = NULL; mutex_init(&sbi->hpfs_mutex); hpfs_lock(s); uid = current_uid(); gid = current_gid(); umask = current_umask(); lowercase = 0; eas = 2; chk = 1; errs = 1; chkdsk = 1; timeshift = 0; if (!(o = parse_opts(options, &uid, &gid, &umask, &lowercase, &eas, &chk, &errs, &chkdsk, ×hift))) { printk("HPFS: bad mount options.\n"); goto bail0; } if (o==2) { hpfs_help(); goto bail0; } /*sbi->sb_mounting = 1;*/ sb_set_blocksize(s, 512); sbi->sb_fs_size = -1; if (!(bootblock = hpfs_map_sector(s, 0, &bh0, 0))) goto bail1; if (!(superblock = hpfs_map_sector(s, 16, &bh1, 1))) goto bail2; if (!(spareblock = hpfs_map_sector(s, 17, &bh2, 0))) goto bail3; /* Check magics */ if (/*le16_to_cpu(bootblock->magic) != BB_MAGIC ||*/ le32_to_cpu(superblock->magic) != SB_MAGIC || le32_to_cpu(spareblock->magic) != SP_MAGIC) { if (!silent) printk("HPFS: Bad magic ... probably not HPFS\n"); goto bail4; } /* Check version */ if (!(s->s_flags & MS_RDONLY) && superblock->funcversion != 2 && superblock->funcversion != 3) { printk("HPFS: Bad version %d,%d. Mount readonly to go around\n", (int)superblock->version, (int)superblock->funcversion); printk("HPFS: please try recent version of HPFS driver at http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi and if it still can't understand this format, contact author - [email protected]\n"); goto bail4; } s->s_flags |= MS_NOATIME; /* Fill superblock stuff */ s->s_magic = HPFS_SUPER_MAGIC; s->s_op = &hpfs_sops; s->s_d_op = &hpfs_dentry_operations; sbi->sb_root = le32_to_cpu(superblock->root); sbi->sb_fs_size = le32_to_cpu(superblock->n_sectors); sbi->sb_bitmaps = le32_to_cpu(superblock->bitmaps); sbi->sb_dirband_start = le32_to_cpu(superblock->dir_band_start); sbi->sb_dirband_size = le32_to_cpu(superblock->n_dir_band); sbi->sb_dmap = le32_to_cpu(superblock->dir_band_bitmap); sbi->sb_uid = uid; sbi->sb_gid = gid; sbi->sb_mode = 0777 & ~umask; sbi->sb_n_free = -1; sbi->sb_n_free_dnodes = -1; sbi->sb_lowercase = lowercase; sbi->sb_eas = eas; sbi->sb_chk = chk; sbi->sb_chkdsk = chkdsk; sbi->sb_err = errs; sbi->sb_timeshift = timeshift; sbi->sb_was_error = 0; sbi->sb_cp_table = NULL; sbi->sb_c_bitmap = -1; sbi->sb_max_fwd_alloc = 0xffffff; if (sbi->sb_fs_size >= 0x80000000) { hpfs_error(s, "invalid size in superblock: %08x", (unsigned)sbi->sb_fs_size); goto bail4; } /* Load bitmap directory */ if (!(sbi->sb_bmp_dir = hpfs_load_bitmap_directory(s, le32_to_cpu(superblock->bitmaps)))) goto bail4; /* Check for general fs errors*/ if (spareblock->dirty && !spareblock->old_wrote) { if (errs == 2) { printk("HPFS: Improperly stopped, not mounted\n"); goto bail4; } hpfs_error(s, "improperly stopped"); } if (!(s->s_flags & MS_RDONLY)) { spareblock->dirty = 1; spareblock->old_wrote = 0; mark_buffer_dirty(bh2); } if (le32_to_cpu(spareblock->hotfixes_used) || le32_to_cpu(spareblock->n_spares_used)) { if (errs >= 2) { printk("HPFS: Hotfixes not supported here, try chkdsk\n"); mark_dirty(s, 0); goto bail4; } hpfs_error(s, "hotfixes not supported here, try chkdsk"); if (errs == 0) printk("HPFS: Proceeding, but your filesystem will be probably corrupted by this driver...\n"); else printk("HPFS: This driver may read bad files or crash when operating on disk with hotfixes.\n"); } if (le32_to_cpu(spareblock->n_dnode_spares) != le32_to_cpu(spareblock->n_dnode_spares_free)) { if (errs >= 2) { printk("HPFS: Spare dnodes used, try chkdsk\n"); mark_dirty(s, 0); goto bail4; } hpfs_error(s, "warning: spare dnodes used, try chkdsk"); if (errs == 0) printk("HPFS: Proceeding, but your filesystem could be corrupted if you delete files or directories\n"); } if (chk) { unsigned a; if (le32_to_cpu(superblock->dir_band_end) - le32_to_cpu(superblock->dir_band_start) + 1 != le32_to_cpu(superblock->n_dir_band) || le32_to_cpu(superblock->dir_band_end) < le32_to_cpu(superblock->dir_band_start) || le32_to_cpu(superblock->n_dir_band) > 0x4000) { hpfs_error(s, "dir band size mismatch: dir_band_start==%08x, dir_band_end==%08x, n_dir_band==%08x", le32_to_cpu(superblock->dir_band_start), le32_to_cpu(superblock->dir_band_end), le32_to_cpu(superblock->n_dir_band)); goto bail4; } a = sbi->sb_dirband_size; sbi->sb_dirband_size = 0; if (hpfs_chk_sectors(s, le32_to_cpu(superblock->dir_band_start), le32_to_cpu(superblock->n_dir_band), "dir_band") || hpfs_chk_sectors(s, le32_to_cpu(superblock->dir_band_bitmap), 4, "dir_band_bitmap") || hpfs_chk_sectors(s, le32_to_cpu(superblock->bitmaps), 4, "bitmaps")) { mark_dirty(s, 0); goto bail4; } sbi->sb_dirband_size = a; } else printk("HPFS: You really don't want any checks? You are crazy...\n"); /* Load code page table */ if (le32_to_cpu(spareblock->n_code_pages)) if (!(sbi->sb_cp_table = hpfs_load_code_page(s, le32_to_cpu(spareblock->code_page_dir)))) printk("HPFS: Warning: code page support is disabled\n"); brelse(bh2); brelse(bh1); brelse(bh0); root = iget_locked(s, sbi->sb_root); if (!root) goto bail0; hpfs_init_inode(root); hpfs_read_inode(root); unlock_new_inode(root); s->s_root = d_alloc_root(root); if (!s->s_root) { iput(root); goto bail0; } /* * find the root directory's . pointer & finish filling in the inode */ root_dno = hpfs_fnode_dno(s, sbi->sb_root); if (root_dno) de = map_dirent(root, root_dno, "\001\001", 2, NULL, &qbh); if (!de) hpfs_error(s, "unable to find root dir"); else { root->i_atime.tv_sec = local_to_gmt(s, le32_to_cpu(de->read_date)); root->i_atime.tv_nsec = 0; root->i_mtime.tv_sec = local_to_gmt(s, le32_to_cpu(de->write_date)); root->i_mtime.tv_nsec = 0; root->i_ctime.tv_sec = local_to_gmt(s, le32_to_cpu(de->creation_date)); root->i_ctime.tv_nsec = 0; hpfs_i(root)->i_ea_size = le16_to_cpu(de->ea_size); hpfs_i(root)->i_parent_dir = root->i_ino; if (root->i_size == -1) root->i_size = 2048; if (root->i_blocks == -1) root->i_blocks = 5; hpfs_brelse4(&qbh); } hpfs_unlock(s); return 0; bail4: brelse(bh2); bail3: brelse(bh1); bail2: brelse(bh0); bail1: bail0: hpfs_unlock(s); kfree(sbi->sb_bmp_dir); kfree(sbi->sb_cp_table); s->s_fs_info = NULL; kfree(sbi); return -EINVAL; }
static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink) { const unsigned char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; struct buffer_head *bh; struct fnode *fnode; fnode_secno fno; int r; struct hpfs_dirent dee; struct inode *result; int err; if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err; hpfs_lock(dir->i_sb); if (hpfs_sb(dir->i_sb)->sb_eas < 2) { hpfs_unlock(dir->i_sb); return -EPERM; } err = -ENOSPC; fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); if (!fnode) goto bail; memset(&dee, 0, sizeof dee); dee.archive = 1; dee.hidden = name[0] == '.'; dee.fnode = cpu_to_le32(fno); dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds())); result = new_inode(dir->i_sb); if (!result) goto bail1; result->i_ino = fno; hpfs_init_inode(result); hpfs_i(result)->i_parent_dir = dir->i_ino; result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date)); result->i_ctime.tv_nsec = 0; result->i_mtime.tv_nsec = 0; result->i_atime.tv_nsec = 0; hpfs_i(result)->i_ea_size = 0; result->i_mode = S_IFLNK | 0777; result->i_uid = current_fsuid(); result->i_gid = current_fsgid(); result->i_blocks = 1; set_nlink(result, 1); result->i_size = strlen(symlink); result->i_op = &page_symlink_inode_operations; result->i_data.a_ops = &hpfs_symlink_aops; r = hpfs_add_dirent(dir, name, len, &dee); if (r == 1) goto bail2; if (r == -1) { err = -EEXIST; goto bail2; } fnode->len = len; memcpy(fnode->name, name, len > 15 ? 15 : len); fnode->up = cpu_to_le32(dir->i_ino); hpfs_set_ea(result, fnode, "SYMLINK", symlink, strlen(symlink)); mark_buffer_dirty(bh); brelse(bh); insert_inode_hash(result); hpfs_write_inode_nolock(result); hpfs_update_directory_times(dir); d_instantiate(dentry, result); hpfs_unlock(dir->i_sb); return 0; bail2: iput(result); bail1: brelse(bh); hpfs_free_sectors(dir->i_sb, fno, 1); bail: hpfs_unlock(dir->i_sb); return err; }
static int hpfs_unlink(struct inode *dir, struct dentry *dentry) { const unsigned char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; struct quad_buffer_head qbh; struct hpfs_dirent *de; struct inode *inode = dentry->d_inode; dnode_secno dno; int r; int rep = 0; int err; hpfs_lock(dir->i_sb); hpfs_adjust_length(name, &len); again: err = -ENOENT; de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh); if (!de) goto out; err = -EPERM; if (de->first) goto out1; err = -EISDIR; if (de->directory) goto out1; r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); switch (r) { case 1: hpfs_error(dir->i_sb, "there was error when removing dirent"); err = -EFSERROR; break; case 2: /* no space for deleting, try to truncate file */ err = -ENOSPC; if (rep++) break; dentry_unhash(dentry); if (!d_unhashed(dentry)) { hpfs_unlock(dir->i_sb); return -ENOSPC; } if (generic_permission(inode, MAY_WRITE) || !S_ISREG(inode->i_mode) || get_write_access(inode)) { d_rehash(dentry); } else { struct iattr newattrs; /*printk("HPFS: truncating file before delete.\n");*/ newattrs.ia_size = 0; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; err = notify_change(dentry, &newattrs); put_write_access(inode); if (!err) goto again; } hpfs_unlock(dir->i_sb); return -ENOSPC; default: drop_nlink(inode); err = 0; } goto out; out1: hpfs_brelse4(&qbh); out: if (!err) hpfs_update_directory_times(dir); hpfs_unlock(dir->i_sb); return err; }
static void hpfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode)); }
static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { const unsigned char *old_name = old_dentry->d_name.name; unsigned old_len = old_dentry->d_name.len; const unsigned char *new_name = new_dentry->d_name.name; unsigned new_len = new_dentry->d_name.len; struct inode *i = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct quad_buffer_head qbh, qbh1; struct hpfs_dirent *dep, *nde; struct hpfs_dirent de; dnode_secno dno; int r; struct buffer_head *bh; struct fnode *fnode; int err; if ((err = hpfs_chk_name(new_name, &new_len))) return err; err = 0; hpfs_adjust_length(old_name, &old_len); hpfs_lock(i->i_sb); /* order doesn't matter, due to VFS exclusion */ /* Erm? Moving over the empty non-busy directory is perfectly legal */ if (new_inode && S_ISDIR(new_inode->i_mode)) { err = -EINVAL; goto end1; } if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, old_name, old_len, &dno, &qbh))) { hpfs_error(i->i_sb, "lookup succeeded but map dirent failed"); err = -ENOENT; goto end1; } copy_de(&de, dep); de.hidden = new_name[0] == '.'; if (new_inode) { int r; if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) { if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, new_name, new_len, NULL, &qbh1))) { clear_nlink(new_inode); copy_de(nde, &de); memcpy(nde->name, new_name, new_len); hpfs_mark_4buffers_dirty(&qbh1); hpfs_brelse4(&qbh1); goto end; } hpfs_error(new_dir->i_sb, "hpfs_rename: could not find dirent"); err = -EFSERROR; goto end1; } err = r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0; goto end1; } if (new_dir == old_dir) hpfs_brelse4(&qbh); if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de))) { if (r == -1) hpfs_error(new_dir->i_sb, "hpfs_rename: dirent already exists!"); err = r == 1 ? -ENOSPC : -EFSERROR; if (new_dir != old_dir) hpfs_brelse4(&qbh); goto end1; } if (new_dir == old_dir) if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, old_name, old_len, &dno, &qbh))) { hpfs_error(i->i_sb, "lookup succeeded but map dirent failed at #2"); err = -ENOENT; goto end1; } if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 0))) { hpfs_error(i->i_sb, "hpfs_rename: could not remove dirent"); err = r == 2 ? -ENOSPC : -EFSERROR; goto end1; } end: hpfs_i(i)->i_parent_dir = new_dir->i_ino; if (S_ISDIR(i->i_mode)) { inc_nlink(new_dir); drop_nlink(old_dir); } if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) { fnode->up = cpu_to_le32(new_dir->i_ino); fnode->len = new_len; memcpy(fnode->name, new_name, new_len>15?15:new_len); if (new_len < 15) memset(&fnode->name[new_len], 0, 15 - new_len); mark_buffer_dirty(bh); brelse(bh); } end1: if (!err) { hpfs_update_directory_times(old_dir); hpfs_update_directory_times(new_dir); } hpfs_unlock(i->i_sb); return err; }
struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { const unsigned char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; struct quad_buffer_head qbh; struct hpfs_dirent *de; ino_t ino; int err; struct inode *result = NULL; struct hpfs_inode_info *hpfs_result; hpfs_lock(dir->i_sb); if ((err = hpfs_chk_name(name, &len))) { if (err == -ENAMETOOLONG) { hpfs_unlock(dir->i_sb); return ERR_PTR(-ENAMETOOLONG); } goto end_add; } /* * '.' and '..' will never be passed here. */ de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, NULL, &qbh); /* * This is not really a bailout, just means file not found. */ if (!de) goto end; /* * Get inode number, what we're after. */ ino = le32_to_cpu(de->fnode); /* * Go find or make an inode. */ result = iget_locked(dir->i_sb, ino); if (!result) { hpfs_error(dir->i_sb, "hpfs_lookup: can't get inode"); goto bail1; } if (result->i_state & I_NEW) { hpfs_init_inode(result); if (de->directory) hpfs_read_inode(result); else if (le32_to_cpu(de->ea_size) && hpfs_sb(dir->i_sb)->sb_eas) hpfs_read_inode(result); else { result->i_mode |= S_IFREG; result->i_mode &= ~0111; result->i_op = &hpfs_file_iops; result->i_fop = &hpfs_file_ops; result->i_nlink = 1; } unlock_new_inode(result); } hpfs_result = hpfs_i(result); if (!de->directory) hpfs_result->i_parent_dir = dir->i_ino; if (de->has_acl || de->has_xtd_perm) if (!(dir->i_sb->s_flags & MS_RDONLY)) { hpfs_error(result->i_sb, "ACLs or XPERM found. This is probably HPFS386. This driver doesn't support it now. Send me some info on these structures"); goto bail1; } /* * Fill in the info from the directory if this is a newly created * inode. */ if (!result->i_ctime.tv_sec) { if (!(result->i_ctime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(de->creation_date)))) result->i_ctime.tv_sec = 1; result->i_ctime.tv_nsec = 0; result->i_mtime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(de->write_date)); result->i_mtime.tv_nsec = 0; result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(de->read_date)); result->i_atime.tv_nsec = 0; hpfs_result->i_ea_size = le32_to_cpu(de->ea_size); if (!hpfs_result->i_ea_mode && de->read_only) result->i_mode &= ~0222; if (!de->directory) { if (result->i_size == -1) { result->i_size = le32_to_cpu(de->file_size); result->i_data.a_ops = &hpfs_aops; hpfs_i(result)->mmu_private = result->i_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. */ result->i_blocks = 1 + ((result->i_size + 511) >> 9); } } }