ext2fs.c revision 1.11 1 1.11 tsutsui /* $NetBSD: ext2fs.c,v 1.11 2011/12/25 06:09:08 tsutsui Exp $ */
2 1.1 tsutsui
3 1.1 tsutsui /*
4 1.1 tsutsui * Copyright (c) 1997 Manuel Bouyer.
5 1.1 tsutsui *
6 1.1 tsutsui * Redistribution and use in source and binary forms, with or without
7 1.1 tsutsui * modification, are permitted provided that the following conditions
8 1.1 tsutsui * are met:
9 1.1 tsutsui * 1. Redistributions of source code must retain the above copyright
10 1.1 tsutsui * notice, this list of conditions and the following disclaimer.
11 1.1 tsutsui * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 tsutsui * notice, this list of conditions and the following disclaimer in the
13 1.1 tsutsui * documentation and/or other materials provided with the distribution.
14 1.1 tsutsui *
15 1.1 tsutsui * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 1.1 tsutsui * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 1.1 tsutsui * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 1.1 tsutsui * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 1.1 tsutsui * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 1.1 tsutsui * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 1.1 tsutsui * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 1.1 tsutsui * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 1.1 tsutsui * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 1.1 tsutsui * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 1.1 tsutsui */
26 1.1 tsutsui
27 1.1 tsutsui /*-
28 1.1 tsutsui * Copyright (c) 1993
29 1.1 tsutsui * The Regents of the University of California. All rights reserved.
30 1.1 tsutsui *
31 1.1 tsutsui * This code is derived from software contributed to Berkeley by
32 1.1 tsutsui * The Mach Operating System project at Carnegie-Mellon University.
33 1.1 tsutsui *
34 1.1 tsutsui * Redistribution and use in source and binary forms, with or without
35 1.1 tsutsui * modification, are permitted provided that the following conditions
36 1.1 tsutsui * are met:
37 1.1 tsutsui * 1. Redistributions of source code must retain the above copyright
38 1.1 tsutsui * notice, this list of conditions and the following disclaimer.
39 1.1 tsutsui * 2. Redistributions in binary form must reproduce the above copyright
40 1.1 tsutsui * notice, this list of conditions and the following disclaimer in the
41 1.1 tsutsui * documentation and/or other materials provided with the distribution.
42 1.1 tsutsui * 3. Neither the name of the University nor the names of its contributors
43 1.1 tsutsui * may be used to endorse or promote products derived from this software
44 1.1 tsutsui * without specific prior written permission.
45 1.1 tsutsui *
46 1.1 tsutsui * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 1.1 tsutsui * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 1.1 tsutsui * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 1.1 tsutsui * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 1.1 tsutsui * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 1.1 tsutsui * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 1.1 tsutsui * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 1.1 tsutsui * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 1.1 tsutsui * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 1.1 tsutsui * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 1.1 tsutsui * SUCH DAMAGE.
57 1.1 tsutsui *
58 1.1 tsutsui *
59 1.1 tsutsui * Copyright (c) 1990, 1991 Carnegie Mellon University
60 1.1 tsutsui * All Rights Reserved.
61 1.1 tsutsui *
62 1.1 tsutsui * Author: David Golub
63 1.1 tsutsui *
64 1.1 tsutsui * Permission to use, copy, modify and distribute this software and its
65 1.1 tsutsui * documentation is hereby granted, provided that both the copyright
66 1.1 tsutsui * notice and this permission notice appear in all copies of the
67 1.1 tsutsui * software, derivative works or modified versions, and any portions
68 1.1 tsutsui * thereof, and that both notices appear in supporting documentation.
69 1.1 tsutsui *
70 1.1 tsutsui * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
71 1.1 tsutsui * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
72 1.1 tsutsui * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
73 1.1 tsutsui *
74 1.1 tsutsui * Carnegie Mellon requests users of this software to return to
75 1.1 tsutsui *
76 1.1 tsutsui * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
77 1.1 tsutsui * School of Computer Science
78 1.1 tsutsui * Carnegie Mellon University
79 1.1 tsutsui * Pittsburgh PA 15213-3890
80 1.1 tsutsui *
81 1.1 tsutsui * any improvements or extensions that they make and grant Carnegie the
82 1.1 tsutsui * rights to redistribute these changes.
83 1.1 tsutsui */
84 1.1 tsutsui
85 1.1 tsutsui /*
86 1.1 tsutsui * Stand-alone file reading package for Ext2 file system.
87 1.1 tsutsui */
88 1.1 tsutsui
89 1.1 tsutsui /* #define EXT2FS_DEBUG */
90 1.1 tsutsui
91 1.1 tsutsui #include <sys/param.h>
92 1.1 tsutsui #include <sys/time.h>
93 1.1 tsutsui #include <ufs/ext2fs/ext2fs_dinode.h>
94 1.1 tsutsui #include <ufs/ext2fs/ext2fs_dir.h>
95 1.1 tsutsui #include <ufs/ext2fs/ext2fs.h>
96 1.1 tsutsui #ifdef _STANDALONE
97 1.1 tsutsui #include <lib/libkern/libkern.h>
98 1.1 tsutsui #else
99 1.1 tsutsui #include <string.h>
100 1.1 tsutsui #endif
101 1.1 tsutsui
102 1.1 tsutsui #include "stand.h"
103 1.1 tsutsui #include "ext2fs.h"
104 1.1 tsutsui
105 1.1 tsutsui #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
106 1.1 tsutsui #define LIBSA_NO_FS_SYMLINK
107 1.1 tsutsui #endif
108 1.1 tsutsui
109 1.1 tsutsui #if defined(LIBSA_NO_TWIDDLE)
110 1.1 tsutsui #define twiddle()
111 1.1 tsutsui #endif
112 1.1 tsutsui
113 1.1 tsutsui #ifndef indp_t
114 1.1 tsutsui #define indp_t int32_t
115 1.1 tsutsui #endif
116 1.1 tsutsui typedef uint32_t ino32_t;
117 1.1 tsutsui #ifndef FSBTODB
118 1.1 tsutsui #define FSBTODB(fs, indp) fsbtodb(fs, indp)
119 1.1 tsutsui #endif
120 1.1 tsutsui
121 1.1 tsutsui /*
122 1.1 tsutsui * To avoid having a lot of filesystem-block sized buffers lurking (which
123 1.1 tsutsui * could be 32k) we only keep a few entries of the indirect block map.
124 1.1 tsutsui * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
125 1.1 tsutsui * ~13 times pulling in a 6M kernel.
126 1.1 tsutsui * The cache size must be smaller than the smallest filesystem block,
127 1.1 tsutsui * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
128 1.1 tsutsui */
129 1.1 tsutsui #define LN2_IND_CACHE_SZ 6
130 1.1 tsutsui #define IND_CACHE_SZ (1 << LN2_IND_CACHE_SZ)
131 1.1 tsutsui #define IND_CACHE_MASK (IND_CACHE_SZ - 1)
132 1.1 tsutsui
133 1.1 tsutsui /*
134 1.1 tsutsui * In-core open file.
135 1.1 tsutsui */
136 1.1 tsutsui struct file {
137 1.1 tsutsui off_t f_seekp; /* seek pointer */
138 1.1 tsutsui struct m_ext2fs *f_fs; /* pointer to super-block */
139 1.1 tsutsui struct ext2fs_dinode f_di; /* copy of on-disk inode */
140 1.1 tsutsui uint f_nishift; /* for blocks in indirect block */
141 1.1 tsutsui indp_t f_ind_cache_block;
142 1.1 tsutsui indp_t f_ind_cache[IND_CACHE_SZ];
143 1.1 tsutsui
144 1.1 tsutsui char *f_buf; /* buffer for data block */
145 1.1 tsutsui size_t f_buf_size; /* size of data block */
146 1.1 tsutsui daddr_t f_buf_blkno; /* block number of data block */
147 1.1 tsutsui };
148 1.1 tsutsui
149 1.11 tsutsui #if defined(LIBSA_ENABLE_LS_OP)
150 1.11 tsutsui
151 1.11 tsutsui #define NELEM(x) (sizeof (x) / sizeof(*x))
152 1.11 tsutsui
153 1.11 tsutsui typedef struct entry_t entry_t;
154 1.11 tsutsui struct entry_t {
155 1.11 tsutsui entry_t *e_next;
156 1.11 tsutsui ino32_t e_ino;
157 1.11 tsutsui uint8_t e_type;
158 1.11 tsutsui char e_name[1];
159 1.11 tsutsui };
160 1.11 tsutsui
161 1.11 tsutsui static const char *const typestr[] = {
162 1.11 tsutsui "unknown",
163 1.11 tsutsui "REG",
164 1.11 tsutsui "DIR",
165 1.11 tsutsui "CHR",
166 1.11 tsutsui "BLK",
167 1.11 tsutsui "FIFO",
168 1.11 tsutsui "SOCK",
169 1.11 tsutsui "LNK"
170 1.11 tsutsui };
171 1.11 tsutsui
172 1.11 tsutsui static int
173 1.11 tsutsui fn_match(const char *fname, const char *pattern)
174 1.11 tsutsui {
175 1.11 tsutsui char fc, pc;
176 1.11 tsutsui
177 1.11 tsutsui do {
178 1.11 tsutsui fc = *fname++;
179 1.11 tsutsui pc = *pattern++;
180 1.11 tsutsui if (!fc && !pc)
181 1.11 tsutsui return 1;
182 1.11 tsutsui if (pc == '?' && fc)
183 1.11 tsutsui pc = fc;
184 1.11 tsutsui } while (fc == pc);
185 1.11 tsutsui
186 1.11 tsutsui if (pc != '*')
187 1.11 tsutsui return 0;
188 1.11 tsutsui /*
189 1.11 tsutsui * Too hard (and unnecessary really) too check for "*?name" etc....
190 1.11 tsutsui * "**" will look for a '*' and "*?" a '?'
191 1.11 tsutsui */
192 1.11 tsutsui pc = *pattern++;
193 1.11 tsutsui if (!pc)
194 1.11 tsutsui return 1;
195 1.11 tsutsui while ((fname = strchr(fname, pc)))
196 1.11 tsutsui if (fn_match(++fname, pattern))
197 1.11 tsutsui return 1;
198 1.11 tsutsui return 0;
199 1.11 tsutsui }
200 1.11 tsutsui #endif /* LIBSA_ENABLE_LS_OP */
201 1.11 tsutsui
202 1.1 tsutsui static int read_inode(ino32_t, struct open_file *);
203 1.1 tsutsui static int block_map(struct open_file *, indp_t, indp_t *);
204 1.1 tsutsui static int buf_read_file(struct open_file *, char **, size_t *);
205 1.1 tsutsui static int search_directory(const char *, int, struct open_file *, ino32_t *);
206 1.1 tsutsui static int read_sblock(struct open_file *, struct m_ext2fs *);
207 1.1 tsutsui static int read_gdblock(struct open_file *, struct m_ext2fs *);
208 1.1 tsutsui #ifdef EXT2FS_DEBUG
209 1.1 tsutsui static void dump_sblock(struct m_ext2fs *);
210 1.1 tsutsui #endif
211 1.1 tsutsui
212 1.1 tsutsui /*
213 1.1 tsutsui * Read a new inode into a file structure.
214 1.1 tsutsui */
215 1.1 tsutsui static int
216 1.1 tsutsui read_inode(ino32_t inumber, struct open_file *f)
217 1.1 tsutsui {
218 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata;
219 1.1 tsutsui struct m_ext2fs *fs = fp->f_fs;
220 1.1 tsutsui char *buf;
221 1.1 tsutsui size_t rsize;
222 1.1 tsutsui int rc;
223 1.1 tsutsui daddr_t inode_sector;
224 1.1 tsutsui struct ext2fs_dinode *dip;
225 1.1 tsutsui
226 1.1 tsutsui inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
227 1.1 tsutsui
228 1.1 tsutsui /*
229 1.1 tsutsui * Read inode and save it.
230 1.1 tsutsui */
231 1.1 tsutsui buf = fp->f_buf;
232 1.1 tsutsui twiddle();
233 1.1 tsutsui rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
234 1.1 tsutsui inode_sector, fs->e2fs_bsize, buf, &rsize);
235 1.1 tsutsui if (rc)
236 1.1 tsutsui return rc;
237 1.1 tsutsui if (rsize != fs->e2fs_bsize)
238 1.1 tsutsui return EIO;
239 1.1 tsutsui
240 1.7 tsutsui dip = (struct ext2fs_dinode *)(buf +
241 1.7 tsutsui EXT2_DINODE_SIZE(fs) * ino_to_fsbo(fs, inumber));
242 1.7 tsutsui e2fs_iload(dip, &fp->f_di);
243 1.1 tsutsui
244 1.1 tsutsui /*
245 1.1 tsutsui * Clear out the old buffers
246 1.1 tsutsui */
247 1.1 tsutsui fp->f_ind_cache_block = ~0;
248 1.1 tsutsui fp->f_buf_blkno = -1;
249 1.1 tsutsui return rc;
250 1.1 tsutsui }
251 1.1 tsutsui
252 1.1 tsutsui /*
253 1.1 tsutsui * Given an offset in a file, find the disk block number that
254 1.1 tsutsui * contains that block.
255 1.1 tsutsui */
256 1.1 tsutsui static int
257 1.1 tsutsui block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p)
258 1.1 tsutsui {
259 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata;
260 1.1 tsutsui struct m_ext2fs *fs = fp->f_fs;
261 1.1 tsutsui uint level;
262 1.1 tsutsui indp_t ind_cache;
263 1.1 tsutsui indp_t ind_block_num;
264 1.1 tsutsui size_t rsize;
265 1.1 tsutsui int rc;
266 1.1 tsutsui indp_t *buf = (void *)fp->f_buf;
267 1.1 tsutsui
268 1.1 tsutsui /*
269 1.1 tsutsui * Index structure of an inode:
270 1.1 tsutsui *
271 1.2 tsutsui * e2di_blocks[0..NDADDR-1]
272 1.2 tsutsui * hold block numbers for blocks
273 1.1 tsutsui * 0..NDADDR-1
274 1.1 tsutsui *
275 1.2 tsutsui * e2di_blocks[NDADDR+0]
276 1.2 tsutsui * block NDADDR+0 is the single indirect block
277 1.1 tsutsui * holds block numbers for blocks
278 1.1 tsutsui * NDADDR .. NDADDR + NINDIR(fs)-1
279 1.1 tsutsui *
280 1.2 tsutsui * e2di_blocks[NDADDR+1]
281 1.2 tsutsui * block NDADDR+1 is the double indirect block
282 1.1 tsutsui * holds block numbers for INDEX blocks for blocks
283 1.1 tsutsui * NDADDR + NINDIR(fs) ..
284 1.1 tsutsui * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
285 1.1 tsutsui *
286 1.2 tsutsui * e2di_blocks[NDADDR+2]
287 1.2 tsutsui * block NDADDR+2 is the triple indirect block
288 1.2 tsutsui * holds block numbers for double-indirect
289 1.1 tsutsui * blocks for blocks
290 1.1 tsutsui * NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
291 1.1 tsutsui * NDADDR + NINDIR(fs) + NINDIR(fs)**2
292 1.1 tsutsui * + NINDIR(fs)**3 - 1
293 1.1 tsutsui */
294 1.1 tsutsui
295 1.1 tsutsui if (file_block < NDADDR) {
296 1.1 tsutsui /* Direct block. */
297 1.1 tsutsui *disk_block_p = fs2h32(fp->f_di.e2di_blocks[file_block]);
298 1.1 tsutsui return 0;
299 1.1 tsutsui }
300 1.1 tsutsui
301 1.1 tsutsui file_block -= NDADDR;
302 1.1 tsutsui
303 1.1 tsutsui ind_cache = file_block >> LN2_IND_CACHE_SZ;
304 1.1 tsutsui if (ind_cache == fp->f_ind_cache_block) {
305 1.2 tsutsui *disk_block_p =
306 1.2 tsutsui fs2h32(fp->f_ind_cache[file_block & IND_CACHE_MASK]);
307 1.1 tsutsui return 0;
308 1.1 tsutsui }
309 1.1 tsutsui
310 1.1 tsutsui for (level = 0;;) {
311 1.1 tsutsui level += fp->f_nishift;
312 1.1 tsutsui if (file_block < (indp_t)1 << level)
313 1.1 tsutsui break;
314 1.1 tsutsui if (level > NIADDR * fp->f_nishift)
315 1.1 tsutsui /* Block number too high */
316 1.1 tsutsui return EFBIG;
317 1.1 tsutsui file_block -= (indp_t)1 << level;
318 1.1 tsutsui }
319 1.1 tsutsui
320 1.1 tsutsui ind_block_num =
321 1.1 tsutsui fs2h32(fp->f_di.e2di_blocks[NDADDR + (level / fp->f_nishift - 1)]);
322 1.1 tsutsui
323 1.1 tsutsui for (;;) {
324 1.1 tsutsui level -= fp->f_nishift;
325 1.1 tsutsui if (ind_block_num == 0) {
326 1.1 tsutsui *disk_block_p = 0; /* missing */
327 1.1 tsutsui return 0;
328 1.1 tsutsui }
329 1.1 tsutsui
330 1.1 tsutsui twiddle();
331 1.1 tsutsui /*
332 1.1 tsutsui * If we were feeling brave, we could work out the number
333 1.1 tsutsui * of the disk sector and read a single disk sector instead
334 1.1 tsutsui * of a filesystem block.
335 1.1 tsutsui * However we don't do this very often anyway...
336 1.1 tsutsui */
337 1.1 tsutsui rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
338 1.1 tsutsui FSBTODB(fp->f_fs, ind_block_num), fs->e2fs_bsize,
339 1.1 tsutsui buf, &rsize);
340 1.1 tsutsui if (rc)
341 1.1 tsutsui return rc;
342 1.1 tsutsui if (rsize != fs->e2fs_bsize)
343 1.1 tsutsui return EIO;
344 1.2 tsutsui ind_block_num = fs2h32(buf[file_block >> level]);
345 1.1 tsutsui if (level == 0)
346 1.1 tsutsui break;
347 1.1 tsutsui file_block &= (1 << level) - 1;
348 1.1 tsutsui }
349 1.1 tsutsui
350 1.1 tsutsui /* Save the part of the block that contains this sector */
351 1.1 tsutsui memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK],
352 1.1 tsutsui IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
353 1.1 tsutsui fp->f_ind_cache_block = ind_cache;
354 1.1 tsutsui
355 1.1 tsutsui *disk_block_p = ind_block_num;
356 1.1 tsutsui
357 1.1 tsutsui return 0;
358 1.1 tsutsui }
359 1.1 tsutsui
360 1.1 tsutsui /*
361 1.1 tsutsui * Read a portion of a file into an internal buffer.
362 1.1 tsutsui * Return the location in the buffer and the amount in the buffer.
363 1.1 tsutsui */
364 1.1 tsutsui static int
365 1.1 tsutsui buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
366 1.1 tsutsui {
367 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata;
368 1.1 tsutsui struct m_ext2fs *fs = fp->f_fs;
369 1.1 tsutsui long off;
370 1.1 tsutsui indp_t file_block;
371 1.1 tsutsui indp_t disk_block;
372 1.1 tsutsui size_t block_size;
373 1.1 tsutsui int rc;
374 1.1 tsutsui
375 1.1 tsutsui off = blkoff(fs, fp->f_seekp);
376 1.1 tsutsui file_block = lblkno(fs, fp->f_seekp);
377 1.1 tsutsui block_size = fs->e2fs_bsize; /* no fragment */
378 1.1 tsutsui
379 1.1 tsutsui if (file_block != fp->f_buf_blkno) {
380 1.1 tsutsui rc = block_map(f, file_block, &disk_block);
381 1.1 tsutsui if (rc)
382 1.1 tsutsui return rc;
383 1.1 tsutsui
384 1.1 tsutsui if (disk_block == 0) {
385 1.1 tsutsui memset(fp->f_buf, 0, block_size);
386 1.1 tsutsui fp->f_buf_size = block_size;
387 1.1 tsutsui } else {
388 1.1 tsutsui twiddle();
389 1.1 tsutsui rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
390 1.1 tsutsui FSBTODB(fs, disk_block),
391 1.1 tsutsui block_size, fp->f_buf, &fp->f_buf_size);
392 1.1 tsutsui if (rc)
393 1.1 tsutsui return rc;
394 1.1 tsutsui }
395 1.1 tsutsui
396 1.1 tsutsui fp->f_buf_blkno = file_block;
397 1.1 tsutsui }
398 1.1 tsutsui
399 1.1 tsutsui /*
400 1.1 tsutsui * Return address of byte in buffer corresponding to
401 1.1 tsutsui * offset, and size of remainder of buffer after that
402 1.1 tsutsui * byte.
403 1.1 tsutsui */
404 1.1 tsutsui *buf_p = fp->f_buf + off;
405 1.1 tsutsui *size_p = block_size - off;
406 1.1 tsutsui
407 1.1 tsutsui /*
408 1.1 tsutsui * But truncate buffer at end of file.
409 1.1 tsutsui */
410 1.1 tsutsui /* XXX should handle LARGEFILE */
411 1.1 tsutsui if (*size_p > fp->f_di.e2di_size - fp->f_seekp)
412 1.1 tsutsui *size_p = fp->f_di.e2di_size - fp->f_seekp;
413 1.1 tsutsui
414 1.1 tsutsui return 0;
415 1.1 tsutsui }
416 1.1 tsutsui
417 1.1 tsutsui /*
418 1.1 tsutsui * Search a directory for a name and return its
419 1.1 tsutsui * inode number.
420 1.1 tsutsui */
421 1.1 tsutsui static int
422 1.1 tsutsui search_directory(const char *name, int length, struct open_file *f,
423 1.1 tsutsui ino32_t *inumber_p)
424 1.1 tsutsui {
425 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata;
426 1.1 tsutsui struct ext2fs_direct *dp;
427 1.1 tsutsui struct ext2fs_direct *edp;
428 1.1 tsutsui char *buf;
429 1.1 tsutsui size_t buf_size;
430 1.1 tsutsui int namlen;
431 1.1 tsutsui int rc;
432 1.1 tsutsui
433 1.1 tsutsui fp->f_seekp = 0;
434 1.1 tsutsui /* XXX should handle LARGEFILE */
435 1.1 tsutsui while (fp->f_seekp < (off_t)fp->f_di.e2di_size) {
436 1.1 tsutsui rc = buf_read_file(f, &buf, &buf_size);
437 1.1 tsutsui if (rc)
438 1.1 tsutsui return rc;
439 1.1 tsutsui
440 1.1 tsutsui dp = (struct ext2fs_direct *)buf;
441 1.1 tsutsui edp = (struct ext2fs_direct *)(buf + buf_size);
442 1.1 tsutsui for (; dp < edp;
443 1.1 tsutsui dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) {
444 1.1 tsutsui if (fs2h16(dp->e2d_reclen) <= 0)
445 1.1 tsutsui break;
446 1.1 tsutsui if (fs2h32(dp->e2d_ino) == (ino32_t)0)
447 1.1 tsutsui continue;
448 1.1 tsutsui namlen = dp->e2d_namlen;
449 1.1 tsutsui if (namlen == length &&
450 1.1 tsutsui !memcmp(name, dp->e2d_name, length)) {
451 1.1 tsutsui /* found entry */
452 1.1 tsutsui *inumber_p = fs2h32(dp->e2d_ino);
453 1.1 tsutsui return 0;
454 1.1 tsutsui }
455 1.1 tsutsui }
456 1.1 tsutsui fp->f_seekp += buf_size;
457 1.1 tsutsui }
458 1.1 tsutsui return ENOENT;
459 1.1 tsutsui }
460 1.1 tsutsui
461 1.1 tsutsui int
462 1.1 tsutsui read_sblock(struct open_file *f, struct m_ext2fs *fs)
463 1.1 tsutsui {
464 1.1 tsutsui static uint8_t sbbuf[SBSIZE];
465 1.1 tsutsui struct ext2fs ext2fs;
466 1.1 tsutsui size_t buf_size;
467 1.1 tsutsui int rc;
468 1.1 tsutsui
469 1.1 tsutsui rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
470 1.1 tsutsui SBOFF / DEV_BSIZE, SBSIZE, sbbuf, &buf_size);
471 1.1 tsutsui if (rc)
472 1.1 tsutsui return rc;
473 1.1 tsutsui
474 1.1 tsutsui if (buf_size != SBSIZE)
475 1.1 tsutsui return EIO;
476 1.1 tsutsui
477 1.1 tsutsui e2fs_sbload((void *)sbbuf, &ext2fs);
478 1.1 tsutsui if (ext2fs.e2fs_magic != E2FS_MAGIC)
479 1.1 tsutsui return EINVAL;
480 1.1 tsutsui if (ext2fs.e2fs_rev > E2FS_REV1 ||
481 1.1 tsutsui (ext2fs.e2fs_rev == E2FS_REV1 &&
482 1.1 tsutsui (ext2fs.e2fs_first_ino != EXT2_FIRSTINO ||
483 1.6 christos (ext2fs.e2fs_inode_size != 128 && ext2fs.e2fs_inode_size != 256) ||
484 1.1 tsutsui ext2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP))) {
485 1.1 tsutsui return ENODEV;
486 1.1 tsutsui }
487 1.1 tsutsui
488 1.1 tsutsui e2fs_sbload((void *)sbbuf, &fs->e2fs);
489 1.1 tsutsui /* compute in-memory m_ext2fs values */
490 1.1 tsutsui fs->e2fs_ncg =
491 1.1 tsutsui howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
492 1.1 tsutsui fs->e2fs.e2fs_bpg);
493 1.1 tsutsui /* XXX assume hw bsize = 512 */
494 1.1 tsutsui fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1;
495 1.1 tsutsui fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize;
496 1.1 tsutsui fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize;
497 1.1 tsutsui fs->e2fs_qbmask = fs->e2fs_bsize - 1;
498 1.1 tsutsui fs->e2fs_bmask = ~fs->e2fs_qbmask;
499 1.1 tsutsui fs->e2fs_ngdb =
500 1.1 tsutsui howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd));
501 1.6 christos fs->e2fs_ipb = fs->e2fs_bsize / ext2fs.e2fs_inode_size;
502 1.1 tsutsui fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb;
503 1.1 tsutsui
504 1.1 tsutsui return 0;
505 1.1 tsutsui }
506 1.1 tsutsui
507 1.1 tsutsui int
508 1.1 tsutsui read_gdblock(struct open_file *f, struct m_ext2fs *fs)
509 1.1 tsutsui {
510 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata;
511 1.1 tsutsui size_t rsize;
512 1.1 tsutsui uint gdpb;
513 1.1 tsutsui int i, rc;
514 1.1 tsutsui
515 1.1 tsutsui gdpb = fs->e2fs_bsize / sizeof(struct ext2_gd);
516 1.1 tsutsui
517 1.1 tsutsui for (i = 0; i < fs->e2fs_ngdb; i++) {
518 1.1 tsutsui rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
519 1.1 tsutsui FSBTODB(fs, fs->e2fs.e2fs_first_dblock +
520 1.1 tsutsui 1 /* superblock */ + i),
521 1.1 tsutsui fs->e2fs_bsize, fp->f_buf, &rsize);
522 1.1 tsutsui if (rc)
523 1.1 tsutsui return rc;
524 1.1 tsutsui if (rsize != fs->e2fs_bsize)
525 1.1 tsutsui return EIO;
526 1.1 tsutsui
527 1.1 tsutsui e2fs_cgload((struct ext2_gd *)fp->f_buf,
528 1.1 tsutsui &fs->e2fs_gd[i * gdpb],
529 1.1 tsutsui (i == (fs->e2fs_ngdb - 1)) ?
530 1.1 tsutsui (fs->e2fs_ncg - gdpb * i) * sizeof(struct ext2_gd):
531 1.1 tsutsui fs->e2fs_bsize);
532 1.1 tsutsui }
533 1.1 tsutsui
534 1.1 tsutsui return 0;
535 1.1 tsutsui }
536 1.1 tsutsui
537 1.1 tsutsui
538 1.1 tsutsui /*
539 1.1 tsutsui * Open a file.
540 1.1 tsutsui */
541 1.10 joerg __compactcall int
542 1.1 tsutsui ext2fs_open(const char *path, struct open_file *f)
543 1.1 tsutsui {
544 1.1 tsutsui #ifndef LIBSA_FS_SINGLECOMPONENT
545 1.1 tsutsui const char *cp, *ncp;
546 1.1 tsutsui int c;
547 1.1 tsutsui #endif
548 1.1 tsutsui ino32_t inumber;
549 1.1 tsutsui struct file *fp;
550 1.1 tsutsui struct m_ext2fs *fs;
551 1.1 tsutsui int rc;
552 1.1 tsutsui #ifndef LIBSA_NO_FS_SYMLINK
553 1.1 tsutsui ino32_t parent_inumber;
554 1.1 tsutsui int nlinks = 0;
555 1.1 tsutsui char namebuf[MAXPATHLEN+1];
556 1.1 tsutsui char *buf;
557 1.1 tsutsui #endif
558 1.1 tsutsui
559 1.1 tsutsui /* allocate file system specific data structure */
560 1.1 tsutsui fp = alloc(sizeof(struct file));
561 1.1 tsutsui memset(fp, 0, sizeof(struct file));
562 1.1 tsutsui f->f_fsdata = (void *)fp;
563 1.1 tsutsui
564 1.1 tsutsui /* allocate space and read super block */
565 1.3 tsutsui fs = alloc(sizeof(*fs));
566 1.9 jakllsch memset(fs, 0, sizeof(*fs));
567 1.1 tsutsui fp->f_fs = fs;
568 1.1 tsutsui twiddle();
569 1.1 tsutsui
570 1.1 tsutsui rc = read_sblock(f, fs);
571 1.1 tsutsui if (rc)
572 1.1 tsutsui goto out;
573 1.1 tsutsui
574 1.1 tsutsui #ifdef EXT2FS_DEBUG
575 1.1 tsutsui dump_sblock(fs);
576 1.1 tsutsui #endif
577 1.1 tsutsui
578 1.1 tsutsui /* alloc a block sized buffer used for all fs transfers */
579 1.1 tsutsui fp->f_buf = alloc(fs->e2fs_bsize);
580 1.1 tsutsui
581 1.1 tsutsui /* read group descriptor blocks */
582 1.1 tsutsui fs->e2fs_gd = alloc(sizeof(struct ext2_gd) * fs->e2fs_ncg);
583 1.1 tsutsui rc = read_gdblock(f, fs);
584 1.1 tsutsui if (rc)
585 1.1 tsutsui goto out;
586 1.1 tsutsui
587 1.1 tsutsui /*
588 1.1 tsutsui * Calculate indirect block levels.
589 1.1 tsutsui */
590 1.1 tsutsui {
591 1.1 tsutsui indp_t mult;
592 1.1 tsutsui int ln2;
593 1.1 tsutsui
594 1.1 tsutsui /*
595 1.1 tsutsui * We note that the number of indirect blocks is always
596 1.1 tsutsui * a power of 2. This lets us use shifts and masks instead
597 1.1 tsutsui * of divide and remainder and avoinds pulling in the
598 1.1 tsutsui * 64bit division routine into the boot code.
599 1.1 tsutsui */
600 1.1 tsutsui mult = NINDIR(fs);
601 1.1 tsutsui #ifdef DEBUG
602 1.1 tsutsui if (!powerof2(mult)) {
603 1.1 tsutsui /* Hummm was't a power of 2 */
604 1.1 tsutsui rc = EINVAL;
605 1.1 tsutsui goto out;
606 1.1 tsutsui }
607 1.1 tsutsui #endif
608 1.1 tsutsui for (ln2 = 0; mult != 1; ln2++)
609 1.1 tsutsui mult >>= 1;
610 1.1 tsutsui
611 1.1 tsutsui fp->f_nishift = ln2;
612 1.1 tsutsui }
613 1.1 tsutsui
614 1.1 tsutsui inumber = EXT2_ROOTINO;
615 1.1 tsutsui if ((rc = read_inode(inumber, f)) != 0)
616 1.1 tsutsui goto out;
617 1.1 tsutsui
618 1.1 tsutsui #ifndef LIBSA_FS_SINGLECOMPONENT
619 1.1 tsutsui cp = path;
620 1.1 tsutsui while (*cp) {
621 1.1 tsutsui
622 1.1 tsutsui /*
623 1.1 tsutsui * Remove extra separators
624 1.1 tsutsui */
625 1.1 tsutsui while (*cp == '/')
626 1.1 tsutsui cp++;
627 1.1 tsutsui if (*cp == '\0')
628 1.1 tsutsui break;
629 1.1 tsutsui
630 1.1 tsutsui /*
631 1.1 tsutsui * Check that current node is a directory.
632 1.1 tsutsui */
633 1.1 tsutsui if ((fp->f_di.e2di_mode & EXT2_IFMT) != EXT2_IFDIR) {
634 1.1 tsutsui rc = ENOTDIR;
635 1.1 tsutsui goto out;
636 1.1 tsutsui }
637 1.1 tsutsui
638 1.1 tsutsui /*
639 1.1 tsutsui * Get next component of path name.
640 1.1 tsutsui */
641 1.1 tsutsui ncp = cp;
642 1.1 tsutsui while ((c = *cp) != '\0' && c != '/')
643 1.1 tsutsui cp++;
644 1.1 tsutsui
645 1.1 tsutsui /*
646 1.1 tsutsui * Look up component in current directory.
647 1.1 tsutsui * Save directory inumber in case we find a
648 1.1 tsutsui * symbolic link.
649 1.1 tsutsui */
650 1.1 tsutsui #ifndef LIBSA_NO_FS_SYMLINK
651 1.1 tsutsui parent_inumber = inumber;
652 1.1 tsutsui #endif
653 1.1 tsutsui rc = search_directory(ncp, cp - ncp, f, &inumber);
654 1.1 tsutsui if (rc)
655 1.1 tsutsui goto out;
656 1.1 tsutsui
657 1.1 tsutsui /*
658 1.1 tsutsui * Open next component.
659 1.1 tsutsui */
660 1.1 tsutsui if ((rc = read_inode(inumber, f)) != 0)
661 1.1 tsutsui goto out;
662 1.1 tsutsui
663 1.1 tsutsui #ifndef LIBSA_NO_FS_SYMLINK
664 1.1 tsutsui /*
665 1.1 tsutsui * Check for symbolic link.
666 1.1 tsutsui */
667 1.1 tsutsui if ((fp->f_di.e2di_mode & EXT2_IFMT) == EXT2_IFLNK) {
668 1.1 tsutsui /* XXX should handle LARGEFILE */
669 1.1 tsutsui int link_len = fp->f_di.e2di_size;
670 1.1 tsutsui int len;
671 1.1 tsutsui
672 1.1 tsutsui len = strlen(cp);
673 1.1 tsutsui
674 1.1 tsutsui if (link_len + len > MAXPATHLEN ||
675 1.1 tsutsui ++nlinks > MAXSYMLINKS) {
676 1.1 tsutsui rc = ENOENT;
677 1.1 tsutsui goto out;
678 1.1 tsutsui }
679 1.1 tsutsui
680 1.1 tsutsui memmove(&namebuf[link_len], cp, len + 1);
681 1.1 tsutsui
682 1.1 tsutsui if (link_len < EXT2_MAXSYMLINKLEN) {
683 1.1 tsutsui memcpy(namebuf, fp->f_di.e2di_blocks, link_len);
684 1.1 tsutsui } else {
685 1.1 tsutsui /*
686 1.1 tsutsui * Read file for symbolic link
687 1.1 tsutsui */
688 1.1 tsutsui size_t buf_size;
689 1.1 tsutsui indp_t disk_block;
690 1.1 tsutsui
691 1.1 tsutsui buf = fp->f_buf;
692 1.1 tsutsui rc = block_map(f, (indp_t)0, &disk_block);
693 1.1 tsutsui if (rc)
694 1.1 tsutsui goto out;
695 1.1 tsutsui
696 1.1 tsutsui twiddle();
697 1.1 tsutsui rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
698 1.1 tsutsui F_READ, FSBTODB(fs, disk_block),
699 1.1 tsutsui fs->e2fs_bsize, buf, &buf_size);
700 1.1 tsutsui if (rc)
701 1.1 tsutsui goto out;
702 1.1 tsutsui
703 1.1 tsutsui memcpy(namebuf, buf, link_len);
704 1.1 tsutsui }
705 1.1 tsutsui
706 1.1 tsutsui /*
707 1.1 tsutsui * If relative pathname, restart at parent directory.
708 1.1 tsutsui * If absolute pathname, restart at root.
709 1.1 tsutsui */
710 1.1 tsutsui cp = namebuf;
711 1.1 tsutsui if (*cp != '/')
712 1.1 tsutsui inumber = parent_inumber;
713 1.1 tsutsui else
714 1.1 tsutsui inumber = (ino32_t)EXT2_ROOTINO;
715 1.1 tsutsui
716 1.1 tsutsui if ((rc = read_inode(inumber, f)) != 0)
717 1.1 tsutsui goto out;
718 1.1 tsutsui }
719 1.1 tsutsui #endif /* !LIBSA_NO_FS_SYMLINK */
720 1.1 tsutsui }
721 1.1 tsutsui
722 1.1 tsutsui /*
723 1.1 tsutsui * Found terminal component.
724 1.1 tsutsui */
725 1.1 tsutsui rc = 0;
726 1.1 tsutsui
727 1.1 tsutsui #else /* !LIBSA_FS_SINGLECOMPONENT */
728 1.1 tsutsui
729 1.1 tsutsui /* look up component in the current (root) directory */
730 1.1 tsutsui rc = search_directory(path, strlen(path), f, &inumber);
731 1.1 tsutsui if (rc)
732 1.1 tsutsui goto out;
733 1.1 tsutsui
734 1.1 tsutsui /* open it */
735 1.1 tsutsui rc = read_inode(inumber, f);
736 1.1 tsutsui
737 1.1 tsutsui #endif /* !LIBSA_FS_SINGLECOMPONENT */
738 1.1 tsutsui
739 1.1 tsutsui fp->f_seekp = 0; /* reset seek pointer */
740 1.1 tsutsui
741 1.1 tsutsui out:
742 1.1 tsutsui if (rc)
743 1.1 tsutsui ext2fs_close(f);
744 1.5 ad else {
745 1.5 ad fsmod = "ext2fs";
746 1.5 ad fsmod2 = "ffs";
747 1.5 ad }
748 1.1 tsutsui return rc;
749 1.1 tsutsui }
750 1.1 tsutsui
751 1.10 joerg __compactcall int
752 1.1 tsutsui ext2fs_close(struct open_file *f)
753 1.1 tsutsui {
754 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata;
755 1.1 tsutsui
756 1.1 tsutsui f->f_fsdata = NULL;
757 1.1 tsutsui if (fp == NULL)
758 1.1 tsutsui return 0;
759 1.1 tsutsui
760 1.4 tsutsui if (fp->f_fs->e2fs_gd)
761 1.4 tsutsui dealloc(fp->f_fs->e2fs_gd,
762 1.4 tsutsui sizeof(struct ext2_gd) * fp->f_fs->e2fs_ncg);
763 1.1 tsutsui if (fp->f_buf)
764 1.1 tsutsui dealloc(fp->f_buf, fp->f_fs->e2fs_bsize);
765 1.4 tsutsui dealloc(fp->f_fs, sizeof(*fp->f_fs));
766 1.1 tsutsui dealloc(fp, sizeof(struct file));
767 1.1 tsutsui return 0;
768 1.1 tsutsui }
769 1.1 tsutsui
770 1.1 tsutsui /*
771 1.1 tsutsui * Copy a portion of a file into kernel memory.
772 1.1 tsutsui * Cross block boundaries when necessary.
773 1.1 tsutsui */
774 1.10 joerg __compactcall int
775 1.1 tsutsui ext2fs_read(struct open_file *f, void *start, size_t size, size_t *resid)
776 1.1 tsutsui {
777 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata;
778 1.1 tsutsui size_t csize;
779 1.1 tsutsui char *buf;
780 1.1 tsutsui size_t buf_size;
781 1.1 tsutsui int rc = 0;
782 1.1 tsutsui char *addr = start;
783 1.1 tsutsui
784 1.1 tsutsui while (size != 0) {
785 1.1 tsutsui /* XXX should handle LARGEFILE */
786 1.1 tsutsui if (fp->f_seekp >= (off_t)fp->f_di.e2di_size)
787 1.1 tsutsui break;
788 1.1 tsutsui
789 1.1 tsutsui rc = buf_read_file(f, &buf, &buf_size);
790 1.1 tsutsui if (rc)
791 1.1 tsutsui break;
792 1.1 tsutsui
793 1.1 tsutsui csize = size;
794 1.1 tsutsui if (csize > buf_size)
795 1.1 tsutsui csize = buf_size;
796 1.1 tsutsui
797 1.1 tsutsui memcpy(addr, buf, csize);
798 1.1 tsutsui
799 1.1 tsutsui fp->f_seekp += csize;
800 1.1 tsutsui addr += csize;
801 1.1 tsutsui size -= csize;
802 1.1 tsutsui }
803 1.1 tsutsui if (resid)
804 1.1 tsutsui *resid = size;
805 1.1 tsutsui return rc;
806 1.1 tsutsui }
807 1.1 tsutsui
808 1.1 tsutsui /*
809 1.1 tsutsui * Not implemented.
810 1.1 tsutsui */
811 1.1 tsutsui #ifndef LIBSA_NO_FS_WRITE
812 1.10 joerg __compactcall int
813 1.1 tsutsui ext2fs_write(struct open_file *f, void *start, size_t size, size_t *resid)
814 1.1 tsutsui {
815 1.1 tsutsui
816 1.1 tsutsui return EROFS;
817 1.1 tsutsui }
818 1.1 tsutsui #endif /* !LIBSA_NO_FS_WRITE */
819 1.1 tsutsui
820 1.1 tsutsui #ifndef LIBSA_NO_FS_SEEK
821 1.10 joerg __compactcall off_t
822 1.1 tsutsui ext2fs_seek(struct open_file *f, off_t offset, int where)
823 1.1 tsutsui {
824 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata;
825 1.1 tsutsui
826 1.1 tsutsui switch (where) {
827 1.1 tsutsui case SEEK_SET:
828 1.1 tsutsui fp->f_seekp = offset;
829 1.1 tsutsui break;
830 1.1 tsutsui case SEEK_CUR:
831 1.1 tsutsui fp->f_seekp += offset;
832 1.1 tsutsui break;
833 1.1 tsutsui case SEEK_END:
834 1.1 tsutsui /* XXX should handle LARGEFILE */
835 1.1 tsutsui fp->f_seekp = fp->f_di.e2di_size - offset;
836 1.1 tsutsui break;
837 1.1 tsutsui default:
838 1.1 tsutsui return -1;
839 1.1 tsutsui }
840 1.1 tsutsui return fp->f_seekp;
841 1.1 tsutsui }
842 1.1 tsutsui #endif /* !LIBSA_NO_FS_SEEK */
843 1.1 tsutsui
844 1.10 joerg __compactcall int
845 1.1 tsutsui ext2fs_stat(struct open_file *f, struct stat *sb)
846 1.1 tsutsui {
847 1.1 tsutsui struct file *fp = (struct file *)f->f_fsdata;
848 1.1 tsutsui
849 1.1 tsutsui /* only important stuff */
850 1.1 tsutsui memset(sb, 0, sizeof *sb);
851 1.1 tsutsui sb->st_mode = fp->f_di.e2di_mode;
852 1.1 tsutsui sb->st_uid = fp->f_di.e2di_uid;
853 1.1 tsutsui sb->st_gid = fp->f_di.e2di_gid;
854 1.1 tsutsui /* XXX should handle LARGEFILE */
855 1.1 tsutsui sb->st_size = fp->f_di.e2di_size;
856 1.1 tsutsui return 0;
857 1.1 tsutsui }
858 1.1 tsutsui
859 1.11 tsutsui #if defined(LIBSA_ENABLE_LS_OP)
860 1.11 tsutsui __compactcall void
861 1.11 tsutsui ext2fs_ls(struct open_file *f, const char *pattern)
862 1.11 tsutsui {
863 1.11 tsutsui struct file *fp = (struct file *)f->f_fsdata;
864 1.11 tsutsui size_t block_size = fp->f_fs->e2fs_bsize;
865 1.11 tsutsui char *buf;
866 1.11 tsutsui size_t buf_size;
867 1.11 tsutsui entry_t *names = 0, *n, **np;
868 1.11 tsutsui
869 1.11 tsutsui fp->f_seekp = 0;
870 1.11 tsutsui while (fp->f_seekp < (off_t)fp->f_di.e2di_size) {
871 1.11 tsutsui struct ext2fs_direct *dp, *edp;
872 1.11 tsutsui int rc = buf_read_file(f, &buf, &buf_size);
873 1.11 tsutsui if (rc)
874 1.11 tsutsui goto out;
875 1.11 tsutsui if (buf_size != block_size || buf_size == 0)
876 1.11 tsutsui goto out;
877 1.11 tsutsui
878 1.11 tsutsui dp = (struct ext2fs_direct *)buf;
879 1.11 tsutsui edp = (struct ext2fs_direct *)(buf + buf_size);
880 1.11 tsutsui
881 1.11 tsutsui for (; dp < edp;
882 1.11 tsutsui dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) {
883 1.11 tsutsui const char *t;
884 1.11 tsutsui
885 1.11 tsutsui if (fs2h16(dp->e2d_reclen) <= 0)
886 1.11 tsutsui goto out;
887 1.11 tsutsui
888 1.11 tsutsui if (fs2h32(dp->e2d_ino) == 0)
889 1.11 tsutsui continue;
890 1.11 tsutsui
891 1.11 tsutsui if (dp->e2d_type >= NELEM(typestr) ||
892 1.11 tsutsui !(t = typestr[dp->e2d_type])) {
893 1.11 tsutsui /*
894 1.11 tsutsui * This does not handle "old"
895 1.11 tsutsui * filesystems properly. On little
896 1.11 tsutsui * endian machines, we get a bogus
897 1.11 tsutsui * type name if the namlen matches a
898 1.11 tsutsui * valid type identifier. We could
899 1.11 tsutsui * check if we read namlen "0" and
900 1.11 tsutsui * handle this case specially, if
901 1.11 tsutsui * there were a pressing need...
902 1.11 tsutsui */
903 1.11 tsutsui printf("bad dir entry\n");
904 1.11 tsutsui goto out;
905 1.11 tsutsui }
906 1.11 tsutsui if (pattern && !fn_match(dp->e2d_name, pattern))
907 1.11 tsutsui continue;
908 1.11 tsutsui n = alloc(sizeof *n + strlen(dp->e2d_name));
909 1.11 tsutsui if (!n) {
910 1.11 tsutsui printf("%d: %s (%s)\n",
911 1.11 tsutsui fs2h32(dp->e2d_ino), dp->e2d_name, t);
912 1.11 tsutsui continue;
913 1.11 tsutsui }
914 1.11 tsutsui n->e_ino = fs2h32(dp->e2d_ino);
915 1.11 tsutsui n->e_type = dp->e2d_type;
916 1.11 tsutsui strcpy(n->e_name, dp->e2d_name);
917 1.11 tsutsui for (np = &names; *np; np = &(*np)->e_next) {
918 1.11 tsutsui if (strcmp(n->e_name, (*np)->e_name) < 0)
919 1.11 tsutsui break;
920 1.11 tsutsui }
921 1.11 tsutsui n->e_next = *np;
922 1.11 tsutsui *np = n;
923 1.11 tsutsui }
924 1.11 tsutsui fp->f_seekp += buf_size;
925 1.11 tsutsui }
926 1.11 tsutsui
927 1.11 tsutsui if (names) {
928 1.11 tsutsui entry_t *p_names = names;
929 1.11 tsutsui do {
930 1.11 tsutsui n = p_names;
931 1.11 tsutsui printf("%d: %s (%s)\n",
932 1.11 tsutsui n->e_ino, n->e_name, typestr[n->e_type]);
933 1.11 tsutsui p_names = n->e_next;
934 1.11 tsutsui } while (p_names);
935 1.11 tsutsui } else {
936 1.11 tsutsui printf("not found\n");
937 1.11 tsutsui }
938 1.11 tsutsui out:
939 1.11 tsutsui if (names) {
940 1.11 tsutsui do {
941 1.11 tsutsui n = names;
942 1.11 tsutsui names = n->e_next;
943 1.11 tsutsui dealloc(n, 0);
944 1.11 tsutsui } while (names);
945 1.11 tsutsui }
946 1.11 tsutsui return;
947 1.11 tsutsui }
948 1.11 tsutsui #endif
949 1.11 tsutsui
950 1.1 tsutsui /*
951 1.1 tsutsui * byte swap functions for big endian machines
952 1.1 tsutsui * (ext2fs is always little endian)
953 1.1 tsutsui *
954 1.1 tsutsui * XXX: We should use src/sys/ufs/ext2fs/ext2fs_bswap.c
955 1.1 tsutsui */
956 1.1 tsutsui
957 1.1 tsutsui /* These functions are only needed if native byte order is not big endian */
958 1.1 tsutsui #if BYTE_ORDER == BIG_ENDIAN
959 1.1 tsutsui void
960 1.1 tsutsui e2fs_sb_bswap(struct ext2fs *old, struct ext2fs *new)
961 1.1 tsutsui {
962 1.1 tsutsui
963 1.1 tsutsui /* preserve unused fields */
964 1.1 tsutsui memcpy(new, old, sizeof(struct ext2fs));
965 1.1 tsutsui new->e2fs_icount = bswap32(old->e2fs_icount);
966 1.1 tsutsui new->e2fs_bcount = bswap32(old->e2fs_bcount);
967 1.1 tsutsui new->e2fs_rbcount = bswap32(old->e2fs_rbcount);
968 1.1 tsutsui new->e2fs_fbcount = bswap32(old->e2fs_fbcount);
969 1.1 tsutsui new->e2fs_ficount = bswap32(old->e2fs_ficount);
970 1.1 tsutsui new->e2fs_first_dblock = bswap32(old->e2fs_first_dblock);
971 1.1 tsutsui new->e2fs_log_bsize = bswap32(old->e2fs_log_bsize);
972 1.1 tsutsui new->e2fs_fsize = bswap32(old->e2fs_fsize);
973 1.1 tsutsui new->e2fs_bpg = bswap32(old->e2fs_bpg);
974 1.1 tsutsui new->e2fs_fpg = bswap32(old->e2fs_fpg);
975 1.1 tsutsui new->e2fs_ipg = bswap32(old->e2fs_ipg);
976 1.1 tsutsui new->e2fs_mtime = bswap32(old->e2fs_mtime);
977 1.1 tsutsui new->e2fs_wtime = bswap32(old->e2fs_wtime);
978 1.1 tsutsui new->e2fs_mnt_count = bswap16(old->e2fs_mnt_count);
979 1.1 tsutsui new->e2fs_max_mnt_count = bswap16(old->e2fs_max_mnt_count);
980 1.1 tsutsui new->e2fs_magic = bswap16(old->e2fs_magic);
981 1.1 tsutsui new->e2fs_state = bswap16(old->e2fs_state);
982 1.1 tsutsui new->e2fs_beh = bswap16(old->e2fs_beh);
983 1.1 tsutsui new->e2fs_minrev = bswap16(old->e2fs_minrev);
984 1.1 tsutsui new->e2fs_lastfsck = bswap32(old->e2fs_lastfsck);
985 1.1 tsutsui new->e2fs_fsckintv = bswap32(old->e2fs_fsckintv);
986 1.1 tsutsui new->e2fs_creator = bswap32(old->e2fs_creator);
987 1.1 tsutsui new->e2fs_rev = bswap32(old->e2fs_rev);
988 1.1 tsutsui new->e2fs_ruid = bswap16(old->e2fs_ruid);
989 1.1 tsutsui new->e2fs_rgid = bswap16(old->e2fs_rgid);
990 1.1 tsutsui new->e2fs_first_ino = bswap32(old->e2fs_first_ino);
991 1.1 tsutsui new->e2fs_inode_size = bswap16(old->e2fs_inode_size);
992 1.1 tsutsui new->e2fs_block_group_nr = bswap16(old->e2fs_block_group_nr);
993 1.1 tsutsui new->e2fs_features_compat = bswap32(old->e2fs_features_compat);
994 1.1 tsutsui new->e2fs_features_incompat = bswap32(old->e2fs_features_incompat);
995 1.1 tsutsui new->e2fs_features_rocompat = bswap32(old->e2fs_features_rocompat);
996 1.1 tsutsui new->e2fs_algo = bswap32(old->e2fs_algo);
997 1.1 tsutsui new->e2fs_reserved_ngdb = bswap16(old->e2fs_reserved_ngdb);
998 1.1 tsutsui }
999 1.1 tsutsui
1000 1.1 tsutsui void e2fs_cg_bswap(struct ext2_gd *old, struct ext2_gd *new, int size)
1001 1.1 tsutsui {
1002 1.1 tsutsui int i;
1003 1.1 tsutsui
1004 1.1 tsutsui for (i = 0; i < (size / sizeof(struct ext2_gd)); i++) {
1005 1.1 tsutsui new[i].ext2bgd_b_bitmap = bswap32(old[i].ext2bgd_b_bitmap);
1006 1.1 tsutsui new[i].ext2bgd_i_bitmap = bswap32(old[i].ext2bgd_i_bitmap);
1007 1.1 tsutsui new[i].ext2bgd_i_tables = bswap32(old[i].ext2bgd_i_tables);
1008 1.1 tsutsui new[i].ext2bgd_nbfree = bswap16(old[i].ext2bgd_nbfree);
1009 1.1 tsutsui new[i].ext2bgd_nifree = bswap16(old[i].ext2bgd_nifree);
1010 1.1 tsutsui new[i].ext2bgd_ndirs = bswap16(old[i].ext2bgd_ndirs);
1011 1.1 tsutsui }
1012 1.1 tsutsui }
1013 1.1 tsutsui
1014 1.1 tsutsui void e2fs_i_bswap(struct ext2fs_dinode *old, struct ext2fs_dinode *new)
1015 1.1 tsutsui {
1016 1.1 tsutsui
1017 1.1 tsutsui new->e2di_mode = bswap16(old->e2di_mode);
1018 1.1 tsutsui new->e2di_uid = bswap16(old->e2di_uid);
1019 1.1 tsutsui new->e2di_gid = bswap16(old->e2di_gid);
1020 1.1 tsutsui new->e2di_nlink = bswap16(old->e2di_nlink);
1021 1.1 tsutsui new->e2di_size = bswap32(old->e2di_size);
1022 1.1 tsutsui new->e2di_atime = bswap32(old->e2di_atime);
1023 1.1 tsutsui new->e2di_ctime = bswap32(old->e2di_ctime);
1024 1.1 tsutsui new->e2di_mtime = bswap32(old->e2di_mtime);
1025 1.1 tsutsui new->e2di_dtime = bswap32(old->e2di_dtime);
1026 1.1 tsutsui new->e2di_nblock = bswap32(old->e2di_nblock);
1027 1.1 tsutsui new->e2di_flags = bswap32(old->e2di_flags);
1028 1.1 tsutsui new->e2di_gen = bswap32(old->e2di_gen);
1029 1.1 tsutsui new->e2di_facl = bswap32(old->e2di_facl);
1030 1.1 tsutsui new->e2di_dacl = bswap32(old->e2di_dacl);
1031 1.1 tsutsui new->e2di_faddr = bswap32(old->e2di_faddr);
1032 1.1 tsutsui memcpy(&new->e2di_blocks[0], &old->e2di_blocks[0],
1033 1.1 tsutsui (NDADDR + NIADDR) * sizeof(uint32_t));
1034 1.1 tsutsui }
1035 1.1 tsutsui #endif
1036 1.1 tsutsui
1037 1.1 tsutsui #ifdef EXT2FS_DEBUG
1038 1.1 tsutsui void
1039 1.1 tsutsui dump_sblock(struct m_ext2fs *fs)
1040 1.1 tsutsui {
1041 1.1 tsutsui
1042 1.1 tsutsui printf("fs->e2fs.e2fs_bcount = %u\n", fs->e2fs.e2fs_bcount);
1043 1.1 tsutsui printf("fs->e2fs.e2fs_first_dblock = %u\n", fs->e2fs.e2fs_first_dblock);
1044 1.1 tsutsui printf("fs->e2fs.e2fs_log_bsize = %u\n", fs->e2fs.e2fs_log_bsize);
1045 1.1 tsutsui printf("fs->e2fs.e2fs_bpg = %u\n", fs->e2fs.e2fs_bpg);
1046 1.1 tsutsui printf("fs->e2fs.e2fs_ipg = %u\n", fs->e2fs.e2fs_ipg);
1047 1.1 tsutsui printf("fs->e2fs.e2fs_magic = 0x%x\n", fs->e2fs.e2fs_magic);
1048 1.1 tsutsui printf("fs->e2fs.e2fs_rev = %u\n", fs->e2fs.e2fs_rev);
1049 1.1 tsutsui
1050 1.1 tsutsui if (fs->e2fs.e2fs_rev == E2FS_REV1) {
1051 1.1 tsutsui printf("fs->e2fs.e2fs_first_ino = %u\n",
1052 1.1 tsutsui fs->e2fs.e2fs_first_ino);
1053 1.1 tsutsui printf("fs->e2fs.e2fs_inode_size = %u\n",
1054 1.1 tsutsui fs->e2fs.e2fs_inode_size);
1055 1.1 tsutsui printf("fs->e2fs.e2fs_features_compat = %u\n",
1056 1.1 tsutsui fs->e2fs.e2fs_features_compat);
1057 1.1 tsutsui printf("fs->e2fs.e2fs_features_incompat = %u\n",
1058 1.1 tsutsui fs->e2fs.e2fs_features_incompat);
1059 1.1 tsutsui printf("fs->e2fs.e2fs_features_rocompat = %u\n",
1060 1.1 tsutsui fs->e2fs.e2fs_features_rocompat);
1061 1.1 tsutsui printf("fs->e2fs.e2fs_reserved_ngdb = %u\n",
1062 1.1 tsutsui fs->e2fs.e2fs_reserved_ngdb);
1063 1.1 tsutsui }
1064 1.1 tsutsui
1065 1.1 tsutsui printf("fs->e2fs_bsize = %u\n", fs->e2fs_bsize);
1066 1.1 tsutsui printf("fs->e2fs_fsbtodb = %u\n", fs->e2fs_fsbtodb);
1067 1.1 tsutsui printf("fs->e2fs_ncg = %u\n", fs->e2fs_ncg);
1068 1.1 tsutsui printf("fs->e2fs_ngdb = %u\n", fs->e2fs_ngdb);
1069 1.1 tsutsui printf("fs->e2fs_ipb = %u\n", fs->e2fs_ipb);
1070 1.1 tsutsui printf("fs->e2fs_itpg = %u\n", fs->e2fs_itpg);
1071 1.1 tsutsui }
1072 1.1 tsutsui #endif
1073