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