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