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