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