Annotation of sys/lib/libsa/ufs.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ufs.c,v 1.18 2007/03/16 21:48:59 tsi Exp $ */
2: /* $NetBSD: ufs.c,v 1.16 1996/09/30 16:01:22 ws Exp $ */
3:
4: /*-
5: * Copyright (c) 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * This code is derived from software contributed to Berkeley by
9: * The Mach Operating System project at Carnegie-Mellon University.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: *
35: *
36: * Copyright (c) 1990, 1991 Carnegie Mellon University
37: * All Rights Reserved.
38: *
39: * Author: David Golub
40: *
41: * Permission to use, copy, modify and distribute this software and its
42: * documentation is hereby granted, provided that both the copyright
43: * notice and this permission notice appear in all copies of the
44: * software, derivative works or modified versions, and any portions
45: * thereof, and that both notices appear in supporting documentation.
46: *
47: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
48: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
49: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
50: *
51: * Carnegie Mellon requests users of this software to return to
52: *
53: * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
54: * School of Computer Science
55: * Carnegie Mellon University
56: * Pittsburgh PA 15213-3890
57: *
58: * any improvements or extensions that they make and grant Carnegie the
59: * rights to redistribute these changes.
60: */
61:
62: /*
63: * Stand-alone file reading package.
64: */
65:
66: #include <sys/param.h>
67: #include <sys/time.h>
68: #include <sys/stat.h>
69: #include <ufs/ffs/fs.h>
70: #include <ufs/ufs/dinode.h>
71: #include <ufs/ufs/dir.h>
72: #include <lib/libkern/libkern.h>
73:
74: #include "stand.h"
75: #include "ufs.h"
76:
77: /*
78: * In-core open file.
79: */
80: struct file {
81: off_t f_seekp; /* seek pointer */
82: struct fs *f_fs; /* pointer to super-block */
83: struct ufs1_dinode f_di; /* copy of on-disk inode */
84: int f_nindir[NIADDR];
85: /* number of blocks mapped by
86: indirect block at level i */
87: char *f_blk[NIADDR]; /* buffer for indirect block at
88: level i */
89: size_t f_blksize[NIADDR];
90: /* size of buffer */
91: daddr_t f_blkno[NIADDR];/* disk address of block in buffer */
92: char *f_buf; /* buffer for data block */
93: size_t f_buf_size; /* size of data block */
94: daddr_t f_buf_blkno; /* block number of data block */
95: };
96:
97: static int read_inode(ino_t, struct open_file *);
98: static int block_map(struct open_file *, daddr_t, daddr_t *);
99: static int buf_read_file(struct open_file *, char **, size_t *);
100: static int search_directory(char *, struct open_file *, ino_t *);
101: #ifdef COMPAT_UFS
102: static void ffs_oldfscompat(struct fs *);
103: #endif
104:
105: /*
106: * Read a new inode into a file structure.
107: */
108: static int
109: read_inode(ino_t inumber, struct open_file *f)
110: {
111: struct file *fp = (struct file *)f->f_fsdata;
112: struct fs *fs = fp->f_fs;
113: char *buf;
114: size_t rsize;
115: int rc;
116:
117: /*
118: * Read inode and save it.
119: */
120: buf = alloc(fs->fs_bsize);
121: twiddle();
122: rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
123: fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
124: buf, &rsize);
125: if (rc)
126: goto out;
127: if (rsize != (size_t)fs->fs_bsize) {
128: rc = EIO;
129: goto out;
130: }
131:
132: {
133: struct ufs1_dinode *dp;
134:
135: dp = (struct ufs1_dinode *)buf;
136: fp->f_di = dp[ino_to_fsbo(fs, inumber)];
137: }
138:
139: /*
140: * Clear out the old buffers
141: */
142: {
143: int level;
144:
145: for (level = 0; level < NIADDR; level++)
146: fp->f_blkno[level] = -1;
147: fp->f_buf_blkno = -1;
148: fp->f_seekp = 0;
149: }
150: out:
151: free(buf, fs->fs_bsize);
152: return (rc);
153: }
154:
155: /*
156: * Given an offset in a file, find the disk block number that
157: * contains that block.
158: */
159: static int
160: block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p)
161: {
162: struct file *fp = (struct file *)f->f_fsdata;
163: daddr_t ind_block_num, *ind_p;
164: struct fs *fs = fp->f_fs;
165: int level, idx, rc;
166:
167: /*
168: * Index structure of an inode:
169: *
170: * di_db[0..NDADDR-1] hold block numbers for blocks
171: * 0..NDADDR-1
172: *
173: * di_ib[0] index block 0 is the single indirect block
174: * holds block numbers for blocks
175: * NDADDR .. NDADDR + NINDIR(fs)-1
176: *
177: * di_ib[1] index block 1 is the double indirect block
178: * holds block numbers for INDEX blocks for blocks
179: * NDADDR + NINDIR(fs) ..
180: * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
181: *
182: * di_ib[2] index block 2 is the triple indirect block
183: * holds block numbers for double-indirect
184: * blocks for blocks
185: * NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
186: * NDADDR + NINDIR(fs) + NINDIR(fs)**2
187: * + NINDIR(fs)**3 - 1
188: */
189:
190: if (file_block < NDADDR) {
191: /* Direct block. */
192: *disk_block_p = fp->f_di.di_db[file_block];
193: return (0);
194: }
195:
196: file_block -= NDADDR;
197:
198: /*
199: * nindir[0] = NINDIR
200: * nindir[1] = NINDIR**2
201: * nindir[2] = NINDIR**3
202: * etc
203: */
204: for (level = 0; level < NIADDR; level++) {
205: if (file_block < fp->f_nindir[level])
206: break;
207: file_block -= fp->f_nindir[level];
208: }
209: if (level == NIADDR) {
210: /* Block number too high */
211: return (EFBIG);
212: }
213:
214: ind_block_num = fp->f_di.di_ib[level];
215:
216: for (; level >= 0; level--) {
217: if (ind_block_num == 0) {
218: *disk_block_p = 0; /* missing */
219: return (0);
220: }
221:
222: if (fp->f_blkno[level] != ind_block_num) {
223: if (fp->f_blk[level] == (char *)0)
224: fp->f_blk[level] =
225: alloc(fs->fs_bsize);
226: twiddle();
227: rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
228: fsbtodb(fp->f_fs, ind_block_num), fs->fs_bsize,
229: fp->f_blk[level], &fp->f_blksize[level]);
230: if (rc)
231: return (rc);
232: if (fp->f_blksize[level] != (size_t)fs->fs_bsize)
233: return (EIO);
234: fp->f_blkno[level] = ind_block_num;
235: }
236:
237: ind_p = (daddr_t *)fp->f_blk[level];
238:
239: if (level > 0) {
240: idx = file_block / fp->f_nindir[level - 1];
241: file_block %= fp->f_nindir[level - 1];
242: } else
243: idx = file_block;
244:
245: ind_block_num = ind_p[idx];
246: }
247:
248: *disk_block_p = ind_block_num;
249: return (0);
250: }
251:
252: /*
253: * Read a portion of a file into an internal buffer. Return
254: * the location in the buffer and the amount in the buffer.
255: */
256: static int
257: buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
258: {
259: struct file *fp = (struct file *)f->f_fsdata;
260: struct fs *fs = fp->f_fs;
261: daddr_t file_block, disk_block;
262: size_t block_size;
263: long off;
264: int rc;
265:
266: off = blkoff(fs, fp->f_seekp);
267: file_block = lblkno(fs, fp->f_seekp);
268: block_size = dblksize(fs, &fp->f_di, file_block);
269:
270: if (file_block != fp->f_buf_blkno) {
271: rc = block_map(f, file_block, &disk_block);
272: if (rc)
273: return (rc);
274:
275: if (fp->f_buf == (char *)0)
276: fp->f_buf = alloc(fs->fs_bsize);
277:
278: if (disk_block == 0) {
279: bzero(fp->f_buf, block_size);
280: fp->f_buf_size = block_size;
281: } else {
282: twiddle();
283: rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
284: fsbtodb(fs, disk_block),
285: block_size, fp->f_buf, &fp->f_buf_size);
286: if (rc)
287: return (rc);
288: }
289:
290: fp->f_buf_blkno = file_block;
291: }
292:
293: /*
294: * Return address of byte in buffer corresponding to
295: * offset, and size of remainder of buffer after that
296: * byte.
297: */
298: *buf_p = fp->f_buf + off;
299: *size_p = block_size - off;
300:
301: /*
302: * But truncate buffer at end of file.
303: */
304: if (*size_p > fp->f_di.di_size - fp->f_seekp)
305: *size_p = fp->f_di.di_size - fp->f_seekp;
306:
307: return (0);
308: }
309:
310: /*
311: * Search a directory for a name and return its
312: * i_number.
313: */
314: static int
315: search_directory(char *name, struct open_file *f, ino_t *inumber_p)
316: {
317: struct file *fp = (struct file *)f->f_fsdata;
318: int namlen, length, rc;
319: struct direct *dp, *edp;
320: size_t buf_size;
321: char *buf;
322:
323: length = strlen(name);
324:
325: fp->f_seekp = 0;
326: while (fp->f_seekp < fp->f_di.di_size) {
327: rc = buf_read_file(f, &buf, &buf_size);
328: if (rc)
329: return (rc);
330:
331: dp = (struct direct *)buf;
332: edp = (struct direct *)(buf + buf_size);
333: while (dp < edp) {
334: if (dp->d_ino == (ino_t)0)
335: goto next;
336: #if BYTE_ORDER == LITTLE_ENDIAN
337: if (fp->f_fs->fs_maxsymlinklen <= 0)
338: namlen = dp->d_type;
339: else
340: #endif
341: namlen = dp->d_namlen;
342: if (namlen == length &&
343: !strcmp(name, dp->d_name)) {
344: /* found entry */
345: *inumber_p = dp->d_ino;
346: return (0);
347: }
348: next:
349: dp = (struct direct *)((char *)dp + dp->d_reclen);
350: }
351: fp->f_seekp += buf_size;
352: }
353: return (ENOENT);
354: }
355:
356: /*
357: * Open a file.
358: */
359: int
360: ufs_open(char *path, struct open_file *f)
361: {
362: char namebuf[MAXPATHLEN+1], *cp, *ncp, *buf = NULL;
363: ino_t inumber, parent_inumber;
364: int rc, c, nlinks = 0;
365: struct file *fp;
366: size_t buf_size;
367: struct fs *fs;
368:
369: /* allocate file system specific data structure */
370: fp = alloc(sizeof(struct file));
371: bzero(fp, sizeof(struct file));
372: f->f_fsdata = (void *)fp;
373:
374: /* allocate space and read super block */
375: fs = alloc(SBSIZE);
376: fp->f_fs = fs;
377: twiddle();
378: rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
379: SBLOCK, SBSIZE, (char *)fs, &buf_size);
380: if (rc)
381: goto out;
382:
383: if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
384: fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
385: rc = EINVAL;
386: goto out;
387: }
388: #ifdef COMPAT_UFS
389: ffs_oldfscompat(fs);
390: #endif
391:
392: /*
393: * Calculate indirect block levels.
394: */
395: {
396: int mult;
397: int level;
398:
399: mult = 1;
400: for (level = 0; level < NIADDR; level++) {
401: mult *= NINDIR(fs);
402: fp->f_nindir[level] = mult;
403: }
404: }
405:
406: inumber = ROOTINO;
407: if ((rc = read_inode(inumber, f)) != 0)
408: goto out;
409:
410: cp = path;
411: while (*cp) {
412:
413: /*
414: * Remove extra separators
415: */
416: while (*cp == '/')
417: cp++;
418: if (*cp == '\0')
419: break;
420:
421: /*
422: * Check that current node is a directory.
423: */
424: if ((fp->f_di.di_mode & IFMT) != IFDIR) {
425: rc = ENOTDIR;
426: goto out;
427: }
428:
429: /*
430: * Get next component of path name.
431: */
432: {
433: int len = 0;
434:
435: ncp = cp;
436: while ((c = *cp) != '\0' && c != '/') {
437: if (++len > MAXNAMLEN) {
438: rc = ENOENT;
439: goto out;
440: }
441: cp++;
442: }
443: *cp = '\0';
444: }
445:
446: /*
447: * Look up component in current directory.
448: * Save directory inumber in case we find a
449: * symbolic link.
450: */
451: parent_inumber = inumber;
452: rc = search_directory(ncp, f, &inumber);
453: *cp = c;
454: if (rc)
455: goto out;
456:
457: /*
458: * Open next component.
459: */
460: if ((rc = read_inode(inumber, f)) != 0)
461: goto out;
462:
463: /*
464: * Check for symbolic link.
465: */
466: if ((fp->f_di.di_mode & IFMT) == IFLNK) {
467: int link_len = fp->f_di.di_size;
468: int len;
469:
470: len = strlen(cp);
471:
472: if (link_len + len > MAXPATHLEN ||
473: ++nlinks > MAXSYMLINKS) {
474: rc = ENOENT;
475: goto out;
476: }
477:
478: bcopy(cp, &namebuf[link_len], len + 1);
479:
480: if (link_len < fs->fs_maxsymlinklen) {
481: bcopy(fp->f_di.di_shortlink, namebuf,
482: (unsigned) link_len);
483: } else {
484: /*
485: * Read file for symbolic link
486: */
487: size_t buf_size;
488: daddr_t disk_block;
489: struct fs *fs = fp->f_fs;
490:
491: if (!buf)
492: buf = alloc(fs->fs_bsize);
493: rc = block_map(f, (daddr_t)0, &disk_block);
494: if (rc)
495: goto out;
496:
497: twiddle();
498: rc = (f->f_dev->dv_strategy)(f->f_devdata,
499: F_READ, fsbtodb(fs, disk_block),
500: fs->fs_bsize, buf, &buf_size);
501: if (rc)
502: goto out;
503:
504: bcopy((char *)buf, namebuf, (unsigned)link_len);
505: }
506:
507: /*
508: * If relative pathname, restart at parent directory.
509: * If absolute pathname, restart at root.
510: */
511: cp = namebuf;
512: if (*cp != '/')
513: inumber = parent_inumber;
514: else
515: inumber = (ino_t)ROOTINO;
516:
517: if ((rc = read_inode(inumber, f)) != 0)
518: goto out;
519: }
520: }
521:
522: /*
523: * Found terminal component.
524: */
525: rc = 0;
526: out:
527: if (buf)
528: free(buf, fs->fs_bsize);
529: if (rc) {
530: free(fp->f_fs, SBSIZE);
531: free(fp, sizeof(struct file));
532: }
533: return (rc);
534: }
535:
536: int
537: ufs_close(struct open_file *f)
538: {
539: struct file *fp = (struct file *)f->f_fsdata;
540: int level;
541:
542: f->f_fsdata = (void *)0;
543: if (fp == (struct file *)0)
544: return (0);
545:
546: for (level = 0; level < NIADDR; level++) {
547: if (fp->f_blk[level])
548: free(fp->f_blk[level], fp->f_fs->fs_bsize);
549: }
550: if (fp->f_buf)
551: free(fp->f_buf, fp->f_fs->fs_bsize);
552: free(fp->f_fs, SBSIZE);
553: free(fp, sizeof(struct file));
554: return (0);
555: }
556:
557: /*
558: * Copy a portion of a file into kernel memory.
559: * Cross block boundaries when necessary.
560: */
561: int
562: ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
563: {
564: struct file *fp = (struct file *)f->f_fsdata;
565: char *buf, *addr = start;
566: size_t csize, buf_size;
567: int rc = 0;
568:
569: while (size != 0) {
570: if (fp->f_seekp >= fp->f_di.di_size)
571: break;
572:
573: rc = buf_read_file(f, &buf, &buf_size);
574: if (rc)
575: break;
576:
577: csize = size;
578: if (csize > buf_size)
579: csize = buf_size;
580:
581: bcopy(buf, addr, csize);
582:
583: fp->f_seekp += csize;
584: addr += csize;
585: size -= csize;
586: }
587: if (resid)
588: *resid = size;
589: return (rc);
590: }
591:
592: /*
593: * Not implemented.
594: */
595: int
596: ufs_write(struct open_file *f, void *start, size_t size, size_t *resid)
597: {
598:
599: return (EROFS);
600: }
601:
602: off_t
603: ufs_seek(struct open_file *f, off_t offset, int where)
604: {
605: struct file *fp = (struct file *)f->f_fsdata;
606:
607: switch (where) {
608: case SEEK_SET:
609: fp->f_seekp = offset;
610: break;
611: case SEEK_CUR:
612: fp->f_seekp += offset;
613: break;
614: case SEEK_END:
615: fp->f_seekp = fp->f_di.di_size - offset;
616: break;
617: default:
618: return (-1);
619: }
620: return (fp->f_seekp);
621: }
622:
623: int
624: ufs_stat(struct open_file *f, struct stat *sb)
625: {
626: struct file *fp = (struct file *)f->f_fsdata;
627:
628: /* only important stuff */
629: sb->st_mode = fp->f_di.di_mode;
630: sb->st_uid = fp->f_di.di_uid;
631: sb->st_gid = fp->f_di.di_gid;
632: sb->st_size = fp->f_di.di_size;
633: return (0);
634: }
635:
636: #ifndef NO_READDIR
637: int
638: ufs_readdir(struct open_file *f, char *name)
639: {
640: struct file *fp = (struct file *)f->f_fsdata;
641: struct direct *dp, *edp;
642: size_t buf_size;
643: int rc, namlen;
644: char *buf;
645:
646: if (name == NULL)
647: fp->f_seekp = 0;
648: else {
649: /* end of dir */
650: if (fp->f_seekp >= fp->f_di.di_size) {
651: *name = '\0';
652: return -1;
653: }
654:
655: do {
656: if ((rc = buf_read_file(f, &buf, &buf_size)) != 0)
657: return rc;
658:
659: dp = (struct direct *)buf;
660: edp = (struct direct *)(buf + buf_size);
661: while (dp < edp && dp->d_ino == (ino_t)0)
662: dp = (struct direct *)((char *)dp + dp->d_reclen);
663: fp->f_seekp += buf_size -
664: ((u_int8_t *)edp - (u_int8_t *)dp);
665: } while (dp >= edp);
666:
667: #if BYTE_ORDER == LITTLE_ENDIAN
668: if (fp->f_fs->fs_maxsymlinklen <= 0)
669: namlen = dp->d_type;
670: else
671: #endif
672: namlen = dp->d_namlen;
673: strncpy(name, dp->d_name, namlen + 1);
674:
675: fp->f_seekp += dp->d_reclen;
676: }
677:
678: return 0;
679: }
680: #endif
681:
682: #ifdef COMPAT_UFS
683: /*
684: * Sanity checks for old file systems.
685: *
686: * XXX - goes away some day.
687: */
688: static void
689: ffs_oldfscompat(struct fs *fs)
690: {
691: int i;
692:
693: fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */
694: fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */
695: if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
696: fs->fs_nrpos = 8; /* XXX */
697: if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
698: quad_t sizepb = fs->fs_bsize; /* XXX */
699: /* XXX */
700: fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */
701: for (i = 0; i < NIADDR; i++) { /* XXX */
702: sizepb *= NINDIR(fs); /* XXX */
703: fs->fs_maxfilesize += sizepb; /* XXX */
704: } /* XXX */
705: fs->fs_qbmask = ~fs->fs_bmask; /* XXX */
706: fs->fs_qfmask = ~fs->fs_fmask; /* XXX */
707: } /* XXX */
708: }
709: #endif
CVSweb