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