]>
git.saurik.com Git - apple/bootx.git/blob - bootx.tproj/fs.subproj/ufs.c
76d1741ed7b51f34c663bb43794a3560c135e392
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 * ufs.c - File System Module for UFS.
25 * Copyright (c) 1998-2000 Apple Computer, Inc.
31 #include "ufs_byteorder.h"
33 typedef struct dinode Inode
, *InodePtr
;
35 // Private function prototypes
37 static char *ReadBlock(long fragNum
, long fragOffset
, long length
,
38 char *buffer
, long cache
);
39 static long ReadInode(long inodeNum
, InodePtr inode
);
40 static long ResolvePathToInode(char *filePath
, long *flags
,
41 InodePtr fileInode
, InodePtr dirInode
);
42 static long ReadDirEntry(InodePtr dirInode
, long *fileInodeNum
,
43 long *dirIndex
, char **name
, long *flags
, long *time
);
44 static long FindFileInDir(char *fileName
, long *flags
,
45 InodePtr fileInode
, InodePtr dirInode
);
46 static char *ReadFileBlock(InodePtr fileInode
, long fragNum
, long blockOffset
,
47 long length
, char *buffer
, long cache
);
48 static long ReadFile(InodePtr fileInode
, long *length
);
51 #define kDevBlockSize (0x200) // Size of each disk block.
52 #define kDiskLableBlock (15) // Block the DL is in.
54 static CICell gCurrentIH
;
55 static long long gPartitionBase
;
56 static char gDLBuf
[8192];
57 static char gFSBuf
[SBSIZE
];
58 static struct fs
*gFS
;
59 static long gBlockSize
;
60 static long gFragSize
;
61 static long gFragsPerBlock
;
62 static char *gTempBlock
;
63 static char gTempName
[MAXNAMLEN
+ 1];
64 static char gTempName2
[MAXNAMLEN
+ 1];
65 static Inode gRootInode
;
66 static Inode gFileInode
;
70 long UFSInitPartition(CICell ih
)
75 if (ih
== gCurrentIH
) return 0;
77 printf("UFSInitPartition: %x\n", ih
);
81 // Assume there is no Disk Label
84 // Look for the Super Block
85 Seek(ih
, gPartitionBase
+ SBOFF
);
86 Read(ih
, (long)gFSBuf
, SBSIZE
);
88 gFS
= (struct fs
*)gFSBuf
;
89 if (gFS
->fs_magic
!= FS_MAGIC
) {
90 // Did not find it... Look for the Disk Label.
91 // Look for the Disk Label
92 Seek(ih
, 1ULL * kDevBlockSize
* kDiskLableBlock
);
93 Read(ih
, (long)gDLBuf
, 8192);
95 dl
= (disk_label_t
*)gDLBuf
;
96 byte_swap_disklabel_in(dl
);
98 if (dl
->dl_version
!= DL_VERSION
) {
102 part
= &dl
->dl_part
[0];
103 gPartitionBase
= (1ULL * (dl
->dl_front
+ part
->p_base
) * dl
->dl_secsize
) -
104 (1ULL * (dl
->dl_label_blkno
- kDiskLableBlock
) * kDevBlockSize
);
106 // Re-read the Super Block.
107 Seek(ih
, gPartitionBase
+ SBOFF
);
108 Read(ih
, (long)gFSBuf
, SBSIZE
);
110 gFS
= (struct fs
*)gFSBuf
;
111 if (gFS
->fs_magic
!= FS_MAGIC
) {
116 // Calculate the block size and set up the block cache.
117 gBlockSize
= gFS
->fs_bsize
;
118 gFragSize
= gFS
->fs_fsize
;
119 gFragsPerBlock
= gBlockSize
/ gFragSize
;
120 if (gTempBlock
!= 0) free(gTempBlock
);
121 gTempBlock
= malloc(gBlockSize
);
122 CacheInit(ih
, gBlockSize
);
126 // Read the Root Inode
127 ReadInode(ROOTINO
, &gRootInode
);
133 long UFSLoadFile(CICell ih
, char *filePath
)
135 long ret
, length
, flags
;
137 if (UFSInitPartition(ih
) == -1) return -1;
139 printf("Loading UFS file: [%s] from %x.\n", filePath
, ih
);
141 // Skip one or two leading '\'.
142 if (*filePath
== '\\') filePath
++;
143 if (*filePath
== '\\') filePath
++;
144 ret
= ResolvePathToInode(filePath
, &flags
, &gFileInode
, &gRootInode
);
145 if ((ret
== -1) || (flags
!= kFlatFileType
)) return -1;
147 ret
= ReadFile(&gFileInode
, &length
);
148 if (ret
== -1) return -1;
154 long UFSGetDirEntry(CICell ih
, char *dirPath
, long *dirIndex
,
155 char **name
, long *flags
, long *time
)
157 long ret
, fileInodeNum
, dirFlags
;
159 if (UFSInitPartition(ih
) == -1) return -1;
161 // Skip a leading '\' if present
162 if (*dirPath
== '\\') dirPath
++;
163 if (*dirPath
== '\\') dirPath
++;
164 ret
= ResolvePathToInode(dirPath
, &dirFlags
, &gFileInode
, &gRootInode
);
165 if ((ret
== -1) || (dirFlags
!= kDirectoryFileType
)) return -1;
168 ret
= ReadDirEntry(&gFileInode
, &fileInodeNum
, dirIndex
,
170 } while ((ret
!= -1) && (*flags
== kUnknownFileType
));
177 static char *ReadBlock(long fragNum
, long blockOffset
, long length
,
178 char *buffer
, long cache
)
183 blockNum
= fragNum
/ gFragsPerBlock
;
184 fragNum
-= blockNum
* gFragsPerBlock
;
186 blockOffset
+= fragNum
* gFragSize
;
188 offset
= gPartitionBase
+ 1ULL * blockNum
* gBlockSize
;
190 if (cache
&& ((blockOffset
+ length
) <= gBlockSize
)) {
191 CacheRead(gCurrentIH
, gTempBlock
, offset
, gBlockSize
, 1);
192 if (buffer
!= 0) bcopy(gTempBlock
+ blockOffset
, buffer
, length
);
193 else buffer
= gTempBlock
+ blockOffset
;
195 offset
+= blockOffset
;
196 CacheRead(gCurrentIH
, buffer
, offset
, length
, 0);
203 static long ReadInode(long inodeNum
, InodePtr inode
)
205 long fragNum
= ino_to_fsba(gFS
, inodeNum
);
206 long blockOffset
= ino_to_fsbo(gFS
, inodeNum
) * sizeof(Inode
);
208 ReadBlock(fragNum
, blockOffset
, sizeof(Inode
), (char *)inode
, 1);
214 static long ResolvePathToInode(char *filePath
, long *flags
,
215 InodePtr fileInode
, InodePtr dirInode
)
220 // if filePath is empty the we want this directory.
221 if (*filePath
== '\0') {
222 bcopy((char *)dirInode
, (char *)fileInode
, sizeof(Inode
));
226 // Copy the file name to gTempName
228 while ((filePath
[cnt
] != '\\') && (filePath
[cnt
] != '\0')) cnt
++;
229 strncpy(gTempName
, filePath
, cnt
);
231 // Move restPath to the right place.
232 if (filePath
[cnt
] != '\0') cnt
++;
233 restPath
= filePath
+ cnt
;
235 // gTempName is a name in the current Dir.
236 // restPath is the rest of the path if any.
238 ret
= FindFileInDir(gTempName
, flags
, fileInode
, dirInode
);
239 if (ret
== -1) return -1;
241 if ((*restPath
!= '\0') && (*flags
== kDirectoryFileType
))
242 ret
= ResolvePathToInode(restPath
, flags
, fileInode
, fileInode
);
248 static long ReadDirEntry(InodePtr dirInode
, long *fileInodeNum
,
249 long *dirIndex
, char **name
, long *flags
, long *time
)
253 long index
= *dirIndex
;
254 long dirBlockNum
, dirBlockOffset
;
257 dirBlockOffset
= index
% DIRBLKSIZ
;
258 dirBlockNum
= index
/ DIRBLKSIZ
;
260 buffer
= ReadFileBlock(dirInode
, dirBlockNum
, 0, DIRBLKSIZ
, 0, 1);
261 if (buffer
== 0) return -1;
263 dir
= (struct direct
*)(buffer
+ dirBlockOffset
);
264 if (dir
->d_ino
== 0) return -1;
266 *dirIndex
+= dir
->d_reclen
;
267 *fileInodeNum
= dir
->d_ino
;
268 *name
= strncpy(gTempName2
, dir
->d_name
, dir
->d_namlen
);
270 ReadInode(dir
->d_ino
, &tmpInode
);
272 *time
= tmpInode
.di_mtime
;
274 switch (tmpInode
.di_mode
& IFMT
) {
275 case IFREG
: *flags
= kFlatFileType
; break;
276 case IFDIR
: *flags
= kDirectoryFileType
; break;
277 case IFLNK
: *flags
= kLinkFileType
; break;
278 default : *flags
= kUnknownFileType
; break;
285 static long FindFileInDir(char *fileName
, long *flags
,
286 InodePtr fileInode
, InodePtr dirInode
)
288 long ret
, inodeNum
, time
, index
= 0;
292 ret
= ReadDirEntry(dirInode
, &inodeNum
, &index
, &name
, flags
, &time
);
293 if (ret
== -1) return -1;
295 if (*flags
== kUnknownFileType
) continue;
297 if (strcmp(fileName
, name
) == 0) break;
300 ReadInode(inodeNum
, fileInode
);
306 static char *ReadFileBlock(InodePtr fileInode
, long fragNum
, long blockOffset
,
307 long length
, char *buffer
, long cache
)
309 long fragCount
, blockNum
;
310 long diskFragNum
, indFragNum
, indBlockOff
, refsPerBlock
;
313 fragCount
= (fileInode
->di_size
+ gFragSize
- 1) / gFragSize
;
314 if (fragNum
>= fragCount
) return 0;
316 refsPerBlock
= gBlockSize
/ sizeof(ufs_daddr_t
);
318 blockNum
= fragNum
/ gFragsPerBlock
;
319 fragNum
-= blockNum
* gFragsPerBlock
;
321 // Get Direct Block Number.
322 if (blockNum
< NDADDR
) {
323 diskFragNum
= fileInode
->di_db
[blockNum
];
327 // Get Single Indirect Fragment Number.
328 if (blockNum
< refsPerBlock
) {
329 indFragNum
= fileInode
->di_ib
[0];
331 blockNum
-= refsPerBlock
;
333 // Get Double Indirect Fragment Number.
334 if (blockNum
< (refsPerBlock
* refsPerBlock
)) {
335 indFragNum
= fileInode
->di_ib
[1];
337 blockNum
-= refsPerBlock
* refsPerBlock
;
339 // Get Triple Indirect Fragment Number.
340 indFragNum
= fileInode
->di_ib
[2];
342 indBlock
= ReadBlock(indFragNum
, 0, gBlockSize
, 0, 1);
343 indBlockOff
= blockNum
/ (refsPerBlock
* refsPerBlock
);
344 blockNum
%= (refsPerBlock
* refsPerBlock
);
345 indFragNum
= ((ufs_daddr_t
*)indBlock
)[indBlockOff
];
348 indBlock
= ReadBlock(indFragNum
, 0, gBlockSize
, 0, 1);
349 indBlockOff
= blockNum
/ refsPerBlock
;
350 blockNum
%= refsPerBlock
;
351 indFragNum
= ((ufs_daddr_t
*)indBlock
)[indBlockOff
];
354 indBlock
= ReadBlock(indFragNum
, 0, gBlockSize
, 0, 1);
355 diskFragNum
= ((ufs_daddr_t
*)indBlock
)[blockNum
];
358 buffer
= ReadBlock(diskFragNum
+fragNum
, blockOffset
, length
, buffer
, cache
);
364 static long ReadFile(InodePtr fileInode
, long *length
)
366 long bytesLeft
, curSize
, curFrag
= 0;
367 char *buffer
, *curAddr
= (char *)kLoadAddr
;
369 bytesLeft
= *length
= fileInode
->di_size
;
371 if (*length
> kLoadSize
) {
372 printf("File is too large.\n");
377 if (bytesLeft
> gBlockSize
) curSize
= gBlockSize
;
378 else curSize
= bytesLeft
;
380 buffer
= ReadFileBlock(fileInode
, curFrag
, 0, curSize
, curAddr
, 0);
381 if (buffer
== 0) break;
383 curFrag
+= gFragsPerBlock
;
385 bytesLeft
-= curSize
;