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