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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
32 * The Regents of the University of California. All rights reserved.
34 * This code is derived from software contributed to Berkeley by
35 * The Mach Operating System project at Carnegie-Mellon University.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * Copyright (c) 1990, 1991 Carnegie Mellon University
67 * All Rights Reserved.
71 * Permission to use, copy, modify and distribute this software and its
72 * documentation is hereby granted, provided that both the copyright
73 * notice and this permission notice appear in all copies of the
74 * software, derivative works or modified versions, and any portions
75 * thereof, and that both notices appear in supporting documentation.
77 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
78 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
79 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
81 * Carnegie Mellon requests users of this software to return to
83 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
84 * School of Computer Science
85 * Carnegie Mellon University
86 * Pittsburgh PA 15213-3890
88 * any improvements or extensions that they make and grant Carnegie the
89 * rights to redistribute these changes.
92 #include <sys/param.h>
97 static int ext2fs_open(const char *path
, struct open_file
*f
);
98 static int ext2fs_close(struct open_file
*f
);
99 static int ext2fs_read(struct open_file
*f
, void *buf
,
100 size_t size
, size_t *resid
);
101 static off_t
ext2fs_seek(struct open_file
*f
, off_t offset
, int where
);
102 static int ext2fs_stat(struct open_file
*f
, struct stat
*sb
);
103 static int ext2fs_readdir(struct open_file
*f
, struct dirent
*d
);
105 static int dtmap
[] = { DT_UNKNOWN
, DT_REG
, DT_DIR
, DT_CHR
,
106 DT_BLK
, DT_FIFO
, DT_SOCK
, DT_LNK
};
107 #define EXTFTODT(x) (x) > sizeof(dtmap) / sizeof(dtmap[0]) ? \
108 DT_UNKNOWN : dtmap[x]
110 struct fs_ops ext2fs_fsops
= {
121 #define EXT2_SBSIZE 1024
122 #define EXT2_SBLOCK (1024 / DEV_BSIZE) /* block offset of superblock */
123 #define EXT2_MAGIC 0xef53
124 #define EXT2_ROOTINO 2
126 #define EXT2_REV0 0 /* original revision of ext2 */
127 #define EXT2_R0_ISIZE 128 /* inode size */
128 #define EXT2_R0_FIRSTINO 11 /* first inode */
130 #define EXT2_MINBSHIFT 10 /* mininum block shift */
131 #define EXT2_MINFSHIFT 10 /* mininum frag shift */
133 #define NDADDR 12 /* # of direct blocks */
134 #define NIADDR 3 /* # of indirect blocks */
137 * file system block to disk address
139 #define fsb_to_db(fs, blk) ((blk) << (fs)->fs_fsbtodb)
142 * inode to block group offset
143 * inode to block group
144 * inode to disk address
145 * inode to block offset
147 #define ino_to_bgo(fs, ino) (((ino) - 1) % (fs)->fs_ipg)
148 #define ino_to_bg(fs, ino) (((ino) - 1) / (fs)->fs_ipg)
149 #define ino_to_db(fs, bg, ino) \
150 fsb_to_db(fs, ((bg)[ino_to_bg(fs, ino)].bg_inotbl + \
151 ino_to_bgo(fs, ino) / (fs)->fs_ipb))
152 #define ino_to_bo(fs, ino) (ino_to_bgo(fs, ino) % (fs)->fs_ipb)
155 ((fs)->fs_bsize / sizeof(u_int32_t))
156 #define lblkno(fs, loc) /* loc / bsize */ \
157 ((loc) >> (fs)->fs_bshift)
158 #define smalllblktosize(fs, blk) /* blk * bsize */ \
159 ((blk) << (fs)->fs_bshift)
160 #define blkoff(fs, loc) /* loc % bsize */ \
161 ((loc) & (fs)->fs_bmask)
162 #define fragroundup(fs, size) /* roundup(size, fsize) */ \
163 (((size) + (fs)->fs_fmask) & ~(fs)->fs_fmask)
164 #define dblksize(fs, dip, lbn) \
165 (((lbn) >= NDADDR || (dip)->di_size >= smalllblktosize(fs, (lbn) + 1)) \
167 : (fragroundup(fs, blkoff(fs, (dip)->di_size))))
170 * superblock describing ext2fs
173 u_int32_t fd_inodes
; /* # of inodes */
174 u_int32_t fd_blocks
; /* # of blocks */
175 u_int32_t fd_resblk
; /* # of reserved blocks */
176 u_int32_t fd_freeblk
; /* # of free blocks */
177 u_int32_t fd_freeino
; /* # of free inodes */
178 u_int32_t fd_firstblk
; /* first data block */
179 u_int32_t fd_bsize
; /* block size */
180 u_int32_t fd_fsize
; /* frag size */
181 u_int32_t fd_bpg
; /* blocks per group */
182 u_int32_t fd_fpg
; /* frags per group */
183 u_int32_t fd_ipg
; /* inodes per group */
184 u_int32_t fd_mtime
; /* mount time */
185 u_int32_t fd_wtime
; /* write time */
186 u_int16_t fd_mount
; /* # of mounts */
187 int16_t fd_maxmount
; /* max # of mounts */
188 u_int16_t fd_magic
; /* magic number */
189 u_int16_t fd_state
; /* state */
190 u_int16_t fd_eflag
; /* error flags */
191 u_int16_t fd_mnrrev
; /* minor revision */
192 u_int32_t fd_lastchk
; /* last check */
193 u_int32_t fd_chkintvl
; /* maximum check interval */
194 u_int32_t fd_os
; /* os */
195 u_int32_t fd_revision
; /* revision */
196 u_int16_t fd_uid
; /* uid for reserved blocks */
197 u_int16_t fd_gid
; /* gid for reserved blocks */
199 u_int32_t fd_firstino
; /* first non-reserved inode */
200 u_int16_t fd_isize
; /* inode size */
201 u_int16_t fd_nblkgrp
; /* block group # of superblock */
202 u_int32_t fd_fcompat
; /* compatible features */
203 u_int32_t fd_fincompat
; /* incompatible features */
204 u_int32_t fd_frocompat
; /* read-only compatibilties */
205 u_int8_t fd_uuid
[16]; /* volume uuid */
206 char fd_volname
[16]; /* volume name */
207 char fd_fsmnt
[64]; /* name last mounted on */
208 u_int32_t fd_bitmap
; /* compression bitmap */
210 u_int8_t fd_nblkpa
; /* # of blocks to preallocate */
211 u_int8_t fd_ndblkpa
; /* # of dir blocks to preallocate */
215 int fc_bsize
; /* block size */
216 int fc_bshift
; /* block shift amount */
217 int fc_bmask
; /* block mask */
218 int fc_fsize
; /* frag size */
219 int fc_fshift
; /* frag shift amount */
220 int fc_fmask
; /* frag mask */
221 int fc_isize
; /* inode size */
222 int fc_imask
; /* inode mask */
223 int fc_firstino
; /* first non-reserved inode */
224 int fc_ipb
; /* inodes per block */
225 int fc_fsbtodb
; /* fsb to ds shift */
229 struct ext2fs_disk fs_fd
;
230 char fs_pad
[EXT2_SBSIZE
- sizeof(struct ext2fs_disk
)];
231 struct ext2fs_core fs_fc
;
233 #define fs_magic fs_fd.fd_magic
234 #define fs_revision fs_fd.fd_revision
235 #define fs_blocks fs_fd.fd_blocks
236 #define fs_firstblk fs_fd.fd_firstblk
237 #define fs_bpg fs_fd.fd_bpg
238 #define fs_ipg fs_fd.fd_ipg
240 #define fs_bsize fs_fc.fc_bsize
241 #define fs_bshift fs_fc.fc_bshift
242 #define fs_bmask fs_fc.fc_bmask
243 #define fs_fsize fs_fc.fc_fsize
244 #define fs_fshift fs_fc.fc_fshift
245 #define fs_fmask fs_fc.fc_fmask
246 #define fs_isize fs_fc.fc_isize
247 #define fs_imask fs_fc.fc_imask
248 #define fs_firstino fs_fc.fc_firstino
249 #define fs_ipb fs_fc.fc_ipb
250 #define fs_fsbtodb fs_fc.fc_fsbtodb
254 u_int32_t bg_blkmap
; /* block bitmap */
255 u_int32_t bg_inomap
; /* inode bitmap */
256 u_int32_t bg_inotbl
; /* inode table */
257 u_int16_t bg_nfblk
; /* # of free blocks */
258 u_int16_t bg_nfino
; /* # of free inodes */
259 u_int16_t bg_ndirs
; /* # of dirs */
264 u_int16_t di_mode
; /* mode */
265 u_int16_t di_uid
; /* uid */
266 u_int32_t di_size
; /* byte size */
267 u_int32_t di_atime
; /* access time */
268 u_int32_t di_ctime
; /* creation time */
269 u_int32_t di_mtime
; /* modification time */
270 u_int32_t di_dtime
; /* deletion time */
271 u_int16_t di_gid
; /* gid */
272 u_int16_t di_nlink
; /* link count */
273 u_int32_t di_nblk
; /* block count */
274 u_int32_t di_flags
; /* file flags */
276 u_int32_t di_osdep1
; /* os dependent stuff */
278 u_int32_t di_db
[NDADDR
]; /* direct blocks */
279 u_int32_t di_ib
[NIADDR
]; /* indirect blocks */
280 u_int32_t di_version
; /* version */
281 u_int32_t di_facl
; /* file acl */
282 u_int32_t di_dacl
; /* dir acl */
283 u_int32_t di_faddr
; /* fragment addr */
285 u_int8_t di_frag
; /* fragment number */
286 u_int8_t di_fsize
; /* fragment size */
290 #define di_shortlink di_db
293 #define EXT2_MAXNAMLEN 255
296 u_int32_t d_ino
; /* inode */
297 u_int16_t d_reclen
; /* directory entry length */
298 u_int8_t d_namlen
; /* name length */
299 u_int8_t d_type
; /* file type */
300 char d_name
[EXT2_MAXNAMLEN
];
304 off_t f_seekp
; /* seek pointer */
305 struct ext2fs
*f_fs
; /* pointer to super-block */
306 struct ext2blkgrp
*f_bg
; /* pointer to blkgrp map */
307 struct ext2dinode f_di
; /* copy of on-disk inode */
308 int f_nindir
[NIADDR
]; /* number of blocks mapped by
309 indirect block at level i */
310 char *f_blk
[NIADDR
]; /* buffer for indirect block
312 size_t f_blksize
[NIADDR
]; /* size of buffer */
313 daddr_t f_blkno
[NIADDR
]; /* disk address of block in
315 char *f_buf
; /* buffer for data block */
316 size_t f_buf_size
; /* size of data block */
317 daddr_t f_buf_blkno
; /* block number of data block */
321 static int read_inode(ino_t inumber
, struct open_file
*f
);
322 static int block_map(struct open_file
*f
, daddr_t file_block
,
323 daddr_t
*disk_block_p
);
324 static int buf_read_file(struct open_file
*f
, char **buf_p
,
326 static int search_directory(char *name
, struct open_file
*f
,
333 ext2fs_open(const char *upath
, struct open_file
*f
)
338 ino_t inumber
, parent_inumber
;
339 int i
, len
, groups
, bg_per_blk
, blkgrps
, mult
;
342 char *cp
, *ncp
, *path
= NULL
, *buf
= NULL
;
343 char namebuf
[MAXPATHLEN
+1];
346 /* allocate file system specific data structure */
347 fp
= malloc(sizeof(struct file
));
350 bzero(fp
, sizeof(struct file
));
351 f
->f_fsdata
= (void *)fp
;
353 /* allocate space and read super block */
354 fs
= (struct ext2fs
*)malloc(sizeof(*fs
));
357 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
358 EXT2_SBLOCK
, 0, EXT2_SBSIZE
, (char *)fs
, &buf_size
);
362 if (buf_size
!= EXT2_SBSIZE
|| fs
->fs_magic
!= EXT2_MAGIC
) {
368 * compute in-core values for the superblock
370 fs
->fs_bshift
= EXT2_MINBSHIFT
+ fs
->fs_fd
.fd_bsize
;
371 fs
->fs_bsize
= 1 << fs
->fs_bshift
;
372 fs
->fs_bmask
= fs
->fs_bsize
- 1;
374 fs
->fs_fshift
= EXT2_MINFSHIFT
+ fs
->fs_fd
.fd_fsize
;
375 fs
->fs_fsize
= 1 << fs
->fs_fshift
;
376 fs
->fs_fmask
= fs
->fs_fsize
- 1;
378 if (fs
->fs_revision
== EXT2_REV0
) {
379 fs
->fs_isize
= EXT2_R0_ISIZE
;
380 fs
->fs_firstino
= EXT2_R0_FIRSTINO
;
382 fs
->fs_isize
= fs
->fs_fd
.fd_isize
;
383 fs
->fs_firstino
= fs
->fs_fd
.fd_firstino
;
385 fs
->fs_imask
= fs
->fs_isize
- 1;
386 fs
->fs_ipb
= fs
->fs_bsize
/ fs
->fs_isize
;
387 fs
->fs_fsbtodb
= (fs
->fs_bsize
/ DEV_BSIZE
) - 1;
390 * we have to load in the "group descriptors" here
392 groups
= howmany(fs
->fs_blocks
- fs
->fs_firstblk
, fs
->fs_bpg
);
393 bg_per_blk
= fs
->fs_bsize
/ sizeof(struct ext2blkgrp
);
394 blkgrps
= howmany(groups
, bg_per_blk
);
395 len
= blkgrps
* fs
->fs_bsize
;
397 fp
->f_bg
= malloc(len
);
399 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
400 EXT2_SBLOCK
+ EXT2_SBSIZE
/ DEV_BSIZE
, 0, len
,
401 (char *)fp
->f_bg
, &buf_size
);
407 * validation of values? (blocksize, descriptors, etc?)
411 * Calculate indirect block levels.
414 for (i
= 0; i
< NIADDR
; i
++) {
416 fp
->f_nindir
[i
] = mult
;
419 inumber
= EXT2_ROOTINO
;
420 if ((error
= read_inode(inumber
, f
)) != 0)
423 path
= strdup(upath
);
431 * Remove extra separators
439 * Check that current node is a directory.
441 if (! S_ISDIR(fp
->f_di
.di_mode
)) {
447 * Get next component of path name.
452 while ((c
= *cp
) != '\0' && c
!= '/') {
453 if (++len
> EXT2_MAXNAMLEN
) {
462 * Look up component in current directory.
463 * Save directory inumber in case we find a
466 parent_inumber
= inumber
;
467 error
= search_directory(ncp
, f
, &inumber
);
473 * Open next component.
475 if ((error
= read_inode(inumber
, f
)) != 0)
479 * Check for symbolic link.
481 if (S_ISLNK(fp
->f_di
.di_mode
)) {
482 int link_len
= fp
->f_di
.di_size
;
486 if (link_len
+ len
> MAXPATHLEN
||
487 ++nlinks
> MAXSYMLINKS
) {
492 bcopy(cp
, &namebuf
[link_len
], len
+ 1);
493 if (fp
->f_di
.di_nblk
== 0) {
494 bcopy(fp
->f_di
.di_shortlink
,
498 * Read file for symbolic link
500 struct ext2fs
*fs
= fp
->f_fs
;
505 buf
= malloc(fs
->fs_bsize
);
506 error
= block_map(f
, (daddr_t
)0, &disk_block
);
511 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
,
512 F_READ
, fsb_to_db(fs
, disk_block
), 0,
513 fs
->fs_bsize
, buf
, &buf_size
);
517 bcopy((char *)buf
, namebuf
, link_len
);
521 * If relative pathname, restart at parent directory.
522 * If absolute pathname, restart at root.
526 inumber
= parent_inumber
;
528 inumber
= (ino_t
)EXT2_ROOTINO
;
530 if ((error
= read_inode(inumber
, f
)) != 0)
536 * Found terminal component.
555 * Read a new inode into a file structure.
558 read_inode(ino_t inumber
, struct open_file
*f
)
560 struct file
*fp
= (struct file
*)f
->f_fsdata
;
561 struct ext2fs
*fs
= fp
->f_fs
;
562 struct ext2dinode
*dp
;
565 int level
, error
= 0;
568 * Read inode and save it.
570 buf
= malloc(fs
->fs_bsize
);
572 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
573 ino_to_db(fs
, fp
->f_bg
, inumber
), 0, fs
->fs_bsize
, buf
, &rsize
);
576 if (rsize
!= fs
->fs_bsize
) {
581 dp
= (struct ext2dinode
*)buf
;
582 fp
->f_di
= dp
[ino_to_bo(fs
, inumber
)];
584 /* clear out old buffers */
585 for (level
= 0; level
< NIADDR
; level
++)
586 fp
->f_blkno
[level
] = -1;
587 fp
->f_buf_blkno
= -1;
596 * Given an offset in a file, find the disk block number that
597 * contains that block.
600 block_map(struct open_file
*f
, daddr_t file_block
, daddr_t
*disk_block_p
)
602 struct file
*fp
= (struct file
*)f
->f_fsdata
;
603 struct ext2fs
*fs
= fp
->f_fs
;
604 daddr_t ind_block_num
;
610 * Index structure of an inode:
612 * di_db[0..NDADDR-1] hold block numbers for blocks
615 * di_ib[0] index block 0 is the single indirect block
616 * holds block numbers for blocks
617 * NDADDR .. NDADDR + NINDIR(fs)-1
619 * di_ib[1] index block 1 is the double indirect block
620 * holds block numbers for INDEX blocks for blocks
621 * NDADDR + NINDIR(fs) ..
622 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
624 * di_ib[2] index block 2 is the triple indirect block
625 * holds block numbers for double-indirect
627 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
628 * NDADDR + NINDIR(fs) + NINDIR(fs)**2
629 * + NINDIR(fs)**3 - 1
632 if (file_block
< NDADDR
) {
634 *disk_block_p
= fp
->f_di
.di_db
[file_block
];
638 file_block
-= NDADDR
;
642 * nindir[1] = NINDIR**2
643 * nindir[2] = NINDIR**3
646 for (level
= 0; level
< NIADDR
; level
++) {
647 if (file_block
< fp
->f_nindir
[level
])
649 file_block
-= fp
->f_nindir
[level
];
651 if (level
== NIADDR
) {
652 /* Block number too high */
656 ind_block_num
= fp
->f_di
.di_ib
[level
];
658 for (; level
>= 0; level
--) {
659 if (ind_block_num
== 0) {
660 *disk_block_p
= 0; /* missing */
664 if (fp
->f_blkno
[level
] != ind_block_num
) {
665 if (fp
->f_blk
[level
] == (char *)0)
667 malloc(fs
->fs_bsize
);
669 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
670 fsb_to_db(fp
->f_fs
, ind_block_num
), 0, fs
->fs_bsize
,
671 fp
->f_blk
[level
], &fp
->f_blksize
[level
]);
674 if (fp
->f_blksize
[level
] != fs
->fs_bsize
)
676 fp
->f_blkno
[level
] = ind_block_num
;
679 ind_p
= (int32_t *)fp
->f_blk
[level
];
682 idx
= file_block
/ fp
->f_nindir
[level
- 1];
683 file_block
%= fp
->f_nindir
[level
- 1];
687 ind_block_num
= ind_p
[idx
];
690 *disk_block_p
= ind_block_num
;
696 * Read a portion of a file into an internal buffer. Return
697 * the location in the buffer and the amount in the buffer.
700 buf_read_file(struct open_file
*f
, char **buf_p
, size_t *size_p
)
702 struct file
*fp
= (struct file
*)f
->f_fsdata
;
703 struct ext2fs
*fs
= fp
->f_fs
;
710 off
= blkoff(fs
, fp
->f_seekp
);
711 file_block
= lblkno(fs
, fp
->f_seekp
);
712 block_size
= dblksize(fs
, &fp
->f_di
, file_block
);
714 if (file_block
!= fp
->f_buf_blkno
) {
715 error
= block_map(f
, file_block
, &disk_block
);
719 if (fp
->f_buf
== (char *)0)
720 fp
->f_buf
= malloc(fs
->fs_bsize
);
722 if (disk_block
== 0) {
723 bzero(fp
->f_buf
, block_size
);
724 fp
->f_buf_size
= block_size
;
727 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
728 fsb_to_db(fs
, disk_block
), 0, block_size
,
729 fp
->f_buf
, &fp
->f_buf_size
);
733 fp
->f_buf_blkno
= file_block
;
737 * Return address of byte in buffer corresponding to
738 * offset, and size of remainder of buffer after that
741 *buf_p
= fp
->f_buf
+ off
;
742 *size_p
= block_size
- off
;
745 * But truncate buffer at end of file.
747 if (*size_p
> fp
->f_di
.di_size
- fp
->f_seekp
)
748 *size_p
= fp
->f_di
.di_size
- fp
->f_seekp
;
754 * Search a directory for a name and return its
758 search_directory(char *name
, struct open_file
*f
, ino_t
*inumber_p
)
760 struct file
*fp
= (struct file
*)f
->f_fsdata
;
761 struct ext2dirent
*dp
, *edp
;
767 length
= strlen(name
);
769 while (fp
->f_seekp
< fp
->f_di
.di_size
) {
770 error
= buf_read_file(f
, &buf
, &buf_size
);
773 dp
= (struct ext2dirent
*)buf
;
774 edp
= (struct ext2dirent
*)(buf
+ buf_size
);
776 if (dp
->d_ino
== (ino_t
)0)
778 namlen
= dp
->d_namlen
;
779 if (namlen
== length
&&
780 strncmp(name
, dp
->d_name
, length
) == 0) {
782 *inumber_p
= dp
->d_ino
;
786 dp
= (struct ext2dirent
*)((char *)dp
+ dp
->d_reclen
);
788 fp
->f_seekp
+= buf_size
;
794 ext2fs_close(struct open_file
*f
)
796 struct file
*fp
= (struct file
*)f
->f_fsdata
;
799 f
->f_fsdata
= (void *)0;
800 if (fp
== (struct file
*)0)
803 for (level
= 0; level
< NIADDR
; level
++) {
804 if (fp
->f_blk
[level
])
805 free(fp
->f_blk
[level
]);
817 ext2fs_read(struct open_file
*f
, void *addr
, size_t size
, size_t *resid
)
819 struct file
*fp
= (struct file
*)f
->f_fsdata
;
820 size_t csize
, buf_size
;
825 if (fp
->f_seekp
>= fp
->f_di
.di_size
)
828 error
= buf_read_file(f
, &buf
, &buf_size
);
833 if (csize
> buf_size
)
836 bcopy(buf
, addr
, csize
);
838 fp
->f_seekp
+= csize
;
839 addr
= (char *)addr
+ csize
;
848 ext2fs_seek(struct open_file
*f
, off_t offset
, int where
)
850 struct file
*fp
= (struct file
*)f
->f_fsdata
;
854 fp
->f_seekp
= offset
;
857 fp
->f_seekp
+= offset
;
860 fp
->f_seekp
= fp
->f_di
.di_size
- offset
;
866 return (fp
->f_seekp
);
870 ext2fs_stat(struct open_file
*f
, struct stat
*sb
)
872 struct file
*fp
= (struct file
*)f
->f_fsdata
;
874 /* only important stuff */
875 sb
->st_mode
= fp
->f_di
.di_mode
;
876 sb
->st_uid
= fp
->f_di
.di_uid
;
877 sb
->st_gid
= fp
->f_di
.di_gid
;
878 sb
->st_size
= fp
->f_di
.di_size
;
883 ext2fs_readdir(struct open_file
*f
, struct dirent
*d
)
885 struct file
*fp
= (struct file
*)f
->f_fsdata
;
886 struct ext2dirent
*ed
;
892 * assume that a directory entry will not be split across blocks
895 if (fp
->f_seekp
>= fp
->f_di
.di_size
)
897 error
= buf_read_file(f
, &buf
, &buf_size
);
900 ed
= (struct ext2dirent
*)buf
;
901 fp
->f_seekp
+= ed
->d_reclen
;
902 if (ed
->d_ino
== (ino_t
)0)
904 d
->d_type
= EXTFTODT(ed
->d_type
);
905 strncpy(d
->d_name
, ed
->d_name
, ed
->d_namlen
);
906 d
->d_name
[ed
->d_namlen
] = '\0';