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