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