ufs.c revision 1.32 1 /* $NetBSD: ufs.c,v 1.32 2003/02/23 22:47:43 simonb 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 #include <ufs/ffs/fs.h>
79 #ifdef _STANDALONE
80 #include <lib/libkern/libkern.h>
81 #else
82 #include <string.h>
83 #endif
84
85 #include "stand.h"
86 #include "ufs.h"
87
88 #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
89 #define LIBSA_NO_FS_SYMLINK
90 #endif
91 #if defined(COMPAT_UFS) && defined(LIBSA_NO_COMPAT_UFS)
92 #undef COMPAT_UFS
93 #endif
94
95
96 /*
97 * In-core open file.
98 */
99 struct file {
100 off_t f_seekp; /* seek pointer */
101 struct fs *f_fs; /* pointer to super-block */
102 struct dinode f_di; /* copy of on-disk inode */
103 unsigned int f_nindir[NIADDR];
104 /* number of blocks mapped by
105 indirect block at level i */
106 char *f_blk[NIADDR]; /* buffer for indirect block at
107 level i */
108 size_t f_blksize[NIADDR];
109 /* size of buffer */
110 daddr_t f_blkno[NIADDR];/* disk address of block in buffer */
111 char *f_buf; /* buffer for data block */
112 size_t f_buf_size; /* size of data block */
113 daddr_t f_buf_blkno; /* block number of data block */
114 };
115
116 static int read_inode __P((ino_t, struct open_file *));
117 static int block_map __P((struct open_file *, daddr_t, daddr_t *));
118 static int buf_read_file __P((struct open_file *, char **, size_t *));
119 static int search_directory __P((char *, struct open_file *, ino_t *));
120 #ifdef COMPAT_UFS
121 static void ffs_oldfscompat __P((struct fs *));
122 #endif
123
124 /*
125 * Read a new inode into a file structure.
126 */
127 static int
128 read_inode(inumber, f)
129 ino_t inumber;
130 struct open_file *f;
131 {
132 struct file *fp = (struct file *)f->f_fsdata;
133 struct fs *fs = fp->f_fs;
134 char *buf;
135 size_t rsize;
136 int rc;
137
138 /*
139 * Read inode and save it.
140 */
141 buf = alloc(fs->fs_bsize);
142 #if !defined(LIBSA_NO_TWIDDLE)
143 twiddle();
144 #endif
145 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
146 fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
147 buf, &rsize);
148 if (rc)
149 goto out;
150 if (rsize != fs->fs_bsize) {
151 rc = EIO;
152 goto out;
153 }
154
155 {
156 struct dinode *dp;
157
158 dp = (struct dinode *)buf;
159 fp->f_di = dp[ino_to_fsbo(fs, inumber)];
160 }
161
162 /*
163 * Clear out the old buffers
164 */
165 {
166 int level;
167
168 for (level = 0; level < NIADDR; level++)
169 fp->f_blkno[level] = -1;
170 fp->f_buf_blkno = -1;
171 }
172 out:
173 free(buf, fs->fs_bsize);
174 return (rc);
175 }
176
177 /*
178 * Given an offset in a file, find the disk block number that
179 * contains that block.
180 */
181 static int
182 block_map(f, file_block, disk_block_p)
183 struct open_file *f;
184 daddr_t file_block;
185 daddr_t *disk_block_p; /* out */
186 {
187 struct file *fp = (struct file *)f->f_fsdata;
188 struct fs *fs = fp->f_fs;
189 int level;
190 int idx;
191 daddr_t ind_block_num;
192 /* XXX ondisk32 */
193 int32_t *ind_p;
194 int rc;
195
196 /*
197 * Index structure of an inode:
198 *
199 * di_db[0..NDADDR-1] hold block numbers for blocks
200 * 0..NDADDR-1
201 *
202 * di_ib[0] index block 0 is the single indirect block
203 * holds block numbers for blocks
204 * NDADDR .. NDADDR + NINDIR(fs)-1
205 *
206 * di_ib[1] index block 1 is the double indirect block
207 * holds block numbers for INDEX blocks for blocks
208 * NDADDR + NINDIR(fs) ..
209 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
210 *
211 * di_ib[2] index block 2 is the triple indirect block
212 * holds block numbers for double-indirect
213 * blocks for blocks
214 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
215 * NDADDR + NINDIR(fs) + NINDIR(fs)**2
216 * + NINDIR(fs)**3 - 1
217 */
218
219 if (file_block < NDADDR) {
220 /* Direct block. */
221 *disk_block_p = fp->f_di.di_db[file_block];
222 return (0);
223 }
224
225 file_block -= NDADDR;
226
227 /*
228 * nindir[0] = NINDIR
229 * nindir[1] = NINDIR**2
230 * nindir[2] = NINDIR**3
231 * etc
232 */
233 for (level = 0; level < NIADDR; level++) {
234 if (file_block < fp->f_nindir[level])
235 break;
236 file_block -= fp->f_nindir[level];
237 }
238 if (level == NIADDR) {
239 /* Block number too high */
240 return (EFBIG);
241 }
242
243 ind_block_num = fp->f_di.di_ib[level];
244
245 for (; level >= 0; level--) {
246 if (ind_block_num == 0) {
247 *disk_block_p = 0; /* missing */
248 return (0);
249 }
250
251 if (fp->f_blkno[level] != ind_block_num) {
252 if (fp->f_blk[level] == (char *)0)
253 fp->f_blk[level] =
254 alloc(fs->fs_bsize);
255 #if !defined(LIBSA_NO_TWIDDLE)
256 twiddle();
257 #endif
258 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
259 fsbtodb(fp->f_fs, ind_block_num),
260 fs->fs_bsize,
261 fp->f_blk[level],
262 &fp->f_blksize[level]);
263 if (rc)
264 return (rc);
265 if (fp->f_blksize[level] != fs->fs_bsize)
266 return (EIO);
267 fp->f_blkno[level] = ind_block_num;
268 }
269
270 /* XXX ondisk32 */
271 ind_p = (int32_t *)fp->f_blk[level];
272
273 if (level > 0) {
274 idx = file_block / fp->f_nindir[level - 1];
275 file_block %= fp->f_nindir[level - 1];
276 } else
277 idx = file_block;
278
279 ind_block_num = ind_p[idx];
280 }
281
282 *disk_block_p = ind_block_num;
283
284 return (0);
285 }
286
287 /*
288 * Read a portion of a file into an internal buffer. Return
289 * the location in the buffer and the amount in the buffer.
290 */
291 static int
292 buf_read_file(f, buf_p, size_p)
293 struct open_file *f;
294 char **buf_p; /* out */
295 size_t *size_p; /* out */
296 {
297 struct file *fp = (struct file *)f->f_fsdata;
298 struct fs *fs = fp->f_fs;
299 long off;
300 daddr_t file_block;
301 daddr_t disk_block;
302 size_t block_size;
303 int rc;
304
305 off = blkoff(fs, fp->f_seekp);
306 file_block = lblkno(fs, fp->f_seekp);
307 block_size = dblksize(fs, &fp->f_di, file_block);
308
309 if (file_block != fp->f_buf_blkno) {
310 rc = block_map(f, file_block, &disk_block);
311 if (rc)
312 return (rc);
313
314 if (fp->f_buf == (char *)0)
315 fp->f_buf = alloc(fs->fs_bsize);
316
317 if (disk_block == 0) {
318 bzero(fp->f_buf, block_size);
319 fp->f_buf_size = block_size;
320 } else {
321 #if !defined(LIBSA_NO_TWIDDLE)
322 twiddle();
323 #endif
324 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
325 fsbtodb(fs, disk_block),
326 block_size, fp->f_buf, &fp->f_buf_size);
327 if (rc)
328 return (rc);
329 }
330
331 fp->f_buf_blkno = file_block;
332 }
333
334 /*
335 * Return address of byte in buffer corresponding to
336 * offset, and size of remainder of buffer after that
337 * byte.
338 */
339 *buf_p = fp->f_buf + off;
340 *size_p = block_size - off;
341
342 /*
343 * But truncate buffer at end of file.
344 */
345 if (*size_p > fp->f_di.di_size - fp->f_seekp)
346 *size_p = fp->f_di.di_size - fp->f_seekp;
347
348 return (0);
349 }
350
351 /*
352 * Search a directory for a name and return its
353 * i_number.
354 */
355 static int
356 search_directory(name, f, inumber_p)
357 char *name;
358 struct open_file *f;
359 ino_t *inumber_p; /* out */
360 {
361 struct file *fp = (struct file *)f->f_fsdata;
362 struct direct *dp;
363 struct direct *edp;
364 char *buf;
365 size_t buf_size;
366 int namlen, length;
367 int rc;
368
369 length = strlen(name);
370
371 fp->f_seekp = 0;
372 while (fp->f_seekp < fp->f_di.di_size) {
373 rc = buf_read_file(f, &buf, &buf_size);
374 if (rc)
375 return (rc);
376
377 dp = (struct direct *)buf;
378 edp = (struct direct *)(buf + buf_size);
379 while (dp < edp) {
380 if (dp->d_ino == (ino_t)0)
381 goto next;
382 #if BYTE_ORDER == LITTLE_ENDIAN
383 if (fp->f_fs->fs_maxsymlinklen <= 0)
384 namlen = dp->d_type;
385 else
386 #endif
387 namlen = dp->d_namlen;
388 if (namlen == length &&
389 !strcmp(name, dp->d_name)) {
390 /* found entry */
391 *inumber_p = dp->d_ino;
392 return (0);
393 }
394 next:
395 dp = (struct direct *)((char *)dp + dp->d_reclen);
396 }
397 fp->f_seekp += buf_size;
398 }
399 return (ENOENT);
400 }
401
402 /*
403 * Open a file.
404 */
405 int
406 ufs_open(path, f)
407 char *path;
408 struct open_file *f;
409 {
410 #ifndef LIBSA_FS_SINGLECOMPONENT
411 char *cp, *ncp;
412 int c;
413 #endif
414 ino_t inumber;
415 struct file *fp;
416 struct fs *fs;
417 int rc;
418 size_t buf_size;
419 #ifndef LIBSA_NO_FS_SYMLINK
420 ino_t parent_inumber;
421 int nlinks = 0;
422 char namebuf[MAXPATHLEN+1];
423 char *buf = NULL;
424 #endif
425
426 /* allocate file system specific data structure */
427 fp = alloc(sizeof(struct file));
428 bzero(fp, sizeof(struct file));
429 f->f_fsdata = (void *)fp;
430
431 /* allocate space and read super block */
432 fs = alloc(SBSIZE);
433 fp->f_fs = fs;
434 #if !defined(LIBSA_NO_TWIDDLE)
435 twiddle();
436 #endif
437 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
438 SBLOCK, SBSIZE, (char *)fs, &buf_size);
439 if (rc)
440 goto out;
441
442 if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
443 fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
444 rc = EINVAL;
445 goto out;
446 }
447 #ifdef COMPAT_UFS
448 ffs_oldfscompat(fs);
449 #endif
450
451 /*
452 * Calculate indirect block levels.
453 */
454 {
455 int mult;
456 int level;
457
458 mult = 1;
459 for (level = 0; level < NIADDR; level++) {
460 mult *= NINDIR(fs);
461 fp->f_nindir[level] = mult;
462 }
463 }
464
465 inumber = ROOTINO;
466 if ((rc = read_inode(inumber, f)) != 0)
467 goto out;
468
469 #ifndef LIBSA_FS_SINGLECOMPONENT
470 cp = path;
471 while (*cp) {
472
473 /*
474 * Remove extra separators
475 */
476 while (*cp == '/')
477 cp++;
478 if (*cp == '\0')
479 break;
480
481 /*
482 * Check that current node is a directory.
483 */
484 if ((fp->f_di.di_mode & IFMT) != IFDIR) {
485 rc = ENOTDIR;
486 goto out;
487 }
488
489 /*
490 * Get next component of path name.
491 */
492 {
493 int len = 0;
494
495 ncp = cp;
496 while ((c = *cp) != '\0' && c != '/') {
497 if (++len > MAXNAMLEN) {
498 rc = ENOENT;
499 goto out;
500 }
501 cp++;
502 }
503 *cp = '\0';
504 }
505
506 /*
507 * Look up component in current directory.
508 * Save directory inumber in case we find a
509 * symbolic link.
510 */
511 #ifndef LIBSA_NO_FS_SYMLINK
512 parent_inumber = inumber;
513 #endif
514 rc = search_directory(ncp, f, &inumber);
515 *cp = c;
516 if (rc)
517 goto out;
518
519 /*
520 * Open next component.
521 */
522 if ((rc = read_inode(inumber, f)) != 0)
523 goto out;
524
525 #ifndef LIBSA_NO_FS_SYMLINK
526 /*
527 * Check for symbolic link.
528 */
529 if ((fp->f_di.di_mode & IFMT) == IFLNK) {
530 int link_len = fp->f_di.di_size;
531 int len;
532
533 len = strlen(cp);
534
535 if (link_len + len > MAXPATHLEN ||
536 ++nlinks > MAXSYMLINKS) {
537 rc = ENOENT;
538 goto out;
539 }
540
541 bcopy(cp, &namebuf[link_len], len + 1);
542
543 if (link_len < fs->fs_maxsymlinklen) {
544 bcopy(fp->f_di.di_shortlink, namebuf,
545 (unsigned) link_len);
546 } else {
547 /*
548 * Read file for symbolic link
549 */
550 size_t buf_size;
551 daddr_t disk_block;
552 struct fs *fs = fp->f_fs;
553
554 if (!buf)
555 buf = alloc(fs->fs_bsize);
556 rc = block_map(f, (daddr_t)0, &disk_block);
557 if (rc)
558 goto out;
559
560 #if !defined(LIBSA_NO_TWIDDLE)
561 twiddle();
562 #endif
563 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
564 F_READ, fsbtodb(fs, disk_block),
565 fs->fs_bsize, buf, &buf_size);
566 if (rc)
567 goto out;
568
569 bcopy((char *)buf, namebuf, (unsigned)link_len);
570 }
571
572 /*
573 * If relative pathname, restart at parent directory.
574 * If absolute pathname, restart at root.
575 */
576 cp = namebuf;
577 if (*cp != '/')
578 inumber = parent_inumber;
579 else
580 inumber = (ino_t)ROOTINO;
581
582 if ((rc = read_inode(inumber, f)) != 0)
583 goto out;
584 }
585 #endif /* !LIBSA_NO_FS_SYMLINK */
586 }
587
588 /*
589 * Found terminal component.
590 */
591 rc = 0;
592
593 #else /* !LIBSA_FS_SINGLECOMPONENT */
594
595 /* look up component in the current (root) directory */
596 rc = search_directory(path, f, &inumber);
597 if (rc)
598 goto out;
599
600 /* open it */
601 rc = read_inode(inumber, f);
602
603 #endif /* !LIBSA_FS_SINGLECOMPONENT */
604
605 fp->f_seekp = 0; /* reset seek pointer */
606
607 out:
608 #ifndef LIBSA_NO_FS_SYMLINK
609 if (buf)
610 free(buf, fs->fs_bsize);
611 #endif
612 if (rc) {
613 if (fp->f_buf)
614 free(fp->f_buf, fp->f_fs->fs_bsize);
615 free(fp->f_fs, SBSIZE);
616 free(fp, sizeof(struct file));
617 }
618 return (rc);
619 }
620
621 #ifndef LIBSA_NO_FS_CLOSE
622 int
623 ufs_close(f)
624 struct open_file *f;
625 {
626 struct file *fp = (struct file *)f->f_fsdata;
627 int level;
628
629 f->f_fsdata = (void *)0;
630 if (fp == (struct file *)0)
631 return (0);
632
633 for (level = 0; level < NIADDR; level++) {
634 if (fp->f_blk[level])
635 free(fp->f_blk[level], fp->f_fs->fs_bsize);
636 }
637 if (fp->f_buf)
638 free(fp->f_buf, fp->f_fs->fs_bsize);
639 free(fp->f_fs, SBSIZE);
640 free(fp, sizeof(struct file));
641 return (0);
642 }
643 #endif /* !LIBSA_NO_FS_CLOSE */
644
645 /*
646 * Copy a portion of a file into kernel memory.
647 * Cross block boundaries when necessary.
648 */
649 int
650 ufs_read(f, start, size, resid)
651 struct open_file *f;
652 void *start;
653 size_t size;
654 size_t *resid; /* out */
655 {
656 struct file *fp = (struct file *)f->f_fsdata;
657 size_t csize;
658 char *buf;
659 size_t buf_size;
660 int rc = 0;
661 char *addr = start;
662
663 while (size != 0) {
664 if (fp->f_seekp >= fp->f_di.di_size)
665 break;
666
667 rc = buf_read_file(f, &buf, &buf_size);
668 if (rc)
669 break;
670
671 csize = size;
672 if (csize > buf_size)
673 csize = buf_size;
674
675 bcopy(buf, addr, csize);
676
677 fp->f_seekp += csize;
678 addr += csize;
679 size -= csize;
680 }
681 if (resid)
682 *resid = size;
683 return (rc);
684 }
685
686 /*
687 * Not implemented.
688 */
689 #ifndef LIBSA_NO_FS_WRITE
690 int
691 ufs_write(f, start, size, resid)
692 struct open_file *f;
693 void *start;
694 size_t size;
695 size_t *resid; /* out */
696 {
697
698 return (EROFS);
699 }
700 #endif /* !LIBSA_NO_FS_WRITE */
701
702 #ifndef LIBSA_NO_FS_SEEK
703 off_t
704 ufs_seek(f, offset, where)
705 struct open_file *f;
706 off_t offset;
707 int where;
708 {
709 struct file *fp = (struct file *)f->f_fsdata;
710
711 switch (where) {
712 case SEEK_SET:
713 fp->f_seekp = offset;
714 break;
715 case SEEK_CUR:
716 fp->f_seekp += offset;
717 break;
718 case SEEK_END:
719 fp->f_seekp = fp->f_di.di_size - offset;
720 break;
721 default:
722 return (-1);
723 }
724 return (fp->f_seekp);
725 }
726 #endif /* !LIBSA_NO_FS_SEEK */
727
728 int
729 ufs_stat(f, sb)
730 struct open_file *f;
731 struct stat *sb;
732 {
733 struct file *fp = (struct file *)f->f_fsdata;
734
735 /* only important stuff */
736 sb->st_mode = fp->f_di.di_mode;
737 sb->st_uid = fp->f_di.di_uid;
738 sb->st_gid = fp->f_di.di_gid;
739 sb->st_size = fp->f_di.di_size;
740 return (0);
741 }
742
743 #ifdef COMPAT_UFS
744 /*
745 * Sanity checks for old file systems.
746 *
747 * XXX - goes away some day.
748 */
749 static void
750 ffs_oldfscompat(fs)
751 struct fs *fs;
752 {
753 int i;
754
755 fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */
756 fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */
757 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
758 fs->fs_nrpos = 8; /* XXX */
759 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
760 quad_t sizepb = fs->fs_bsize; /* XXX */
761 /* XXX */
762 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */
763 for (i = 0; i < NIADDR; i++) { /* XXX */
764 sizepb *= NINDIR(fs); /* XXX */
765 fs->fs_maxfilesize += sizepb; /* XXX */
766 } /* XXX */
767 fs->fs_qbmask = ~fs->fs_bmask; /* XXX */
768 fs->fs_qfmask = ~fs->fs_fmask; /* XXX */
769 } /* XXX */
770 }
771 #endif
772