Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
MFSCore.h
/* |
File: MFSCore.h |
Contains: Core MFS implementation for MFSLives. |
Written by: DTS |
Copyright: Copyright (c) 2006 by Apple Computer, Inc., All Rights Reserved. |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
("Apple") in consideration of your agreement to the following terms, and your |
use, installation, modification or redistribution of this Apple software |
constitutes acceptance of these terms. If you do not agree with these terms, |
please do not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject |
to these terms, Apple grants you a personal, non-exclusive license, under Apple's |
copyrights in this original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or without |
modifications, in source and/or binary forms; provided that if you redistribute |
the Apple Software in its entirety and without modifications, you must retain |
this notice and the following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks or logos of |
Apple Computer, Inc. may be used to endorse or promote products derived from the |
Apple Software without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any patent rights that |
may be infringed by your derivative works or by other works in which the Apple |
Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Change History (most recent first): |
$Log: MFSCore.h,v $ |
Revision 1.1 2006/07/27 15:47:47 eskimo1 |
First checked in. |
*/ |
#ifndef _MFSCORE_H |
#define _MFSCORE_H |
///////////////////////////////////////////////////////////////////// |
#include <stdint.h> |
#include <mach/boolean.h> |
#include <sys/time.h> |
#include <sys/mount.h> |
#include <sys/vnode.h> |
#if ! KERNEL |
#include "VNodeAttr.h" |
#endif |
///////////////////////////////////////////////////////////////////// |
/* |
Design Philosophy |
----------------- |
This module implements the core MFS core. None of the code outside of this |
module contains any significant understanding of the MFS volume format. |
Also, none of the code within this module contains any significant dependency |
on the kernel environment. |
The reason for this isolation is that we want to be able to build run this |
code in user space. There are two reasons for this: |
o We have a user space unit test program to exercise this code. |
o The MFSLives.util tool uses this code to work with MFS volumes without |
installing kernel code, which is a handy dandy feature. |
The upshot of this is that the MFS core does not read or write blocks, or do |
any locking for multi-threaded access, or allocate memory. All of these tasks |
are the responsibility of the caller. In some cases I've had to bend the API |
a little to maintain this constraint (for example, |
MFSDirectoryBlockFindEntryByName requires that you pass it a temporary buffer), |
but that's the price you pay. |
Finally, because MFS isn't really suitable as a read/write volume format |
(on a read/write volume, what would you do if you were asked to create a |
directory?!), I have not gone out of my way to provide read/write support in |
the MFS core code. For example, the MFS core API exposes the raw directory |
offset to the caller, which isn't architecturally advantageous for a read/write |
implementation. |
MFS Volume Format |
----------------- |
Inside Macintosh II contains a very rudimentary description of the MFS volume |
format. This description leaves a number of open issues, and I've tried to |
cover these in the most sensible way. |
o Folders -- If you're old enough to remember the original Macintosh, you |
may recall that it did support folders. These folders were an illusion |
maintained by the Finder. The MFS file system is strictly flat. |
o Alternative Block Sizes -- All real world MFS disks had a block size of |
512 bytes (modulo the wacky tag bytes on the 400 KB floppy drives, but |
that doesn't affect the actual volume format). In theory, one could create |
an MFS volume on a disk with a different block size. In the MFS core code |
(and in most of the rest of MFSLives as a whole) I've avoided hard-coding |
the block size at 512 bytes. Rather, I've kept a clear separate between |
quantities that are in bytes, blocks, and allocation blocks, and I don't |
try to convert from one to the other. |
For example, the location the MFS directory is in blocks, and the MFS core |
does not assume that this is a specific byte offset from the beginning |
of the disk. Rather, it returns the values in blocks to the caller, and |
expects it to get that block number. |
I don't know if anyone ever created an MFS volume on a device with a block |
size that's not 512, so I can't check if this approach is correct. |
I /do/ make the assumption that the block size is big enough to hold the |
MFS master directory block (64 bytes). |
o Text Encodings -- MFS stores a name (file and volume) as a Pascal string, |
with no associated text encoding. For simplicity's sake, I assume that |
this string is MacRoman. If you have MFS disks from a Japanese system, |
you are out of luck. |
If this was production code, I'd allow you to specify the encoding at mount |
time. However, given the paucity of text encoding conversion support within |
the kernel, that's just too much work for this sample code. |
There's a big discussion of how I implement text encoding conversion below. |
o Dates/Time Values -- MFS date/time values are stored in local time. |
VFS (and general common sense) requires that date/time values be returned |
in UTC. I originally tried to make it so that the times displayed by the |
Finder would match the times displayed by the Finder on a Mac 128K. I did |
this by doing a local-to-UTC conversion in the "MFSCore.c", in the hope that |
it would exactly match the ultimate client's UTC-to-local conversion. |
However, it's impossible to do this correctly (see below), so I changed my |
approach and decided that I'd treat all MFS date/time values as if they were |
in UTC. |
The reasons why it's impossible to implement my previous approach are: |
- You might have two clients in two different time zones, and thus it's |
impossible to local-to-UTC conversion that will satisfy both. |
I don't consider this to be a serious problem; it's rare for this |
situation to arise on a typical Mac. |
- Local time is not linear. In time zones that have summer time, at the |
point where summer time changes back to winter time, a given local |
time has two possible UTC values. For example, if you're on British |
Summer Time (BST is UTC+0100) and the clock goes back to GMT (UTC+0000) |
at 0200, a local time value of 0130 corresponds to both 0030 UTC (when the |
local time is in BST) and 0130 (an hour later, after the local time has |
reverted to GMT). |
The following table illustrates this in more detail. Notice how the |
right column (UTC) progresses linearly, whereas the left column has |
discontinuities. |
0130 local (BST) -> 0030 UTC |
0159 local (BST) -> 0059 UTC |
<<< local time goes back one hour at 0200 local >>> |
0101 local (GMT) -> 0101 UTC |
0130 local (GMT) -> 0130 UTC |
The upshot of this is that a given local time can have more than one |
possible UTC value, so there's no unique transform from local time to UTC. |
- Even if you ignore the above (which is only really an issue during |
local time changes), the mechanics of the client's UTC-to-local conversion |
make it hard to do the correction. Specifically, system routines that |
do UTC-to-local conversion (such as <x-man-page://3/localtime_r> will |
typically do it in the time zone that was in effect at that time. That is, |
if you live in Scotland (BST/GMT) and convert a UTC value from 1 Jan 1986 |
to local time, you'll get a GMT value because GMT was in effect on 1 Jan 1986. |
OTOH, if the UTC value is 1 Jul 1986, you'll get a BST value. |
So, from the kernel's perspective, there's no simple UTC correction factor |
that you can add to all local times to get their UTC values such that |
clients who convert the resulting UTC values back to local time will get |
the value you started off with. Instead, you have to do a different |
conversion for each potential date. All of this makes the problem /way/ |
too hard for this sample code. |
So, rather than do a poor job of local-to-UTC conversion, I decided to |
just ignore the problem and assume (wrongly) that all MFS disks were used |
in UTC. This means that you get reasonably consistent results (if file |
X was modified an hour after file Y, that difference will be reflected |
correctly to the client), but the Finder will no show the correct local time |
for any given file. |
This change also allowed me to delete a bunch of code. Hey, if you can't |
get it right, you might as well keep it simple. |
Finally, I /do/ have to do epoch conversion. MFS date/time values start |
at 00:00:00 1 Jan 1904. VFS date/time values start at 00:00:00 1 Jan 1970. |
This module does the epoch conversion internally. MFS date/time values |
before 00:00:00 1970 are clipped to 00:00:00 1970. |
Quinn says: time is hard. |
Text Encodings |
-------------- |
For general information about text encodings in VFS, see DTS Q&A 1173 "Text |
Encodings in VFS". |
<http://developer.apple.com/qa/qa2001/qa1173.html> |
As I mentioned above, I assume that all names on MFS volumes are in MacRoman. |
As VFS expects to work in UTF-8, I need to be able to: |
1. convert from UTF-8 (decomposed or precomposed) to MacRoman |
2. convert from MacRoman to UTF-8 (decomposed) |
3. do case insensitive equality testing |
The kernel provides very limited support for text encoding conversion, so I have |
to do most of this myself. I do it using a variety of lookup tables that I |
precompute (using the TableGenerator program, see "TableGenerator.c") and then |
copy'n'paste into the source of the MFS core. I use a number of tricks to make |
these tables manageably small: |
o In all cases except case folding, I special case the bottom 128 code points |
because I know that MacRoman and UTF-8 both inherit their bottom 128 |
code points from the same place (ASCII). |
o For UTF-8 (decomposed or precomposed) to MacRoman conversion, I first use the |
kernel routine utf_decodestr to convert the string to precomposed UTF-16. |
Each valid MacRoman has a unique precomposed UTF-16 value, so I have a |
table that maps valid UTF-16 values to their MacRoman equivalents |
(kUTF16ToMacRoman). As the UTF-16 space is huge, this table is sparse, |
so I generate a sorted table and binary search it. |
This approach means that I don't have to parse UTF-8, or do canonical |
composition; utf_decodestr takes care of that. It also means that I don't |
have to worry about decomposed UTF-16, because any combining UTF-16 |
code point remaining after precomposition is necessarily not in MacRoman. |
o For MacRoman to UTF-8 (decomposed) conversion, I simply have a table that |
maps the MacRoman character to its corresponding UTF-8 (decomposed) string. |
One interesting case here is truncation. If I have to truncate a string, |
I make sure that I truncate it at a MacRoman boundary. That is, you either |
get all of the UTF-8 for a given MacRoman character, or none of it. |
o For case insensitive equality testing, I'm testing an arbitrary UTF-8 |
string against a list of MacRoman file names (to do a directory lookup |
by name). In this case, I convert the UTF-8 string to MacRoman and do |
the comparison in the MacRoman space. I do the comparison in MacRoman |
space by simply having a table that maps every MacRoman character to |
its upper case equivalent. |
If the UTF-8 string does not convert to MacRoman, it clearly isn't a match |
for any of my MacRoman strings. |
The upshot of this is that, with some sneaky coding, I can handle text encodings |
correctly while keeping my conversion tables small. |
One minor quibble is that there's an asymmetry in the code: I use <sys/utfconv.h> |
routines to got from UTF-8 to UTF-16 (and hence to MacRoman), but not the other |
way. I did this because the <sys/utfconv.h> routines require me to have an |
extra buffer (for the UTF-16), which is a pain. So I only use them if |
they offer a real advantage. In the case of utf8_decodestr, it handles |
all of the ugliness of UTF-8 parsing and does pre-composition, both things |
that I really need. So the hassle of the extra buffer is far outweighed |
by the benefits. OTOH, when going the other way, it's just as easy for |
my table to contain UTF-8 as it would be for it to contain UTF-16, so I just |
go directly from MacRoman to UTF-8. |
*/ |
///////////////////////////////////////////////////////////////////// |
// Special inode numbers -- All of these are traditional for Macintosh-based file systems |
// starting with HFS. MFS uses a different approach (file numbers start from 1), so |
// the MFS core does an internal translation to these numbers. |
enum { |
kMFSRootParentInodeNumber = 1, |
kMFSRootInodeNumber = 2, |
kMFSFirstFileInodeName = 16 |
}; |
// Special block numbers -- There's only one, allowing the caller to find the |
// master directory block (MDB) to pass to MFSMDBCheck. |
enum { |
kMFSMDBBlock = 2 // block number of the MDB (includes the start of the VABM) |
}; |
// The volume allocation block map (VABM) follows immediately after the MDB on disk |
// (that is, the start of the VABM shares the same block as the MDB). |
extern int MFSMDBCheck( |
const void * mdbBlockPtr, |
uint64_t containerBlockCount, |
size_t * mdbAndVABMSizeInBytesPtr, |
uint16_t * directoryStartBlockPtr, |
uint16_t * directoryBlockCountPtr, |
uint16_t * allocationBlocksStartBlockPtr, |
uint32_t * allocationBlockSizeInBytesPtr |
); |
// Given a pointer to an MFS master directory block (MDB), this routine returns |
// 0 if the MDB is valid and EINVAL if it isn't. |
// |
// mdbBlockPtr must be a pointer to master directory block that you've read in. |
// This is always block kMFSMDBBlock on the disk. The size of this block must |
// be at least 64 bytes (which is the size of the MFS MDB). |
// |
// containerBlockCount must be the number of blocks on the disk. The routine uses |
// this value to range check various fields in the MDB. |
// |
// On entry, any combination of mdbAndVABMSizeInBytesPtr, directoryStartBlockPtr, |
// directoryBlockCountPtr, allocationBlocksStartBlockPtr, and allocationBlockSizeInBytesPtr may |
// be NULL, in which case that value is not returned. If xxxPtr is not NULL, |
// *xxxPtr is ignored on entry. If xxxPtr is not NULL then, on success, |
// *xxxPtr contains a valid value and, on error, the value of *xxxPtr will be unchanged. |
// |
// On success when mdbAndVABMSizeInBytesPtr is not NULL, *mdbAndVABMSizeInBytesPtr |
// will be the size of the combined MDB and VABM. The caller is expected to read in |
// at least this many bytes when it calls MFSForkGetExtent. |
// |
// On success when directoryStartBlockPtr is not NULL, *directoryStartBlockPtr will |
// be the block number of the first directory block. |
// |
// On success when directoryBlockCountPtr is not NULL, *directoryBlockCountPtr will |
// be the number of directory blocks. |
// |
// To search the directory, the caller is expected to iterate over all of the directory |
// blocks, reading in each block and presenting it to the appropriate MFS core routine |
// (MFSDirectoryBlockIterate or MFSDirectoryBlockFindEntryByName). |
// |
// On success when allocationBlocksStartBlockPtr is not NULL, *allocationBlocksStartBlockPtr |
// will be the block number of the block that holds the first allocation block. |
// |
// On success when allocationBlockSizeInBytesPtr is not NULL, *allocationBlockSizeInBytesPtr |
// will be the size in bytes of each allocation block. |
extern void MFSMDBGetError( |
const void * mdbBlockPtr, |
uint64_t containerBlockCount, |
char * errStr, |
size_t errStrSize |
); |
// If MFSMDBCheck fails with EINVAL, you can call this routine to get a |
// non-localised description of what the MFS core does not like about the |
// MDB. |
// |
// mdbBlockPtr and containerBlockCount are as per MFSMDBCheck. |
// |
// errStr must point to a buffer where the error is returned (as a UTF-8 |
// C string). errStrSize is the size of that buffer. It must be |
// at least 1 (otherwise we couldn't returning a valid C string, |
// with its terminating null character). If it's too short, the |
// routine silently truncates the string. A value of 256 should be |
// sufficient. |
extern int MFSMDBGetAttr( |
const void * mdbBlockPtr, |
struct vfs_attr * attr |
); |
// Returns information about the MFS volume. |
// |
// mdbBlockPtr is as per MFSMDBCheck. |
// |
// attr must not be NULL; it is handled as per the VFS plug-in's vfs_getattr |
// entry point. |
// |
// Note that, with one exception, this routine always returns all of the |
// attributes that are available for the MFS volume, because the cost of |
// returns those values is trivial. That is, it (typically) ignores |
// the f_active field of attr. The one exception is f_vol_name; because getting |
// the volume requires MacRoman to UTF-8 conversion, which is potentially |
// time consuming, this routine only returns f_vol_name if you request it. |
#define kMFSDirectoryBlockIterateFromStart ((size_t)-1) |
extern int MFSDirectoryBlockIterate( |
const void * directoryBlockPtr, |
size_t directoryBlockSizeInBytes, |
size_t * dirOffsetPtr, |
struct vnode_attr * attr |
); |
// Allows you to iterate over every directory entry within an MFS directory block. |
// To do this, start by setting *dirOffsetPtr to kMFSDirectoryBlockIterateFromStart. |
// Each time you call the routine, it will either fail with ENOENT |
// (indicating that there are no more directory entries in the directory |
// block), or update *dirOffsetPtr to be the offset of the next directory |
// entry within the block. |
// |
// directoryBlockPtr must point to an MFS directory block. See MFSMDBCheck |
// for information on how to locate these. |
// |
// directoryBlockSizeInBytes must be the size of that block. |
// |
// dirOffsetPtr must not be NULL. On entry, it must either be |
// kMFSDirectoryBlockIterateFromStart (indicating that you're requesting the |
// first directory entry in the block), or a value that was previously |
// returned by this routine. On success, it is set to the offset of the |
// next directory entry within the directory block. On failure, its |
// value is unchanged. |
// |
// On entry, if attr is NULL, no attributes are returned. OTOH, if attr is not |
// NULL then, on success, the directory entry's attributes will be returned |
// in *attr. See MFSDirectoryEntryGetAttr for specific details on this. |
extern int MFSDirectoryBlockCheckDirOffset( |
const void * directoryBlockPtr, |
size_t directoryBlockSizeInBytes, |
size_t candidateDirOffset |
); |
// Checks to see if candidateDirOffset is a valid directory offset, that is, |
// an offset that you would get back if you iterated the directory from the |
// start. |
// |
// directoryBlockPtr must point to an MFS directory block. See MFSMDBCheck |
// for information on how to locate these. |
// |
// directoryBlockSizeInBytes must be the size of that block. |
// |
// candidateDirOffset must be less than directoryBlockSizeInBytes. |
// |
// Returns EINVAL if candidateDirOffset is not valid, and 0 otherwise. |
enum { |
kMFSDirectoryBlockFindEntryByNameTempBufferSize = MAXPATHLEN |
}; |
extern int MFSDirectoryBlockFindEntryByName( |
const void * directoryBlockPtr, |
size_t directoryBlockSizeInBytes, |
const char * utf8Name, |
size_t utf8NameLen, |
void * tempBuffer, |
size_t * dirOffsetPtr, |
struct vnode_attr * attr |
); |
// Searches, by name, for a directory entry within an MFS directory block. |
// To do this, first allocate a temporary buffer of size |
// kMFSDirectoryBlockFindEntryByNameTempBufferSize, and set its first byte |
// to 0. Then call this routine. If it finds the named directory entry, |
// it returns 0. If it fails to find the entry, it returns ENOENT. |
// Other errors can occur if the input name is not valid. |
// |
// If you want to search multiple directory blocks for the same name, you |
// can speed things up by preserving the contents of the temporary buffer |
// across multilpe calls to this routine. This routine uses the temporary |
// buffer to cache the MacRoman conversion of the UTF-8 name. |
// |
// directoryBlockPtr must point to an MFS directory block. See MFSMDBCheck |
// for information on how to locate these. |
// |
// directoryBlockSizeInBytes must be the size of that block. |
// |
// utf8Name must be a pointer to a UTF-8 string (either precomposed or decomposed) |
// of the name that you're looking for. |
// |
// utf8NameLen is the length of that name in bytes. |
// |
// tempBuffer must point to a buffer of at least |
// kMFSDirectoryBlockFindEntryByNameTempBufferSize bytes. See the discussion |
// above for information about how to set up this buffer. |
// |
// dirOffsetPtr must not be NULL. On entry, *dirOffsetPtr is ignored. Or success, |
// *dirOffsetPtr will be the offset of the found directory entry within the |
// directory block. |
// |
// On entry, if attr is NULL, no attributes are returned. OTOH, if attr is not |
// NULL then, on success, the directory entry's attributes will be returned |
// in *attr. See MFSDirectoryEntryGetAttr for specific details on this. |
extern int MFSDirectoryEntryGetAttr( |
const void * directoryBlockPtr, |
size_t dirOffset, |
struct vnode_attr * attr |
); |
// Gets attributes for an MFS directory entry. |
// |
// directoryBlockPtr must point to an MFS directory block. See MFSMDBCheck |
// for information on how to locate these. |
// |
// dirOffset must be the offset of a directory entry within that block. |
// You typically get this by calling (MFSDirectoryBlockIterate or |
// MFSDirectoryBlockFindEntryByName). |
// |
// attr must not be NULL; it is handled as per the VFS plug-in's VNOPGetattr |
// entry point. |
// |
// Note that, with one exception, this routine always returns all of the |
// attributes that are available for the directory entry, because the cost of |
// returns those values is trivial. That is, it (typically) ignores |
// the va_active field of attr. The one exception is va_name; because getting |
// the directory entry's name requires MacRoman to UTF-8 conversion, which is |
// potentially time consuming, this routine only returns va_name if you request it. |
extern int MFSDirectoryEntryGetFinderInfo( |
const void * directoryBlockPtr, |
size_t dirOffset, |
void * finderInfoPtr |
); |
// Gets the Finder information for an MFS directory entry. |
// |
// directoryBlockPtr must point to an MFS directory block. See MFSMDBCheck |
// for information on how to locate these. |
// |
// dirOffset must be the offset of a directory entry within that block. |
// You typically get this by calling (MFSDirectoryBlockIterate or |
// MFSDirectoryBlockFindEntryByName). |
// |
// finderInfoPtr must point to a buffer of 16 bytes. On success, this |
// buffer will contain the directory entry's Finder information. |
// |
// IMPORTANT |
// MFS only supports 16 bytes of Finder information (the 16 bytes of extended |
// Finder information were added with HFS). This corresponds to the FileInfo |
// structure in "Finder.h" |
// The MFSForkInfo structure is used to return information about a file's fork. |
// |
// firstAllocationBlock is the allocation block number of the first allocation |
// block of the fork. The caller is not expected to interpret this. Rather, |
// if it needs to get the extents of the fork, it should call MFSForkGetExtent. |
// |
// lengthInBytes is the logical length of the fork. |
// |
// physicalLengthInBytes is the logical length of the fork, that is, the number |
// of bytes that it's consuming on the disk. |
struct MFSForkInfo { |
uint16_t firstAllocationBlock; |
uint32_t lengthInBytes; |
uint32_t physicalLengthInBytes; |
}; |
typedef struct MFSForkInfo MFSForkInfo; |
extern int MFSDirectoryEntryGetForkInfo( |
const void * directoryBlockPtr, |
size_t dirOffset, |
size_t forkIndex, |
MFSForkInfo * forkInfo |
); |
// Returns information about a file's fork. |
// |
// directoryBlockPtr must point to an MFS directory block. See MFSMDBCheck |
// for information on how to locate these. |
// |
// dirOffset must be the offset of a directory entry within that block. |
// You typically get this by calling (MFSDirectoryBlockIterate or |
// MFSDirectoryBlockFindEntryByName). |
// |
// forkIndex must either be 0 for the data fork or 1 for the resource fork. |
// |
// forkInfo must not be NULL. On entry, *forkInfo is ignored. On success, |
// *forkInfo contains the fork information. |
extern int MFSForkGetExtent( |
const void * mdbAndVABMPtr, |
const MFSForkInfo * forkInfo, |
uint32_t forkOffsetInBytes, |
uint32_t * offsetFromFirstAllocationBlockInBytesPtr, |
uint32_t * contiguousPhysicalBytesPtr |
); |
// Returns information about the location of a fork on disk. |
// |
// mdbAndVABMPtr must be a pointer to the combined MDB and VABM. |
// You must get this by reading X bytes starting at the MDB |
// block (kMFSMDBBlock), where X is the number returned by a call to |
// MFSMDBCheck (in the *mdbAndVABMSizeInBytesPtr parameter). |
// |
// forkInfo must be a pointer to the fork's information, as returned |
// by MFSDirectoryEntryGetForkInfo. |
// |
// forkOffsetInBytes is the offset into the fork whose location you |
// wish to obtain. This must be an even multiple of the allocation |
// block size (as returned by MFSMDBCheck). |
// |
// offsetFromFirstAllocationBlockInBytesPtr must not be NULL. |
// On success, *offsetFromFirstAllocationBlockInBytesPtr will be the |
// offset, in bytes, from the start of the first allocation block |
// to forkOffset'th byte of the fork. You can map this to a disk |
// block number by dividing it by the block size and then adding it |
// to the disk block number of the first allocation block (returned |
// by allocationBlocksStartBlockPtr). |
// |
// contiguousPhysicalBytesPtr must not be NULL. |
// On success, *contiguousPhysicalBytesPtr will be the number of |
// physically contiguous bytes of fork data to be found at |
// *offsetFromFirstAllocationBlockInBytesPtr. |
// |
// Returns 0 on success, EINVAL if you try to get an extent for a non- |
// existant fork (that is, one whose forkInfo->lengthInBytes is 0), or |
// EPIPE if there are bytes at forkOffset within the file. |
// |
// You can use this routine to find all of a fork's data by setting |
// forkOffset 0, calling this routine to get the first extent, then |
// adding contiguousPhysicalBytes to forkOffset, and repeating the call. |
// When you get EPIPE, you have all of the extents. |
enum { |
kUTF8ToMFSNameTempBufferSize = 255 * sizeof(uint16_t) |
}; |
extern errno_t UTF8ToMFSName(const char *utf8Name, size_t utf8NameLen, void *tempBuffer, uint8_t *mfsName); |
extern size_t MFSNameToUTF8(const uint8_t *name, char *utf8Name, size_t utf8NameSize); |
extern void MFSNameToUpper(uint8_t *mfsName); |
extern boolean_t MFSNameEqualToUpper(const uint8_t *mfsName, const uint8_t *mfsNameUpper); |
extern struct timespec MFSDateTimeToTimeSpec(uint32_t mfsDateTime); |
// These are exported purely for the benefit of the test engine. Thus, the comments |
// are attached to the implementation. |
// |
// Well, not quite. MFSNameToUTF8 is actually used by the MFSLives.util tool to |
// convert OSTypes to UTF-8. That's kinda lame, but the alternative was to write |
// a bunch more code that doesn't really add any value. |
#endif |
Copyright © 2006 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2006-11-09