2 * Copyright (c) 1999,2000 Jonathan Lemon <jlemon@freebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/lib/libstand/ext2fs.c,v 1.1.2.2 2001/03/05 06:26:07 kris Exp $
27 * $DragonFly: src/lib/libstand/ext2fs.c,v 1.2 2003/06/17 04:26:51 dillon Exp $
31 * The Regents of the University of California. All rights reserved.
33 * This code is derived from software contributed to Berkeley by
34 * The Mach Operating System project at Carnegie-Mellon University.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * Copyright (c) 1990, 1991 Carnegie Mellon University
62 * All Rights Reserved.
66 * Permission to use, copy, modify and distribute this software and its
67 * documentation is hereby granted, provided that both the copyright
68 * notice and this permission notice appear in all copies of the
69 * software, derivative works or modified versions, and any portions
70 * thereof, and that both notices appear in supporting documentation.
72 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
73 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
74 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
76 * Carnegie Mellon requests users of this software to return to
78 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
79 * School of Computer Science
80 * Carnegie Mellon University
81 * Pittsburgh PA 15213-3890
83 * any improvements or extensions that they make and grant Carnegie the
84 * rights to redistribute these changes.
87 #include <sys/param.h>
92 static int ext2fs_open(const char *path
, struct open_file
*f
);
93 static int ext2fs_close(struct open_file
*f
);
94 static int ext2fs_read(struct open_file
*f
, void *buf
,
95 size_t size
, size_t *resid
);
96 static off_t
ext2fs_seek(struct open_file
*f
, off_t offset
, int where
);
97 static int ext2fs_stat(struct open_file
*f
, struct stat
*sb
);
98 static int ext2fs_readdir(struct open_file
*f
, struct dirent
*d
);
100 static int dtmap
[] = { DT_UNKNOWN
, DT_REG
, DT_DIR
, DT_CHR
,
101 DT_BLK
, DT_FIFO
, DT_SOCK
, DT_LNK
};
102 #define EXTFTODT(x) (x) > sizeof(dtmap) / sizeof(dtmap[0]) ? \
103 DT_UNKNOWN : dtmap[x]
105 struct fs_ops ext2fs_fsops
= {
116 #define EXT2_SBSIZE 1024
117 #define EXT2_SBLOCK (1024 / DEV_BSIZE) /* block offset of superblock */
118 #define EXT2_MAGIC 0xef53
119 #define EXT2_ROOTINO 2
121 #define EXT2_REV0 0 /* original revision of ext2 */
122 #define EXT2_R0_ISIZE 128 /* inode size */
123 #define EXT2_R0_FIRSTINO 11 /* first inode */
125 #define EXT2_MINBSHIFT 10 /* mininum block shift */
126 #define EXT2_MINFSHIFT 10 /* mininum frag shift */
128 #define NDADDR 12 /* # of direct blocks */
129 #define NIADDR 3 /* # of indirect blocks */
132 * file system block to disk address
134 #define fsb_to_db(fs, blk) ((blk) << (fs)->fs_fsbtodb)
137 * inode to block group offset
138 * inode to block group
139 * inode to disk address
140 * inode to block offset
142 #define ino_to_bgo(fs, ino) (((ino) - 1) % (fs)->fs_ipg)
143 #define ino_to_bg(fs, ino) (((ino) - 1) / (fs)->fs_ipg)
144 #define ino_to_db(fs, bg, ino) \
145 fsb_to_db(fs, ((bg)[ino_to_bg(fs, ino)].bg_inotbl + \
146 ino_to_bgo(fs, ino) / (fs)->fs_ipb))
147 #define ino_to_bo(fs, ino) (ino_to_bgo(fs, ino) % (fs)->fs_ipb)
150 ((fs)->fs_bsize / sizeof(u_int32_t))
151 #define lblkno(fs, loc) /* loc / bsize */ \
152 ((loc) >> (fs)->fs_bshift)
153 #define smalllblktosize(fs, blk) /* blk * bsize */ \
154 ((blk) << (fs)->fs_bshift)
155 #define blkoff(fs, loc) /* loc % bsize */ \
156 ((loc) & (fs)->fs_bmask)
157 #define fragroundup(fs, size) /* roundup(size, fsize) */ \
158 (((size) + (fs)->fs_fmask) & ~(fs)->fs_fmask)
159 #define dblksize(fs, dip, lbn) \
160 (((lbn) >= NDADDR || (dip)->di_size >= smalllblktosize(fs, (lbn) + 1)) \
162 : (fragroundup(fs, blkoff(fs, (dip)->di_size))))
165 * superblock describing ext2fs
168 u_int32_t fd_inodes
; /* # of inodes */
169 u_int32_t fd_blocks
; /* # of blocks */
170 u_int32_t fd_resblk
; /* # of reserved blocks */
171 u_int32_t fd_freeblk
; /* # of free blocks */
172 u_int32_t fd_freeino
; /* # of free inodes */
173 u_int32_t fd_firstblk
; /* first data block */
174 u_int32_t fd_bsize
; /* block size */
175 u_int32_t fd_fsize
; /* frag size */
176 u_int32_t fd_bpg
; /* blocks per group */
177 u_int32_t fd_fpg
; /* frags per group */
178 u_int32_t fd_ipg
; /* inodes per group */
179 u_int32_t fd_mtime
; /* mount time */
180 u_int32_t fd_wtime
; /* write time */
181 u_int16_t fd_mount
; /* # of mounts */
182 int16_t fd_maxmount
; /* max # of mounts */
183 u_int16_t fd_magic
; /* magic number */
184 u_int16_t fd_state
; /* state */
185 u_int16_t fd_eflag
; /* error flags */
186 u_int16_t fd_mnrrev
; /* minor revision */
187 u_int32_t fd_lastchk
; /* last check */
188 u_int32_t fd_chkintvl
; /* maximum check interval */
189 u_int32_t fd_os
; /* os */
190 u_int32_t fd_revision
; /* revision */
191 u_int16_t fd_uid
; /* uid for reserved blocks */
192 u_int16_t fd_gid
; /* gid for reserved blocks */
194 u_int32_t fd_firstino
; /* first non-reserved inode */
195 u_int16_t fd_isize
; /* inode size */
196 u_int16_t fd_nblkgrp
; /* block group # of superblock */
197 u_int32_t fd_fcompat
; /* compatible features */
198 u_int32_t fd_fincompat
; /* incompatible features */
199 u_int32_t fd_frocompat
; /* read-only compatibilties */
200 u_int8_t fd_uuid
[16]; /* volume uuid */
201 char fd_volname
[16]; /* volume name */
202 char fd_fsmnt
[64]; /* name last mounted on */
203 u_int32_t fd_bitmap
; /* compression bitmap */
205 u_int8_t fd_nblkpa
; /* # of blocks to preallocate */
206 u_int8_t fd_ndblkpa
; /* # of dir blocks to preallocate */
210 int fc_bsize
; /* block size */
211 int fc_bshift
; /* block shift amount */
212 int fc_bmask
; /* block mask */
213 int fc_fsize
; /* frag size */
214 int fc_fshift
; /* frag shift amount */
215 int fc_fmask
; /* frag mask */
216 int fc_isize
; /* inode size */
217 int fc_imask
; /* inode mask */
218 int fc_firstino
; /* first non-reserved inode */
219 int fc_ipb
; /* inodes per block */
220 int fc_fsbtodb
; /* fsb to ds shift */
224 struct ext2fs_disk fs_fd
;
225 char fs_pad
[EXT2_SBSIZE
- sizeof(struct ext2fs_disk
)];
226 struct ext2fs_core fs_fc
;
228 #define fs_magic fs_fd.fd_magic
229 #define fs_revision fs_fd.fd_revision
230 #define fs_blocks fs_fd.fd_blocks
231 #define fs_firstblk fs_fd.fd_firstblk
232 #define fs_bpg fs_fd.fd_bpg
233 #define fs_ipg fs_fd.fd_ipg
235 #define fs_bsize fs_fc.fc_bsize
236 #define fs_bshift fs_fc.fc_bshift
237 #define fs_bmask fs_fc.fc_bmask
238 #define fs_fsize fs_fc.fc_fsize
239 #define fs_fshift fs_fc.fc_fshift
240 #define fs_fmask fs_fc.fc_fmask
241 #define fs_isize fs_fc.fc_isize
242 #define fs_imask fs_fc.fc_imask
243 #define fs_firstino fs_fc.fc_firstino
244 #define fs_ipb fs_fc.fc_ipb
245 #define fs_fsbtodb fs_fc.fc_fsbtodb
249 u_int32_t bg_blkmap
; /* block bitmap */
250 u_int32_t bg_inomap
; /* inode bitmap */
251 u_int32_t bg_inotbl
; /* inode table */
252 u_int16_t bg_nfblk
; /* # of free blocks */
253 u_int16_t bg_nfino
; /* # of free inodes */
254 u_int16_t bg_ndirs
; /* # of dirs */
259 u_int16_t di_mode
; /* mode */
260 u_int16_t di_uid
; /* uid */
261 u_int32_t di_size
; /* byte size */
262 u_int32_t di_atime
; /* access time */
263 u_int32_t di_ctime
; /* creation time */
264 u_int32_t di_mtime
; /* modification time */
265 u_int32_t di_dtime
; /* deletion time */
266 u_int16_t di_gid
; /* gid */
267 u_int16_t di_nlink
; /* link count */
268 u_int32_t di_nblk
; /* block count */
269 u_int32_t di_flags
; /* file flags */
271 u_int32_t di_osdep1
; /* os dependent stuff */
273 u_int32_t di_db
[NDADDR
]; /* direct blocks */
274 u_int32_t di_ib
[NIADDR
]; /* indirect blocks */
275 u_int32_t di_version
; /* version */
276 u_int32_t di_facl
; /* file acl */
277 u_int32_t di_dacl
; /* dir acl */
278 u_int32_t di_faddr
; /* fragment addr */
280 u_int8_t di_frag
; /* fragment number */
281 u_int8_t di_fsize
; /* fragment size */
285 #define di_shortlink di_db
288 #define EXT2_MAXNAMLEN 255
291 u_int32_t d_ino
; /* inode */
292 u_int16_t d_reclen
; /* directory entry length */
293 u_int8_t d_namlen
; /* name length */
294 u_int8_t d_type
; /* file type */
295 char d_name
[EXT2_MAXNAMLEN
];
299 off_t f_seekp
; /* seek pointer */
300 struct ext2fs
*f_fs
; /* pointer to super-block */
301 struct ext2blkgrp
*f_bg
; /* pointer to blkgrp map */
302 struct ext2dinode f_di
; /* copy of on-disk inode */
303 int f_nindir
[NIADDR
]; /* number of blocks mapped by
304 indirect block at level i */
305 char *f_blk
[NIADDR
]; /* buffer for indirect block
307 size_t f_blksize
[NIADDR
]; /* size of buffer */
308 daddr_t f_blkno
[NIADDR
]; /* disk address of block in
310 char *f_buf
; /* buffer for data block */
311 size_t f_buf_size
; /* size of data block */
312 daddr_t f_buf_blkno
; /* block number of data block */
316 static int read_inode(ino_t inumber
, struct open_file
*f
);
317 static int block_map(struct open_file
*f
, daddr_t file_block
,
318 daddr_t
*disk_block_p
);
319 static int buf_read_file(struct open_file
*f
, char **buf_p
,
321 static int search_directory(char *name
, struct open_file
*f
,
328 ext2fs_open(const char *upath
, struct open_file
*f
)
333 ino_t inumber
, parent_inumber
;
334 int i
, len
, groups
, bg_per_blk
, blkgrps
, mult
;
337 char *cp
, *ncp
, *path
= NULL
, *buf
= NULL
;
338 char namebuf
[MAXPATHLEN
+1];
341 /* allocate file system specific data structure */
342 fp
= malloc(sizeof(struct file
));
345 bzero(fp
, sizeof(struct file
));
346 f
->f_fsdata
= (void *)fp
;
348 /* allocate space and read super block */
349 fs
= (struct ext2fs
*)malloc(sizeof(*fs
));
352 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
353 EXT2_SBLOCK
, EXT2_SBSIZE
, (char *)fs
, &buf_size
);
357 if (buf_size
!= EXT2_SBSIZE
|| fs
->fs_magic
!= EXT2_MAGIC
) {
363 * compute in-core values for the superblock
365 fs
->fs_bshift
= EXT2_MINBSHIFT
+ fs
->fs_fd
.fd_bsize
;
366 fs
->fs_bsize
= 1 << fs
->fs_bshift
;
367 fs
->fs_bmask
= fs
->fs_bsize
- 1;
369 fs
->fs_fshift
= EXT2_MINFSHIFT
+ fs
->fs_fd
.fd_fsize
;
370 fs
->fs_fsize
= 1 << fs
->fs_fshift
;
371 fs
->fs_fmask
= fs
->fs_fsize
- 1;
373 if (fs
->fs_revision
== EXT2_REV0
) {
374 fs
->fs_isize
= EXT2_R0_ISIZE
;
375 fs
->fs_firstino
= EXT2_R0_FIRSTINO
;
377 fs
->fs_isize
= fs
->fs_fd
.fd_isize
;
378 fs
->fs_firstino
= fs
->fs_fd
.fd_firstino
;
380 fs
->fs_imask
= fs
->fs_isize
- 1;
381 fs
->fs_ipb
= fs
->fs_bsize
/ fs
->fs_isize
;
382 fs
->fs_fsbtodb
= (fs
->fs_bsize
/ DEV_BSIZE
) - 1;
385 * we have to load in the "group descriptors" here
387 groups
= howmany(fs
->fs_blocks
- fs
->fs_firstblk
, fs
->fs_bpg
);
388 bg_per_blk
= fs
->fs_bsize
/ sizeof(struct ext2blkgrp
);
389 blkgrps
= howmany(groups
, bg_per_blk
);
390 len
= blkgrps
* fs
->fs_bsize
;
392 fp
->f_bg
= malloc(len
);
394 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
395 EXT2_SBLOCK
+ EXT2_SBSIZE
/ DEV_BSIZE
, len
,
396 (char *)fp
->f_bg
, &buf_size
);
402 * validation of values? (blocksize, descriptors, etc?)
406 * Calculate indirect block levels.
409 for (i
= 0; i
< NIADDR
; i
++) {
411 fp
->f_nindir
[i
] = mult
;
414 inumber
= EXT2_ROOTINO
;
415 if ((error
= read_inode(inumber
, f
)) != 0)
418 path
= strdup(upath
);
426 * Remove extra separators
434 * Check that current node is a directory.
436 if (! S_ISDIR(fp
->f_di
.di_mode
)) {
442 * Get next component of path name.
447 while ((c
= *cp
) != '\0' && c
!= '/') {
448 if (++len
> EXT2_MAXNAMLEN
) {
457 * Look up component in current directory.
458 * Save directory inumber in case we find a
461 parent_inumber
= inumber
;
462 error
= search_directory(ncp
, f
, &inumber
);
468 * Open next component.
470 if ((error
= read_inode(inumber
, f
)) != 0)
474 * Check for symbolic link.
476 if (S_ISLNK(fp
->f_di
.di_mode
)) {
477 int link_len
= fp
->f_di
.di_size
;
481 if (link_len
+ len
> MAXPATHLEN
||
482 ++nlinks
> MAXSYMLINKS
) {
487 bcopy(cp
, &namebuf
[link_len
], len
+ 1);
488 if (fp
->f_di
.di_nblk
== 0) {
489 bcopy(fp
->f_di
.di_shortlink
,
493 * Read file for symbolic link
495 struct ext2fs
*fs
= fp
->f_fs
;
500 buf
= malloc(fs
->fs_bsize
);
501 error
= block_map(f
, (daddr_t
)0, &disk_block
);
506 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
,
507 F_READ
, fsb_to_db(fs
, disk_block
),
508 fs
->fs_bsize
, buf
, &buf_size
);
512 bcopy((char *)buf
, namebuf
, link_len
);
516 * If relative pathname, restart at parent directory.
517 * If absolute pathname, restart at root.
521 inumber
= parent_inumber
;
523 inumber
= (ino_t
)EXT2_ROOTINO
;
525 if ((error
= read_inode(inumber
, f
)) != 0)
531 * Found terminal component.
550 * Read a new inode into a file structure.
553 read_inode(ino_t inumber
, struct open_file
*f
)
555 struct file
*fp
= (struct file
*)f
->f_fsdata
;
556 struct ext2fs
*fs
= fp
->f_fs
;
557 struct ext2dinode
*dp
;
560 int level
, error
= 0;
563 * Read inode and save it.
565 buf
= malloc(fs
->fs_bsize
);
567 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
568 ino_to_db(fs
, fp
->f_bg
, inumber
), fs
->fs_bsize
, buf
, &rsize
);
571 if (rsize
!= fs
->fs_bsize
) {
576 dp
= (struct ext2dinode
*)buf
;
577 fp
->f_di
= dp
[ino_to_bo(fs
, inumber
)];
579 /* clear out old buffers */
580 for (level
= 0; level
< NIADDR
; level
++)
581 fp
->f_blkno
[level
] = -1;
582 fp
->f_buf_blkno
= -1;
590 * Given an offset in a file, find the disk block number that
591 * contains that block.
594 block_map(struct open_file
*f
, daddr_t file_block
, daddr_t
*disk_block_p
)
596 struct file
*fp
= (struct file
*)f
->f_fsdata
;
597 struct ext2fs
*fs
= fp
->f_fs
;
598 daddr_t ind_block_num
;
604 * Index structure of an inode:
606 * di_db[0..NDADDR-1] hold block numbers for blocks
609 * di_ib[0] index block 0 is the single indirect block
610 * holds block numbers for blocks
611 * NDADDR .. NDADDR + NINDIR(fs)-1
613 * di_ib[1] index block 1 is the double indirect block
614 * holds block numbers for INDEX blocks for blocks
615 * NDADDR + NINDIR(fs) ..
616 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
618 * di_ib[2] index block 2 is the triple indirect block
619 * holds block numbers for double-indirect
621 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
622 * NDADDR + NINDIR(fs) + NINDIR(fs)**2
623 * + NINDIR(fs)**3 - 1
626 if (file_block
< NDADDR
) {
628 *disk_block_p
= fp
->f_di
.di_db
[file_block
];
632 file_block
-= NDADDR
;
636 * nindir[1] = NINDIR**2
637 * nindir[2] = NINDIR**3
640 for (level
= 0; level
< NIADDR
; level
++) {
641 if (file_block
< fp
->f_nindir
[level
])
643 file_block
-= fp
->f_nindir
[level
];
645 if (level
== NIADDR
) {
646 /* Block number too high */
650 ind_block_num
= fp
->f_di
.di_ib
[level
];
652 for (; level
>= 0; level
--) {
653 if (ind_block_num
== 0) {
654 *disk_block_p
= 0; /* missing */
658 if (fp
->f_blkno
[level
] != ind_block_num
) {
659 if (fp
->f_blk
[level
] == NULL
)
661 malloc(fs
->fs_bsize
);
663 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
664 fsb_to_db(fp
->f_fs
, ind_block_num
), fs
->fs_bsize
,
665 fp
->f_blk
[level
], &fp
->f_blksize
[level
]);
668 if (fp
->f_blksize
[level
] != fs
->fs_bsize
)
670 fp
->f_blkno
[level
] = ind_block_num
;
673 ind_p
= (daddr_t
*)fp
->f_blk
[level
];
676 idx
= file_block
/ fp
->f_nindir
[level
- 1];
677 file_block
%= fp
->f_nindir
[level
- 1];
681 ind_block_num
= ind_p
[idx
];
684 *disk_block_p
= ind_block_num
;
690 * Read a portion of a file into an internal buffer. Return
691 * the location in the buffer and the amount in the buffer.
694 buf_read_file(struct open_file
*f
, char **buf_p
, size_t *size_p
)
696 struct file
*fp
= (struct file
*)f
->f_fsdata
;
697 struct ext2fs
*fs
= fp
->f_fs
;
704 off
= blkoff(fs
, fp
->f_seekp
);
705 file_block
= lblkno(fs
, fp
->f_seekp
);
706 block_size
= dblksize(fs
, &fp
->f_di
, file_block
);
708 if (file_block
!= fp
->f_buf_blkno
) {
709 error
= block_map(f
, file_block
, &disk_block
);
713 if (fp
->f_buf
== NULL
)
714 fp
->f_buf
= malloc(fs
->fs_bsize
);
716 if (disk_block
== 0) {
717 bzero(fp
->f_buf
, block_size
);
718 fp
->f_buf_size
= block_size
;
721 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
722 fsb_to_db(fs
, disk_block
), block_size
,
723 fp
->f_buf
, &fp
->f_buf_size
);
727 fp
->f_buf_blkno
= file_block
;
731 * Return address of byte in buffer corresponding to
732 * offset, and size of remainder of buffer after that
735 *buf_p
= fp
->f_buf
+ off
;
736 *size_p
= block_size
- off
;
739 * But truncate buffer at end of file.
741 if (*size_p
> fp
->f_di
.di_size
- fp
->f_seekp
)
742 *size_p
= fp
->f_di
.di_size
- fp
->f_seekp
;
748 * Search a directory for a name and return its
752 search_directory(char *name
, struct open_file
*f
, ino_t
*inumber_p
)
754 struct file
*fp
= (struct file
*)f
->f_fsdata
;
755 struct ext2dirent
*dp
, *edp
;
761 length
= strlen(name
);
763 while (fp
->f_seekp
< fp
->f_di
.di_size
) {
764 error
= buf_read_file(f
, &buf
, &buf_size
);
767 dp
= (struct ext2dirent
*)buf
;
768 edp
= (struct ext2dirent
*)(buf
+ buf_size
);
770 if (dp
->d_ino
== (ino_t
)0)
772 namlen
= dp
->d_namlen
;
773 if (namlen
== length
&&
774 strncmp(name
, dp
->d_name
, length
) == 0) {
776 *inumber_p
= dp
->d_ino
;
780 dp
= (struct ext2dirent
*)((char *)dp
+ dp
->d_reclen
);
782 fp
->f_seekp
+= buf_size
;
788 ext2fs_close(struct open_file
*f
)
790 struct file
*fp
= (struct file
*)f
->f_fsdata
;
797 for (level
= 0; level
< NIADDR
; level
++) {
798 if (fp
->f_blk
[level
])
799 free(fp
->f_blk
[level
]);
811 ext2fs_read(struct open_file
*f
, void *addr
, size_t size
, size_t *resid
)
813 struct file
*fp
= (struct file
*)f
->f_fsdata
;
814 size_t csize
, buf_size
;
819 if (fp
->f_seekp
>= fp
->f_di
.di_size
)
822 error
= buf_read_file(f
, &buf
, &buf_size
);
827 if (csize
> buf_size
)
830 bcopy(buf
, addr
, csize
);
832 fp
->f_seekp
+= csize
;
842 ext2fs_seek(struct open_file
*f
, off_t offset
, int where
)
844 struct file
*fp
= (struct file
*)f
->f_fsdata
;
848 fp
->f_seekp
= offset
;
851 fp
->f_seekp
+= offset
;
854 fp
->f_seekp
= fp
->f_di
.di_size
- offset
;
859 return (fp
->f_seekp
);
863 ext2fs_stat(struct open_file
*f
, struct stat
*sb
)
865 struct file
*fp
= (struct file
*)f
->f_fsdata
;
867 /* only important stuff */
868 sb
->st_mode
= fp
->f_di
.di_mode
;
869 sb
->st_uid
= fp
->f_di
.di_uid
;
870 sb
->st_gid
= fp
->f_di
.di_gid
;
871 sb
->st_size
= fp
->f_di
.di_size
;
876 ext2fs_readdir(struct open_file
*f
, struct dirent
*d
)
878 struct file
*fp
= (struct file
*)f
->f_fsdata
;
879 struct ext2dirent
*ed
;
885 * assume that a directory entry will not be split across blocks
888 if (fp
->f_seekp
>= fp
->f_di
.di_size
)
890 error
= buf_read_file(f
, &buf
, &buf_size
);
893 ed
= (struct ext2dirent
*)buf
;
894 fp
->f_seekp
+= ed
->d_reclen
;
895 if (ed
->d_ino
== (ino_t
)0)
897 d
->d_type
= EXTFTODT(ed
->d_type
);
898 strncpy(d
->d_name
, ed
->d_name
, ed
->d_namlen
);
899 d
->d_name
[ed
->d_namlen
] = '\0';