]>
git.saurik.com Git - apple/boot.git/blob - i386/libsaio/ufs.c
4182f25faa2b68358ac0e11de746e293501639f8
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.
36 #include "ufs_byteorder.h"
38 typedef struct dinode Inode
, *InodePtr
;
40 // Private function prototypes
42 static char *ReadBlock(long fragNum
, long fragOffset
, long length
,
43 char *buffer
, long cache
);
44 static long ReadInode(long inodeNum
, InodePtr inode
, long *flags
, long *time
);
45 static long ResolvePathToInode(char *filePath
, long *flags
,
46 InodePtr fileInode
, InodePtr dirInode
);
47 static long ReadDirEntry(InodePtr dirInode
, long *fileInodeNum
,
48 long *dirIndex
, char **name
);
49 static long FindFileInDir(char *fileName
, long *flags
,
50 InodePtr fileInode
, InodePtr dirInode
);
51 static char *ReadFileBlock(InodePtr fileInode
, long fragNum
, long blockOffset
,
52 long length
, char *buffer
, long cache
);
53 static long ReadFile(InodePtr fileInode
, long *length
);
55 #define kDevBlockSize (0x200) // Size of each disk block.
56 #define kDiskLableBlock (15) // Block the DL is in.
60 static CICell gCurrentIH
;
61 static long long gPartitionBase
;
64 static struct fs
*gFS
;
65 static long gBlockSize
;
66 static long gFragSize
;
67 static long gFragsPerBlock
;
68 static char *gTempBlock
;
69 static char *gTempName
;
70 static char *gTempName2
;
71 static InodePtr gRootInodePtr
;
72 static InodePtr gFileInodePtr
;
76 static CICell gCurrentIH
;
77 static long long gPartitionBase
;
78 static char gDLBuf
[8192];
79 static char gFSBuf
[SBSIZE
];
80 static struct fs
*gFS
;
81 static long gBlockSize
;
82 static long gFragSize
;
83 static long gFragsPerBlock
;
84 static char *gTempBlock
;
85 static char gTempName
[MAXNAMLEN
+ 1];
86 static char gTempName2
[MAXNAMLEN
+ 1];
87 static Inode _gRootInode
;
88 static Inode _gFileInode
;
89 static InodePtr gRootInodePtr
= &_gRootInode
;
90 static InodePtr gFileInodePtr
= &_gFileInode
;
92 #endif /* !__i386__ */
96 long UFSInitPartition( CICell ih
)
98 if (ih
== gCurrentIH
) {
100 CacheInit(ih
, gBlockSize
);
105 verbose("UFSInitPartition: %x\n", ih
);
110 if (!gDLBuf
) gDLBuf
= (char *) malloc(8192);
111 if (!gFSBuf
) gFSBuf
= (char *) malloc(SBSIZE
);
112 if (!gTempName
) gTempName
= (char *) malloc(MAXNAMLEN
+ 1);
113 if (!gTempName2
) gTempName2
= (char *) malloc(MAXNAMLEN
+ 1);
114 if (!gRootInodePtr
) gRootInodePtr
= (InodePtr
) malloc(sizeof(Inode
));
115 if (!gFileInodePtr
) gFileInodePtr
= (InodePtr
) malloc(sizeof(Inode
));
116 if (!gDLBuf
|| !gFSBuf
|| !gTempName
|| !gTempName2
||
117 !gRootInodePtr
|| !gFileInodePtr
) return -1;
120 // Assume there is no Disk Label
123 // Look for the Super Block
124 Seek(ih
, gPartitionBase
+ SBOFF
);
125 Read(ih
, (long)gFSBuf
, SBSIZE
);
127 gFS
= (struct fs
*)gFSBuf
;
128 byte_swap_superblock(gFS
);
130 if (gFS
->fs_magic
!= FS_MAGIC
) {
132 return -1; // not yet for Intel
133 #else /* !__i386__ */
137 // Did not find it... Look for the Disk Label.
138 // Look for the Disk Label
139 Seek(ih
, 1ULL * kDevBlockSize
* kDiskLableBlock
);
140 Read(ih
, (long)gDLBuf
, 8192);
142 dl
= (disk_label_t
*)gDLBuf
;
143 byte_swap_disklabel_in(dl
);
145 if (dl
->dl_version
!= DL_VERSION
) {
149 part
= &dl
->dl_part
[0];
150 gPartitionBase
= (1ULL * (dl
->dl_front
+ part
->p_base
) * dl
->dl_secsize
) -
151 (1ULL * (dl
->dl_label_blkno
- kDiskLableBlock
) * kDevBlockSize
);
153 // Re-read the Super Block.
154 Seek(ih
, gPartitionBase
+ SBOFF
);
155 Read(ih
, (long)gFSBuf
, SBSIZE
);
157 gFS
= (struct fs
*)gFSBuf
;
158 if (gFS
->fs_magic
!= FS_MAGIC
) {
161 #endif /* !__i386__ */
164 // Calculate the block size and set up the block cache.
165 gBlockSize
= gFS
->fs_bsize
;
166 gFragSize
= gFS
->fs_fsize
;
167 gFragsPerBlock
= gBlockSize
/ gFragSize
;
168 if (gTempBlock
!= 0) free(gTempBlock
);
169 gTempBlock
= malloc(gBlockSize
);
170 CacheInit(ih
, gBlockSize
);
174 // Read the Root Inode
175 ReadInode(ROOTINO
, gRootInodePtr
, 0, 0);
180 long UFSLoadFile( CICell ih
, char * filePath
)
182 long ret
, length
, flags
;
184 verbose("Loading UFS file: [%s] from %x.\n", filePath
, (unsigned)ih
);
186 if (UFSInitPartition(ih
) == -1) return -1;
188 // Skip one or two leading '/'.
189 if (*filePath
== '/') filePath
++;
190 if (*filePath
== '/') filePath
++;
192 ret
= ResolvePathToInode(filePath
, &flags
, gFileInodePtr
, gRootInodePtr
);
193 if ((ret
== -1) || ((flags
& kFileTypeMask
) != kFileTypeFlat
)) return -1;
196 // System.config/Default.table will fail this check.
197 // Turn this back on when usage of System.config is deprecated.
198 if (flags
& (kOwnerNotRoot
| kPermGroupWrite
| kPermOtherWrite
)) return -1;
201 ret
= ReadFile(gFileInodePtr
, &length
);
202 if (ret
== -1) return -1;
207 long UFSGetDirEntry( CICell ih
, char * dirPath
, long * dirIndex
,
208 char ** name
, long * flags
, long * time
)
210 long ret
, fileInodeNum
, dirFlags
;
213 if (UFSInitPartition(ih
) == -1) return -1;
215 // Skip a leading '/' if present
216 if (*dirPath
== '/') dirPath
++;
217 if (*dirPath
== '/') dirPath
++;
219 ret
= ResolvePathToInode(dirPath
, &dirFlags
, gFileInodePtr
, gRootInodePtr
);
220 if ((ret
== -1) || ((dirFlags
& kFileTypeMask
) != kFileTypeDirectory
))
223 ret
= ReadDirEntry(gFileInodePtr
, &fileInodeNum
, dirIndex
, name
);
224 if (ret
!= 0) return ret
;
226 ReadInode(fileInodeNum
, &tmpInode
, flags
, time
);
233 static char * ReadBlock( long fragNum
, long blockOffset
, long length
,
234 char * buffer
, long cache
)
239 blockNum
= fragNum
/ gFragsPerBlock
;
240 fragNum
-= blockNum
* gFragsPerBlock
;
242 blockOffset
+= fragNum
* gFragSize
;
244 offset
= gPartitionBase
+ 1ULL * blockNum
* gBlockSize
;
246 if (cache
&& ((blockOffset
+ length
) <= gBlockSize
)) {
247 CacheRead(gCurrentIH
, gTempBlock
, offset
, gBlockSize
, 1);
248 if (buffer
!= 0) bcopy(gTempBlock
+ blockOffset
, buffer
, length
);
249 else buffer
= gTempBlock
+ blockOffset
;
251 offset
+= blockOffset
;
252 CacheRead(gCurrentIH
, buffer
, offset
, length
, 0);
258 static long ReadInode( long inodeNum
, InodePtr inode
, long * flags
, long * time
)
260 long fragNum
= ino_to_fsba(gFS
, inodeNum
);
261 long blockOffset
= ino_to_fsbo(gFS
, inodeNum
) * sizeof(Inode
);
263 ReadBlock(fragNum
, blockOffset
, sizeof(Inode
), (char *)inode
, 1);
264 byte_swap_dinode_in(inode
);
266 if (time
!= 0) *time
= inode
->di_mtime
;
269 switch (inode
->di_mode
& IFMT
) {
270 case IFREG
: *flags
= kFileTypeFlat
; break;
271 case IFDIR
: *flags
= kFileTypeDirectory
; break;
272 case IFLNK
: *flags
= kFileTypeLink
; break;
273 default : *flags
= kFileTypeUnknown
; break;
276 *flags
|= inode
->di_mode
& kPermMask
;
278 if (inode
->di_uid
!= 0) *flags
|= kOwnerNotRoot
;
284 static long ResolvePathToInode( char * filePath
, long * flags
,
285 InodePtr fileInode
, InodePtr dirInode
)
290 // if filePath is empty the we want this directory.
291 if (*filePath
== '\0') {
292 bcopy((char *)dirInode
, (char *)fileInode
, sizeof(Inode
));
296 // Copy the file name to gTempName
298 while ((filePath
[cnt
] != '/') && (filePath
[cnt
] != '\0')) cnt
++;
299 strlcpy(gTempName
, filePath
, cnt
+1);
301 // Move restPath to the right place.
302 if (filePath
[cnt
] != '\0') cnt
++;
303 restPath
= filePath
+ cnt
;
305 // gTempName is a name in the current Dir.
306 // restPath is the rest of the path if any.
308 ret
= FindFileInDir(gTempName
, flags
, fileInode
, dirInode
);
309 if (ret
== -1) return -1;
311 if ((*restPath
!= '\0') && ((*flags
& kFileTypeMask
) == kFileTypeDirectory
))
312 ret
= ResolvePathToInode(restPath
, flags
, fileInode
, fileInode
);
317 static long ReadDirEntry( InodePtr dirInode
, long * fileInodeNum
,
318 long * dirIndex
, char ** name
)
323 long dirBlockNum
, dirBlockOffset
;
328 dirBlockOffset
= index
% DIRBLKSIZ
;
329 dirBlockNum
= index
/ DIRBLKSIZ
;
331 buffer
= ReadFileBlock(dirInode
, dirBlockNum
, 0, DIRBLKSIZ
, 0, 1);
332 if (buffer
== 0) return -1;
334 dir
= (struct direct
*)(buffer
+ dirBlockOffset
);
335 byte_swap_dir_block_in((char *)dir
, 1);
337 *dirIndex
+= dir
->d_reclen
;
339 if (dir
->d_ino
!= 0) break;
341 if (dirBlockOffset
!= 0) return -1;
344 *fileInodeNum
= dir
->d_ino
;
345 *name
= strlcpy(gTempName2
, dir
->d_name
, dir
->d_namlen
+1);
350 static long FindFileInDir( char * fileName
, long * flags
,
351 InodePtr fileInode
, InodePtr dirInode
)
353 long ret
, inodeNum
, index
= 0;
357 ret
= ReadDirEntry(dirInode
, &inodeNum
, &index
, &name
);
358 if (ret
== -1) return -1;
360 if (strcmp(fileName
, name
) == 0) break;
363 ReadInode(inodeNum
, fileInode
, flags
, 0);
368 static char * ReadFileBlock( InodePtr fileInode
, long fragNum
, long blockOffset
,
369 long length
, char * buffer
, long cache
)
371 long fragCount
, blockNum
;
372 long diskFragNum
, indFragNum
, indBlockOff
, refsPerBlock
;
375 fragCount
= (fileInode
->di_size
+ gFragSize
- 1) / gFragSize
;
376 if (fragNum
>= fragCount
) return 0;
378 refsPerBlock
= gBlockSize
/ sizeof(ufs_daddr_t
);
380 blockNum
= fragNum
/ gFragsPerBlock
;
381 fragNum
-= blockNum
* gFragsPerBlock
;
383 // Get Direct Block Number.
384 if (blockNum
< NDADDR
) {
385 diskFragNum
= fileInode
->di_db
[blockNum
];
389 // Get Single Indirect Fragment Number.
390 if (blockNum
< refsPerBlock
) {
391 indFragNum
= fileInode
->di_ib
[0];
393 blockNum
-= refsPerBlock
;
395 // Get Double Indirect Fragment Number.
396 if (blockNum
< (refsPerBlock
* refsPerBlock
)) {
397 indFragNum
= fileInode
->di_ib
[1];
399 blockNum
-= refsPerBlock
* refsPerBlock
;
401 // Get Triple Indirect Fragment Number.
402 indFragNum
= fileInode
->di_ib
[2];
404 indBlock
= ReadBlock(indFragNum
, 0, gBlockSize
, 0, 1);
405 indBlockOff
= blockNum
/ (refsPerBlock
* refsPerBlock
);
406 blockNum
%= (refsPerBlock
* refsPerBlock
);
407 indFragNum
= SWAP_BE32(((ufs_daddr_t
*)indBlock
)[indBlockOff
]);
410 indBlock
= ReadBlock(indFragNum
, 0, gBlockSize
, 0, 1);
411 indBlockOff
= blockNum
/ refsPerBlock
;
412 blockNum
%= refsPerBlock
;
413 indFragNum
= SWAP_BE32(((ufs_daddr_t
*)indBlock
)[indBlockOff
]);
416 indBlock
= ReadBlock(indFragNum
, 0, gBlockSize
, 0, 1);
417 diskFragNum
= SWAP_BE32(((ufs_daddr_t
*)indBlock
)[blockNum
]);
420 buffer
= ReadBlock(diskFragNum
+fragNum
, blockOffset
, length
, buffer
, cache
);
425 static long ReadFile( InodePtr fileInode
, long * length
)
427 long bytesLeft
, curSize
, curFrag
= 0;
428 char *buffer
, *curAddr
= (char *)kLoadAddr
;
431 curAddr
= gFSLoadAddress
;
434 bytesLeft
= *length
= fileInode
->di_size
;
436 if (*length
> kLoadSize
) {
437 printf("File is too large.\n");
442 if (bytesLeft
> gBlockSize
) curSize
= gBlockSize
;
443 else curSize
= bytesLeft
;
445 buffer
= ReadFileBlock(fileInode
, curFrag
, 0, curSize
, curAddr
, 0);
446 if (buffer
== 0) break;
448 curFrag
+= gFragsPerBlock
;
450 bytesLeft
-= curSize
;