| 1 | |
| 2 | |
| 3 | * linux/fs/hpfs/dir.c
|
| 4 | *
|
| 5 | * Mikulas Patocka ([email protected]), 1998-1999
|
| 6 | *
|
| 7 | * directory VFS functions
|
| 8 |
|
| 9 |
|
| 10 | #include <linux/slab.h>
|
| 11 | #include "hpfs_fn.h"
|
| 12 |
|
| 13 | static int hpfs_dir_release(struct inode *inode, struct file *filp)
|
| 14 | {
|
| 15 | hpfs_lock(inode->i_sb);
|
| 16 | hpfs_del_pos(inode, &filp->f_pos);
|
| 17 |
|
| 18 | hpfs_unlock(inode->i_sb);
|
| 19 | return 0;
|
| 20 | }
|
| 21 |
|
| 22 |
|
| 23 |
|
| 24 | static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
|
| 25 | {
|
| 26 | loff_t new_off = off + (whence == 1 ? filp->f_pos : 0);
|
| 27 | loff_t pos;
|
| 28 | struct quad_buffer_head qbh;
|
| 29 | struct inode *i = file_inode(filp);
|
| 30 | struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
|
| 31 | struct super_block *s = i->i_sb;
|
| 32 |
|
| 33 |
|
| 34 | if (whence == SEEK_DATA || whence == SEEK_HOLE)
|
| 35 | return -EINVAL;
|
| 36 |
|
| 37 | inode_lock(i);
|
| 38 | hpfs_lock(s);
|
| 39 |
|
| 40 |
|
| 41 | if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok;
|
| 42 | pos = ((loff_t) hpfs_de_as_down_as_possible(s, hpfs_inode->i_dno) << 4) + 1;
|
| 43 | while (pos != new_off) {
|
| 44 | if (map_pos_dirent(i, &pos, &qbh)) hpfs_brelse4(&qbh);
|
| 45 | else goto fail;
|
| 46 | if (pos == 12) goto fail;
|
| 47 | }
|
| 48 | if (unlikely(hpfs_add_pos(i, &filp->f_pos) < 0)) {
|
| 49 | hpfs_unlock(s);
|
| 50 | inode_unlock(i);
|
| 51 | return -ENOMEM;
|
| 52 | }
|
| 53 | ok:
|
| 54 | filp->f_pos = new_off;
|
| 55 | hpfs_unlock(s);
|
| 56 | inode_unlock(i);
|
| 57 | return new_off;
|
| 58 | fail:
|
| 59 |
|
| 60 | hpfs_unlock(s);
|
| 61 | inode_unlock(i);
|
| 62 | return -ESPIPE;
|
| 63 | }
|
| 64 |
|
| 65 | static int hpfs_readdir(struct file *file, struct dir_context *ctx)
|
| 66 | {
|
| 67 | struct inode *inode = file_inode(file);
|
| 68 | struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
|
| 69 | struct quad_buffer_head qbh;
|
| 70 | struct hpfs_dirent *de;
|
| 71 | int lc;
|
| 72 | loff_t next_pos;
|
| 73 | unsigned char *tempname;
|
| 74 | int c1, c2 = 0;
|
| 75 | int ret = 0;
|
| 76 |
|
| 77 | hpfs_lock(inode->i_sb);
|
| 78 |
|
| 79 | if (hpfs_sb(inode->i_sb)->sb_chk) {
|
| 80 | if (hpfs_chk_sectors(inode->i_sb, inode->i_ino, 1, "dir_fnode")) {
|
| 81 | ret = -EFSERROR;
|
| 82 | goto out;
|
| 83 | }
|
| 84 | if (hpfs_chk_sectors(inode->i_sb, hpfs_inode->i_dno, 4, "dir_dnode")) {
|
| 85 | ret = -EFSERROR;
|
| 86 | goto out;
|
| 87 | }
|
| 88 | }
|
| 89 | if (hpfs_sb(inode->i_sb)->sb_chk >= 2) {
|
| 90 | struct buffer_head *bh;
|
| 91 | struct fnode *fno;
|
| 92 | int e = 0;
|
| 93 | if (!(fno = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) {
|
| 94 | ret = -EIOERROR;
|
| 95 | goto out;
|
| 96 | }
|
| 97 | if (!fnode_is_dir(fno)) {
|
| 98 | e = 1;
|
| 99 | hpfs_error(inode->i_sb, "not a directory, fnode %08llx",
|
| 100 | inode->i_ino);
|
| 101 | }
|
| 102 | if (hpfs_inode->i_dno != le32_to_cpu(fno->u.external[0].disk_secno)) {
|
| 103 | e = 1;
|
| 104 | 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));
|
| 105 | }
|
| 106 | brelse(bh);
|
| 107 | if (e) {
|
| 108 | ret = -EFSERROR;
|
| 109 | goto out;
|
| 110 | }
|
| 111 | }
|
| 112 | lc = hpfs_sb(inode->i_sb)->sb_lowercase;
|
| 113 | if (ctx->pos == 12) {
|
| 114 | ctx->pos = 13;
|
| 115 | goto out;
|
| 116 | }
|
| 117 | if (ctx->pos == 13) {
|
| 118 | ret = -ENOENT;
|
| 119 | goto out;
|
| 120 | }
|
| 121 |
|
| 122 | while (1) {
|
| 123 | again:
|
| 124 | |
| 125 | accepted by filldir, but what can I do?
|
| 126 | maybe killall -9 ls helps
|
| 127 | if (hpfs_sb(inode->i_sb)->sb_chk)
|
| 128 | if (hpfs_stop_cycles(inode->i_sb, ctx->pos, &c1, &c2, "hpfs_readdir")) {
|
| 129 | ret = -EFSERROR;
|
| 130 | goto out;
|
| 131 | }
|
| 132 | if (ctx->pos == 12)
|
| 133 | goto out;
|
| 134 | if (ctx->pos == 3 || ctx->pos == 4 || ctx->pos == 5) {
|
| 135 | pr_err("pos==%d\n", (int)ctx->pos);
|
| 136 | goto out;
|
| 137 | }
|
| 138 | if (ctx->pos == 0) {
|
| 139 | if (!dir_emit_dot(file, ctx))
|
| 140 | goto out;
|
| 141 | ctx->pos = 11;
|
| 142 | }
|
| 143 | if (ctx->pos == 11) {
|
| 144 | if (!dir_emit(ctx, "..", 2, hpfs_inode->i_parent_dir, DT_DIR))
|
| 145 | goto out;
|
| 146 | ctx->pos = 1;
|
| 147 | }
|
| 148 | if (ctx->pos == 1) {
|
| 149 | ret = hpfs_add_pos(inode, &file->f_pos);
|
| 150 | if (unlikely(ret < 0))
|
| 151 | goto out;
|
| 152 | ctx->pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, hpfs_inode->i_dno) << 4) + 1;
|
| 153 | }
|
| 154 | next_pos = ctx->pos;
|
| 155 | if (!(de = map_pos_dirent(inode, &next_pos, &qbh))) {
|
| 156 | ctx->pos = next_pos;
|
| 157 | ret = -EIOERROR;
|
| 158 | goto out;
|
| 159 | }
|
| 160 | if (de->first || de->last) {
|
| 161 | if (hpfs_sb(inode->i_sb)->sb_chk) {
|
| 162 | if (de->first && !de->last && (de->namelen != 2
|
| 163 | || de ->name[0] != 1 || de->name[1] != 1))
|
| 164 | hpfs_error(inode->i_sb, "hpfs_readdir: bad ^A^A entry; pos = %08lx", (unsigned long)ctx->pos);
|
| 165 | if (de->last && (de->namelen != 1 || de ->name[0] != 255))
|
| 166 | hpfs_error(inode->i_sb, "hpfs_readdir: bad \\377 entry; pos = %08lx", (unsigned long)ctx->pos);
|
| 167 | }
|
| 168 | hpfs_brelse4(&qbh);
|
| 169 | ctx->pos = next_pos;
|
| 170 | goto again;
|
| 171 | }
|
| 172 | tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3);
|
| 173 | if (!dir_emit(ctx, tempname, de->namelen, le32_to_cpu(de->fnode), DT_UNKNOWN)) {
|
| 174 | if (tempname != de->name) kfree(tempname);
|
| 175 | hpfs_brelse4(&qbh);
|
| 176 | goto out;
|
| 177 | }
|
| 178 | ctx->pos = next_pos;
|
| 179 | if (tempname != de->name) kfree(tempname);
|
| 180 | hpfs_brelse4(&qbh);
|
| 181 | }
|
| 182 | out:
|
| 183 | hpfs_unlock(inode->i_sb);
|
| 184 | return ret;
|
| 185 | }
|
| 186 |
|
| 187 | |
| 188 | * lookup. Search the specified directory for the specified name, set
|
| 189 | * *result to the corresponding inode.
|
| 190 | *
|
| 191 | * lookup uses the inode number to tell read_inode whether it is reading
|
| 192 | * the inode of a directory or a file -- file ino's are odd, directory
|
| 193 | * ino's are even. read_inode avoids i/o for file inodes; everything
|
| 194 | * needed is up here in the directory. (And file fnodes are out in
|
| 195 | * the boondocks.)
|
| 196 | *
|
| 197 | * - M.P.: this is over, sometimes we've got to read file's fnode for eas
|
| 198 | * inode numbers are just fnode sector numbers; iget lock is used
|
| 199 | * to tell read_inode to read fnode or not.
|
| 200 |
|
| 201 |
|
| 202 | struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
|
| 203 | {
|
| 204 | const unsigned char *name = dentry->d_name.name;
|
| 205 | unsigned len = dentry->d_name.len;
|
| 206 | struct quad_buffer_head qbh;
|
| 207 | struct hpfs_dirent *de;
|
| 208 | ino_t ino;
|
| 209 | int err;
|
| 210 | struct inode *result = NULL;
|
| 211 | struct hpfs_inode_info *hpfs_result;
|
| 212 |
|
| 213 | hpfs_lock(dir->i_sb);
|
| 214 | if ((err = hpfs_chk_name(name, &len))) {
|
| 215 | if (err == -ENAMETOOLONG) {
|
| 216 | hpfs_unlock(dir->i_sb);
|
| 217 | return ERR_PTR(-ENAMETOOLONG);
|
| 218 | }
|
| 219 | goto end_add;
|
| 220 | }
|
| 221 |
|
| 222 | |
| 223 | * '.' and '..' will never be passed here.
|
| 224 |
|
| 225 |
|
| 226 | de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, NULL, &qbh);
|
| 227 |
|
| 228 | |
| 229 | * This is not really a bailout, just means file not found.
|
| 230 |
|
| 231 |
|
| 232 | if (!de) goto end;
|
| 233 |
|
| 234 | |
| 235 | * Get inode number, what we're after.
|
| 236 |
|
| 237 |
|
| 238 | ino = le32_to_cpu(de->fnode);
|
| 239 |
|
| 240 | |
| 241 | * Go find or make an inode.
|
| 242 |
|
| 243 |
|
| 244 | result = iget_locked(dir->i_sb, ino);
|
| 245 | if (!result) {
|
| 246 | hpfs_error(dir->i_sb, "hpfs_lookup: can't get inode");
|
| 247 | result = ERR_PTR(-ENOMEM);
|
| 248 | goto bail1;
|
| 249 | }
|
| 250 | if (inode_state_read_once(result) & I_NEW) {
|
| 251 | hpfs_init_inode(result);
|
| 252 | if (de->directory)
|
| 253 | hpfs_read_inode(result);
|
| 254 | else if (le32_to_cpu(de->ea_size) && hpfs_sb(dir->i_sb)->sb_eas)
|
| 255 | hpfs_read_inode(result);
|
| 256 | else {
|
| 257 | result->i_mode |= S_IFREG;
|
| 258 | result->i_mode &= ~0111;
|
| 259 | result->i_op = &hpfs_file_iops;
|
| 260 | result->i_fop = &hpfs_file_ops;
|
| 261 | set_nlink(result, 1);
|
| 262 | }
|
| 263 | unlock_new_inode(result);
|
| 264 | }
|
| 265 | hpfs_result = hpfs_i(result);
|
| 266 | if (!de->directory) hpfs_result->i_parent_dir = dir->i_ino;
|
| 267 |
|
| 268 | if (de->has_acl || de->has_xtd_perm) if (!sb_rdonly(dir->i_sb)) {
|
| 269 | 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");
|
| 270 | iput(result);
|
| 271 | result = ERR_PTR(-EINVAL);
|
| 272 | goto bail1;
|
| 273 | }
|
| 274 |
|
| 275 | |
| 276 | * Fill in the info from the directory if this is a newly created
|
| 277 | * inode.
|
| 278 |
|
| 279 |
|
| 280 | if (!inode_get_ctime_sec(result)) {
|
| 281 | time64_t csec = local_to_gmt(dir->i_sb, le32_to_cpu(de->creation_date));
|
| 282 |
|
| 283 | inode_set_ctime(result, csec ? csec : 1, 0);
|
| 284 | inode_set_mtime(result,
|
| 285 | local_to_gmt(dir->i_sb, le32_to_cpu(de->write_date)),
|
| 286 | 0);
|
| 287 | inode_set_atime(result,
|
| 288 | local_to_gmt(dir->i_sb, le32_to_cpu(de->read_date)),
|
| 289 | 0);
|
| 290 | hpfs_result->i_ea_size = le32_to_cpu(de->ea_size);
|
| 291 | if (!hpfs_result->i_ea_mode && de->read_only)
|
| 292 | result->i_mode &= ~0222;
|
| 293 | if (!de->directory) {
|
| 294 | if (result->i_size == -1) {
|
| 295 | result->i_size = le32_to_cpu(de->file_size);
|
| 296 | result->i_data.a_ops = &hpfs_aops;
|
| 297 | hpfs_i(result)->mmu_private = result->i_size;
|
| 298 | |
| 299 | * i_blocks should count the fnode and any anodes.
|
| 300 | * We count 1 for the fnode and don't bother about
|
| 301 | * anodes -- the disk heads are on the directory band
|
| 302 | * and we want them to stay there.
|
| 303 |
|
| 304 | result->i_blocks = 1 + ((result->i_size + 511) >> 9);
|
| 305 | }
|
| 306 | }
|
| 307 | }
|
| 308 |
|
| 309 | bail1:
|
| 310 | hpfs_brelse4(&qbh);
|
| 311 |
|
| 312 | |
| 313 | * Made it.
|
| 314 |
|
| 315 |
|
| 316 | end:
|
| 317 | end_add:
|
| 318 | hpfs_unlock(dir->i_sb);
|
| 319 | return d_splice_alias(result, dentry);
|
| 320 | }
|
| 321 |
|
| 322 | const struct file_operations hpfs_dir_ops =
|
| 323 | {
|
| 324 | .llseek = hpfs_dir_lseek,
|
| 325 | .read = generic_read_dir,
|
| 326 | .iterate_shared = hpfs_readdir,
|
| 327 | .release = hpfs_dir_release,
|
| 328 | .fsync = hpfs_file_fsync,
|
| 329 | .unlocked_ioctl = hpfs_ioctl,
|
| 330 | .compat_ioctl = compat_ptr_ioctl,
|
| 331 | };
|