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