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

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

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ 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.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * Squashfs - a compressed read only filesystem for Linux
  4  *
  5  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
  6  * Phillip Lougher <phillip@squashfs.org.uk>
  7  *
  8  * dir.c
  9  */
 10 
 11 /*
 12  * This file implements code to read directories from disk.
 13  *
 14  * See namei.c for a description of directory organisation on disk.
 15  */
 16 
 17 #include <linux/fs.h>
 18 #include <linux/vfs.h>
 19 #include <linux/slab.h>
 20 
 21 #include "squashfs_fs.h"
 22 #include "squashfs_fs_sb.h"
 23 #include "squashfs_fs_i.h"
 24 #include "squashfs.h"
 25 
 26 static const unsigned char squashfs_filetype_table[] = {
 27         DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
 28 };
 29 
 30 /*
 31  * Lookup offset (f_pos) in the directory index, returning the
 32  * metadata block containing it.
 33  *
 34  * If we get an error reading the index then return the part of the index
 35  * (if any) we have managed to read - the index isn't essential, just
 36  * quicker.
 37  */
 38 static int get_dir_index_using_offset(struct super_block *sb,
 39         u64 *next_block, int *next_offset, u64 index_start, int index_offset,
 40         int i_count, u64 f_pos)
 41 {
 42         struct squashfs_sb_info *msblk = sb->s_fs_info;
 43         int err, i, index, length = 0;
 44         unsigned int size;
 45         struct squashfs_dir_index dir_index;
 46 
 47         TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %lld\n",
 48                                         i_count, f_pos);
 49 
 50         /*
 51          * Translate from external f_pos to the internal f_pos.  This
 52          * is offset by 3 because we invent "." and ".." entries which are
 53          * not actually stored in the directory.
 54          */
 55         if (f_pos <= 3)
 56                 return f_pos;
 57         f_pos -= 3;
 58 
 59         for (i = 0; i < i_count; i++) {
 60                 err = squashfs_read_metadata(sb, &dir_index, &index_start,
 61                                 &index_offset, sizeof(dir_index));
 62                 if (err < 0)
 63                         break;
 64 
 65                 index = le32_to_cpu(dir_index.index);
 66                 if (index > f_pos)
 67                         /*
 68                          * Found the index we're looking for.
 69                          */
 70                         break;
 71 
 72                 size = le32_to_cpu(dir_index.size) + 1;
 73 
 74                 /* size should never be larger than SQUASHFS_NAME_LEN */
 75                 if (size > SQUASHFS_NAME_LEN)
 76                         break;
 77 
 78                 err = squashfs_read_metadata(sb, NULL, &index_start,
 79                                 &index_offset, size);
 80                 if (err < 0)
 81                         break;
 82 
 83                 length = index;
 84                 *next_block = le32_to_cpu(dir_index.start_block) +
 85                                         msblk->directory_table;
 86         }
 87 
 88         *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
 89 
 90         /*
 91          * Translate back from internal f_pos to external f_pos.
 92          */
 93         return length + 3;
 94 }
 95 
 96 
 97 static int squashfs_readdir(struct file *file, struct dir_context *ctx)
 98 {
 99         struct inode *inode = file_inode(file);
100         struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
101         u64 block = squashfs_i(inode)->start + msblk->directory_table;
102         int offset = squashfs_i(inode)->offset, length, err;
103         unsigned int inode_number, dir_count, size, type;
104         struct squashfs_dir_header dirh;
105         struct squashfs_dir_entry *dire;
106 
107         TRACE("Entered squashfs_readdir [%llx:%x]\n", block, offset);
108 
109         dire = kmalloc(sizeof(*dire) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
110         if (dire == NULL) {
111                 ERROR("Failed to allocate squashfs_dir_entry\n");
112                 goto finish;
113         }
114 
115         /*
116          * Return "." and  ".." entries as the first two filenames in the
117          * directory.  To maximise compression these two entries are not
118          * stored in the directory, and so we invent them here.
119          *
120          * It also means that the external f_pos is offset by 3 from the
121          * on-disk directory f_pos.
122          */
123         while (ctx->pos < 3) {
124                 char *name;
125                 int i_ino;
126 
127                 if (ctx->pos == 0) {
128                         name = ".";
129                         size = 1;
130                         i_ino = inode->i_ino;
131                 } else {
132                         name = "..";
133                         size = 2;
134                         i_ino = squashfs_i(inode)->parent;
135                 }
136 
137                 if (!dir_emit(ctx, name, size, i_ino,
138                                 squashfs_filetype_table[1]))
139                         goto finish;
140 
141                 ctx->pos += size;
142         }
143 
144         length = get_dir_index_using_offset(inode->i_sb, &block, &offset,
145                                 squashfs_i(inode)->dir_idx_start,
146                                 squashfs_i(inode)->dir_idx_offset,
147                                 squashfs_i(inode)->dir_idx_cnt,
148                                 ctx->pos);
149 
150         while (length < i_size_read(inode)) {
151                 /*
152                  * Read directory header
153                  */
154                 err = squashfs_read_metadata(inode->i_sb, &dirh, &block,
155                                         &offset, sizeof(dirh));
156                 if (err < 0)
157                         goto failed_read;
158 
159                 length += sizeof(dirh);
160 
161                 dir_count = le32_to_cpu(dirh.count) + 1;
162 
163                 if (dir_count > SQUASHFS_DIR_COUNT)
164                         goto failed_read;
165 
166                 while (dir_count--) {
167                         /*
168                          * Read directory entry.
169                          */
170                         err = squashfs_read_metadata(inode->i_sb, dire, &block,
171                                         &offset, sizeof(*dire));
172                         if (err < 0)
173                                 goto failed_read;
174 
175                         size = le16_to_cpu(dire->size) + 1;
176 
177                         /* size should never be larger than SQUASHFS_NAME_LEN */
178                         if (size > SQUASHFS_NAME_LEN)
179                                 goto failed_read;
180 
181                         err = squashfs_read_metadata(inode->i_sb, dire->name,
182                                         &block, &offset, size);
183                         if (err < 0)
184                                 goto failed_read;
185 
186                         length += sizeof(*dire) + size;
187 
188                         if (ctx->pos >= length)
189                                 continue;
190 
191                         dire->name[size] = '\0';
192                         inode_number = le32_to_cpu(dirh.inode_number) +
193                                 ((short) le16_to_cpu(dire->inode_number));
194                         type = le16_to_cpu(dire->type);
195 
196                         if (type > SQUASHFS_MAX_DIR_TYPE)
197                                 goto failed_read;
198 
199                         if (!dir_emit(ctx, dire->name, size,
200                                         inode_number,
201                                         squashfs_filetype_table[type]))
202                                 goto finish;
203 
204                         ctx->pos = length;
205                 }
206         }
207 
208 finish:
209         kfree(dire);
210         return 0;
211 
212 failed_read:
213         ERROR("Unable to read directory block [%llx:%x]\n", block, offset);
214         kfree(dire);
215         return 0;
216 }
217 
218 
219 const struct file_operations squashfs_dir_ops = {
220         .read = generic_read_dir,
221         .iterate_shared = squashfs_readdir,
222         .llseek = generic_file_llseek,
223 };
224 

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

kernel.org | git.kernel.org | LWN.net | Project Home | 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.

sflogo.php