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