]>
git.saurik.com Git - apple/bootx.git/blob - bootx.tproj/fs.subproj/ext2fs.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * ext2.c - File System Module for Ext2.
25 * Copyright (c) 1999-2000 Apple Computer, Inc.
33 #include <bsd/sys/types.h>
36 #include "ext2fs_dinode.h"
37 #include "ext2fs_dir.h"
39 typedef struct ext2fs_dinode Inode
, *InodePtr
;
41 // Private function prototypes
43 static long HowMany(long bufferSize
, long unitSize
);
44 static char *ReadBlock(long blockNum
, long blockOffset
, long length
,
45 char *buffer
, long cache
);
46 static long ReadInode(long inodeNum
, InodePtr inode
);
47 static long ResolvePathToInode(char *filePath
, long *flags
,
48 InodePtr fileInode
, InodePtr dirInode
);
49 static long ReadDirEntry(InodePtr dirInode
, long *fileInodeNum
,
50 long *dirIndex
, char **name
, long *flags
, long *time
);
51 static long FindFileInDir(char *fileName
, long *flags
,
52 InodePtr fileInode
, InodePtr dirInode
);
53 static char *ReadFileBlock(InodePtr fileInode
, long blockNum
, long blockOffset
,
54 long length
, char *buffer
, long cache
);
55 static long ReadFile(InodePtr fileInode
, long *length
);
58 static CICell gCurrentIH
;
59 static char gFSBuf
[SBSIZE
* 2];
60 static struct m_ext2fs
*gFS
;
61 static long gBlockSize
;
62 static char *gTempBlock
;
63 static char gTempName
[EXT2FS_MAXNAMLEN
+ 1];
64 static char gTempName2
[EXT2FS_MAXNAMLEN
+ 1];
65 static Inode gRootInode
;
66 static Inode gFileInode
;
70 long Ext2InitPartition(CICell ih
)
74 if (ih
== gCurrentIH
) return 0;
76 printf("Ext2InitPartition: %x\n", ih
);
80 // Read for the Super Block.
82 Read(ih
, (long)gFSBuf
, SBSIZE
);
84 gFS
= (struct m_ext2fs
*)gFSBuf
;
85 e2fs_sb_bswap(&gFS
->e2fs
, &gFS
->e2fs
);
86 if (gFS
->e2fs
.e2fs_magic
!= E2FS_MAGIC
) return -1;
88 // Calculate the block size and set up the block cache.
89 gBlockSize
= 1024 << gFS
->e2fs
.e2fs_log_bsize
;
90 if (gTempBlock
!= 0) free(gTempBlock
);
91 gTempBlock
= malloc(gBlockSize
);
92 CacheInit(ih
, gBlockSize
);
96 gdPerBlock
= gBlockSize
/ sizeof(struct ext2_gd
);
98 // Fill in the in memory super block fields.
99 gFS
->e2fs_bsize
= 1024 << gFS
->e2fs
.e2fs_log_bsize
;
100 gFS
->e2fs_bshift
= LOG_MINBSIZE
+ gFS
->e2fs
.e2fs_log_bsize
;
101 gFS
->e2fs_qbmask
= gFS
->e2fs_bsize
- 1;
102 gFS
->e2fs_bmask
= ~gFS
->e2fs_qbmask
;
103 gFS
->e2fs_fsbtodb
= gFS
->e2fs
.e2fs_log_bsize
+ 1;
104 gFS
->e2fs_ncg
= HowMany(gFS
->e2fs
.e2fs_bcount
- gFS
->e2fs
.e2fs_first_dblock
,
106 gFS
->e2fs_ngdb
= HowMany(gFS
->e2fs_ncg
, gdPerBlock
);
107 gFS
->e2fs_ipb
= gFS
->e2fs_bsize
/ EXT2_DINODE_SIZE
;
108 gFS
->e2fs_itpg
= gFS
->e2fs
.e2fs_ipg
/ gFS
->e2fs_ipb
;
109 gFS
->e2fs_gd
= malloc(gFS
->e2fs_ngdb
* gFS
->e2fs_bsize
);
111 // Read the summary information from disk.
112 for (cnt
= 0; cnt
< gFS
->e2fs_ngdb
; cnt
++) {
113 ReadBlock(((gBlockSize
> 1024) ? 0 : 1) + cnt
+ 1, 0, gBlockSize
,
114 (char *)&gFS
->e2fs_gd
[gdPerBlock
* cnt
], 0);
115 e2fs_cg_bswap(&gFS
->e2fs_gd
[gdPerBlock
* cnt
],
116 &gFS
->e2fs_gd
[gdPerBlock
* cnt
], gBlockSize
);
119 // Read the Root Inode
120 ReadInode(EXT2_ROOTINO
, &gRootInode
);
126 long Ext2LoadFile(CICell ih
, char *filePath
)
128 long ret
, length
, flags
;
130 if (Ext2InitPartition(ih
) == -1) return -1;
132 printf("Loading Ext2 file: [%s] from %x.\n", filePath
, ih
);
134 // Skip one or two leading '\'.
135 if (*filePath
== '\\') filePath
++;
136 if (*filePath
== '\\') filePath
++;
137 ret
= ResolvePathToInode(filePath
, &flags
, &gFileInode
, &gRootInode
);
138 if ((ret
== -1) || (flags
!= kFlatFileType
)) return -1;
140 ret
= ReadFile(&gFileInode
, &length
);
141 if (ret
!= 0) return -1;
147 long Ext2GetDirEntry(CICell ih
, char *dirPath
, long *dirIndex
,
148 char **name
, long *flags
, long *time
)
150 long ret
, fileInodeNum
, dirFlags
;
152 if (Ext2InitPartition(ih
) == -1) return -1;
154 // Skip a leading '\' if present
155 if (dirPath
[0] == '\\') dirPath
++;
156 ret
= ResolvePathToInode(dirPath
, &dirFlags
, &gFileInode
, &gRootInode
);
157 if ((ret
== -1) || (dirFlags
!= kDirectoryFileType
)) return -1;
160 ret
= ReadDirEntry(&gFileInode
, &fileInodeNum
, dirIndex
, name
, flags
,time
);
161 } while ((ret
!= -1) && (*flags
== kUnknownFileType
));
168 static long HowMany(long bufferSize
, long unitSize
)
170 return (bufferSize
+ unitSize
- 1) / unitSize
;
174 static char *ReadBlock(long blockNum
, long blockOffset
, long length
,
175 char *buffer
, long cache
)
179 offset
= 1ULL * blockNum
* gBlockSize
;
181 if (cache
&& ((blockOffset
+ length
) <= gBlockSize
)) {
182 CacheRead(gCurrentIH
, gTempBlock
, offset
, gBlockSize
, 1);
183 if (buffer
!= 0) bcopy(gTempBlock
+ blockOffset
, buffer
, length
);
184 else buffer
= gTempBlock
+ blockOffset
;
186 offset
+= blockOffset
;
187 CacheRead(gCurrentIH
, buffer
, offset
, length
, 0);
194 static long ReadInode(long inodeNum
, InodePtr inode
)
196 long blockNum
= ino_to_fsba(gFS
, inodeNum
);
197 long blockOffset
= ino_to_fsbo(gFS
, inodeNum
) * sizeof(Inode
);
199 ReadBlock(blockNum
, blockOffset
, sizeof(Inode
), (char *)inode
, 1);
200 e2fs_i_bswap(inode
, inode
);
206 static long ResolvePathToInode(char *filePath
, long *flags
,
207 InodePtr fileInode
, InodePtr dirInode
)
212 // if filePath is empty the we want this directory.
213 if (*filePath
== '\0') {
214 bcopy((char *)dirInode
, (char *)fileInode
, sizeof(Inode
));
218 // Copy the file name to gTempName
220 while ((filePath
[cnt
] != '\\') && (filePath
[cnt
] != '\0')) cnt
++;
221 strncpy(gTempName
, filePath
, cnt
);
223 // Move restPath to the right place.
224 if (filePath
[cnt
] != '\0') cnt
++;
225 restPath
= filePath
+ cnt
;
227 // gTempName is a name in the current Dir.
228 // restPath is the rest of the path if any.
230 ret
= FindFileInDir(gTempName
, flags
, fileInode
, dirInode
);
231 if (ret
== -1) return -1;
233 if ((*restPath
!= '\0') && (*flags
== kDirectoryFileType
))
234 ret
= ResolvePathToInode(restPath
, flags
, fileInode
, fileInode
);
240 static long ReadDirEntry(InodePtr dirInode
, long *fileInodeNum
,
241 long *dirIndex
, char **name
, long *flags
, long *time
)
243 struct ext2fs_direct
*dir
;
245 long offset
, index
= *dirIndex
;
246 long blockNum
, inodeNum
;
249 offset
= index
% gBlockSize
;
250 blockNum
= index
/ gBlockSize
;
252 buffer
= ReadFileBlock(dirInode
, blockNum
, 0, gBlockSize
, 0, 1);
253 if (buffer
== 0) return -1;
255 dir
= (struct ext2fs_direct
*)(buffer
+ offset
);
256 inodeNum
= bswap32(dir
->e2d_ino
);
257 if (inodeNum
== 0) return -1;
259 *dirIndex
+= bswap16(dir
->e2d_reclen
);
260 *fileInodeNum
= inodeNum
;
261 *name
= strncpy(gTempName2
, dir
->e2d_name
, dir
->e2d_namlen
);
263 ReadInode(inodeNum
, &tmpInode
);
265 *time
= tmpInode
.e2di_mtime
;
267 switch (tmpInode
.e2di_mode
& EXT2_IFMT
) {
268 case EXT2_IFREG
: *flags
= kFlatFileType
; break;
269 case EXT2_IFDIR
: *flags
= kDirectoryFileType
; break;
270 case EXT2_IFLNK
: *flags
= kLinkFileType
; break;
271 default : *flags
= kUnknownFileType
; break;
278 static long FindFileInDir(char *fileName
, long *flags
,
279 InodePtr fileInode
, InodePtr dirInode
)
281 long ret
, inodeNum
, time
, index
= 0;
285 ret
= ReadDirEntry(dirInode
, &inodeNum
, &index
, &name
, flags
, &time
);
286 if (ret
== -1) return -1;
288 if (*flags
== kUnknownFileType
) continue;
290 if (strcmp(fileName
, name
) == 0) break;
293 ReadInode(inodeNum
, fileInode
);
299 static char *ReadFileBlock(InodePtr fileInode
, long blockNum
, long blockOffset
,
300 long length
, char *buffer
, long cache
)
302 long diskBlockNum
, indBlockNum
, indBlockOff
, refsPerBlock
;
305 if (blockNum
>= fileInode
->e2di_nblock
) return 0;
307 refsPerBlock
= gBlockSize
/ sizeof(u_int32_t
);
309 // Get Direct Block Number.
310 if (blockNum
< NDADDR
) {
311 diskBlockNum
= bswap32(fileInode
->e2di_blocks
[blockNum
]);
315 // Get Single Indirect Block Number.
316 if (blockNum
< refsPerBlock
) {
317 indBlockNum
= bswap32(fileInode
->e2di_blocks
[NDADDR
]);
319 blockNum
-= refsPerBlock
;
321 // Get Double Indirect Block Number.
322 if (blockNum
< (refsPerBlock
* refsPerBlock
)) {
323 indBlockNum
= fileInode
->e2di_blocks
[NDADDR
+ 1];
325 blockNum
-= refsPerBlock
* refsPerBlock
;
327 // Get Triple Indirect Block Number.
328 indBlockNum
= fileInode
->e2di_blocks
[NDADDR
+ 2];
330 indBlock
= ReadBlock(indBlockNum
, 0, gBlockSize
, 0, 1);
331 indBlockOff
= blockNum
/ (refsPerBlock
* refsPerBlock
);
332 blockNum
%= (refsPerBlock
* refsPerBlock
);
333 indBlockNum
= bswap32(((u_int32_t
*)indBlock
)[indBlockOff
]);
336 indBlock
= ReadBlock(indBlockNum
, 0, gBlockSize
, 0, 1);
337 indBlockOff
= blockNum
/ refsPerBlock
;
338 blockNum
%= refsPerBlock
;
339 indBlockNum
= bswap32(((u_int32_t
*)indBlock
)[indBlockOff
]);
342 indBlock
= ReadBlock(indBlockNum
, 0, gBlockSize
, 0, 1);
343 diskBlockNum
= bswap32(((u_int32_t
*)indBlock
)[blockNum
]);
346 buffer
= ReadBlock(diskBlockNum
, blockOffset
, length
, buffer
, cache
);
351 static long ReadFile(InodePtr fileInode
, long *length
)
353 long bytesLeft
, curSize
, curBlock
= 0;
354 char *buffer
, *curAddr
= (char *)kLoadAddr
;
356 bytesLeft
= *length
= fileInode
->e2di_size
;
358 if (*length
> kLoadSize
) {
359 printf("File is too large.\n");
364 if (bytesLeft
> gBlockSize
) curSize
= gBlockSize
;
365 else curSize
= bytesLeft
;
367 buffer
= ReadFileBlock(fileInode
, curBlock
, 0, curSize
, curAddr
, 0);
368 if (buffer
== 0) break;
372 bytesLeft
-= curSize
;