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