libstand: Add uuid_{from,to}_string() and uuid_create_nil() (from libc).
[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 (dp->d_type == DT_WHT)
376                                 goto next;
377 #if BYTE_ORDER == LITTLE_ENDIAN
378                         if (fp->f_fs->fs_maxsymlinklen <= 0)
379                                 namlen = dp->d_type;
380                         else
381 #endif
382                                 namlen = dp->d_namlen;
383                         if (namlen == length &&
384                             !strcmp(name, dp->d_name)) {
385                                 /* found entry */
386                                 *inumber_p = dp->d_ino;
387                                 return (0);
388                         }
389                 next:
390                         dp = (struct direct *)((char *)dp + dp->d_reclen);
391                 }
392                 fp->f_seekp += buf_size;
393         }
394         return (ENOENT);
395 }
396
397 /*
398  * Open a file.
399  */
400 static int
401 ufs_open(const char *upath, struct open_file *f)
402 {
403         char *cp, *ncp;
404         int c;
405         ino_t inumber, parent_inumber;
406         struct file *fp;
407         struct fs *fs;
408         int rc;
409         size_t buf_size;
410         int nlinks = 0;
411         char namebuf[MAXPATHLEN+1];
412         char *buf = NULL;
413         char *path = NULL;
414
415         /* allocate file system specific data structure */
416         fp = malloc(sizeof(struct file));
417         bzero(fp, sizeof(struct file));
418         f->f_fsdata = (void *)fp;
419
420         /* allocate space and read super block */
421         fs = malloc(SBSIZE);
422         fp->f_fs = fs;
423         twiddle();
424         rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
425                 SBOFF / DEV_BSIZE, SBSIZE, (char *)fs, &buf_size);
426         if (rc)
427                 goto out;
428
429         if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
430             fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
431                 rc = EINVAL;
432                 goto out;
433         }
434 #ifdef COMPAT_UFS
435         ffs_oldfscompat(fs);
436 #endif
437
438         /*
439          * Calculate indirect block levels.
440          */
441         {
442                 int omult;
443                 int mult;
444                 int level;
445
446                 omult = 0;
447                 mult = 1;
448                 for (level = 0; level < NIADDR; level++) {
449                         mult *= NINDIR(fs);
450                         if (mult < omult)
451                                 mult = 0x7FFFFFFF;
452                         fp->f_nindir[level] = mult;
453                         omult = mult;
454                 }
455         }
456
457         inumber = ROOTINO;
458         if ((rc = read_inode(inumber, f)) != 0)
459                 goto out;
460
461         cp = path = strdup(upath);
462         if (path == NULL) {
463             rc = ENOMEM;
464             goto out;
465         }
466         while (*cp) {
467
468                 /*
469                  * Remove extra separators
470                  */
471                 while (*cp == '/')
472                         cp++;
473                 if (*cp == '\0')
474                         break;
475
476                 /*
477                  * Check that current node is a directory.
478                  */
479                 if ((fp->f_di.di_mode & IFMT) != IFDIR) {
480                         rc = ENOTDIR;
481                         goto out;
482                 }
483
484                 /*
485                  * Get next component of path name.
486                  */
487                 {
488                         int len = 0;
489
490                         ncp = cp;
491                         while ((c = *cp) != '\0' && c != '/') {
492                                 if (++len > MAXNAMLEN) {
493                                         rc = ENOENT;
494                                         goto out;
495                                 }
496                                 cp++;
497                         }
498                         *cp = '\0';
499                 }
500
501                 /*
502                  * Look up component in current directory.
503                  * Save directory inumber in case we find a
504                  * symbolic link.
505                  */
506                 parent_inumber = inumber;
507                 rc = search_directory(ncp, f, &inumber);
508                 *cp = c;
509                 if (rc)
510                         goto out;
511
512                 /*
513                  * Open next component.
514                  */
515                 if ((rc = read_inode(inumber, f)) != 0)
516                         goto out;
517
518                 /*
519                  * Check for symbolic link.
520                  */
521                 if ((fp->f_di.di_mode & IFMT) == IFLNK) {
522                         int link_len = fp->f_di.di_size;
523                         int len;
524
525                         len = strlen(cp);
526
527                         if (link_len + len > MAXPATHLEN ||
528                             ++nlinks > MAXSYMLINKS) {
529                                 rc = ENOENT;
530                                 goto out;
531                         }
532
533                         bcopy(cp, &namebuf[link_len], len + 1);
534
535                         if (link_len < fs->fs_maxsymlinklen) {
536                                 bcopy(fp->f_di.di_shortlink, namebuf,
537                                       (unsigned) link_len);
538                         } else {
539                                 /*
540                                  * Read file for symbolic link
541                                  */
542                                 size_t buf_size;
543                                 daddr_t disk_block;
544                                 struct fs *fs = fp->f_fs;
545
546                                 if (!buf)
547                                         buf = malloc(fs->fs_bsize);
548                                 rc = block_map(f, (daddr_t)0, &disk_block);
549                                 if (rc)
550                                         goto out;
551                                 
552                                 twiddle();
553                                 rc = (f->f_dev->dv_strategy)(f->f_devdata,
554                                         F_READ, fsbtodb(fs, disk_block),
555                                         fs->fs_bsize, buf, &buf_size);
556                                 if (rc)
557                                         goto out;
558
559                                 bcopy((char *)buf, namebuf, (unsigned)link_len);
560                         }
561
562                         /*
563                          * If relative pathname, restart at parent directory.
564                          * If absolute pathname, restart at root.
565                          */
566                         cp = namebuf;
567                         if (*cp != '/')
568                                 inumber = parent_inumber;
569                         else
570                                 inumber = (ino_t)ROOTINO;
571
572                         if ((rc = read_inode(inumber, f)) != 0)
573                                 goto out;
574                 }
575         }
576
577         /*
578          * Found terminal component.
579          */
580         fp->f_seekp = 0;
581         rc = 0;
582 out:
583         if (buf)
584                 free(buf);
585         if (path)
586                 free(path);
587         if (rc) {
588                 f->f_fsdata = NULL;
589                 if (fp->f_buf)
590                         free(fp->f_buf);
591                 free(fp->f_fs);
592                 free(fp);
593         }
594         return (rc);
595 }
596
597 static int
598 ufs_close(struct open_file *f)
599 {
600         struct file *fp = (struct file *)f->f_fsdata;
601         int level;
602
603         f->f_fsdata = NULL;
604         if (fp == NULL)
605                 return (0);
606
607         for (level = 0; level < NIADDR; level++) {
608                 if (fp->f_blk[level])
609                         free(fp->f_blk[level]);
610         }
611         if (fp->f_buf)
612                 free(fp->f_buf);
613         free(fp->f_fs);
614         free(fp);
615         return (0);
616 }
617
618 /*
619  * Copy a portion of a file into kernel memory.
620  * Cross block boundaries when necessary.
621  *
622  * Parameters:
623  *      resid:  out
624  */
625 static int
626 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
627 {
628         struct file *fp = (struct file *)f->f_fsdata;
629         size_t csize;
630         char *buf;
631         size_t buf_size;
632         int rc = 0;
633         char *addr = start;
634
635         while (size != 0) {
636                 if (fp->f_seekp >= fp->f_di.di_size)
637                         break;
638
639                 rc = buf_read_file(f, &buf, &buf_size);
640                 if (rc)
641                         break;
642
643                 csize = size;
644                 if (csize > buf_size)
645                         csize = buf_size;
646
647                 bcopy(buf, addr, csize);
648
649                 fp->f_seekp += csize;
650                 addr += csize;
651                 size -= csize;
652         }
653         if (resid)
654                 *resid = size;
655         return (rc);
656 }
657
658 static off_t
659 ufs_seek(struct open_file *f, off_t offset, int where)
660 {
661         struct file *fp = (struct file *)f->f_fsdata;
662
663         switch (where) {
664         case SEEK_SET:
665                 fp->f_seekp = offset;
666                 break;
667         case SEEK_CUR:
668                 fp->f_seekp += offset;
669                 break;
670         case SEEK_END:
671                 fp->f_seekp = fp->f_di.di_size - offset;
672                 break;
673         default:
674                 return (-1);
675         }
676         return (fp->f_seekp);
677 }
678
679 static int
680 ufs_stat(struct open_file *f, struct stat *sb)
681 {
682         struct file *fp = (struct file *)f->f_fsdata;
683
684         /* only important stuff */
685         sb->st_mode = fp->f_di.di_mode;
686         sb->st_uid = fp->f_di.di_uid;
687         sb->st_gid = fp->f_di.di_gid;
688         sb->st_size = fp->f_di.di_size;
689         return (0);
690 }
691
692 static int
693 ufs_readdir(struct open_file *f, struct dirent *d)
694 {
695         struct file *fp = (struct file *)f->f_fsdata;
696         struct direct *dp;
697         char *buf;
698         size_t buf_size;
699         int error;
700
701         /*
702          * assume that a directory entry will not be split across blocks
703          */
704 again:
705         if (fp->f_seekp >= fp->f_di.di_size)
706                 return (ENOENT);
707         error = buf_read_file(f, &buf, &buf_size);
708         if (error)
709                 return (error);
710         dp = (struct direct *)buf;
711         fp->f_seekp += dp->d_reclen;
712         if (dp->d_ino == (ino_t)0)
713                 goto again;
714         d->d_type = dp->d_type;
715         strcpy(d->d_name, dp->d_name);
716         return (0);
717 }
718
719 #ifdef COMPAT_UFS
720 /*
721  * Sanity checks for old file systems.
722  *
723  * XXX - goes away some day.
724  */
725 static void
726 ffs_oldfscompat(struct fs *fs)
727 {
728         int i;
729
730         fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);       /* XXX */
731         fs->fs_interleave = max(fs->fs_interleave, 1);          /* XXX */
732         if (fs->fs_postblformat == FS_42POSTBLFMT)              /* XXX */
733                 fs->fs_nrpos = 8;                               /* XXX */
734         if (fs->fs_inodefmt < FS_44INODEFMT) {                  /* XXX */
735                 quad_t sizepb = fs->fs_bsize;                   /* XXX */
736                                                                 /* XXX */
737                 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */
738                 for (i = 0; i < NIADDR; i++) {                  /* XXX */
739                         sizepb *= NINDIR(fs);                   /* XXX */
740                         fs->fs_maxfilesize += sizepb;           /* XXX */
741                 }                                               /* XXX */
742                 fs->fs_qbmask = ~fs->fs_bmask;                  /* XXX */
743                 fs->fs_qfmask = ~fs->fs_fmask;                  /* XXX */
744         }                                                       /* XXX */
745 }
746 #endif