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