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