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