]>
git.saurik.com Git - apple/bootx.git/blob - bootx.tproj/fs.subproj/ufs.c
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 * ufs.c - File System Module for UFS.
32 * Copyright (c) 1998-2004 Apple Computer, Inc.
39 #include "ufs_byteorder.h"
41 #include <dirent.h> // for MAXNAMLEN
43 typedef struct dinode Inode
, *InodePtr
;
45 // Private function prototypes
47 static char *ReadBlock(long fragNum
, long fragOffset
, long length
,
48 char *buffer
, long cache
);
49 static long ReadInode(long inodeNum
, InodePtr inode
, long *flags
, long *time
);
50 static long ResolvePathToInode(char *filePath
, long *flags
,
51 InodePtr fileInode
, InodePtr dirInode
);
52 static long ReadDirEntry(InodePtr dirInode
, long *fileInodeNum
,
53 unsigned long *dirIndex
, char **name
);
54 static long FindFileInDir(char *fileName
, long *flags
,
55 InodePtr fileInode
, InodePtr dirInode
);
56 static char *ReadFileBlock(InodePtr fileInode
, long fragNum
, long blockOffset
,
57 long length
, char *buffer
, long cache
);
58 static long ReadFile(InodePtr fileInode
, long *length
,
59 void *base
, long offset
);
62 static CICell gCurrentIH
;
63 static long long gPartitionBase
;
64 static char gFSBuf
[SBSIZE
];
65 static struct fs
*gFS
;
66 static struct ufslabel gUFSLabel
; // for UUID
67 static long gBlockSize
;
68 static long gBlockSizeOld
;
69 static long gFragSize
;
70 static long gFragsPerBlock
;
71 static char *gTempBlock
;
72 static char gTempName
[MAXNAMLEN
+ 1];
73 static char gTempName2
[MAXNAMLEN
+ 1];
74 static Inode gRootInode
;
75 static Inode gFileInode
;
79 long UFSInitPartition(CICell ih
)
83 if (ih
== gCurrentIH
) return 0;
85 printf("UFSInitPartition: %x\n", ih
);
89 // Assume UFS starts at the beginning of the device
92 // read the disk label to get the UUID
93 // (rumor has it that UFS headers can be either-endian on disk; hopefully
94 // that isn't true for this UUID field).
95 Seek(ih
, gPartitionBase
+ UFS_LABEL_OFFSET
);
96 ret
= Read(ih
, (long)&gUFSLabel
, UFS_LABEL_SIZE
);
97 if(ret
!= UFS_LABEL_SIZE
)
98 bzero(&gUFSLabel
, UFS_LABEL_SIZE
);
100 // Look for the Super Block
101 Seek(ih
, gPartitionBase
+ SBOFF
);
102 Read(ih
, (long)gFSBuf
, SBSIZE
);
104 gFS
= (struct fs
*)gFSBuf
;
105 //printf("looking for UFS magic ... \n");
106 if (gFS
->fs_magic
!= FS_MAGIC
) {
109 //printf("continuing w/UFS\n");
111 // Calculate the block size and set up the block cache.
112 gBlockSize
= gFS
->fs_bsize
;
113 gFragSize
= gFS
->fs_fsize
;
114 gFragsPerBlock
= gBlockSize
/ gFragSize
;
116 if (gBlockSizeOld
<= gBlockSize
) {
117 gTempBlock
= AllocateBootXMemory(gBlockSize
);
120 CacheInit(ih
, gBlockSize
);
122 gBlockSizeOld
= gBlockSize
;
126 // Read the Root Inode
127 ReadInode(ROOTINO
, &gRootInode
, 0, 0);
133 long UFSGetUUID(CICell ih
, char *uuidStr
)
135 long long uuid
= gUFSLabel
.ul_uuid
;
137 if (UFSInitPartition(ih
) == -1) return -1;
138 if (uuid
== 0LL) return -1;
140 return CreateUUIDString((uint8_t*)(&uuid
), sizeof(uuid
), uuidStr
);
143 long UFSLoadFile(CICell ih
, char *filePath
)
145 return UFSReadFile(ih
, filePath
, (void *)kLoadAddr
, 0, 0);
148 long UFSReadFile(CICell ih
, char *filePath
, void *base
,
149 unsigned long offset
, unsigned long length
)
153 if (UFSInitPartition(ih
) == -1) return -1;
155 printf("%s UFS file: [%s] from %x.\n",
156 (((offset
== 0) && (length
== 0)) ? "Loading" : "Reading"),
159 // Skip one or two leading '\'.
160 if (*filePath
== '\\') filePath
++;
161 if (*filePath
== '\\') filePath
++;
162 ret
= ResolvePathToInode(filePath
, &flags
, &gFileInode
, &gRootInode
);
163 if ((ret
== -1) || ((flags
& kFileTypeMask
) != kFileTypeFlat
)) return -1;
165 if (flags
& (kOwnerNotRoot
| kPermGroupWrite
| kPermOtherWrite
)) {
166 printf("%s: permissions incorrect\n", filePath
);
170 ret
= ReadFile(&gFileInode
, &length
, base
, offset
);
171 if (ret
== -1) return -1;
177 long UFSGetDirEntry(CICell ih
, char *dirPath
, unsigned long *dirIndex
,
178 char **name
, long *flags
, long *time
)
180 long ret
, fileInodeNum
, dirFlags
;
183 if (UFSInitPartition(ih
) == -1) return -1;
185 // Skip a leading '\' if present
186 if (*dirPath
== '\\') dirPath
++;
187 if (*dirPath
== '\\') dirPath
++;
188 ret
= ResolvePathToInode(dirPath
, &dirFlags
, &gFileInode
, &gRootInode
);
189 if ((ret
== -1) || ((dirFlags
& kFileTypeMask
) != kFileTypeDirectory
))
192 ret
= ReadDirEntry(&gFileInode
, &fileInodeNum
, dirIndex
, name
);
193 if (ret
!= 0) return ret
;
195 ReadInode(fileInodeNum
, &tmpInode
, flags
, time
);
202 static char *ReadBlock(long fragNum
, long blockOffset
, long length
,
203 char *buffer
, long cache
)
208 blockNum
= fragNum
/ gFragsPerBlock
;
209 fragNum
-= blockNum
* gFragsPerBlock
;
211 blockOffset
+= fragNum
* gFragSize
;
213 offset
= gPartitionBase
+ 1ULL * blockNum
* gBlockSize
;
215 if (cache
&& ((blockOffset
+ length
) <= gBlockSize
)) {
216 CacheRead(gCurrentIH
, gTempBlock
, offset
, gBlockSize
, 1);
217 if (buffer
!= 0) bcopy(gTempBlock
+ blockOffset
, buffer
, length
);
218 else buffer
= gTempBlock
+ blockOffset
;
220 offset
+= blockOffset
;
221 CacheRead(gCurrentIH
, buffer
, offset
, length
, 0);
228 static long ReadInode(long inodeNum
, InodePtr inode
, long *flags
, long *time
)
230 long fragNum
= ino_to_fsba(gFS
, inodeNum
);
231 long blockOffset
= ino_to_fsbo(gFS
, inodeNum
) * sizeof(Inode
);
233 ReadBlock(fragNum
, blockOffset
, sizeof(Inode
), (char *)inode
, 1);
235 if (time
!= 0) *time
= inode
->di_mtime
;
238 switch (inode
->di_mode
& IFMT
) {
239 case IFREG
: *flags
= kFileTypeFlat
; break;
240 case IFDIR
: *flags
= kFileTypeDirectory
; break;
241 case IFLNK
: *flags
= kFileTypeLink
; break;
242 default : *flags
= kFileTypeUnknown
; break;
245 *flags
|= inode
->di_mode
& kPermMask
;
247 if (inode
->di_uid
!= 0) {
248 static int nwarnings
= 0;
249 if(nwarnings
++ < 25) // so we don't warn for all in an Extensions walk
250 printf("non-root file owner detected: %d\n", inode
->di_uid
);
251 *flags
|= kOwnerNotRoot
;
259 static long ResolvePathToInode(char *filePath
, long *flags
,
260 InodePtr fileInode
, InodePtr dirInode
)
265 // if filePath is empty the we want this directory.
266 if (*filePath
== '\0') {
267 bcopy((char *)dirInode
, (char *)fileInode
, sizeof(Inode
));
271 // Copy the file name to gTempName
273 while ((filePath
[cnt
] != '\\') && (filePath
[cnt
] != '\0')) cnt
++;
274 strncpy(gTempName
, filePath
, cnt
);
276 // Move restPath to the right place.
277 if (filePath
[cnt
] != '\0') cnt
++;
278 restPath
= filePath
+ cnt
;
280 // gTempName is a name in the current Dir.
281 // restPath is the rest of the path if any.
283 ret
= FindFileInDir(gTempName
, flags
, fileInode
, dirInode
);
284 if (ret
== -1) return -1;
286 if ((*restPath
!= '\0') && ((*flags
& kFileTypeMask
) == kFileTypeDirectory
))
287 ret
= ResolvePathToInode(restPath
, flags
, fileInode
, fileInode
);
293 static long ReadDirEntry(InodePtr dirInode
, long *fileInodeNum
,
294 unsigned long *dirIndex
, char **name
)
299 long dirBlockNum
, dirBlockOffset
;
304 dirBlockOffset
= index
% DIRBLKSIZ
;
305 dirBlockNum
= index
/ DIRBLKSIZ
;
307 buffer
= ReadFileBlock(dirInode
, dirBlockNum
, 0, DIRBLKSIZ
, 0, 1);
308 if (buffer
== 0) return -1;
310 dir
= (struct direct
*)(buffer
+ dirBlockOffset
);
311 *dirIndex
+= dir
->d_reclen
;
313 if (dir
->d_ino
!= 0) break;
315 if (dirBlockOffset
!= 0) return -1;
318 *fileInodeNum
= dir
->d_ino
;
319 *name
= strncpy(gTempName2
, dir
->d_name
, dir
->d_namlen
);
325 static long FindFileInDir(char *fileName
, long *flags
,
326 InodePtr fileInode
, InodePtr dirInode
)
329 unsigned long index
= 0;
333 ret
= ReadDirEntry(dirInode
, &inodeNum
, &index
, &name
);
334 if (ret
== -1) return -1;
336 if (strcmp(fileName
, name
) == 0) break;
339 ReadInode(inodeNum
, fileInode
, flags
, 0);
345 static char *ReadFileBlock(InodePtr fileInode
, long fragNum
, long blockOffset
,
346 long length
, char *buffer
, long cache
)
348 long fragCount
, blockNum
;
349 long diskFragNum
, indFragNum
, indBlockOff
, refsPerBlock
;
352 fragCount
= (fileInode
->di_size
+ gFragSize
- 1) / gFragSize
;
353 if (fragNum
>= fragCount
) return 0;
355 refsPerBlock
= gBlockSize
/ sizeof(ufs_daddr_t
);
357 blockNum
= fragNum
/ gFragsPerBlock
;
358 fragNum
-= blockNum
* gFragsPerBlock
;
360 // Get Direct Block Number.
361 if (blockNum
< NDADDR
) {
362 diskFragNum
= fileInode
->di_db
[blockNum
];
366 // Get Single Indirect Fragment Number.
367 if (blockNum
< refsPerBlock
) {
368 indFragNum
= fileInode
->di_ib
[0];
370 blockNum
-= refsPerBlock
;
372 // Get Double Indirect Fragment Number.
373 if (blockNum
< (refsPerBlock
* refsPerBlock
)) {
374 indFragNum
= fileInode
->di_ib
[1];
376 blockNum
-= refsPerBlock
* refsPerBlock
;
378 // Get Triple Indirect Fragment Number.
379 indFragNum
= fileInode
->di_ib
[2];
381 indBlock
= ReadBlock(indFragNum
, 0, gBlockSize
, 0, 1);
382 indBlockOff
= blockNum
/ (refsPerBlock
* refsPerBlock
);
383 blockNum
%= (refsPerBlock
* refsPerBlock
);
384 indFragNum
= ((ufs_daddr_t
*)indBlock
)[indBlockOff
];
387 indBlock
= ReadBlock(indFragNum
, 0, gBlockSize
, 0, 1);
388 indBlockOff
= blockNum
/ refsPerBlock
;
389 blockNum
%= refsPerBlock
;
390 indFragNum
= ((ufs_daddr_t
*)indBlock
)[indBlockOff
];
393 indBlock
= ReadBlock(indFragNum
, 0, gBlockSize
, 0, 1);
394 diskFragNum
= ((ufs_daddr_t
*)indBlock
)[blockNum
];
397 buffer
= ReadBlock(diskFragNum
+fragNum
, blockOffset
, length
, buffer
, cache
);
403 static long ReadFile(InodePtr fileInode
, long *length
, void *base
, long offset
)
405 long bytesLeft
, curSize
, curFrag
;
406 char *buffer
, *curAddr
= (char *)base
;
408 bytesLeft
= fileInode
->di_size
;
410 if (offset
> bytesLeft
) {
411 printf("Offset is too large.\n");
415 if ((*length
== 0) || ((offset
+ *length
) > bytesLeft
)) {
416 *length
= bytesLeft
- offset
;
419 if (*length
> kLoadSize
) {
420 printf("File is too large.\n");
425 curFrag
= (offset
/ gBlockSize
) * gFragsPerBlock
;
426 offset
%= gBlockSize
;
429 curSize
= gBlockSize
;
430 if (curSize
> bytesLeft
) curSize
= bytesLeft
;
431 if (offset
!= 0) curSize
-= offset
;
433 buffer
= ReadFileBlock(fileInode
, curFrag
, offset
, curSize
, curAddr
, 0);
434 if (buffer
== 0) break;
436 if (offset
!= 0) offset
= 0;
438 curFrag
+= gFragsPerBlock
;
440 bytesLeft
-= curSize
;