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