]>
git.saurik.com Git - apple/bootx.git/blob - bootx.tproj/fs.subproj/ufs.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * ufs.c - File System Module for UFS.
28 * Copyright (c) 1998-2002 Apple Computer, Inc.
35 #include "ufs_byteorder.h"
37 typedef struct dinode Inode
, *InodePtr
;
39 // Private function prototypes
41 static char *ReadBlock(long fragNum
, long fragOffset
, long length
,
42 char *buffer
, long cache
);
43 static long ReadInode(long inodeNum
, InodePtr inode
, long *flags
, long *time
);
44 static long ResolvePathToInode(char *filePath
, long *flags
,
45 InodePtr fileInode
, InodePtr dirInode
);
46 static long ReadDirEntry(InodePtr dirInode
, long *fileInodeNum
,
47 long *dirIndex
, char **name
);
48 static long FindFileInDir(char *fileName
, long *flags
,
49 InodePtr fileInode
, InodePtr dirInode
);
50 static char *ReadFileBlock(InodePtr fileInode
, long fragNum
, long blockOffset
,
51 long length
, char *buffer
, long cache
);
52 static long ReadFile(InodePtr fileInode
, long *length
);
55 static CICell gCurrentIH
;
56 static long long gPartitionBase
;
57 static char gFSBuf
[SBSIZE
];
58 static struct fs
*gFS
;
59 static long gBlockSize
;
60 static long gBlockSizeOld
;
61 static long gFragSize
;
62 static long gFragsPerBlock
;
63 static char *gTempBlock
;
64 static char gTempName
[MAXNAMLEN
+ 1];
65 static char gTempName2
[MAXNAMLEN
+ 1];
66 static Inode gRootInode
;
67 static Inode gFileInode
;
71 long UFSInitPartition(CICell ih
)
73 if (ih
== gCurrentIH
) return 0;
75 printf("UFSInitPartition: %x\n", ih
);
79 // Assume there is no Disk Label
82 // Look for the Super Block
83 Seek(ih
, gPartitionBase
+ SBOFF
);
84 Read(ih
, (long)gFSBuf
, SBSIZE
);
86 gFS
= (struct fs
*)gFSBuf
;
87 if (gFS
->fs_magic
!= FS_MAGIC
) {
91 // Calculate the block size and set up the block cache.
92 gBlockSize
= gFS
->fs_bsize
;
93 gFragSize
= gFS
->fs_fsize
;
94 gFragsPerBlock
= gBlockSize
/ gFragSize
;
96 if (gBlockSizeOld
<= gBlockSize
) {
97 gTempBlock
= AllocateBootXMemory(gBlockSize
);
100 CacheInit(ih
, gBlockSize
);
102 gBlockSizeOld
= gBlockSize
;
106 // Read the Root Inode
107 ReadInode(ROOTINO
, &gRootInode
, 0, 0);
113 long UFSLoadFile(CICell ih
, char *filePath
)
115 long ret
, length
, flags
;
117 if (UFSInitPartition(ih
) == -1) return -1;
119 printf("Loading UFS file: [%s] from %x.\n", filePath
, ih
);
121 // Skip one or two leading '\'.
122 if (*filePath
== '\\') filePath
++;
123 if (*filePath
== '\\') filePath
++;
124 ret
= ResolvePathToInode(filePath
, &flags
, &gFileInode
, &gRootInode
);
125 if ((ret
== -1) || ((flags
& kFileTypeMask
) != kFileTypeFlat
)) return -1;
127 if (flags
& (kOwnerNotRoot
| kPermGroupWrite
| kPermOtherWrite
)) return -1;
129 ret
= ReadFile(&gFileInode
, &length
);
130 if (ret
== -1) return -1;
136 long UFSGetDirEntry(CICell ih
, char *dirPath
, long *dirIndex
,
137 char **name
, long *flags
, long *time
)
139 long ret
, fileInodeNum
, dirFlags
;
142 if (UFSInitPartition(ih
) == -1) return -1;
144 // Skip a leading '\' if present
145 if (*dirPath
== '\\') dirPath
++;
146 if (*dirPath
== '\\') dirPath
++;
147 ret
= ResolvePathToInode(dirPath
, &dirFlags
, &gFileInode
, &gRootInode
);
148 if ((ret
== -1) || ((dirFlags
& kFileTypeMask
) != kFileTypeDirectory
))
151 ret
= ReadDirEntry(&gFileInode
, &fileInodeNum
, dirIndex
, name
);
152 if (ret
!= 0) return ret
;
154 ReadInode(fileInodeNum
, &tmpInode
, flags
, time
);
161 static char *ReadBlock(long fragNum
, long blockOffset
, long length
,
162 char *buffer
, long cache
)
167 blockNum
= fragNum
/ gFragsPerBlock
;
168 fragNum
-= blockNum
* gFragsPerBlock
;
170 blockOffset
+= fragNum
* gFragSize
;
172 offset
= gPartitionBase
+ 1ULL * blockNum
* gBlockSize
;
174 if (cache
&& ((blockOffset
+ length
) <= gBlockSize
)) {
175 CacheRead(gCurrentIH
, gTempBlock
, offset
, gBlockSize
, 1);
176 if (buffer
!= 0) bcopy(gTempBlock
+ blockOffset
, buffer
, length
);
177 else buffer
= gTempBlock
+ blockOffset
;
179 offset
+= blockOffset
;
180 CacheRead(gCurrentIH
, buffer
, offset
, length
, 0);
187 static long ReadInode(long inodeNum
, InodePtr inode
, long *flags
, long *time
)
189 long fragNum
= ino_to_fsba(gFS
, inodeNum
);
190 long blockOffset
= ino_to_fsbo(gFS
, inodeNum
) * sizeof(Inode
);
192 ReadBlock(fragNum
, blockOffset
, sizeof(Inode
), (char *)inode
, 1);
194 if (time
!= 0) *time
= inode
->di_mtime
;
197 switch (inode
->di_mode
& IFMT
) {
198 case IFREG
: *flags
= kFileTypeFlat
; break;
199 case IFDIR
: *flags
= kFileTypeDirectory
; break;
200 case IFLNK
: *flags
= kFileTypeLink
; break;
201 default : *flags
= kFileTypeUnknown
; break;
204 *flags
|= inode
->di_mode
& kPermMask
;
206 if (inode
->di_uid
!= 0) *flags
|= kOwnerNotRoot
;
213 static long ResolvePathToInode(char *filePath
, long *flags
,
214 InodePtr fileInode
, InodePtr dirInode
)
219 // if filePath is empty the we want this directory.
220 if (*filePath
== '\0') {
221 bcopy((char *)dirInode
, (char *)fileInode
, sizeof(Inode
));
225 // Copy the file name to gTempName
227 while ((filePath
[cnt
] != '\\') && (filePath
[cnt
] != '\0')) cnt
++;
228 strncpy(gTempName
, filePath
, cnt
);
230 // Move restPath to the right place.
231 if (filePath
[cnt
] != '\0') cnt
++;
232 restPath
= filePath
+ cnt
;
234 // gTempName is a name in the current Dir.
235 // restPath is the rest of the path if any.
237 ret
= FindFileInDir(gTempName
, flags
, fileInode
, dirInode
);
238 if (ret
== -1) return -1;
240 if ((*restPath
!= '\0') && ((*flags
& kFileTypeMask
) == kFileTypeDirectory
))
241 ret
= ResolvePathToInode(restPath
, flags
, fileInode
, fileInode
);
247 static long ReadDirEntry(InodePtr dirInode
, long *fileInodeNum
,
248 long *dirIndex
, char **name
)
253 long dirBlockNum
, dirBlockOffset
;
258 dirBlockOffset
= index
% DIRBLKSIZ
;
259 dirBlockNum
= index
/ DIRBLKSIZ
;
261 buffer
= ReadFileBlock(dirInode
, dirBlockNum
, 0, DIRBLKSIZ
, 0, 1);
262 if (buffer
== 0) return -1;
264 dir
= (struct direct
*)(buffer
+ dirBlockOffset
);
265 *dirIndex
+= dir
->d_reclen
;
267 if (dir
->d_ino
!= 0) break;
269 if (dirBlockOffset
!= 0) return -1;
272 *fileInodeNum
= dir
->d_ino
;
273 *name
= strncpy(gTempName2
, dir
->d_name
, dir
->d_namlen
);
279 static long FindFileInDir(char *fileName
, long *flags
,
280 InodePtr fileInode
, InodePtr dirInode
)
282 long ret
, inodeNum
, index
= 0;
286 ret
= ReadDirEntry(dirInode
, &inodeNum
, &index
, &name
);
287 if (ret
== -1) return -1;
289 if (strcmp(fileName
, name
) == 0) break;
292 ReadInode(inodeNum
, fileInode
, flags
, 0);
298 static char *ReadFileBlock(InodePtr fileInode
, long fragNum
, long blockOffset
,
299 long length
, char *buffer
, long cache
)
301 long fragCount
, blockNum
;
302 long diskFragNum
, indFragNum
, indBlockOff
, refsPerBlock
;
305 fragCount
= (fileInode
->di_size
+ gFragSize
- 1) / gFragSize
;
306 if (fragNum
>= fragCount
) return 0;
308 refsPerBlock
= gBlockSize
/ sizeof(ufs_daddr_t
);
310 blockNum
= fragNum
/ gFragsPerBlock
;
311 fragNum
-= blockNum
* gFragsPerBlock
;
313 // Get Direct Block Number.
314 if (blockNum
< NDADDR
) {
315 diskFragNum
= fileInode
->di_db
[blockNum
];
319 // Get Single Indirect Fragment Number.
320 if (blockNum
< refsPerBlock
) {
321 indFragNum
= fileInode
->di_ib
[0];
323 blockNum
-= refsPerBlock
;
325 // Get Double Indirect Fragment Number.
326 if (blockNum
< (refsPerBlock
* refsPerBlock
)) {
327 indFragNum
= fileInode
->di_ib
[1];
329 blockNum
-= refsPerBlock
* refsPerBlock
;
331 // Get Triple Indirect Fragment Number.
332 indFragNum
= fileInode
->di_ib
[2];
334 indBlock
= ReadBlock(indFragNum
, 0, gBlockSize
, 0, 1);
335 indBlockOff
= blockNum
/ (refsPerBlock
* refsPerBlock
);
336 blockNum
%= (refsPerBlock
* refsPerBlock
);
337 indFragNum
= ((ufs_daddr_t
*)indBlock
)[indBlockOff
];
340 indBlock
= ReadBlock(indFragNum
, 0, gBlockSize
, 0, 1);
341 indBlockOff
= blockNum
/ refsPerBlock
;
342 blockNum
%= refsPerBlock
;
343 indFragNum
= ((ufs_daddr_t
*)indBlock
)[indBlockOff
];
346 indBlock
= ReadBlock(indFragNum
, 0, gBlockSize
, 0, 1);
347 diskFragNum
= ((ufs_daddr_t
*)indBlock
)[blockNum
];
350 buffer
= ReadBlock(diskFragNum
+fragNum
, blockOffset
, length
, buffer
, cache
);
356 static long ReadFile(InodePtr fileInode
, long *length
)
358 long bytesLeft
, curSize
, curFrag
= 0;
359 char *buffer
, *curAddr
= (char *)kLoadAddr
;
361 bytesLeft
= *length
= fileInode
->di_size
;
363 if (*length
> kLoadSize
) {
364 printf("File is too large.\n");
369 if (bytesLeft
> gBlockSize
) curSize
= gBlockSize
;
370 else curSize
= bytesLeft
;
372 buffer
= ReadFileBlock(fileInode
, curFrag
, 0, curSize
, curAddr
, 0);
373 if (buffer
== 0) break;
375 curFrag
+= gFragsPerBlock
;
377 bytesLeft
-= curSize
;