~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/affs/dir.c

Version: ~ [ linux-5.13-rc5 ] ~ [ linux-5.12.9 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.42 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.124 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.193 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.235 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.271 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.271 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 }
145 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp