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