1 /* $NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $ */
2
3 /*-
4 * Copyright (c) 2002 Networks Associates Technology, Inc.
5 * All rights reserved.
6 *
7 * This software was developed for the FreeBSD Project by Marshall
8 * Kirk McKusick and Network Associates Laboratories, the Security
9 * Research Division of Network Associates, Inc. under DARPA/SPAWAR
10 * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
11 * research program
12 *
13 * Copyright (c) 1982, 1989, 1993
14 * The Regents of the University of California. All rights reserved.
15 *
16 * This code is derived from software contributed to Berkeley by
17 * The Mach Operating System project at Carnegie-Mellon University.
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 * 3. Neither the name of the University nor the names of its contributors
28 * may be used to endorse or promote products derived from this software
29 * without specific prior written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
35 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 * SUCH DAMAGE.
42 *
43 *
44 * Copyright (c) 1990, 1991 Carnegie Mellon University
45 * All Rights Reserved.
46 *
47 * Author: David Golub
48 *
49 * Permission to use, copy, modify and distribute this software and its
50 * documentation is hereby granted, provided that both the copyright
51 * notice and this permission notice appear in all copies of the
52 * software, derivative works or modified versions, and any portions
53 * thereof, and that both notices appear in supporting documentation.
54 *
55 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
56 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
57 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
58 *
59 * Carnegie Mellon requests users of this software to return to
60 *
61 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
62 * School of Computer Science
63 * Carnegie Mellon University
64 * Pittsburgh PA 15213-3890
65 *
66 * any improvements or extensions that they make and grant Carnegie the
67 * rights to redistribute these changes.
68 */
69
70 /*
71 * Stand-alone file reading package.
72 */
73
74 #include <sys/param.h>
75 #include <sys/disklabel.h>
76 #include <sys/time.h>
77 #include <ufs/ufs/dinode.h>
78 #include <ufs/ufs/dir.h>
79 #include <ufs/ffs/fs.h>
80 #include "stand.h"
81 #include "string.h"
82
83 static int ufs_open(const char *path, struct open_file *f);
84 static int ufs_write(struct open_file *f, const void *buf, size_t size,
85 size_t *resid);
86 static int ufs_close(struct open_file *f);
87 static int ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
88 static off_t ufs_seek(struct open_file *f, off_t offset, int where);
89 static int ufs_stat(struct open_file *f, struct stat *sb);
90 static int ufs_readdir(struct open_file *f, struct dirent *d);
91 static int ufs_mount(const char *dev, const char *path, void **data);
92 static int ufs_unmount(const char *dev, void *data);
93
94 struct fs_ops ufs_fsops = {
95 .fs_name = "ufs",
96 .fs_flags = 0,
97 .fo_open = ufs_open,
98 .fo_close = ufs_close,
99 .fo_read = ufs_read,
100 .fo_write = ufs_write,
101 .fo_seek = ufs_seek,
102 .fo_stat = ufs_stat,
103 .fo_readdir = ufs_readdir,
104 .fo_mount = ufs_mount,
105 .fo_unmount = ufs_unmount
106 };
107
108 /*
109 * In-core open file.
110 */
111 struct file {
112 off_t f_seekp; /* seek pointer */
113 struct fs *f_fs; /* pointer to super-block */
114 union dinode f_dp; /* copy of on-disk inode */
115 int f_nindir[UFS_NIADDR];
116 /* number of blocks mapped by
117 indirect block at level i */
118 char *f_blk[UFS_NIADDR]; /* buffer for indirect block at
119 level i */
120 size_t f_blksize[UFS_NIADDR];
121 /* size of buffer */
122 ufs2_daddr_t f_blkno[UFS_NIADDR];/* disk address of block in buffer */
123 ufs2_daddr_t f_buf_blkno; /* block number of data block */
124 char *f_buf; /* buffer for data block */
125 size_t f_buf_size; /* size of data block */
126 int f_inumber; /* inumber */
127 };
128 #define DIP(fp, field) \
129 ((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \
130 (fp)->f_dp.dp1.field : (fp)->f_dp.dp2.field)
131
132 typedef struct ufs_mnt {
133 char *um_dev;
134 int um_fd;
135 STAILQ_ENTRY(ufs_mnt) um_link;
136 } ufs_mnt_t;
137
138 typedef STAILQ_HEAD(ufs_mnt_list, ufs_mnt) ufs_mnt_list_t;
139 static ufs_mnt_list_t mnt_list = STAILQ_HEAD_INITIALIZER(mnt_list);
140
141 static int read_inode(ino_t, struct open_file *);
142 static int block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *);
143 static int buf_read_file(struct open_file *, char **, size_t *);
144 static int buf_write_file(struct open_file *, const char *, size_t *);
145 static int search_directory(char *, struct open_file *, ino_t *);
146 static int ufs_use_sa_read(void *, off_t, void **, int);
147
148 /* from ffs_subr.c */
149 int ffs_sbget(void *devfd, struct fs **fsp, off_t sblock, int flags,
150 char *filltype,
151 int (*readfunc)(void *devfd, off_t loc, void **bufp, int size));
152 int ffs_sbsearch(void *, struct fs **, int, char *,
153 int (*)(void *, off_t, void **, int));
154
155 /*
156 * Read a new inode into a file structure.
157 */
158 static int
read_inode(ino_t inumber,struct open_file * f)159 read_inode(ino_t inumber, struct open_file *f)
160 {
161 struct file *fp = (struct file *)f->f_fsdata;
162 struct fs *fs = fp->f_fs;
163 char *buf;
164 size_t rsize;
165 int rc;
166
167 if (fs == NULL)
168 panic("fs == NULL");
169
170 /*
171 * Read inode and save it.
172 */
173 buf = malloc(fs->fs_bsize);
174 twiddle(1);
175 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
176 fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
177 buf, &rsize);
178 if (rc)
179 goto out;
180 if (rsize != fs->fs_bsize) {
181 rc = EIO;
182 goto out;
183 }
184
185 if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
186 fp->f_dp.dp1 = ((struct ufs1_dinode *)buf)
187 [ino_to_fsbo(fs, inumber)];
188 else
189 fp->f_dp.dp2 = ((struct ufs2_dinode *)buf)
190 [ino_to_fsbo(fs, inumber)];
191
192 /*
193 * Clear out the old buffers
194 */
195 {
196 int level;
197
198 for (level = 0; level < UFS_NIADDR; level++)
199 fp->f_blkno[level] = -1;
200 fp->f_buf_blkno = -1;
201 }
202 fp->f_seekp = 0;
203 fp->f_inumber = inumber;
204 out:
205 free(buf);
206 return (rc);
207 }
208
209 /*
210 * Given an offset in a file, find the disk block number that
211 * contains that block.
212 */
213 static int
block_map(struct open_file * f,ufs2_daddr_t file_block,ufs2_daddr_t * disk_block_p)214 block_map(struct open_file *f, ufs2_daddr_t file_block,
215 ufs2_daddr_t *disk_block_p)
216 {
217 struct file *fp = (struct file *)f->f_fsdata;
218 struct fs *fs = fp->f_fs;
219 int level;
220 int idx;
221 ufs2_daddr_t ind_block_num;
222 int rc;
223
224 /*
225 * Index structure of an inode:
226 *
227 * di_db[0..UFS_NDADDR-1] hold block numbers for blocks
228 * 0..UFS_NDADDR-1
229 *
230 * di_ib[0] index block 0 is the single indirect block
231 * holds block numbers for blocks
232 * UFS_NDADDR .. UFS_NDADDR + NINDIR(fs)-1
233 *
234 * di_ib[1] index block 1 is the double indirect block
235 * holds block numbers for INDEX blocks for blocks
236 * UFS_NDADDR + NINDIR(fs) ..
237 * UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
238 *
239 * di_ib[2] index block 2 is the triple indirect block
240 * holds block numbers for double-indirect
241 * blocks for blocks
242 * UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
243 * UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2
244 * + NINDIR(fs)**3 - 1
245 */
246
247 if (file_block < UFS_NDADDR) {
248 /* Direct block. */
249 *disk_block_p = DIP(fp, di_db[file_block]);
250 return (0);
251 }
252
253 file_block -= UFS_NDADDR;
254
255 /*
256 * nindir[0] = NINDIR
257 * nindir[1] = NINDIR**2
258 * nindir[2] = NINDIR**3
259 * etc
260 */
261 for (level = 0; level < UFS_NIADDR; level++) {
262 if (file_block < fp->f_nindir[level])
263 break;
264 file_block -= fp->f_nindir[level];
265 }
266 if (level == UFS_NIADDR) {
267 /* Block number too high */
268 return (EFBIG);
269 }
270
271 ind_block_num = DIP(fp, di_ib[level]);
272
273 for (; level >= 0; level--) {
274 if (ind_block_num == 0) {
275 *disk_block_p = 0; /* missing */
276 return (0);
277 }
278
279 if (fp->f_blkno[level] != ind_block_num) {
280 if (fp->f_blk[level] == (char *)0)
281 fp->f_blk[level] =
282 malloc(fs->fs_bsize);
283 twiddle(1);
284 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
285 fsbtodb(fp->f_fs, ind_block_num),
286 fs->fs_bsize,
287 fp->f_blk[level],
288 &fp->f_blksize[level]);
289 if (rc)
290 return (rc);
291 if (fp->f_blksize[level] != fs->fs_bsize)
292 return (EIO);
293 fp->f_blkno[level] = ind_block_num;
294 }
295
296 if (level > 0) {
297 idx = file_block / fp->f_nindir[level - 1];
298 file_block %= fp->f_nindir[level - 1];
299 } else
300 idx = file_block;
301
302 if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
303 ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx];
304 else
305 ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx];
306 }
307
308 *disk_block_p = ind_block_num;
309
310 return (0);
311 }
312
313 /*
314 * Write a portion of a file from an internal buffer.
315 */
316 static int
buf_write_file(struct open_file * f,const char * buf_p,size_t * size_p)317 buf_write_file(struct open_file *f, const char *buf_p, size_t *size_p)
318 {
319 struct file *fp = (struct file *)f->f_fsdata;
320 struct fs *fs = fp->f_fs;
321 long off;
322 ufs_lbn_t file_block;
323 ufs2_daddr_t disk_block;
324 size_t block_size;
325 int rc;
326
327 /*
328 * Calculate the starting block address and offset.
329 */
330 off = blkoff(fs, fp->f_seekp);
331 file_block = lblkno(fs, fp->f_seekp);
332 block_size = sblksize(fs, DIP(fp, di_size), file_block);
333
334 rc = block_map(f, file_block, &disk_block);
335 if (rc)
336 return (rc);
337
338 if (disk_block == 0)
339 /* Because we can't allocate space on the drive */
340 return (EFBIG);
341
342 /*
343 * Truncate buffer at end of file, and at the end of
344 * this block.
345 */
346 if (*size_p > DIP(fp, di_size) - fp->f_seekp)
347 *size_p = DIP(fp, di_size) - fp->f_seekp;
348 if (*size_p > block_size - off)
349 *size_p = block_size - off;
350
351 /*
352 * If we don't entirely occlude the block and it's not
353 * in memory already, read it in first.
354 */
355 if (((off > 0) || (*size_p + off < block_size)) &&
356 (file_block != fp->f_buf_blkno)) {
357
358 if (fp->f_buf == (char *)0)
359 fp->f_buf = malloc(fs->fs_bsize);
360
361 twiddle(4);
362 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
363 fsbtodb(fs, disk_block),
364 block_size, fp->f_buf, &fp->f_buf_size);
365 if (rc)
366 return (rc);
367
368 fp->f_buf_blkno = file_block;
369 }
370
371 /*
372 * Copy the user data into the cached block.
373 */
374 bcopy(buf_p, fp->f_buf + off, *size_p);
375
376 /*
377 * Write the block out to storage.
378 */
379
380 twiddle(4);
381 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE,
382 fsbtodb(fs, disk_block),
383 block_size, fp->f_buf, &fp->f_buf_size);
384 return (rc);
385 }
386
387 /*
388 * Read a portion of a file into an internal buffer. Return
389 * the location in the buffer and the amount in the buffer.
390 */
391 static int
buf_read_file(struct open_file * f,char ** buf_p,size_t * size_p)392 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
393 {
394 struct file *fp = (struct file *)f->f_fsdata;
395 struct fs *fs = fp->f_fs;
396 long off;
397 ufs_lbn_t file_block;
398 ufs2_daddr_t disk_block;
399 size_t block_size;
400 int rc;
401
402 off = blkoff(fs, fp->f_seekp);
403 file_block = lblkno(fs, fp->f_seekp);
404 block_size = sblksize(fs, DIP(fp, di_size), file_block);
405
406 if (file_block != fp->f_buf_blkno) {
407 if (fp->f_buf == NULL)
408 fp->f_buf = malloc(fs->fs_bsize);
409
410 rc = block_map(f, file_block, &disk_block);
411 if (rc)
412 return (rc);
413
414 if (disk_block == 0) {
415 bzero(fp->f_buf, block_size);
416 fp->f_buf_size = block_size;
417 } else {
418 twiddle(4);
419 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
420 fsbtodb(fs, disk_block),
421 block_size, fp->f_buf, &fp->f_buf_size);
422 if (rc)
423 return (rc);
424 }
425
426 fp->f_buf_blkno = file_block;
427 }
428
429 /*
430 * Return address of byte in buffer corresponding to
431 * offset, and size of remainder of buffer after that
432 * byte.
433 */
434 *buf_p = fp->f_buf + off;
435 *size_p = block_size - off;
436
437 /*
438 * But truncate buffer at end of file.
439 */
440 if (*size_p > DIP(fp, di_size) - fp->f_seekp)
441 *size_p = DIP(fp, di_size) - fp->f_seekp;
442
443 return (0);
444 }
445
446 /*
447 * Search a directory for a name and return its
448 * i_number.
449 */
450 static int
search_directory(char * name,struct open_file * f,ino_t * inumber_p)451 search_directory(char *name, struct open_file *f, ino_t *inumber_p)
452 {
453 struct file *fp = (struct file *)f->f_fsdata;
454 struct direct *dp;
455 struct direct *edp;
456 char *buf;
457 size_t buf_size;
458 int namlen, length;
459 int rc;
460
461 length = strlen(name);
462
463 fp->f_seekp = 0;
464 while (fp->f_seekp < DIP(fp, di_size)) {
465 rc = buf_read_file(f, &buf, &buf_size);
466 if (rc)
467 return (rc);
468
469 dp = (struct direct *)buf;
470 edp = (struct direct *)(buf + buf_size);
471 while (dp < edp) {
472 if (dp->d_ino == (ino_t)0)
473 goto next;
474 #if BYTE_ORDER == LITTLE_ENDIAN
475 if (fp->f_fs->fs_maxsymlinklen <= 0)
476 namlen = dp->d_type;
477 else
478 #endif
479 namlen = dp->d_namlen;
480 if (namlen == length &&
481 !strcmp(name, dp->d_name)) {
482 /* found entry */
483 *inumber_p = dp->d_ino;
484 return (0);
485 }
486 next:
487 dp = (struct direct *)((char *)dp + dp->d_reclen);
488 }
489 fp->f_seekp += buf_size;
490 }
491 return (ENOENT);
492 }
493
494 /*
495 * Open a file.
496 */
497 static int
ufs_open(const char * upath,struct open_file * f)498 ufs_open(const char *upath, struct open_file *f)
499 {
500 char *cp, *ncp;
501 int c;
502 ino_t inumber, parent_inumber;
503 struct file *fp;
504 struct fs *fs;
505 int rc;
506 int nlinks = 0;
507 char namebuf[MAXPATHLEN+1];
508 char *buf = NULL;
509 char *path = NULL;
510 const char *dev;
511 ufs_mnt_t *mnt;
512
513 /* allocate file system specific data structure */
514 errno = 0;
515 fp = calloc(1, sizeof(struct file));
516 if (fp == NULL)
517 return (errno);
518 f->f_fsdata = (void *)fp;
519
520 dev = devformat((struct devdesc *)f->f_devdata);
521 /* Is this device mounted? */
522 STAILQ_FOREACH(mnt, &mnt_list, um_link) {
523 if (strcmp(dev, mnt->um_dev) == 0)
524 break;
525 }
526
527 if (mnt == NULL) {
528 /* read super block */
529 twiddle(1);
530 if ((rc = ffs_sbget(f, &fs, UFS_STDSB, UFS_NOHASHFAIL, "stand",
531 ufs_use_sa_read)) != 0) {
532 goto out;
533 }
534 } else {
535 struct open_file *sbf;
536 struct file *sfp;
537
538 /* get superblock from mounted file system */
539 sbf = fd2open_file(mnt->um_fd);
540 sfp = sbf->f_fsdata;
541 fs = sfp->f_fs;
542 }
543 fp->f_fs = fs;
544
545 /*
546 * Calculate indirect block levels.
547 */
548 {
549 ufs2_daddr_t mult;
550 int level;
551
552 mult = 1;
553 for (level = 0; level < UFS_NIADDR; level++) {
554 mult *= NINDIR(fs);
555 fp->f_nindir[level] = mult;
556 }
557 }
558
559 inumber = UFS_ROOTINO;
560 if ((rc = read_inode(inumber, f)) != 0)
561 goto out;
562
563 cp = path = strdup(upath);
564 if (path == NULL) {
565 rc = ENOMEM;
566 goto out;
567 }
568 while (*cp) {
569
570 /*
571 * Remove extra separators
572 */
573 while (*cp == '/')
574 cp++;
575 if (*cp == '\0')
576 break;
577
578 /*
579 * Check that current node is a directory.
580 */
581 if ((DIP(fp, di_mode) & IFMT) != IFDIR) {
582 rc = ENOTDIR;
583 goto out;
584 }
585
586 /*
587 * Get next component of path name.
588 */
589 {
590 int len = 0;
591
592 ncp = cp;
593 while ((c = *cp) != '\0' && c != '/') {
594 if (++len > UFS_MAXNAMLEN) {
595 rc = ENOENT;
596 goto out;
597 }
598 cp++;
599 }
600 *cp = '\0';
601 }
602
603 /*
604 * Look up component in current directory.
605 * Save directory inumber in case we find a
606 * symbolic link.
607 */
608 parent_inumber = inumber;
609 rc = search_directory(ncp, f, &inumber);
610 *cp = c;
611 if (rc)
612 goto out;
613
614 /*
615 * Open next component.
616 */
617 if ((rc = read_inode(inumber, f)) != 0)
618 goto out;
619
620 /*
621 * Check for symbolic link.
622 */
623 if ((DIP(fp, di_mode) & IFMT) == IFLNK) {
624 int link_len = DIP(fp, di_size);
625 int len;
626
627 len = strlen(cp);
628
629 if (link_len + len > MAXPATHLEN ||
630 ++nlinks > MAXSYMLINKS) {
631 rc = ENOENT;
632 goto out;
633 }
634
635 bcopy(cp, &namebuf[link_len], len + 1);
636
637 if (link_len < fs->fs_maxsymlinklen) {
638 bcopy(DIP(fp, di_shortlink), namebuf,
639 (unsigned) link_len);
640 } else {
641 /*
642 * Read file for symbolic link
643 */
644 size_t buf_size;
645 ufs2_daddr_t disk_block;
646 struct fs *fs = fp->f_fs;
647
648 if (!buf)
649 buf = malloc(fs->fs_bsize);
650 rc = block_map(f, (ufs2_daddr_t)0, &disk_block);
651 if (rc)
652 goto out;
653
654 twiddle(1);
655 rc = (f->f_dev->dv_strategy)(f->f_devdata,
656 F_READ, fsbtodb(fs, disk_block),
657 fs->fs_bsize, buf, &buf_size);
658 if (rc)
659 goto out;
660
661 bcopy((char *)buf, namebuf, (unsigned)link_len);
662 }
663
664 /*
665 * If relative pathname, restart at parent directory.
666 * If absolute pathname, restart at root.
667 */
668 cp = namebuf;
669 if (*cp != '/')
670 inumber = parent_inumber;
671 else
672 inumber = (ino_t)UFS_ROOTINO;
673
674 if ((rc = read_inode(inumber, f)) != 0)
675 goto out;
676 }
677 }
678
679 /*
680 * Found terminal component.
681 */
682 rc = 0;
683 fp->f_seekp = 0;
684 out:
685 free(buf);
686 free(path);
687 if (rc) {
688 free(fp->f_buf);
689
690 if (mnt == NULL && fp->f_fs != NULL) {
691 free(fp->f_fs->fs_csp);
692 free(fp->f_fs->fs_si);
693 free(fp->f_fs);
694 }
695 free(fp);
696 }
697 return (rc);
698 }
699
700 /*
701 * A read function for use by standalone-layer routines.
702 */
703 static int
ufs_use_sa_read(void * devfd,off_t loc,void ** bufp,int size)704 ufs_use_sa_read(void *devfd, off_t loc, void **bufp, int size)
705 {
706 struct open_file *f;
707 size_t buf_size;
708 int error;
709
710 f = (struct open_file *)devfd;
711 if ((*bufp = malloc(size)) == NULL)
712 return (ENOSPC);
713 error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, loc / DEV_BSIZE,
714 size, *bufp, &buf_size);
715 if (error != 0)
716 return (error);
717 if (buf_size != size)
718 return (EIO);
719 return (0);
720 }
721
722 static int
ufs_close(struct open_file * f)723 ufs_close(struct open_file *f)
724 {
725 ufs_mnt_t *mnt;
726 struct file *fp = (struct file *)f->f_fsdata;
727 int level;
728 char *dev;
729
730 f->f_fsdata = NULL;
731 if (fp == NULL)
732 return (0);
733
734 for (level = 0; level < UFS_NIADDR; level++) {
735 free(fp->f_blk[level]);
736 }
737 free(fp->f_buf);
738
739 dev = devformat((struct devdesc *)f->f_devdata);
740 STAILQ_FOREACH(mnt, &mnt_list, um_link) {
741 if (strcmp(dev, mnt->um_dev) == 0)
742 break;
743 }
744
745 if (mnt == NULL && fp->f_fs != NULL) {
746 free(fp->f_fs->fs_csp);
747 free(fp->f_fs->fs_si);
748 free(fp->f_fs);
749 }
750
751 free(fp);
752 return (0);
753 }
754
755 /*
756 * Copy a portion of a file into kernel memory.
757 * Cross block boundaries when necessary.
758 */
759 static int
ufs_read(struct open_file * f,void * start,size_t size,size_t * resid)760 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
761 {
762 struct file *fp = (struct file *)f->f_fsdata;
763 size_t csize;
764 char *buf;
765 size_t buf_size;
766 int rc = 0;
767 char *addr = start;
768
769 while (size != 0) {
770 if (fp->f_seekp >= DIP(fp, di_size))
771 break;
772
773 rc = buf_read_file(f, &buf, &buf_size);
774 if (rc)
775 break;
776
777 csize = size;
778 if (csize > buf_size)
779 csize = buf_size;
780
781 bcopy(buf, addr, csize);
782
783 fp->f_seekp += csize;
784 addr += csize;
785 size -= csize;
786 }
787 if (resid)
788 *resid = size;
789 return (rc);
790 }
791
792 /*
793 * Write to a portion of an already allocated file.
794 * Cross block boundaries when necessary. Can not
795 * extend the file.
796 */
797 static int
ufs_write(struct open_file * f,const void * start,size_t size,size_t * resid)798 ufs_write(struct open_file *f, const void *start, size_t size, size_t *resid)
799 {
800 struct file *fp = (struct file *)f->f_fsdata;
801 size_t csize;
802 int rc = 0;
803 const char *addr = start;
804
805 csize = size;
806 while ((size != 0) && (csize != 0)) {
807 if (fp->f_seekp >= DIP(fp, di_size))
808 break;
809
810 if (csize >= 512) csize = 512; /* XXX */
811
812 rc = buf_write_file(f, addr, &csize);
813 if (rc)
814 break;
815
816 fp->f_seekp += csize;
817 addr += csize;
818 size -= csize;
819 }
820 if (resid)
821 *resid = size;
822 return (rc);
823 }
824
825 static off_t
ufs_seek(struct open_file * f,off_t offset,int where)826 ufs_seek(struct open_file *f, off_t offset, int where)
827 {
828 struct file *fp = (struct file *)f->f_fsdata;
829
830 switch (where) {
831 case SEEK_SET:
832 fp->f_seekp = offset;
833 break;
834 case SEEK_CUR:
835 fp->f_seekp += offset;
836 break;
837 case SEEK_END:
838 fp->f_seekp = DIP(fp, di_size) - offset;
839 break;
840 default:
841 errno = EINVAL;
842 return (-1);
843 }
844 return (fp->f_seekp);
845 }
846
847 static int
ufs_stat(struct open_file * f,struct stat * sb)848 ufs_stat(struct open_file *f, struct stat *sb)
849 {
850 struct file *fp = (struct file *)f->f_fsdata;
851
852 /* only important stuff */
853 sb->st_mode = DIP(fp, di_mode);
854 sb->st_uid = DIP(fp, di_uid);
855 sb->st_gid = DIP(fp, di_gid);
856 sb->st_size = DIP(fp, di_size);
857 sb->st_mtime = DIP(fp, di_mtime);
858 /*
859 * The items below are ufs specific!
860 * Other fs types will need their own solution
861 * if these fields are needed.
862 */
863 sb->st_ino = fp->f_inumber;
864 /*
865 * We need something to differentiate devs.
866 * fs_id is unique but 64bit, we xor the two
867 * halves to squeeze it into 32bits.
868 */
869 sb->st_dev = (dev_t)(fp->f_fs->fs_id[0] ^ fp->f_fs->fs_id[1]);
870
871 return (0);
872 }
873
874 static int
ufs_readdir(struct open_file * f,struct dirent * d)875 ufs_readdir(struct open_file *f, struct dirent *d)
876 {
877 struct file *fp = (struct file *)f->f_fsdata;
878 struct direct *dp;
879 char *buf;
880 size_t buf_size;
881 int error;
882
883 /*
884 * assume that a directory entry will not be split across blocks
885 */
886
887 do {
888 if (fp->f_seekp >= DIP(fp, di_size))
889 return (ENOENT);
890 error = buf_read_file(f, &buf, &buf_size);
891 if (error)
892 return (error);
893 dp = (struct direct *)buf;
894 /*
895 * Check for corrupt directory entry and bail out rather
896 * than spin forever hoping that the user has other options.
897 */
898 if (dp->d_reclen == 0)
899 return (0);
900 fp->f_seekp += dp->d_reclen;
901 } while (dp->d_ino == (ino_t)0);
902
903 d->d_type = dp->d_type;
904 strcpy(d->d_name, dp->d_name);
905 return (0);
906 }
907
908 static int
ufs_mount(const char * dev,const char * path,void ** data)909 ufs_mount(const char *dev, const char *path, void **data)
910 {
911 char *fs;
912 ufs_mnt_t *mnt;
913 struct open_file *f;
914
915 errno = 0;
916 mnt = calloc(1, sizeof(*mnt));
917 if (mnt == NULL)
918 return (errno);
919 mnt->um_fd = -1;
920 mnt->um_dev = strdup(dev);
921 if (mnt->um_dev == NULL)
922 goto done;
923
924 if (asprintf(&fs, "%s%s", dev, path) < 0)
925 goto done;
926
927 mnt->um_fd = open(fs, O_RDONLY);
928 free(fs);
929 if (mnt->um_fd == -1)
930 goto done;
931
932 /* Is it ufs file system? */
933 f = fd2open_file(mnt->um_fd);
934 if (strcmp(f->f_ops->fs_name, "ufs") == 0)
935 STAILQ_INSERT_TAIL(&mnt_list, mnt, um_link);
936 else
937 errno = ENXIO;
938
939 done:
940 if (errno != 0) {
941 free(mnt->um_dev);
942 if (mnt->um_fd >= 0)
943 close(mnt->um_fd);
944 free(mnt);
945 } else {
946 *data = mnt;
947 }
948
949 return (errno);
950 }
951
952 static int
ufs_unmount(const char * dev __unused,void * data)953 ufs_unmount(const char *dev __unused, void *data)
954 {
955 ufs_mnt_t *mnt = data;
956
957 STAILQ_REMOVE(&mnt_list, mnt, ufs_mnt, um_link);
958 free(mnt->um_dev);
959 close(mnt->um_fd);
960 free(mnt);
961 return (0);
962 }
963