1 /*        $NetBSD: ufs.c,v 1.88 2022/12/01 18:06:09 christos Exp $    */
2 
3 /*-
4  * Copyright (c) 1993
5  *        The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * The Mach Operating System project at Carnegie-Mellon University.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *
35  * Copyright (c) 1990, 1991 Carnegie Mellon University
36  * All Rights Reserved.
37  *
38  * Author: David Golub
39  *
40  * Permission to use, copy, modify and distribute this software and its
41  * documentation is hereby granted, provided that both the copyright
42  * notice and this permission notice appear in all copies of the
43  * software, derivative works or modified versions, and any portions
44  * thereof, and that both notices appear in supporting documentation.
45  *
46  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
47  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
48  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
49  *
50  * Carnegie Mellon requests users of this software to return to
51  *
52  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
53  *  School of Computer Science
54  *  Carnegie Mellon University
55  *  Pittsburgh PA 15213-3890
56  *
57  * any improvements or extensions that they make and grant Carnegie the
58  * rights to redistribute these changes.
59  */
60 
61 /*
62  *        Stand-alone file reading package for UFS and LFS filesystems.
63  */
64 
65 #include <sys/param.h>
66 #include <sys/time.h>
67 #include <ufs/ufs/dinode.h>
68 #include <ufs/ufs/dir.h>
69 #ifdef LIBSA_LFS
70 #include <sys/queue.h>
71 #include <sys/condvar.h>
72 #include <sys/mount.h>                            /* XXX for MNAMELEN */
73 #include <ufs/lfs/lfs.h>
74 #else
75 #include <ufs/ffs/fs.h>
76 #endif
77 #ifdef _STANDALONE
78 #include <lib/libkern/libkern.h>
79 #else
80 #include <string.h>
81 #endif
82 
83 #include "stand.h"
84 #ifdef LIBSA_LFS
85 #include "lfs.h"
86 #else
87 #include "ufs.h"
88 #endif
89 
90 /* If this file is compiled by itself, build ufs (aka ffsv1) support */
91 #if !defined(LIBSA_FFSv2) && !defined(LIBSA_LFS)
92 #define LIBSA_FFSv1
93 #endif
94 
95 #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
96 #define LIBSA_NO_FS_SYMLINK
97 #endif
98 #if defined(COMPAT_UFS) && defined(LIBSA_NO_COMPAT_UFS)
99 #undef COMPAT_UFS
100 #endif
101 
102 #ifdef LIBSA_LFS
103 /* Do not (yet) support FFS_EI on LFS. */
104 #undef LIBSA_FFS_EI
105 /*
106  * In-core LFS superblock - just the on-disk one.
107  */
108 struct salfs {
109           union {
110                     struct dlfs u_32;
111                     struct dlfs64 u_64;
112           } lfs_dlfs_u;
113           unsigned lfs_is64 : 1,
114                     lfs_dobyteswap : 1,
115                     lfs_hasolddirfmt : 1;
116 };
117 /* Get lfs accessors that use struct salfs. */
118 #define STRUCT_LFS struct salfs
119 #include <ufs/lfs/lfs_accessors.h>
120 
121 /* override this to avoid a mess with the dinode accessors */
122 #define lfs_dino_getsize(fs, dp) ((dp)->di_size)
123 
124 typedef struct salfs FS;
125 #define fs_magic    lfs_dlfs_u.u_32.dlfs_magic
126 #define fs_maxsymlinklen lfs_dlfs_u.u_32.dlfs_maxsymlinklen
127 #define lfs_version lfs_dlfs_u.u_32.dlfs_version
128 
129 #define SBLOCKSIZE  LFS_SBPAD
130 #define SBLOCKOFFSET          LFS_LABELPAD
131 #else
132 /* NB ufs2 doesn't use the common superblock code... */
133 typedef struct fs FS;
134 #define SBLOCKOFFSET          SBLOCK_UFS1
135 #endif
136 
137 #if defined(LIBSA_NO_TWIDDLE)
138 #define twiddle()
139 #endif
140 
141 #undef cgstart
142 #if defined(LIBSA_FFSv2)
143 #define cgstart(fc, c) cgstart_ufs2((fs), (c))
144 #else
145 #define cgstart(fc, c) cgstart_ufs1((fs), (c))
146 #endif
147 
148 #ifndef ufs_dinode
149 #define ufs_dinode  ufs1_dinode
150 #endif
151 #ifndef indp_t
152 #define indp_t                int32_t
153 #endif
154 typedef uint32_t    ino32_t;
155 
156 #ifndef FSBTODB
157 #define FSBTODB(fs, indp) FFS_FSBTODB(fs, indp)
158 #endif
159 #ifndef UFS_NINDIR
160 #define UFS_NINDIR FFS_NINDIR
161 #endif
162 #ifndef ufs_blkoff
163 #define ufs_blkoff ffs_blkoff
164 #endif
165 #ifndef ufs_lblkno
166 #define ufs_lblkno ffs_lblkno
167 #endif
168 #ifndef ufs_dinode_swap
169 #define ufs_dinode_swap ffs_dinode1_swap
170 #endif
171 #ifndef ufs_indp_swap
172 #define ufs_indp_swap bswap32
173 #endif
174 
175 /*
176  * To avoid having a lot of filesystem-block sized buffers lurking (which
177  * could be 32k) we only keep a few entries of the indirect block map.
178  * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
179  * ~13 times pulling in a 6M kernel.
180  * The cache size must be smaller than the smallest filesystem block,
181  * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
182  */
183 #define LN2_IND_CACHE_SZ      6
184 #define IND_CACHE_SZ                    (1 << LN2_IND_CACHE_SZ)
185 #define IND_CACHE_MASK                  (IND_CACHE_SZ - 1)
186 
187 /*
188  * In-core open file.
189  */
190 struct file {
191           off_t               f_seekp;  /* seek pointer */
192           FS                  *f_fs;              /* pointer to super-block */
193           struct ufs_dinode   f_di;               /* copy of on-disk inode */
194           uint                f_nishift;          /* for blocks in indirect block */
195           indp_t              f_ind_cache_block;
196           indp_t              f_ind_cache[IND_CACHE_SZ];
197 
198           char                *f_buf;             /* buffer for data block */
199           size_t              f_buf_size;         /* size of data block */
200           daddr_t             f_buf_blkno;        /* block number of data block */
201 #if defined(LIBSA_FFS_EI)
202           bool                f_swapped;          /* FFS is other endian */
203 #endif
204 };
205 
206 static int read_inode(ino32_t, struct open_file *);
207 static int block_map(struct open_file *, indp_t, indp_t *);
208 static int buf_read_file(struct open_file *, char **, size_t *);
209 static int search_directory(const char *, int, struct open_file *, ino32_t *);
210 #ifdef LIBSA_FFSv1
211 static void ffs_oldfscompat(FS *);
212 #endif
213 
214 #ifdef LIBSA_FFSv1
215 static __inline__ bool
ffs_is_magic(FS * fs)216 ffs_is_magic(FS *fs)
217 {
218           return fs->fs_magic == FS_UFS1_MAGIC;
219 }
220 
221 #ifdef LIBSA_FFS_EI
222 static __inline__ bool
ffs_is_magic_swapped(FS * fs)223 ffs_is_magic_swapped(FS *fs)
224 {
225           return fs->fs_magic == bswap32(FS_UFS1_MAGIC);
226 }
227 #endif
228 
229 #endif
230 
231 #ifdef LIBSA_FFSv2
232 static __inline__ bool
ffs_is_magic(FS * fs)233 ffs_is_magic(FS *fs)
234 {
235           return fs->fs_magic == FS_UFS2_MAGIC || fs->fs_magic == FS_UFS2EA_MAGIC;
236 }
237 
238 #ifdef LIBSA_FFS_EI
239 static __inline__ bool
ffs_is_magic_swapped(FS * fs)240 ffs_is_magic_swapped(FS *fs)
241 {
242           return fs->fs_magic == bswap32(FS_UFS2_MAGIC) ||
243                     fs->fs_magic == bswap32(FS_UFS2EA_MAGIC);
244 }
245 #endif
246 
247 #endif
248 
249 #ifdef LIBSA_LFS
250 static __inline__ bool
ffs_is_magic(FS * fs)251 ffs_is_magic(FS *fs)
252 {
253           return fs->fs_magic == LFS_MAGIC;
254 }
255 
256 #ifdef LIBSA_FFS_EI
257 static __inline__ bool
ffs_is_magic_swapped(FS * fs)258 ffs_is_magic_swapped(FS *fs)
259 {
260           return fs->fs_magic == bswap32(LFS_MAGIC);
261 }
262 #endif
263 
264 #endif
265 
266 static __inline__ void
ffs_fix_magic_swapped(struct file * fp,FS * fs)267 ffs_fix_magic_swapped(struct file *fp, FS *fs)
268 {
269 #ifdef LIBSA_FFS_EI
270           fp->f_swapped = ffs_is_magic_swapped(fs);
271           if (fp->f_swapped)
272 {
273                     ffs_sb_swap(fs, fs);
274 }
275 #endif
276 }
277 
278 #ifdef LIBSA_FFS_EI
279 static __inline__ bool
ffs_swapped(struct file * fp)280 ffs_swapped(struct file *fp)
281 {
282           return fp->f_swapped;
283 }
284 #endif
285 
286 static __inline__ uint16_t
ffs_get_reclen(struct file * fp,struct direct * dp)287 ffs_get_reclen(struct file *fp, struct direct *dp)
288 {
289 #ifdef LIBSA_FFS_EI
290           if (ffs_swapped(fp))
291                     return bswap16(dp->d_reclen);
292 #endif
293           return dp->d_reclen;
294 }
295 
296 static __inline__ uint32_t
ffs_get_ino(struct file * fp,struct direct * dp)297 ffs_get_ino(struct file *fp, struct direct *dp)
298 {
299 #ifdef LIBSA_FFS_EI
300           if (ffs_swapped(fp))
301                     return bswap32(dp->d_ino);
302 #endif
303           return dp->d_ino;
304 }
305 
306 
307 #ifdef LIBSA_LFS
308 /*
309  * Find an inode's block.  Look it up in the ifile.  Whee!
310  */
311 static int
find_inode_sector(ino32_t inumber,struct open_file * f,daddr_t * isp)312 find_inode_sector(ino32_t inumber, struct open_file *f, daddr_t *isp)
313 {
314           struct file *fp = (struct file *)f->f_fsdata;
315           FS *fs = fp->f_fs;
316           daddr_t ifileent_blkno;
317           char *ent_in_buf;
318           size_t buf_after_ent;
319           size_t entsize;
320           int rc;
321 
322           rc = read_inode(LFS_IFILE_INUM, f);
323           if (rc)
324                     return rc;
325 
326           entsize = fs->lfs_is64 ? sizeof(IFILE64) :
327                     (lfs_sb_getversion(fs) > 1 ? sizeof(IFILE32) : sizeof(IFILE_V1));
328           ifileent_blkno =
329               (inumber / lfs_sb_getifpb(fs)) + lfs_sb_getcleansz(fs) + lfs_sb_getsegtabsz(fs);
330           fp->f_seekp = (off_t)ifileent_blkno * lfs_sb_getbsize(fs) +
331               (inumber % lfs_sb_getifpb(fs)) * entsize;
332           rc = buf_read_file(f, &ent_in_buf, &buf_after_ent);
333           if (rc)
334                     return rc;
335           /* make sure something's not badly wrong, but don't panic. */
336           if (buf_after_ent < entsize)
337                     return EINVAL;
338 
339           *isp = FSBTODB(fs, lfs_if_getdaddr(fs, (IFILE *)ent_in_buf));
340           if (*isp == LFS_UNUSED_DADDR) /* again, something badly wrong */
341                     return EINVAL;
342           return 0;
343 }
344 #endif
345 
346 /*
347  * Read a new inode into a file structure.
348  */
349 static int
read_inode(ino32_t inumber,struct open_file * f)350 read_inode(ino32_t inumber, struct open_file *f)
351 {
352           struct file *fp = (struct file *)f->f_fsdata;
353           FS *fs = fp->f_fs;
354           char *buf;
355           size_t rsize;
356           int rc;
357           daddr_t inode_sector = 0; /* XXX: gcc */
358 #ifdef LIBSA_LFS
359           struct ufs_dinode *dip;
360           int cnt;
361 #endif
362 
363 #ifdef LIBSA_LFS
364           if (inumber == LFS_IFILE_INUM)
365                     inode_sector = FSBTODB(fs, lfs_sb_getidaddr(fs));
366           else if ((rc = find_inode_sector(inumber, f, &inode_sector)) != 0)
367                     return rc;
368 #else
369           inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
370 #endif
371 
372           /*
373            * Read inode and save it.
374            */
375           buf = fp->f_buf;
376           twiddle();
377           rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
378               inode_sector, fs->fs_bsize, buf, &rsize);
379           if (rc)
380                     return rc;
381           if (rsize != (size_t)fs->fs_bsize)
382                     return EIO;
383 
384 #ifdef LIBSA_LFS
385           cnt = INOPBx(fs);
386           dip = (struct ufs_dinode *)buf + (cnt - 1);
387           for (; dip->di_inumber != inumber; --dip) {
388                     /* kernel code panics, but boot blocks which panic are Bad. */
389                     if (--cnt == 0)
390                               return EINVAL;
391           }
392           fp->f_di = *dip;
393 #else
394           fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)];
395 #ifdef LIBSA_FFS_EI
396           if (ffs_swapped(fp))
397                     ufs_dinode_swap(&fp->f_di, &fp->f_di);
398 #endif
399 #endif
400 
401           /*
402            * Clear out the old buffers
403            */
404           fp->f_ind_cache_block = ~0;
405           fp->f_buf_blkno = -1;
406           return rc;
407 }
408 
409 /*
410  * Given an offset in a file, find the disk block number that
411  * contains that block.
412  */
413 static int
block_map(struct open_file * f,indp_t file_block,indp_t * disk_block_p)414 block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p)
415 {
416           struct file *fp = (struct file *)f->f_fsdata;
417           FS *fs = fp->f_fs;
418           uint level;
419           indp_t ind_cache;
420           indp_t ind_block_num;
421           size_t rsize;
422           int rc;
423           indp_t *buf = (void *)fp->f_buf;
424 
425           /*
426            * Index structure of an inode:
427            *
428            * di_db[0..UFS_NDADDR-1]     hold block numbers for blocks
429            *                            0..UFS_NDADDR-1
430            *
431            * di_ib[0]                   index block 0 is the single indirect block
432            *                            holds block numbers for blocks
433            *                            UFS_NDADDR .. UFS_NDADDR + UFS_NINDIR(fs)-1
434            *
435            * di_ib[1]                   index block 1 is the double indirect block
436            *                            holds block numbers for INDEX blocks for blocks
437            *                            UFS_NDADDR + UFS_NINDIR(fs) ..
438            *                            UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 - 1
439            *
440            * di_ib[2]                   index block 2 is the triple indirect block
441            *                            holds block numbers for double-indirect
442            *                            blocks for blocks
443            *                            UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 ..
444            *                            UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2
445            *                                      + UFS_NINDIR(fs)**3 - 1
446            */
447 
448           if (file_block < UFS_NDADDR) {
449                     /* Direct block. */
450                     *disk_block_p = fp->f_di.di_db[file_block];
451                     return 0;
452           }
453 
454           file_block -= UFS_NDADDR;
455 
456           ind_cache = file_block >> LN2_IND_CACHE_SZ;
457           if (ind_cache == fp->f_ind_cache_block) {
458                     *disk_block_p = fp->f_ind_cache[file_block & IND_CACHE_MASK];
459                     return 0;
460           }
461 
462           for (level = 0;;) {
463                     level += fp->f_nishift;
464                     if (file_block < (indp_t)1 << level)
465                               break;
466                     if (level > UFS_NIADDR * fp->f_nishift)
467                               /* Block number too high */
468                               return EFBIG;
469                     file_block -= (indp_t)1 << level;
470           }
471 
472           ind_block_num = fp->f_di.di_ib[level / fp->f_nishift - 1];
473 
474           for (;;) {
475                     level -= fp->f_nishift;
476                     if (ind_block_num == 0) {
477                               *disk_block_p = 0;  /* missing */
478                               return 0;
479                     }
480 
481                     twiddle();
482                     /*
483                      * If we were feeling brave, we could work out the number
484                      * of the disk sector and read a single disk sector instead
485                      * of a filesystem block.
486                      * However we don't do this very often anyway...
487                      */
488                     rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
489                               FSBTODB(fp->f_fs, ind_block_num), fs->fs_bsize,
490                               buf, &rsize);
491                     if (rc)
492                               return rc;
493                     if (rsize != (size_t)fs->fs_bsize)
494                               return EIO;
495 #ifdef LIBSA_FFS_EI
496                     if (ffs_swapped(fp))
497                               ind_block_num = ufs_indp_swap(buf[file_block >> level]);
498                     else
499 #endif
500                               ind_block_num = buf[file_block >> level];
501                     if (level == 0)
502                               break;
503                     file_block &= (1 << level) - 1;
504           }
505 
506           /* Save the part of the block that contains this sector */
507 #if defined(LIBSA_FFS_EI)
508           if (ffs_swapped(fp)) {
509                     size_t i;
510 
511                     for (i = 0; i < IND_CACHE_SZ; i++) {
512                               fp->f_ind_cache[i] = ufs_indp_swap(
513                                   buf[(file_block & ~IND_CACHE_MASK) + i]);
514                     }
515           } else
516 #endif
517                     memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK],
518                         IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
519           fp->f_ind_cache_block = ind_cache;
520 
521           *disk_block_p = ind_block_num;
522 
523           return 0;
524 }
525 
526 /*
527  * Read a portion of a file into an internal buffer.
528  * Return the location in the buffer and the amount in the buffer.
529  */
530 static int
buf_read_file(struct open_file * f,char ** buf_p,size_t * size_p)531 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
532 {
533           struct file *fp = (struct file *)f->f_fsdata;
534           FS *fs = fp->f_fs;
535           long off;
536           indp_t file_block;
537           size_t block_size;
538           int rc;
539 
540           off = ufs_blkoff(fs, fp->f_seekp);
541           file_block = ufs_lblkno(fs, fp->f_seekp);
542 #ifdef LIBSA_LFS
543           block_size = (size_t)dblksize(fs, &fp->f_di, (uint64_t)file_block);
544 #else
545           block_size = (size_t)ffs_sblksize(fs, (int64_t)fp->f_di.di_size, file_block);
546 #endif
547 
548           if (file_block != fp->f_buf_blkno) {
549                     indp_t disk_block = 0; /* XXX: gcc */
550                     rc = block_map(f, file_block, &disk_block);
551                     if (rc)
552                               return rc;
553 
554                     if (disk_block == 0) {
555                               memset(fp->f_buf, 0, block_size);
556                               fp->f_buf_size = block_size;
557                     } else {
558                               twiddle();
559                               rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
560                                         FSBTODB(fs, disk_block),
561                                         block_size, fp->f_buf, &fp->f_buf_size);
562                               if (rc)
563                                         return rc;
564                     }
565 
566                     fp->f_buf_blkno = file_block;
567           }
568 
569           /*
570            * Return address of byte in buffer corresponding to
571            * offset, and size of remainder of buffer after that
572            * byte.
573            */
574           *buf_p = fp->f_buf + off;
575           *size_p = block_size - off;
576 
577           /*
578            * But truncate buffer at end of file.
579            */
580           if (*size_p > fp->f_di.di_size - fp->f_seekp)
581                     *size_p = fp->f_di.di_size - fp->f_seekp;
582 
583           return 0;
584 }
585 
586 /*
587  * Search a directory for a name and return its
588  * inode number.
589  */
590 static int
search_directory(const char * name,int length,struct open_file * f,ino32_t * inumber_p)591 search_directory(const char *name, int length, struct open_file *f,
592           ino32_t *inumber_p)
593 {
594           struct file *fp = (struct file *)f->f_fsdata;
595           struct direct *dp;
596           struct direct *edp;
597           char *buf;
598           size_t buf_size;
599           int namlen;
600           int rc;
601 
602           fp->f_seekp = 0;
603           while (fp->f_seekp < (off_t)fp->f_di.di_size) {
604                     rc = buf_read_file(f, &buf, &buf_size);
605                     if (rc)
606                               return rc;
607 
608                     dp = (struct direct *)buf;
609                     edp = (struct direct *)(buf + buf_size);
610                     for (; dp < edp;
611                          dp = (void *)((char *)dp + ffs_get_reclen(fp, dp))) {
612                               if (ffs_get_reclen(fp, dp) <= 0)
613                                         break;
614                               if (ffs_get_ino(fp, dp) == (ino32_t)0)
615                                         continue;
616 #if BYTE_ORDER == LITTLE_ENDIAN
617                               if (fp->f_fs->fs_maxsymlinklen <= 0)
618                                         namlen = dp->d_type;
619                               else
620 #endif
621                                         namlen = dp->d_namlen;
622                               if (namlen == length &&
623                                   !memcmp(name, dp->d_name, length)) {
624                                         /* found entry */
625                                         *inumber_p = ffs_get_ino(fp, dp);
626                                         return 0;
627                               }
628                     }
629                     fp->f_seekp += buf_size;
630           }
631           return ENOENT;
632 }
633 
634 static __inline__ int
ffs_find_superblock(struct open_file * f,FS * fs)635 ffs_find_superblock(struct open_file *f, FS *fs)
636 {
637           struct file *fp = (struct file *)f->f_fsdata;
638           int rc;
639           size_t buf_size;
640 #ifdef LIBSA_FFSv2
641           static daddr_t sblock_try[] = SBLOCKSEARCH;
642           int i;
643 #endif
644 
645 #ifdef LIBSA_FFSv2
646           for (i = 0; sblock_try[i] != -1; i++) {
647                     rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
648                         sblock_try[i] / GETSECSIZE(f), SBLOCKSIZE, fs, &buf_size);
649                     if (rc)
650                               return rc;
651                     if (buf_size != SBLOCKSIZE)
652                               return EINVAL;
653                     ffs_fix_magic_swapped(fp, fs);
654                     if (fs->fs_sblockloc != sblock_try[i])
655                               /* an alternate superblock - try again */
656                               continue;
657                     if (ffs_is_magic(fs))
658                               return 0;
659           }
660           return EINVAL;
661 #else /* LIBSA_FFSv2 */
662           rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
663                     SBLOCKOFFSET / GETSECSIZE(f), SBLOCKSIZE, fs, &buf_size);
664           if (rc)
665                     return rc;
666           if (buf_size != SBLOCKSIZE)
667                     return EINVAL;
668           ffs_fix_magic_swapped(fp, fs);
669 
670 #ifdef LIBSA_LFS
671           if (fs->lfs_version != REQUIRED_LFS_VERSION)
672                     return EINVAL;
673 #endif
674           if (!ffs_is_magic(fs))
675                     return EINVAL;
676 
677           return 0;
678 #endif /* !LIBSA_FFSv2 */
679 }
680 
681 /*
682  * Open a file.
683  */
684 __compactcall int
ufs_open(const char * path,struct open_file * f)685 ufs_open(const char *path, struct open_file *f)
686 {
687 #ifndef LIBSA_FS_SINGLECOMPONENT
688           const char *cp, *ncp;
689           int c;
690 #endif
691           ino32_t inumber;
692           struct file *fp;
693           FS *fs;
694           int rc;
695 #ifndef LIBSA_NO_FS_SYMLINK
696           ino32_t parent_inumber;
697           int nlinks = 0;
698           char namebuf[MAXPATHLEN+1];
699           char *buf;
700 #endif
701 
702           /* allocate file system specific data structure */
703           fp = alloc(sizeof(struct file));
704           memset(fp, 0, sizeof(struct file));
705           f->f_fsdata = (void *)fp;
706 
707           /* allocate space and read super block */
708           fs = alloc(SBLOCKSIZE);
709           fp->f_fs = fs;
710           twiddle();
711 
712           rc = ffs_find_superblock(f, fs);
713           if (rc)
714                     goto out;
715 
716 #if defined(LIBSA_LFS) && REQUIRED_LFS_VERSION == 2
717           /*
718            * XXX    We should check the second superblock and use the eldest
719            *        of the two.  See comments near the top of lfs_mountfs()
720            *        in sys/ufs/lfs/lfs_vfsops.c.
721            *      This may need a LIBSA_LFS_SMALL check as well.
722            */
723 #endif
724 #if defined(LIBSA_LFS)
725           fs->lfs_is64 = 0;
726           fs->lfs_dobyteswap = 0;
727           fs->lfs_hasolddirfmt = (fs->fs_maxsymlinklen <= 0);
728 #endif
729 #ifdef LIBSA_FFSv1
730           ffs_oldfscompat(fs);
731 #endif
732 
733           if (fs->fs_bsize > MAXBSIZE ||
734               (size_t)fs->fs_bsize < sizeof(FS)) {
735                     rc = EINVAL;
736                     goto out;
737           }
738 
739           /*
740            * Calculate indirect block levels.
741            */
742           {
743                     indp_t mult;
744                     int ln2;
745 
746                     /*
747                      * We note that the number of indirect blocks is always
748                      * a power of 2.  This lets us use shifts and masks instead
749                      * of divide and remainder and avoids pulling in the
750                      * 64bit division routine into the boot code.
751                      */
752                     mult = UFS_NINDIR(fs);
753 #ifdef DEBUG
754                     if (mult & (mult - 1)) {
755                               /* Hummm was't a power of 2 */
756                               rc = EINVAL;
757                               goto out;
758                     }
759 #endif
760                     for (ln2 = 0; mult != 1; ln2++)
761                               mult >>= 1;
762 
763                     fp->f_nishift = ln2;
764           }
765 
766           /* alloc a block sized buffer used for all fs transfers */
767           fp->f_buf = alloc(fs->fs_bsize);
768           inumber = UFS_ROOTINO;
769           if ((rc = read_inode(inumber, f)) != 0)
770                     goto out;
771 
772 #ifndef LIBSA_FS_SINGLECOMPONENT
773           cp = path;
774           while (*cp) {
775 
776                     /*
777                      * Remove extra separators
778                      */
779                     while (*cp == '/')
780                               cp++;
781                     if (*cp == '\0')
782                               break;
783 
784                     /*
785                      * Check that current node is a directory.
786                      */
787                     if ((fp->f_di.di_mode & IFMT) != IFDIR) {
788                               rc = ENOTDIR;
789                               goto out;
790                     }
791 
792                     /*
793                      * Get next component of path name.
794                      */
795                     ncp = cp;
796                     while ((c = *cp) != '\0' && c != '/')
797                               cp++;
798 
799                     /*
800                      * Look up component in current directory.
801                      * Save directory inumber in case we find a
802                      * symbolic link.
803                      */
804 #ifndef LIBSA_NO_FS_SYMLINK
805                     parent_inumber = inumber;
806 #endif
807                     rc = search_directory(ncp, cp - ncp, f, &inumber);
808                     if (rc)
809                               goto out;
810 
811                     /*
812                      * Open next component.
813                      */
814                     if ((rc = read_inode(inumber, f)) != 0)
815                               goto out;
816 
817 #ifndef LIBSA_NO_FS_SYMLINK
818                     /*
819                      * Check for symbolic link.
820                      */
821                     if ((fp->f_di.di_mode & IFMT) == IFLNK) {
822                               int link_len = fp->f_di.di_size;
823                               int len;
824 
825                               len = strlen(cp);
826 
827                               if (link_len + len > MAXPATHLEN ||
828                                   ++nlinks > MAXSYMLINKS) {
829                                         rc = ENOENT;
830                                         goto out;
831                               }
832 
833                               memmove(&namebuf[link_len], cp, len + 1);
834 
835                               if (link_len < fs->fs_maxsymlinklen) {
836                                         memcpy(namebuf, fp->f_di.di_db, link_len);
837                               } else {
838                                         /*
839                                          * Read file for symbolic link
840                                          */
841                                         size_t buf_size;
842                                         indp_t    disk_block;
843 
844                                         buf = fp->f_buf;
845                                         rc = block_map(f, (indp_t)0, &disk_block);
846                                         if (rc)
847                                                   goto out;
848 
849                                         twiddle();
850                                         rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
851                                                   F_READ, FSBTODB(fs, disk_block),
852                                                   fs->fs_bsize, buf, &buf_size);
853                                         if (rc)
854                                                   goto out;
855 
856                                         memcpy(namebuf, buf, link_len);
857                               }
858 
859                               /*
860                                * If relative pathname, restart at parent directory.
861                                * If absolute pathname, restart at root.
862                                */
863                               cp = namebuf;
864                               if (*cp != '/')
865                                         inumber = parent_inumber;
866                               else
867                                         inumber = (ino32_t)UFS_ROOTINO;
868 
869                               if ((rc = read_inode(inumber, f)) != 0)
870                                         goto out;
871                     }
872 #endif    /* !LIBSA_NO_FS_SYMLINK */
873           }
874 
875           /*
876            * Found terminal component.
877            */
878           rc = 0;
879 
880 #else /* !LIBSA_FS_SINGLECOMPONENT */
881 
882           /* look up component in the current (root) directory */
883           rc = search_directory(path, strlen(path), f, &inumber);
884           if (rc)
885                     goto out;
886 
887           /* open it */
888           rc = read_inode(inumber, f);
889 
890 #endif /* !LIBSA_FS_SINGLECOMPONENT */
891 
892           fp->f_seekp = 0;              /* reset seek pointer */
893 
894 out:
895           if (rc)
896                     ufs_close(f);
897           else
898 #ifdef FSMOD
899                     fsmod = FSMOD;
900 #else
901                     fsmod = NULL;
902 #endif
903           return rc;
904 }
905 
906 __compactcall int
ufs_close(struct open_file * f)907 ufs_close(struct open_file *f)
908 {
909           struct file *fp = (struct file *)f->f_fsdata;
910 
911           f->f_fsdata = NULL;
912           if (fp == NULL)
913                     return 0;
914 
915           if (fp->f_buf)
916                     dealloc(fp->f_buf, fp->f_fs->fs_bsize);
917           dealloc(fp->f_fs, SBLOCKSIZE);
918           dealloc(fp, sizeof(struct file));
919           return 0;
920 }
921 
922 /*
923  * Copy a portion of a file into kernel memory.
924  * Cross block boundaries when necessary.
925  */
926 __compactcall int
ufs_read(struct open_file * f,void * start,size_t size,size_t * resid)927 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
928 {
929           struct file *fp = (struct file *)f->f_fsdata;
930           size_t csize;
931           char *buf;
932           size_t buf_size;
933           int rc = 0;
934           char *addr = start;
935 
936           while (size != 0) {
937                     if (fp->f_seekp >= (off_t)fp->f_di.di_size)
938                               break;
939 
940                     rc = buf_read_file(f, &buf, &buf_size);
941                     if (rc)
942                               break;
943 
944                     csize = size;
945                     if (csize > buf_size)
946                               csize = buf_size;
947 
948                     memcpy(addr, buf, csize);
949 
950                     fp->f_seekp += csize;
951                     addr += csize;
952                     size -= csize;
953           }
954           if (resid)
955                     *resid = size;
956           return rc;
957 }
958 
959 /*
960  * Not implemented.
961  */
962 #ifndef LIBSA_NO_FS_WRITE
963 __compactcall int
ufs_write(struct open_file * f,void * start,size_t size,size_t * resid)964 ufs_write(struct open_file *f, void *start, size_t size, size_t *resid)
965 {
966 
967           return EROFS;
968 }
969 #endif /* !LIBSA_NO_FS_WRITE */
970 
971 #ifndef LIBSA_NO_FS_SEEK
972 __compactcall off_t
ufs_seek(struct open_file * f,off_t offset,int where)973 ufs_seek(struct open_file *f, off_t offset, int where)
974 {
975           struct file *fp = (struct file *)f->f_fsdata;
976 
977           switch (where) {
978           case SEEK_SET:
979                     fp->f_seekp = offset;
980                     break;
981           case SEEK_CUR:
982                     fp->f_seekp += offset;
983                     break;
984           case SEEK_END:
985                     fp->f_seekp = fp->f_di.di_size - offset;
986                     break;
987           default:
988                     return -1;
989           }
990           return fp->f_seekp;
991 }
992 #endif /* !LIBSA_NO_FS_SEEK */
993 
994 __compactcall int
ufs_stat(struct open_file * f,struct stat * sb)995 ufs_stat(struct open_file *f, struct stat *sb)
996 {
997           struct file *fp = (struct file *)f->f_fsdata;
998 
999           /* only important stuff */
1000           memset(sb, 0, sizeof *sb);
1001           sb->st_mode = fp->f_di.di_mode;
1002           sb->st_uid = fp->f_di.di_uid;
1003           sb->st_gid = fp->f_di.di_gid;
1004           sb->st_size = fp->f_di.di_size;
1005           return 0;
1006 }
1007 
1008 #if defined(LIBSA_ENABLE_LS_OP)
1009 
1010 #include "ls.h"
1011 
1012 static const char    *const typestr[] = {
1013           "unknown",
1014           "FIFO",
1015           "CHR",
1016           0,
1017           "DIR",
1018           0,
1019           "BLK",
1020           0,
1021           "REG",
1022           0,
1023           "LNK",
1024           0,
1025           "SOCK",
1026           0,
1027           "WHT"
1028 };
1029 
1030 __compactcall void
ufs_ls(struct open_file * f,const char * pattern)1031 ufs_ls(struct open_file *f, const char *pattern)
1032 {
1033           struct file *fp = (struct file *)f->f_fsdata;
1034           char *buf;
1035           size_t buf_size;
1036           lsentry_t *names = NULL;
1037 
1038           fp->f_seekp = 0;
1039           while (fp->f_seekp < (off_t)fp->f_di.di_size) {
1040                     struct direct  *dp, *edp;
1041                     int rc = buf_read_file(f, &buf, &buf_size);
1042                     if (rc)
1043                               goto out;
1044                     /* some firmware might use block size larger than DEV_BSIZE */
1045                     if (buf_size < UFS_DIRBLKSIZ)
1046                               goto out;
1047 
1048                     dp = (struct direct *)buf;
1049                     edp = (struct direct *)(buf + buf_size);
1050 
1051                     for (; dp < edp;
1052                          dp = (void *)((char *)dp + ffs_get_reclen(fp, dp))) {
1053                               const char *t;
1054                               if (ffs_get_ino(fp, dp) == 0)
1055                                         continue;
1056 
1057                               if (dp->d_type >= NELEM(typestr) ||
1058                                   !(t = typestr[dp->d_type])) {
1059                                         /*
1060                                          * This does not handle "old"
1061                                          * filesystems properly. On little
1062                                          * endian machines, we get a bogus
1063                                          * type name if the namlen matches a
1064                                          * valid type identifier. We could
1065                                          * check if we read namlen "0" and
1066                                          * handle this case specially, if
1067                                          * there were a pressing need...
1068                                          */
1069                                         printf("bad dir entry\n");
1070                                         goto out;
1071                               }
1072                               lsadd(&names, pattern, dp->d_name, strlen(dp->d_name),
1073                                   ffs_get_ino(fp, dp), t);
1074                     }
1075                     fp->f_seekp += buf_size;
1076           }
1077           lsprint(names);
1078 out:      lsfree(names);
1079 }
1080 #endif /* LIBSA_ENABLE_LS_OP */
1081 
1082 #ifdef LIBSA_FFSv1
1083 /*
1084  * Sanity checks for old file systems.
1085  *
1086  * XXX - goes away some day.
1087  * Stripped of stuff libsa doesn't need.....
1088  */
1089 static void
ffs_oldfscompat(FS * fs)1090 ffs_oldfscompat(FS *fs)
1091 {
1092 
1093 #ifdef COMPAT_UFS
1094           /*
1095            * Newer Solaris versions have a slightly incompatible
1096            * superblock - so always calculate this values on the fly, which
1097            * is good enough for libsa purposes
1098            */
1099           if (fs->fs_magic == FS_UFS1_MAGIC
1100 #ifndef COMPAT_SOLARIS_UFS
1101               && fs->fs_old_inodefmt < FS_44INODEFMT
1102 #endif
1103               ) {
1104                     fs->fs_qbmask = ~fs->fs_bmask;
1105                     fs->fs_qfmask = ~fs->fs_fmask;
1106           }
1107 #endif
1108 }
1109 #endif
1110