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