ufs.c revision 1.37 1 /* $NetBSD: ufs.c,v 1.37 2003/08/18 08:00:52 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/mount.h> /* XXX for MNAMELEN */
72 #include <ufs/lfs/lfs.h>
73 #else
74 #include <ufs/ffs/fs.h>
75 #endif
76 #ifdef _STANDALONE
77 #include <lib/libkern/libkern.h>
78 #else
79 #include <string.h>
80 #endif
81
82 #include "stand.h"
83 #ifdef LIBSA_LFS
84 #include "lfs.h"
85 #else
86 #include "ufs.h"
87 #endif
88
89 /* If this file is compiled by itself, build ufs (aka ffsv1) support */
90 #if !defined(LIBSA_FFSv2) && !defined(LIBSA_LFS)
91 #define LIBSA_FFSv1
92 #endif
93
94 #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
95 #define LIBSA_NO_FS_SYMLINK
96 #endif
97 #if defined(COMPAT_UFS) && defined(LIBSA_NO_COMPAT_UFS)
98 #undef COMPAT_UFS
99 #endif
100
101 #ifdef LIBSA_LFS
102 /*
103 * In-core LFS superblock. This exists only to placate the macros in lfs.h,
104 */
105 struct fs {
106 struct dlfs lfs_dlfs;
107 };
108 #define fs_magic lfs_magic
109 #define fs_maxsymlinklen lfs_maxsymlinklen
110
111 #define FS_MAGIC LFS_MAGIC
112 #define SBLOCKSIZE LFS_SBPAD
113 #define SBLOCKOFFSET LFS_LABELPAD
114 #else
115 /* NB ufs2 doesn't use the common suberblock code... */
116 #define FS_MAGIC FS_UFS1_MAGIC
117 #define SBLOCKOFFSET SBLOCK_UFS1
118 #endif
119
120 #if defined(LIBSA_NO_TWIDDLE)
121 #define twiddle()
122 #endif
123
124 #ifndef ufs_dinode
125 #define ufs_dinode ufs1_dinode
126 #endif
127 #ifndef indp_t
128 #define indp_t uint32_t
129 #endif
130 #ifndef FSBTODB
131 #define FSBTODB(fs, daddr) fsbtodb(fs, daddr)
132 #endif
133
134 /*
135 * In-core open file.
136 */
137 struct file {
138 off_t f_seekp; /* seek pointer */
139 struct fs *f_fs; /* pointer to super-block */
140 struct ufs_dinode f_di; /* copy of on-disk inode */
141 daddr_t f_nindir[NIADDR];
142 /* number of blocks mapped by
143 indirect block at level i */
144 int f_l2indir[NIADDR]; /* log2(f_nindir) */
145 char *f_blk[NIADDR]; /* buffer for indirect block at
146 level i */
147 size_t f_blksize[NIADDR];
148 /* size of buffer */
149 daddr_t f_blkno[NIADDR];/* disk address of block in buffer */
150 char *f_buf; /* buffer for data block */
151 size_t f_buf_size; /* size of data block */
152 daddr_t f_buf_blkno; /* block number of data block */
153 };
154
155 static int read_inode(ino_t, struct open_file *);
156 static int block_map(struct open_file *, daddr_t, daddr_t *);
157 static int buf_read_file(struct open_file *, char **, size_t *);
158 static int search_directory(const char *, struct open_file *, ino_t *);
159 #ifdef LIBSA_FFSv1
160 static void ffs_oldfscompat(struct fs *);
161 #endif
162 #ifdef LIBSA_FFSv2
163 static int ffs_find_superblock(struct open_file *, struct fs *);
164 #endif
165
166 #ifdef LIBSA_LFS
167 /*
168 * Find an inode's block. Look it up in the ifile. Whee!
169 */
170 static int
171 find_inode_sector(ino_t inumber, struct open_file *f, daddr_t *isp)
172 {
173 struct file *fp = (struct file *)f->f_fsdata;
174 struct fs *fs = fp->f_fs;
175 daddr_t ifileent_blkno;
176 char *ent_in_buf;
177 size_t buf_after_ent;
178 int rc;
179
180 rc = read_inode(fs->lfs_ifile, f);
181 if (rc)
182 return (rc);
183
184 ifileent_blkno =
185 (inumber / fs->lfs_ifpb) + fs->lfs_cleansz + fs->lfs_segtabsz;
186 fp->f_seekp = (off_t)ifileent_blkno * fs->fs_bsize +
187 (inumber % fs->lfs_ifpb) * sizeof (IFILE_Vx);
188 rc = buf_read_file(f, &ent_in_buf, &buf_after_ent);
189 if (rc)
190 return (rc);
191 /* make sure something's not badly wrong, but don't panic. */
192 if (buf_after_ent < sizeof (IFILE_Vx))
193 return (EINVAL);
194
195 *isp = FSBTODB(fs, ((IFILE_Vx *)ent_in_buf)->if_daddr);
196 if (*isp == LFS_UNUSED_DADDR) /* again, something badly wrong */
197 return (EINVAL);
198 return (0);
199 }
200 #endif
201
202 /*
203 * Read a new inode into a file structure.
204 */
205 static int
206 read_inode(ino_t inumber, struct open_file *f)
207 {
208 struct file *fp = (struct file *)f->f_fsdata;
209 struct fs *fs = fp->f_fs;
210 char *buf;
211 size_t rsize;
212 int rc;
213 daddr_t inode_sector;
214 #ifdef LIBSA_LFS
215 struct ufs_dinode *dip;
216 int cnt;
217 #endif
218
219 #ifdef LIBSA_LFS
220 if (inumber == fs->lfs_ifile)
221 inode_sector = FSBTODB(fs, fs->lfs_idaddr);
222 else if ((rc = find_inode_sector(inumber, f, &inode_sector)) != 0)
223 return (rc);
224 #else
225 inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
226 #endif
227
228 /*
229 * Read inode and save it.
230 */
231 buf = alloc(fs->fs_bsize);
232 twiddle();
233 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
234 inode_sector, fs->fs_bsize,
235 buf, &rsize);
236 if (rc)
237 goto out;
238 if (rsize != fs->fs_bsize) {
239 rc = EIO;
240 goto out;
241 }
242
243 #ifdef LIBSA_LFS
244 rc = EINVAL;
245 cnt = INOPBx(fs);
246 for (dip = (struct ufs_dinode *)buf + (cnt - 1); cnt--; --dip) {
247 if (dip->di_inumber == inumber) {
248 rc = 0;
249 break;
250 }
251 }
252 /* kernel code panics, but boot blocks which panic are Bad. */
253 if (rc)
254 goto out;
255 fp->f_di = *dip;
256 #else
257 fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)];
258 #endif
259
260 /*
261 * Clear out the old buffers
262 */
263 {
264 int level;
265
266 for (level = 0; level < NIADDR; level++)
267 fp->f_blkno[level] = -1;
268 fp->f_buf_blkno = -1;
269 }
270 out:
271 free(buf, fs->fs_bsize);
272 return (rc);
273 }
274
275 /*
276 * Given an offset in a file, find the disk block number that
277 * contains that block.
278 */
279 static int
280 block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p)
281 {
282 struct file *fp = (struct file *)f->f_fsdata;
283 struct fs *fs = fp->f_fs;
284 int level;
285 int idx;
286 daddr_t ind_block_num;
287 indp_t *ind_p;
288 int rc;
289
290 /*
291 * Index structure of an inode:
292 *
293 * di_db[0..NDADDR-1] hold block numbers for blocks
294 * 0..NDADDR-1
295 *
296 * di_ib[0] index block 0 is the single indirect block
297 * holds block numbers for blocks
298 * NDADDR .. NDADDR + NINDIR(fs)-1
299 *
300 * di_ib[1] index block 1 is the double indirect block
301 * holds block numbers for INDEX blocks for blocks
302 * NDADDR + NINDIR(fs) ..
303 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
304 *
305 * di_ib[2] index block 2 is the triple indirect block
306 * holds block numbers for double-indirect
307 * blocks for blocks
308 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
309 * NDADDR + NINDIR(fs) + NINDIR(fs)**2
310 * + NINDIR(fs)**3 - 1
311 */
312
313 if (file_block < NDADDR) {
314 /* Direct block. */
315 *disk_block_p = fp->f_di.di_db[file_block];
316 return (0);
317 }
318
319 file_block -= NDADDR;
320
321 /*
322 * nindir[0] = NINDIR
323 * nindir[1] = NINDIR**2
324 * nindir[2] = NINDIR**3
325 * etc
326 */
327 for (level = 0; level < NIADDR; level++) {
328 if (file_block < fp->f_nindir[level])
329 break;
330 file_block -= fp->f_nindir[level];
331 }
332 if (level == NIADDR) {
333 /* Block number too high */
334 return (EFBIG);
335 }
336
337 ind_block_num = fp->f_di.di_ib[level];
338
339 for (; level >= 0; level--) {
340 if (ind_block_num == 0) {
341 *disk_block_p = 0; /* missing */
342 return (0);
343 }
344
345 if (fp->f_blkno[level] != ind_block_num) {
346 if (fp->f_blk[level] == (char *)0)
347 fp->f_blk[level] =
348 alloc(fs->fs_bsize);
349 twiddle();
350 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
351 FSBTODB(fp->f_fs, ind_block_num),
352 fs->fs_bsize,
353 fp->f_blk[level],
354 &fp->f_blksize[level]);
355 if (rc)
356 return (rc);
357 if (fp->f_blksize[level] != fs->fs_bsize)
358 return (EIO);
359 fp->f_blkno[level] = ind_block_num;
360 }
361
362 if (level > 0) {
363 idx = file_block >> fp->f_l2indir[level - 1];
364 file_block &= fp->f_nindir[level - 1] - 1;
365 } else
366 idx = file_block;
367
368 ind_p = (void *)fp->f_blk[level];
369 ind_block_num = ind_p[idx];
370 }
371
372 *disk_block_p = ind_block_num;
373
374 return (0);
375 }
376
377 /*
378 * Read a portion of a file into an internal buffer. Return
379 * the location in the buffer and the amount in the buffer.
380 */
381 static int
382 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
383 {
384 struct file *fp = (struct file *)f->f_fsdata;
385 struct fs *fs = fp->f_fs;
386 long off;
387 daddr_t file_block;
388 daddr_t disk_block;
389 size_t block_size;
390 int rc;
391
392 off = blkoff(fs, fp->f_seekp);
393 file_block = lblkno(fs, fp->f_seekp);
394 #ifdef LIBSA_LFS
395 block_size = dblksize(fs, &fp->f_di, file_block);
396 #else
397 block_size = sblksize(fs, fp->f_di.di_size, file_block);
398 #endif
399
400 if (file_block != fp->f_buf_blkno) {
401 rc = block_map(f, file_block, &disk_block);
402 if (rc)
403 return (rc);
404
405 if (fp->f_buf == (char *)0)
406 fp->f_buf = alloc(fs->fs_bsize);
407
408 if (disk_block == 0) {
409 bzero(fp->f_buf, block_size);
410 fp->f_buf_size = block_size;
411 } else {
412 twiddle();
413 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
414 FSBTODB(fs, disk_block),
415 block_size, fp->f_buf, &fp->f_buf_size);
416 if (rc)
417 return (rc);
418 }
419
420 fp->f_buf_blkno = file_block;
421 }
422
423 /*
424 * Return address of byte in buffer corresponding to
425 * offset, and size of remainder of buffer after that
426 * byte.
427 */
428 *buf_p = fp->f_buf + off;
429 *size_p = block_size - off;
430
431 /*
432 * But truncate buffer at end of file.
433 */
434 if (*size_p > fp->f_di.di_size - fp->f_seekp)
435 *size_p = fp->f_di.di_size - fp->f_seekp;
436
437 return (0);
438 }
439
440 /*
441 * Search a directory for a name and return its
442 * i_number.
443 */
444 static int
445 search_directory(const char *name, struct open_file *f, ino_t *inumber_p)
446 {
447 struct file *fp = (struct file *)f->f_fsdata;
448 struct direct *dp;
449 struct direct *edp;
450 char *buf;
451 size_t buf_size;
452 int namlen, length;
453 int rc;
454
455 length = strlen(name);
456
457 fp->f_seekp = 0;
458 while (fp->f_seekp < fp->f_di.di_size) {
459 rc = buf_read_file(f, &buf, &buf_size);
460 if (rc)
461 return (rc);
462
463 dp = (struct direct *)buf;
464 edp = (struct direct *)(buf + buf_size);
465 while (dp < edp) {
466 if (dp->d_ino == (ino_t)0)
467 goto next;
468 #if BYTE_ORDER == LITTLE_ENDIAN
469 if (fp->f_fs->fs_maxsymlinklen <= 0)
470 namlen = dp->d_type;
471 else
472 #endif
473 namlen = dp->d_namlen;
474 if (namlen == length &&
475 !strcmp(name, dp->d_name)) {
476 /* found entry */
477 *inumber_p = dp->d_ino;
478 return (0);
479 }
480 next:
481 dp = (struct direct *)((char *)dp + dp->d_reclen);
482 }
483 fp->f_seekp += buf_size;
484 }
485 return (ENOENT);
486 }
487
488 #ifdef LIBSA_FFSv2
489
490 daddr_t sblock_try[] = SBLOCKSEARCH;
491
492 static int
493 ffs_find_superblock(struct open_file *f, struct fs *fs)
494 {
495 int i, rc;
496 size_t buf_size;
497
498 for (i = 0; sblock_try[i] != -1; i++) {
499 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
500 sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, (char *)fs,
501 &buf_size);
502 if (rc != 0 || buf_size != SBLOCKSIZE)
503 return rc;
504 if (fs->fs_magic == FS_UFS2_MAGIC) {
505 return 0;
506 }
507 }
508 return EINVAL;
509 }
510
511 #endif
512
513 /*
514 * Open a file.
515 */
516 int
517 ufs_open(char *path, struct open_file *f)
518 {
519 #ifndef LIBSA_FS_SINGLECOMPONENT
520 char *cp, *ncp;
521 int c;
522 #endif
523 ino_t inumber;
524 struct file *fp;
525 struct fs *fs;
526 int rc;
527 #ifndef LIBSA_NO_FS_SYMLINK
528 ino_t parent_inumber;
529 int nlinks = 0;
530 char namebuf[MAXPATHLEN+1];
531 char *buf = NULL;
532 #endif
533
534 /* allocate file system specific data structure */
535 fp = alloc(sizeof(struct file));
536 bzero(fp, sizeof(struct file));
537 f->f_fsdata = (void *)fp;
538
539 /* allocate space and read super block */
540 fs = alloc(SBLOCKSIZE);
541 fp->f_fs = fs;
542 twiddle();
543
544 #ifdef LIBSA_FFSv2
545 rc = ffs_find_superblock(f, fs);
546 if (rc)
547 goto out;
548 #else
549 {
550 size_t buf_size;
551 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
552 SBLOCKOFFSET / DEV_BSIZE,
553 SBLOCKSIZE, (char *)fs, &buf_size);
554 if (rc)
555 goto out;
556 if (buf_size != SBLOCKSIZE ||
557 #ifdef LIBSA_FFS
558 fs->lfs_version != REQUIRED_LFS_VERSION ||
559 #endif
560 fs->fs_magic != FS_MAGIC) {
561 rc = EINVAL;
562 goto out;
563 }
564 }
565 #if defined(LIBSA_LFS) && REQUIRED_LFS_VERSION == 2
566 /*
567 * XXX We should check the second superblock and use the eldest
568 * of the two. See comments near the top of lfs_mountfs()
569 * in sys/ufs/lfs/lfs_vfsops.c.
570 * This may need a LIBSA_LFS_SMALL check as well.
571 */
572 #endif
573 #endif
574
575 #ifdef LIBSA_FFSv1
576 ffs_oldfscompat(fs);
577 #endif
578
579 if (fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
580 rc = EINVAL;
581 goto out;
582 }
583
584 /*
585 * Calculate indirect block levels.
586 */
587 {
588 daddr_t mult;
589 int level;
590 int ln2;
591
592 /*
593 * We note that the number of indirect blocks is always
594 * a power of 2. This lets us use shifts and masks instead
595 * of divide and remainder and avoinds pulling in the
596 * 64bit division routine into the boot code.
597 */
598 mult = NINDIR(fs);
599 #ifdef DEBUG
600 if (mult & (mult - 1)) {
601 /* Hummm was't a power of 2 */
602 rc = EINVAL;
603 goto out;
604 }
605 #endif
606 for (ln2 = 0; mult != 1; ln2++)
607 mult >>= 1;
608
609 for (level = 0; level < NIADDR; level++) {
610 mult *= NINDIR(fs);
611 fp->f_nindir[level] = mult;
612 fp->f_l2indir[level] = ln2 * (level + 1);
613 }
614 }
615
616 inumber = ROOTINO;
617 if ((rc = read_inode(inumber, f)) != 0)
618 goto out;
619
620 #ifndef LIBSA_FS_SINGLECOMPONENT
621 cp = path;
622 while (*cp) {
623
624 /*
625 * Remove extra separators
626 */
627 while (*cp == '/')
628 cp++;
629 if (*cp == '\0')
630 break;
631
632 /*
633 * Check that current node is a directory.
634 */
635 if ((fp->f_di.di_mode & IFMT) != IFDIR) {
636 rc = ENOTDIR;
637 goto out;
638 }
639
640 /*
641 * Get next component of path name.
642 */
643 {
644 int len = 0;
645
646 ncp = cp;
647 while ((c = *cp) != '\0' && c != '/') {
648 if (++len > MAXNAMLEN) {
649 rc = ENOENT;
650 goto out;
651 }
652 cp++;
653 }
654 *cp = '\0';
655 }
656
657 /*
658 * Look up component in current directory.
659 * Save directory inumber in case we find a
660 * symbolic link.
661 */
662 #ifndef LIBSA_NO_FS_SYMLINK
663 parent_inumber = inumber;
664 #endif
665 rc = search_directory(ncp, f, &inumber);
666 *cp = c;
667 if (rc)
668 goto out;
669
670 /*
671 * Open next component.
672 */
673 if ((rc = read_inode(inumber, f)) != 0)
674 goto out;
675
676 #ifndef LIBSA_NO_FS_SYMLINK
677 /*
678 * Check for symbolic link.
679 */
680 if ((fp->f_di.di_mode & IFMT) == IFLNK) {
681 int link_len = fp->f_di.di_size;
682 int len;
683
684 len = strlen(cp);
685
686 if (link_len + len > MAXPATHLEN ||
687 ++nlinks > MAXSYMLINKS) {
688 rc = ENOENT;
689 goto out;
690 }
691
692 bcopy(cp, &namebuf[link_len], len + 1);
693
694 if (link_len < fs->fs_maxsymlinklen) {
695 bcopy(fp->f_di.di_db, namebuf,
696 (unsigned)link_len);
697 } else {
698 /*
699 * Read file for symbolic link
700 */
701 size_t buf_size;
702 daddr_t disk_block;
703
704 if (!buf)
705 buf = alloc(fs->fs_bsize);
706 rc = block_map(f, (daddr_t)0, &disk_block);
707 if (rc)
708 goto out;
709
710 twiddle();
711 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
712 F_READ, FSBTODB(fs, disk_block),
713 fs->fs_bsize, buf, &buf_size);
714 if (rc)
715 goto out;
716
717 bcopy(buf, namebuf, (unsigned)link_len);
718 }
719
720 /*
721 * If relative pathname, restart at parent directory.
722 * If absolute pathname, restart at root.
723 */
724 cp = namebuf;
725 if (*cp != '/')
726 inumber = parent_inumber;
727 else
728 inumber = (ino_t)ROOTINO;
729
730 if ((rc = read_inode(inumber, f)) != 0)
731 goto out;
732 }
733 #endif /* !LIBSA_NO_FS_SYMLINK */
734 }
735
736 /*
737 * Found terminal component.
738 */
739 rc = 0;
740
741 #else /* !LIBSA_FS_SINGLECOMPONENT */
742
743 /* look up component in the current (root) directory */
744 rc = search_directory(path, f, &inumber);
745 if (rc)
746 goto out;
747
748 /* open it */
749 rc = read_inode(inumber, f);
750
751 #endif /* !LIBSA_FS_SINGLECOMPONENT */
752
753 fp->f_seekp = 0; /* reset seek pointer */
754
755 out:
756 #ifndef LIBSA_NO_FS_SYMLINK
757 if (buf)
758 free(buf, fs->fs_bsize);
759 #endif
760 if (rc) {
761 if (fp->f_buf)
762 free(fp->f_buf, fp->f_fs->fs_bsize);
763 free(fp->f_fs, SBLOCKSIZE);
764 free(fp, sizeof(struct file));
765 }
766 return (rc);
767 }
768
769 #ifndef LIBSA_NO_FS_CLOSE
770 int
771 ufs_close(struct open_file *f)
772 {
773 struct file *fp = (struct file *)f->f_fsdata;
774 int level;
775
776 f->f_fsdata = (void *)0;
777 if (fp == (struct file *)0)
778 return (0);
779
780 for (level = 0; level < NIADDR; level++) {
781 if (fp->f_blk[level])
782 free(fp->f_blk[level], fp->f_fs->fs_bsize);
783 }
784 if (fp->f_buf)
785 free(fp->f_buf, fp->f_fs->fs_bsize);
786 free(fp->f_fs, SBLOCKSIZE);
787 free(fp, sizeof(struct file));
788 return (0);
789 }
790 #endif /* !LIBSA_NO_FS_CLOSE */
791
792 /*
793 * Copy a portion of a file into kernel memory.
794 * Cross block boundaries when necessary.
795 */
796 int
797 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
798 {
799 struct file *fp = (struct file *)f->f_fsdata;
800 size_t csize;
801 char *buf;
802 size_t buf_size;
803 int rc = 0;
804 char *addr = start;
805
806 while (size != 0) {
807 if (fp->f_seekp >= fp->f_di.di_size)
808 break;
809
810 rc = buf_read_file(f, &buf, &buf_size);
811 if (rc)
812 break;
813
814 csize = size;
815 if (csize > buf_size)
816 csize = buf_size;
817
818 bcopy(buf, addr, csize);
819
820 fp->f_seekp += csize;
821 addr += csize;
822 size -= csize;
823 }
824 if (resid)
825 *resid = size;
826 return (rc);
827 }
828
829 /*
830 * Not implemented.
831 */
832 #ifndef LIBSA_NO_FS_WRITE
833 int
834 ufs_write(struct open_file *f, void *start, size_t size, size_t *resid)
835 {
836
837 return (EROFS);
838 }
839 #endif /* !LIBSA_NO_FS_WRITE */
840
841 #ifndef LIBSA_NO_FS_SEEK
842 off_t
843 ufs_seek(struct open_file *f, off_t offset, int where)
844 {
845 struct file *fp = (struct file *)f->f_fsdata;
846
847 switch (where) {
848 case SEEK_SET:
849 fp->f_seekp = offset;
850 break;
851 case SEEK_CUR:
852 fp->f_seekp += offset;
853 break;
854 case SEEK_END:
855 fp->f_seekp = fp->f_di.di_size - offset;
856 break;
857 default:
858 return (-1);
859 }
860 return (fp->f_seekp);
861 }
862 #endif /* !LIBSA_NO_FS_SEEK */
863
864 int
865 ufs_stat(struct open_file *f, struct stat *sb)
866 {
867 struct file *fp = (struct file *)f->f_fsdata;
868
869 /* only important stuff */
870 sb->st_mode = fp->f_di.di_mode;
871 sb->st_uid = fp->f_di.di_uid;
872 sb->st_gid = fp->f_di.di_gid;
873 sb->st_size = fp->f_di.di_size;
874 return (0);
875 }
876
877 #ifdef LIBSA_FFSv1
878 /*
879 * Sanity checks for old file systems.
880 *
881 * XXX - goes away some day.
882 */
883 static void
884 ffs_oldfscompat(struct fs *fs)
885 {
886 #ifdef COMPAT_UFS
887 int i;
888 #endif
889
890 if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_size != fs->fs_old_size) {
891 fs->fs_maxbsize = fs->fs_bsize;
892 fs->fs_time = fs->fs_old_time;
893 fs->fs_size = fs->fs_old_size;
894 fs->fs_dsize = fs->fs_old_dsize;
895 fs->fs_csaddr = fs->fs_old_csaddr;
896 fs->fs_cstotal.cs_ndir = fs->fs_old_cstotal.cs_ndir;
897 fs->fs_cstotal.cs_nbfree = fs->fs_old_cstotal.cs_nbfree;
898 fs->fs_cstotal.cs_nifree = fs->fs_old_cstotal.cs_nifree;
899 fs->fs_cstotal.cs_nffree = fs->fs_old_cstotal.cs_nffree;
900 }
901 #ifdef COMPAT_UFS
902 if (fs->fs_magic == FS_UFS1_MAGIC &&
903 fs->fs_old_inodefmt < FS_44INODEFMT) {
904 quad_t sizepb = fs->fs_bsize;
905 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;
906 for (i = 0; i < NIADDR; i++) {
907 sizepb *= NINDIR(fs);
908 fs->fs_maxfilesize += sizepb;
909 }
910 fs->fs_qbmask = ~fs->fs_bmask;
911 fs->fs_qfmask = ~fs->fs_fmask;
912 }
913 #endif
914 }
915 #endif
916