1 /* $NetBSD: ufs.c,v 1.74 2015/09/01 06:16:58 dholland 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 /*
104 * In-core LFS superblock - just the on-disk one.
105 */
106 struct salfs {
107 union {
108 struct dlfs u_32;
109 struct dlfs64 u_64;
110 } lfs_dlfs_u;
111 unsigned lfs_is64 : 1,
112 lfs_dobyteswap : 1,
113 lfs_hasolddirfmt : 1;
114 };
115 /* Get lfs accessors that use struct salfs. */
116 #define STRUCT_LFS struct salfs
117 #include <ufs/lfs/lfs_accessors.h>
118
119 /* override this to avoid a mess with the dinode accessors */
120 #define lfs_dino_getsize(fs, dp) ((dp)->di_size)
121
122 typedef struct salfs FS;
123 #define fs_magic lfs_dlfs_u.u_32.dlfs_magic
124 #define fs_maxsymlinklen lfs_dlfs_u.u_32.dlfs_maxsymlinklen
125
126 #define FS_MAGIC LFS_MAGIC
127 #define SBLOCKSIZE LFS_SBPAD
128 #define SBLOCKOFFSET LFS_LABELPAD
129 #else
130 /* NB ufs2 doesn't use the common superblock code... */
131 typedef struct fs FS;
132 #define FS_MAGIC FS_UFS1_MAGIC
133 #define SBLOCKOFFSET SBLOCK_UFS1
134 #endif
135
136 #if defined(LIBSA_NO_TWIDDLE)
137 #define twiddle()
138 #endif
139
140 #undef cgstart
141 #if defined(LIBSA_FFSv2)
142 #define cgstart(fc, c) cgstart_ufs2((fs), (c))
143 #else
144 #define cgstart(fc, c) cgstart_ufs1((fs), (c))
145 #endif
146
147 #ifndef ufs_dinode
148 #define ufs_dinode ufs1_dinode
149 #endif
150 #ifndef indp_t
151 #define indp_t int32_t
152 #endif
153 typedef uint32_t ino32_t;
154
155 #ifndef FSBTODB
156 #define FSBTODB(fs, indp) FFS_FSBTODB(fs, indp)
157 #endif
158 #ifndef UFS_NINDIR
159 #define UFS_NINDIR FFS_NINDIR
160 #endif
161 #ifndef ufs_blkoff
162 #define ufs_blkoff ffs_blkoff
163 #endif
164 #ifndef ufs_lblkno
165 #define ufs_lblkno ffs_lblkno
166 #endif
167
168 /*
169 * To avoid having a lot of filesystem-block sized buffers lurking (which
170 * could be 32k) we only keep a few entries of the indirect block map.
171 * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
172 * ~13 times pulling in a 6M kernel.
173 * The cache size must be smaller than the smallest filesystem block,
174 * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
175 */
176 #define LN2_IND_CACHE_SZ 6
177 #define IND_CACHE_SZ (1 << LN2_IND_CACHE_SZ)
178 #define IND_CACHE_MASK (IND_CACHE_SZ - 1)
179
180 /*
181 * In-core open file.
182 */
183 struct file {
184 off_t f_seekp; /* seek pointer */
185 FS *f_fs; /* pointer to super-block */
186 struct ufs_dinode f_di; /* copy of on-disk inode */
187 uint f_nishift; /* for blocks in indirect block */
188 indp_t f_ind_cache_block;
189 indp_t f_ind_cache[IND_CACHE_SZ];
190
191 char *f_buf; /* buffer for data block */
192 size_t f_buf_size; /* size of data block */
193 daddr_t f_buf_blkno; /* block number of data block */
194 };
195
196 static int read_inode(ino32_t, struct open_file *);
197 static int block_map(struct open_file *, indp_t, indp_t *);
198 static int buf_read_file(struct open_file *, char **, size_t *);
199 static int search_directory(const char *, int, struct open_file *, ino32_t *);
200 #ifdef LIBSA_FFSv1
201 static void ffs_oldfscompat(FS *);
202 #endif
203 #ifdef LIBSA_FFSv2
204 static int ffs_find_superblock(struct open_file *, FS *);
205 #endif
206
207
208 #ifdef LIBSA_LFS
209 /*
210 * Find an inode's block. Look it up in the ifile. Whee!
211 */
212 static int
find_inode_sector(ino32_t inumber,struct open_file * f,daddr_t * isp)213 find_inode_sector(ino32_t inumber, struct open_file *f, daddr_t *isp)
214 {
215 struct file *fp = (struct file *)f->f_fsdata;
216 FS *fs = fp->f_fs;
217 daddr_t ifileent_blkno;
218 char *ent_in_buf;
219 size_t buf_after_ent;
220 size_t entsize;
221 int rc;
222
223 rc = read_inode(LFS_IFILE_INUM, f);
224 if (rc)
225 return rc;
226
227 entsize = fs->lfs_is64 ? sizeof(IFILE64) :
228 (lfs_sb_getversion(fs) > 1 ? sizeof(IFILE32) : sizeof(IFILE_V1));
229 ifileent_blkno =
230 (inumber / lfs_sb_getifpb(fs)) + lfs_sb_getcleansz(fs) + lfs_sb_getsegtabsz(fs);
231 fp->f_seekp = (off_t)ifileent_blkno * lfs_sb_getbsize(fs) +
232 (inumber % lfs_sb_getifpb(fs)) * entsize;
233 rc = buf_read_file(f, &ent_in_buf, &buf_after_ent);
234 if (rc)
235 return rc;
236 /* make sure something's not badly wrong, but don't panic. */
237 if (buf_after_ent < entsize)
238 return EINVAL;
239
240 *isp = FSBTODB(fs, lfs_if_getdaddr(fs, (IFILE *)ent_in_buf));
241 if (*isp == LFS_UNUSED_DADDR) /* again, something badly wrong */
242 return EINVAL;
243 return 0;
244 }
245 #endif
246
247 /*
248 * Read a new inode into a file structure.
249 */
250 static int
read_inode(ino32_t inumber,struct open_file * f)251 read_inode(ino32_t inumber, struct open_file *f)
252 {
253 struct file *fp = (struct file *)f->f_fsdata;
254 FS *fs = fp->f_fs;
255 char *buf;
256 size_t rsize;
257 int rc;
258 daddr_t inode_sector = 0; /* XXX: gcc */
259 #ifdef LIBSA_LFS
260 struct ufs_dinode *dip;
261 int cnt;
262 #endif
263
264 #ifdef LIBSA_LFS
265 if (inumber == LFS_IFILE_INUM)
266 inode_sector = FSBTODB(fs, lfs_sb_getidaddr(fs));
267 else if ((rc = find_inode_sector(inumber, f, &inode_sector)) != 0)
268 return rc;
269 #else
270 inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
271 #endif
272
273 /*
274 * Read inode and save it.
275 */
276 buf = fp->f_buf;
277 twiddle();
278 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
279 inode_sector, fs->fs_bsize, buf, &rsize);
280 if (rc)
281 return rc;
282 if (rsize != fs->fs_bsize)
283 return EIO;
284
285 #ifdef LIBSA_LFS
286 cnt = INOPBx(fs);
287 dip = (struct ufs_dinode *)buf + (cnt - 1);
288 for (; dip->di_inumber != inumber; --dip) {
289 /* kernel code panics, but boot blocks which panic are Bad. */
290 if (--cnt == 0)
291 return EINVAL;
292 }
293 fp->f_di = *dip;
294 #else
295 fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)];
296 #endif
297
298 /*
299 * Clear out the old buffers
300 */
301 fp->f_ind_cache_block = ~0;
302 fp->f_buf_blkno = -1;
303 return rc;
304 }
305
306 /*
307 * Given an offset in a file, find the disk block number that
308 * contains that block.
309 */
310 static int
block_map(struct open_file * f,indp_t file_block,indp_t * disk_block_p)311 block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p)
312 {
313 struct file *fp = (struct file *)f->f_fsdata;
314 FS *fs = fp->f_fs;
315 uint level;
316 indp_t ind_cache;
317 indp_t ind_block_num;
318 size_t rsize;
319 int rc;
320 indp_t *buf = (void *)fp->f_buf;
321
322 /*
323 * Index structure of an inode:
324 *
325 * di_db[0..UFS_NDADDR-1] hold block numbers for blocks
326 * 0..UFS_NDADDR-1
327 *
328 * di_ib[0] index block 0 is the single indirect block
329 * holds block numbers for blocks
330 * UFS_NDADDR .. UFS_NDADDR + UFS_NINDIR(fs)-1
331 *
332 * di_ib[1] index block 1 is the double indirect block
333 * holds block numbers for INDEX blocks for blocks
334 * UFS_NDADDR + UFS_NINDIR(fs) ..
335 * UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 - 1
336 *
337 * di_ib[2] index block 2 is the triple indirect block
338 * holds block numbers for double-indirect
339 * blocks for blocks
340 * UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 ..
341 * UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2
342 * + UFS_NINDIR(fs)**3 - 1
343 */
344
345 if (file_block < UFS_NDADDR) {
346 /* Direct block. */
347 *disk_block_p = fp->f_di.di_db[file_block];
348 return 0;
349 }
350
351 file_block -= UFS_NDADDR;
352
353 ind_cache = file_block >> LN2_IND_CACHE_SZ;
354 if (ind_cache == fp->f_ind_cache_block) {
355 *disk_block_p = fp->f_ind_cache[file_block & IND_CACHE_MASK];
356 return 0;
357 }
358
359 for (level = 0;;) {
360 level += fp->f_nishift;
361 if (file_block < (indp_t)1 << level)
362 break;
363 if (level > UFS_NIADDR * fp->f_nishift)
364 /* Block number too high */
365 return EFBIG;
366 file_block -= (indp_t)1 << level;
367 }
368
369 ind_block_num = fp->f_di.di_ib[level / fp->f_nishift - 1];
370
371 for (;;) {
372 level -= fp->f_nishift;
373 if (ind_block_num == 0) {
374 *disk_block_p = 0; /* missing */
375 return 0;
376 }
377
378 twiddle();
379 /*
380 * If we were feeling brave, we could work out the number
381 * of the disk sector and read a single disk sector instead
382 * of a filesystem block.
383 * However we don't do this very often anyway...
384 */
385 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
386 FSBTODB(fp->f_fs, ind_block_num), fs->fs_bsize,
387 buf, &rsize);
388 if (rc)
389 return rc;
390 if (rsize != fs->fs_bsize)
391 return EIO;
392 ind_block_num = buf[file_block >> level];
393 if (level == 0)
394 break;
395 file_block &= (1 << level) - 1;
396 }
397
398 /* Save the part of the block that contains this sector */
399 memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK],
400 IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
401 fp->f_ind_cache_block = ind_cache;
402
403 *disk_block_p = ind_block_num;
404
405 return 0;
406 }
407
408 /*
409 * Read a portion of a file into an internal buffer.
410 * Return the location in the buffer and the amount in the buffer.
411 */
412 static int
buf_read_file(struct open_file * f,char ** buf_p,size_t * size_p)413 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
414 {
415 struct file *fp = (struct file *)f->f_fsdata;
416 FS *fs = fp->f_fs;
417 long off;
418 indp_t file_block;
419 size_t block_size;
420 int rc;
421
422 off = ufs_blkoff(fs, fp->f_seekp);
423 file_block = ufs_lblkno(fs, fp->f_seekp);
424 #ifdef LIBSA_LFS
425 block_size = dblksize(fs, &fp->f_di, file_block);
426 #else
427 block_size = ffs_sblksize(fs, (int64_t)fp->f_di.di_size, file_block);
428 #endif
429
430 if (file_block != fp->f_buf_blkno) {
431 indp_t disk_block = 0; /* XXX: gcc */
432 rc = block_map(f, file_block, &disk_block);
433 if (rc)
434 return rc;
435
436 if (disk_block == 0) {
437 memset(fp->f_buf, 0, block_size);
438 fp->f_buf_size = block_size;
439 } else {
440 twiddle();
441 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
442 FSBTODB(fs, disk_block),
443 block_size, fp->f_buf, &fp->f_buf_size);
444 if (rc)
445 return rc;
446 }
447
448 fp->f_buf_blkno = file_block;
449 }
450
451 /*
452 * Return address of byte in buffer corresponding to
453 * offset, and size of remainder of buffer after that
454 * byte.
455 */
456 *buf_p = fp->f_buf + off;
457 *size_p = block_size - off;
458
459 /*
460 * But truncate buffer at end of file.
461 */
462 if (*size_p > fp->f_di.di_size - fp->f_seekp)
463 *size_p = fp->f_di.di_size - fp->f_seekp;
464
465 return 0;
466 }
467
468 /*
469 * Search a directory for a name and return its
470 * inode number.
471 */
472 static int
search_directory(const char * name,int length,struct open_file * f,ino32_t * inumber_p)473 search_directory(const char *name, int length, struct open_file *f,
474 ino32_t *inumber_p)
475 {
476 struct file *fp = (struct file *)f->f_fsdata;
477 struct direct *dp;
478 struct direct *edp;
479 char *buf;
480 size_t buf_size;
481 int namlen;
482 int rc;
483
484 fp->f_seekp = 0;
485 while (fp->f_seekp < (off_t)fp->f_di.di_size) {
486 rc = buf_read_file(f, &buf, &buf_size);
487 if (rc)
488 return rc;
489
490 dp = (struct direct *)buf;
491 edp = (struct direct *)(buf + buf_size);
492 for (;dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) {
493 if (dp->d_reclen <= 0)
494 break;
495 if (dp->d_ino == (ino32_t)0)
496 continue;
497 #if BYTE_ORDER == LITTLE_ENDIAN
498 if (fp->f_fs->fs_maxsymlinklen <= 0)
499 namlen = dp->d_type;
500 else
501 #endif
502 namlen = dp->d_namlen;
503 if (namlen == length &&
504 !memcmp(name, dp->d_name, length)) {
505 /* found entry */
506 *inumber_p = dp->d_ino;
507 return 0;
508 }
509 }
510 fp->f_seekp += buf_size;
511 }
512 return ENOENT;
513 }
514
515 #ifdef LIBSA_FFSv2
516
517 daddr_t sblock_try[] = SBLOCKSEARCH;
518
519 static int
ffs_find_superblock(struct open_file * f,FS * fs)520 ffs_find_superblock(struct open_file *f, FS *fs)
521 {
522 int i, rc;
523 size_t buf_size;
524
525 for (i = 0; sblock_try[i] != -1; i++) {
526 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
527 sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size);
528 if (rc != 0 || buf_size != SBLOCKSIZE)
529 return rc;
530 if (fs->fs_sblockloc != sblock_try[i])
531 /* an alternate superblock - try again */
532 continue;
533 if (fs->fs_magic == FS_UFS2_MAGIC) {
534 return 0;
535 }
536 }
537 return EINVAL;
538 }
539
540 #endif
541
542 /*
543 * Open a file.
544 */
545 __compactcall int
ufs_open(const char * path,struct open_file * f)546 ufs_open(const char *path, struct open_file *f)
547 {
548 #ifndef LIBSA_FS_SINGLECOMPONENT
549 const char *cp, *ncp;
550 int c;
551 #endif
552 ino32_t inumber;
553 struct file *fp;
554 FS *fs;
555 int rc;
556 #ifndef LIBSA_NO_FS_SYMLINK
557 ino32_t parent_inumber;
558 int nlinks = 0;
559 char namebuf[MAXPATHLEN+1];
560 char *buf;
561 #endif
562
563 /* allocate file system specific data structure */
564 fp = alloc(sizeof(struct file));
565 memset(fp, 0, sizeof(struct file));
566 f->f_fsdata = (void *)fp;
567
568 /* allocate space and read super block */
569 fs = alloc(SBLOCKSIZE);
570 fp->f_fs = fs;
571 twiddle();
572
573 #ifdef LIBSA_FFSv2
574 rc = ffs_find_superblock(f, fs);
575 if (rc)
576 goto out;
577 #else
578 {
579 size_t buf_size;
580 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
581 SBLOCKOFFSET / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size);
582 if (rc)
583 goto out;
584 if (buf_size != SBLOCKSIZE ||
585 #ifdef LIBSA_FFS
586 fs->lfs_version != REQUIRED_LFS_VERSION ||
587 #endif
588 fs->fs_magic != FS_MAGIC) {
589 rc = EINVAL;
590 goto out;
591 }
592 }
593 #if defined(LIBSA_LFS) && REQUIRED_LFS_VERSION == 2
594 /*
595 * XXX We should check the second superblock and use the eldest
596 * of the two. See comments near the top of lfs_mountfs()
597 * in sys/ufs/lfs/lfs_vfsops.c.
598 * This may need a LIBSA_LFS_SMALL check as well.
599 */
600 #endif
601 #if defined(LIBSA_LFS)
602 fs->lfs_is64 = 0;
603 fs->lfs_dobyteswap = 0;
604 fs->lfs_hasolddirfmt = (fs->fs_maxsymlinklen <= 0);
605 #endif
606 #endif
607
608 #ifdef LIBSA_FFSv1
609 ffs_oldfscompat(fs);
610 #endif
611
612 if (fs->fs_bsize > MAXBSIZE ||
613 (size_t)fs->fs_bsize < sizeof(FS)) {
614 rc = EINVAL;
615 goto out;
616 }
617
618 /*
619 * Calculate indirect block levels.
620 */
621 {
622 indp_t mult;
623 int ln2;
624
625 /*
626 * We note that the number of indirect blocks is always
627 * a power of 2. This lets us use shifts and masks instead
628 * of divide and remainder and avoinds pulling in the
629 * 64bit division routine into the boot code.
630 */
631 mult = UFS_NINDIR(fs);
632 #ifdef DEBUG
633 if (mult & (mult - 1)) {
634 /* Hummm was't a power of 2 */
635 rc = EINVAL;
636 goto out;
637 }
638 #endif
639 for (ln2 = 0; mult != 1; ln2++)
640 mult >>= 1;
641
642 fp->f_nishift = ln2;
643 }
644
645 /* alloc a block sized buffer used for all fs transfers */
646 fp->f_buf = alloc(fs->fs_bsize);
647 inumber = UFS_ROOTINO;
648 if ((rc = read_inode(inumber, f)) != 0)
649 goto out;
650
651 #ifndef LIBSA_FS_SINGLECOMPONENT
652 cp = path;
653 while (*cp) {
654
655 /*
656 * Remove extra separators
657 */
658 while (*cp == '/')
659 cp++;
660 if (*cp == '\0')
661 break;
662
663 /*
664 * Check that current node is a directory.
665 */
666 if ((fp->f_di.di_mode & IFMT) != IFDIR) {
667 rc = ENOTDIR;
668 goto out;
669 }
670
671 /*
672 * Get next component of path name.
673 */
674 ncp = cp;
675 while ((c = *cp) != '\0' && c != '/')
676 cp++;
677
678 /*
679 * Look up component in current directory.
680 * Save directory inumber in case we find a
681 * symbolic link.
682 */
683 #ifndef LIBSA_NO_FS_SYMLINK
684 parent_inumber = inumber;
685 #endif
686 rc = search_directory(ncp, cp - ncp, f, &inumber);
687 if (rc)
688 goto out;
689
690 /*
691 * Open next component.
692 */
693 if ((rc = read_inode(inumber, f)) != 0)
694 goto out;
695
696 #ifndef LIBSA_NO_FS_SYMLINK
697 /*
698 * Check for symbolic link.
699 */
700 if ((fp->f_di.di_mode & IFMT) == IFLNK) {
701 int link_len = fp->f_di.di_size;
702 int len;
703
704 len = strlen(cp);
705
706 if (link_len + len > MAXPATHLEN ||
707 ++nlinks > MAXSYMLINKS) {
708 rc = ENOENT;
709 goto out;
710 }
711
712 memmove(&namebuf[link_len], cp, len + 1);
713
714 if (link_len < fs->fs_maxsymlinklen) {
715 memcpy(namebuf, fp->f_di.di_db, link_len);
716 } else {
717 /*
718 * Read file for symbolic link
719 */
720 size_t buf_size;
721 indp_t disk_block;
722
723 buf = fp->f_buf;
724 rc = block_map(f, (indp_t)0, &disk_block);
725 if (rc)
726 goto out;
727
728 twiddle();
729 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
730 F_READ, FSBTODB(fs, disk_block),
731 fs->fs_bsize, buf, &buf_size);
732 if (rc)
733 goto out;
734
735 memcpy(namebuf, buf, link_len);
736 }
737
738 /*
739 * If relative pathname, restart at parent directory.
740 * If absolute pathname, restart at root.
741 */
742 cp = namebuf;
743 if (*cp != '/')
744 inumber = parent_inumber;
745 else
746 inumber = (ino32_t)UFS_ROOTINO;
747
748 if ((rc = read_inode(inumber, f)) != 0)
749 goto out;
750 }
751 #endif /* !LIBSA_NO_FS_SYMLINK */
752 }
753
754 /*
755 * Found terminal component.
756 */
757 rc = 0;
758
759 #else /* !LIBSA_FS_SINGLECOMPONENT */
760
761 /* look up component in the current (root) directory */
762 rc = search_directory(path, strlen(path), f, &inumber);
763 if (rc)
764 goto out;
765
766 /* open it */
767 rc = read_inode(inumber, f);
768
769 #endif /* !LIBSA_FS_SINGLECOMPONENT */
770
771 fp->f_seekp = 0; /* reset seek pointer */
772
773 out:
774 if (rc)
775 ufs_close(f);
776 #ifdef FSMOD /* Only defined for lfs */
777 else
778 fsmod = FSMOD;
779 #endif
780 return rc;
781 }
782
783 __compactcall int
ufs_close(struct open_file * f)784 ufs_close(struct open_file *f)
785 {
786 struct file *fp = (struct file *)f->f_fsdata;
787
788 f->f_fsdata = NULL;
789 if (fp == NULL)
790 return 0;
791
792 if (fp->f_buf)
793 dealloc(fp->f_buf, fp->f_fs->fs_bsize);
794 dealloc(fp->f_fs, SBLOCKSIZE);
795 dealloc(fp, sizeof(struct file));
796 return 0;
797 }
798
799 /*
800 * Copy a portion of a file into kernel memory.
801 * Cross block boundaries when necessary.
802 */
803 __compactcall int
ufs_read(struct open_file * f,void * start,size_t size,size_t * resid)804 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
805 {
806 struct file *fp = (struct file *)f->f_fsdata;
807 size_t csize;
808 char *buf;
809 size_t buf_size;
810 int rc = 0;
811 char *addr = start;
812
813 while (size != 0) {
814 if (fp->f_seekp >= (off_t)fp->f_di.di_size)
815 break;
816
817 rc = buf_read_file(f, &buf, &buf_size);
818 if (rc)
819 break;
820
821 csize = size;
822 if (csize > buf_size)
823 csize = buf_size;
824
825 memcpy(addr, buf, csize);
826
827 fp->f_seekp += csize;
828 addr += csize;
829 size -= csize;
830 }
831 if (resid)
832 *resid = size;
833 return rc;
834 }
835
836 /*
837 * Not implemented.
838 */
839 #ifndef LIBSA_NO_FS_WRITE
840 __compactcall int
ufs_write(struct open_file * f,void * start,size_t size,size_t * resid)841 ufs_write(struct open_file *f, void *start, size_t size, size_t *resid)
842 {
843
844 return EROFS;
845 }
846 #endif /* !LIBSA_NO_FS_WRITE */
847
848 #ifndef LIBSA_NO_FS_SEEK
849 __compactcall off_t
ufs_seek(struct open_file * f,off_t offset,int where)850 ufs_seek(struct open_file *f, off_t offset, int where)
851 {
852 struct file *fp = (struct file *)f->f_fsdata;
853
854 switch (where) {
855 case SEEK_SET:
856 fp->f_seekp = offset;
857 break;
858 case SEEK_CUR:
859 fp->f_seekp += offset;
860 break;
861 case SEEK_END:
862 fp->f_seekp = fp->f_di.di_size - offset;
863 break;
864 default:
865 return -1;
866 }
867 return fp->f_seekp;
868 }
869 #endif /* !LIBSA_NO_FS_SEEK */
870
871 __compactcall int
ufs_stat(struct open_file * f,struct stat * sb)872 ufs_stat(struct open_file *f, struct stat *sb)
873 {
874 struct file *fp = (struct file *)f->f_fsdata;
875
876 /* only important stuff */
877 memset(sb, 0, sizeof *sb);
878 sb->st_mode = fp->f_di.di_mode;
879 sb->st_uid = fp->f_di.di_uid;
880 sb->st_gid = fp->f_di.di_gid;
881 sb->st_size = fp->f_di.di_size;
882 return 0;
883 }
884
885 #if defined(LIBSA_ENABLE_LS_OP)
886
887 #include "ls.h"
888
889 static const char *const typestr[] = {
890 "unknown",
891 "FIFO",
892 "CHR",
893 0,
894 "DIR",
895 0,
896 "BLK",
897 0,
898 "REG",
899 0,
900 "LNK",
901 0,
902 "SOCK",
903 0,
904 "WHT"
905 };
906
907 __compactcall void
ufs_ls(struct open_file * f,const char * pattern)908 ufs_ls(struct open_file *f, const char *pattern)
909 {
910 struct file *fp = (struct file *)f->f_fsdata;
911 char *buf;
912 size_t buf_size;
913 lsentry_t *names = NULL;
914
915 fp->f_seekp = 0;
916 while (fp->f_seekp < (off_t)fp->f_di.di_size) {
917 struct direct *dp, *edp;
918 int rc = buf_read_file(f, &buf, &buf_size);
919 if (rc)
920 goto out;
921 /* some firmware might use block size larger than DEV_BSIZE */
922 if (buf_size < UFS_DIRBLKSIZ)
923 goto out;
924
925 dp = (struct direct *)buf;
926 edp = (struct direct *)(buf + buf_size);
927
928 for (; dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) {
929 const char *t;
930 if (dp->d_ino == 0)
931 continue;
932
933 if (dp->d_type >= NELEM(typestr) ||
934 !(t = typestr[dp->d_type])) {
935 /*
936 * This does not handle "old"
937 * filesystems properly. On little
938 * endian machines, we get a bogus
939 * type name if the namlen matches a
940 * valid type identifier. We could
941 * check if we read namlen "0" and
942 * handle this case specially, if
943 * there were a pressing need...
944 */
945 printf("bad dir entry\n");
946 goto out;
947 }
948 lsadd(&names, pattern, dp->d_name, strlen(dp->d_name),
949 dp->d_ino, t);
950 }
951 fp->f_seekp += buf_size;
952 }
953 lsprint(names);
954 out: lsfree(names);
955 }
956 #endif /* LIBSA_ENABLE_LS_OP */
957
958 #ifdef LIBSA_FFSv1
959 /*
960 * Sanity checks for old file systems.
961 *
962 * XXX - goes away some day.
963 * Stripped of stuff libsa doesn't need.....
964 */
965 static void
ffs_oldfscompat(FS * fs)966 ffs_oldfscompat(FS *fs)
967 {
968
969 #ifdef COMPAT_UFS
970 /*
971 * Newer Solaris versions have a slightly incompatible
972 * superblock - so always calculate this values on the fly, which
973 * is good enough for libsa purposes
974 */
975 if (fs->fs_magic == FS_UFS1_MAGIC
976 #ifndef COMPAT_SOLARIS_UFS
977 && fs->fs_old_inodefmt < FS_44INODEFMT
978 #endif
979 ) {
980 fs->fs_qbmask = ~fs->fs_bmask;
981 fs->fs_qfmask = ~fs->fs_fmask;
982 }
983 #endif
984 }
985 #endif
986