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 $
30 * The Regents of the University of California. All rights reserved.
32 * This code is derived from software contributed to Berkeley by
33 * The Mach Operating System project at Carnegie-Mellon University.
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * Copyright (c) 1990, 1991 Carnegie Mellon University
61 * All Rights Reserved.
65 * Permission to use, copy, modify and distribute this software and its
66 * documentation is hereby granted, provided that both the copyright
67 * notice and this permission notice appear in all copies of the
68 * software, derivative works or modified versions, and any portions
69 * thereof, and that both notices appear in supporting documentation.
71 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
72 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
73 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
75 * Carnegie Mellon requests users of this software to return to
77 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
78 * School of Computer Science
79 * Carnegie Mellon University
80 * Pittsburgh PA 15213-3890
82 * any improvements or extensions that they make and grant Carnegie the
83 * rights to redistribute these changes.
86 #include <sys/param.h>
91 static int ext2fs_open(const char *path
, struct open_file
*f
);
92 static int ext2fs_close(struct open_file
*f
);
93 static int ext2fs_read(struct open_file
*f
, void *buf
,
94 size_t size
, size_t *resid
);
95 static off_t
ext2fs_seek(struct open_file
*f
, off_t offset
, int where
);
96 static int ext2fs_stat(struct open_file
*f
, struct stat
*sb
);
97 static int ext2fs_readdir(struct open_file
*f
, struct dirent
*d
);
99 static int dtmap
[] = { DT_UNKNOWN
, DT_REG
, DT_DIR
, DT_CHR
,
100 DT_BLK
, DT_FIFO
, DT_SOCK
, DT_LNK
};
101 #define EXTFTODT(x) (x) > NELEM(dtmap) ? DT_UNKNOWN : dtmap[(x)]
103 struct fs_ops ext2fs_fsops
= {
114 #define EXT2_SBSIZE 1024
115 #define EXT2_SBLOCK (1024 / DEV_BSIZE) /* block offset of superblock */
116 #define EXT2_MAGIC 0xef53
117 #define EXT2_ROOTINO 2
119 #define EXT2_REV0 0 /* original revision of ext2 */
120 #define EXT2_R0_ISIZE 128 /* inode size */
121 #define EXT2_R0_FIRSTINO 11 /* first inode */
123 #define EXT2_MINBSHIFT 10 /* mininum block shift */
124 #define EXT2_MINFSHIFT 10 /* mininum frag shift */
126 #define NDADDR 12 /* # of direct blocks */
127 #define NIADDR 3 /* # of indirect blocks */
130 * file system block to disk address
132 #define fsb_to_db(fs, blk) ((blk) << (fs)->fs_fsbtodb)
135 * inode to block group offset
136 * inode to block group
137 * inode to disk address
138 * inode to block offset
140 #define ino_to_bgo(fs, ino) (((ino) - 1) % (fs)->fs_ipg)
141 #define ino_to_bg(fs, ino) (((ino) - 1) / (fs)->fs_ipg)
142 #define ino_to_db(fs, bg, ino) \
143 fsb_to_db(fs, ((bg)[ino_to_bg(fs, ino)].bg_inotbl + \
144 ino_to_bgo(fs, ino) / (fs)->fs_ipb))
145 #define ino_to_bo(fs, ino) (ino_to_bgo(fs, ino) % (fs)->fs_ipb)
148 ((fs)->fs_bsize / sizeof(u_int32_t))
149 #define lblkno(fs, loc) /* loc / bsize */ \
150 ((loc) >> (fs)->fs_bshift)
151 #define smalllblktosize(fs, blk) /* blk * bsize */ \
152 ((blk) << (fs)->fs_bshift)
153 #define blkoff(fs, loc) /* loc % bsize */ \
154 ((loc) & (fs)->fs_bmask)
155 #define fragroundup(fs, size) /* roundup(size, fsize) */ \
156 (((size) + (fs)->fs_fmask) & ~(fs)->fs_fmask)
157 #define dblksize(fs, dip, lbn) \
158 (((lbn) >= NDADDR || (dip)->di_size >= smalllblktosize(fs, (lbn) + 1)) \
160 : (fragroundup(fs, blkoff(fs, (dip)->di_size))))
163 * superblock describing ext2fs
166 u_int32_t fd_inodes
; /* # of inodes */
167 u_int32_t fd_blocks
; /* # of blocks */
168 u_int32_t fd_resblk
; /* # of reserved blocks */
169 u_int32_t fd_freeblk
; /* # of free blocks */
170 u_int32_t fd_freeino
; /* # of free inodes */
171 u_int32_t fd_firstblk
; /* first data block */
172 u_int32_t fd_bsize
; /* block size */
173 u_int32_t fd_fsize
; /* frag size */
174 u_int32_t fd_bpg
; /* blocks per group */
175 u_int32_t fd_fpg
; /* frags per group */
176 u_int32_t fd_ipg
; /* inodes per group */
177 u_int32_t fd_mtime
; /* mount time */
178 u_int32_t fd_wtime
; /* write time */
179 u_int16_t fd_mount
; /* # of mounts */
180 int16_t fd_maxmount
; /* max # of mounts */
181 u_int16_t fd_magic
; /* magic number */
182 u_int16_t fd_state
; /* state */
183 u_int16_t fd_eflag
; /* error flags */
184 u_int16_t fd_mnrrev
; /* minor revision */
185 u_int32_t fd_lastchk
; /* last check */
186 u_int32_t fd_chkintvl
; /* maximum check interval */
187 u_int32_t fd_os
; /* os */
188 u_int32_t fd_revision
; /* revision */
189 u_int16_t fd_uid
; /* uid for reserved blocks */
190 u_int16_t fd_gid
; /* gid for reserved blocks */
192 u_int32_t fd_firstino
; /* first non-reserved inode */
193 u_int16_t fd_isize
; /* inode size */
194 u_int16_t fd_nblkgrp
; /* block group # of superblock */
195 u_int32_t fd_fcompat
; /* compatible features */
196 u_int32_t fd_fincompat
; /* incompatible features */
197 u_int32_t fd_frocompat
; /* read-only compatibilties */
198 u_int8_t fd_uuid
[16]; /* volume uuid */
199 char fd_volname
[16]; /* volume name */
200 char fd_fsmnt
[64]; /* name last mounted on */
201 u_int32_t fd_bitmap
; /* compression bitmap */
203 u_int8_t fd_nblkpa
; /* # of blocks to preallocate */
204 u_int8_t fd_ndblkpa
; /* # of dir blocks to preallocate */
208 int fc_bsize
; /* block size */
209 int fc_bshift
; /* block shift amount */
210 int fc_bmask
; /* block mask */
211 int fc_fsize
; /* frag size */
212 int fc_fshift
; /* frag shift amount */
213 int fc_fmask
; /* frag mask */
214 int fc_isize
; /* inode size */
215 int fc_imask
; /* inode mask */
216 int fc_firstino
; /* first non-reserved inode */
217 int fc_ipb
; /* inodes per block */
218 int fc_fsbtodb
; /* fsb to ds shift */
222 struct ext2fs_disk fs_fd
;
223 char fs_pad
[EXT2_SBSIZE
- sizeof(struct ext2fs_disk
)];
224 struct ext2fs_core fs_fc
;
226 #define fs_magic fs_fd.fd_magic
227 #define fs_revision fs_fd.fd_revision
228 #define fs_blocks fs_fd.fd_blocks
229 #define fs_firstblk fs_fd.fd_firstblk
230 #define fs_bpg fs_fd.fd_bpg
231 #define fs_ipg fs_fd.fd_ipg
233 #define fs_bsize fs_fc.fc_bsize
234 #define fs_bshift fs_fc.fc_bshift
235 #define fs_bmask fs_fc.fc_bmask
236 #define fs_fsize fs_fc.fc_fsize
237 #define fs_fshift fs_fc.fc_fshift
238 #define fs_fmask fs_fc.fc_fmask
239 #define fs_isize fs_fc.fc_isize
240 #define fs_imask fs_fc.fc_imask
241 #define fs_firstino fs_fc.fc_firstino
242 #define fs_ipb fs_fc.fc_ipb
243 #define fs_fsbtodb fs_fc.fc_fsbtodb
247 u_int32_t bg_blkmap
; /* block bitmap */
248 u_int32_t bg_inomap
; /* inode bitmap */
249 u_int32_t bg_inotbl
; /* inode table */
250 u_int16_t bg_nfblk
; /* # of free blocks */
251 u_int16_t bg_nfino
; /* # of free inodes */
252 u_int16_t bg_ndirs
; /* # of dirs */
257 u_int16_t di_mode
; /* mode */
258 u_int16_t di_uid
; /* uid */
259 u_int32_t di_size
; /* byte size */
260 u_int32_t di_atime
; /* access time */
261 u_int32_t di_ctime
; /* creation time */
262 u_int32_t di_mtime
; /* modification time */
263 u_int32_t di_dtime
; /* deletion time */
264 u_int16_t di_gid
; /* gid */
265 u_int16_t di_nlink
; /* link count */
266 u_int32_t di_nblk
; /* block count */
267 u_int32_t di_flags
; /* file flags */
269 u_int32_t di_osdep1
; /* os dependent stuff */
271 u_int32_t di_db
[NDADDR
]; /* direct blocks */
272 u_int32_t di_ib
[NIADDR
]; /* indirect blocks */
273 u_int32_t di_version
; /* version */
274 u_int32_t di_facl
; /* file acl */
275 u_int32_t di_dacl
; /* dir acl */
276 u_int32_t di_faddr
; /* fragment addr */
278 u_int8_t di_frag
; /* fragment number */
279 u_int8_t di_fsize
; /* fragment size */
283 #define di_shortlink di_db
286 #define EXT2_MAXNAMLEN 255
289 u_int32_t d_ino
; /* inode */
290 u_int16_t d_reclen
; /* directory entry length */
291 u_int8_t d_namlen
; /* name length */
292 u_int8_t d_type
; /* file type */
293 char d_name
[EXT2_MAXNAMLEN
];
297 off_t f_seekp
; /* seek pointer */
298 struct ext2fs
*f_fs
; /* pointer to super-block */
299 struct ext2blkgrp
*f_bg
; /* pointer to blkgrp map */
300 struct ext2dinode f_di
; /* copy of on-disk inode */
301 int f_nindir
[NIADDR
]; /* number of blocks mapped by
302 indirect block at level i */
303 char *f_blk
[NIADDR
]; /* buffer for indirect block
305 size_t f_blksize
[NIADDR
]; /* size of buffer */
306 daddr_t f_blkno
[NIADDR
]; /* disk address of block in
308 char *f_buf
; /* buffer for data block */
309 size_t f_buf_size
; /* size of data block */
310 daddr_t f_buf_blkno
; /* block number of data block */
314 static int read_inode(ino_t inumber
, struct open_file
*f
);
315 static int block_map(struct open_file
*f
, daddr_t file_block
,
316 daddr_t
*disk_block_p
);
317 static int buf_read_file(struct open_file
*f
, char **buf_p
,
319 static int search_directory(char *name
, struct open_file
*f
,
326 ext2fs_open(const char *upath
, struct open_file
*f
)
331 ino_t inumber
, parent_inumber
;
332 int i
, len
, groups
, bg_per_blk
, blkgrps
, mult
;
335 char *cp
, *ncp
, *path
= NULL
, *buf
= NULL
;
336 char namebuf
[MAXPATHLEN
+1];
339 /* allocate file system specific data structure */
340 fp
= malloc(sizeof(struct file
));
343 bzero(fp
, sizeof(struct file
));
344 f
->f_fsdata
= (void *)fp
;
346 /* allocate space and read super block */
347 fs
= (struct ext2fs
*)malloc(sizeof(*fs
));
350 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
351 EXT2_SBLOCK
, EXT2_SBSIZE
, (char *)fs
, &buf_size
);
355 if (buf_size
!= EXT2_SBSIZE
|| fs
->fs_magic
!= EXT2_MAGIC
) {
361 * compute in-core values for the superblock
363 fs
->fs_bshift
= EXT2_MINBSHIFT
+ fs
->fs_fd
.fd_bsize
;
364 fs
->fs_bsize
= 1 << fs
->fs_bshift
;
365 fs
->fs_bmask
= fs
->fs_bsize
- 1;
367 fs
->fs_fshift
= EXT2_MINFSHIFT
+ fs
->fs_fd
.fd_fsize
;
368 fs
->fs_fsize
= 1 << fs
->fs_fshift
;
369 fs
->fs_fmask
= fs
->fs_fsize
- 1;
371 if (fs
->fs_revision
== EXT2_REV0
) {
372 fs
->fs_isize
= EXT2_R0_ISIZE
;
373 fs
->fs_firstino
= EXT2_R0_FIRSTINO
;
375 fs
->fs_isize
= fs
->fs_fd
.fd_isize
;
376 fs
->fs_firstino
= fs
->fs_fd
.fd_firstino
;
378 fs
->fs_imask
= fs
->fs_isize
- 1;
379 fs
->fs_ipb
= fs
->fs_bsize
/ fs
->fs_isize
;
380 fs
->fs_fsbtodb
= (fs
->fs_bsize
/ DEV_BSIZE
) - 1;
383 * we have to load in the "group descriptors" here
385 groups
= howmany(fs
->fs_blocks
- fs
->fs_firstblk
, fs
->fs_bpg
);
386 bg_per_blk
= fs
->fs_bsize
/ sizeof(struct ext2blkgrp
);
387 blkgrps
= howmany(groups
, bg_per_blk
);
388 len
= blkgrps
* fs
->fs_bsize
;
390 fp
->f_bg
= malloc(len
);
392 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
393 EXT2_SBLOCK
+ EXT2_SBSIZE
/ DEV_BSIZE
, len
,
394 (char *)fp
->f_bg
, &buf_size
);
400 * validation of values? (blocksize, descriptors, etc?)
404 * Calculate indirect block levels.
407 for (i
= 0; i
< NIADDR
; i
++) {
409 fp
->f_nindir
[i
] = mult
;
412 inumber
= EXT2_ROOTINO
;
413 if ((error
= read_inode(inumber
, f
)) != 0)
416 path
= strdup(upath
);
424 * Remove extra separators
432 * Check that current node is a directory.
434 if (! S_ISDIR(fp
->f_di
.di_mode
)) {
440 * Get next component of path name.
445 while ((c
= *cp
) != '\0' && c
!= '/') {
446 if (++len
> EXT2_MAXNAMLEN
) {
455 * Look up component in current directory.
456 * Save directory inumber in case we find a
459 parent_inumber
= inumber
;
460 error
= search_directory(ncp
, f
, &inumber
);
466 * Open next component.
468 if ((error
= read_inode(inumber
, f
)) != 0)
472 * Check for symbolic link.
474 if (S_ISLNK(fp
->f_di
.di_mode
)) {
475 int link_len
= fp
->f_di
.di_size
;
479 if (link_len
+ len
> MAXPATHLEN
||
480 ++nlinks
> MAXSYMLINKS
) {
485 bcopy(cp
, &namebuf
[link_len
], len
+ 1);
486 if (fp
->f_di
.di_nblk
== 0) {
487 bcopy(fp
->f_di
.di_shortlink
,
491 * Read file for symbolic link
493 struct ext2fs
*fs
= fp
->f_fs
;
498 buf
= malloc(fs
->fs_bsize
);
499 error
= block_map(f
, (daddr_t
)0, &disk_block
);
504 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
,
505 F_READ
, fsb_to_db(fs
, disk_block
),
506 fs
->fs_bsize
, buf
, &buf_size
);
510 bcopy((char *)buf
, namebuf
, link_len
);
514 * If relative pathname, restart at parent directory.
515 * If absolute pathname, restart at root.
519 inumber
= parent_inumber
;
521 inumber
= (ino_t
)EXT2_ROOTINO
;
523 if ((error
= read_inode(inumber
, f
)) != 0)
529 * Found terminal component.
548 * Read a new inode into a file structure.
551 read_inode(ino_t inumber
, struct open_file
*f
)
553 struct file
*fp
= (struct file
*)f
->f_fsdata
;
554 struct ext2fs
*fs
= fp
->f_fs
;
555 struct ext2dinode
*dp
;
558 int level
, error
= 0;
561 * Read inode and save it.
563 buf
= malloc(fs
->fs_bsize
);
565 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
566 ino_to_db(fs
, fp
->f_bg
, inumber
), fs
->fs_bsize
, buf
, &rsize
);
569 if (rsize
!= fs
->fs_bsize
) {
574 dp
= (struct ext2dinode
*)buf
;
575 fp
->f_di
= dp
[ino_to_bo(fs
, inumber
)];
577 /* clear out old buffers */
578 for (level
= 0; level
< NIADDR
; level
++)
579 fp
->f_blkno
[level
] = -1;
580 fp
->f_buf_blkno
= -1;
588 * Given an offset in a file, find the disk block number that
589 * contains that block.
592 block_map(struct open_file
*f
, daddr_t file_block
, daddr_t
*disk_block_p
)
594 struct file
*fp
= (struct file
*)f
->f_fsdata
;
595 struct ext2fs
*fs
= fp
->f_fs
;
596 daddr_t ind_block_num
;
602 * Index structure of an inode:
604 * di_db[0..NDADDR-1] hold block numbers for blocks
607 * di_ib[0] index block 0 is the single indirect block
608 * holds block numbers for blocks
609 * NDADDR .. NDADDR + NINDIR(fs)-1
611 * di_ib[1] index block 1 is the double indirect block
612 * holds block numbers for INDEX blocks for blocks
613 * NDADDR + NINDIR(fs) ..
614 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
616 * di_ib[2] index block 2 is the triple indirect block
617 * holds block numbers for double-indirect
619 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
620 * NDADDR + NINDIR(fs) + NINDIR(fs)**2
621 * + NINDIR(fs)**3 - 1
624 if (file_block
< NDADDR
) {
626 *disk_block_p
= fp
->f_di
.di_db
[file_block
];
630 file_block
-= NDADDR
;
634 * nindir[1] = NINDIR**2
635 * nindir[2] = NINDIR**3
638 for (level
= 0; level
< NIADDR
; level
++) {
639 if (file_block
< fp
->f_nindir
[level
])
641 file_block
-= fp
->f_nindir
[level
];
643 if (level
== NIADDR
) {
644 /* Block number too high */
648 ind_block_num
= fp
->f_di
.di_ib
[level
];
650 for (; level
>= 0; level
--) {
651 if (ind_block_num
== 0) {
652 *disk_block_p
= 0; /* missing */
656 if (fp
->f_blkno
[level
] != ind_block_num
) {
657 if (fp
->f_blk
[level
] == NULL
)
659 malloc(fs
->fs_bsize
);
661 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
662 fsb_to_db(fp
->f_fs
, ind_block_num
), fs
->fs_bsize
,
663 fp
->f_blk
[level
], &fp
->f_blksize
[level
]);
666 if (fp
->f_blksize
[level
] != fs
->fs_bsize
)
668 fp
->f_blkno
[level
] = ind_block_num
;
671 ind_p
= (daddr_t
*)fp
->f_blk
[level
];
674 idx
= file_block
/ fp
->f_nindir
[level
- 1];
675 file_block
%= fp
->f_nindir
[level
- 1];
679 ind_block_num
= ind_p
[idx
];
682 *disk_block_p
= ind_block_num
;
688 * Read a portion of a file into an internal buffer. Return
689 * the location in the buffer and the amount in the buffer.
692 buf_read_file(struct open_file
*f
, char **buf_p
, size_t *size_p
)
694 struct file
*fp
= (struct file
*)f
->f_fsdata
;
695 struct ext2fs
*fs
= fp
->f_fs
;
702 off
= blkoff(fs
, fp
->f_seekp
);
703 file_block
= lblkno(fs
, fp
->f_seekp
);
704 block_size
= dblksize(fs
, &fp
->f_di
, file_block
);
706 if (file_block
!= fp
->f_buf_blkno
) {
707 error
= block_map(f
, file_block
, &disk_block
);
711 if (fp
->f_buf
== NULL
)
712 fp
->f_buf
= malloc(fs
->fs_bsize
);
714 if (disk_block
== 0) {
715 bzero(fp
->f_buf
, block_size
);
716 fp
->f_buf_size
= block_size
;
719 error
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
,
720 fsb_to_db(fs
, disk_block
), block_size
,
721 fp
->f_buf
, &fp
->f_buf_size
);
725 fp
->f_buf_blkno
= file_block
;
729 * Return address of byte in buffer corresponding to
730 * offset, and size of remainder of buffer after that
733 *buf_p
= fp
->f_buf
+ off
;
734 *size_p
= block_size
- off
;
737 * But truncate buffer at end of file.
739 if (*size_p
> fp
->f_di
.di_size
- fp
->f_seekp
)
740 *size_p
= fp
->f_di
.di_size
- fp
->f_seekp
;
746 * Search a directory for a name and return its
750 search_directory(char *name
, struct open_file
*f
, ino_t
*inumber_p
)
752 struct file
*fp
= (struct file
*)f
->f_fsdata
;
753 struct ext2dirent
*dp
, *edp
;
759 length
= strlen(name
);
761 while (fp
->f_seekp
< fp
->f_di
.di_size
) {
762 error
= buf_read_file(f
, &buf
, &buf_size
);
765 dp
= (struct ext2dirent
*)buf
;
766 edp
= (struct ext2dirent
*)(buf
+ buf_size
);
768 if (dp
->d_ino
== (ino_t
)0)
770 namlen
= dp
->d_namlen
;
771 if (namlen
== length
&&
772 strncmp(name
, dp
->d_name
, length
) == 0) {
774 *inumber_p
= dp
->d_ino
;
778 dp
= (struct ext2dirent
*)((char *)dp
+ dp
->d_reclen
);
780 fp
->f_seekp
+= buf_size
;
786 ext2fs_close(struct open_file
*f
)
788 struct file
*fp
= (struct file
*)f
->f_fsdata
;
795 for (level
= 0; level
< NIADDR
; level
++) {
796 if (fp
->f_blk
[level
])
797 free(fp
->f_blk
[level
]);
809 ext2fs_read(struct open_file
*f
, void *addr
, size_t size
, size_t *resid
)
811 struct file
*fp
= (struct file
*)f
->f_fsdata
;
812 size_t csize
, buf_size
;
817 if (fp
->f_seekp
>= fp
->f_di
.di_size
)
820 error
= buf_read_file(f
, &buf
, &buf_size
);
825 if (csize
> buf_size
)
828 bcopy(buf
, addr
, csize
);
830 fp
->f_seekp
+= csize
;
840 ext2fs_seek(struct open_file
*f
, off_t offset
, int where
)
842 struct file
*fp
= (struct file
*)f
->f_fsdata
;
846 fp
->f_seekp
= offset
;
849 fp
->f_seekp
+= offset
;
852 fp
->f_seekp
= fp
->f_di
.di_size
- offset
;
857 return (fp
->f_seekp
);
861 ext2fs_stat(struct open_file
*f
, struct stat
*sb
)
863 struct file
*fp
= (struct file
*)f
->f_fsdata
;
865 /* only important stuff */
866 sb
->st_mode
= fp
->f_di
.di_mode
;
867 sb
->st_uid
= fp
->f_di
.di_uid
;
868 sb
->st_gid
= fp
->f_di
.di_gid
;
869 sb
->st_size
= fp
->f_di
.di_size
;
874 ext2fs_readdir(struct open_file
*f
, struct dirent
*d
)
876 struct file
*fp
= (struct file
*)f
->f_fsdata
;
877 struct ext2dirent
*ed
;
883 * assume that a directory entry will not be split across blocks
886 if (fp
->f_seekp
>= fp
->f_di
.di_size
)
888 error
= buf_read_file(f
, &buf
, &buf_size
);
891 ed
= (struct ext2dirent
*)buf
;
892 fp
->f_seekp
+= ed
->d_reclen
;
893 if (ed
->d_ino
== (ino_t
)0)
895 d
->d_type
= EXTFTODT(ed
->d_type
);
896 strncpy(d
->d_name
, ed
->d_name
, ed
->d_namlen
);
897 d
->d_name
[ed
->d_namlen
] = '\0';