Merge from vendor branch OPENPAM:
[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.5 2005/03/13 15:10:03 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 #include <vfs/ufs/dinode.h>
74 #include <vfs/ufs/dir.h>
75 #include <vfs/ufs/fs.h>
76 #include "stand.h"
77 #include "string.h"
78
79 static int      ufs_open(const char *path, struct open_file *f);
80 static int      ufs_close(struct open_file *f);
81 static int      ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
82 static off_t    ufs_seek(struct open_file *f, off_t offset, int where);
83 static int      ufs_stat(struct open_file *f, struct stat *sb);
84 static int      ufs_readdir(struct open_file *f, struct dirent *d);
85
86 struct fs_ops ufs_fsops = {
87         "ufs",
88         ufs_open,
89         ufs_close,
90         ufs_read,
91         null_write,
92         ufs_seek,
93         ufs_stat,
94         ufs_readdir
95 };
96
97 /*
98  * In-core open file.
99  */
100 struct file {
101         off_t           f_seekp;        /* seek pointer */
102         struct fs       *f_fs;          /* pointer to super-block */
103         struct dinode   f_di;           /* copy of on-disk inode */
104         int             f_nindir[NIADDR];
105                                         /* number of blocks mapped by
106                                            indirect block at level i */
107         char            *f_blk[NIADDR]; /* buffer for indirect block at
108                                            level i */
109         size_t          f_blksize[NIADDR];
110                                         /* size of buffer */
111         daddr_t         f_blkno[NIADDR];/* disk address of block in buffer */
112         char            *f_buf;         /* buffer for data block */
113         size_t          f_buf_size;     /* size of data block */
114         daddr_t         f_buf_blkno;    /* block number of data block */
115 };
116
117 static int      read_inode(ino_t, struct open_file *);
118 static int      block_map(struct open_file *, daddr_t, daddr_t *);
119 static int      buf_read_file(struct open_file *, char **, size_t *);
120 static int      search_directory(char *, struct open_file *, ino_t *);
121 #ifdef COMPAT_UFS
122 static void     ffs_oldfscompat(struct fs *);
123 #endif
124
125 /*
126  * Read a new inode into a file structure.
127  */
128 static int
129 read_inode(inumber, f)
130         ino_t inumber;
131         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 static int
184 block_map(f, file_block, disk_block_p)
185         struct open_file *f;
186         daddr_t file_block;
187         daddr_t *disk_block_p;  /* out */
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 static int
290 buf_read_file(f, buf_p, size_p)
291         struct open_file *f;
292         char **buf_p;           /* out */
293         size_t *size_p;         /* out */
294 {
295         struct file *fp = (struct file *)f->f_fsdata;
296         struct fs *fs = fp->f_fs;
297         long off;
298         daddr_t file_block;
299         daddr_t disk_block;
300         size_t block_size;
301         int rc;
302
303         off = blkoff(fs, fp->f_seekp);
304         file_block = lblkno(fs, fp->f_seekp);
305         block_size = dblksize(fs, &fp->f_di, file_block);
306
307         if (file_block != fp->f_buf_blkno) {
308                 rc = block_map(f, file_block, &disk_block);
309                 if (rc)
310                         return (rc);
311
312                 if (fp->f_buf == (char *)0)
313                         fp->f_buf = malloc(fs->fs_bsize);
314
315                 if (disk_block == 0) {
316                         bzero(fp->f_buf, block_size);
317                         fp->f_buf_size = block_size;
318                 } else {
319                         twiddle();
320                         rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
321                                 fsbtodb(fs, disk_block),
322                                 block_size, fp->f_buf, &fp->f_buf_size);
323                         if (rc)
324                                 return (rc);
325                 }
326
327                 fp->f_buf_blkno = file_block;
328         }
329
330         /*
331          * Return address of byte in buffer corresponding to
332          * offset, and size of remainder of buffer after that
333          * byte.
334          */
335         *buf_p = fp->f_buf + off;
336         *size_p = block_size - off;
337
338         /*
339          * But truncate buffer at end of file.
340          */
341         if (*size_p > fp->f_di.di_size - fp->f_seekp)
342                 *size_p = fp->f_di.di_size - fp->f_seekp;
343
344         return (0);
345 }
346
347 /*
348  * Search a directory for a name and return its
349  * i_number.
350  */
351 static int
352 search_directory(name, f, inumber_p)
353         char *name;
354         struct open_file *f;
355         ino_t *inumber_p;               /* out */
356 {
357         struct file *fp = (struct file *)f->f_fsdata;
358         struct direct *dp;
359         struct direct *edp;
360         char *buf;
361         size_t buf_size;
362         int namlen, length;
363         int rc;
364
365         length = strlen(name);
366
367         fp->f_seekp = 0;
368         while (fp->f_seekp < fp->f_di.di_size) {
369                 rc = buf_read_file(f, &buf, &buf_size);
370                 if (rc)
371                         return (rc);
372
373                 dp = (struct direct *)buf;
374                 edp = (struct direct *)(buf + buf_size);
375                 while (dp < edp) {
376                         if (dp->d_ino == (ino_t)0)
377                                 goto next;
378 #if BYTE_ORDER == LITTLE_ENDIAN
379                         if (fp->f_fs->fs_maxsymlinklen <= 0)
380                                 namlen = dp->d_type;
381                         else
382 #endif
383                                 namlen = dp->d_namlen;
384                         if (namlen == length &&
385                             !strcmp(name, dp->d_name)) {
386                                 /* found entry */
387                                 *inumber_p = dp->d_ino;
388                                 return (0);
389                         }
390                 next:
391                         dp = (struct direct *)((char *)dp + dp->d_reclen);
392                 }
393                 fp->f_seekp += buf_size;
394         }
395         return (ENOENT);
396 }
397
398 /*
399  * Open a file.
400  */
401 static int
402 ufs_open(upath, f)
403         const char *upath;
404         struct open_file *f;
405 {
406         char *cp, *ncp;
407         int c;
408         ino_t inumber, parent_inumber;
409         struct file *fp;
410         struct fs *fs;
411         int rc;
412         size_t buf_size;
413         int nlinks = 0;
414         char namebuf[MAXPATHLEN+1];
415         char *buf = NULL;
416         char *path = NULL;
417
418         /* allocate file system specific data structure */
419         fp = malloc(sizeof(struct file));
420         bzero(fp, sizeof(struct file));
421         f->f_fsdata = (void *)fp;
422
423         /* allocate space and read super block */
424         fs = malloc(SBSIZE);
425         fp->f_fs = fs;
426         twiddle();
427         rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
428                 SBLOCK, SBSIZE, (char *)fs, &buf_size);
429         if (rc)
430                 goto out;
431
432         if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
433             fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
434                 rc = EINVAL;
435                 goto out;
436         }
437 #ifdef COMPAT_UFS
438         ffs_oldfscompat(fs);
439 #endif
440
441         /*
442          * Calculate indirect block levels.
443          */
444         {
445                 int mult;
446                 int level;
447
448                 mult = 1;
449                 for (level = 0; level < NIADDR; level++) {
450                         mult *= NINDIR(fs);
451                         fp->f_nindir[level] = mult;
452                 }
453         }
454
455         inumber = ROOTINO;
456         if ((rc = read_inode(inumber, f)) != 0)
457                 goto out;
458
459         cp = path = strdup(upath);
460         if (path == NULL) {
461             rc = ENOMEM;
462             goto out;
463         }
464         while (*cp) {
465
466                 /*
467                  * Remove extra separators
468                  */
469                 while (*cp == '/')
470                         cp++;
471                 if (*cp == '\0')
472                         break;
473
474                 /*
475                  * Check that current node is a directory.
476                  */
477                 if ((fp->f_di.di_mode & IFMT) != IFDIR) {
478                         rc = ENOTDIR;
479                         goto out;
480                 }
481
482                 /*
483                  * Get next component of path name.
484                  */
485                 {
486                         int len = 0;
487
488                         ncp = cp;
489                         while ((c = *cp) != '\0' && c != '/') {
490                                 if (++len > MAXNAMLEN) {
491                                         rc = ENOENT;
492                                         goto out;
493                                 }
494                                 cp++;
495                         }
496                         *cp = '\0';
497                 }
498
499                 /*
500                  * Look up component in current directory.
501                  * Save directory inumber in case we find a
502                  * symbolic link.
503                  */
504                 parent_inumber = inumber;
505                 rc = search_directory(ncp, f, &inumber);
506                 *cp = c;
507                 if (rc)
508                         goto out;
509
510                 /*
511                  * Open next component.
512                  */
513                 if ((rc = read_inode(inumber, f)) != 0)
514                         goto out;
515
516                 /*
517                  * Check for symbolic link.
518                  */
519                 if ((fp->f_di.di_mode & IFMT) == IFLNK) {
520                         int link_len = fp->f_di.di_size;
521                         int len;
522
523                         len = strlen(cp);
524
525                         if (link_len + len > MAXPATHLEN ||
526                             ++nlinks > MAXSYMLINKS) {
527                                 rc = ENOENT;
528                                 goto out;
529                         }
530
531                         bcopy(cp, &namebuf[link_len], len + 1);
532
533                         if (link_len < fs->fs_maxsymlinklen) {
534                                 bcopy(fp->f_di.di_shortlink, namebuf,
535                                       (unsigned) link_len);
536                         } else {
537                                 /*
538                                  * Read file for symbolic link
539                                  */
540                                 size_t buf_size;
541                                 daddr_t disk_block;
542                                 struct fs *fs = fp->f_fs;
543
544                                 if (!buf)
545                                         buf = malloc(fs->fs_bsize);
546                                 rc = block_map(f, (daddr_t)0, &disk_block);
547                                 if (rc)
548                                         goto out;
549                                 
550                                 twiddle();
551                                 rc = (f->f_dev->dv_strategy)(f->f_devdata,
552                                         F_READ, fsbtodb(fs, disk_block),
553                                         fs->fs_bsize, buf, &buf_size);
554                                 if (rc)
555                                         goto out;
556
557                                 bcopy((char *)buf, namebuf, (unsigned)link_len);
558                         }
559
560                         /*
561                          * If relative pathname, restart at parent directory.
562                          * If absolute pathname, restart at root.
563                          */
564                         cp = namebuf;
565                         if (*cp != '/')
566                                 inumber = parent_inumber;
567                         else
568                                 inumber = (ino_t)ROOTINO;
569
570                         if ((rc = read_inode(inumber, f)) != 0)
571                                 goto out;
572                 }
573         }
574
575         /*
576          * Found terminal component.
577          */
578         rc = 0;
579 out:
580         if (buf)
581                 free(buf);
582         if (path)
583                 free(path);
584         if (rc) {
585                 if (fp->f_buf)
586                         free(fp->f_buf);
587                 free(fp->f_fs);
588                 free(fp);
589         }
590         return (rc);
591 }
592
593 static int
594 ufs_close(f)
595         struct open_file *f;
596 {
597         struct file *fp = (struct file *)f->f_fsdata;
598         int level;
599
600         f->f_fsdata = (void *)0;
601         if (fp == (struct file *)0)
602                 return (0);
603
604         for (level = 0; level < NIADDR; level++) {
605                 if (fp->f_blk[level])
606                         free(fp->f_blk[level]);
607         }
608         if (fp->f_buf)
609                 free(fp->f_buf);
610         free(fp->f_fs);
611         free(fp);
612         return (0);
613 }
614
615 /*
616  * Copy a portion of a file into kernel memory.
617  * Cross block boundaries when necessary.
618  */
619 static int
620 ufs_read(f, start, size, resid)
621         struct open_file *f;
622         void *start;
623         size_t size;
624         size_t *resid;  /* out */
625 {
626         struct file *fp = (struct file *)f->f_fsdata;
627         size_t csize;
628         char *buf;
629         size_t buf_size;
630         int rc = 0;
631         char *addr = start;
632
633         while (size != 0) {
634                 if (fp->f_seekp >= fp->f_di.di_size)
635                         break;
636
637                 rc = buf_read_file(f, &buf, &buf_size);
638                 if (rc)
639                         break;
640
641                 csize = size;
642                 if (csize > buf_size)
643                         csize = buf_size;
644
645                 bcopy(buf, addr, csize);
646
647                 fp->f_seekp += csize;
648                 addr += csize;
649                 size -= csize;
650         }
651         if (resid)
652                 *resid = size;
653         return (rc);
654 }
655
656 static off_t
657 ufs_seek(f, offset, where)
658         struct open_file *f;
659         off_t offset;
660         int where;
661 {
662         struct file *fp = (struct file *)f->f_fsdata;
663
664         switch (where) {
665         case SEEK_SET:
666                 fp->f_seekp = offset;
667                 break;
668         case SEEK_CUR:
669                 fp->f_seekp += offset;
670                 break;
671         case SEEK_END:
672                 fp->f_seekp = fp->f_di.di_size - offset;
673                 break;
674         default:
675                 return (-1);
676         }
677         return (fp->f_seekp);
678 }
679
680 static int
681 ufs_stat(f, sb)
682         struct open_file *f;
683         struct stat *sb;
684 {
685         struct file *fp = (struct file *)f->f_fsdata;
686
687         /* only important stuff */
688         sb->st_mode = fp->f_di.di_mode;
689         sb->st_uid = fp->f_di.di_uid;
690         sb->st_gid = fp->f_di.di_gid;
691         sb->st_size = fp->f_di.di_size;
692         return (0);
693 }
694
695 static int
696 ufs_readdir(struct open_file *f, struct dirent *d)
697 {
698         struct file *fp = (struct file *)f->f_fsdata;
699         struct direct *dp;
700         char *buf;
701         size_t buf_size;
702         int error;
703
704         /*
705          * assume that a directory entry will not be split across blocks
706          */
707 again:
708         if (fp->f_seekp >= fp->f_di.di_size)
709                 return (ENOENT);
710         error = buf_read_file(f, &buf, &buf_size);
711         if (error)
712                 return (error);
713         dp = (struct direct *)buf;
714         fp->f_seekp += dp->d_reclen;
715         if (dp->d_ino == (ino_t)0)
716                 goto again;
717         d->d_type = dp->d_type;
718         strcpy(d->d_name, dp->d_name);
719         return (0);
720 }
721
722 #ifdef COMPAT_UFS
723 /*
724  * Sanity checks for old file systems.
725  *
726  * XXX - goes away some day.
727  */
728 static void
729 ffs_oldfscompat(fs)
730         struct fs *fs;
731 {
732         int i;
733
734         fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);       /* XXX */
735         fs->fs_interleave = max(fs->fs_interleave, 1);          /* XXX */
736         if (fs->fs_postblformat == FS_42POSTBLFMT)              /* XXX */
737                 fs->fs_nrpos = 8;                               /* XXX */
738         if (fs->fs_inodefmt < FS_44INODEFMT) {                  /* XXX */
739                 quad_t sizepb = fs->fs_bsize;                   /* XXX */
740                                                                 /* XXX */
741                 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */
742                 for (i = 0; i < NIADDR; i++) {                  /* XXX */
743                         sizepb *= NINDIR(fs);                   /* XXX */
744                         fs->fs_maxfilesize += sizepb;           /* XXX */
745                 }                                               /* XXX */
746                 fs->fs_qbmask = ~fs->fs_bmask;                  /* XXX */
747                 fs->fs_qfmask = ~fs->fs_fmask;                  /* XXX */
748         }                                                       /* XXX */
749 }
750 #endif