1 /* $OpenBSD: ufs.c,v 1.19 2008/01/06 11:17:18 otto 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 <sys/slibkern.h>
70 #include <ufs/ffs/fs.h>
71 #include <ufs/ufs/dinode.h>
72 #include <ufs/ufs/dir.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
read_inode(ino_t inumber,struct open_file * f)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, (daddr_t)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
block_map(struct open_file * f,daddr_t file_block,daddr_t * disk_block_p)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
buf_read_file(struct open_file * f,char ** buf_p,size_t * size_p)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
search_directory(char * name,struct open_file * f,ino_t * inumber_p)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
ufs_open(char * path,struct open_file * f)360 ufs_open(char *path, struct open_file *f)
361 {
362 char *namebuf, *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 namebuf = alloc(MAXPATHLEN + 1);
370
371 /* allocate file system specific data structure */
372 fp = alloc(sizeof(struct file));
373 bzero(fp, sizeof(struct file));
374 f->f_fsdata = (void *)fp;
375
376 /* allocate space and read super block */
377 fs = alloc(SBSIZE);
378 fp->f_fs = fs;
379 twiddle();
380 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
381 SBLOCK, SBSIZE, (char *)fs, &buf_size);
382 if (rc)
383 goto out;
384
385 if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
386 fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
387 rc = EINVAL;
388 goto out;
389 }
390 #ifdef COMPAT_UFS
391 ffs_oldfscompat(fs);
392 #endif
393
394 /*
395 * Calculate indirect block levels.
396 */
397 {
398 int mult;
399 int level;
400
401 mult = 1;
402 for (level = 0; level < NIADDR; level++) {
403 mult *= NINDIR(fs);
404 fp->f_nindir[level] = mult;
405 }
406 }
407
408 inumber = ROOTINO;
409 if ((rc = read_inode(inumber, f)) != 0)
410 goto out;
411
412 cp = path;
413 while (*cp) {
414
415 /*
416 * Remove extra separators
417 */
418 while (*cp == '/')
419 cp++;
420 if (*cp == '\0')
421 break;
422
423 /*
424 * Check that current node is a directory.
425 */
426 if ((fp->f_di.di_mode & IFMT) != IFDIR) {
427 rc = ENOTDIR;
428 goto out;
429 }
430
431 /*
432 * Get next component of path name.
433 */
434 {
435 int len = 0;
436
437 ncp = cp;
438 while ((c = *cp) != '\0' && c != '/') {
439 if (++len > MAXNAMLEN) {
440 rc = ENOENT;
441 goto out;
442 }
443 cp++;
444 }
445 *cp = '\0';
446 }
447
448 /*
449 * Look up component in current directory.
450 * Save directory inumber in case we find a
451 * symbolic link.
452 */
453 parent_inumber = inumber;
454 rc = search_directory(ncp, f, &inumber);
455 *cp = c;
456 if (rc)
457 goto out;
458
459 /*
460 * Open next component.
461 */
462 if ((rc = read_inode(inumber, f)) != 0)
463 goto out;
464
465 /*
466 * Check for symbolic link.
467 */
468 if ((fp->f_di.di_mode & IFMT) == IFLNK) {
469 int link_len = fp->f_di.di_size;
470 int len;
471
472 len = strlen(cp);
473
474 if (link_len + len > MAXPATHLEN ||
475 ++nlinks > MAXSYMLINKS) {
476 rc = ENOENT;
477 goto out;
478 }
479
480 bcopy(cp, &namebuf[link_len], len + 1);
481
482 if (link_len < fs->fs_maxsymlinklen) {
483 bcopy(fp->f_di.di_shortlink, namebuf,
484 (unsigned) link_len);
485 } else {
486 /*
487 * Read file for symbolic link
488 */
489 size_t buf_size;
490 daddr_t disk_block;
491 struct fs *fs = fp->f_fs;
492
493 if (!buf)
494 buf = alloc(fs->fs_bsize);
495 rc = block_map(f, (daddr_t)0, &disk_block);
496 if (rc)
497 goto out;
498
499 twiddle();
500 rc = (f->f_dev->dv_strategy)(f->f_devdata,
501 F_READ, fsbtodb(fs, disk_block),
502 fs->fs_bsize, buf, &buf_size);
503 if (rc)
504 goto out;
505
506 bcopy((char *)buf, namebuf, (unsigned)link_len);
507 }
508
509 /*
510 * If relative pathname, restart at parent directory.
511 * If absolute pathname, restart at root.
512 */
513 cp = namebuf;
514 if (*cp != '/')
515 inumber = parent_inumber;
516 else
517 inumber = (ino_t)ROOTINO;
518
519 if ((rc = read_inode(inumber, f)) != 0)
520 goto out;
521 }
522 }
523
524 /*
525 * Found terminal component.
526 */
527 rc = 0;
528 out:
529 if (buf)
530 free(buf, fs->fs_bsize);
531 if (rc) {
532 free(fp->f_fs, SBSIZE);
533 free(fp, sizeof(struct file));
534 }
535 free(namebuf, MAXPATHLEN + 1);
536 return (rc);
537 }
538
539 int
ufs_close(struct open_file * f)540 ufs_close(struct open_file *f)
541 {
542 struct file *fp = (struct file *)f->f_fsdata;
543 int level;
544
545 f->f_fsdata = (void *)0;
546 if (fp == (struct file *)0)
547 return (0);
548
549 for (level = 0; level < NIADDR; level++) {
550 if (fp->f_blk[level])
551 free(fp->f_blk[level], fp->f_fs->fs_bsize);
552 }
553 if (fp->f_buf)
554 free(fp->f_buf, fp->f_fs->fs_bsize);
555 free(fp->f_fs, SBSIZE);
556 free(fp, sizeof(struct file));
557 return (0);
558 }
559
560 /*
561 * Copy a portion of a file into kernel memory.
562 * Cross block boundaries when necessary.
563 */
564 int
ufs_read(struct open_file * f,void * start,size_t size,size_t * resid)565 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
566 {
567 struct file *fp = (struct file *)f->f_fsdata;
568 char *buf, *addr = start;
569 size_t csize, buf_size;
570 int rc = 0;
571
572 while (size != 0) {
573 if (fp->f_seekp >= fp->f_di.di_size)
574 break;
575
576 rc = buf_read_file(f, &buf, &buf_size);
577 if (rc)
578 break;
579
580 csize = size;
581 if (csize > buf_size)
582 csize = buf_size;
583
584 bcopy(buf, addr, csize);
585
586 fp->f_seekp += csize;
587 addr += csize;
588 size -= csize;
589 }
590 if (resid)
591 *resid = size;
592 return (rc);
593 }
594
595 /*
596 * Not implemented.
597 */
598 int
ufs_write(struct open_file * f,void * start,size_t size,size_t * resid)599 ufs_write(struct open_file *f, void *start, size_t size, size_t *resid)
600 {
601
602 return (EROFS);
603 }
604
605 off_t
ufs_seek(struct open_file * f,off_t offset,int where)606 ufs_seek(struct open_file *f, off_t offset, int where)
607 {
608 struct file *fp = (struct file *)f->f_fsdata;
609
610 switch (where) {
611 case SEEK_SET:
612 fp->f_seekp = offset;
613 break;
614 case SEEK_CUR:
615 fp->f_seekp += offset;
616 break;
617 case SEEK_END:
618 fp->f_seekp = fp->f_di.di_size + offset;
619 break;
620 default:
621 return (-1);
622 }
623 return (fp->f_seekp);
624 }
625
626 int
ufs_stat(struct open_file * f,struct stat * sb)627 ufs_stat(struct open_file *f, struct stat *sb)
628 {
629 struct file *fp = (struct file *)f->f_fsdata;
630
631 /* only important stuff */
632 sb->st_mode = fp->f_di.di_mode;
633 sb->st_uid = fp->f_di.di_uid;
634 sb->st_gid = fp->f_di.di_gid;
635 sb->st_size = fp->f_di.di_size;
636 return (0);
637 }
638
639 #ifndef NO_READDIR
640 int
ufs_readdir(struct open_file * f,char * name)641 ufs_readdir(struct open_file *f, char *name)
642 {
643 struct file *fp = (struct file *)f->f_fsdata;
644 struct direct *dp, *edp;
645 size_t buf_size;
646 int rc, namlen;
647 char *buf;
648
649 if (name == NULL)
650 fp->f_seekp = 0;
651 else {
652 /* end of dir */
653 if (fp->f_seekp >= fp->f_di.di_size) {
654 *name = '\0';
655 return -1;
656 }
657
658 do {
659 if ((rc = buf_read_file(f, &buf, &buf_size)) != 0)
660 return rc;
661
662 dp = (struct direct *)buf;
663 edp = (struct direct *)(buf + buf_size);
664 while (dp < edp && dp->d_ino == (ino_t)0)
665 dp = (struct direct *)((char *)dp + dp->d_reclen);
666 fp->f_seekp += buf_size -
667 ((u_int8_t *)edp - (u_int8_t *)dp);
668 } while (dp >= edp);
669
670 #if BYTE_ORDER == LITTLE_ENDIAN
671 if (fp->f_fs->fs_maxsymlinklen <= 0)
672 namlen = dp->d_type;
673 else
674 #endif
675 namlen = dp->d_namlen;
676 strncpy(name, dp->d_name, namlen + 1);
677
678 fp->f_seekp += dp->d_reclen;
679 }
680
681 return 0;
682 }
683 #endif
684
685 #ifdef COMPAT_UFS
686 /*
687 * Sanity checks for old file systems.
688 *
689 * XXX - goes away some day.
690 */
691 static void
ffs_oldfscompat(struct fs * fs)692 ffs_oldfscompat(struct fs *fs)
693 {
694 int i;
695
696 fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */
697 fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */
698 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
699 fs->fs_nrpos = 8; /* XXX */
700 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
701 quad_t sizepb = fs->fs_bsize; /* XXX */
702 /* XXX */
703 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */
704 for (i = 0; i < NIADDR; i++) { /* XXX */
705 sizepb *= NINDIR(fs); /* XXX */
706 fs->fs_maxfilesize += sizepb; /* XXX */
707 } /* XXX */
708 fs->fs_qbmask = ~fs->fs_bmask; /* XXX */
709 fs->fs_qfmask = ~fs->fs_fmask; /* XXX */
710 } /* XXX */
711 }
712 #endif
713