Make struct dirent contain a full 64bit inode. Allow more than 255 byte
[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.6 2005/08/27 20:23:05 joerg 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(inumber, f)
132         ino_t inumber;
133         struct open_file *f;
134 {
135         struct file *fp = (struct file *)f->f_fsdata;
136         struct fs *fs = fp->f_fs;
137         char *buf;
138         size_t rsize;
139         int rc;
140
141         if (fs == NULL)
142             panic("fs == NULL");
143
144         /*
145          * Read inode and save it.
146          */
147         buf = malloc(fs->fs_bsize);
148         twiddle();
149         rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
150                 fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
151                 buf, &rsize);
152         if (rc)
153                 goto out;
154         if (rsize != fs->fs_bsize) {
155                 rc = EIO;
156                 goto out;
157         }
158
159         {
160                 struct dinode *dp;
161
162                 dp = (struct dinode *)buf;
163                 fp->f_di = dp[ino_to_fsbo(fs, inumber)];
164         }
165
166         /*
167          * Clear out the old buffers
168          */
169         {
170                 int level;
171
172                 for (level = 0; level < NIADDR; level++)
173                         fp->f_blkno[level] = -1;
174                 fp->f_buf_blkno = -1;
175         }
176 out:
177         free(buf);
178         return (rc);     
179 }
180
181 /*
182  * Given an offset in a file, find the disk block number that
183  * contains that block.
184  */
185 static int
186 block_map(f, file_block, disk_block_p)
187         struct open_file *f;
188         daddr_t file_block;
189         daddr_t *disk_block_p;  /* out */
190 {
191         struct file *fp = (struct file *)f->f_fsdata;
192         struct fs *fs = fp->f_fs;
193         int level;
194         int idx;
195         daddr_t ind_block_num;
196         daddr_t *ind_p;
197         int rc;
198
199         /*
200          * Index structure of an inode:
201          *
202          * di_db[0..NDADDR-1]   hold block numbers for blocks
203          *                      0..NDADDR-1
204          *
205          * di_ib[0]             index block 0 is the single indirect block
206          *                      holds block numbers for blocks
207          *                      NDADDR .. NDADDR + NINDIR(fs)-1
208          *
209          * di_ib[1]             index block 1 is the double indirect block
210          *                      holds block numbers for INDEX blocks for blocks
211          *                      NDADDR + NINDIR(fs) ..
212          *                      NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
213          *
214          * di_ib[2]             index block 2 is the triple indirect block
215          *                      holds block numbers for double-indirect
216          *                      blocks for blocks
217          *                      NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
218          *                      NDADDR + NINDIR(fs) + NINDIR(fs)**2
219          *                              + NINDIR(fs)**3 - 1
220          */
221
222         if (file_block < NDADDR) {
223                 /* Direct block. */
224                 *disk_block_p = fp->f_di.di_db[file_block];
225                 return (0);
226         }
227
228         file_block -= NDADDR;
229
230         /*
231          * nindir[0] = NINDIR
232          * nindir[1] = NINDIR**2
233          * nindir[2] = NINDIR**3
234          *      etc
235          */
236         for (level = 0; level < NIADDR; level++) {
237                 if (file_block < fp->f_nindir[level])
238                         break;
239                 file_block -= fp->f_nindir[level];
240         }
241         if (level == NIADDR) {
242                 /* Block number too high */
243                 return (EFBIG);
244         }
245
246         ind_block_num = fp->f_di.di_ib[level];
247
248         for (; level >= 0; level--) {
249                 if (ind_block_num == 0) {
250                         *disk_block_p = 0;      /* missing */
251                         return (0);
252                 }
253
254                 if (fp->f_blkno[level] != ind_block_num) {
255                         if (fp->f_blk[level] == (char *)0)
256                                 fp->f_blk[level] =
257                                         malloc(fs->fs_bsize);
258                         twiddle();
259                         rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
260                                 fsbtodb(fp->f_fs, ind_block_num),
261                                 fs->fs_bsize,
262                                 fp->f_blk[level],
263                                 &fp->f_blksize[level]);
264                         if (rc)
265                                 return (rc);
266                         if (fp->f_blksize[level] != fs->fs_bsize)
267                                 return (EIO);
268                         fp->f_blkno[level] = ind_block_num;
269                 }
270
271                 ind_p = (daddr_t *)fp->f_blk[level];
272
273                 if (level > 0) {
274                         idx = file_block / fp->f_nindir[level - 1];
275                         file_block %= fp->f_nindir[level - 1];
276                 } else
277                         idx = file_block;
278
279                 ind_block_num = ind_p[idx];
280         }
281
282         *disk_block_p = ind_block_num;
283
284         return (0);
285 }
286
287 /*
288  * Read a portion of a file into an internal buffer.  Return
289  * the location in the buffer and the amount in the buffer.
290  */
291 static int
292 buf_read_file(f, buf_p, size_p)
293         struct open_file *f;
294         char **buf_p;           /* out */
295         size_t *size_p;         /* out */
296 {
297         struct file *fp = (struct file *)f->f_fsdata;
298         struct fs *fs = fp->f_fs;
299         long off;
300         daddr_t file_block;
301         daddr_t disk_block;
302         size_t block_size;
303         int rc;
304
305         off = blkoff(fs, fp->f_seekp);
306         file_block = lblkno(fs, fp->f_seekp);
307         block_size = dblksize(fs, &fp->f_di, file_block);
308
309         if (file_block != fp->f_buf_blkno) {
310                 rc = block_map(f, file_block, &disk_block);
311                 if (rc)
312                         return (rc);
313
314                 if (fp->f_buf == (char *)0)
315                         fp->f_buf = malloc(fs->fs_bsize);
316
317                 if (disk_block == 0) {
318                         bzero(fp->f_buf, block_size);
319                         fp->f_buf_size = block_size;
320                 } else {
321                         twiddle();
322                         rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
323                                 fsbtodb(fs, disk_block),
324                                 block_size, fp->f_buf, &fp->f_buf_size);
325                         if (rc)
326                                 return (rc);
327                 }
328
329                 fp->f_buf_blkno = file_block;
330         }
331
332         /*
333          * Return address of byte in buffer corresponding to
334          * offset, and size of remainder of buffer after that
335          * byte.
336          */
337         *buf_p = fp->f_buf + off;
338         *size_p = block_size - off;
339
340         /*
341          * But truncate buffer at end of file.
342          */
343         if (*size_p > fp->f_di.di_size - fp->f_seekp)
344                 *size_p = fp->f_di.di_size - fp->f_seekp;
345
346         return (0);
347 }
348
349 /*
350  * Search a directory for a name and return its
351  * i_number.
352  */
353 static int
354 search_directory(name, f, inumber_p)
355         char *name;
356         struct open_file *f;
357         ino_t *inumber_p;               /* out */
358 {
359         struct file *fp = (struct file *)f->f_fsdata;
360         struct direct *dp;
361         struct direct *edp;
362         char *buf;
363         size_t buf_size;
364         int namlen, length;
365         int rc;
366
367         length = strlen(name);
368
369         fp->f_seekp = 0;
370         while (fp->f_seekp < fp->f_di.di_size) {
371                 rc = buf_read_file(f, &buf, &buf_size);
372                 if (rc)
373                         return (rc);
374
375                 dp = (struct direct *)buf;
376                 edp = (struct direct *)(buf + buf_size);
377                 while (dp < edp) {
378                         if (dp->d_ino == (ino_t)0)
379                                 goto next;
380 #if BYTE_ORDER == LITTLE_ENDIAN
381                         if (fp->f_fs->fs_maxsymlinklen <= 0)
382                                 namlen = dp->d_type;
383                         else
384 #endif
385                                 namlen = dp->d_namlen;
386                         if (namlen == length &&
387                             !strcmp(name, dp->d_name)) {
388                                 /* found entry */
389                                 *inumber_p = dp->d_ino;
390                                 return (0);
391                         }
392                 next:
393                         dp = (struct direct *)((char *)dp + dp->d_reclen);
394                 }
395                 fp->f_seekp += buf_size;
396         }
397         return (ENOENT);
398 }
399
400 /*
401  * Open a file.
402  */
403 static int
404 ufs_open(upath, f)
405         const char *upath;
406         struct open_file *f;
407 {
408         char *cp, *ncp;
409         int c;
410         ino_t inumber, parent_inumber;
411         struct file *fp;
412         struct fs *fs;
413         int rc;
414         size_t buf_size;
415         int nlinks = 0;
416         char namebuf[MAXPATHLEN+1];
417         char *buf = NULL;
418         char *path = NULL;
419
420         /* allocate file system specific data structure */
421         fp = malloc(sizeof(struct file));
422         bzero(fp, sizeof(struct file));
423         f->f_fsdata = (void *)fp;
424
425         /* allocate space and read super block */
426         fs = malloc(SBSIZE);
427         fp->f_fs = fs;
428         twiddle();
429         rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
430                 SBLOCK, SBSIZE, (char *)fs, &buf_size);
431         if (rc)
432                 goto out;
433
434         if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
435             fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
436                 rc = EINVAL;
437                 goto out;
438         }
439 #ifdef COMPAT_UFS
440         ffs_oldfscompat(fs);
441 #endif
442
443         /*
444          * Calculate indirect block levels.
445          */
446         {
447                 int mult;
448                 int level;
449
450                 mult = 1;
451                 for (level = 0; level < NIADDR; level++) {
452                         mult *= NINDIR(fs);
453                         fp->f_nindir[level] = 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         rc = 0;
581 out:
582         if (buf)
583                 free(buf);
584         if (path)
585                 free(path);
586         if (rc) {
587                 if (fp->f_buf)
588                         free(fp->f_buf);
589                 free(fp->f_fs);
590                 free(fp);
591         }
592         return (rc);
593 }
594
595 static int
596 ufs_close(f)
597         struct open_file *f;
598 {
599         struct file *fp = (struct file *)f->f_fsdata;
600         int level;
601
602         f->f_fsdata = (void *)0;
603         if (fp == (struct file *)0)
604                 return (0);
605
606         for (level = 0; level < NIADDR; level++) {
607                 if (fp->f_blk[level])
608                         free(fp->f_blk[level]);
609         }
610         if (fp->f_buf)
611                 free(fp->f_buf);
612         free(fp->f_fs);
613         free(fp);
614         return (0);
615 }
616
617 /*
618  * Copy a portion of a file into kernel memory.
619  * Cross block boundaries when necessary.
620  */
621 static int
622 ufs_read(f, start, size, resid)
623         struct open_file *f;
624         void *start;
625         size_t size;
626         size_t *resid;  /* out */
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(f, offset, where)
660         struct open_file *f;
661         off_t offset;
662         int where;
663 {
664         struct file *fp = (struct file *)f->f_fsdata;
665
666         switch (where) {
667         case SEEK_SET:
668                 fp->f_seekp = offset;
669                 break;
670         case SEEK_CUR:
671                 fp->f_seekp += offset;
672                 break;
673         case SEEK_END:
674                 fp->f_seekp = fp->f_di.di_size - offset;
675                 break;
676         default:
677                 return (-1);
678         }
679         return (fp->f_seekp);
680 }
681
682 static int
683 ufs_stat(f, sb)
684         struct open_file *f;
685         struct stat *sb;
686 {
687         struct file *fp = (struct file *)f->f_fsdata;
688
689         /* only important stuff */
690         sb->st_mode = fp->f_di.di_mode;
691         sb->st_uid = fp->f_di.di_uid;
692         sb->st_gid = fp->f_di.di_gid;
693         sb->st_size = fp->f_di.di_size;
694         return (0);
695 }
696
697 static int
698 ufs_readdir(struct open_file *f, struct dirent *d)
699 {
700         struct file *fp = (struct file *)f->f_fsdata;
701         struct direct *dp;
702         char *buf;
703         size_t buf_size;
704         int error;
705
706         /*
707          * assume that a directory entry will not be split across blocks
708          */
709 again:
710         if (fp->f_seekp >= fp->f_di.di_size)
711                 return (ENOENT);
712         error = buf_read_file(f, &buf, &buf_size);
713         if (error)
714                 return (error);
715         dp = (struct direct *)buf;
716         fp->f_seekp += dp->d_reclen;
717         if (dp->d_ino == (ino_t)0)
718                 goto again;
719         d->d_type = dp->d_type;
720         strcpy(d->d_name, dp->d_name);
721         return (0);
722 }
723
724 #ifdef COMPAT_UFS
725 /*
726  * Sanity checks for old file systems.
727  *
728  * XXX - goes away some day.
729  */
730 static void
731 ffs_oldfscompat(fs)
732         struct fs *fs;
733 {
734         int i;
735
736         fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);       /* XXX */
737         fs->fs_interleave = max(fs->fs_interleave, 1);          /* XXX */
738         if (fs->fs_postblformat == FS_42POSTBLFMT)              /* XXX */
739                 fs->fs_nrpos = 8;                               /* XXX */
740         if (fs->fs_inodefmt < FS_44INODEFMT) {                  /* XXX */
741                 quad_t sizepb = fs->fs_bsize;                   /* XXX */
742                                                                 /* XXX */
743                 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */
744                 for (i = 0; i < NIADDR; i++) {                  /* XXX */
745                         sizepb *= NINDIR(fs);                   /* XXX */
746                         fs->fs_maxfilesize += sizepb;           /* XXX */
747                 }                                               /* XXX */
748                 fs->fs_qbmask = ~fs->fs_bmask;                  /* XXX */
749                 fs->fs_qfmask = ~fs->fs_fmask;                  /* XXX */
750         }                                                       /* XXX */
751 }
752 #endif