ufs.c revision 1.57 1 /* $NetBSD: ufs.c,v 1.57 2012/01/16 18:44:13 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 (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 else {
774 #ifdef FSMOD
775 fsmod = FSMOD;
776 #endif
777 #ifdef FSMOD2
778 fsmod2 = FSMOD2;
779 #endif
780 }
781 return rc;
782 }
783
784 __compactcall int
785 ufs_close(struct open_file *f)
786 {
787 struct file *fp = (struct file *)f->f_fsdata;
788
789 f->f_fsdata = NULL;
790 if (fp == NULL)
791 return 0;
792
793 if (fp->f_buf)
794 dealloc(fp->f_buf, fp->f_fs->fs_bsize);
795 dealloc(fp->f_fs, SBLOCKSIZE);
796 dealloc(fp, sizeof(struct file));
797 return 0;
798 }
799
800 /*
801 * Copy a portion of a file into kernel memory.
802 * Cross block boundaries when necessary.
803 */
804 __compactcall int
805 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
806 {
807 struct file *fp = (struct file *)f->f_fsdata;
808 size_t csize;
809 char *buf;
810 size_t buf_size;
811 int rc = 0;
812 char *addr = start;
813
814 while (size != 0) {
815 if (fp->f_seekp >= (off_t)fp->f_di.di_size)
816 break;
817
818 rc = buf_read_file(f, &buf, &buf_size);
819 if (rc)
820 break;
821
822 csize = size;
823 if (csize > buf_size)
824 csize = buf_size;
825
826 memcpy(addr, buf, csize);
827
828 fp->f_seekp += csize;
829 addr += csize;
830 size -= csize;
831 }
832 if (resid)
833 *resid = size;
834 return rc;
835 }
836
837 /*
838 * Not implemented.
839 */
840 #ifndef LIBSA_NO_FS_WRITE
841 __compactcall int
842 ufs_write(struct open_file *f, void *start, size_t size, size_t *resid)
843 {
844
845 return EROFS;
846 }
847 #endif /* !LIBSA_NO_FS_WRITE */
848
849 #ifndef LIBSA_NO_FS_SEEK
850 __compactcall off_t
851 ufs_seek(struct open_file *f, off_t offset, int where)
852 {
853 struct file *fp = (struct file *)f->f_fsdata;
854
855 switch (where) {
856 case SEEK_SET:
857 fp->f_seekp = offset;
858 break;
859 case SEEK_CUR:
860 fp->f_seekp += offset;
861 break;
862 case SEEK_END:
863 fp->f_seekp = fp->f_di.di_size - offset;
864 break;
865 default:
866 return -1;
867 }
868 return fp->f_seekp;
869 }
870 #endif /* !LIBSA_NO_FS_SEEK */
871
872 __compactcall int
873 ufs_stat(struct open_file *f, struct stat *sb)
874 {
875 struct file *fp = (struct file *)f->f_fsdata;
876
877 /* only important stuff */
878 memset(sb, 0, sizeof *sb);
879 sb->st_mode = fp->f_di.di_mode;
880 sb->st_uid = fp->f_di.di_uid;
881 sb->st_gid = fp->f_di.di_gid;
882 sb->st_size = fp->f_di.di_size;
883 return 0;
884 }
885
886 #if defined(LIBSA_ENABLE_LS_OP)
887 __compactcall void
888 ufs_ls(struct open_file *f, const char *pattern)
889 {
890 struct file *fp = (struct file *)f->f_fsdata;
891 char *buf;
892 size_t buf_size;
893 entry_t *names = 0, *n, **np;
894
895 fp->f_seekp = 0;
896 while (fp->f_seekp < (off_t)fp->f_di.di_size) {
897 struct direct *dp, *edp;
898 int rc = buf_read_file(f, &buf, &buf_size);
899 if (rc)
900 goto out;
901 /* some firmware might use block size larger than DEV_BSIZE */
902 if (buf_size < DIRBLKSIZ)
903 goto out;
904
905 dp = (struct direct *)buf;
906 edp = (struct direct *)(buf + buf_size);
907
908 for (; dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) {
909 const char *t;
910 if (dp->d_ino == 0)
911 continue;
912
913 if (dp->d_type >= NELEM(typestr) ||
914 !(t = typestr[dp->d_type])) {
915 /*
916 * This does not handle "old"
917 * filesystems properly. On little
918 * endian machines, we get a bogus
919 * type name if the namlen matches a
920 * valid type identifier. We could
921 * check if we read namlen "0" and
922 * handle this case specially, if
923 * there were a pressing need...
924 */
925 printf("bad dir entry\n");
926 goto out;
927 }
928 if (pattern && !fnmatch(dp->d_name, pattern))
929 continue;
930 n = alloc(sizeof *n + strlen(dp->d_name));
931 if (!n) {
932 printf("%d: %s (%s)\n",
933 dp->d_ino, dp->d_name, t);
934 continue;
935 }
936 n->e_ino = dp->d_ino;
937 n->e_type = dp->d_type;
938 strcpy(n->e_name, dp->d_name);
939 for (np = &names; *np; np = &(*np)->e_next) {
940 if (strcmp(n->e_name, (*np)->e_name) < 0)
941 break;
942 }
943 n->e_next = *np;
944 *np = n;
945 }
946 fp->f_seekp += buf_size;
947 }
948
949 if (names) {
950 entry_t *p_names = names;
951 do {
952 n = p_names;
953 printf("%d: %s (%s)\n",
954 n->e_ino, n->e_name, typestr[n->e_type]);
955 p_names = n->e_next;
956 } while (p_names);
957 } else {
958 printf("not found\n");
959 }
960 out:
961 if (names) {
962 do {
963 n = names;
964 names = n->e_next;
965 dealloc(n, 0);
966 } while (names);
967 }
968 }
969 #endif /* LIBSA_ENABLE_LS_OP */
970
971 #ifdef LIBSA_FFSv1
972 /*
973 * Sanity checks for old file systems.
974 *
975 * XXX - goes away some day.
976 * Stripped of stuff libsa doesn't need.....
977 */
978 static void
979 ffs_oldfscompat(struct fs *fs)
980 {
981
982 #ifdef COMPAT_UFS
983 /*
984 * Newer Solaris versions have a slightly incompatible
985 * superblock - so always calculate this values on the fly, which
986 * is good enough for libsa purposes
987 */
988 if (fs->fs_magic == FS_UFS1_MAGIC
989 #ifndef COMPAT_SOLARIS_UFS
990 && fs->fs_old_inodefmt < FS_44INODEFMT
991 #endif
992 ) {
993 fs->fs_qbmask = ~fs->fs_bmask;
994 fs->fs_qfmask = ~fs->fs_fmask;
995 }
996 #endif
997 }
998 #endif
999