ufs.c revision 1.66 1 /* $NetBSD: ufs.c,v 1.66 2015/07/24 06:53:24 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 typedef struct dlfs FS;
107 #define fs_magic dlfs_magic
108 #define fs_maxsymlinklen dlfs_maxsymlinklen
109
110 /* XXX these will go away in the near future */
111 #undef lfs_bmask
112 #define lfs_bmask dlfs_bmask
113 #undef lfs_ifile
114 #define lfs_ifile dlfs_ifile
115 #undef lfs_ifpb
116 #define lfs_ifpb dlfs_ifpb
117 #undef lfs_cleansz
118 #define lfs_cleansz dlfs_cleansz
119 #undef lfs_segtabsz
120 #define lfs_segtabsz dlfs_segtabsz
121 #undef lfs_idaddr
122 #define lfs_idaddr dlfs_idaddr
123 #undef lfs_inopb
124 #define lfs_inopb dlfs_inopb
125 #undef lfs_bshift
126 #define lfs_bshift dlfs_bshift
127 #undef lfs_bsize
128 #define lfs_bsize dlfs_bsize
129 #undef lfs_ffmask
130 #define lfs_ffmask dlfs_ffmask
131 #undef lfs_fsbtodb
132 #define lfs_fsbtodb dlfs_fsbtodb
133
134 #define FS_MAGIC LFS_MAGIC
135 #define SBLOCKSIZE LFS_SBPAD
136 #define SBLOCKOFFSET LFS_LABELPAD
137 #else
138 /* NB ufs2 doesn't use the common superblock code... */
139 typedef struct fs FS;
140 #define FS_MAGIC FS_UFS1_MAGIC
141 #define SBLOCKOFFSET SBLOCK_UFS1
142 #endif
143
144 #if defined(LIBSA_NO_TWIDDLE)
145 #define twiddle()
146 #endif
147
148 #undef cgstart
149 #if defined(LIBSA_FFSv2)
150 #define cgstart(fc, c) cgstart_ufs2((fs), (c))
151 #else
152 #define cgstart(fc, c) cgstart_ufs1((fs), (c))
153 #endif
154
155 #ifndef ufs_dinode
156 #define ufs_dinode ufs1_dinode
157 #endif
158 #ifndef indp_t
159 #define indp_t int32_t
160 #endif
161 typedef uint32_t ino32_t;
162
163 #ifndef FSBTODB
164 #define FSBTODB(fs, indp) FFS_FSBTODB(fs, indp)
165 #endif
166 #ifndef UFS_NINDIR
167 #define UFS_NINDIR FFS_NINDIR
168 #endif
169 #ifndef ufs_blkoff
170 #define ufs_blkoff ffs_blkoff
171 #endif
172 #ifndef ufs_lblkno
173 #define ufs_lblkno ffs_lblkno
174 #endif
175
176 /*
177 * To avoid having a lot of filesystem-block sized buffers lurking (which
178 * could be 32k) we only keep a few entries of the indirect block map.
179 * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
180 * ~13 times pulling in a 6M kernel.
181 * The cache size must be smaller than the smallest filesystem block,
182 * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
183 */
184 #define LN2_IND_CACHE_SZ 6
185 #define IND_CACHE_SZ (1 << LN2_IND_CACHE_SZ)
186 #define IND_CACHE_MASK (IND_CACHE_SZ - 1)
187
188 /*
189 * In-core open file.
190 */
191 struct file {
192 off_t f_seekp; /* seek pointer */
193 FS *f_fs; /* pointer to super-block */
194 struct ufs_dinode f_di; /* copy of on-disk inode */
195 uint f_nishift; /* for blocks in indirect block */
196 indp_t f_ind_cache_block;
197 indp_t f_ind_cache[IND_CACHE_SZ];
198
199 char *f_buf; /* buffer for data block */
200 size_t f_buf_size; /* size of data block */
201 daddr_t f_buf_blkno; /* block number of data block */
202 };
203
204 static int read_inode(ino32_t, struct open_file *);
205 static int block_map(struct open_file *, indp_t, indp_t *);
206 static int buf_read_file(struct open_file *, char **, size_t *);
207 static int search_directory(const char *, int, struct open_file *, ino32_t *);
208 #ifdef LIBSA_FFSv1
209 static void ffs_oldfscompat(FS *);
210 #endif
211 #ifdef LIBSA_FFSv2
212 static int ffs_find_superblock(struct open_file *, FS *);
213 #endif
214
215
216 #ifdef LIBSA_LFS
217 /*
218 * Find an inode's block. Look it up in the ifile. Whee!
219 */
220 static int
221 find_inode_sector(ino32_t inumber, struct open_file *f, daddr_t *isp)
222 {
223 struct file *fp = (struct file *)f->f_fsdata;
224 FS *fs = fp->f_fs;
225 daddr_t ifileent_blkno;
226 char *ent_in_buf;
227 size_t buf_after_ent;
228 int rc;
229
230 rc = read_inode(fs->lfs_ifile, f);
231 if (rc)
232 return rc;
233
234 ifileent_blkno =
235 (inumber / fs->lfs_ifpb) + fs->lfs_cleansz + fs->lfs_segtabsz;
236 fp->f_seekp = (off_t)ifileent_blkno * fs->fs_bsize +
237 (inumber % fs->lfs_ifpb) * sizeof (IFILE_Vx);
238 rc = buf_read_file(f, &ent_in_buf, &buf_after_ent);
239 if (rc)
240 return rc;
241 /* make sure something's not badly wrong, but don't panic. */
242 if (buf_after_ent < sizeof (IFILE_Vx))
243 return EINVAL;
244
245 *isp = FSBTODB(fs, ((IFILE_Vx *)ent_in_buf)->if_daddr);
246 if (*isp == LFS_UNUSED_DADDR) /* again, something badly wrong */
247 return EINVAL;
248 return 0;
249 }
250 #endif
251
252 /*
253 * Read a new inode into a file structure.
254 */
255 static int
256 read_inode(ino32_t inumber, struct open_file *f)
257 {
258 struct file *fp = (struct file *)f->f_fsdata;
259 FS *fs = fp->f_fs;
260 char *buf;
261 size_t rsize;
262 int rc;
263 daddr_t inode_sector = 0; /* XXX: gcc */
264 #ifdef LIBSA_LFS
265 struct ufs_dinode *dip;
266 int cnt;
267 #endif
268
269 #ifdef LIBSA_LFS
270 if (inumber == fs->lfs_ifile)
271 inode_sector = FSBTODB(fs, fs->lfs_idaddr);
272 else if ((rc = find_inode_sector(inumber, f, &inode_sector)) != 0)
273 return rc;
274 #else
275 inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
276 #endif
277
278 /*
279 * Read inode and save it.
280 */
281 buf = fp->f_buf;
282 twiddle();
283 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
284 inode_sector, fs->fs_bsize, buf, &rsize);
285 if (rc)
286 return rc;
287 if (rsize != fs->fs_bsize)
288 return EIO;
289
290 #ifdef LIBSA_LFS
291 cnt = INOPBx(fs);
292 dip = (struct ufs_dinode *)buf + (cnt - 1);
293 for (; dip->di_inumber != inumber; --dip) {
294 /* kernel code panics, but boot blocks which panic are Bad. */
295 if (--cnt == 0)
296 return EINVAL;
297 }
298 fp->f_di = *dip;
299 #else
300 fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)];
301 #endif
302
303 /*
304 * Clear out the old buffers
305 */
306 fp->f_ind_cache_block = ~0;
307 fp->f_buf_blkno = -1;
308 return rc;
309 }
310
311 /*
312 * Given an offset in a file, find the disk block number that
313 * contains that block.
314 */
315 static int
316 block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p)
317 {
318 struct file *fp = (struct file *)f->f_fsdata;
319 FS *fs = fp->f_fs;
320 uint level;
321 indp_t ind_cache;
322 indp_t ind_block_num;
323 size_t rsize;
324 int rc;
325 indp_t *buf = (void *)fp->f_buf;
326
327 /*
328 * Index structure of an inode:
329 *
330 * di_db[0..UFS_NDADDR-1] hold block numbers for blocks
331 * 0..UFS_NDADDR-1
332 *
333 * di_ib[0] index block 0 is the single indirect block
334 * holds block numbers for blocks
335 * UFS_NDADDR .. UFS_NDADDR + UFS_NINDIR(fs)-1
336 *
337 * di_ib[1] index block 1 is the double indirect block
338 * holds block numbers for INDEX blocks for blocks
339 * UFS_NDADDR + UFS_NINDIR(fs) ..
340 * UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 - 1
341 *
342 * di_ib[2] index block 2 is the triple indirect block
343 * holds block numbers for double-indirect
344 * blocks for blocks
345 * UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 ..
346 * UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2
347 * + UFS_NINDIR(fs)**3 - 1
348 */
349
350 if (file_block < UFS_NDADDR) {
351 /* Direct block. */
352 *disk_block_p = fp->f_di.di_db[file_block];
353 return 0;
354 }
355
356 file_block -= UFS_NDADDR;
357
358 ind_cache = file_block >> LN2_IND_CACHE_SZ;
359 if (ind_cache == fp->f_ind_cache_block) {
360 *disk_block_p = fp->f_ind_cache[file_block & IND_CACHE_MASK];
361 return 0;
362 }
363
364 for (level = 0;;) {
365 level += fp->f_nishift;
366 if (file_block < (indp_t)1 << level)
367 break;
368 if (level > UFS_NIADDR * fp->f_nishift)
369 /* Block number too high */
370 return EFBIG;
371 file_block -= (indp_t)1 << level;
372 }
373
374 ind_block_num = fp->f_di.di_ib[level / fp->f_nishift - 1];
375
376 for (;;) {
377 level -= fp->f_nishift;
378 if (ind_block_num == 0) {
379 *disk_block_p = 0; /* missing */
380 return 0;
381 }
382
383 twiddle();
384 /*
385 * If we were feeling brave, we could work out the number
386 * of the disk sector and read a single disk sector instead
387 * of a filesystem block.
388 * However we don't do this very often anyway...
389 */
390 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
391 FSBTODB(fp->f_fs, ind_block_num), fs->fs_bsize,
392 buf, &rsize);
393 if (rc)
394 return rc;
395 if (rsize != fs->fs_bsize)
396 return EIO;
397 ind_block_num = buf[file_block >> level];
398 if (level == 0)
399 break;
400 file_block &= (1 << level) - 1;
401 }
402
403 /* Save the part of the block that contains this sector */
404 memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK],
405 IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
406 fp->f_ind_cache_block = ind_cache;
407
408 *disk_block_p = ind_block_num;
409
410 return 0;
411 }
412
413 /*
414 * Read a portion of a file into an internal buffer.
415 * Return the location in the buffer and the amount in the buffer.
416 */
417 static int
418 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
419 {
420 struct file *fp = (struct file *)f->f_fsdata;
421 FS *fs = fp->f_fs;
422 long off;
423 indp_t file_block;
424 size_t block_size;
425 int rc;
426
427 off = ufs_blkoff(fs, fp->f_seekp);
428 file_block = ufs_lblkno(fs, fp->f_seekp);
429 #ifdef LIBSA_LFS
430 block_size = dblksize(fs, &fp->f_di, file_block);
431 #else
432 block_size = ffs_sblksize(fs, (int64_t)fp->f_di.di_size, file_block);
433 #endif
434
435 if (file_block != fp->f_buf_blkno) {
436 indp_t disk_block = 0; /* XXX: gcc */
437 rc = block_map(f, file_block, &disk_block);
438 if (rc)
439 return rc;
440
441 if (disk_block == 0) {
442 memset(fp->f_buf, 0, block_size);
443 fp->f_buf_size = block_size;
444 } else {
445 twiddle();
446 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
447 FSBTODB(fs, disk_block),
448 block_size, fp->f_buf, &fp->f_buf_size);
449 if (rc)
450 return rc;
451 }
452
453 fp->f_buf_blkno = file_block;
454 }
455
456 /*
457 * Return address of byte in buffer corresponding to
458 * offset, and size of remainder of buffer after that
459 * byte.
460 */
461 *buf_p = fp->f_buf + off;
462 *size_p = block_size - off;
463
464 /*
465 * But truncate buffer at end of file.
466 */
467 if (*size_p > fp->f_di.di_size - fp->f_seekp)
468 *size_p = fp->f_di.di_size - fp->f_seekp;
469
470 return 0;
471 }
472
473 /*
474 * Search a directory for a name and return its
475 * inode number.
476 */
477 static int
478 search_directory(const char *name, int length, struct open_file *f,
479 ino32_t *inumber_p)
480 {
481 struct file *fp = (struct file *)f->f_fsdata;
482 struct direct *dp;
483 struct direct *edp;
484 char *buf;
485 size_t buf_size;
486 int namlen;
487 int rc;
488
489 fp->f_seekp = 0;
490 while (fp->f_seekp < (off_t)fp->f_di.di_size) {
491 rc = buf_read_file(f, &buf, &buf_size);
492 if (rc)
493 return rc;
494
495 dp = (struct direct *)buf;
496 edp = (struct direct *)(buf + buf_size);
497 for (;dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) {
498 if (dp->d_reclen <= 0)
499 break;
500 if (dp->d_ino == (ino32_t)0)
501 continue;
502 #if BYTE_ORDER == LITTLE_ENDIAN
503 if (fp->f_fs->fs_maxsymlinklen <= 0)
504 namlen = dp->d_type;
505 else
506 #endif
507 namlen = dp->d_namlen;
508 if (namlen == length &&
509 !memcmp(name, dp->d_name, length)) {
510 /* found entry */
511 *inumber_p = dp->d_ino;
512 return 0;
513 }
514 }
515 fp->f_seekp += buf_size;
516 }
517 return ENOENT;
518 }
519
520 #ifdef LIBSA_FFSv2
521
522 daddr_t sblock_try[] = SBLOCKSEARCH;
523
524 static int
525 ffs_find_superblock(struct open_file *f, FS *fs)
526 {
527 int i, rc;
528 size_t buf_size;
529
530 for (i = 0; sblock_try[i] != -1; i++) {
531 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
532 sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size);
533 if (rc != 0 || buf_size != SBLOCKSIZE)
534 return rc;
535 if (fs->fs_sblockloc != sblock_try[i])
536 /* an alternate superblock - try again */
537 continue;
538 if (fs->fs_magic == FS_UFS2_MAGIC) {
539 return 0;
540 }
541 }
542 return EINVAL;
543 }
544
545 #endif
546
547 /*
548 * Open a file.
549 */
550 __compactcall int
551 ufs_open(const char *path, struct open_file *f)
552 {
553 #ifndef LIBSA_FS_SINGLECOMPONENT
554 const char *cp, *ncp;
555 int c;
556 #endif
557 ino32_t inumber;
558 struct file *fp;
559 FS *fs;
560 int rc;
561 #ifndef LIBSA_NO_FS_SYMLINK
562 ino32_t parent_inumber;
563 int nlinks = 0;
564 char namebuf[MAXPATHLEN+1];
565 char *buf;
566 #endif
567
568 /* allocate file system specific data structure */
569 fp = alloc(sizeof(struct file));
570 memset(fp, 0, sizeof(struct file));
571 f->f_fsdata = (void *)fp;
572
573 /* allocate space and read super block */
574 fs = alloc(SBLOCKSIZE);
575 fp->f_fs = fs;
576 twiddle();
577
578 #ifdef LIBSA_FFSv2
579 rc = ffs_find_superblock(f, fs);
580 if (rc)
581 goto out;
582 #else
583 {
584 size_t buf_size;
585 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
586 SBLOCKOFFSET / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size);
587 if (rc)
588 goto out;
589 if (buf_size != SBLOCKSIZE ||
590 #ifdef LIBSA_FFS
591 fs->lfs_version != REQUIRED_LFS_VERSION ||
592 #endif
593 fs->fs_magic != FS_MAGIC) {
594 rc = EINVAL;
595 goto out;
596 }
597 }
598 #if defined(LIBSA_LFS) && REQUIRED_LFS_VERSION == 2
599 /*
600 * XXX We should check the second superblock and use the eldest
601 * of the two. See comments near the top of lfs_mountfs()
602 * in sys/ufs/lfs/lfs_vfsops.c.
603 * This may need a LIBSA_LFS_SMALL check as well.
604 */
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
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
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
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
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
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
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
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