root/fs/affs/dir.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. affs_readdir

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  *  linux/fs/affs/dir.c
   4  *
   5  *  (c) 1996  Hans-Joachim Widmaier - Rewritten
   6  *
   7  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
   8  *
   9  *  (C) 1992  Eric Youngdale Modified for ISO 9660 filesystem.
  10  *
  11  *  (C) 1991  Linus Torvalds - minix filesystem
  12  *
  13  *  affs directory handling functions
  14  *
  15  */
  16 
  17 #include <linux/iversion.h>
  18 #include "affs.h"
  19 
  20 static int affs_readdir(struct file *, struct dir_context *);
  21 
  22 const struct file_operations affs_dir_operations = {
  23         .read           = generic_read_dir,
  24         .llseek         = generic_file_llseek,
  25         .iterate_shared = affs_readdir,
  26         .fsync          = affs_file_fsync,
  27 };
  28 
  29 /*
  30  * directories can handle most operations...
  31  */
  32 const struct inode_operations affs_dir_inode_operations = {
  33         .create         = affs_create,
  34         .lookup         = affs_lookup,
  35         .link           = affs_link,
  36         .unlink         = affs_unlink,
  37         .symlink        = affs_symlink,
  38         .mkdir          = affs_mkdir,
  39         .rmdir          = affs_rmdir,
  40         .rename         = affs_rename2,
  41         .setattr        = affs_notify_change,
  42 };
  43 
  44 static int
  45 affs_readdir(struct file *file, struct dir_context *ctx)
  46 {
  47         struct inode            *inode = file_inode(file);
  48         struct super_block      *sb = inode->i_sb;
  49         struct buffer_head      *dir_bh = NULL;
  50         struct buffer_head      *fh_bh = NULL;
  51         unsigned char           *name;
  52         int                      namelen;
  53         u32                      i;
  54         int                      hash_pos;
  55         int                      chain_pos;
  56         u32                      ino;
  57         int                      error = 0;
  58 
  59         pr_debug("%s(ino=%lu,f_pos=%llx)\n", __func__, inode->i_ino, ctx->pos);
  60 
  61         if (ctx->pos < 2) {
  62                 file->private_data = (void *)0;
  63                 if (!dir_emit_dots(file, ctx))
  64                         return 0;
  65         }
  66 
  67         affs_lock_dir(inode);
  68         chain_pos = (ctx->pos - 2) & 0xffff;
  69         hash_pos  = (ctx->pos - 2) >> 16;
  70         if (chain_pos == 0xffff) {
  71                 affs_warning(sb, "readdir", "More than 65535 entries in chain");
  72                 chain_pos = 0;
  73                 hash_pos++;
  74                 ctx->pos = ((hash_pos << 16) | chain_pos) + 2;
  75         }
  76         dir_bh = affs_bread(sb, inode->i_ino);
  77         if (!dir_bh)
  78                 goto out_unlock_dir;
  79 
  80         /* If the directory hasn't changed since the last call to readdir(),
  81          * we can jump directly to where we left off.
  82          */
  83         ino = (u32)(long)file->private_data;
  84         if (ino && inode_eq_iversion(inode, file->f_version)) {
  85                 pr_debug("readdir() left off=%d\n", ino);
  86                 goto inside;
  87         }
  88 
  89         ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
  90         for (i = 0; ino && i < chain_pos; i++) {
  91                 fh_bh = affs_bread(sb, ino);
  92                 if (!fh_bh) {
  93                         affs_error(sb, "readdir","Cannot read block %d", i);
  94                         error = -EIO;
  95                         goto out_brelse_dir;
  96                 }
  97                 ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
  98                 affs_brelse(fh_bh);
  99                 fh_bh = NULL;
 100         }
 101         if (ino)
 102                 goto inside;
 103         hash_pos++;
 104 
 105         for (; hash_pos < AFFS_SB(sb)->s_hashsize; hash_pos++) {
 106                 ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
 107                 if (!ino)
 108                         continue;
 109                 ctx->pos = (hash_pos << 16) + 2;
 110 inside:
 111                 do {
 112                         fh_bh = affs_bread(sb, ino);
 113                         if (!fh_bh) {
 114                                 affs_error(sb, "readdir",
 115                                            "Cannot read block %d", ino);
 116                                 break;
 117                         }
 118 
 119                         namelen = min(AFFS_TAIL(sb, fh_bh)->name[0],
 120                                       (u8)AFFSNAMEMAX);
 121                         name = AFFS_TAIL(sb, fh_bh)->name + 1;
 122                         pr_debug("readdir(): dir_emit(\"%.*s\", ino=%u), hash=%d, f_pos=%llx\n",
 123                                  namelen, name, ino, hash_pos, ctx->pos);
 124 
 125                         if (!dir_emit(ctx, name, namelen, ino, DT_UNKNOWN))
 126                                 goto done;
 127                         ctx->pos++;
 128                         ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
 129                         affs_brelse(fh_bh);
 130                         fh_bh = NULL;
 131                 } while (ino);
 132         }
 133 done:
 134         file->f_version = inode_query_iversion(inode);
 135         file->private_data = (void *)(long)ino;
 136         affs_brelse(fh_bh);
 137 
 138 out_brelse_dir:
 139         affs_brelse(dir_bh);
 140 
 141 out_unlock_dir:
 142         affs_unlock_dir(inode);
 143         return error;
 144 }

/* [<][>][^][v][top][bottom][index][help] */