ufs.c revision 1.33 1 /* $NetBSD: ufs.c,v 1.33 2003/04/02 10:39:34 fvdl 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 * XXX NOTE: ufs.c (FFS) and lfs.c (LFS) should eventually use much common
67 * XXX code. until then, the two files should be easily diffable.
68 */
69
70 /*
71 * Stand-alone file reading package.
72 */
73
74 #include <sys/param.h>
75 #include <sys/time.h>
76 #include <ufs/ufs/dinode.h>
77 #include <ufs/ufs/dir.h>
78 #include <ufs/ffs/fs.h>
79 #ifdef _STANDALONE
80 #include <lib/libkern/libkern.h>
81 #else
82 #include <string.h>
83 #endif
84
85 #include "stand.h"
86 #include "ufs.h"
87
88 #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
89 #define LIBSA_NO_FS_SYMLINK
90 #endif
91 #if defined(COMPAT_UFS) && defined(LIBSA_NO_COMPAT_UFS)
92 #undef COMPAT_UFS
93 #endif
94
95 union dinode {
96 struct ufs1_dinode dp1;
97 #ifdef LIBSA_SUPPORT_UFS2
98 struct ufs2_dinode dp2;
99 #endif
100 };
101
102 #ifdef LIBSA_SUPPORT_UFS2
103 #define DIP(d,field) (is_ufs2 ? d.dp2.di_##field : d.dp1.di_##field)
104 #else
105 #define DIP(d,field) d.dp1.di_##field
106 #endif
107
108 /*
109 * In-core open file.
110 */
111 struct file {
112 off_t f_seekp; /* seek pointer */
113 struct fs *f_fs; /* pointer to super-block */
114 union dinode f_di; /* copy of on-disk inode */
115 unsigned int f_nindir[NIADDR];
116 /* number of blocks mapped by
117 indirect block at level i */
118 char *f_blk[NIADDR]; /* buffer for indirect block at
119 level i */
120 size_t f_blksize[NIADDR];
121 /* size of buffer */
122 daddr_t f_blkno[NIADDR];/* disk address of block in buffer */
123 char *f_buf; /* buffer for data block */
124 size_t f_buf_size; /* size of data block */
125 daddr_t f_buf_blkno; /* block number of data block */
126 };
127
128 static int read_inode __P((ino_t, struct open_file *));
129 static int block_map __P((struct open_file *, daddr_t, daddr_t *));
130 static int buf_read_file __P((struct open_file *, char **, size_t *));
131 static int search_directory __P((char *, struct open_file *, ino_t *));
132 static void ffs_oldfscompat __P((struct fs *));
133
134 #ifdef LIBSA_SUPPORT_UFS2
135 static int is_ufs2;
136 static int ffs_find_superblock __P((struct open_file *, struct fs *));
137 #endif
138
139 /*
140 * Read a new inode into a file structure.
141 */
142 static int
143 read_inode(inumber, f)
144 ino_t inumber;
145 struct open_file *f;
146 {
147 struct file *fp = (struct file *)f->f_fsdata;
148 struct fs *fs = fp->f_fs;
149 char *buf;
150 size_t rsize;
151 int rc;
152
153 /*
154 * Read inode and save it.
155 */
156 buf = alloc(fs->fs_bsize);
157 #if !defined(LIBSA_NO_TWIDDLE)
158 twiddle();
159 #endif
160 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
161 fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
162 buf, &rsize);
163 if (rc)
164 goto out;
165 if (rsize != fs->fs_bsize) {
166 rc = EIO;
167 goto out;
168 }
169
170 {
171 struct ufs1_dinode *dp1;
172 #ifdef LIBSA_SUPPORT_UFS2
173 struct ufs2_dinode *dp2;
174
175 if (is_ufs2) {
176 dp2 = (struct ufs2_dinode *)buf;
177 fp->f_di.dp2 = dp2[ino_to_fsbo(fs, inumber)];
178 } else
179 #endif
180 {
181 dp1 = (struct ufs1_dinode *)buf;
182 fp->f_di.dp1 = dp1[ino_to_fsbo(fs, inumber)];
183 }
184 }
185
186 /*
187 * Clear out the old buffers
188 */
189 {
190 int level;
191
192 for (level = 0; level < NIADDR; level++)
193 fp->f_blkno[level] = -1;
194 fp->f_buf_blkno = -1;
195 }
196 out:
197 free(buf, fs->fs_bsize);
198 return (rc);
199 }
200
201 /*
202 * Given an offset in a file, find the disk block number that
203 * contains that block.
204 */
205 static int
206 block_map(f, file_block, disk_block_p)
207 struct open_file *f;
208 daddr_t file_block;
209 daddr_t *disk_block_p; /* out */
210 {
211 struct file *fp = (struct file *)f->f_fsdata;
212 struct fs *fs = fp->f_fs;
213 int level;
214 int idx;
215 daddr_t ind_block_num;
216 int32_t *ind_p32 = NULL;
217 #ifdef LIBSA_SUPPORT_UFS2
218 int64_t *ind_p64 = NULL;
219 #endif
220 int rc;
221
222 /*
223 * Index structure of an inode:
224 *
225 * di_db[0..NDADDR-1] hold block numbers for blocks
226 * 0..NDADDR-1
227 *
228 * di_ib[0] index block 0 is the single indirect block
229 * holds block numbers for blocks
230 * NDADDR .. NDADDR + NINDIR(fs)-1
231 *
232 * di_ib[1] index block 1 is the double indirect block
233 * holds block numbers for INDEX blocks for blocks
234 * NDADDR + NINDIR(fs) ..
235 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
236 *
237 * di_ib[2] index block 2 is the triple indirect block
238 * holds block numbers for double-indirect
239 * blocks for blocks
240 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
241 * NDADDR + NINDIR(fs) + NINDIR(fs)**2
242 * + NINDIR(fs)**3 - 1
243 */
244
245 if (file_block < NDADDR) {
246 /* Direct block. */
247 *disk_block_p = DIP(fp->f_di, db[file_block]);
248 return (0);
249 }
250
251 file_block -= NDADDR;
252
253 /*
254 * nindir[0] = NINDIR
255 * nindir[1] = NINDIR**2
256 * nindir[2] = NINDIR**3
257 * etc
258 */
259 for (level = 0; level < NIADDR; level++) {
260 if (file_block < fp->f_nindir[level])
261 break;
262 file_block -= fp->f_nindir[level];
263 }
264 if (level == NIADDR) {
265 /* Block number too high */
266 return (EFBIG);
267 }
268
269 ind_block_num = DIP(fp->f_di, ib[level]);
270
271 for (; level >= 0; level--) {
272 if (ind_block_num == 0) {
273 *disk_block_p = 0; /* missing */
274 return (0);
275 }
276
277 if (fp->f_blkno[level] != ind_block_num) {
278 if (fp->f_blk[level] == (char *)0)
279 fp->f_blk[level] =
280 alloc(fs->fs_bsize);
281 #if !defined(LIBSA_NO_TWIDDLE)
282 twiddle();
283 #endif
284 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
285 fsbtodb(fp->f_fs, ind_block_num),
286 fs->fs_bsize,
287 fp->f_blk[level],
288 &fp->f_blksize[level]);
289 if (rc)
290 return (rc);
291 if (fp->f_blksize[level] != fs->fs_bsize)
292 return (EIO);
293 fp->f_blkno[level] = ind_block_num;
294 }
295
296 #ifdef LIBSA_SUPPORT_UFS2
297 if (is_ufs2)
298 ind_p64 = (int64_t *)fp->f_blk[level];
299 else
300 #endif
301 ind_p32 = (int32_t *)fp->f_blk[level];
302
303 if (level > 0) {
304 idx = file_block / fp->f_nindir[level - 1];
305 file_block %= fp->f_nindir[level - 1];
306 } else
307 idx = file_block;
308
309 #ifdef LIBSA_SUPPORT_UFS2
310 if (is_ufs2)
311 ind_block_num = ind_p64[idx];
312 else
313 #endif
314 ind_block_num = ind_p32[idx];
315 }
316
317 *disk_block_p = ind_block_num;
318
319 return (0);
320 }
321
322 /*
323 * Read a portion of a file into an internal buffer. Return
324 * the location in the buffer and the amount in the buffer.
325 */
326 static int
327 buf_read_file(f, buf_p, size_p)
328 struct open_file *f;
329 char **buf_p; /* out */
330 size_t *size_p; /* out */
331 {
332 struct file *fp = (struct file *)f->f_fsdata;
333 struct fs *fs = fp->f_fs;
334 long off;
335 daddr_t file_block;
336 daddr_t disk_block;
337 size_t block_size;
338 int rc;
339
340 off = blkoff(fs, fp->f_seekp);
341 file_block = lblkno(fs, fp->f_seekp);
342 block_size = sblksize(fs, DIP(fp->f_di, size), file_block);
343
344 if (file_block != fp->f_buf_blkno) {
345 rc = block_map(f, file_block, &disk_block);
346 if (rc)
347 return (rc);
348
349 if (fp->f_buf == (char *)0)
350 fp->f_buf = alloc(fs->fs_bsize);
351
352 if (disk_block == 0) {
353 bzero(fp->f_buf, block_size);
354 fp->f_buf_size = block_size;
355 } else {
356 #if !defined(LIBSA_NO_TWIDDLE)
357 twiddle();
358 #endif
359 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
360 fsbtodb(fs, disk_block),
361 block_size, fp->f_buf, &fp->f_buf_size);
362 if (rc)
363 return (rc);
364 }
365
366 fp->f_buf_blkno = file_block;
367 }
368
369 /*
370 * Return address of byte in buffer corresponding to
371 * offset, and size of remainder of buffer after that
372 * byte.
373 */
374 *buf_p = fp->f_buf + off;
375 *size_p = block_size - off;
376
377 /*
378 * But truncate buffer at end of file.
379 */
380 if (*size_p > DIP(fp->f_di, size) - fp->f_seekp)
381 *size_p = DIP(fp->f_di, size) - fp->f_seekp;
382
383 return (0);
384 }
385
386 /*
387 * Search a directory for a name and return its
388 * i_number.
389 */
390 static int
391 search_directory(name, f, inumber_p)
392 char *name;
393 struct open_file *f;
394 ino_t *inumber_p; /* out */
395 {
396 struct file *fp = (struct file *)f->f_fsdata;
397 struct direct *dp;
398 struct direct *edp;
399 char *buf;
400 size_t buf_size;
401 int namlen, length;
402 int rc;
403
404 length = strlen(name);
405
406 fp->f_seekp = 0;
407 while (fp->f_seekp < DIP(fp->f_di, size)) {
408 rc = buf_read_file(f, &buf, &buf_size);
409 if (rc)
410 return (rc);
411
412 dp = (struct direct *)buf;
413 edp = (struct direct *)(buf + buf_size);
414 while (dp < edp) {
415 if (dp->d_ino == (ino_t)0)
416 goto next;
417 #if BYTE_ORDER == LITTLE_ENDIAN
418 if (fp->f_fs->fs_maxsymlinklen <= 0)
419 namlen = dp->d_type;
420 else
421 #endif
422 namlen = dp->d_namlen;
423 if (namlen == length &&
424 !strcmp(name, dp->d_name)) {
425 /* found entry */
426 *inumber_p = dp->d_ino;
427 return (0);
428 }
429 next:
430 dp = (struct direct *)((char *)dp + dp->d_reclen);
431 }
432 fp->f_seekp += buf_size;
433 }
434 return (ENOENT);
435 }
436
437 #ifdef LIBSA_SUPPORT_UFS2
438
439 daddr_t sblock_try[] = SBLOCKSEARCH;
440
441 static int
442 ffs_find_superblock(f, fs)
443 struct open_file *f;
444 struct fs *fs;
445 {
446 int i, rc;
447 size_t buf_size;
448
449 for (i = 0; sblock_try[i] != -1; i++) {
450 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
451 sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, (char *)fs,
452 &buf_size);
453 if (rc != 0 || buf_size != SBLOCKSIZE)
454 return rc;
455 if (fs->fs_magic == FS_UFS1_MAGIC) {
456 is_ufs2 = 0;
457 return 0;
458 }
459 if (fs->fs_magic == FS_UFS2_MAGIC) {
460 is_ufs2 = 1;
461 return 0;
462 }
463 }
464 return EINVAL;
465 }
466
467 #endif
468
469 /*
470 * Open a file.
471 */
472 int
473 ufs_open(path, f)
474 char *path;
475 struct open_file *f;
476 {
477 #ifndef LIBSA_FS_SINGLECOMPONENT
478 char *cp, *ncp;
479 int c;
480 #endif
481 ino_t inumber;
482 struct file *fp;
483 struct fs *fs;
484 int rc;
485 #ifndef LIBSA_NO_FS_SYMLINK
486 ino_t parent_inumber;
487 int nlinks = 0;
488 char namebuf[MAXPATHLEN+1];
489 char *buf = NULL;
490 #endif
491 #ifndef LIBSA_SUPPORT_UFS2
492 size_t buf_size;
493 #endif
494
495 /* allocate file system specific data structure */
496 fp = alloc(sizeof(struct file));
497 bzero(fp, sizeof(struct file));
498 f->f_fsdata = (void *)fp;
499
500 /* allocate space and read super block */
501 fs = alloc(SBLOCKSIZE);
502 fp->f_fs = fs;
503 #if !defined(LIBSA_NO_TWIDDLE)
504 twiddle();
505 #endif
506
507 #ifdef LIBSA_SUPPORT_UFS2
508 rc = ffs_find_superblock(f, fs);
509 if (rc)
510 goto out;
511 #else
512 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
513 SBLOCK_UFS1 / DEV_BSIZE, SBLOCKSIZE, (char *)fs, &buf_size);
514 if (rc)
515 goto out;
516 if (buf_size != SBLOCKSIZE || fs->fs_magic != FS_UFS1_MAGIC) {
517 rc = EINVAL;
518 goto out;
519 }
520 #endif
521
522 ffs_oldfscompat(fs);
523
524 if (fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
525 rc = EINVAL;
526 goto out;
527 }
528
529 /*
530 * Calculate indirect block levels.
531 */
532 {
533 int mult;
534 int level;
535
536 mult = 1;
537 for (level = 0; level < NIADDR; level++) {
538 mult *= NINDIR(fs);
539 fp->f_nindir[level] = mult;
540 }
541 }
542
543 inumber = ROOTINO;
544 if ((rc = read_inode(inumber, f)) != 0)
545 goto out;
546
547 #ifndef LIBSA_FS_SINGLECOMPONENT
548 cp = path;
549 while (*cp) {
550
551 /*
552 * Remove extra separators
553 */
554 while (*cp == '/')
555 cp++;
556 if (*cp == '\0')
557 break;
558
559 /*
560 * Check that current node is a directory.
561 */
562 if ((DIP(fp->f_di, mode) & IFMT) != IFDIR) {
563 rc = ENOTDIR;
564 goto out;
565 }
566
567 /*
568 * Get next component of path name.
569 */
570 {
571 int len = 0;
572
573 ncp = cp;
574 while ((c = *cp) != '\0' && c != '/') {
575 if (++len > MAXNAMLEN) {
576 rc = ENOENT;
577 goto out;
578 }
579 cp++;
580 }
581 *cp = '\0';
582 }
583
584 /*
585 * Look up component in current directory.
586 * Save directory inumber in case we find a
587 * symbolic link.
588 */
589 #ifndef LIBSA_NO_FS_SYMLINK
590 parent_inumber = inumber;
591 #endif
592 rc = search_directory(ncp, f, &inumber);
593 *cp = c;
594 if (rc)
595 goto out;
596
597 /*
598 * Open next component.
599 */
600 if ((rc = read_inode(inumber, f)) != 0)
601 goto out;
602
603 #ifndef LIBSA_NO_FS_SYMLINK
604 /*
605 * Check for symbolic link.
606 */
607 if ((DIP(fp->f_di, mode) & IFMT) == IFLNK) {
608 int link_len = DIP(fp->f_di, size);
609 int len;
610
611 len = strlen(cp);
612
613 if (link_len + len > MAXPATHLEN ||
614 ++nlinks > MAXSYMLINKS) {
615 rc = ENOENT;
616 goto out;
617 }
618
619 bcopy(cp, &namebuf[link_len], len + 1);
620
621 if (link_len < fs->fs_maxsymlinklen) {
622 #ifdef LIBSA_SUPPORT_UFS2
623 if (is_ufs2)
624 bcopy(fp->f_di.dp2.di_db, namebuf,
625 (unsigned) link_len);
626 else
627 #endif
628 bcopy(fp->f_di.dp1.di_db, namebuf,
629 (unsigned) link_len);
630 } else {
631 /*
632 * Read file for symbolic link
633 */
634 size_t buf_size;
635 daddr_t disk_block;
636 struct fs *fs = fp->f_fs;
637
638 if (!buf)
639 buf = alloc(fs->fs_bsize);
640 rc = block_map(f, (daddr_t)0, &disk_block);
641 if (rc)
642 goto out;
643
644 #if !defined(LIBSA_NO_TWIDDLE)
645 twiddle();
646 #endif
647 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
648 F_READ, fsbtodb(fs, disk_block),
649 fs->fs_bsize, buf, &buf_size);
650 if (rc)
651 goto out;
652
653 bcopy((char *)buf, namebuf, (unsigned)link_len);
654 }
655
656 /*
657 * If relative pathname, restart at parent directory.
658 * If absolute pathname, restart at root.
659 */
660 cp = namebuf;
661 if (*cp != '/')
662 inumber = parent_inumber;
663 else
664 inumber = (ino_t)ROOTINO;
665
666 if ((rc = read_inode(inumber, f)) != 0)
667 goto out;
668 }
669 #endif /* !LIBSA_NO_FS_SYMLINK */
670 }
671
672 /*
673 * Found terminal component.
674 */
675 rc = 0;
676
677 #else /* !LIBSA_FS_SINGLECOMPONENT */
678
679 /* look up component in the current (root) directory */
680 rc = search_directory(path, f, &inumber);
681 if (rc)
682 goto out;
683
684 /* open it */
685 rc = read_inode(inumber, f);
686
687 #endif /* !LIBSA_FS_SINGLECOMPONENT */
688
689 fp->f_seekp = 0; /* reset seek pointer */
690
691 out:
692 #ifndef LIBSA_NO_FS_SYMLINK
693 if (buf)
694 free(buf, fs->fs_bsize);
695 #endif
696 if (rc) {
697 if (fp->f_buf)
698 free(fp->f_buf, fp->f_fs->fs_bsize);
699 free(fp->f_fs, SBLOCKSIZE);
700 free(fp, sizeof(struct file));
701 }
702 return (rc);
703 }
704
705 #ifndef LIBSA_NO_FS_CLOSE
706 int
707 ufs_close(f)
708 struct open_file *f;
709 {
710 struct file *fp = (struct file *)f->f_fsdata;
711 int level;
712
713 f->f_fsdata = (void *)0;
714 if (fp == (struct file *)0)
715 return (0);
716
717 for (level = 0; level < NIADDR; level++) {
718 if (fp->f_blk[level])
719 free(fp->f_blk[level], fp->f_fs->fs_bsize);
720 }
721 if (fp->f_buf)
722 free(fp->f_buf, fp->f_fs->fs_bsize);
723 free(fp->f_fs, SBLOCKSIZE);
724 free(fp, sizeof(struct file));
725 return (0);
726 }
727 #endif /* !LIBSA_NO_FS_CLOSE */
728
729 /*
730 * Copy a portion of a file into kernel memory.
731 * Cross block boundaries when necessary.
732 */
733 int
734 ufs_read(f, start, size, resid)
735 struct open_file *f;
736 void *start;
737 size_t size;
738 size_t *resid; /* out */
739 {
740 struct file *fp = (struct file *)f->f_fsdata;
741 size_t csize;
742 char *buf;
743 size_t buf_size;
744 int rc = 0;
745 char *addr = start;
746
747 while (size != 0) {
748 if (fp->f_seekp >= DIP(fp->f_di, size))
749 break;
750
751 rc = buf_read_file(f, &buf, &buf_size);
752 if (rc)
753 break;
754
755 csize = size;
756 if (csize > buf_size)
757 csize = buf_size;
758
759 bcopy(buf, addr, csize);
760
761 fp->f_seekp += csize;
762 addr += csize;
763 size -= csize;
764 }
765 if (resid)
766 *resid = size;
767 return (rc);
768 }
769
770 /*
771 * Not implemented.
772 */
773 #ifndef LIBSA_NO_FS_WRITE
774 int
775 ufs_write(f, start, size, resid)
776 struct open_file *f;
777 void *start;
778 size_t size;
779 size_t *resid; /* out */
780 {
781
782 return (EROFS);
783 }
784 #endif /* !LIBSA_NO_FS_WRITE */
785
786 #ifndef LIBSA_NO_FS_SEEK
787 off_t
788 ufs_seek(f, offset, where)
789 struct open_file *f;
790 off_t offset;
791 int where;
792 {
793 struct file *fp = (struct file *)f->f_fsdata;
794
795 switch (where) {
796 case SEEK_SET:
797 fp->f_seekp = offset;
798 break;
799 case SEEK_CUR:
800 fp->f_seekp += offset;
801 break;
802 case SEEK_END:
803 fp->f_seekp = DIP(fp->f_di, size) - offset;
804 break;
805 default:
806 return (-1);
807 }
808 return (fp->f_seekp);
809 }
810 #endif /* !LIBSA_NO_FS_SEEK */
811
812 int
813 ufs_stat(f, sb)
814 struct open_file *f;
815 struct stat *sb;
816 {
817 struct file *fp = (struct file *)f->f_fsdata;
818
819 /* only important stuff */
820 sb->st_mode = DIP(fp->f_di, mode);
821 sb->st_uid = DIP(fp->f_di, uid);
822 sb->st_gid = DIP(fp->f_di, gid);
823 sb->st_size = DIP(fp->f_di, size);
824 return (0);
825 }
826
827 /*
828 * Sanity checks for old file systems.
829 *
830 * XXX - goes away some day.
831 */
832 static void
833 ffs_oldfscompat(fs)
834 struct fs *fs;
835 {
836 int i;
837
838 if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_size != fs->fs_old_size) {
839 fs->fs_maxbsize = fs->fs_bsize;
840 fs->fs_time = fs->fs_old_time;
841 fs->fs_size = fs->fs_old_size;
842 fs->fs_dsize = fs->fs_old_dsize;
843 fs->fs_csaddr = fs->fs_old_csaddr;
844 fs->fs_cstotal.cs_ndir = fs->fs_old_cstotal.cs_ndir;
845 fs->fs_cstotal.cs_nbfree = fs->fs_old_cstotal.cs_nbfree;
846 fs->fs_cstotal.cs_nifree = fs->fs_old_cstotal.cs_nifree;
847 fs->fs_cstotal.cs_nffree = fs->fs_old_cstotal.cs_nffree;
848 }
849 #ifdef COMPAT_UFS
850 if (fs->fs_magic == FS_UFS1_MAGIC &&
851 fs->fs_old_inodefmt < FS_44INODEFMT) {
852 quad_t sizepb = fs->fs_bsize;
853 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;
854 for (i = 0; i < NIADDR; i++) {
855 sizepb *= NINDIR(fs);
856 fs->fs_maxfilesize += sizepb;
857 }
858 fs->fs_qbmask = ~fs->fs_bmask;
859 fs->fs_qfmask = ~fs->fs_fmask;
860 }
861 #endif
862 }
863