ufs.c revision 1.87 1 /* $NetBSD: ufs.c,v 1.87 2022/11/17 06:40:40 chs 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 UFS_NINDIR
160 #define UFS_NINDIR FFS_NINDIR
161 #endif
162 #ifndef ufs_blkoff
163 #define ufs_blkoff ffs_blkoff
164 #endif
165 #ifndef ufs_lblkno
166 #define ufs_lblkno ffs_lblkno
167 #endif
168 #ifndef ufs_dinode_swap
169 #define ufs_dinode_swap ffs_dinode1_swap
170 #endif
171 #ifndef ufs_indp_swap
172 #define ufs_indp_swap bswap32
173 #endif
174
175 /*
176 * To avoid having a lot of filesystem-block sized buffers lurking (which
177 * could be 32k) we only keep a few entries of the indirect block map.
178 * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
179 * ~13 times pulling in a 6M kernel.
180 * The cache size must be smaller than the smallest filesystem block,
181 * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
182 */
183 #define LN2_IND_CACHE_SZ 6
184 #define IND_CACHE_SZ (1 << LN2_IND_CACHE_SZ)
185 #define IND_CACHE_MASK (IND_CACHE_SZ - 1)
186
187 /*
188 * In-core open file.
189 */
190 struct file {
191 off_t f_seekp; /* seek pointer */
192 FS *f_fs; /* pointer to super-block */
193 struct ufs_dinode f_di; /* copy of on-disk inode */
194 uint f_nishift; /* for blocks in indirect block */
195 indp_t f_ind_cache_block;
196 indp_t f_ind_cache[IND_CACHE_SZ];
197
198 char *f_buf; /* buffer for data block */
199 size_t f_buf_size; /* size of data block */
200 daddr_t f_buf_blkno; /* block number of data block */
201 #if defined(LIBSA_FFS_EI)
202 bool f_swapped; /* FFS is other endian */
203 #endif
204 };
205
206 static int read_inode(ino32_t, struct open_file *);
207 static int block_map(struct open_file *, indp_t, indp_t *);
208 static int buf_read_file(struct open_file *, char **, size_t *);
209 static int search_directory(const char *, int, struct open_file *, ino32_t *);
210 #ifdef LIBSA_FFSv1
211 static void ffs_oldfscompat(FS *);
212 #endif
213
214 #ifdef LIBSA_FFSv1
215 static __inline__ bool
216 ffs_is_magic(FS *fs)
217 {
218 return fs->fs_magic == FS_UFS1_MAGIC;
219 }
220
221 static __inline__ bool
222 ffs_is_magic_swapped(FS *fs)
223 {
224 return fs->fs_magic == bswap32(FS_UFS1_MAGIC);
225 }
226 #endif
227
228 #ifdef LIBSA_FFSv2
229 static __inline__ bool
230 ffs_is_magic(FS *fs)
231 {
232 return fs->fs_magic == FS_UFS2_MAGIC || fs->fs_magic == FS_UFS2EA_MAGIC;
233 }
234
235 static __inline__ bool
236 ffs_is_magic_swapped(FS *fs)
237 {
238 return fs->fs_magic == bswap32(FS_UFS2_MAGIC) ||
239 fs->fs_magic == bswap32(FS_UFS2EA_MAGIC);
240 }
241 #endif
242
243 #ifdef LIBSA_LFS
244 static __inline__ bool
245 ffs_is_magic(FS *fs)
246 {
247 return fs->fs_magic == LFS_MAGIC;
248 }
249
250 static __inline__ bool
251 ffs_is_magic_swapped(FS *fs)
252 {
253 return fs->fs_magic == bswap32(LFS_MAGIC);
254 }
255 #endif
256
257 static __inline__ void
258 ffs_fix_magic_swapped(struct file *fp, FS *fs)
259 {
260 #ifdef LIBSA_FFS_EI
261 fp->f_swapped = ffs_is_magic_swapped(fs);
262 if (fp->f_swapped)
263 {
264 ffs_sb_swap(fs, fs);
265 }
266 #endif
267 }
268
269 #ifdef LIBSA_FFS_EI
270 static __inline__ bool
271 ffs_swapped(struct file *fp)
272 {
273 return fp->f_swapped;
274 }
275 #endif
276
277 static __inline__ uint16_t
278 ffs_get_reclen(struct file *fp, struct direct *dp)
279 {
280 #ifdef LIBSA_FFS_EI
281 if (ffs_swapped(fp))
282 return bswap16(dp->d_reclen);
283 #endif
284 return dp->d_reclen;
285 }
286
287 static __inline__ uint32_t
288 ffs_get_ino(struct file *fp, struct direct *dp)
289 {
290 #ifdef LIBSA_FFS_EI
291 if (ffs_swapped(fp))
292 return bswap32(dp->d_ino);
293 #endif
294 return dp->d_ino;
295 }
296
297
298 #ifdef LIBSA_LFS
299 /*
300 * Find an inode's block. Look it up in the ifile. Whee!
301 */
302 static int
303 find_inode_sector(ino32_t inumber, struct open_file *f, daddr_t *isp)
304 {
305 struct file *fp = (struct file *)f->f_fsdata;
306 FS *fs = fp->f_fs;
307 daddr_t ifileent_blkno;
308 char *ent_in_buf;
309 size_t buf_after_ent;
310 size_t entsize;
311 int rc;
312
313 rc = read_inode(LFS_IFILE_INUM, f);
314 if (rc)
315 return rc;
316
317 entsize = fs->lfs_is64 ? sizeof(IFILE64) :
318 (lfs_sb_getversion(fs) > 1 ? sizeof(IFILE32) : sizeof(IFILE_V1));
319 ifileent_blkno =
320 (inumber / lfs_sb_getifpb(fs)) + lfs_sb_getcleansz(fs) + lfs_sb_getsegtabsz(fs);
321 fp->f_seekp = (off_t)ifileent_blkno * lfs_sb_getbsize(fs) +
322 (inumber % lfs_sb_getifpb(fs)) * entsize;
323 rc = buf_read_file(f, &ent_in_buf, &buf_after_ent);
324 if (rc)
325 return rc;
326 /* make sure something's not badly wrong, but don't panic. */
327 if (buf_after_ent < entsize)
328 return EINVAL;
329
330 *isp = FSBTODB(fs, lfs_if_getdaddr(fs, (IFILE *)ent_in_buf));
331 if (*isp == LFS_UNUSED_DADDR) /* again, something badly wrong */
332 return EINVAL;
333 return 0;
334 }
335 #endif
336
337 /*
338 * Read a new inode into a file structure.
339 */
340 static int
341 read_inode(ino32_t inumber, struct open_file *f)
342 {
343 struct file *fp = (struct file *)f->f_fsdata;
344 FS *fs = fp->f_fs;
345 char *buf;
346 size_t rsize;
347 int rc;
348 daddr_t inode_sector = 0; /* XXX: gcc */
349 #ifdef LIBSA_LFS
350 struct ufs_dinode *dip;
351 int cnt;
352 #endif
353
354 #ifdef LIBSA_LFS
355 if (inumber == LFS_IFILE_INUM)
356 inode_sector = FSBTODB(fs, lfs_sb_getidaddr(fs));
357 else if ((rc = find_inode_sector(inumber, f, &inode_sector)) != 0)
358 return rc;
359 #else
360 inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
361 #endif
362
363 /*
364 * Read inode and save it.
365 */
366 buf = fp->f_buf;
367 twiddle();
368 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
369 inode_sector, fs->fs_bsize, buf, &rsize);
370 if (rc)
371 return rc;
372 if (rsize != (size_t)fs->fs_bsize)
373 return EIO;
374
375 #ifdef LIBSA_LFS
376 cnt = INOPBx(fs);
377 dip = (struct ufs_dinode *)buf + (cnt - 1);
378 for (; dip->di_inumber != inumber; --dip) {
379 /* kernel code panics, but boot blocks which panic are Bad. */
380 if (--cnt == 0)
381 return EINVAL;
382 }
383 fp->f_di = *dip;
384 #else
385 fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)];
386 #ifdef LIBSA_FFS_EI
387 if (ffs_swapped(fp))
388 ufs_dinode_swap(&fp->f_di, &fp->f_di);
389 #endif
390 #endif
391
392 /*
393 * Clear out the old buffers
394 */
395 fp->f_ind_cache_block = ~0;
396 fp->f_buf_blkno = -1;
397 return rc;
398 }
399
400 /*
401 * Given an offset in a file, find the disk block number that
402 * contains that block.
403 */
404 static int
405 block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p)
406 {
407 struct file *fp = (struct file *)f->f_fsdata;
408 FS *fs = fp->f_fs;
409 uint level;
410 indp_t ind_cache;
411 indp_t ind_block_num;
412 size_t rsize;
413 int rc;
414 indp_t *buf = (void *)fp->f_buf;
415
416 /*
417 * Index structure of an inode:
418 *
419 * di_db[0..UFS_NDADDR-1] hold block numbers for blocks
420 * 0..UFS_NDADDR-1
421 *
422 * di_ib[0] index block 0 is the single indirect block
423 * holds block numbers for blocks
424 * UFS_NDADDR .. UFS_NDADDR + UFS_NINDIR(fs)-1
425 *
426 * di_ib[1] index block 1 is the double indirect block
427 * holds block numbers for INDEX blocks for blocks
428 * UFS_NDADDR + UFS_NINDIR(fs) ..
429 * UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 - 1
430 *
431 * di_ib[2] index block 2 is the triple indirect block
432 * holds block numbers for double-indirect
433 * blocks for blocks
434 * UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 ..
435 * UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2
436 * + UFS_NINDIR(fs)**3 - 1
437 */
438
439 if (file_block < UFS_NDADDR) {
440 /* Direct block. */
441 *disk_block_p = fp->f_di.di_db[file_block];
442 return 0;
443 }
444
445 file_block -= UFS_NDADDR;
446
447 ind_cache = file_block >> LN2_IND_CACHE_SZ;
448 if (ind_cache == fp->f_ind_cache_block) {
449 *disk_block_p = fp->f_ind_cache[file_block & IND_CACHE_MASK];
450 return 0;
451 }
452
453 for (level = 0;;) {
454 level += fp->f_nishift;
455 if (file_block < (indp_t)1 << level)
456 break;
457 if (level > UFS_NIADDR * fp->f_nishift)
458 /* Block number too high */
459 return EFBIG;
460 file_block -= (indp_t)1 << level;
461 }
462
463 ind_block_num = fp->f_di.di_ib[level / fp->f_nishift - 1];
464
465 for (;;) {
466 level -= fp->f_nishift;
467 if (ind_block_num == 0) {
468 *disk_block_p = 0; /* missing */
469 return 0;
470 }
471
472 twiddle();
473 /*
474 * If we were feeling brave, we could work out the number
475 * of the disk sector and read a single disk sector instead
476 * of a filesystem block.
477 * However we don't do this very often anyway...
478 */
479 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
480 FSBTODB(fp->f_fs, ind_block_num), fs->fs_bsize,
481 buf, &rsize);
482 if (rc)
483 return rc;
484 if (rsize != (size_t)fs->fs_bsize)
485 return EIO;
486 #ifdef LIBSA_FFS_EI
487 if (ffs_swapped(fp))
488 ind_block_num = ufs_indp_swap(buf[file_block >> level]);
489 else
490 #endif
491 ind_block_num = buf[file_block >> level];
492 if (level == 0)
493 break;
494 file_block &= (1 << level) - 1;
495 }
496
497 /* Save the part of the block that contains this sector */
498 #if defined(LIBSA_FFS_EI)
499 if (ffs_swapped(fp)) {
500 size_t i;
501
502 for (i = 0; i < IND_CACHE_SZ; i++) {
503 fp->f_ind_cache[i] = ufs_indp_swap(
504 buf[(file_block & ~IND_CACHE_MASK) + i]);
505 }
506 } else
507 #endif
508 memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK],
509 IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
510 fp->f_ind_cache_block = ind_cache;
511
512 *disk_block_p = ind_block_num;
513
514 return 0;
515 }
516
517 /*
518 * Read a portion of a file into an internal buffer.
519 * Return the location in the buffer and the amount in the buffer.
520 */
521 static int
522 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
523 {
524 struct file *fp = (struct file *)f->f_fsdata;
525 FS *fs = fp->f_fs;
526 long off;
527 indp_t file_block;
528 size_t block_size;
529 int rc;
530
531 off = ufs_blkoff(fs, fp->f_seekp);
532 file_block = ufs_lblkno(fs, fp->f_seekp);
533 #ifdef LIBSA_LFS
534 block_size = (size_t)dblksize(fs, &fp->f_di, (uint64_t)file_block);
535 #else
536 block_size = (size_t)ffs_sblksize(fs, (int64_t)fp->f_di.di_size, file_block);
537 #endif
538
539 if (file_block != fp->f_buf_blkno) {
540 indp_t disk_block = 0; /* XXX: gcc */
541 rc = block_map(f, file_block, &disk_block);
542 if (rc)
543 return rc;
544
545 if (disk_block == 0) {
546 memset(fp->f_buf, 0, block_size);
547 fp->f_buf_size = block_size;
548 } else {
549 twiddle();
550 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
551 FSBTODB(fs, disk_block),
552 block_size, fp->f_buf, &fp->f_buf_size);
553 if (rc)
554 return rc;
555 }
556
557 fp->f_buf_blkno = file_block;
558 }
559
560 /*
561 * Return address of byte in buffer corresponding to
562 * offset, and size of remainder of buffer after that
563 * byte.
564 */
565 *buf_p = fp->f_buf + off;
566 *size_p = block_size - off;
567
568 /*
569 * But truncate buffer at end of file.
570 */
571 if (*size_p > fp->f_di.di_size - fp->f_seekp)
572 *size_p = fp->f_di.di_size - fp->f_seekp;
573
574 return 0;
575 }
576
577 /*
578 * Search a directory for a name and return its
579 * inode number.
580 */
581 static int
582 search_directory(const char *name, int length, struct open_file *f,
583 ino32_t *inumber_p)
584 {
585 struct file *fp = (struct file *)f->f_fsdata;
586 struct direct *dp;
587 struct direct *edp;
588 char *buf;
589 size_t buf_size;
590 int namlen;
591 int rc;
592
593 fp->f_seekp = 0;
594 while (fp->f_seekp < (off_t)fp->f_di.di_size) {
595 rc = buf_read_file(f, &buf, &buf_size);
596 if (rc)
597 return rc;
598
599 dp = (struct direct *)buf;
600 edp = (struct direct *)(buf + buf_size);
601 for (; dp < edp;
602 dp = (void *)((char *)dp + ffs_get_reclen(fp, dp))) {
603 if (ffs_get_reclen(fp, dp) <= 0)
604 break;
605 if (ffs_get_ino(fp, dp) == (ino32_t)0)
606 continue;
607 #if BYTE_ORDER == LITTLE_ENDIAN
608 if (fp->f_fs->fs_maxsymlinklen <= 0)
609 namlen = dp->d_type;
610 else
611 #endif
612 namlen = dp->d_namlen;
613 if (namlen == length &&
614 !memcmp(name, dp->d_name, length)) {
615 /* found entry */
616 *inumber_p = ffs_get_ino(fp, dp);
617 return 0;
618 }
619 }
620 fp->f_seekp += buf_size;
621 }
622 return ENOENT;
623 }
624
625 static __inline__ int
626 ffs_find_superblock(struct open_file *f, FS *fs)
627 {
628 struct file *fp = (struct file *)f->f_fsdata;
629 int rc;
630 size_t buf_size;
631 #ifdef LIBSA_FFSv2
632 static daddr_t sblock_try[] = SBLOCKSEARCH;
633 int i;
634 #endif
635
636 #ifdef LIBSA_FFSv2
637 for (i = 0; sblock_try[i] != -1; i++) {
638 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
639 sblock_try[i] / GETSECSIZE(f), SBLOCKSIZE, fs, &buf_size);
640 if (rc)
641 return rc;
642 if (buf_size != SBLOCKSIZE)
643 return EINVAL;
644 ffs_fix_magic_swapped(fp, fs);
645 if (fs->fs_sblockloc != sblock_try[i])
646 /* an alternate superblock - try again */
647 continue;
648 if (ffs_is_magic(fs))
649 return 0;
650 }
651 return EINVAL;
652 #else /* LIBSA_FFSv2 */
653 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
654 SBLOCKOFFSET / GETSECSIZE(f), SBLOCKSIZE, fs, &buf_size);
655 if (rc)
656 return rc;
657 if (buf_size != SBLOCKSIZE)
658 return EINVAL;
659 ffs_fix_magic_swapped(fp, fs);
660
661 #ifdef LIBSA_LFS
662 if (fs->lfs_version != REQUIRED_LFS_VERSION)
663 return EINVAL;
664 #endif
665 if (!ffs_is_magic(fs))
666 return EINVAL;
667
668 return 0;
669 #endif /* !LIBSA_FFSv2 */
670 }
671
672 /*
673 * Open a file.
674 */
675 __compactcall int
676 ufs_open(const char *path, struct open_file *f)
677 {
678 #ifndef LIBSA_FS_SINGLECOMPONENT
679 const char *cp, *ncp;
680 int c;
681 #endif
682 ino32_t inumber;
683 struct file *fp;
684 FS *fs;
685 int rc;
686 #ifndef LIBSA_NO_FS_SYMLINK
687 ino32_t parent_inumber;
688 int nlinks = 0;
689 char namebuf[MAXPATHLEN+1];
690 char *buf;
691 #endif
692
693 /* allocate file system specific data structure */
694 fp = alloc(sizeof(struct file));
695 memset(fp, 0, sizeof(struct file));
696 f->f_fsdata = (void *)fp;
697
698 /* allocate space and read super block */
699 fs = alloc(SBLOCKSIZE);
700 fp->f_fs = fs;
701 twiddle();
702
703 rc = ffs_find_superblock(f, fs);
704 if (rc)
705 goto out;
706
707 #if defined(LIBSA_LFS) && REQUIRED_LFS_VERSION == 2
708 /*
709 * XXX We should check the second superblock and use the eldest
710 * of the two. See comments near the top of lfs_mountfs()
711 * in sys/ufs/lfs/lfs_vfsops.c.
712 * This may need a LIBSA_LFS_SMALL check as well.
713 */
714 #endif
715 #if defined(LIBSA_LFS)
716 fs->lfs_is64 = 0;
717 fs->lfs_dobyteswap = 0;
718 fs->lfs_hasolddirfmt = (fs->fs_maxsymlinklen <= 0);
719 #endif
720 #ifdef LIBSA_FFSv1
721 ffs_oldfscompat(fs);
722 #endif
723
724 if (fs->fs_bsize > MAXBSIZE ||
725 (size_t)fs->fs_bsize < sizeof(FS)) {
726 rc = EINVAL;
727 goto out;
728 }
729
730 /*
731 * Calculate indirect block levels.
732 */
733 {
734 indp_t mult;
735 int ln2;
736
737 /*
738 * We note that the number of indirect blocks is always
739 * a power of 2. This lets us use shifts and masks instead
740 * of divide and remainder and avoids pulling in the
741 * 64bit division routine into the boot code.
742 */
743 mult = UFS_NINDIR(fs);
744 #ifdef DEBUG
745 if (mult & (mult - 1)) {
746 /* Hummm was't a power of 2 */
747 rc = EINVAL;
748 goto out;
749 }
750 #endif
751 for (ln2 = 0; mult != 1; ln2++)
752 mult >>= 1;
753
754 fp->f_nishift = ln2;
755 }
756
757 /* alloc a block sized buffer used for all fs transfers */
758 fp->f_buf = alloc(fs->fs_bsize);
759 inumber = UFS_ROOTINO;
760 if ((rc = read_inode(inumber, f)) != 0)
761 goto out;
762
763 #ifndef LIBSA_FS_SINGLECOMPONENT
764 cp = path;
765 while (*cp) {
766
767 /*
768 * Remove extra separators
769 */
770 while (*cp == '/')
771 cp++;
772 if (*cp == '\0')
773 break;
774
775 /*
776 * Check that current node is a directory.
777 */
778 if ((fp->f_di.di_mode & IFMT) != IFDIR) {
779 rc = ENOTDIR;
780 goto out;
781 }
782
783 /*
784 * Get next component of path name.
785 */
786 ncp = cp;
787 while ((c = *cp) != '\0' && c != '/')
788 cp++;
789
790 /*
791 * Look up component in current directory.
792 * Save directory inumber in case we find a
793 * symbolic link.
794 */
795 #ifndef LIBSA_NO_FS_SYMLINK
796 parent_inumber = inumber;
797 #endif
798 rc = search_directory(ncp, cp - ncp, f, &inumber);
799 if (rc)
800 goto out;
801
802 /*
803 * Open next component.
804 */
805 if ((rc = read_inode(inumber, f)) != 0)
806 goto out;
807
808 #ifndef LIBSA_NO_FS_SYMLINK
809 /*
810 * Check for symbolic link.
811 */
812 if ((fp->f_di.di_mode & IFMT) == IFLNK) {
813 int link_len = fp->f_di.di_size;
814 int len;
815
816 len = strlen(cp);
817
818 if (link_len + len > MAXPATHLEN ||
819 ++nlinks > MAXSYMLINKS) {
820 rc = ENOENT;
821 goto out;
822 }
823
824 memmove(&namebuf[link_len], cp, len + 1);
825
826 if (link_len < fs->fs_maxsymlinklen) {
827 memcpy(namebuf, fp->f_di.di_db, link_len);
828 } else {
829 /*
830 * Read file for symbolic link
831 */
832 size_t buf_size;
833 indp_t disk_block;
834
835 buf = fp->f_buf;
836 rc = block_map(f, (indp_t)0, &disk_block);
837 if (rc)
838 goto out;
839
840 twiddle();
841 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
842 F_READ, FSBTODB(fs, disk_block),
843 fs->fs_bsize, buf, &buf_size);
844 if (rc)
845 goto out;
846
847 memcpy(namebuf, buf, link_len);
848 }
849
850 /*
851 * If relative pathname, restart at parent directory.
852 * If absolute pathname, restart at root.
853 */
854 cp = namebuf;
855 if (*cp != '/')
856 inumber = parent_inumber;
857 else
858 inumber = (ino32_t)UFS_ROOTINO;
859
860 if ((rc = read_inode(inumber, f)) != 0)
861 goto out;
862 }
863 #endif /* !LIBSA_NO_FS_SYMLINK */
864 }
865
866 /*
867 * Found terminal component.
868 */
869 rc = 0;
870
871 #else /* !LIBSA_FS_SINGLECOMPONENT */
872
873 /* look up component in the current (root) directory */
874 rc = search_directory(path, strlen(path), f, &inumber);
875 if (rc)
876 goto out;
877
878 /* open it */
879 rc = read_inode(inumber, f);
880
881 #endif /* !LIBSA_FS_SINGLECOMPONENT */
882
883 fp->f_seekp = 0; /* reset seek pointer */
884
885 out:
886 if (rc)
887 ufs_close(f);
888 else
889 #ifdef FSMOD
890 fsmod = FSMOD;
891 #else
892 fsmod = NULL;
893 #endif
894 return rc;
895 }
896
897 __compactcall int
898 ufs_close(struct open_file *f)
899 {
900 struct file *fp = (struct file *)f->f_fsdata;
901
902 f->f_fsdata = NULL;
903 if (fp == NULL)
904 return 0;
905
906 if (fp->f_buf)
907 dealloc(fp->f_buf, fp->f_fs->fs_bsize);
908 dealloc(fp->f_fs, SBLOCKSIZE);
909 dealloc(fp, sizeof(struct file));
910 return 0;
911 }
912
913 /*
914 * Copy a portion of a file into kernel memory.
915 * Cross block boundaries when necessary.
916 */
917 __compactcall int
918 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
919 {
920 struct file *fp = (struct file *)f->f_fsdata;
921 size_t csize;
922 char *buf;
923 size_t buf_size;
924 int rc = 0;
925 char *addr = start;
926
927 while (size != 0) {
928 if (fp->f_seekp >= (off_t)fp->f_di.di_size)
929 break;
930
931 rc = buf_read_file(f, &buf, &buf_size);
932 if (rc)
933 break;
934
935 csize = size;
936 if (csize > buf_size)
937 csize = buf_size;
938
939 memcpy(addr, buf, csize);
940
941 fp->f_seekp += csize;
942 addr += csize;
943 size -= csize;
944 }
945 if (resid)
946 *resid = size;
947 return rc;
948 }
949
950 /*
951 * Not implemented.
952 */
953 #ifndef LIBSA_NO_FS_WRITE
954 __compactcall int
955 ufs_write(struct open_file *f, void *start, size_t size, size_t *resid)
956 {
957
958 return EROFS;
959 }
960 #endif /* !LIBSA_NO_FS_WRITE */
961
962 #ifndef LIBSA_NO_FS_SEEK
963 __compactcall off_t
964 ufs_seek(struct open_file *f, off_t offset, int where)
965 {
966 struct file *fp = (struct file *)f->f_fsdata;
967
968 switch (where) {
969 case SEEK_SET:
970 fp->f_seekp = offset;
971 break;
972 case SEEK_CUR:
973 fp->f_seekp += offset;
974 break;
975 case SEEK_END:
976 fp->f_seekp = fp->f_di.di_size - offset;
977 break;
978 default:
979 return -1;
980 }
981 return fp->f_seekp;
982 }
983 #endif /* !LIBSA_NO_FS_SEEK */
984
985 __compactcall int
986 ufs_stat(struct open_file *f, struct stat *sb)
987 {
988 struct file *fp = (struct file *)f->f_fsdata;
989
990 /* only important stuff */
991 memset(sb, 0, sizeof *sb);
992 sb->st_mode = fp->f_di.di_mode;
993 sb->st_uid = fp->f_di.di_uid;
994 sb->st_gid = fp->f_di.di_gid;
995 sb->st_size = fp->f_di.di_size;
996 return 0;
997 }
998
999 #if defined(LIBSA_ENABLE_LS_OP)
1000
1001 #include "ls.h"
1002
1003 static const char *const typestr[] = {
1004 "unknown",
1005 "FIFO",
1006 "CHR",
1007 0,
1008 "DIR",
1009 0,
1010 "BLK",
1011 0,
1012 "REG",
1013 0,
1014 "LNK",
1015 0,
1016 "SOCK",
1017 0,
1018 "WHT"
1019 };
1020
1021 __compactcall void
1022 ufs_ls(struct open_file *f, const char *pattern)
1023 {
1024 struct file *fp = (struct file *)f->f_fsdata;
1025 char *buf;
1026 size_t buf_size;
1027 lsentry_t *names = NULL;
1028
1029 fp->f_seekp = 0;
1030 while (fp->f_seekp < (off_t)fp->f_di.di_size) {
1031 struct direct *dp, *edp;
1032 int rc = buf_read_file(f, &buf, &buf_size);
1033 if (rc)
1034 goto out;
1035 /* some firmware might use block size larger than DEV_BSIZE */
1036 if (buf_size < UFS_DIRBLKSIZ)
1037 goto out;
1038
1039 dp = (struct direct *)buf;
1040 edp = (struct direct *)(buf + buf_size);
1041
1042 for (; dp < edp;
1043 dp = (void *)((char *)dp + ffs_get_reclen(fp, dp))) {
1044 const char *t;
1045 if (ffs_get_ino(fp, dp) == 0)
1046 continue;
1047
1048 if (dp->d_type >= NELEM(typestr) ||
1049 !(t = typestr[dp->d_type])) {
1050 /*
1051 * This does not handle "old"
1052 * filesystems properly. On little
1053 * endian machines, we get a bogus
1054 * type name if the namlen matches a
1055 * valid type identifier. We could
1056 * check if we read namlen "0" and
1057 * handle this case specially, if
1058 * there were a pressing need...
1059 */
1060 printf("bad dir entry\n");
1061 goto out;
1062 }
1063 lsadd(&names, pattern, dp->d_name, strlen(dp->d_name),
1064 ffs_get_ino(fp, dp), t);
1065 }
1066 fp->f_seekp += buf_size;
1067 }
1068 lsprint(names);
1069 out: lsfree(names);
1070 }
1071 #endif /* LIBSA_ENABLE_LS_OP */
1072
1073 #ifdef LIBSA_FFSv1
1074 /*
1075 * Sanity checks for old file systems.
1076 *
1077 * XXX - goes away some day.
1078 * Stripped of stuff libsa doesn't need.....
1079 */
1080 static void
1081 ffs_oldfscompat(FS *fs)
1082 {
1083
1084 #ifdef COMPAT_UFS
1085 /*
1086 * Newer Solaris versions have a slightly incompatible
1087 * superblock - so always calculate this values on the fly, which
1088 * is good enough for libsa purposes
1089 */
1090 if (fs->fs_magic == FS_UFS1_MAGIC
1091 #ifndef COMPAT_SOLARIS_UFS
1092 && fs->fs_old_inodefmt < FS_44INODEFMT
1093 #endif
1094 ) {
1095 fs->fs_qbmask = ~fs->fs_bmask;
1096 fs->fs_qfmask = ~fs->fs_fmask;
1097 }
1098 #endif
1099 }
1100 #endif
1101