417e981e920552be35ee345fca901afd959acce6
[dragonfly.git] / lib / libstand / ufs.c
1 /* $FreeBSD: src/lib/libstand/ufs.c,v 1.5.6.1 2000/05/04 13:47:53 ps Exp $ */
2 /* $DragonFly: src/lib/libstand/ufs.c,v 1.7 2005/12/11 02:27:26 swildner Exp $ */
3 /*      $NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $    */
4
5 /*-
6  * Copyright (c) 1993
7  *      The Regents of the University of California.  All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * The Mach Operating System project at Carnegie-Mellon University.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *      This product includes software developed by the University of
23  *      California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *  
40  *
41  * Copyright (c) 1990, 1991 Carnegie Mellon University
42  * All Rights Reserved.
43  *
44  * Author: David Golub
45  * 
46  * Permission to use, copy, modify and distribute this software and its
47  * documentation is hereby granted, provided that both the copyright
48  * notice and this permission notice appear in all copies of the
49  * software, derivative works or modified versions, and any portions
50  * thereof, and that both notices appear in supporting documentation.
51  * 
52  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
53  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
54  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
55  * 
56  * Carnegie Mellon requests users of this software to return to
57  * 
58  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
59  *  School of Computer Science
60  *  Carnegie Mellon University
61  *  Pittsburgh PA 15213-3890
62  * 
63  * any improvements or extensions that they make and grant Carnegie the
64  * rights to redistribute these changes.
65  */
66
67 /*
68  *      Stand-alone file reading package.
69  */
70
71 #include <sys/param.h>
72 #include <sys/time.h>
73
74 #include "stand.h"
75
76 #include <vfs/ufs/dinode.h>
77 #include <vfs/ufs/dir.h>
78 #include <vfs/ufs/fs.h>
79 #include "string.h"
80
81 static int      ufs_open(const char *path, struct open_file *f);
82 static int      ufs_close(struct open_file *f);
83 static int      ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
84 static off_t    ufs_seek(struct open_file *f, off_t offset, int where);
85 static int      ufs_stat(struct open_file *f, struct stat *sb);
86 static int      ufs_readdir(struct open_file *f, struct dirent *d);
87
88 struct fs_ops ufs_fsops = {
89         "ufs",
90         ufs_open,
91         ufs_close,
92         ufs_read,
93         null_write,
94         ufs_seek,
95         ufs_stat,
96         ufs_readdir
97 };
98
99 /*
100  * In-core open file.
101  */
102 struct file {
103         off_t           f_seekp;        /* seek pointer */
104         struct fs       *f_fs;          /* pointer to super-block */
105         struct dinode   f_di;           /* copy of on-disk inode */
106         int             f_nindir[NIADDR];
107                                         /* number of blocks mapped by
108                                            indirect block at level i */
109         char            *f_blk[NIADDR]; /* buffer for indirect block at
110                                            level i */
111         size_t          f_blksize[NIADDR];
112                                         /* size of buffer */
113         daddr_t         f_blkno[NIADDR];/* disk address of block in buffer */
114         char            *f_buf;         /* buffer for data block */
115         size_t          f_buf_size;     /* size of data block */
116         daddr_t         f_buf_blkno;    /* block number of data block */
117 };
118
119 static int      read_inode(ino_t, struct open_file *);
120 static int      block_map(struct open_file *, daddr_t, daddr_t *);
121 static int      buf_read_file(struct open_file *, char **, size_t *);
122 static int      search_directory(char *, struct open_file *, ino_t *);
123 #ifdef COMPAT_UFS
124 static void     ffs_oldfscompat(struct fs *);
125 #endif
126
127 /*
128  * Read a new inode into a file structure.
129  */
130 static int
131 read_inode(ino_t inumber, struct open_file *f)
132 {
133         struct file *fp = (struct file *)f->f_fsdata;
134         struct fs *fs = fp->f_fs;
135         char *buf;
136         size_t rsize;
137         int rc;
138
139         if (fs == NULL)
140             panic("fs == NULL");
141
142         /*
143          * Read inode and save it.
144          */
145         buf = malloc(fs->fs_bsize);
146         twiddle();
147         rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
148                 fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
149                 buf, &rsize);
150         if (rc)
151                 goto out;
152         if (rsize != fs->fs_bsize) {
153                 rc = EIO;
154                 goto out;
155         }
156
157         {
158                 struct dinode *dp;
159
160                 dp = (struct dinode *)buf;
161                 fp->f_di = dp[ino_to_fsbo(fs, inumber)];
162         }
163
164         /*
165          * Clear out the old buffers
166          */
167         {
168                 int level;
169
170                 for (level = 0; level < NIADDR; level++)
171                         fp->f_blkno[level] = -1;
172                 fp->f_buf_blkno = -1;
173         }
174 out:
175         free(buf);
176         return (rc);     
177 }
178
179 /*
180  * Given an offset in a file, find the disk block number that
181  * contains that block.
182  *
183  * Parameters:
184  *      disk_block_p:   out
185  */
186 static int
187 block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p)
188 {
189         struct file *fp = (struct file *)f->f_fsdata;
190         struct fs *fs = fp->f_fs;
191         int level;
192         int idx;
193         daddr_t ind_block_num;
194         daddr_t *ind_p;
195         int rc;
196
197         /*
198          * Index structure of an inode:
199          *
200          * di_db[0..NDADDR-1]   hold block numbers for blocks
201          *                      0..NDADDR-1
202          *
203          * di_ib[0]             index block 0 is the single indirect block
204          *                      holds block numbers for blocks
205          *                      NDADDR .. NDADDR + NINDIR(fs)-1
206          *
207          * di_ib[1]             index block 1 is the double indirect block
208          *                      holds block numbers for INDEX blocks for blocks
209          *                      NDADDR + NINDIR(fs) ..
210          *                      NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
211          *
212          * di_ib[2]             index block 2 is the triple indirect block
213          *                      holds block numbers for double-indirect
214          *                      blocks for blocks
215          *                      NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
216          *                      NDADDR + NINDIR(fs) + NINDIR(fs)**2
217          *                              + NINDIR(fs)**3 - 1
218          */
219
220         if (file_block < NDADDR) {
221                 /* Direct block. */
222                 *disk_block_p = fp->f_di.di_db[file_block];
223                 return (0);
224         }
225
226         file_block -= NDADDR;
227
228         /*
229          * nindir[0] = NINDIR
230          * nindir[1] = NINDIR**2
231          * nindir[2] = NINDIR**3
232          *      etc
233          */
234         for (level = 0; level < NIADDR; level++) {
235                 if (file_block < fp->f_nindir[level])
236                         break;
237                 file_block -= fp->f_nindir[level];
238         }
239         if (level == NIADDR) {
240                 /* Block number too high */
241                 return (EFBIG);
242         }
243
244         ind_block_num = fp->f_di.di_ib[level];
245
246         for (; level >= 0; level--) {
247                 if (ind_block_num == 0) {
248                         *disk_block_p = 0;      /* missing */
249                         return (0);
250                 }
251
252                 if (fp->f_blkno[level] != ind_block_num) {
253                         if (fp->f_blk[level] == (char *)0)
254                                 fp->f_blk[level] =
255                                         malloc(fs->fs_bsize);
256                         twiddle();
257                         rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
258                                 fsbtodb(fp->f_fs, ind_block_num),
259                                 fs->fs_bsize,
260                                 fp->f_blk[level],
261                                 &fp->f_blksize[level]);
262                         if (rc)
263                                 return (rc);
264                         if (fp->f_blksize[level] != fs->fs_bsize)
265                                 return (EIO);
266                         fp->f_blkno[level] = ind_block_num;
267                 }
268
269                 ind_p = (daddr_t *)fp->f_blk[level];
270
271                 if (level > 0) {
272                         idx = file_block / fp->f_nindir[level - 1];
273                         file_block %= fp->f_nindir[level - 1];
274                 } else
275                         idx = file_block;
276
277                 ind_block_num = ind_p[idx];
278         }
279
280         *disk_block_p = ind_block_num;
281
282         return (0);
283 }
284
285 /*
286  * Read a portion of a file into an internal buffer.  Return
287  * the location in the buffer and the amount in the buffer.
288  *
289  * Parameters:
290  *      buf_p:  out
291  *      size_p: out
292  */
293 static int
294 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
295 {
296         struct file *fp = (struct file *)f->f_fsdata;
297         struct fs *fs = fp->f_fs;
298         long off;
299         daddr_t file_block;
300         daddr_t disk_block;
301         size_t block_size;
302         int rc;
303
304         off = blkoff(fs, fp->f_seekp);
305         file_block = lblkno(fs, fp->f_seekp);
306         block_size = dblksize(fs, &fp->f_di, file_block);
307
308         if (file_block != fp->f_buf_blkno) {
309                 rc = block_map(f, file_block, &disk_block);
310                 if (rc)
311                         return (rc);
312
313                 if (fp->f_buf == (char *)0)
314                         fp->f_buf = malloc(fs->fs_bsize);
315
316                 if (disk_block == 0) {
317                         bzero(fp->f_buf, block_size);
318                         fp->f_buf_size = block_size;
319                 } else {
320                         twiddle();
321                         rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
322                                 fsbtodb(fs, disk_block),
323                                 block_size, fp->f_buf, &fp->f_buf_size);
324                         if (rc)
325                                 return (rc);
326                 }
327
328                 fp->f_buf_blkno = file_block;
329         }
330
331         /*
332          * Return address of byte in buffer corresponding to
333          * offset, and size of remainder of buffer after that
334          * byte.
335          */
336         *buf_p = fp->f_buf + off;
337         *size_p = block_size - off;
338
339         /*
340          * But truncate buffer at end of file.
341          */
342         if (*size_p > fp->f_di.di_size - fp->f_seekp)
343                 *size_p = fp->f_di.di_size - fp->f_seekp;
344
345         return (0);
346 }
347
348 /*
349  * Search a directory for a name and return its
350  * i_number.
351  *
352  * Parameters:
353  *      inumber_p:      out
354  */
355 static int
356 search_directory(char *name, struct open_file *f, ino_t *inumber_p)
357 {
358         struct file *fp = (struct file *)f->f_fsdata;
359         struct direct *dp;
360         struct direct *edp;
361         char *buf;
362         size_t buf_size;
363         int namlen, length;
364         int rc;
365
366         length = strlen(name);
367
368         fp->f_seekp = 0;
369         while (fp->f_seekp < fp->f_di.di_size) {
370                 rc = buf_read_file(f, &buf, &buf_size);
371                 if (rc)
372                         return (rc);
373
374                 dp = (struct direct *)buf;
375                 edp = (struct direct *)(buf + buf_size);
376                 while (dp < edp) {
377                         if (dp->d_ino == (ino_t)0)
378                                 goto next;
379 #if BYTE_ORDER == LITTLE_ENDIAN
380                         if (fp->f_fs->fs_maxsymlinklen <= 0)
381                                 namlen = dp->d_type;
382                         else
383 #endif
384                                 namlen = dp->d_namlen;
385                         if (namlen == length &&
386                             !strcmp(name, dp->d_name)) {
387                                 /* found entry */
388                                 *inumber_p = dp->d_ino;
389                                 return (0);
390                         }
391                 next:
392                         dp = (struct direct *)((char *)dp + dp->d_reclen);
393                 }
394                 fp->f_seekp += buf_size;
395         }
396         return (ENOENT);
397 }
398
399 /*
400  * Open a file.
401  */
402 static int
403 ufs_open(const char *upath, struct open_file *f)
404 {
405         char *cp, *ncp;
406         int c;
407         ino_t inumber, parent_inumber;
408         struct file *fp;
409         struct fs *fs;
410         int rc;
411         size_t buf_size;
412         int nlinks = 0;
413         char namebuf[MAXPATHLEN+1];
414         char *buf = NULL;
415         char *path = NULL;
416
417         /* allocate file system specific data structure */
418         fp = malloc(sizeof(struct file));
419         bzero(fp, sizeof(struct file));
420         f->f_fsdata = (void *)fp;
421
422         /* allocate space and read super block */
423         fs = malloc(SBSIZE);
424         fp->f_fs = fs;
425         twiddle();
426         rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
427                 SBLOCK, SBSIZE, (char *)fs, &buf_size);
428         if (rc)
429                 goto out;
430
431         if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
432             fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
433                 rc = EINVAL;
434                 goto out;
435         }
436 #ifdef COMPAT_UFS
437         ffs_oldfscompat(fs);
438 #endif
439
440         /*
441          * Calculate indirect block levels.
442          */
443         {
444                 int mult;
445                 int level;
446
447                 mult = 1;
448                 for (level = 0; level < NIADDR; level++) {
449                         mult *= NINDIR(fs);
450                         fp->f_nindir[level] = mult;
451                 }
452         }
453
454         inumber = ROOTINO;
455         if ((rc = read_inode(inumber, f)) != 0)
456                 goto out;
457
458         cp = path = strdup(upath);
459         if (path == NULL) {
460             rc = ENOMEM;
461             goto out;
462         }
463         while (*cp) {
464
465                 /*
466                  * Remove extra separators
467                  */
468                 while (*cp == '/')
469                         cp++;
470                 if (*cp == '\0')
471                         break;
472
473                 /*
474                  * Check that current node is a directory.
475                  */
476                 if ((fp->f_di.di_mode & IFMT) != IFDIR) {
477                         rc = ENOTDIR;
478                         goto out;
479                 }
480
481                 /*
482                  * Get next component of path name.
483                  */
484                 {
485                         int len = 0;
486
487                         ncp = cp;
488                         while ((c = *cp) != '\0' && c != '/') {
489                                 if (++len > MAXNAMLEN) {
490                                         rc = ENOENT;
491                                         goto out;
492                                 }
493                                 cp++;
494                         }
495                         *cp = '\0';
496                 }
497
498                 /*
499                  * Look up component in current directory.
500                  * Save directory inumber in case we find a
501                  * symbolic link.
502                  */
503                 parent_inumber = inumber;
504                 rc = search_directory(ncp, f, &inumber);
505                 *cp = c;
506                 if (rc)
507                         goto out;
508
509                 /*
510                  * Open next component.
511                  */
512                 if ((rc = read_inode(inumber, f)) != 0)
513                         goto out;
514
515                 /*
516                  * Check for symbolic link.
517                  */
518                 if ((fp->f_di.di_mode & IFMT) == IFLNK) {
519                         int link_len = fp->f_di.di_size;
520                         int len;
521
522                         len = strlen(cp);
523
524                         if (link_len + len > MAXPATHLEN ||
525                             ++nlinks > MAXSYMLINKS) {
526                                 rc = ENOENT;
527                                 goto out;
528                         }
529
530                         bcopy(cp, &namebuf[link_len], len + 1);
531
532                         if (link_len < fs->fs_maxsymlinklen) {
533                                 bcopy(fp->f_di.di_shortlink, namebuf,
534                                       (unsigned) link_len);
535                         } else {
536                                 /*
537                                  * Read file for symbolic link
538                                  */
539                                 size_t buf_size;
540                                 daddr_t disk_block;
541                                 struct fs *fs = fp->f_fs;
542
543                                 if (!buf)
544                                         buf = malloc(fs->fs_bsize);
545                                 rc = block_map(f, (daddr_t)0, &disk_block);
546                                 if (rc)
547                                         goto out;
548                                 
549                                 twiddle();
550                                 rc = (f->f_dev->dv_strategy)(f->f_devdata,
551                                         F_READ, fsbtodb(fs, disk_block),
552                                         fs->fs_bsize, buf, &buf_size);
553                                 if (rc)
554                                         goto out;
555
556                                 bcopy((char *)buf, namebuf, (unsigned)link_len);
557                         }
558
559                         /*
560                          * If relative pathname, restart at parent directory.
561                          * If absolute pathname, restart at root.
562                          */
563                         cp = namebuf;
564                         if (*cp != '/')
565                                 inumber = parent_inumber;
566                         else
567                                 inumber = (ino_t)ROOTINO;
568
569                         if ((rc = read_inode(inumber, f)) != 0)
570                                 goto out;
571                 }
572         }
573
574         /*
575          * Found terminal component.
576          */
577         rc = 0;
578 out:
579         if (buf)
580                 free(buf);
581         if (path)
582                 free(path);
583         if (rc) {
584                 if (fp->f_buf)
585                         free(fp->f_buf);
586                 free(fp->f_fs);
587                 free(fp);
588         }
589         return (rc);
590 }
591
592 static int
593 ufs_close(struct open_file *f)
594 {
595         struct file *fp = (struct file *)f->f_fsdata;
596         int level;
597
598         f->f_fsdata = (void *)0;
599         if (fp == (struct file *)0)
600                 return (0);
601
602         for (level = 0; level < NIADDR; level++) {
603                 if (fp->f_blk[level])
604                         free(fp->f_blk[level]);
605         }
606         if (fp->f_buf)
607                 free(fp->f_buf);
608         free(fp->f_fs);
609         free(fp);
610         return (0);
611 }
612
613 /*
614  * Copy a portion of a file into kernel memory.
615  * Cross block boundaries when necessary.
616  *
617  * Parameters:
618  *      resid:  out
619  */
620 static int
621 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
622 {
623         struct file *fp = (struct file *)f->f_fsdata;
624         size_t csize;
625         char *buf;
626         size_t buf_size;
627         int rc = 0;
628         char *addr = start;
629
630         while (size != 0) {
631                 if (fp->f_seekp >= fp->f_di.di_size)
632                         break;
633
634                 rc = buf_read_file(f, &buf, &buf_size);
635                 if (rc)
636                         break;
637
638                 csize = size;
639                 if (csize > buf_size)
640                         csize = buf_size;
641
642                 bcopy(buf, addr, csize);
643
644                 fp->f_seekp += csize;
645                 addr += csize;
646                 size -= csize;
647         }
648         if (resid)
649                 *resid = size;
650         return (rc);
651 }
652
653 static off_t
654 ufs_seek(struct open_file *f, off_t offset, int where)
655 {
656         struct file *fp = (struct file *)f->f_fsdata;
657
658         switch (where) {
659         case SEEK_SET:
660                 fp->f_seekp = offset;
661                 break;
662         case SEEK_CUR:
663                 fp->f_seekp += offset;
664                 break;
665         case SEEK_END:
666                 fp->f_seekp = fp->f_di.di_size - offset;
667                 break;
668         default:
669                 return (-1);
670         }
671         return (fp->f_seekp);
672 }
673
674 static int
675 ufs_stat(struct open_file *f, struct stat *sb)
676 {
677         struct file *fp = (struct file *)f->f_fsdata;
678
679         /* only important stuff */
680         sb->st_mode = fp->f_di.di_mode;
681         sb->st_uid = fp->f_di.di_uid;
682         sb->st_gid = fp->f_di.di_gid;
683         sb->st_size = fp->f_di.di_size;
684         return (0);
685 }
686
687 static int
688 ufs_readdir(struct open_file *f, struct dirent *d)
689 {
690         struct file *fp = (struct file *)f->f_fsdata;
691         struct direct *dp;
692         char *buf;
693         size_t buf_size;
694         int error;
695
696         /*
697          * assume that a directory entry will not be split across blocks
698          */
699 again:
700         if (fp->f_seekp >= fp->f_di.di_size)
701                 return (ENOENT);
702         error = buf_read_file(f, &buf, &buf_size);
703         if (error)
704                 return (error);
705         dp = (struct direct *)buf;
706         fp->f_seekp += dp->d_reclen;
707         if (dp->d_ino == (ino_t)0)
708                 goto again;
709         d->d_type = dp->d_type;
710         strcpy(d->d_name, dp->d_name);
711         return (0);
712 }
713
714 #ifdef COMPAT_UFS
715 /*
716  * Sanity checks for old file systems.
717  *
718  * XXX - goes away some day.
719  */
720 static void
721 ffs_oldfscompat(struct fs *fs)
722 {
723         int i;
724
725         fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);       /* XXX */
726         fs->fs_interleave = max(fs->fs_interleave, 1);          /* XXX */
727         if (fs->fs_postblformat == FS_42POSTBLFMT)              /* XXX */
728                 fs->fs_nrpos = 8;                               /* XXX */
729         if (fs->fs_inodefmt < FS_44INODEFMT) {                  /* XXX */
730                 quad_t sizepb = fs->fs_bsize;                   /* XXX */
731                                                                 /* XXX */
732                 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */
733                 for (i = 0; i < NIADDR; i++) {                  /* XXX */
734                         sizepb *= NINDIR(fs);                   /* XXX */
735                         fs->fs_maxfilesize += sizepb;           /* XXX */
736                 }                                               /* XXX */
737                 fs->fs_qbmask = ~fs->fs_bmask;                  /* XXX */
738                 fs->fs_qfmask = ~fs->fs_fmask;                  /* XXX */
739         }                                                       /* XXX */
740 }
741 #endif