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