├── msdosfs.kextproj └── msdosfs.kmodproj │ ├── msdosfs_vnops.c │ ├── kext.xcconfig │ ├── bootsect.h │ ├── msdosfs_kdebug.h │ ├── direntry.h │ ├── bpb.h │ └── fat.h ├── dpkg └── control ├── mount_msdos.tproj ├── mount_msdos.entitlements ├── iso22dos ├── koi2dos └── mount_msdos.8 ├── msdosfs.xcconfig ├── fsck_msdos.tproj ├── fsck_msdos.entitlements ├── fsck_msdos.8 └── main.c ├── msdos_util.tproj ├── msdos_util.entitlements ├── en.lproj │ └── InfoPlist.strings └── msdos.util.8 ├── newfs_msdos.tproj ├── newfs_msdos.entitlements └── newfs_msdos.8 ├── msdos_appex ├── ItemCache.h ├── msdosFileSystem.entitlements ├── msdosFileSystem.h ├── msdosItem.h ├── DirBlock.h ├── msdosVolume.h ├── msdosProgressHelper.m ├── msdosProgressHelper.h ├── ExtensionCommon.h ├── FATManager.h ├── ItemCache.m ├── utils.h ├── DirNameCache.h ├── DirBlock.m ├── FATVolume.h ├── DirItem.h ├── Info.plist └── FATItem.h ├── HexDump.py ├── code_coverage.sh ├── lib_newfs_msdos ├── lib_newfs_msdos.c ├── lib_newfs_msdos.h ├── format.h └── newfs_data_types.h ├── lib_fsck_msdos ├── fsck_msdos_errors.h ├── lib_fsck_msdos.h ├── lib_fsck_msdos.c ├── fsutil.h ├── ext.h ├── fsutil.c └── dosfs.h ├── Info-msdosfs_kext.plist ├── copy_kext.sh ├── Fuzzing └── main.c ├── Locking.rtf └── Info-msdos_fs.plist /msdosfs.kextproj/msdosfs.kmodproj/msdosfs_vnops.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apple-oss-distributions/msdosfs/HEAD/msdosfs.kextproj/msdosfs.kmodproj/msdosfs_vnops.c -------------------------------------------------------------------------------- /msdosfs.kextproj/msdosfs.kmodproj/kext.xcconfig: -------------------------------------------------------------------------------- 1 | BUILD_VARIANTS[sdk=macosx*] = normal kasan 2 | BUILD_VARIANTS[sdk=iphoneos*] = normal kasan 3 | CODE_SIGN_IDENTITY = - 4 | OTHER_CFLAGS_kasan = $(KASAN_DEFAULT_CFLAGS) 5 | -------------------------------------------------------------------------------- /dpkg/control: -------------------------------------------------------------------------------- 1 | Package: msdosfs 2 | Maintainer: Darwin Developers 3 | Description: MSDOS filesystem 4 | Build-Depends: libsystem, cctools, gcc, files, zsh, jam, file-cmds, text-cmds, shell-cmds, system-cmds, xnu, grep, architecture, csu, diskdev-cmds, corefoundation, carbonheaders 5 | -------------------------------------------------------------------------------- /mount_msdos.tproj/mount_msdos.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.rootless.restricted-block-devices 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /msdosfs.xcconfig: -------------------------------------------------------------------------------- 1 | MSDOSFS_VERSION = 1.10 2 | MSDOSFS_COPYRIGHT_INFO_STRING = $MSDOSFS_VERSION, Copyright © 2000-2021 Apple Inc. All rights reserved. 3 | FS_BUNDLE_PATH = /System/Library/Filesystems/msdos.fs 4 | FS_BUNDLE_BIN_DIR = $() 5 | FS_BUNDLE_BIN_DIR[sdk=macosx*] = Contents/Resources 6 | FS_BUNDLE_BIN_PATH = $FS_BUNDLE_PATH/$FS_BUNDLE_BIN_DIR 7 | SUPPORTED_PLATFORMS = macosx 8 | -------------------------------------------------------------------------------- /fsck_msdos.tproj/fsck_msdos.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.private.security.disk-device-access 6 | 7 | com.apple.rootless.restricted-block-devices 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /msdos_util.tproj/msdos_util.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.private.security.disk-device-access 6 | 7 | com.apple.rootless.restricted-block-devices 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /newfs_msdos.tproj/newfs_msdos.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.private.security.disk-device-access 6 | 7 | com.apple.rootless.restricted-block-devices 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /msdos_appex/ItemCache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Apple Inc. All rights reserved. 3 | */ 4 | 5 | #ifndef FileIdentityCache_h 6 | #define FileIdentityCache_h 7 | 8 | #import "FATItem.h" 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface ItemCache : NSObject 13 | 14 | -(instancetype _Nullable)initWithVolume:(FATVolume *)volume; 15 | 16 | - (void)insertItem:(FATItem *)item 17 | replyHandler:(void (^)(FATItem * _Nullable cachedItem, 18 | NSError * _Nullable error))reply; 19 | 20 | -(void)removeItem:(FATItem*)item; 21 | 22 | @end 23 | 24 | NS_ASSUME_NONNULL_END 25 | 26 | #endif /* FileIdentityCache_h */ 27 | -------------------------------------------------------------------------------- /msdos_appex/msdosFileSystem.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.application-identifier 6 | com.apple.fskit.msdos 7 | com.apple.developer.fskit.fsmodule 8 | 9 | com.apple.security.app-sandbox 10 | 11 | com.apple.security.temporary-exception.iokit-user-client-class 12 | AppleLIFSUserClient 13 | com.apple.security.exception.iokit-user-client-class 14 | AppleLIFSUserClient 15 | 16 | 17 | -------------------------------------------------------------------------------- /msdos_appex/msdosFileSystem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Apple Inc. All rights reserved. 3 | */ 4 | 5 | #import 6 | #import 7 | 8 | #include "lib_newfs_msdos.h" 9 | #import "msdosVolume.h" 10 | #import "FATVolume.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | int wipeFSCallback(newfs_client_ctx_t ctx, WipeFSProperties wipeFSProps); 15 | 16 | @interface msdosFileSystem : FSUnaryFileSystem 17 | 18 | @property msdosVolume * _Nullable volume; 19 | @property FSBlockDeviceResource * _Nullable resource; 20 | 21 | @end 22 | 23 | typedef NSArray taskParameters; 24 | 25 | NS_ASSUME_NONNULL_END 26 | -------------------------------------------------------------------------------- /msdos_util.tproj/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FSPersonalities 6 | 7 | MS-DOS 8 | 9 | FSName 10 | MS-DOS (FAT) 11 | 12 | MS-DOS FAT12 13 | 14 | FSName 15 | MS-DOS (FAT12) 16 | 17 | MS-DOS FAT16 18 | 19 | FSName 20 | MS-DOS (FAT16) 21 | 22 | MS-DOS FAT32 23 | 24 | FSName 25 | MS-DOS (FAT32) 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /HexDump.py: -------------------------------------------------------------------------------- 1 | def HexByte(byte): 2 | byte = ord(byte) 3 | digits = "0123456789ABCDEF" 4 | return digits[byte >> 4] + digits[byte & 0x0F] 5 | 6 | def HexDump(bytes, offset=0, bytesPerLine=32, offsetFormat="%08X: ", verbose=False): 7 | printable = "." * 32 + "".join(map(chr, range(32,127))) + "." * 129 8 | if offsetFormat is None or offset is None: 9 | offsetFormat = "" 10 | length = len(bytes) 11 | index = 0 12 | lastLine = "" 13 | skipping = False 14 | while index < length: 15 | if "%" in offsetFormat: 16 | offStr = offsetFormat % offset 17 | else: 18 | offStr = "" 19 | line = bytes[index:index+bytesPerLine] 20 | if line == lastLine and not verbose: 21 | if not skipping: 22 | print "*" 23 | skipping = True 24 | else: 25 | hex = " ".join(map(HexByte, line)) 26 | ascii = line.translate(printable) 27 | print "%s%-*s |%s|" % (offStr, 3*bytesPerLine, hex, ascii) 28 | lastLine = line 29 | skipping = False 30 | index += bytesPerLine 31 | offset += bytesPerLine 32 | if skipping and ("%" in offsetFormat): 33 | print offsetFormat % offset 34 | -------------------------------------------------------------------------------- /msdos_appex/msdosItem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2024 Apple Inc. All rights reserved. 3 | */ 4 | 5 | #ifndef msdosItem_h 6 | #define msdosItem_h 7 | 8 | #import 9 | #import 10 | #import "ExtensionCommon.h" 11 | #import "msdosVolume.h" 12 | #import "direntry.h" 13 | #import "FATItem.h" 14 | #import "DirItem.h" 15 | 16 | NS_ASSUME_NONNULL_BEGIN 17 | 18 | @interface MsdosDirEntryData : DirEntryData 19 | 20 | @property uint64_t dosDirEntryOffsetInDirBlock; /* offset in dir block of the dosdirentry data */ 21 | @property uint64_t dosDirEntryDirBlockNum; /* dir block number (in volume) which holds the dosdirentry data */ 22 | 23 | @end 24 | 25 | @interface MsdosDirItem: DirItem 26 | 27 | /* 28 | * Instead of iterate the directory for every shortname looking for the next 29 | * available generation number, use a single counter for the entire directory. 30 | * If we wrap around, iterate the directory next time. 31 | */ 32 | @property uint32_t maxShortNameIndex; 33 | 34 | @end 35 | 36 | 37 | @interface MsdosFileItem : FileItem 38 | 39 | -(void)waitForWrites; 40 | 41 | @end 42 | 43 | NS_ASSUME_NONNULL_END 44 | #endif /* msdosItem_h */ 45 | -------------------------------------------------------------------------------- /code_coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Run code coverage on fsck_msdos 4 | # 5 | # To use this script, you must have already built fsck_msdos using the 6 | # CodeCoverage configuration. You can do that by: 7 | # xcodebuild -target fsck_msdos -configuration CodeCoverage 8 | # 9 | 10 | OBJECTS=build/msdosfs.build/CodeCoverage/fsck_msdos.build/Objects-normal/`arch` 11 | 12 | # Remove any pre-existing samples 13 | rm -f $OBJECTS/*.gcda *.gcov 14 | 15 | # Run the tests 16 | python test_fsck.py build/CodeCoverage/fsck_msdos || exit 17 | 18 | # Run gcov on each source file 19 | for FILE in fsck_msdos.tproj/*.c; do 20 | gcov -o $OBJECTS $FILE 21 | done 22 | 23 | # Produce summaries for each file 24 | for FILE in *.gcov; do 25 | cat $FILE | awk 'BEGIN {total=0; covered=0} 26 | {if($1 != "-:") { total++; if($1 != "#####:") covered++}} 27 | END {printf("%f%% of %d lines covered", 100 * covered/total, total)}' 28 | echo " for ${FILE%.gcov}" 29 | done 30 | 31 | # Produce an overall percentage of coverage 32 | find . -name "*.gcov" | xargs cat | awk 'BEGIN {total=0; covered=0} 33 | {if($1 != "-:") { total++; if($1 != "#####:") covered++}} 34 | END {printf("Total: %f%% of %d lines covered\n", 100 * covered/total, total)}' 35 | -------------------------------------------------------------------------------- /msdos_appex/DirBlock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Apple Inc. All rights reserved. 3 | */ 4 | 5 | #ifndef DirBlock_h 6 | #define DirBlock_h 7 | 8 | #import "DirItem.h" 9 | 10 | @interface DirBlock : NSObject 11 | 12 | @property uint64_t offsetInVolume; /* Offset within the file system */ 13 | 14 | -(instancetype)initInDir:(DirItem *)dirItem; 15 | 16 | -(void)releaseBlock; 17 | 18 | /** Reads the specified dir block number (which is relative to volume start) into the dir block. */ 19 | -(NSError *)readDirBlockNum:(uint64_t)dirBlockNumberInVolume; 20 | 21 | /** Reads the specified dir block number (which is relative to dir start) into the dir block. */ 22 | -(NSError *)readRelativeDirBlockNum:(uint32_t)dirBlockIdxInDir; 23 | 24 | /** Returns a pointer to the dir block's data, at the given offset. */ 25 | -(void *)getBytesAtOffset:(uint64_t)offsetInDirBlock; 26 | 27 | -(NSError *)setBytes:(NSData *)data 28 | atOffset:(uint64_t)offsetInDirBlock; 29 | 30 | /** Write the whole dir block to disk. */ 31 | -(NSError *)writeToDisk; 32 | 33 | /** Write a part of the dir block to disk. */ 34 | -(NSError *)writeToDiskFromOffset:(uint64_t)offsetInDirBlock 35 | length:(uint64_t)lengthToWrite; 36 | 37 | @end 38 | 39 | 40 | 41 | 42 | #endif /* DirBlock_h */ 43 | -------------------------------------------------------------------------------- /msdos_appex/msdosVolume.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Apple Inc. All rights reserved. 3 | */ 4 | 5 | #ifndef msdosVolume_h 6 | #define msdosVolume_h 7 | 8 | #import 9 | #import "FATVolume.h" 10 | 11 | #define MSDOS_FAT_BLOCKSIZE(offset, fatSize) (((offset) + FAT_BLOCKSIZE > (fatSize)) ? (fatSize) - (offset) : FAT_BLOCKSIZE) 12 | 13 | #define MSDOSFS_XATTR_VOLUME_ID_NAME "com.apple.filesystems.msdosfs.volume_id" 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | @interface msdosVolume : FATVolume 18 | 19 | @property bool isVolumeDirty; 20 | @property fatType type; 21 | 22 | -(int)ScanBootSector; 23 | 24 | -(instancetype)initWithResource:(FSResource *)resource 25 | volumeID:(FSVolumeIdentifier *)volumeID 26 | volumeName:(NSString *)volumeName; 27 | 28 | @end 29 | 30 | 31 | @interface FileSystemInfo() 32 | 33 | @property uint32_t rootDirSize; // Root dir size in sectors 34 | @property uint64_t metaDataZoneSize; 35 | @property uint32_t fsInfoSectorNumber; // FAT32 only, 0 for FAT12/16 36 | @property NSMutableData *fsInfoSector; // FAT32 only 37 | 38 | @end 39 | 40 | @interface msdosVolume() 41 | 42 | @property FSOperations * fsOps; 43 | 44 | @end 45 | 46 | NS_ASSUME_NONNULL_END 47 | 48 | #endif /* msdosVolume_h */ 49 | -------------------------------------------------------------------------------- /lib_newfs_msdos/lib_newfs_msdos.c: -------------------------------------------------------------------------------- 1 | // 2 | // lib_newfs_msdos.c 3 | // newfs_msdos 4 | // 5 | // Created by Kujan Lauz on 04/09/2022. 6 | // 7 | 8 | #include 9 | #include "lib_newfs_msdos.h" 10 | 11 | 12 | lib_newfs_ctx_t newfs_ctx; 13 | 14 | void newfs_set_context_properties(newfs_msdos_print_funct_t print, 15 | newfs_msdos_wipefs_func_t wipefs, 16 | newfs_client_ctx_t client) 17 | { 18 | newfs_ctx.wipefs = wipefs; 19 | newfs_ctx.print = print; 20 | newfs_ctx.client_ctx = client; 21 | } 22 | 23 | void newfs_print(lib_newfs_ctx_t c, int level, const char *fmt, ...) 24 | { 25 | if (c.print) { 26 | va_list ap; 27 | va_start(ap, fmt); 28 | c.print(c.client_ctx, level, fmt, ap); 29 | va_end(ap); 30 | } 31 | } 32 | 33 | newfs_msdos_wipefs_func_t newfs_get_wipefs_function_callback(void) { 34 | return newfs_ctx.wipefs; 35 | } 36 | 37 | void newfs_set_wipefs_function_callback(newfs_msdos_wipefs_func_t func) { 38 | newfs_ctx.wipefs = func; 39 | } 40 | 41 | newfs_msdos_print_funct_t newfs_get_print_function_callback(void) { 42 | return newfs_ctx.print; 43 | } 44 | 45 | void newfs_set_print_function_callback(newfs_msdos_print_funct_t func) { 46 | newfs_ctx.print = func; 47 | } 48 | 49 | newfs_client_ctx_t newfs_get_client(void) { 50 | return newfs_ctx.client_ctx; 51 | } 52 | 53 | void newfs_set_client (newfs_client_ctx_t c) { 54 | newfs_ctx.client_ctx = c; 55 | } 56 | -------------------------------------------------------------------------------- /lib_fsck_msdos/fsck_msdos_errors.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Apple Inc. All rights reserved. 3 | * 4 | * lib_fsck_msdos 5 | * fsck_msdos_errors.h 6 | * 7 | * This file contain error numbers that are returned from checkfilesys. 8 | * We want the error codes to be unique so we can recognize each error case by 9 | * the error code we get from telemetry. 10 | */ 11 | 12 | #ifndef _FSCK_MSDOS_ERRORS_H 13 | #define _FSCK_MSDOS_ERRORS_H 14 | 15 | enum fsck_msdos_errors { 16 | /* 17 | * Starting from 100 to not collide with POSIX error codes which may be 18 | * returned from pread/pwrite during fsck run (to keep our error codes unique). 19 | */ 20 | fsckErrQuickCheckDirty = 200, /* File system was found dirty in quick check. */ 21 | fsckErrBootRegionInvalid, /* Couldn't read the boot region, or it contains a non-recoverable corruption. */ 22 | fsckErrCouldNotInitFAT, /* Got a fatal error while initializing the FAT structure. */ 23 | fsckErrCouldNotInitRootDir, /* Got a fatal error while initializing the root dir structure. */ 24 | fsckErrCouldNotScanDirs, /* Got a fatal error while scanning the volume's directory hierarchy. */ 25 | fsckErrCouldNotFreeUnused, /* Got a fatal error while freeing unused clusters in the FAT. */ 26 | fsckErrCannotRepairReadOnly, /* Volume cannot be repaired because we're on read-only mode. */ 27 | fsckErrCannotRepairAfterRetry, /* Volume couldn't be repaired after one or more retries. */ 28 | }; 29 | 30 | #endif /* _FSCK_MSDOS_ERRORS_H */ 31 | 32 | -------------------------------------------------------------------------------- /Info-msdosfs_kext.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | msdosfs 9 | CFBundleIconFile 10 | 11 | CFBundleGetInfoString 12 | $MSDOSFS_COPYRIGHT_INFO_STRING 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | msdosfs 19 | CFBundlePackageType 20 | KEXT 21 | CFBundleShortVersionString 22 | $(MSDOSFS_VERSION) 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | $(MSDOSFS_VERSION) 27 | IOKitPersonalities 28 | 29 | OSBundleAllowUserLoad 30 | 31 | OSBundleLibraries 32 | 33 | com.apple.kpi.bsd 34 | 8.0.0 35 | com.apple.kpi.libkern 36 | 9.0.0 37 | com.apple.kpi.mach 38 | 8.0.0 39 | com.apple.kpi.unsupported 40 | 8.0.0 41 | com.apple.kpi.private 42 | 15 43 | com.apple.kpi.iokit 44 | 15.0 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /msdos_appex/msdosProgressHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // msdosProgressHelper.m 3 | // msdos.appex 4 | // 5 | // Created by William Stouder-Studenmund on 5/1/24. 6 | // 7 | 8 | #import "msdosProgressHelper.h" 9 | #import 10 | 11 | @implementation msdosProgressHelper 12 | 13 | -(nullable instancetype)initWithProgress:(NSProgress *)progress 14 | { 15 | self = [super init]; 16 | if (self) { 17 | _parentProgress = progress; 18 | _childProgress = nil; 19 | } 20 | return self; 21 | } 22 | 23 | -(NSError* _Nullable)startPhase:(NSString *)description 24 | parentUnitCount:(int64_t)parentUnitCount 25 | phaseTotalCount:(int64_t)phaseTotalCount 26 | completedCounter:(const unsigned int *)completedCounter 27 | { 28 | if (_childProgress != nil) { 29 | // We are in the middle a phase - expect it to end before starting a new one. 30 | os_log_fault(OS_LOG_DEFAULT, "%s missing endPhase call for %@", __FUNCTION__, _parentProgress.localizedDescription); 31 | return fs_errorForPOSIXError(EINVAL); 32 | } 33 | 34 | _parentProgress.localizedDescription = description; 35 | _childProgress = [NSProgress progressWithTotalUnitCount:phaseTotalCount]; 36 | [_parentProgress addChild:_childProgress withPendingUnitCount:parentUnitCount]; 37 | 38 | return nil; 39 | } 40 | 41 | -(void)endPhase:(NSString *)description 42 | { 43 | // We expect to be called for cleanup once sometime after startPhase got called. 44 | // Silently do nothing if we got unexpected end call 45 | if (_childProgress) { 46 | _parentProgress.localizedDescription = description; 47 | _childProgress.completedUnitCount = _childProgress.totalUnitCount; 48 | _childProgress = nil; 49 | } 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /lib_fsck_msdos/lib_fsck_msdos.h: -------------------------------------------------------------------------------- 1 | // 2 | // lib_fsck_msdos.h 3 | // fsck_msdos 4 | // 5 | // Created by Kujan Lauz on 25/08/2022. 6 | // 7 | 8 | #ifndef lib_fsck_msdos_h 9 | #define lib_fsck_msdos_h 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | typedef void* fsck_client_ctx_t; 16 | 17 | /** Prints message */ 18 | typedef void (*fsck_msdos_print_funct_t)(fsck_client_ctx_t, int level, const char *fmt, va_list ap); 19 | 20 | /** Asks the user a YES/NO question */ 21 | typedef int (*fsck_msdos_ask_func_t)(fsck_client_ctx_t, int def, const char *fmt, va_list ap); 22 | 23 | /** Struct containing pointer functions to our print functions */ 24 | typedef struct { 25 | fsck_msdos_print_funct_t print; 26 | fsck_msdos_ask_func_t ask; 27 | fsck_client_ctx_t client_ctx; 28 | } lib_fsck_ctx_t; 29 | 30 | /** Sets up the print/ask functions, this method should be called before running checkfilesystem */ 31 | void fsck_set_context_properties(fsck_msdos_print_funct_t print, 32 | fsck_msdos_ask_func_t ask, 33 | fsck_client_ctx_t client); 34 | 35 | void fsck_set_alwaysyes(bool alwaysyes); 36 | bool fsck_alwaysyes(void); 37 | 38 | void fsck_set_alwaysno(bool alwaysno); 39 | bool fsck_alwaysno(void); 40 | 41 | void fsck_set_preen(bool preen); 42 | bool fsck_preen(void); 43 | 44 | void fsck_set_quick(bool quick); 45 | bool fsck_quick(void); 46 | 47 | void fsck_set_quiet(bool quiet); 48 | bool fsck_quiet(void); 49 | 50 | void fsck_set_rdonly(bool rdonly); 51 | bool fsck_rdonly(void); 52 | 53 | void fsck_set_maxmem(size_t maxmem); 54 | size_t fsck_maxmem(void); 55 | 56 | void fsck_set_dev(const char* dev); 57 | const char* fsck_dev(void); 58 | 59 | void fsck_set_fd(int fd); 60 | int fsck_fd(void); 61 | 62 | void fsck_print(lib_fsck_ctx_t, int level, const char *fmt, ...) __printflike(3, 4); 63 | int fsck_ask(lib_fsck_ctx_t, int def, const char *fmt, ...) __printflike(3, 4); 64 | 65 | /** Instance containing the function pointers for running fsck_msdos */ 66 | extern lib_fsck_ctx_t fsck_ctx; 67 | 68 | #endif /* lib_fsck_msdos_h */ 69 | -------------------------------------------------------------------------------- /msdos_appex/msdosProgressHelper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Apple Inc. All rights reserved. 3 | */ 4 | 5 | #import 6 | 7 | NS_ASSUME_NONNULL_BEGIN 8 | 9 | /** 10 | @class msdosProgressHelper 11 | @abstract Class to help manage phases of work, Especially helpful in a C/CF bridged environment 12 | @discussion This class serves to help work with nested NSProgress objects in a C/CF environment. It acts as function calls and a context. 13 | */ 14 | @interface msdosProgressHelper : NSObject 15 | 16 | - (instancetype)init NS_UNAVAILABLE; 17 | 18 | - (nullable instancetype)initWithProgress:(NSProgress *)progress; 19 | 20 | /* 21 | * startPhase: and endPhase: 22 | * 23 | * Start or end a phase of our overall progress object. This phase will 24 | * consume `parentUnitCount` of the parent's work. For instance, if one phase 25 | * of work represents 20 of the parent's 100 units, this parameter would be 20. 26 | * This phase of work will, itself, have `phaseTotalCount` items of work. 27 | * 28 | * This API was designed to support being used to wrap an existing, unmodified 29 | * for loop as in: 30 | * 31 | * unsigned int loop_counter = 0; 32 | * [helper startPhase:... completedCounter:&loop_counter]; 33 | * for(cluster_num = 0; cluster_num < number_of_clusters_to_process; cluster_num++) { 34 | * loop_counter = cluster_num; 35 | * .. do work 36 | * } 37 | * [helper endPhase:...]; 38 | * 39 | * Currently we don't use it as such, so we don't use completedCounter. 40 | */ 41 | 42 | /** 43 | @method startPhase:parentUnitCount:phaseTotalCount:completedCounter: - start a phase of work on the parent 44 | @param description string describing the work being done 45 | @param parentUnitCount count of units in the parent work space being done in this phase 46 | @param phaseTotalCount count of ujits of work in this sub-phase 47 | @param completedCounter pointer to an unsigned int storing the current step of work 48 | */ 49 | - (NSError* _Nullable)startPhase:(NSString *)description 50 | parentUnitCount:(int64_t)parentUnitCount 51 | phaseTotalCount:(int64_t)phaseTotalCount 52 | completedCounter:(const unsigned int *)completedCounter; 53 | 54 | - (void)endPhase:(NSString *)description; 55 | 56 | @property (retain) NSProgress *parentProgress; 57 | @property (nullable, retain) NSProgress *childProgress; 58 | 59 | @end 60 | 61 | NS_ASSUME_NONNULL_END 62 | -------------------------------------------------------------------------------- /mount_msdos.tproj/iso22dos: -------------------------------------------------------------------------------- 1 | # $FreeBSD: src/sbin/mount_msdos/iso22dos,v 1.1 2000/01/08 17:17:32 ache Exp $ 2 | # 3 | # u2w: 16 rows of Latin2 -> Unicode conversion table (upper half) 4 | # 5 | 0x0080 0x0081 0x0082 0x0083 0x0084 0x0085 0x0086 0x0087 6 | 0x0088 0x0089 0x008a 0x008b 0x008c 0x008d 0x008e 0x008f 7 | 0x0090 0x0091 0x0092 0x0093 0x0094 0x0095 0x0096 0x0097 8 | 0x0098 0x0099 0x009a 0x009b 0x009c 0x009d 0x009e 0x009f 9 | 0x00a0 0x0104 0x02d8 0x0141 0x00a4 0x013d 0x015a 0x00a7 10 | 0x00a8 0x0160 0x015e 0x0164 0x0179 0x00ad 0x017d 0x017b 11 | 0x00b0 0x0105 0x02db 0x0142 0x00b4 0x013e 0x015b 0x02c7 12 | 0x00b8 0x0161 0x015f 0x0165 0x017a 0x02dd 0x017e 0x017c 13 | 0x0154 0x00c1 0x00c2 0x0102 0x00c4 0x0139 0x0106 0x00c7 14 | 0x010c 0x00c9 0x0118 0x00cb 0x011a 0x00cd 0x00ce 0x010e 15 | 0x0110 0x0143 0x0147 0x00d3 0x00d4 0x0150 0x00d6 0x00d7 16 | 0x0158 0x016e 0x00da 0x0170 0x00dc 0x00dd 0x0162 0x00df 17 | 0x0155 0x00e1 0x00e2 0x0103 0x00e4 0x013a 0x0107 0x00e7 18 | 0x010d 0x00e9 0x0119 0x00eb 0x011b 0x00ed 0x00ee 0x010f 19 | 0x0111 0x0144 0x0148 0x00f3 0x00f4 0x0151 0x00f6 0x00f7 20 | 0x0159 0x016f 0x00fa 0x0171 0x00fc 0x00fd 0x0163 0x02d9 21 | # 22 | # d2u: 16 rows of CP852 -> Latin2 conversion table (upper half) 23 | # 24 | 0xc7 0xfc 0xe9 0xe2 0xe4 0xf9 0xe6 0xe7 25 | 0xb3 0xeb 0xd5 0xf5 0xee 0xac 0xc4 0xc6 26 | 0xc9 0xc5 0xe5 0xf4 0xf6 0xa5 0xb5 0xa6 27 | 0xb6 0xd6 0xdc 0xab 0xbb 0xa3 0xd7 0xe8 28 | 0xe1 0xed 0xf3 0xfa 0xa1 0xb1 0xae 0xbe 29 | 0xca 0xea 0x3f 0xbc 0xc8 0xba 0x3f 0x3f 30 | 0x3f 0x3f 0x3f 0x3f 0x3f 0xc1 0xc2 0xcc 31 | 0xaa 0x3f 0x3f 0x3f 0x3f 0xaf 0xbf 0x3f 32 | 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0xc3 0xe3 33 | 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0x3f 0xa4 34 | 0xf0 0xd0 0xcf 0xcb 0xef 0xd2 0xcd 0xce 35 | 0xec 0x3f 0x3f 0x3f 0x3f 0xde 0xd9 0x3f 36 | 0xd3 0xdf 0xd4 0xd1 0xf1 0xf2 0xa9 0xb9 37 | 0xc0 0xda 0xe0 0xdb 0xfd 0xdd 0xfe 0xb4 38 | 0xad 0xbd 0xb2 0xb7 0xa2 0xa7 0xf7 0xb8 39 | 0xb0 0xa8 0xff 0xfb 0xd8 0xf8 0x3f 0xa0 40 | # 41 | # u2d: 16 rows of Latin2 -> CP852 conversion table (upper half) 42 | # 43 | 0 0 0 0 0 0 0 0 44 | 0 0 0 0 0 0 0 0 45 | 0 0 0 0 0 0 0 0 46 | 0 0 0 0 0 0 0 0 47 | 0xff 0xa4 0xf4 0x9d 0xcf 0x95 0x97 0xf5 48 | 0xf9 0xe6 0xb8 0x9b 0x8d 0xf0 0xa6 0xbd 49 | 0xf8 0xa5 0xf2 0x88 0xef 0x96 0x98 0xf3 50 | 0xf7 0xe7 0xad 0x9c 0xab 0xf1 0xa7 0xbe 51 | 0xe8 0xb5 0xb6 0xc6 0x8e 0x91 0x8f 0x80 52 | 0xac 0x90 0xa8 0xd3 0xb7 0xd6 0xd7 0xd2 53 | 0xd1 0xe3 0xd5 0xe0 0xe2 0x8a 0x99 0x9e 54 | 0xfc 0xde 0xe9 0xeb 0x9a 0xed 0xdd 0xe1 55 | 0xea 0xa0 0x83 0xc7 0x84 0x92 0x86 0x87 56 | 0x9f 0x82 0xa9 0x89 0xd8 0xa1 0x8c 0xd4 57 | 0xd0 0xe4 0xe5 0xa2 0x93 0x8b 0x94 0xf6 58 | 0xfd 0x85 0xa3 0xfb 0x81 0xec 0xee 0xfa 59 | -------------------------------------------------------------------------------- /mount_msdos.tproj/koi2dos: -------------------------------------------------------------------------------- 1 | # $FreeBSD: src/sbin/mount_msdos/koi2dos,v 1.2 2000/01/08 16:47:54 ache Exp $ 2 | # 3 | # u2w: 16 rows of KOI8-R -> Unicode conversion table (upper half) 4 | # 5 | 0x2500 0x2502 0x250c 0x2510 0x2514 0x2518 0x251c 0x2524 6 | 0x252c 0x2534 0x253c 0x2580 0x2584 0x2588 0x258c 0x2590 7 | 0x2591 0x2592 0x2593 0x2320 0x25a0 0x2219 0x221a 0x2248 8 | 0x2264 0x2265 0x00a0 0x2321 0x00b0 0x00b2 0x00b7 0x00f7 9 | 0x2550 0x2551 0x2552 0x0451 0x2553 0x2554 0x2555 0x2556 10 | 0x2557 0x2558 0x2559 0x255a 0x255b 0x255c 0x255d 0x255e 11 | 0x255f 0x2560 0x2561 0x0401 0x2562 0x2563 0x2564 0x2565 12 | 0x2566 0x2567 0x2568 0x2569 0x256a 0x256b 0x256c 0x00a9 13 | 0x044e 0x0430 0x0431 0x0446 0x0434 0x0435 0x0444 0x0433 14 | 0x0445 0x0438 0x0439 0x043a 0x043b 0x043c 0x043d 0x043e 15 | 0x043f 0x044f 0x0440 0x0441 0x0442 0x0443 0x0436 0x0432 16 | 0x044c 0x044b 0x0437 0x0448 0x044d 0x0449 0x0447 0x044a 17 | 0x042e 0x0410 0x0411 0x0426 0x0414 0x0415 0x0424 0x0413 18 | 0x0425 0x0418 0x0419 0x041a 0x041b 0x041c 0x041d 0x041e 19 | 0x041f 0x042f 0x0420 0x0421 0x0422 0x0423 0x0416 0x0412 20 | 0x042c 0x042b 0x0417 0x0428 0x042d 0x0429 0x0427 0x042a 21 | # 22 | # d2u: 16 rows of CP866 -> KOI8-R conversion table (upper half) 23 | # 24 | 0xe1 0xe2 0xf7 0xe7 0xe4 0xe5 0xf6 0xfa 25 | 0xe9 0xea 0xeb 0xec 0xed 0xee 0xef 0xf0 26 | 0xf2 0xf3 0xf4 0xf5 0xe6 0xe8 0xe3 0xfe 27 | 0xfb 0xfd 0xff 0xf9 0xf8 0xfc 0xe0 0xf1 28 | 0xc1 0xc2 0xd7 0xc7 0xc4 0xc5 0xd6 0xda 29 | 0xc9 0xca 0xcb 0xcc 0xcd 0xce 0xcf 0xd0 30 | 0x90 0x91 0x92 0x81 0x87 0xb2 0xb4 0xa7 31 | 0xa6 0xb5 0xa1 0xa8 0xae 0xad 0xac 0x83 32 | 0x84 0x89 0x88 0x86 0x80 0x8a 0xaf 0xb0 33 | 0xab 0xa5 0xbb 0xb8 0xb1 0xa0 0xbe 0xb9 34 | 0xba 0xb6 0xb7 0xaa 0xa9 0xa2 0xa4 0xbd 35 | 0xbc 0x85 0x82 0x8d 0x8c 0x8e 0x8f 0x8b 36 | 0xd2 0xd3 0xd4 0xd5 0xc6 0xc8 0xc3 0xde 37 | 0xdb 0xdd 0xdf 0xd9 0xd8 0xdc 0xc0 0xd1 38 | 0xb3 0xa3 229 197 73 105 245 213 39 | 0x9c 0x95 0x9e 0x96 78 210 0x94 0x9a 40 | # 41 | # u2d: 16 rows of KOI8-R -> CP866 conversion table (upper half) 42 | # 43 | 0xc4 0xb3 0xda 0xbf 0xc0 0xd9 0xc3 0xb4 44 | 0xc2 0xc1 0xc5 0xdf 0xdc 0xdb 0xdd 0xde 45 | 0xb0 0xb1 0xb2 179 0xfe 0xf9 0xfb 61 46 | 60 62 0xff 179 0xf8 50 0xfa 58 47 | 0xcd 0xba 0xd5 0xf1 0xd6 0xc9 0xb8 0xb7 48 | 0xbb 0xd4 0xd3 0xc8 0xbe 0xbd 0xbc 0xc6 49 | 0xc7 0xcc 0xb5 0xf0 0xb6 0xb9 0xd1 0xd2 50 | 0xcb 0xcf 0xd0 0xca 0xd8 0xd7 0xce 99 51 | 0xee 0xa0 0xa1 0xe6 0xa4 0xa5 0xe4 0xa3 52 | 0xe5 0xa8 0xa9 0xaa 0xab 0xac 0xad 0xae 53 | 0xaf 0xef 0xe0 0xe1 0xe2 0xe3 0xa6 0xa2 54 | 0xec 0xeb 0xa7 0xe8 0xed 0xe9 0xe7 0xea 55 | 0x9e 0x80 0x81 0x96 0x84 0x85 0x94 0x83 56 | 0x95 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 57 | 0x8f 0x9f 0x90 0x91 0x92 0x93 0x86 0x82 58 | 0x9c 0x9b 0x87 0x98 0x9d 0x99 0x97 0x9a 59 | -------------------------------------------------------------------------------- /copy_kext.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copy the Development build (as built by Xcode) of msdosfs.kext to one or 4 | # more test machines. It will unload the kext if previously loaded, 5 | # touch /System/Library/Extensions to invalidate the KEXT cache, manually 6 | # load the new KEXT, and copy the symbols back to the development machine 7 | # (in a directory named for the target machine). 8 | # 9 | # The target machine host names are passed as command line arguments. If 10 | # there are no command line arguments, but $MACHINE is set, then the target 11 | # host name is in $MACHINE. It is an error if there are no command line 12 | # arguments and $MACHINE is not set. 13 | # 14 | # This script doesn't currently handle the case where the KEXT cannot be 15 | # unloaded (usually because a volume is still mounted). It will just copy 16 | # the new KEXT over and fail to load it. 17 | # 18 | # Note that the kext gets copied to the current user's home directory 19 | # on the target machine. That way, if it panics, you can always reboot 20 | # and get the standard KEXT from /System/Library/Extensions. 21 | # 22 | # Also note that this script assumes it can SSH as root to the target 23 | # machine. In a default install, root has no password, and no SSH keys, 24 | # so SSH to root fails unless you give root a password or SSH keys. I prefer 25 | # to set up root's SSH authorized keys to be my user's keys, so my user 26 | # can SSH to root without any prompt. Here's how I do it: 27 | # 28 | # ~ $ sudo -s 29 | # Password: 30 | # ~ # cd ~root 31 | # ~root # mkdir .ssh 32 | # ~root # cp ~mark/.ssh/authorized_keys* .ssh 33 | # ~root # exit 34 | # ~ $ 35 | # 36 | 37 | configuration=Debug 38 | kext=msdosfs 39 | 40 | if [ "$1" = "-config" ]; then 41 | configuration="$2" 42 | shift 2 43 | fi 44 | 45 | if [ $# -eq 0 ]; then 46 | if [ -z "$MACHINE" ]; then 47 | echo 'No arguments, and $MACHINE not set!' 1>&2 48 | exit 1 49 | fi 50 | set $MACHINE 51 | fi 52 | 53 | # 54 | # Determine the $BUILT_PRODUCTS_DIR for the given configuration 55 | # 56 | BUILT_PRODUCTS_DIR=$(xcodebuild -configuration $configuration -showBuildSettings 2>/dev/null | sed -n -E '1,$ s/[ \t]+BUILT_PRODUCTS_DIR = //p') 57 | 58 | for m 59 | do 60 | ssh root@$m kextunload -b com.apple.filesystems.${kext} 61 | scp -r "$BUILT_PRODUCTS_DIR/${kext}.kext" root@$m:"/var/tmp" 62 | ssh root@$m chgrp -R wheel "/var/tmp/${kext}.kext" 63 | ssh root@$m touch /System/Library/Extensions 64 | ssh root@$m kextutil -c -s /tmp "/var/tmp/${kext}.kext" || exit 65 | mkdir -p /tmp/$m 66 | scp root@$m:/tmp/"com.apple.*.sym" /tmp/$m 67 | rm -rf /tmp/$m/${kext}.kext{,.dSYM} 68 | cp -r "$BUILT_PRODUCTS_DIR/${kext}.kext"{,.dSYM} /tmp/$m 69 | done 70 | -------------------------------------------------------------------------------- /lib_fsck_msdos/lib_fsck_msdos.c: -------------------------------------------------------------------------------- 1 | // 2 | // lib_fsck_msdos.c 3 | // fsck_msdos 4 | // 5 | // Created by Kujan Lauz on 25/08/2022. 6 | // 7 | 8 | #include "lib_fsck_msdos.h" 9 | 10 | /** Struct containing the preferenes on running fsck_msdos */ 11 | typedef struct { 12 | int alwaysno; /* assume "no" for all questions */ 13 | int alwaysyes; /* assume "yes" for all questions */ 14 | int preen; /* set when preening */ 15 | int quick; /* set to quickly check if volume is dirty */ 16 | int quiet; /* set to supress most messages */ 17 | int rdonly; /* device is opened read only (supersedes above) */ 18 | size_t maxmem; /* If non-zero, limit major allocations to this many bytes */ 19 | const char *dev; /* Device name */ 20 | int fd; /* File descriptor */ 21 | } fsck_state_t; 22 | 23 | fsck_state_t fsck_state; 24 | lib_fsck_ctx_t fsck_ctx; 25 | 26 | void fsck_set_context_properties(fsck_msdos_print_funct_t print, 27 | fsck_msdos_ask_func_t ask, 28 | fsck_client_ctx_t client) 29 | { 30 | fsck_ctx.print = print; 31 | fsck_ctx.ask = ask; 32 | fsck_ctx.client_ctx = client; 33 | fsck_state.fd = -1; 34 | } 35 | 36 | void fsck_set_alwaysyes(bool alwaysyes) 37 | { 38 | fsck_state.alwaysyes = alwaysyes; 39 | } 40 | 41 | bool fsck_alwaysyes(void) 42 | { 43 | return fsck_state.alwaysyes; 44 | } 45 | 46 | void fsck_set_alwaysno(bool alwaysno) 47 | { 48 | fsck_state.alwaysno = alwaysno; 49 | } 50 | 51 | bool fsck_alwaysno(void) 52 | { 53 | return fsck_state.alwaysno; 54 | } 55 | 56 | void fsck_set_preen(bool preen) 57 | { 58 | fsck_state.preen = preen; 59 | } 60 | 61 | bool fsck_preen(void) 62 | { 63 | return fsck_state.preen; 64 | } 65 | 66 | void fsck_set_quick(bool quick) 67 | { 68 | fsck_state.quick = quick; 69 | } 70 | bool fsck_quick(void) 71 | { 72 | return fsck_state.quick; 73 | } 74 | 75 | void fsck_set_quiet(bool quiet) 76 | { 77 | fsck_state.quiet = quiet; 78 | } 79 | bool fsck_quiet(void) 80 | { 81 | return fsck_state.quiet; 82 | } 83 | 84 | void fsck_set_rdonly(bool rdonly) 85 | { 86 | fsck_state.rdonly = rdonly; 87 | } 88 | bool fsck_rdonly(void) 89 | { 90 | return fsck_state.rdonly; 91 | } 92 | 93 | void fsck_set_maxmem(size_t maxmem) 94 | { 95 | fsck_state.maxmem = maxmem; 96 | } 97 | 98 | size_t fsck_maxmem(void) 99 | { 100 | return fsck_state.maxmem; 101 | } 102 | 103 | void fsck_set_dev(const char* dev) 104 | { 105 | fsck_state.dev = dev; 106 | } 107 | 108 | const char* fsck_dev(void) 109 | { 110 | return fsck_state.dev; 111 | } 112 | 113 | void fsck_set_fd(int fd) 114 | { 115 | fsck_state.fd = fd; 116 | } 117 | int fsck_fd(void) 118 | { 119 | return fsck_state.fd; 120 | } 121 | -------------------------------------------------------------------------------- /lib_newfs_msdos/lib_newfs_msdos.h: -------------------------------------------------------------------------------- 1 | // 2 | // lib_newfs_msdos.h 3 | // msdosfs 4 | // 5 | // Created by Kujan Lauz on 04/09/2022. 6 | // 7 | 8 | #ifndef lib_newfs_msdos_h 9 | #define lib_newfs_msdos_h 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | typedef void* newfs_client_ctx_t; 17 | 18 | /** Struct containing fields required for running newfs, some of these fields can only be collected by a root level process, or by an entitled process. 19 | The fields in the struct are expected to initialized to 0 (memset), so if a field is not set it will be 0. 20 | */ 21 | typedef struct { 22 | int fd; /* File descriptor */ 23 | const char *devName; /* Device name */ 24 | uint32_t physBlockSize; /* Physical block size */ 25 | uint64_t partitionBase; /* Partition offset */ 26 | uint64_t blockCount; /* Block count */ 27 | uint32_t blockSize; /* Block size */ 28 | const char *bname; /* Bootstrap file */ 29 | int bootFD; /* Bootstrap file descriptor */ 30 | struct stat sb; /* File stats */ 31 | } NewfsProperties; 32 | 33 | typedef struct { 34 | int fd; 35 | size_t block_size; 36 | u_int except_block_start; 37 | u_int except_block_length; 38 | } WipeFSProperties; 39 | 40 | /** Prints message */ 41 | typedef void (*newfs_msdos_print_funct_t)(newfs_client_ctx_t, int level, const char *fmt, va_list ap); 42 | 43 | /** WipeFS function, wipes a resource by given properties */ 44 | typedef int (*newfs_msdos_wipefs_func_t)(newfs_client_ctx_t ctx, WipeFSProperties props); 45 | 46 | /** Struct containing pointer functions to our print functions */ 47 | typedef struct { 48 | newfs_msdos_print_funct_t print; 49 | newfs_msdos_wipefs_func_t wipefs; 50 | newfs_client_ctx_t client_ctx; 51 | } lib_newfs_ctx_t; 52 | 53 | extern lib_newfs_ctx_t newfs_ctx; 54 | 55 | void newfs_set_context_properties(newfs_msdos_print_funct_t print, newfs_msdos_wipefs_func_t wipefs, newfs_client_ctx_t client); 56 | void newfs_print(lib_newfs_ctx_t c, int level, const char *fmt, ...) __printflike(3, 4); 57 | 58 | /* Setters and getters for library properties */ 59 | newfs_msdos_wipefs_func_t newfs_get_wipefs_function_callback(void); 60 | void newfs_set_wipefs_function_callback(newfs_msdos_wipefs_func_t func); 61 | 62 | newfs_msdos_print_funct_t newfs_get_print_function_callback(void); 63 | void newfs_set_print_function_callback(newfs_msdos_print_funct_t func); 64 | 65 | newfs_client_ctx_t newfs_get_client(void); 66 | void newfs_set_client (newfs_client_ctx_t c); 67 | 68 | /* Wipes target device by calling directly to wipefs library */ 69 | int wipefs(newfs_client_ctx_t ctx, WipeFSProperties props); 70 | 71 | #endif /* lib_newfs_msdos_h */ 72 | -------------------------------------------------------------------------------- /msdos_util.tproj/msdos.util.8: -------------------------------------------------------------------------------- 1 | .\""Copyright (c) 2001 Apple Computer, Inc. All Rights Reserved. 2 | .\"The contents of this file constitute Original Code as defined in and are 3 | .\"subject to the Apple Public Source License Version 1.2 (the 'License'). 4 | .\"You may not use this file except in compliance with the 5 | .\"License. Please obtain a copy of the License at 6 | .\"http://www.apple.com/publicsource and read it before using this file. 7 | .\" 8 | .\"This Original Code and all software distributed under the License are 9 | .\"distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 10 | .\"EXPRESS OR IMPLIED, AND APPLE 11 | .\"HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY 12 | .\"WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 13 | .\"QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 14 | .\"specific language governing rights and limitations under the License." 15 | .Dd March 24, 2001 16 | .Dt MSDOS.UTIL 8 17 | .Os Darwin 18 | .Sh NAME 19 | .Nm msdos.util 20 | .Nd DOS/Windows (FAT) file system utility 21 | .Sh SYNOPSIS 22 | .Nm 23 | .Fl m Ar mountflag1 mountflag2 mountflag3 mountflag4 24 | .Ar device node 25 | .Pp 26 | .Nm 27 | .Fl p Ar mountflag1 mountflag2 mountflag3 mountflag4 28 | .Ar device 29 | .Pp 30 | .Nm 31 | .Fl u 32 | .Ar device 33 | .Pp 34 | .Nm 35 | .Fl k 36 | .Ar device 37 | .Pp 38 | .Nm 39 | .Fl n 40 | .Ar device name 41 | .Sh DESCRIPTION 42 | The 43 | .Nm 44 | command supports the mounting, probing, and unmounting of FAT file systems. 45 | .Pp 46 | Options: 47 | .Bl -tag -compact -offset indent 48 | .It Fl m Ar mountflag1 mountflag2 mountflag3 mountflag4 49 | mount 50 | .It Fl n 51 | set name 52 | .It Fl p Ar mountflag1 mountflag2 mountflag3 mountflag4 53 | probe for mounting 54 | .It Fl u 55 | unmount 56 | .It Fl k 57 | print volume UUID 58 | .El 59 | .Pp 60 | .Ar mountflags 61 | above are either: 62 | .Bl -bullet -compact -offset indent 63 | .It 64 | .Ar removable 65 | or 66 | .Ar fixed 67 | .It 68 | .Ar readonly 69 | or 70 | .Ar writeable 71 | .It 72 | .Ar suid 73 | or 74 | .Ar nosuid 75 | .It 76 | .Ar dev 77 | or 78 | .Ar nodev 79 | .El 80 | .Pp 81 | FAT volumes do not actually have a volume UUID. 82 | They have an optional 4-byte volume ID. 83 | If a volume has an ID, then it will be converted to a version 3 UUID 84 | using MD5 to checksum the kFSUUIDNamespaceSHA1 UUID folowed by the volume ID. 85 | .Pp 86 | For the 87 | .Fl k 88 | option, if the volume has a volume ID, the exit status will be 253 and the UUID 89 | will be printed to standard out, without any trailing newline. 90 | Otherwise, if the volume appears to be FAT, the exit status will be 255. 91 | If the volume does not appear to be FAT, the exit status will be 254. 92 | .Sh FILES 93 | .Pa /System/Library/Filesystems/msdos.fs/Contents/Resources/msdos.util 94 | .Sh SEE ALSO 95 | .Xr diskarbitrationd 8 96 | .Sh HISTORY 97 | Derived from the Openstep Workspace Manager file system utility programs. 98 | -------------------------------------------------------------------------------- /Fuzzing/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "ext.h" 6 | 7 | 8 | typedef struct { 9 | uint8_t* data; 10 | size_t size; 11 | } fuzzing_input; 12 | 13 | 14 | int checkfilesys (const char* fname, check_context* context); 15 | int LLVMFuzzerInitialize (int* argc, char*** argv); 16 | int LLVMFuzzerTestOneInput (uint8_t* data, size_t size); 17 | 18 | check_context CTX = { 0 }; 19 | static int TOCTOU_MODE_SET = 0; 20 | 21 | static size_t 22 | ctx_rw (fuzzing_input* resource, void* buffer, size_t nbytes, off_t offset, bool isWrite) { 23 | if (offset >= resource->size) { 24 | return 0; 25 | } 26 | 27 | // Determine the number of bytes to copy, ensuring we don't go beyond the resource's size. 28 | size_t bytes_to_copy = 29 | (resource->size - offset < nbytes) ? (resource->size - offset) : nbytes; 30 | 31 | 32 | // Perform either read or write operation based on 'isWrite' flag. 33 | if (isWrite) { 34 | memcpy (resource->data + offset, buffer, bytes_to_copy); 35 | } else { 36 | memcpy (buffer, resource->data + offset, bytes_to_copy); 37 | if (TOCTOU_MODE_SET) { 38 | memset(resource->data + offset, 0xFF, bytes_to_copy); 39 | } 40 | } 41 | 42 | return bytes_to_copy; 43 | } 44 | 45 | static size_t ctx_read (fuzzing_input* resource, void* buffer, size_t nbytes, off_t offset) { 46 | return ctx_rw (resource, buffer, nbytes, offset, false); 47 | } 48 | 49 | static size_t ctx_write (fuzzing_input* resource, void* buffer, size_t nbytes, off_t offset) { 50 | return ctx_rw (resource, buffer, nbytes, offset, true); 51 | } 52 | 53 | static int ctx_fstat (fuzzing_input* resource, struct stat* buffer) { 54 | // Fail if resource is empty 55 | if (resource->size == 0) { 56 | return 1; 57 | } 58 | return 0; 59 | } 60 | 61 | 62 | int LLVMFuzzerInitialize (int* argc, char*** argv) { 63 | CTX.resource = 0; 64 | CTX.readHelper = (size_t (*)(void*, void*, size_t, off_t)) ctx_read; 65 | CTX.writeHelper = (size_t (*)(void*, void*, size_t, off_t)) ctx_write; 66 | CTX.fstatHelper = (int (*)(void *, struct stat *)) ctx_fstat; 67 | CTX.resource = 0; 68 | return 0; 69 | } 70 | 71 | 72 | int LLVMFuzzerTestOneInput (uint8_t* data, size_t size) { 73 | fuzzing_input resource; 74 | 75 | // msdosfs actually writes back to the buffer for some reason ¯\_(ツ)_/¯ 76 | uint8_t* writeable_data = calloc (1, size); 77 | memcpy (writeable_data, data, size); 78 | // Make sure we are not using the const data anymore 79 | data = (uint8_t*)0xdeadbeef; 80 | 81 | // Prepare resource for fuzzing 82 | resource.data = writeable_data; 83 | resource.size = size; 84 | CTX.resource = (void*)&resource; 85 | // fuzz 86 | checkfilesys ((const char*)"/dev/disk", &CTX); 87 | // cleanup (might not even be needed) 88 | CTX.resource = 0; 89 | free (writeable_data); 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /msdos_appex/ExtensionCommon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Apple Inc. All rights reserved. 3 | */ 4 | 5 | #include 6 | 7 | #define ROOT_DIR_FILENUM (1) 8 | 9 | /* 10 | * We use the 64bit cookie in the following way: 11 | * Lower 32 bits = offset in dir cluster. 12 | * Upper 32 bits = index of the desired dir entry in dir (index = 0 --> first file in dir). 13 | */ 14 | #define OFFSET_FROM_COOKIE(cookie) (cookie & 0xFFFFFFFFU) 15 | #define INDEX_FROM_COOKIE(cookie) ((cookie >> 32) & 0xFFFFFFFFU) 16 | #define COOKIE_FROM_OFFSET_AND_INDEX(offset, index) (((index & 0x00000000FFFFFFFFLLU) << 32) + (offset & 0xFFFFFFFFU)) 17 | #define DOT_COOKIE (0) 18 | #define DOT_SIZE (2) 19 | #define DOT_DOT_COOKIE (DOT_SIZE) 20 | #define SYNTHESIZE_ROOT_DOTS_SIZE (2*DOT_SIZE) 21 | #define NUM_DOT_ENTRIES (2) 22 | 23 | /* Dir enumeration error codes */ 24 | #define READDIR_BAD_COOKIE (-1002) 25 | 26 | /* 27 | * The maximum file size on FAT is 4GB-1, which is the largest value that fits 28 | * in an unsigned 32-bit integer. 29 | */ 30 | #define DOS_FILESIZE_MAX 0xffffffff 31 | 32 | #define MSDOS_VALID_BSD_FLAGS_MASK (SF_ARCHIVED | SF_IMMUTABLE | UF_IMMUTABLE | UF_HIDDEN) 33 | 34 | /* Zero-length file ID */ 35 | #define INITIAL_ZERO_LENGTH_FILEID (0xFFFFFFFFFFFFFFFF) 36 | #define WRAPAROUND_ZERO_LENGTH_FILEID (0xFFFFFFFF00000000) 37 | 38 | #define MAX_META_BLOCK_RANGES (8) // -> fskit defines, leave original name 39 | 40 | #define FAT_MAX_FILENAME_UTF8 (WIN_MAXLEN * 3 + 1) 41 | 42 | #define DOS_SYMLINK_LENGTH_LENGTH (4) 43 | #define DOS_SYMLINK_MAGIC_LENGTH (5) 44 | 45 | #ifndef SYMLINK_LINK_MAX 46 | static const char symlink_magic[5] = "XSym\n"; 47 | 48 | #define SYMLINK_LINK_MAX 1024 49 | 50 | struct symlink { 51 | char magic[5]; /* == symlink_magic */ 52 | char length[4]; /* four decimal digits */ 53 | char newline1; /* '\n' */ 54 | char md5[32]; /* MD5 hex digest of "length" bytes of "link" field */ 55 | char newline2; /* '\n' */ 56 | char link[SYMLINK_LINK_MAX]; /* "length" bytes, padded by '\n' and spaces */ 57 | }; 58 | #endif 59 | 60 | #ifndef UNISTR255 61 | #define UNISTR255 62 | struct unistr255 { 63 | uint16_t length; 64 | uint16_t chars[255]; 65 | }; 66 | #endif 67 | 68 | /* Preallocation / KOIO definitions */ 69 | #define PREALLOCATE_ALLOCATEALL 0x00000002 70 | #define PREALLOCATE_ALLOCATECONTIG 0x00000004 71 | #define PREALLOCATE_ALLOCATEFROVOL 0x00000020 72 | 73 | typedef struct FSKit_KOIO_Extent_t { // leave here, Tal to remove soon 74 | uint32_t reserved:24, 75 | type:8; 76 | uint32_t length; 77 | uint64_t offset; 78 | } FSKit_KOIO_Extent; 79 | 80 | #define PREALLOCATE_MAX_EXTENTS (8) 81 | 82 | typedef struct preallocate_args_s { // TODO: handle when adding proper preallocate support 83 | off_t offset; 84 | off_t length; 85 | uint32_t flags; 86 | off_t bytesAllocated; 87 | FSKit_KOIO_Extent extentsList[PREALLOCATE_MAX_EXTENTS]; 88 | int extentsCount; 89 | } preAllocateArgs; 90 | -------------------------------------------------------------------------------- /lib_fsck_msdos/fsutil.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000, 2005-2008 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 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. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | /* 24 | * Copyright (c) 1996 Christos Zoulas. All rights reserved. 25 | * 26 | * Redistribution and use in source and binary forms, with or without 27 | * modification, are permitted provided that the following conditions 28 | * are met: 29 | * 1. Redistributions of source code must retain the above copyright 30 | * notice, this list of conditions and the following disclaimer. 31 | * 2. Redistributions in binary form must reproduce the above copyright 32 | * notice, this list of conditions and the following disclaimer in the 33 | * documentation and/or other materials provided with the distribution. 34 | * 3. All advertising materials mentioning features or use of this software 35 | * must display the following acknowledgement: 36 | * This product includes software developed by Christos Zoulas. 37 | * 4. The name of the author may not be used to endorse or promote products 38 | * derived from this software without specific prior written permission. 39 | * 40 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 41 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 42 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 43 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 44 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 46 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 47 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 48 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 49 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | */ 51 | 52 | #include "lib_fsck_msdos.h" 53 | 54 | void perrno __P((const char *)); 55 | void errexit __P((const char *, ...)) 56 | __attribute__((__noreturn__,__format__(__printf__,1,2))); 57 | void pfatal __P((const char *, ...)) 58 | __attribute__((__format__(__printf__,1,2))); 59 | void pwarn __P((const char *, ...)) 60 | __attribute__((__format__(__printf__,1,2))); 61 | void perr __P((const char *, ...)) 62 | __attribute__((__format__(__printf__,1,2))); 63 | 64 | void vpfatal(fsck_client_ctx_t, const char *fmt, va_list ap); 65 | void vpwarn(fsck_client_ctx_t, const char *fmt, va_list ap); 66 | void vperr(fsck_client_ctx_t, const char *fmt, va_list ap); 67 | void vprint(fsck_client_ctx_t client, int level, const char *fmt, va_list ap); 68 | 69 | #define CHECK_PREEN 1 70 | #define CHECK_VERBOSE 2 71 | #define CHECK_DEBUG 4 72 | -------------------------------------------------------------------------------- /msdosfs.kextproj/msdosfs.kmodproj/bootsect.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 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. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | /* $FreeBSD: src/sys/msdosfs/bootsect.h,v 1.7 1999/08/28 00:48:06 peter Exp $ */ 24 | /* $NetBSD: bootsect.h,v 1.9 1997/11/17 15:36:17 ws Exp $ */ 25 | 26 | /* 27 | * Written by Paul Popelka (paulp@uts.amdahl.com) 28 | * 29 | * You can do anything you want with this software, just don't say you wrote 30 | * it, and don't remove this notice. 31 | * 32 | * This software is provided "as is". 33 | * 34 | * The author supplies this software to be publicly redistributed on the 35 | * understanding that the author is not responsible for the correct 36 | * functioning of this software in any circumstances and is not liable for 37 | * any damages caused by this software. 38 | * 39 | * October 1992 40 | */ 41 | 42 | /* 43 | * Format of a boot sector. This is the first sector on a DOS floppy disk 44 | * or the fist sector of a partition on a hard disk. But, it is not the 45 | * first sector of a partitioned hard disk. 46 | */ 47 | struct bootsector33 { 48 | u_int8_t bsJump[3]; /* jump inst E9xxxx or EBxx90 */ 49 | int8_t bsOemName[8]; /* OEM name and version */ 50 | int8_t bsBPB[19]; /* BIOS parameter block */ 51 | int8_t bsDriveNumber; /* drive number (0x80) */ 52 | int8_t bsBootCode[479]; /* pad so struct is 512b */ 53 | u_int8_t bsBootSectSig0; 54 | u_int8_t bsBootSectSig1; 55 | #define BOOTSIG0 0x55 56 | #define BOOTSIG1 0xaa 57 | }; 58 | 59 | struct extboot { 60 | int8_t exDriveNumber; /* drive number (0x80) */ 61 | int8_t exReserved1; /* reserved */ 62 | int8_t exBootSignature; /* ext. boot signature (0x29) */ 63 | #define EXBOOTSIG 0x29 64 | uint8_t exVolumeID[4]; /* volume ID number */ 65 | int8_t exVolumeLabel[11]; /* volume label */ 66 | int8_t exFileSysType[8]; /* fs type (FAT12 or FAT16) */ 67 | }; 68 | 69 | struct bootsector50 { 70 | u_int8_t bsJump[3]; /* jump inst E9xxxx or EBxx90 */ 71 | int8_t bsOemName[8]; /* OEM name and version */ 72 | int8_t bsBPB[25]; /* BIOS parameter block */ 73 | int8_t bsExt[26]; /* Bootsector Extension */ 74 | int8_t bsBootCode[448]; /* pad so structure is 512b */ 75 | u_int8_t bsBootSectSig0; 76 | u_int8_t bsBootSectSig1; 77 | #define BOOTSIG0 0x55 78 | #define BOOTSIG1 0xaa 79 | }; 80 | 81 | struct bootsector710 { 82 | u_int8_t bsJump[3]; /* jump inst E9xxxx or EBxx90 */ 83 | int8_t bsOEMName[8]; /* OEM name and version */ 84 | int8_t bsBPB[53]; /* BIOS parameter block */ 85 | int8_t bsExt[26]; /* Bootsector Extension */ 86 | int8_t bsBootCode[420]; /* pad so structure is 512b */ 87 | u_int8_t bsBootSectSig0; 88 | u_int8_t bsBootSectSig1; 89 | #define BOOTSIG0 0x55 90 | #define BOOTSIG1 0xaa 91 | }; 92 | 93 | union bootsector { 94 | struct bootsector33 bs33; 95 | struct bootsector50 bs50; 96 | struct bootsector710 bs710; 97 | }; 98 | -------------------------------------------------------------------------------- /lib_newfs_msdos/format.h: -------------------------------------------------------------------------------- 1 | // 2 | // format.h 3 | // newfs_msdos 4 | // This file contains the functions that were used to format a disk copied from newfs_msdos.c file. 5 | // This file allows us to encapsulate the format logic into this file, and use the "format" function to format a device 6 | // from newfs_msdos CLI tool, or from FSKit. 7 | // 8 | // Created by Kujan Lauz on 06/09/2022. 9 | // 10 | 11 | #ifndef format_h 12 | #define format_h 13 | 14 | #include "newfs_data_types.h" 15 | #include "lib_newfs_msdos.h" 16 | 17 | typedef struct { 18 | const char *bootStrapFromFile; // Get bootstrap from file. 19 | const char *volumeName; // Volume name (filesystem name), up to 11 characters. The name should consist of only those characters permitted in regular DOS (8+3) filenames. 20 | const char *OEMString; // OEM string (up to 8 characters). The default is "BSD 4.4" (with two spaces). 21 | const char *standardFormat; // Specify a standard (floppy disk) format. The eight standard formats are (capacities in kilobytes): 160, 180, 320, 360, 640, 720, 1200, 1232, 1440, 2880. 22 | u_int FATType; // FAT type (one of 12, 16, or 32). 23 | u_int volumeID; // Volume ID. 24 | u_int sectorSize; // Number of bytes per sector. Acceptable values are powers of 2 in the range 128 through 32768. 25 | u_int numOfSectorsPerFAT; // Number of sectors per FAT. 26 | u_int blockSize; // File system block size (bytes per cluster). This should resolve to an acceptable number of sectors per cluster (see clusterSize). 27 | u_int clusterSize; // Sectors per cluster. Acceptable values are powers of 2 in the range 1 through 128. 28 | u_int numOfRootDirEnts; // Number of root directory entries (FAT12 and FAT16 only). 29 | u_int numDriveHeads; // Number of drive heads. 30 | u_int systemSectorLocation; // Location of the file system info sector (FAT32 only). A value of 0xffff signifies no info sector. 31 | u_int backupSectorLocation; // Location of the backup boot sector (FAT32 only). A value of 0xffff signifies no backup sector. 32 | u_int mediaDescriptor; // Media descriptor (acceptable range 0xf0 to 0xff). 33 | u_int numbOfFATs; // Number of FATs. Acceptable values are 1 to 16 inclusive. The default is 2. 34 | u_int numOfHiddenSectors; // Number of hidden sectors. 35 | u_int numOfReservedSectors; // Number of reserved sectors. 36 | u_int fsSizeInSectors; // File system size, in sectors. 37 | u_int numOfSectorsPerTrack; // Number of sectors per track. 38 | u_int physicalBytes; // Physical bytes/sector 39 | int dryRun; // Don't create file system, just print out parameters 40 | int volumeIDFlag; // Volume ID flag 41 | int mediaDescriptorFlag; // Media descriptor flag 42 | int hiddenSectorsFlag; // Hidden sectors flag 43 | } NewfsOptions; 44 | 45 | typedef struct format_context_s { 46 | void *updater; 47 | void (*startPhase)(char *description, int64_t pendingUnits, int64_t totalCount, unsigned int *completedCount, void *updater); 48 | void (*endPhase)(char *description, void *updater); 49 | void *resource; 50 | size_t (*readHelper)(void *resource, void *buffer, size_t nbytes, off_t offset); 51 | size_t (*writeHelper)(void *resource, void *buffer, size_t nbytes, off_t offset); 52 | 53 | } *format_context; 54 | 55 | int format(NewfsOptions sopts, NewfsProperties newfsProps, format_context context); 56 | int getstdfmt(const char *, struct bpb *); 57 | int getdiskinfo(NewfsProperties newfsProps, int oflag, struct bpb *bpb); 58 | enum SDCardType sd_card_type_for_path(const char *path); 59 | void sd_card_set_defaults(const char *path, u_int *fat, struct bpb *bpb); 60 | void print_bpb(struct bpb *); 61 | u_int argtou(const char *, u_int, u_int, const char *); 62 | int oklabel(const char *); 63 | void mklabel(u_int8_t *, const char *); 64 | void setstr(u_int8_t *, const char *, size_t); 65 | 66 | #endif /* format_h */ 67 | -------------------------------------------------------------------------------- /mount_msdos.tproj/mount_msdos.8: -------------------------------------------------------------------------------- 1 | .\" $NetBSD: mount_msdos.8,v 1.13 1998/02/06 05:57:00 perry Exp $ 2 | .\" 3 | .\" Copyright (c) 1993,1994 Christopher G. Demetriou 4 | .\" All rights reserved. 5 | .\" 6 | .\" Redistribution and use in source and binary forms, with or without 7 | .\" modification, are permitted provided that the following conditions 8 | .\" are met: 9 | .\" 1. Redistributions of source code must retain the above copyright 10 | .\" notice, this list of conditions and the following disclaimer. 11 | .\" 2. Redistributions in binary form must reproduce the above copyright 12 | .\" notice, this list of conditions and the following disclaimer in the 13 | .\" documentation and/or other materials provided with the distribution. 14 | .\" 3. All advertising materials mentioning features or use of this software 15 | .\" must display the following acknowledgment: 16 | .\" This product includes software developed by Christopher G. Demetriou. 17 | .\" 3. The name of the author may not be used to endorse or promote products 18 | .\" derived from this software without specific prior written permission 19 | .\" 20 | .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 | .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 | .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 | .\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 | .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 | .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | .\" 31 | .\" $FreeBSD: src/sbin/mount_msdos/mount_msdos.8,v 1.19 2000/03/01 11:27:14 sheldonh Exp $ 32 | .\" 33 | .Dd April 7, 1994 34 | .Dt MOUNT_MSDOS 8 35 | .Os 36 | .Sh NAME 37 | .Nm mount_msdos 38 | .Nd mount an MS-DOS file system 39 | .Sh SYNOPSIS 40 | .Nm mount_msdos 41 | .Op Fl o Ar options 42 | .Op Fl u Ar uid 43 | .Op Fl g Ar gid 44 | .Op Fl m Ar mask 45 | .Pa special 46 | .Pa node 47 | .Sh DESCRIPTION 48 | The 49 | .Nm 50 | command attaches the MS-DOS filesystem residing on 51 | the device 52 | .Pa special 53 | to the global filesystem namespace at the location 54 | indicated by 55 | .Pa node . 56 | This command is normally executed by 57 | .Xr mount 8 58 | at boot time, but can be used by any user to mount an 59 | MS-DOS file system on any directory that they own (provided, 60 | of course, that they have appropriate access to the device that 61 | contains the file system). 62 | .Pp 63 | The options are as follows: 64 | .Bl -tag -width Ds 65 | .It Fl o Ar options 66 | Use the specified mount 67 | .Ar options , 68 | as described in 69 | .Xr mount 8 . 70 | .It Fl u Ar uid 71 | Set the owner of the files in the file system to 72 | .Ar uid . 73 | The default owner is the owner of the directory 74 | on which the file system is being mounted. 75 | .It Fl g Ar gid 76 | Set the group of the files in the file system to 77 | .Ar gid . 78 | The default group is the group of the directory 79 | on which the file system is being mounted. 80 | .It Fl m Ar mask 81 | Specify the maximum file permissions for files 82 | in the file system. 83 | (For example, a 84 | .Ar mask 85 | of 86 | .Li 755 87 | specifies that, by default, the owner should have 88 | read, write, and execute permissions for files, but 89 | others should only have read and execute permissions. 90 | See 91 | .Xr chmod 1 92 | for more information about octal file modes.) 93 | Only the nine low-order bits of 94 | .Ar mask 95 | are used. 96 | The default 97 | .Ar mask 98 | is taken from the 99 | directory on which the file system is being mounted. 100 | .El 101 | .Sh SEE ALSO 102 | .Xr mount 2 , 103 | .Xr unmount 2 , 104 | .Xr fstab 5 , 105 | .Xr mount 8 106 | .Sh CAVEATS 107 | .Pp 108 | .Fx 2.1 109 | and earlier versions could not handle cluster sizes larger than 16K. 110 | Just mounting an MS-DOS file system could cause corruption to any 111 | mounted file system. 112 | Cluster sizes larger than 16K are unavoidable for file system sizes 113 | larger than 1G, and also occur when filesystems larger than 1G are 114 | shrunk to smaller than 1G using FIPS. 115 | .Sh HISTORY 116 | The 117 | .Nm 118 | utility first appeared in 119 | .Fx 2.0 . 120 | Its predecessor, the 121 | .Nm mount_pcfs 122 | utility appeared in 123 | .Fx 1.0 , 124 | and was abandoned in favor 125 | of the more aptly-named 126 | .Nm Ns . 127 | -------------------------------------------------------------------------------- /Locking.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf270 2 | {\fonttbl\f0\froman\fcharset0 Times-Roman;\f1\fswiss\fcharset0 Helvetica;\f2\fnil\fcharset0 Monaco; 3 | } 4 | {\colortbl;\red255\green255\blue255;} 5 | \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\qc\pardirnatural 6 | 7 | \f0\b\fs36 \cf0 msdosfs Locking Model\ 8 | \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural 9 | 10 | \f1\b0\fs24 \cf0 \ 11 | This document describes the locking model used by the msdosfs KEXT.\ 12 | \ 13 | There are five different kinds of locks used by msdosfs. To avoid deadlock, msdosfs always acquires multiple locks in a specific, consistent order. The different types of locks are acquired in this order:\ 14 | \'95 vnodes (denodes)\ 15 | \'95 denode hash\ 16 | \'95 rename\ 17 | \'95 cluster extent cache (de_cluster_lock)\ 18 | \'95 FAT\ 19 | \'95 buffer cache\ 20 | \ 21 | No lock of a particular type may be acquired if any locks of types further down in the list have been acquired. For example, if the FAT lock is acquired, no vnode locks may be acquired until the FAT lock (and denode hash, rename, or buffer cache locks) are released. Specific details about each of the above lock types is provided below.\ 22 | \ 23 | 24 | \b vnodes (denodes) 25 | \b0 \ 26 | VFS calls us with a "use count" reference on all vnodes it passes to us. But the reference does not prevent the underlying object from being renamed or deleted (or another object being created with the same name). Therefore we cannot depend on a "child" vnode actually being a child of the "parent" vnode, or that the child still exists or still has the same name that was used to look up the vnode.\ 27 | \ 28 | The 29 | \f2\fs18 \CocoaLigature0 de_lock 30 | \f1\fs24 \CocoaLigature1 in the denode protects the object. The lock prevents the object's parent or name from changing (though it doesn't prevent other ancestors from changing, nor prevent the parent's name from changing), and protects changes to the object's size. For directories, the lock prevents directory entries from being added, removed, or moved; it protects the name space within that directory. The lock on a directory does not prevent changes to the contents of existing directory entries (other than the deName, and the flags which indicate whether the entry is a long name entry). The lock on a file (including a symlink) protects that file's directory entry and its contents.\ 31 | \ 32 | When multiple denodes must be locked, they are locked in order of increasing address (of the denode itself, not the vnode).\ 33 | \ 34 | 35 | \b denode hash 36 | \b0 \ 37 | The 38 | \f2\fs18 \CocoaLigature0 msdosfs_hash_lock 39 | \f1\fs24 is used to protect the denode hash table ( 40 | \f2\fs18 dehashtbl 41 | \f1\fs24 ). It is only locked long enough to search, insert or remove a denode. When a new denode must be added to the hash, the 42 | \f2\fs18 msdosfs_hash_lock 43 | \f1\fs24 is 44 | \i not 45 | \i0 held while the denode is initialized (which generally requires I/O). Instead, a minimally initialized denode with the 46 | \f2\fs18 DE_INIT 47 | \f1\fs24 flag set is inserted into the hash. When searching for a denode, if the 48 | \f2\fs18 DE_INIT 49 | \f1\fs24 flag is set, then the 50 | \f2\fs18 msdosfs_hash_lock 51 | \f1\fs24 is released, the thread sleeps waiting for 52 | \f2\fs18 DE_INIT 53 | \f1\fs24 to be cleared, and then reacquires the 54 | \f2\fs18 msdosfs_hash_lock 55 | \f1\fs24 to search again.\ 56 | \ 57 | The 58 | \f2\fs18 msdosfs_hash_lock 59 | \f1\fs24 is global to msdosfs.kext; it is not per-volume. The hash table is shared by all volumes.\ 60 | \CocoaLigature1 \ 61 | 62 | \b rename 63 | \b0 \ 64 | Per-volume lock for renames which "reshape" the hierarchy. If renaming a directory, and the directory will be moving to a new parent, then the 65 | \f2\fs18 \CocoaLigature0 pm_rename_lock 66 | \f1\fs24 \CocoaLigature1 is taken. This prevents the relationship between the "from" directory and the "to" directory from changing while rename verifies that the directory isn't being moved into one of its descendants.\ 67 | \ 68 | 69 | \b cluster extent cache 70 | \b0 ( 71 | \f2\fs18 de_cluster_lock 72 | \f1\fs24 )\ 73 | This lock is used to protect the "cluster extent cache," which keeps track of the most recently mapped extent of contiguous clusters. Specifically, it protects the 74 | \f2\fs18 de_cluster_ 75 | \f1\fs24 * fields that follow the 76 | \f2\fs18 de_cluster_lock 77 | \f1\fs24 field in 78 | \f2\fs18 struct denode 79 | \f1\fs24 .\ 80 | \ 81 | 82 | \b FAT 83 | \b0 \ 84 | The 85 | \f2\fs18 \CocoaLigature0 pm_fat_lock 86 | \f1\fs24 \CocoaLigature1 is a per-volume lock which protects that volume's File Allocation Table on disk.\ 87 | \ 88 | 89 | \b buffer cache 90 | \b0 \ 91 | The buffer cache internally acquires a mutex when you "get" or read a buffer. Only one buffer is acquired at a time. Operations which affect multiple buffers must release a buffer before accessing another buffer. Some operations (such as creating or removing a directory entry with multiple long name entries; or allocating or freeing multiple clusters) which affect multiple buffers protect the overall operation with one of the other lock types (for example, a directory's denode lock, or the FAT lock).\ 92 | } -------------------------------------------------------------------------------- /msdos_appex/FATManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Apple Inc. All rights reserved. 3 | */ 4 | 5 | #ifndef FATMANAGER_h 6 | #define FATMANAGER_h 7 | 8 | #import "FATVolume.h" 9 | #import "utils.h" 10 | 11 | #define EOF_CLUSTER (0xFFFFFFFF) 12 | #define EOF_RANGE_START (0xFFFFFFF8) 13 | #define EOF_RANGE_END (0xFFFFFFFF) 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | typedef NS_ENUM(uint8_t, iterateClustersResult) { 18 | iterateClustersContinue, 19 | iterateClustersStop 20 | }; 21 | 22 | @interface FATBlock :NSObject 23 | 24 | -(instancetype)initWithOffset:(uint64_t)offset; 25 | 26 | @property NSMutableData *data; 27 | @property uint64_t startOffset; 28 | 29 | @end 30 | 31 | @interface FATManager : NSObject 32 | 33 | @property FSBlockDeviceResource *device; 34 | @property dispatch_queue_t fatQueue; 35 | @property FileSystemInfo *fsInfo; 36 | @property FSOperations *fsOps; 37 | 38 | @property uint32_t fatSize; 39 | @property uint32_t rwSize; 40 | @property bool useCache; 41 | 42 | -(instancetype _Nullable)initWithDevice:(FSBlockDeviceResource *)device 43 | info:(FileSystemInfo *)info 44 | ops:(FSOperations *)fsOps 45 | usingCache:(bool)usingCache; 46 | 47 | /** 48 | Allocate clusters to extend an item's existing cluster chain. 49 | @param numOfClusters How many clusters to allocate 50 | @param theItem The item to allocate more clusters for 51 | @param allowPartial If false, failing to fully allocate clusters will return an error 52 | @param zeroFill CURRENTLY IGNORED 53 | @param mustBeContig If true, only allocate a single cluster chain. 54 | @param reply In case of a failure returns a non-nil error and zeros. Else, error is nil and the first, last and count of clusters allocated is returned. 55 | */ 56 | -(void)allocateClusters:(uint32_t)numOfClusters 57 | forItem:(FATItem *)theItem 58 | allowPartial:(bool)allowPartial 59 | mustBeContig:(bool)mustBeContig 60 | zeroFill:(bool)zeroFill 61 | replyHandler:(void (^)(NSError * _Nullable error, 62 | uint32_t firstAllocatedCluster, 63 | uint32_t lastAllocatedCluster, 64 | uint32_t numAllocated)) reply; 65 | 66 | /** 67 | Allocate clusters wrapper starting from the FAT's first free cluster. 68 | @param numOfClusters How many clusters to allocate 69 | @param allowPartial If false, failing to fully allocate clusters will return an error 70 | @param zeroFill CURRENTLY IGNORED 71 | @param mustBeContig If true, only allocate a single cluster chain. 72 | @param reply In case of a failure returns a non-nil error and zeros. Else, error is nil and the first, last and count of clusters allocated is returned. 73 | */ 74 | -(void)allocateClusters:(uint32_t)numOfClusters 75 | allowPartial:(bool)allowPartial 76 | zeroFill:(bool)zeroFill 77 | mustBeContig:(bool)mustBeContig 78 | replyHandler:(void (^)(NSError * _Nullable error, 79 | uint32_t firstAllocatedCluster, 80 | uint32_t lastAllocatedCluster, 81 | uint32_t numAllocated)) reply; 82 | 83 | -(void)freeClusters:(uint32_t)numClusters 84 | ofItem:(FATItem *)theItem 85 | replyHandler:(void (^)(NSError * _Nullable error)) reply; 86 | 87 | /** THIS METHOD SHOULD ONLY BE USED IN ERROR FLOWS! 88 | For example, if during create, clusters were allocated but the item was not 89 | properly created. 90 | For other usages, Use freeClusters:ofFile:reply. 91 | 92 | Frees the cluster chain starting from startCluster up to EOF. 93 | Note: This method takes no item, so the FATManager won't be setting a new EOF 94 | to the item to which the clusters were allocated, so iterating its cluster chain 95 | may result in corruption. */ 96 | -(void)freeClusterFrom:(uint32_t)startCluster 97 | numClusters:(uint32_t)numClusters 98 | replyHandler:(void(^)(NSError * _Nullable error))reply; 99 | 100 | -(void)getContigClusterChainLengthStartingAt:(uint32_t)startCluster 101 | replyHandler:(void (^)(NSError * _Nullable error, 102 | uint32_t numOfContigClusters, 103 | uint32_t nextCluster))reply; 104 | 105 | -(void)clusterChainLength:(FATItem*)item 106 | replyHandler:(void (^)(NSError * _Nullable error, 107 | uint32_t lastCluster, 108 | uint32_t length))reply; 109 | 110 | -(void)iterateClusterChainOfItem:(FATItem *)item 111 | replyHandler:(iterateClustersResult (^)(NSError * _Nullable error, 112 | uint32_t startCluster, 113 | uint32_t numOfContigClusters))reply; 114 | 115 | -(void)setDirtyBitValue:(dirtyBitValue)newValue 116 | forceWriteToDisk:(bool)forceWriteToDisk 117 | replyHandler:(void (^)(NSError * _Nullable error))reply; 118 | 119 | 120 | -(void)getDirtyBitValue:(void (^)(NSError * _Nullable error, 121 | dirtyBitValue value))reply; 122 | 123 | -(bool)isEOFCluster:(uint64_t)cluster; 124 | 125 | @end 126 | 127 | NS_ASSUME_NONNULL_END 128 | 129 | #endif /* FATMANAGER_h */ 130 | -------------------------------------------------------------------------------- /fsck_msdos.tproj/fsck_msdos.8: -------------------------------------------------------------------------------- 1 | .\" $NetBSD: fsck_msdos.8,v 1.10 1999/03/07 11:02:06 mycroft Exp $ 2 | .\" 3 | .\" Copyright (C) 1995 Wolfgang Solfrank 4 | .\" Copyright (c) 1995 Martin Husemann 5 | .\" 6 | .\" Redistribution and use in source and binary forms, with or without 7 | .\" modification, are permitted provided that the following conditions 8 | .\" are met: 9 | .\" 1. Redistributions of source code must retain the above copyright 10 | .\" notice, this list of conditions and the following disclaimer. 11 | .\" 2. Redistributions in binary form must reproduce the above copyright 12 | .\" notice, this list of conditions and the following disclaimer in the 13 | .\" documentation and/or other materials provided with the distribution. 14 | .\" 3. All advertising materials mentioning features or use of this software 15 | .\" must display the following acknowledgement: 16 | .\" This product includes software developed by Martin Husemann 17 | .\" and Wolfgang Solfrank. 18 | .\" 4. Neither the name of the University nor the names of its contributors 19 | .\" may be used to endorse or promote products derived from this software 20 | .\" without specific prior written permission. 21 | .\" 22 | .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 23 | .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 | .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 | .\" IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 | .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 | .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 | .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | .\" 33 | .\" 34 | .Dd August 13, 1995 35 | .Dt FSCK_MSDOS 8 36 | .Os NetBSD 1.1 37 | .Sh NAME 38 | .Nm fsck_msdos 39 | .Nd DOS/Windows (FAT) file system consistency check 40 | .Sh SYNOPSIS 41 | .Nm fsck_msdos 42 | .Fl q 43 | .Ar special ... 44 | .Nm fsck_msdos 45 | .Fl p 46 | .Op Fl f 47 | .Ar special ... 48 | .Nm fsck_msdos 49 | .Op Fl fny 50 | .Ar special ... 51 | .Sh DESCRIPTION 52 | .Pp 53 | The 54 | .Nm 55 | utility verifies and repairs 56 | .Tn FAT 57 | file systems (more commonly known 58 | as 59 | .Tn DOS 60 | file systems). 61 | .Pp 62 | The first form of 63 | .Nm 64 | quickly checks the specified file systems to determine whether 65 | they were cleanly unmounted. 66 | .Pp 67 | The second form of 68 | .Nm 69 | preens the specified file systems. 70 | It is normally started by 71 | .Xr fsck 8 72 | run from 73 | .Pa /etc/rc.boot 74 | during automatic reboot, when a FAT file system is detected. 75 | When preening file systems, 76 | .Nm 77 | will fix common inconsistencies non-interactively. If 78 | more serious problems are found, 79 | .Nm 80 | does not try to fix them, indicates that it was not 81 | successful, and exits. 82 | .Pp 83 | The third form of 84 | .Nm 85 | checks the specified file systems and tries to repair all 86 | detected inconsistencies, requesting confirmation before 87 | making any changes. The default behavior is to always ask 88 | for confirmation of each change. Use the -n or -y options 89 | to override this default behavior. 90 | .Pp 91 | The options are as follows: 92 | .Bl -hang -offset indent 93 | .It Fl q 94 | Causes 95 | .Nm 96 | to quickly check whether the volume was unmounted cleanly. 97 | If the volume was unmounted cleanly, then the exit status is 0. 98 | If the volume was not unmounted cleanly, then the exit status 99 | will be non-zero. In either case, a message is printed to 100 | standard output describing whether the volume was clean or dirty. 101 | .It Fl f 102 | This option is ignored by 103 | .Nm 104 | and is present only for compatibility with programs that 105 | check other file system types for consistency. 106 | .It Fl n 107 | Causes 108 | .Nm 109 | to assume no as the answer to all operator 110 | questions, except 111 | .Dq CONTINUE? . 112 | .It Fl p 113 | Preen the specified file systems. 114 | .It Fl y 115 | Causes 116 | .Nm 117 | to assume yes as the answer to all operator questions. 118 | .It Fl M 119 | Limits the amount of memory used by 120 | .Nm . 121 | .It Fl S Ar directory 122 | Causes 123 | .Nm 124 | to create a shadow file containing all metadata read from the device in the given directory. 125 | This functionality is intended for inclusion with bug reports regarding excpetional problems. 126 | One file is created for each checked device. 127 | .Nm 128 | may re-read metadata from disk at different phases of the repair process. If the repair 129 | process has repaired the metadata, the shadow file will capture its state as last read 130 | from disk. For optimal debug value, the shadow file should be captured in conjunction 131 | with the -n option. 132 | The shadow file's name will be shadow-diskXsY or shadow-fd, depends on the information 133 | given to 134 | .Nm . 135 | If this file already exists, 136 | .Nm 137 | will attempt to add a counter postfix to the name. 138 | The resulting shadow file can be mounted by diskimagetool. 139 | Failure to generate or write to the shadow file will not affect the behavior of 140 | .Nm . 141 | 142 | .El 143 | .Sh EXIT VALUES 144 | .Nm 145 | exits with a value of 0 when the filesystem is clean (or has been repaired), 146 | and 8 otherwise. 147 | .Sh SEE ALSO 148 | .Xr fsck 8 149 | -------------------------------------------------------------------------------- /msdos_appex/ItemCache.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Apple Inc. All rights reserved. 3 | */ 4 | 5 | #import 6 | 7 | #import "FATManager.h" 8 | #import "FATVolume.h" 9 | #import "ItemCache.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ItemCache() 14 | 15 | @property NSMutableDictionary *itemsHash; 16 | @property FATVolume *volume; 17 | 18 | @end 19 | 20 | 21 | @implementation ItemCache 22 | 23 | -(instancetype _Nullable)initWithVolume:(FATVolume *)volume 24 | { 25 | self = [super init]; 26 | if (!self) { 27 | return nil; 28 | } 29 | 30 | _itemsHash = [[NSMutableDictionary alloc]init]; 31 | 32 | if (!_itemsHash) { 33 | os_log_error(OS_LOG_DEFAULT, "%s: Failed to initialize queue / hash", __func__); 34 | return nil; 35 | } 36 | 37 | _volume = volume; 38 | 39 | return self; 40 | } 41 | 42 | - (void)calculateKeyForItem:(FATItem *)item 43 | replyHandler:(void (^)(uint64_t key, 44 | NSError * _Nullable error))reply 45 | { 46 | __block uint64_t itemOffsetInDir = item.entryData.firstEntryOffsetInDir; 47 | uint32_t clusterSize = _volume.systemInfo.bytesPerCluster; 48 | __block uint64_t offsetInVolume = 0; 49 | __block uint64_t accOffset = 0; 50 | __block NSError *error = nil; 51 | 52 | /* Root dir is a special case, leave its key to be 0 */ 53 | if (item.parentDir != nil) { 54 | /* 55 | * Calculate the key - the offset of the first direntry in the volume 56 | * divided by the size of direntry 57 | */ 58 | [_volume.fatManager iterateClusterChainOfItem:item.parentDir 59 | replyHandler:^iterateClustersResult(NSError *innerError, 60 | uint32_t startCluster, 61 | uint32_t numOfContigClusters) { 62 | if (innerError) { 63 | error = innerError; 64 | return iterateClustersStop; 65 | } else { 66 | if (numOfContigClusters == 0) { 67 | /* Item has no clusters, no key */ 68 | return iterateClustersStop; 69 | } 70 | if (itemOffsetInDir - accOffset + sizeof(struct dosdirentry) > numOfContigClusters * clusterSize) { 71 | /* Our offset is not in this batch of contiguous clusters */ 72 | accOffset += numOfContigClusters * clusterSize; 73 | return iterateClustersContinue; 74 | } else { 75 | /* We are in the correct clusters range */ 76 | offsetInVolume = (itemOffsetInDir - accOffset) + startCluster * clusterSize; 77 | return iterateClustersStop; 78 | } 79 | } 80 | }]; 81 | } 82 | 83 | if (error) { 84 | /* We failed to find the volume index */ 85 | return reply(0, error); 86 | } 87 | 88 | return reply(offsetInVolume, nil); 89 | } 90 | 91 | - (void)insertItem:(FATItem *)item 92 | replyHandler:(void (^)(FATItem * _Nullable cachedItem, 93 | NSError * _Nullable error))reply 94 | { 95 | __block FATItem *existingItem = nil; 96 | __block FATItem *itemToReturn = nil; 97 | __block uint64_t volumeOffset = 0; 98 | __block NSError *error = nil; 99 | NSString *key = nil; 100 | 101 | /* Make sure the item is not deleted */ 102 | if (item.isDeleted) { 103 | os_log_fault(OS_LOG_DEFAULT, "%s: Item is deleted", __func__); 104 | return reply(nil, fs_errorForPOSIXError(EINVAL)); 105 | } 106 | 107 | volumeOffset = [item.entryData calcFirstEntryOffsetInVolume:item.volume.systemInfo]; 108 | 109 | key = [[NSString alloc] initWithFormat:@"%llu", volumeOffset]; 110 | 111 | @synchronized (_itemsHash) { 112 | /* Make sure the item is not in the cache. If it is, return it */ 113 | existingItem = [_itemsHash objectForKey:key]; 114 | if (existingItem != nil) { 115 | if (existingItem.isDeleted) { 116 | /* Need to update the item */ 117 | [_itemsHash setObject:item forKey:key]; 118 | itemToReturn = item; 119 | } else { 120 | itemToReturn = existingItem; 121 | os_log_debug(OS_LOG_DEFAULT, "%s: Item already cached", __func__); 122 | } 123 | } else { 124 | /* Item is not in the cache. Insert it. */ 125 | [_itemsHash setObject:item forKey:key]; 126 | } 127 | }; 128 | 129 | return reply(itemToReturn ? itemToReturn : item, error); 130 | } 131 | 132 | -(void)removeItem:(FATItem*)item 133 | { 134 | __block uint64_t volumeOffset = [item.entryData calcFirstEntryOffsetInVolume:item.volume.systemInfo]; 135 | __block FATItem *cachedItem = nil; 136 | 137 | NSString *key = [[NSString alloc] initWithFormat:@"%llu", volumeOffset]; 138 | 139 | @synchronized (_itemsHash) { 140 | cachedItem = [_itemsHash objectForKey:key]; 141 | if (cachedItem == nil) { 142 | /* TODO: Do we want to fault here? */ 143 | os_log_fault(OS_LOG_DEFAULT, "%s: item for key %@ not found", __func__, key); 144 | } else { 145 | [_itemsHash removeObjectForKey:key]; 146 | } 147 | }; 148 | } 149 | 150 | @end 151 | 152 | NS_ASSUME_NONNULL_END 153 | -------------------------------------------------------------------------------- /msdos_appex/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Apple Inc. All rights reserved. 3 | */ 4 | 5 | #ifndef utils_h 6 | #define utils_h 7 | 8 | #import 9 | #import 10 | #import 11 | #import 12 | #import "bootsect.h" 13 | #import "direntry.h" 14 | #import "Conv.h" 15 | #import "bpb.h" 16 | 17 | #include 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | /* 22 | * The maximum file size on FAT is 4GB-1, which is the largest value that fits 23 | * in an unsigned 32-bit integer. 24 | */ 25 | #define MAX_DOS_FILESIZE 0xffffffff 26 | 27 | #define LABEL_LENGTH 11 /* Maximal volume label length */ 28 | 29 | #define MAX_DOS_BLOCKSIZE (4096) 30 | #define FAT_BLOCKSIZE (8192U) 31 | #define FAT_BLOCKMASK (FAT_BLOCKSIZE - 1) 32 | 33 | #define FREE_CLUSTER (0) 34 | #define FIRST_VALID_CLUSTER (2) /* 2 is the minimum valid cluster number */ 35 | #define RESERVED_CLUSTERS_START (0xFFFFFFF6) /* start of reserved clusters */ 36 | 37 | #define MSDOS_MAX_DIR_BLOCK_SIZE_MACOS (4096U) 38 | #define RESERVED_CLUSTER_RANGE (0xFFFFFFF6) 39 | #define MASK_12BIT (0x00000FFF) 40 | #define MASK_16BIT (0x0000FFFF) 41 | #define MASK_32BIT (0x0FFFFFFF) 42 | 43 | #define FAT_DIRTY_BIT_CLUSTER 1 44 | #define FAT_16_DIRTY_BIT_IDX 15 45 | #define FAT_32_DIRTY_BIT_IDX 27 46 | 47 | 48 | #if (BYTE_ORDER == LITTLE_ENDIAN) /* && defined(UNALIGNED_ACCESS) */ 49 | #define getuint16(x) *((u_int16_t *)(x)) 50 | #define getuint32(x) *((u_int32_t *)(x)) 51 | #define putuint16(p, v) (*((u_int16_t *)(p)) = (v)) 52 | #define putuint32(p, v) (*((u_int32_t *)(p)) = (v)) 53 | #else 54 | #define getuint16(x) (((u_int8_t *)(x))[0] + (((u_int8_t *)(x))[1] << 8)) 55 | #define getuint32(x) (((u_int8_t *)(x))[0] + (((u_int8_t *)(x))[1] << 8) \ 56 | + (((u_int8_t *)(x))[2] << 16) \ 57 | + (((u_int8_t *)(x))[3] << 24)) 58 | #define putuint16(p, v) (((u_int8_t *)(p))[0] = (v) & 0xFF, \ 59 | ((u_int8_t *)(p))[1] = ((v) >> 8) & 0xFF) 60 | #define putuint32(p, v) (((u_int8_t *)(p))[0] = (v) & 0xFF, \ 61 | ((u_int8_t *)(p))[1] = ((v) >> 8) & 0xFF, \ 62 | ((u_int8_t *)(p))[2] = ((v) >> 16) & 0xFF, \ 63 | ((u_int8_t *)(p))[3] = ((v) >> 24) & 0xFF) 64 | #endif 65 | 66 | #undef ROUND_DOWN 67 | #define ROUND_DOWN(_x, _m) (((_x) / (_m)) * (_m)) 68 | 69 | #undef ROUND_UP 70 | #define ROUND_UP(_x, _m) ROUND_DOWN((_x) + (_m) - 1, (_m)) 71 | 72 | 73 | typedef NS_ENUM(uint32_t, parseCharacterResult) { 74 | parseCharacterResultError = 0, /* unexpected character */ 75 | parseCharacterResultEnd, /* this is the last character in name */ 76 | parseCharacterResultContinue /* continue iterating the name */ 77 | }; 78 | 79 | typedef NS_ENUM(uint8_t, dirtyBitValue) { 80 | dirtyBitClean = 0, 81 | dirtyBitDirty = 1, 82 | dirtyBitUnknown = 2 83 | }; 84 | 85 | typedef NS_ENUM(uint8_t, volumeLabelSrc) { 86 | LABEL_FROM_DIRENTRY = 1, 87 | LABEL_FROM_BOOTSECT = 2 88 | }; 89 | 90 | 91 | @interface Utilities : NSObject 92 | 93 | +(NSString*)getVolumeName:(FSBlockDeviceResource *)device 94 | bps:(uint16_t)bps 95 | spc:(uint8_t)spc 96 | bootsector:(union bootsector *)bootSector 97 | flags:(uint8_t)flags; 98 | 99 | +(BOOL)isLabelLegal:(char *)label; 100 | 101 | +(NSUUID*)generateVolumeUuid:(union bootsector * _Nonnull)bootSector 102 | uuid:(unsigned char *)uuid; 103 | 104 | +(FSFileName *)getVolumeLabelFromBootSector:(int8_t*)volumeLabel; 105 | 106 | +(CFStringEncoding)getDefaultDOSEncoding; 107 | 108 | +(parseCharacterResult)parseCharacterOfLongNameEntry:(struct winentry *)longNameEntry 109 | charIdxInEntry:(uint32_t)idxInEntry 110 | charIdxInName:(uint32_t)idxInName 111 | unistrName:(struct unistr255 *)name 112 | isFirstLongEntryInSet:(bool)isFirst; 113 | 114 | +(bool)isDotOrDotDot:(char *)name 115 | length:(size_t)length; 116 | 117 | +(NSError * _Nullable)syncMetaReadFromDevice:(FSBlockDeviceResource *)device 118 | into:(void *)buffer 119 | startingAt:(off_t)offset 120 | length:(size_t)nbyte; 121 | 122 | +(NSError * _Nullable)metaWriteToDevice:(FSBlockDeviceResource *)device 123 | from:(void *)buffer 124 | startingAt:(off_t)offset 125 | length:(size_t)nbyte 126 | forceSyncWrite:(bool)forceSync; 127 | 128 | +(NSError * _Nullable)syncMetaClearToDevice:(FSBlockDeviceResource *)device 129 | rangesToClear:(NSArray *)rangesToClear; 130 | 131 | +(NSError * _Nullable)syncMetaPurgeToDevice:(FSBlockDeviceResource *)device 132 | rangesToPurge:(NSArray *)rangesToPurge; 133 | 134 | +(NSData *)getMD5Digest:(uint32_t)length 135 | forData:(const char *)data 136 | length:(uint32_t)DataLeng; 137 | 138 | +(bool)containsReadOnlyAttributes:(nonnull FSItemSetAttributesRequest *)attributes; 139 | 140 | +(void)enableMetaRW; 141 | 142 | #if DEBUG 143 | /* For testing use only. */ 144 | +(void)disableMetaRW; 145 | #endif 146 | 147 | +(void)setGMTDiffOffset; 148 | 149 | @end 150 | 151 | NS_ASSUME_NONNULL_END 152 | 153 | #endif /* utils_h */ 154 | -------------------------------------------------------------------------------- /msdosfs.kextproj/msdosfs.kmodproj/msdosfs_kdebug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 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. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | 24 | #include 25 | 26 | /* 27 | * Kernel Debug subclass for FAT is 0xF. 28 | * 29 | * That means that our codes are of the form 0x030Fxxxx. 30 | */ 31 | #define MSDOSFS_CODE(code) KDBG_CODE(DBG_FSYSTEM, 0xF, code) 32 | 33 | enum { 34 | MSDOSFS_VFS_MOUNT = MSDOSFS_CODE(0), /* 0x030f0000 */ 35 | MSDOSFS_VFS_START = MSDOSFS_CODE(1), /* 0x030f0004 */ 36 | MSDOSFS_VFS_UNMOUNT = MSDOSFS_CODE(2), /* 0x030f0008 */ 37 | MSDOSFS_VFS_ROOT = MSDOSFS_CODE(3), /* 0x030f000c */ 38 | MSDOSFS_VFS_GETATTR = MSDOSFS_CODE(4), /* 0x030f0010 */ 39 | MSDOSFS_VFS_SYNC = MSDOSFS_CODE(5), /* 0x030f0014 */ 40 | MSDOSFS_VFS_INIT = MSDOSFS_CODE(6), /* 0x030f0018 */ 41 | MSDOSFS_VFS_SYSCTL = MSDOSFS_CODE(7), /* 0x030f001c */ 42 | MSDOSFS_VFS_SETATTR = MSDOSFS_CODE(8), /* 0x030f0020 */ 43 | MSDOSFS_VFS_STATFS = MSDOSFS_CODE(9), /* 0x030f0024 */ 44 | 45 | MSDOSFS_VNOP_LOOKUP = MSDOSFS_CODE(16), /* 0x030f0040 */ 46 | MSDOSFS_VNOP_CREATE = MSDOSFS_CODE(17), /* 0x030f0044 */ 47 | MSDOSFS_VNOP_MKNOD = MSDOSFS_CODE(18), /* 0x030f0048 */ 48 | MSDOSFS_VNOP_OPEN = MSDOSFS_CODE(19), /* 0x030f004c */ 49 | MSDOSFS_VNOP_CLOSE = MSDOSFS_CODE(20), /* 0x030f0050 */ 50 | MSDOSFS_VNOP_GETATTR = MSDOSFS_CODE(21), /* 0x030f0054 */ 51 | MSDOSFS_VNOP_SETATTR = MSDOSFS_CODE(22), /* 0x030f0058 */ 52 | MSDOSFS_VNOP_READ = MSDOSFS_CODE(23), /* 0x030f005c */ 53 | MSDOSFS_VNOP_WRITE = MSDOSFS_CODE(24), /* 0x030f0060 */ 54 | MSDOSFS_VNOP_FSYNC = MSDOSFS_CODE(25), /* 0x030f0064 */ 55 | MSDOSFS_VNOP_REMOVE = MSDOSFS_CODE(26), /* 0x030f0068 */ 56 | MSDOSFS_VNOP_RENAME = MSDOSFS_CODE(27), /* 0x030f006c */ 57 | MSDOSFS_VNOP_MKDIR = MSDOSFS_CODE(28), /* 0x030f0070 */ 58 | MSDOSFS_VNOP_RMDIR = MSDOSFS_CODE(29), /* 0x030f0074 */ 59 | MSDOSFS_VNOP_READDIR = MSDOSFS_CODE(30), /* 0x030f0078 */ 60 | MSDOSFS_VNOP_INACTIVE = MSDOSFS_CODE(31), /* 0x030f007c */ 61 | MSDOSFS_VNOP_RECLAIM = MSDOSFS_CODE(32), /* 0x030f0080 */ 62 | MSDOSFS_VNOP_PATHCONF = MSDOSFS_CODE(33), /* 0x030f0084 */ 63 | MSDOSFS_VNOP_PAGEIN = MSDOSFS_CODE(34), /* 0x030f0088 */ 64 | MSDOSFS_VNOP_PAGEOUT = MSDOSFS_CODE(35), /* 0x030f008c */ 65 | MSDOSFS_VNOP_BLKTOOFF = MSDOSFS_CODE(36), /* 0x030f0090 */ 66 | MSDOSFS_VNOP_OFFTOBLK = MSDOSFS_CODE(37), /* 0x030f0094 */ 67 | MSDOSFS_VNOP_BLOCKMAP = MSDOSFS_CODE(38), /* 0x030f0098 */ 68 | MSDOSFS_VNOP_STRATEGY = MSDOSFS_CODE(39), /* 0x030f009c */ 69 | MSDOSFS_VNOP_SYMLINK = MSDOSFS_CODE(40), /* 0x030f00a0 */ 70 | MSDOSFS_VNOP_READLINK = MSDOSFS_CODE(41), /* 0x030f00a4 */ 71 | MSDOSFS_VNOP_IOCTL = MSDOSFS_CODE(42), /* 0x030f00a8 */ 72 | 73 | MSDOSFS_UPDATE_FSINFO = MSDOSFS_CODE(64), /* 0x030f0100 */ 74 | MSDOSFS_FAT_CACHE_FLUSH = MSDOSFS_CODE(65), /* 0x030f0104 */ 75 | MSDOSFS_FAT_MAP = MSDOSFS_CODE(66), /* 0x030f0108 */ 76 | MSDOSFS_META_FLUSH_INTERNAL = MSDOSFS_CODE(67), /* 0x030f010c */ 77 | MSDOSFS_META_FLUSH = MSDOSFS_CODE(68), /* 0x030f0110 */ 78 | MSDOSFS_META_SYNC_CALLBACK = MSDOSFS_CODE(69), /* 0x030f0114 */ 79 | MSDOSFS_PCBMAP_INTERNAL = MSDOSFS_CODE(70), /* 0x030f0118 */ 80 | MSDOSFS_PCBMAP = MSDOSFS_CODE(71), /* 0x030f011c */ 81 | /* 0x030f0120 was MSDOSFS_CLUSTERFREE_INTERNAL */ 82 | /* 0x030f0124 was MSDOSFS_CLUSTERFREE */ 83 | MSDOSFS_FATENTRY_INTERNAL = MSDOSFS_CODE(74), /* 0x030f0128 */ 84 | MSDOSFS_FATENTRY = MSDOSFS_CODE(75), /* 0x030f012c */ 85 | MSDOSFS_FATCHAIN = MSDOSFS_CODE(76), /* 0x030f0130 */ 86 | MSDOSFS_CHAINLENGTH = MSDOSFS_CODE(77), /* 0x030f0134 */ 87 | MSDOSFS_CHAINALLOC = MSDOSFS_CODE(78), /* 0x030f0138 */ 88 | MSDOSFS_CLUSTERALLOC_INTERNAL= MSDOSFS_CODE(79), /* 0x030f013c */ 89 | MSDOSFS_CLUSTERALLOC = MSDOSFS_CODE(80), /* 0x030f0140 */ 90 | MSDOSFS_FREECLUSTERCHAIN = MSDOSFS_CODE(81), /* 0x030f0144 */ 91 | MSDOSFS_COUNT_FREE_CLUSTERS = MSDOSFS_CODE(82), /* 0x030f0148 */ 92 | MSDOSFS_EXTENDFILE = MSDOSFS_CODE(83), /* 0x030f014c */ 93 | MSDOSFS_MARKVOLDIRTY = MSDOSFS_CODE(84), /* 0x030f0150 */ 94 | MSDOSFS_FAT_FSYNC = MSDOSFS_CODE(85), /* 0x030f0154 */ 95 | MSDOSFS_FIND_FREE_EXTENTS = MSDOSFS_CODE(86), /* 0x030f0158 */ 96 | MSDOSFS_FIND_NEXT_FREE = MSDOSFS_CODE(87), /* 0x030f015C */ 97 | MSDOSFS_LOOKUP_NAME = MSDOSFS_CODE(88), /* 0x030f0160 */ 98 | MSDOSFS_FINDSLOTS = MSDOSFS_CODE(89), /* 0x030f0164 */ 99 | MSDOSFS_UNIQDOSNAME = MSDOSFS_CODE(90), /* 0x030f0168 */ 100 | MSDOSFS_CREATEDE = MSDOSFS_CODE(91), /* 0x030f016C */ 101 | MSDOSFS_FREESPACE = MSDOSFS_CODE(92), /* 0x030f0170 */ 102 | }; -------------------------------------------------------------------------------- /msdos_appex/DirNameCache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Apple Inc. All rights reserved. 3 | */ 4 | 5 | #ifndef DirNameCache_h 6 | #define DirNameCache_h 7 | 8 | #import "ExtensionCommon.h" 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | typedef struct NameCacheEntry_s { 13 | uint32_t hash; 14 | uint32_t indexInDir; 15 | } NameCacheEntry; 16 | 17 | @interface NameCacheBucket : NSObject { 18 | @public NameCacheEntry * _Nullable elements; 19 | } 20 | @property uint32_t currCount; 21 | @property uint32_t currSize; 22 | 23 | @end 24 | 25 | 26 | @interface DirNameCache : NSObject 27 | @property NSMutableDictionary *nameCacheBuckets; 28 | @property (atomic) bool isInUse; 29 | @property (atomic) bool isIncomplete; 30 | /* Save this property of the DirItem to convert a 64b offset to an index*/ 31 | @property uint32_t dirEntrySize; 32 | 33 | /* 34 | * Initialize a DNC with the dir entry size of the dir, so we can convert between 35 | * an entry's offset (64b) and its index in the dir (32b). 36 | */ 37 | -(instancetype _Nullable)initWithDirEntrySize:(uint32_t)dirEntrySize; 38 | /** Add an entry to the cache. 39 | @param chrString The entry's utf8 name 40 | @param stringLen The string's length 41 | @param offset The entry's offset in the directory 42 | @return Nil on success, the appropriate NSError in case an error happened. 43 | */ 44 | -(NSError * _Nullable)insertDirEntryNamed:(char *)chrString 45 | ofLength:(size_t)stringLen 46 | offsetInDir:(uint64_t)offset; 47 | /** Remove the entry from the cache. 48 | @param chrString The entry's utf8 name 49 | @param stringLen The string's length 50 | @param offset The entry's offset 51 | */ 52 | -(void)removeDirEntryNamed:(char *)chrString 53 | ofLength:(size_t)stringLen 54 | offsetInDir:(uint64_t)offset; 55 | /** Lookup an entry to get its offset in the directory. 56 | If there are several hashed values with the same hash(name) result, the first 57 | one will be returned. 58 | @param chrString The entry's utf8 name 59 | @param stringLen The string's length 60 | @param reply Reply block with the error (nil on success) and the entry offset. 61 | */ 62 | -(void)lookupDirEntryNamed:(char *)chrString 63 | ofLength:(size_t)stringLen 64 | replyHandler:(void(^)(NSError *error, 65 | uint64_t entryOffsetInDir)) reply; 66 | 67 | /** Add an entry to the cache. 68 | @param name The entry's utf16 name 69 | @param offset The entry's offset in the directory 70 | @return Nil on success, the appropriate NSError in case an error happened. 71 | */ 72 | -(NSError * _Nullable)insertDirEntryNamedUtf16:(struct unistr255 *)name 73 | offsetInDir:(uint64_t)offset; 74 | /** Remove the entry from the cache. 75 | @param name The entry's utf16 name 76 | @param offset The entry's offset 77 | */ 78 | -(void)removeDirEntryNamedUtf16:(struct unistr255 *)name 79 | offsetInDir:(uint64_t)offset; 80 | /** Lookup an entry to get its offset in the directory. 81 | If there are several hashed values with the same hash(name) result, the first 82 | one will be returned. 83 | @param name The entry's utf16 name 84 | @param reply Reply block with the error (nil on success) and the entry offset. 85 | */ 86 | -(void)lookupDirEntryNamedUtf16:(struct unistr255 *)name 87 | replyHandler:(void(^)(NSError *error, 88 | uint64_t entryOffsetInDir)) reply; 89 | 90 | 91 | @end 92 | 93 | 94 | @interface DNCPoolEntry : NSObject 95 | @end 96 | 97 | @class DirItem; 98 | 99 | /** 100 | The DirNameCachePool serves as a LRU cache for directory name caches. It limits 101 | the number of DNCs we have at any given moment to keep our memory footprint at 102 | bay. 103 | When a new DNC is needed, the LRU entry which is not in use is evacuated and a 104 | new DNC is being allocated that slot. 105 | */ 106 | @interface DirNameCachePool : NSObject 107 | 108 | /** 109 | Retrieves a DirNameCache from the main cache. The cache is limited in space, 110 | so it has up to entries, being defined in initWithSize. 111 | Once a DNC is retrieved, it will not be purged from the cache until 112 | doneWithNameCacheForDir will be called for it. The number of DirNameCache instances 113 | in the main cache is limited. getNameCacheForDir will wait for one of the instances to be available 114 | but after some time it will give up and will return nil DirNameCache with no error. 115 | 116 | @param dir The directory for which to retrieve a cache 117 | @param cachedOnly If true and no cache exists for that directory, don't create a new cache 118 | @param reply Reply block which returns an error (nil on success), the name 119 | cache (or nil) and whether or not this cache is new or was already 120 | cached. 121 | */ 122 | -(void)getNameCacheForDir:(DirItem*)dir 123 | cachedOnly:(bool)cachedOnly /* If true, don't create a new table if there isn't one already */ 124 | replyHandler:(void(^)(NSError * _Nullable error, 125 | DirNameCache * _Nullable cache, 126 | bool isNew))reply; 127 | 128 | /** 129 | Remove a DNC from the cache. 130 | The cache frees the LRU entries when needed, but this method allows users to 131 | actively reduce the cache's size. 132 | 133 | @param dir The directory for which to find and remove the name cache. 134 | */ 135 | 136 | /** 137 | Assumption: Called while holding the DNC 138 | Mark the DNC as not being used and freeing a cache slot to be used by other threads. 139 | This makes the DNC purgeable. 140 | 141 | @param dir The directory for which the DNC is no longer in use 142 | */ 143 | -(void)removeNameCacheForDir:(nonnull DirItem *)dir; 144 | 145 | /** 146 | Assumption: Called while holding the DNC 147 | Mark the DNC as not being used and freeing a cache slot to be used by other threads. 148 | This makes the DNC purgeable. 149 | 150 | @param dir The directory for which to find and mark the cache as not in use. 151 | */ 152 | -(void)doneWithNameCacheForDir:(DirItem*)dir; 153 | -(void)check; 154 | 155 | @end 156 | 157 | NS_ASSUME_NONNULL_END 158 | 159 | #endif /* DirNameCache_h */ 160 | -------------------------------------------------------------------------------- /newfs_msdos.tproj/newfs_msdos.8: -------------------------------------------------------------------------------- 1 | .\" Copyright (c) 1998 Robert Nordier 2 | .\" All rights reserved. 3 | .\" 4 | .\" Redistribution and use in source and binary forms, with or without 5 | .\" modification, are permitted provided that the following conditions 6 | .\" are met: 7 | .\" 1. Redistributions of source code must retain the above copyright 8 | .\" notice, this list of conditions and the following disclaimer. 9 | .\" 2. Redistributions in binary form must reproduce the above copyright 10 | .\" notice, this list of conditions and the following disclaimer in 11 | .\" the documentation and/or other materials provided with the 12 | .\" distribution. 13 | .\" 14 | .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS 15 | .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY 18 | .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 20 | .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22 | .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 24 | .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | .\" 26 | .\" $FreeBSD: src/sbin/newfs_msdos/newfs_msdos.8,v 1.9 2000/05/07 09:08:31 kris Exp $ 27 | .\" 28 | .Dd July 6, 1998 29 | .Dt NEWFS_MSDOS 8 30 | .Os 31 | .Sh NAME 32 | .Nm newfs_msdos 33 | .Nd construct a new MS-DOS (FAT) file system 34 | .Sh SYNOPSIS 35 | .Nm newfs_msdos 36 | .Op Fl N 37 | .Op Fl B Ar boot 38 | .Op Fl F Ar FAT-type 39 | .Op Fl I Ar volid 40 | .Op Fl O Ar OEM 41 | .Op Fl S Ar sector-size 42 | .Op Fl a Ar FAT-size 43 | .Op Fl b Ar block-size 44 | .Op Fl c Ar cluster-size 45 | .Op Fl e Ar dirents 46 | .Op Fl f Ar format 47 | .Op Fl h Ar heads 48 | .Op Fl i Ar info 49 | .Op Fl k Ar backup 50 | .Op Fl m Ar media 51 | .Op Fl n Ar FATs 52 | .Op Fl o Ar hidden 53 | .Op Fl r Ar reserved 54 | .Op Fl s Ar total 55 | .Op Fl u Ar track-size 56 | .Op Fl v Ar volume-name 57 | .Ar special 58 | .Op Ar disktype 59 | .Sh DESCRIPTION 60 | The 61 | .Nm 62 | utility creates a FAT12, FAT16, or FAT32 file system on device 63 | .Ar special , 64 | using 65 | .Xr disktab 5 66 | entry 67 | .Ar disktype 68 | to determine geometry, if required. 69 | .Pp 70 | The options are as follows: 71 | .Bl -tag -width indent 72 | .It Fl N 73 | Don't create a file system: just print out parameters. 74 | .It Fl B Ar boot 75 | Get bootstrap from file. 76 | .It Fl F Ar FAT-type 77 | FAT type (one of 12, 16, or 32). 78 | .It Fl I Ar volid 79 | Volume ID. 80 | .It Fl O Ar OEM 81 | OEM string (up to 8 characters). The default is 82 | "BSD 4.4" (with two spaces). 83 | .It Fl S Ar sector-size 84 | Number of bytes per sector. Acceptable values are powers of 2 85 | in the range 128 through 32768. 86 | .It Fl a Ar FAT-size 87 | Number of sectors per FAT. 88 | .It Fl b Ar block-size 89 | File system block size (bytes per cluster). This should resolve to an 90 | acceptable number of sectors per cluster (see below). 91 | .It Fl c Ar cluster-size 92 | Sectors per cluster. Acceptable values are powers of 2 in the range 93 | 1 through 128. 94 | .It Fl e Ar dirents 95 | Number of root directory entries (FAT12 and FAT16 only). 96 | .It Fl f Ar format 97 | Specify a standard (floppy disk) format. The eight standard formats 98 | are (capacities in kilobytes): 160, 180, 320, 360, 640, 720, 1200, 99 | 1232, 1440, 2880. 100 | .It Fl h Ar heads 101 | Number of drive heads. 102 | .It Fl i Ar info 103 | Location of the file system info sector (FAT32 only). 104 | A value of 0xffff signifies no info sector. 105 | .It Fl k Ar backup 106 | Location of the backup boot sector (FAT32 only). A value 107 | of 0xffff signifies no backup sector. 108 | .It Fl m Ar media 109 | Media descriptor (acceptable range 0xf0 to 0xff). 110 | .It Fl n Ar FATs 111 | Number of FATs. Acceptable values are 1 to 16 inclusive. 112 | The default 113 | is 2. 114 | .It Fl o Ar hidden 115 | Number of hidden sectors. 116 | .It Fl r Ar reserved 117 | Number of reserved sectors. 118 | .It Fl s Ar total 119 | File system size, in sectors. 120 | .It Fl u Ar track-size 121 | Number of sectors per track. 122 | .It Fl v Ar volume-name 123 | Volume name (filesystem name), up to 11 characters. The name should consist of 124 | only those characters permitted in regular DOS (8+3) filenames. 125 | .El 126 | .Sh NOTES 127 | FAT file system parameters occupy a "Boot Sector BPB (BIOS Parameter 128 | Block)" in the first of the "reserved" sectors which precede the actual 129 | file system. For reference purposes, this structure is presented 130 | below. 131 | .Bd -literal 132 | struct bsbpb { 133 | u_int16_t bps; /* [-S] bytes per sector */ 134 | u_int8_t spc; /* [-c] sectors per cluster */ 135 | u_int16_t res; /* [-r] reserved sectors */ 136 | u_int8_t nft; /* [-n] number of FATs */ 137 | u_int16_t rde; /* [-e] root directory entries */ 138 | u_int16_t sec; /* [-s] total sectors */ 139 | u_int8_t mid; /* [-m] media descriptor */ 140 | u_int16_t spf; /* [-a] sectors per FAT */ 141 | u_int16_t spt; /* [-u] sectors per track */ 142 | u_int16_t hds; /* [-h] drive heads */ 143 | u_int32_t hid; /* [-o] hidden sectors */ 144 | u_int32_t bsec; /* [-s] big total sectors */ 145 | }; 146 | /* FAT32 extensions */ 147 | struct bsxbpb { 148 | u_int32_t bspf; /* [-a] big sectors per FAT */ 149 | u_int16_t xflg; /* control flags */ 150 | u_int16_t vers; /* file system version */ 151 | u_int32_t rdcl; /* root directory start cluster */ 152 | u_int16_t infs; /* [-i] file system info sector */ 153 | u_int16_t bkbs; /* [-k] backup boot sector */ 154 | }; 155 | .Ed 156 | .Sh EXAMPLES 157 | .Dl newfs_msdos /dev/disk0s1 158 | Create a file system, using default parameters, on /dev/disk0s1. 159 | .Pp 160 | .Dl newfs_msdos -f 1440 -v foo fd0 161 | Create a standard 1.44M file system, with volume name "foo", on 162 | /dev/fd0. 163 | .Sh SEE ALSO 164 | .Xr fdisk 8 , 165 | .Xr mount 8 166 | .Sh DIAGNOSTICS 167 | Exit status is 0 on success and 1 on error. 168 | .Sh HISTORY 169 | The 170 | .Nm 171 | command appeared in FreeBSD 3.0. 172 | .Sh AUTHORS 173 | .An Robert Nordier Aq rnordier@FreeBSD.org . 174 | -------------------------------------------------------------------------------- /msdos_appex/DirBlock.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Apple Inc. All rights reserved. 3 | */ 4 | 5 | #import 6 | #import "FATManager.h" 7 | #import "DirBlock.h" 8 | #import "DirItem.h" 9 | #import "utils.h" 10 | 11 | @interface DirBlock() 12 | 13 | @property DirItem *dir; 14 | @property NSMutableData *data; 15 | @property size_t size; 16 | 17 | @end 18 | 19 | @implementation DirBlock 20 | 21 | -(instancetype)initInDir:(DirItem *)dirItem 22 | { 23 | self = [super init]; 24 | if (self) { 25 | self.dir = dirItem; 26 | self.offsetInVolume = 0; 27 | self.size = [dirItem getDirBlockSize]; 28 | self.data = [NSMutableData dataWithLength:self.size]; 29 | dispatch_semaphore_wait(self.dir.sem, DISPATCH_TIME_FOREVER); 30 | } 31 | return self; 32 | } 33 | 34 | -(void)releaseBlock 35 | { 36 | dispatch_semaphore_signal(self.dir.sem); 37 | } 38 | 39 | -(NSError *)readDirBlockNum:(uint64_t)dirBlockNumberInVolume 40 | { 41 | uint64_t dirBlockOffsetInVolume = 0; 42 | if ([self.dir isFat1216RootDir]) { 43 | /* For FAT12/16, we have a single dir block for the root directory, and we know its offset. */ 44 | dirBlockOffsetInVolume = self.dir.volume.systemInfo.rootSector * self.dir.volume.systemInfo.bytesPerSector; 45 | } else { 46 | dirBlockOffsetInVolume = [self.dir.volume.systemInfo offsetForDirBlock:dirBlockNumberInVolume]; 47 | } 48 | NSError *error = [Utilities syncMetaReadFromDevice:self.dir.volume.resource 49 | into:self.data.mutableBytes 50 | startingAt:dirBlockOffsetInVolume 51 | length:self.size]; 52 | if (error == nil) { 53 | self.offsetInVolume = dirBlockOffsetInVolume; 54 | } 55 | return error; 56 | } 57 | 58 | -(NSError *)readRelativeDirBlockNum:(uint32_t)dirBlockIdxInDir 59 | { 60 | __block NSError *error = 0; 61 | __block uint32_t curNextCluster = 0; 62 | __block uint32_t numContigClusters = 0; 63 | uint32_t dirBlockNumInVolume = 0; 64 | uint32_t curStartCluster = self.dir.firstCluster; 65 | uint32_t curDirBlockIdx = 0; 66 | size_t dirBlockSize = self.dir.volume.systemInfo.dirBlockSize; 67 | size_t clusterSize = self.dir.volume.systemInfo.bytesPerCluster; 68 | size_t dirBlocksPerCluster = clusterSize / dirBlockSize; 69 | 70 | if ([self.dir isFat1216RootDir]) { 71 | /* For FAT12/16 root dir, we don't care about the "dirBlockNumInVolume", 72 | because we have a single dir block with fixed offset. */ 73 | return [self readDirBlockNum:0]; 74 | } 75 | 76 | while ([self.dir.volume.systemInfo isClusterValid:curStartCluster]) { 77 | [self.dir.volume.fatManager getContigClusterChainLengthStartingAt:curStartCluster 78 | replyHandler:^(NSError * _Nullable fatError, 79 | uint32_t length, 80 | uint32_t nextClusterInChain) { 81 | if (fatError) { 82 | error = fatError; 83 | } else { 84 | numContigClusters = length; 85 | curNextCluster = nextClusterInChain; 86 | } 87 | }]; 88 | 89 | if (error) { 90 | os_log_error(OS_LOG_DEFAULT, "%s: Failed to get the next cluster(s). Error = %@.", __func__, error); 91 | return error; 92 | } 93 | 94 | if ((curDirBlockIdx <= dirBlockIdxInDir) && 95 | (curDirBlockIdx + numContigClusters * dirBlocksPerCluster > dirBlockIdxInDir)) { 96 | /* We've got to a cluster we're interested in. */ 97 | dirBlockNumInVolume = (uint32_t)(curStartCluster * dirBlocksPerCluster + (dirBlockIdxInDir - curDirBlockIdx)); 98 | break; 99 | } 100 | curDirBlockIdx += numContigClusters * dirBlocksPerCluster; 101 | curStartCluster = curNextCluster; 102 | } 103 | 104 | if (dirBlockNumInVolume == 0) { 105 | /* Couldn't find the given dir block index (0 is an invalid value when we're not in FAT12/16 root dir). */ 106 | os_log_fault(OS_LOG_DEFAULT, "%s: Couldn't find dir block index %u. Dir Size = %llu.", __func__, dirBlockIdxInDir, [self.dir getDirSize]); 107 | return fs_errorForPOSIXError(EFAULT); 108 | } 109 | 110 | /* Succussfully converted the idx to absolute number. Now perform the actual read. */ 111 | return [self readDirBlockNum:dirBlockNumInVolume]; 112 | } 113 | 114 | 115 | -(void *)getBytesAtOffset:(uint64_t)offsetInDirBlock 116 | { 117 | if (offsetInDirBlock >= self.size) { 118 | os_log_error(OS_LOG_DEFAULT, "%s: unexpected offset in dir block (%llu), dir block size %zu", __FUNCTION__, offsetInDirBlock, self.size); 119 | return NULL; 120 | } 121 | return (void *)((uint8_t *)self.data.bytes + offsetInDirBlock); 122 | } 123 | 124 | -(NSError *)setBytes:(NSData *)data 125 | atOffset:(uint64_t)offsetInDirBlock 126 | { 127 | if (offsetInDirBlock + data.length > self.size) { 128 | return fs_errorForPOSIXError(EINVAL); 129 | } 130 | 131 | memcpy((uint8_t *)self.data.mutableBytes + offsetInDirBlock, (uint8_t*)data.bytes, data.length); 132 | return nil; 133 | } 134 | 135 | -(NSError *)writeToDisk 136 | { 137 | return [Utilities metaWriteToDevice:self.dir.volume.resource 138 | from:(void *)self.data.bytes 139 | startingAt:self.offsetInVolume 140 | length:self.size 141 | forceSyncWrite:false]; 142 | } 143 | 144 | -(NSError *)writeToDiskFromOffset:(uint64_t)offsetInDirBlock 145 | length:(uint64_t)lengthToWrite 146 | { 147 | if (offsetInDirBlock + lengthToWrite > self.size) { 148 | return fs_errorForPOSIXError(EINVAL); 149 | } 150 | // TODO: should be subblock meta write. Otherwise there's no reason for calling this method. 151 | // return [Utilities metaWriteToDevice:self.dir.volume.resource 152 | // from:(uint8_t *)(self.data.bytes) + offsetInDirBlock 153 | // startingAt:self.offsetInVolume + offsetInDirBlock 154 | // length:lengthToWrite]; 155 | return [self writeToDisk]; 156 | } 157 | 158 | @end 159 | -------------------------------------------------------------------------------- /lib_fsck_msdos/ext.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 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. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | /* 24 | * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank 25 | * Copyright (c) 1995 Martin Husemann 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. All advertising materials mentioning features or use of this software 36 | * must display the following acknowledgement: 37 | * This product includes software developed by Martin Husemann 38 | * and Wolfgang Solfrank. 39 | * 4. Neither the name of the University nor the names of its contributors 40 | * may be used to endorse or promote products derived from this software 41 | * without specific prior written permission. 42 | * 43 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 44 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 45 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 46 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 47 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 48 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 50 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 52 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 | */ 54 | 55 | #ifndef EXT_H 56 | #define EXT_H 57 | 58 | #include 59 | #include 60 | 61 | #include "dosfs.h" 62 | #include "lib_fsck_msdos.h" 63 | 64 | #define LOSTDIR "LOST.DIR" 65 | 66 | extern struct dosDirEntry *rootDir; 67 | 68 | /* 69 | * function declarations 70 | */ 71 | int ask __P((int, const char *, ...)); 72 | int vask __P((fsck_client_ctx_t, int, const char *, va_list)); 73 | 74 | /* 75 | * Check filesystem given as arg 76 | */ 77 | typedef struct check_context_s { 78 | void *updater; 79 | void (*startPhase)(char *description, int64_t pendingUnits, int64_t totalCount, unsigned int *completedCount, void *updater); 80 | void (*endPhase)(char *description, void *updater); 81 | void *resource; 82 | size_t (*readHelper)(void *resource, void *buffer, size_t nbytes, off_t offset); 83 | size_t (*writeHelper)(void *resource, void *buffer, size_t nbytes, off_t offset); 84 | int (*fstatHelper)(void *resource, struct stat *); 85 | char *shadowPrefix; 86 | int shadowFD; 87 | } check_context; 88 | int checkfilesys(const char *fname, check_context *context); 89 | 90 | /* 91 | * Return values of various functions 92 | */ 93 | #define FSOK 0 /* Check was OK */ 94 | #define FSBOOTMOD 1 /* Boot block was modified */ 95 | #define FSDIRMOD 2 /* Some directory was modified */ 96 | #define FSFATMOD 4 /* The FAT was modified */ 97 | #define FSERROR 8 /* Some unrecovered error remains */ 98 | #define FSFATAL 16 /* Some unrecoverable error occured */ 99 | #define FSDIRTY 32 /* File system is dirty */ 100 | #define FSFIXFAT 64 /* Fix file system FAT */ 101 | 102 | /* 103 | * read a boot block in a machine independend fashion and translate 104 | * it into our struct bootblock. 105 | */ 106 | int readboot __P((struct bootblock *, check_context*)); 107 | 108 | /* 109 | * Correct the FSInfo block. 110 | */ 111 | int writefsinfo __P((struct bootblock *, check_context*)); 112 | 113 | /* 114 | * Read a directory 115 | */ 116 | int resetDosDirSection(struct bootblock *boot, check_context *context); 117 | void finishDosDirSection __P((void)); 118 | int handleDirTree(int, struct bootblock *boot, int, check_context *context); 119 | 120 | /* 121 | * Small helper functions 122 | */ 123 | /* 124 | * Return the type of a reserved cluster as text 125 | */ 126 | char *rsrvdcltype __P((cl_t)); 127 | 128 | /* 129 | * Routines to read/write the FAT 130 | */ 131 | int fat_init(struct bootblock *boot, check_context *context); 132 | void fat_uninit(void); 133 | extern cl_t (*fat_get)(cl_t cluster, check_context *context); 134 | extern int (*fat_set)(cl_t cluster, cl_t value, check_context *context); 135 | int fat_free_unused(check_context *context); 136 | int fat_flush(check_context *context); 137 | /* 138 | * Determine whether a volume is dirty, without reading the entire FAT. 139 | */ 140 | int isdirty(struct bootblock *boot, int fat, check_context *context); 141 | /* 142 | * Mark the volume "clean." 143 | */ 144 | int fat_mark_clean(check_context *context); 145 | 146 | 147 | /* 148 | * Routines to track which clusters are in use (referenced by some directory entry). 149 | */ 150 | /* Returns error if memory cannot be allocated */ 151 | int initUseMap(struct bootblock *boot); 152 | void freeUseMap(void); 153 | /* Returns non-zero if block is marked allocated */ 154 | int isUsed(cl_t cluster); 155 | /* Returns non-zero if cluster already marked allocated */ 156 | int markUsed(cl_t cluster); 157 | /* Returns non-zero if cluster already marked free */ 158 | int markFree(cl_t cluster); 159 | 160 | #endif 161 | -------------------------------------------------------------------------------- /lib_fsck_msdos/fsutil.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000, 2005-2008 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 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. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | /* 24 | * Copyright (c) 1990, 1993 25 | * The Regents of the University of California. All rights reserved. 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. All advertising materials mentioning features or use of this software 36 | * must display the following acknowledgement: 37 | * This product includes software developed by the University of 38 | * California, Berkeley and its contributors. 39 | * 4. Neither the name of the University nor the names of its contributors 40 | * may be used to endorse or promote products derived from this software 41 | * without specific prior written permission. 42 | * 43 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 44 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 45 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 46 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 47 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 48 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 49 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 50 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 51 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 52 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 53 | * SUCH DAMAGE. 54 | */ 55 | 56 | #include 57 | 58 | #include 59 | #include 60 | #include 61 | #if __STDC__ 62 | #include 63 | #else 64 | #include 65 | #endif 66 | #include 67 | #include 68 | #include 69 | 70 | #include 71 | #include 72 | 73 | #include "ext.h" 74 | #include "fsutil.h" 75 | 76 | extern char *__progname; 77 | 78 | static void vmsg __P((int, const char *, va_list)); 79 | 80 | /*VARARGS*/ 81 | void 82 | #if __STDC__ 83 | errexit(const char *fmt, ...) 84 | #else 85 | errexit(va_alist) 86 | va_dcl 87 | #endif 88 | { 89 | va_list ap; 90 | 91 | #if __STDC__ 92 | va_start(ap, fmt); 93 | #else 94 | const char *fmt; 95 | 96 | va_start(ap); 97 | fmt = va_arg(ap, const char *); 98 | #endif 99 | (void) vfprintf(stderr, fmt, ap); 100 | va_end(ap); 101 | exit(8); 102 | } 103 | 104 | static void 105 | vmsg(int fatal, const char *fmt, va_list ap) 106 | { 107 | if (!fatal && fsck_preen()) 108 | (void) printf("%s: ", fsck_dev()); 109 | 110 | if (!fsck_quiet()) 111 | (void) vprintf(fmt, ap); 112 | 113 | if (fatal && fsck_preen()) 114 | (void) printf("\n"); 115 | 116 | if (fatal && fsck_preen()) { 117 | (void) printf("%s: UNEXPECTED INCONSISTENCY; RUN %s MANUALLY.\n", fsck_dev(), __progname); 118 | exit(8); 119 | } 120 | } 121 | 122 | /*VARARGS*/ 123 | void 124 | #if __STDC__ 125 | pfatal(const char *fmt, ...) 126 | #else 127 | pfatal(va_alist) 128 | va_dcl 129 | #endif 130 | { 131 | va_list ap; 132 | 133 | #if __STDC__ 134 | va_start(ap, fmt); 135 | #else 136 | const char *fmt; 137 | 138 | va_start(ap); 139 | fmt = va_arg(ap, const char *); 140 | #endif 141 | vpfatal(NULL, fmt, ap); 142 | va_end(ap); 143 | } 144 | 145 | /*VARARGS*/ 146 | void 147 | #if __STDC__ 148 | pwarn(const char *fmt, ...) 149 | #else 150 | pwarn(va_alist) 151 | va_dcl 152 | #endif 153 | { 154 | va_list ap; 155 | #if __STDC__ 156 | va_start(ap, fmt); 157 | #else 158 | const char *fmt; 159 | 160 | va_start(ap); 161 | fmt = va_arg(ap, const char *); 162 | #endif 163 | vpwarn(NULL, fmt, ap); 164 | va_end(ap); 165 | } 166 | 167 | #ifdef __APPLE__ 168 | __private_extern__ 169 | #endif 170 | void 171 | perrno(const char *s) 172 | { 173 | pfatal("%s (%s)\n", s, strerror(errno)); 174 | } 175 | 176 | void perr(const char *fmt, ...) 177 | { 178 | va_list ap; 179 | va_start(ap, fmt); 180 | vperr(NULL, fmt, ap); 181 | va_end(ap); 182 | } 183 | 184 | void vpfatal(fsck_client_ctx_t client, const char *fmt, va_list ap) 185 | { 186 | vmsg(1, fmt, ap); 187 | } 188 | 189 | void vpwarn(fsck_client_ctx_t client, const char *fmt, va_list ap) 190 | { 191 | vmsg(0, fmt, ap); 192 | } 193 | 194 | void vperr(fsck_client_ctx_t client, const char *fmt, va_list ap) 195 | { 196 | if (fsck_preen()) { 197 | (void) fprintf(stderr, "%s: ", fsck_dev()); 198 | } 199 | if (!fsck_quiet()) { 200 | (void) vfprintf(stderr, fmt, ap); 201 | } 202 | } 203 | 204 | void vprint(fsck_client_ctx_t client, int level, const char *fmt, va_list ap) 205 | { 206 | switch (level) { 207 | case LOG_INFO: 208 | vprintf(fmt, ap); 209 | break; 210 | case LOG_ERR: 211 | vperr(client, fmt, ap); 212 | break; 213 | case LOG_CRIT: 214 | vpfatal(client, fmt, ap); 215 | break; 216 | default: 217 | break; 218 | } 219 | } 220 | 221 | void fsck_print(lib_fsck_ctx_t c, int level, const char *fmt, ...) 222 | { 223 | if (c.print) { 224 | va_list ap; 225 | va_start(ap, fmt); 226 | c.print(c.client_ctx, level, fmt, ap); 227 | va_end(ap); 228 | } 229 | } 230 | 231 | int fsck_ask(lib_fsck_ctx_t c, int def, const char *fmt, ...) 232 | { 233 | if (c.ask) { 234 | va_list ap; 235 | va_start(ap, fmt); 236 | int retval = c.ask(c.client_ctx, def, fmt, ap); 237 | va_end(ap); 238 | return retval; 239 | } 240 | return -1; 241 | } 242 | -------------------------------------------------------------------------------- /lib_fsck_msdos/dosfs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 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. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | /* 24 | * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank 25 | * Copyright (c) 1995 Martin Husemann 26 | * Some structure declaration borrowed from Paul Popelka 27 | * (paulp@uts.amdahl.com), see /sys/msdosfs/ for reference. 28 | * 29 | * Redistribution and use in source and binary forms, with or without 30 | * modification, are permitted provided that the following conditions 31 | * are met: 32 | * 1. Redistributions of source code must retain the above copyright 33 | * notice, this list of conditions and the following disclaimer. 34 | * 2. Redistributions in binary form must reproduce the above copyright 35 | * notice, this list of conditions and the following disclaimer in the 36 | * documentation and/or other materials provided with the distribution. 37 | * 3. All advertising materials mentioning features or use of this software 38 | * must display the following acknowledgement: 39 | * This product includes software developed by Martin Husemann 40 | * and Wolfgang Solfrank. 41 | * 4. Neither the name of the University nor the names of its contributors 42 | * may be used to endorse or promote products derived from this software 43 | * without specific prior written permission. 44 | * 45 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 46 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 47 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 48 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 49 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 50 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 51 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 52 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 53 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 54 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 | */ 56 | 57 | #ifndef DOSFS_H 58 | #define DOSFS_H 59 | 60 | #define DOSBOOTBLOCKSIZE 512 61 | #define MAX_SECTOR_SIZE 4096 62 | 63 | typedef u_int32_t cl_t; /* type holding a cluster number */ 64 | 65 | /* 66 | * architecture independent description of all the info stored in a 67 | * FAT boot block. 68 | */ 69 | struct bootblock { 70 | u_int BytesPerSec; /* bytes per sector */ 71 | u_int SecPerClust; /* sectors per cluster */ 72 | u_int ResSectors; /* number of reserved sectors */ 73 | u_int FATs; /* number of FATs */ 74 | u_int RootDirEnts; /* number of root directory entries */ 75 | u_int Media; /* media descriptor */ 76 | u_int FATsmall; /* number of sectors per FAT */ 77 | u_int SecPerTrack; /* sectors per track */ 78 | u_int Heads; /* number of heads */ 79 | u_int32_t Sectors; /* total number of sectors */ 80 | u_int32_t HiddenSecs; /* # of hidden sectors */ 81 | u_int32_t HugeSectors; /* # of sectors if bpbSectors == 0 */ 82 | u_int FSInfo; /* FSInfo sector */ 83 | u_int Backup; /* Backup of Bootblocks */ 84 | cl_t RootCl; /* Start of Root Directory */ 85 | cl_t FSFree; /* Number of free clusters acc. FSInfo */ 86 | cl_t FSNext; /* Next free cluster acc. FSInfo */ 87 | 88 | /* and some more calculated values */ 89 | u_int flags; /* some flags: */ 90 | #ifndef FAT32 91 | #define FAT32 1 /* this is a FAT32 filesystem */ 92 | #endif 93 | /* 94 | * Maybe, we should separate out 95 | * various parts of FAT32? XXX 96 | */ 97 | int ValidFat; /* valid fat if FAT32 non-mirrored */ 98 | cl_t ClustMask; /* mask for entries in FAT */ 99 | cl_t NumClusters; /* # of entries in a FAT */ 100 | u_int32_t NumSectors; /* how many sectors are there */ 101 | u_int32_t FATsecs; /* how many sectors are in FAT */ 102 | u_int32_t NumFatEntries; /* how many entries really are there */ 103 | u_int ClusterOffset; /* at what sector would cluster #2 start */ 104 | u_int ClusterSize; /* Cluster size in bytes */ 105 | 106 | /* Now some statistics: */ 107 | u_int NumFiles; /* # of plain files */ 108 | u_int NumFree; /* # of free clusters */ 109 | u_int NumBad; /* # of bad clusters */ 110 | }; 111 | 112 | /* 113 | * Note: FAT32 only uses 28 bits for cluster numbers; the upper 4 bits are 114 | * reserved. For ease of coding, reserved/bad/EOF values are sign extended 115 | * to a full 32 bits regardless of FAT type. 116 | * 117 | * The CLUST_ERROR value is a value that can't be represented in the FAT. 118 | * It is a synthetic value that indicates an error occured. 119 | */ 120 | #define CLUST_FREE 0 /* 0 means cluster is free */ 121 | #define CLUST_FIRST 2 /* 2 is the minimum valid cluster number */ 122 | #define CLUST_ERROR 0xEEEEEEEE /* fat_get got an error */ 123 | #define CLUST_RSRVD 0xfffffff6 /* start of reserved clusters */ 124 | #define CLUST_BAD 0xfffffff7 /* a cluster with a defect */ 125 | #define CLUST_EOFS 0xfffffff8 /* start of EOF indicators */ 126 | #define CLUST_EOF 0xffffffff /* standard value for last cluster */ 127 | 128 | /* 129 | * Masks for cluster values 130 | */ 131 | #define CLUST12_MASK 0x0fff 132 | #define CLUST16_MASK 0xffff 133 | #define CLUST32_MASK 0x0fffffff 134 | 135 | #define DOSLONGNAMELEN 256 /* long name maximal length */ 136 | #define LRFIRST 0x40 /* first long name record */ 137 | #define LRNOMASK 0x1f /* mask to extract long record 138 | * sequence number */ 139 | 140 | /* 141 | * Architecture independent description of a directory entry 142 | */ 143 | struct dosDirEntry { 144 | struct dosDirEntry 145 | *parent, /* previous tree level */ 146 | *next, /* next brother */ 147 | *child; /* if this is a directory */ 148 | char name[8+1+3+1]; /* alias name first part */ 149 | char lname[DOSLONGNAMELEN]; /* real name */ 150 | uint flags; /* attributes */ 151 | cl_t head; /* cluster no */ 152 | cl_t end; /* cluster # to stop iterating at */ 153 | u_int32_t size; /* filesize in bytes */ 154 | u_int64_t physicalSize; /* Number of bytes in object's cluster chain */ 155 | uint fsckflags; /* flags during fsck */ 156 | }; 157 | /* Flags in fsckflags: */ 158 | #define DIREMPTY 1 159 | #define DIREMPWARN 2 160 | 161 | /* 162 | * TODO-list of unread directories 163 | */ 164 | struct dirTodoNode { 165 | struct dosDirEntry *dir; 166 | struct dirTodoNode *next; 167 | }; 168 | 169 | #endif 170 | -------------------------------------------------------------------------------- /msdos_appex/FATVolume.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Apple Inc. All rights reserved. 3 | */ 4 | 5 | #ifndef FATVolume_h 6 | #define FATVolume_h 7 | 8 | #import 9 | #import 10 | #import 11 | 12 | #import "utils.h" 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | typedef NS_ENUM(uint8_t, fatType) { 17 | FAT12, 18 | FAT16, 19 | FAT32, 20 | EXFAT 21 | }; 22 | 23 | 24 | @interface FileSystemInfo : NSObject 25 | 26 | @property fatType type; 27 | @property uint32_t FATMask; 28 | 29 | @property dirtyBitValue dirtyBitValue; 30 | @property dirtyBitValue dirtyBitValueOnDisk; 31 | 32 | @property size_t dirBlockSize; 33 | @property uint32_t bytesPerSector; 34 | @property uint32_t bytesPerCluster; 35 | 36 | @property uint32_t firstFreeCluster; 37 | @property uint32_t firstClusterOffset; /* in sectors */ 38 | @property uint64_t maxValidCluster; 39 | @property uint32_t firstDirBlockNum; 40 | 41 | @property uint64_t freeClusters; // FAT32 / ExFAT only 42 | @property uint32_t rootFirstCluster; // FAT32 / ExFAT only 43 | @property uint8_t numOfFATs; // MSDOS only 44 | 45 | @property uint32_t rootSector; // Offset in sectors from volume start to root dir start 46 | @property (nonatomic,readonly) uint64_t rootDirBytes; // Root dir size in bytes (msdos only). 47 | 48 | @property NSString *fsTypeName; 49 | @property NSString *fsSubTypeName; // TBD - remove when we have new FSVolume properties 50 | @property NSNumber *fsSubTypeNum; // TBD - remove when we have new FSVolume properties 51 | @property NSString *volumeLabel; 52 | @property bool volumeLabelExists; 53 | 54 | @property uint32_t serialNumber; 55 | @property bool serialNumberExists; 56 | 57 | @property FSVolumeIdentifier * _Nonnull uuid; 58 | @property bool uuidExists; 59 | 60 | @property uint64_t fatOffset; // Offset in bytes from volume start to active FAT 61 | @property uint64_t fatSize; // Size of FAT in bytes 62 | 63 | -(bool)isClusterValid:(uint32_t)cluster; 64 | 65 | -(uint64_t)offsetForCluster:(uint64_t)cluster; 66 | -(uint64_t)offsetForDirBlock:(uint64_t)dirBlock; 67 | 68 | -(bool)isFAT12Or16; 69 | 70 | -(uint64_t)fileSizeInBits; // TBD - remove when we have new FSVolume properties 71 | 72 | @end 73 | 74 | /// Use an array of this object when reporting back allocated clusters 75 | @interface AllocatedClustersInfo : NSObject 76 | 77 | @property uint32_t startCluster; 78 | @property uint32_t chainLength; 79 | 80 | @end 81 | 82 | 83 | @class DirNameCachePool; 84 | @class DirNameCache; 85 | @class ItemCache; 86 | @class FATManager; 87 | @class FATItem; 88 | @class DirItem; 89 | @class FileItem; 90 | @class SymLinkItem; 91 | @class DirEntryData; 92 | 93 | @protocol FATOps 94 | 95 | -(DirItem *)createDirItemWithParent:(FATItem * _Nullable)parentDir 96 | firstCluster:(uint32_t)firstCluster 97 | dirEntryData:(DirEntryData * _Nullable)dirEntryData 98 | name:(FSFileName *)name 99 | isRoot:(bool)isRoot; 100 | 101 | -(FileItem *)createFileItemWithParent:(FATItem * _Nullable)parentDir 102 | firstCluster:(uint32_t)firstCluster 103 | dirEntryData:(DirEntryData * _Nullable)dirEntryData 104 | name:(FSFileName *)name; 105 | 106 | -(SymLinkItem *)createSymlinkItemWithParent:(FATItem * _Nullable)parentDir 107 | firstCluster:(uint32_t)firstCluster 108 | dirEntryData:(DirEntryData * _Nullable)dirEntryData 109 | name:(FSFileName *)name 110 | symlinkLength:(uint16_t)length; 111 | 112 | -(void)FatMount:(FSTaskOptions *)options 113 | replyHandler:(void (^)(FSItem * _Nullable, NSError * _Nullable))reply; 114 | 115 | -(void)getFreeClustersStats:(uint32_t *_Nonnull)freeClusters 116 | replyHandler:(void (^)(NSError * _Nullable error))reply; 117 | 118 | -(void)calcNumOfDirEntriesForName:(struct unistr255)unistrName 119 | replyHandler:(void (^)(NSError * _Nullable error, uint32_t numberOfEntries))reply; 120 | 121 | -(void)nameToUnistr:(FSFileName *)name 122 | flags:(uint32_t)flags 123 | replyHandler:(void (^)(NSError *error, struct unistr255 unistrName))reply; 124 | 125 | -(NSError *)verifyFileSize:(uint64_t)fileSize; 126 | 127 | -(bool)isOffsetInMetadataZone:(uint64_t)offset; 128 | 129 | /* Per-FS syncing specifics go here, as msdos and ExFAT diverge */ 130 | -(NSError *)sync; 131 | 132 | -(void)setVolumeLabel:(NSData *)name 133 | rootDir:(DirItem *)rootItem 134 | replyHandler:(void (^)(FSFileName * _Nullable newVolumeName, 135 | NSError * _Nullable error))reply; 136 | 137 | @end 138 | 139 | 140 | @interface FATVolume : FSVolume 141 | 142 | @property FSItemDeactivationOptions itemDeactivationPolicy; 143 | @property FSBlockDeviceResource *resource; 144 | @property DirNameCachePool *nameCachePool; 145 | @property FileSystemInfo *systemInfo; 146 | @property FATManager *fatManager; 147 | @property ItemCache *itemCache; 148 | @property DirItem *rootItem; 149 | 150 | @property (nonatomic, readonly, getter=GetGMTDiffOffset) int gmtDiffOffset; 151 | 152 | -(instancetype)initWithResource:(FSResource *)resource 153 | volumeID:(nonnull FSVolumeIdentifier *)volumeID 154 | volumeName:(nonnull NSString *)volumeName; 155 | 156 | -(instancetype)init NS_UNAVAILABLE; 157 | 158 | -(NSError *)clearNewDirClustersFrom:(uint32_t)firstClusterToClear 159 | amount:(uint32_t)numClustersToClear; 160 | -(uint64_t)getFileID:(DirEntryData *)entryData; 161 | -(uint64_t)getNextAvailableFileID; 162 | - (FSItemGetAttributesRequest *)getAttrRequestForNewDirEntry; 163 | -(uint64_t)incNumberOfPreallocatedFiles; 164 | -(uint64_t)decNumberOfPreallocatedFiles; 165 | -(uint64_t)incNumberOfOpenUnlinkedFiles; 166 | -(uint64_t)decNumberOfOpenUnlinkedFiles; 167 | -(uint64_t)getNumberOfPreallocatedFiles; 168 | -(uint64_t)getNumberOfOpenUnlinkedFiles; 169 | 170 | @end 171 | 172 | 173 | /// Operations based on the file system subtype (FAT12, 16, 32) 174 | @interface FSOperations : NSObject 175 | 176 | @property fatType fatType; 177 | 178 | -(instancetype)init NS_UNAVAILABLE; 179 | -(id)initWithType:(fatType)type; 180 | 181 | /* 182 | * For FAT16/32, returns the amount of bytes it takes to 183 | * represent a cluster in the FAT. For FAT12, returning 0. 184 | * (For FAT12 there is no such constant. This is a function of the cluster number). 185 | * NOTE: In case this method returns 0, the caller should call fatEntryOffsetForCluster 186 | * for each cluster number to get the desired offset, rather than incrementing the offset. 187 | */ 188 | -(uint32_t)numBytesPerClusterInFat; 189 | 190 | -(uint32_t)fatEntryOffsetForCluster:(uint32_t)cluster; 191 | 192 | -(uint32_t)getNextClusterFromEntryForCluster:(uint32_t)cluster 193 | entry:(uint8_t*)entry; 194 | 195 | -(uint32_t)setFatEntryForCluster:(uint32_t)cluster 196 | entry:(uint8_t*)entry 197 | withValue:(uint32_t)value; 198 | 199 | -(uint32_t)getDirtyBitCluster; 200 | 201 | -(dirtyBitValue)getDirtyBitValueForEntry:(uint8_t *)dirtyBitEntry; 202 | 203 | -(void)applyDirtyBitValueToEntry:(uint8_t *)dirtyBitEntry 204 | newValue:(dirtyBitValue)newValue; 205 | 206 | @end 207 | 208 | 209 | NS_ASSUME_NONNULL_END 210 | #endif /* FATVolume_h */ 211 | -------------------------------------------------------------------------------- /fsck_msdos.tproj/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 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. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | /* 24 | * Copyright (C) 1995 Wolfgang Solfrank 25 | * Copyright (c) 1995 Martin Husemann 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. All advertising materials mentioning features or use of this software 36 | * must display the following acknowledgement: 37 | * This product includes software developed by Martin Husemann 38 | * and Wolfgang Solfrank. 39 | * 4. Neither the name of the University nor the names of its contributors 40 | * may be used to endorse or promote products derived from this software 41 | * without specific prior written permission. 42 | * 43 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 44 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 45 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 46 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 47 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 48 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 50 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 52 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 | */ 54 | 55 | 56 | #include 57 | #include 58 | 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #if __STDC__ 66 | #include 67 | #else 68 | #include 69 | #endif 70 | 71 | #include "fsutil.h" 72 | #include "ext.h" 73 | #include "lib_fsck_msdos.h" 74 | 75 | static void usage __P((void)); 76 | int main __P((int, char **)); 77 | 78 | static void 79 | usage(void) 80 | { 81 | printf("Usage: fsck_msdos [-fnpqy] [-M [k|K|m|M]] [-S path] filesystem ... \n"); 82 | exit(8); 83 | } 84 | 85 | static size_t 86 | fsckReadHelper(void *resource, void *buffer, size_t nbytes, off_t offset) 87 | { 88 | int *fd = (int*)resource; 89 | ssize_t readBytes = pread(*fd, buffer, nbytes, offset); 90 | 91 | return readBytes == nbytes ? readBytes : 0; 92 | } 93 | 94 | static size_t 95 | fsckWriteHelper(void *resource, void *buffer, size_t nbytes, off_t offset) 96 | { 97 | int *fd = (int*)resource; 98 | ssize_t written = pwrite(*fd, buffer, nbytes, offset); 99 | 100 | return written == nbytes ? written : 0; 101 | } 102 | 103 | static int 104 | fsckFstatHelper(void *resource, struct stat *buffer) 105 | { 106 | int *fd = (int*)resource; 107 | 108 | return fstat(*fd, buffer); 109 | } 110 | 111 | int 112 | main(int argc, char **argv) 113 | { 114 | check_context context = {0}; 115 | int ret = 0, erg; 116 | int ch; 117 | int offset; 118 | size_t maxmem = 0; 119 | 120 | fsck_set_context_properties(vprint, vask, NULL); 121 | context.shadowFD = -1; 122 | 123 | /* 124 | * Allow default maximum memory to be specified at compile time. 125 | */ 126 | #if FSCK_MAX_MEM 127 | maxmem = FSCK_MAX_MEM; 128 | #endif 129 | 130 | while ((ch = getopt(argc, argv, "pynfqM:S:")) != -1) { 131 | switch (ch) { 132 | case 'f': 133 | /* 134 | * We are always forced, since we don't 135 | * have a clean flag 136 | */ 137 | break; 138 | case 'n': 139 | fsck_set_alwaysno(1); 140 | fsck_set_alwaysyes(0); 141 | fsck_set_preen(0); 142 | break; 143 | case 'y': 144 | fsck_set_alwaysyes(1); 145 | fsck_set_alwaysno(0); 146 | fsck_set_preen(0); 147 | break; 148 | case 'p': 149 | fsck_set_preen(1); 150 | fsck_set_alwaysyes(0); 151 | fsck_set_alwaysno(0); 152 | break; 153 | case 'q': 154 | fsck_set_quick(true); 155 | break; 156 | case 'S': 157 | context.shadowPrefix = strdup(optarg); 158 | break; 159 | case 'M': 160 | if (sscanf(optarg, "%zi%n", &maxmem, &offset) == 0) 161 | { 162 | pfatal("Size argument '%s' not recognized\n", optarg); 163 | usage(); 164 | } 165 | switch (optarg[offset]) 166 | { 167 | case 'M': 168 | case 'm': 169 | maxmem *= 1024; 170 | /* Fall through */ 171 | case 'K': 172 | case 'k': 173 | maxmem *= 1024; 174 | if (optarg[offset+1]) 175 | goto bad_multiplier; 176 | break; 177 | case '\0': 178 | break; 179 | default: 180 | bad_multiplier: 181 | pfatal("Size multiplier '%s' not recognized\n", optarg+offset); 182 | usage(); 183 | } 184 | fsck_set_maxmem(maxmem); 185 | break; 186 | default: 187 | pfatal("Option '%c' not recognized\n", optopt); 188 | usage(); 189 | break; 190 | } 191 | } 192 | 193 | argc -= optind; 194 | argv += optind; 195 | 196 | if (!argc) 197 | usage(); 198 | 199 | context.readHelper = fsckReadHelper; 200 | context.writeHelper = fsckWriteHelper; 201 | context.fstatHelper = fsckFstatHelper; 202 | 203 | /* 204 | * Realistically, this does not work well with multiple filesystems. 205 | */ 206 | while (--argc >= 0) { 207 | fsck_set_dev(*argv); 208 | erg = checkfilesys(*argv++, &context); 209 | if (erg > ret) 210 | ret = erg; 211 | } 212 | 213 | return ret; 214 | } 215 | 216 | 217 | /*VARARGS*/ 218 | int 219 | #if __STDC__ 220 | ask(int def, const char *fmt, ...) 221 | #else 222 | ask(def, fmt, va_alist) 223 | int def; 224 | char *fmt; 225 | va_dcl 226 | #endif 227 | { 228 | va_list ap; 229 | #if __STDC__ 230 | va_start(ap, fmt); 231 | #else 232 | va_start(ap); 233 | #endif 234 | int ret = vask(NULL, def, fmt, ap); 235 | va_end(ap); 236 | return ret; 237 | } 238 | 239 | int vask(fsck_client_ctx_t client, int def, const char *fmt, va_list ap) 240 | { 241 | char prompt[256]; 242 | int c; 243 | 244 | if (fsck_preen()) { 245 | if (fsck_rdonly()) { 246 | def = 0; 247 | } 248 | if (def) { 249 | fsck_print(fsck_ctx, LOG_INFO, "FIXED\n"); 250 | } 251 | return def; 252 | } 253 | 254 | vsnprintf(prompt, sizeof(prompt), fmt, ap); 255 | 256 | if (fsck_alwaysyes() || fsck_rdonly()) { 257 | if (!fsck_quiet()) { 258 | fsck_print(fsck_ctx, LOG_INFO, "%s? %s\n", prompt, fsck_rdonly() ? "no" : "yes"); 259 | } 260 | return !fsck_rdonly(); 261 | } 262 | do { 263 | fsck_print(fsck_ctx, LOG_INFO, "%s? [yn] ", prompt); 264 | fflush(stdout); 265 | c = getchar(); 266 | while (c != '\n' && getchar() != '\n') { 267 | if (feof(stdin)) { 268 | return 0; 269 | } 270 | } 271 | } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); 272 | return c == 'y' || c == 'Y'; 273 | } 274 | -------------------------------------------------------------------------------- /msdosfs.kextproj/msdosfs.kmodproj/direntry.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000-2008, 2010-2012 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 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. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | /* $FreeBSD: src/sys/msdosfs/direntry.h,v 1.15 1999/12/29 04:54:52 peter Exp $ */ 24 | /* $NetBSD: direntry.h,v 1.14 1997/11/17 15:36:32 ws Exp $ */ 25 | 26 | /*- 27 | * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 28 | * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 29 | * All rights reserved. 30 | * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 31 | * 32 | * Redistribution and use in source and binary forms, with or without 33 | * modification, are permitted provided that the following conditions 34 | * are met: 35 | * 1. Redistributions of source code must retain the above copyright 36 | * notice, this list of conditions and the following disclaimer. 37 | * 2. Redistributions in binary form must reproduce the above copyright 38 | * notice, this list of conditions and the following disclaimer in the 39 | * documentation and/or other materials provided with the distribution. 40 | * 3. All advertising materials mentioning features or use of this software 41 | * must display the following acknowledgement: 42 | * This product includes software developed by TooLs GmbH. 43 | * 4. The name of TooLs GmbH may not be used to endorse or promote products 44 | * derived from this software without specific prior written permission. 45 | * 46 | * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 47 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49 | * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 50 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 51 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 52 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 53 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 54 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 55 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 | */ 57 | /* 58 | * Written by Paul Popelka (paulp@uts.amdahl.com) 59 | * 60 | * You can do anything you want with this software, just don't say you wrote 61 | * it, and don't remove this notice. 62 | * 63 | * This software is provided "as is". 64 | * 65 | * The author supplies this software to be publicly redistributed on the 66 | * understanding that the author is not responsible for the correct 67 | * functioning of this software in any circumstances and is not liable for 68 | * any damages caused by this software. 69 | * 70 | * October 1992 71 | */ 72 | 73 | /* 74 | * Structure of a dos directory entry. 75 | */ 76 | 77 | #ifndef __direntry_h_ 78 | #define __direntry_h_ 79 | 80 | struct dosdirentry { 81 | u_int8_t deName[8]; /* filename, blank filled */ 82 | #define SLOT_EMPTY 0x00 /* slot has never been used */ 83 | #define SLOT_E5 0x05 /* the real value is 0xe5 */ 84 | #define SLOT_DELETED 0xe5 /* file in this slot deleted */ 85 | u_int8_t deExtension[3]; /* extension, blank filled */ 86 | u_int8_t deAttributes; /* file attributes */ 87 | #define ATTR_NORMAL 0x00 /* normal file */ 88 | #define ATTR_READONLY 0x01 /* file is read-only (immutable) */ 89 | #define ATTR_HIDDEN 0x02 /* file is hidden */ 90 | #define ATTR_SYSTEM 0x04 /* file is a system file */ 91 | #define ATTR_VOLUME 0x08 /* entry is a volume label */ 92 | #define ATTR_DIRECTORY 0x10 /* entry is a directory name */ 93 | #define ATTR_ARCHIVE 0x20 /* file is new or modified */ 94 | u_int8_t deLowerCase; /* NT VFAT lower case flags */ 95 | #define LCASE_BASE 0x08 /* filename base in lower case */ 96 | #define LCASE_EXT 0x10 /* filename extension in lower case */ 97 | u_int8_t deCHundredth; /* hundredth of seconds in CTime */ 98 | u_int8_t deCTime[2]; /* create time */ 99 | u_int8_t deCDate[2]; /* create date */ 100 | u_int8_t deADate[2]; /* access date */ 101 | u_int8_t deHighClust[2]; /* high bytes of cluster number */ 102 | u_int8_t deMTime[2]; /* last update time */ 103 | u_int8_t deMDate[2]; /* last update date */ 104 | u_int8_t deStartCluster[2]; /* starting cluster of file */ 105 | u_int8_t deFileSize[4]; /* size of file in bytes */ 106 | }; 107 | 108 | /* 109 | * Structure of a Win95 long name directory entry 110 | */ 111 | struct winentry { 112 | u_int8_t weCnt; 113 | #define WIN_LAST 0x40 114 | #define WIN_CNT 0x3f 115 | u_int8_t wePart1[10]; 116 | u_int8_t weAttributes; 117 | #define ATTR_WIN95 0x0f 118 | #define ATTR_WIN95_MASK 0x3f 119 | u_int8_t weReserved1; 120 | u_int8_t weChksum; 121 | u_int8_t wePart2[12]; 122 | u_int16_t weReserved2; 123 | u_int8_t wePart3[4]; 124 | }; 125 | #define WIN_CHARS 13 /* Number of chars per winentry */ 126 | 127 | /* 128 | * Maximum filename length in Win95 129 | * Note: Must be < sizeof(dirent.d_name) 130 | */ 131 | #define WIN_MAXLEN 255 132 | 133 | /* 134 | * Maximum filename length for short names: 135 | * 8 bytes of filename plus 3 bytes of extension. 136 | * The dot between the filename and extension is implied. 137 | */ 138 | #define SHORT_NAME_LEN 11 139 | 140 | /* 141 | * This is the format of the contents of the deTime field in the dosdirentry 142 | * structure. 143 | * We don't use bitfields because we don't know how compilers for 144 | * arbitrary machines will lay them out. 145 | */ 146 | #define DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */ 147 | #define DT_2SECONDS_SHIFT 0 148 | #define DT_MINUTES_MASK 0x7E0 /* minutes */ 149 | #define DT_MINUTES_SHIFT 5 150 | #define DT_HOURS_MASK 0xF800 /* hours */ 151 | #define DT_HOURS_SHIFT 11 152 | 153 | /* 154 | * This is the format of the contents of the deDate field in the dosdirentry 155 | * structure. 156 | */ 157 | #define DD_DAY_MASK 0x1F /* day of month */ 158 | #define DD_DAY_SHIFT 0 159 | #define DD_MONTH_MASK 0x1E0 /* month */ 160 | #define DD_MONTH_SHIFT 5 161 | #define DD_YEAR_MASK 0xFE00 /* year - 1980 */ 162 | #define DD_YEAR_SHIFT 9 163 | 164 | #ifdef KERNEL 165 | struct dirent; 166 | void msdosfs_unix2dostime(struct timespec *tsp, u_int16_t *ddp, 167 | u_int16_t *dtp, u_int8_t *dhp); 168 | void msdosfs_dos2unixtime(u_int dd, u_int dt, u_int dh, struct timespec *tsp); 169 | size_t msdosfs_dos2unicodefn(u_char dn[SHORT_NAME_LEN], u_int16_t *un, int lower); 170 | int msdosfs_unicode_to_dos_name(const uint16_t *unicode, 171 | size_t unicode_length, 172 | uint8_t short_name[SHORT_NAME_LEN], 173 | u_int8_t *lower_case); 174 | int msdosfs_apply_generation_to_short_name(uint8_t short_name[SHORT_NAME_LEN], 175 | unsigned generation); 176 | int msdosfs_unicode2winfn(const u_int16_t *un, int unlen, struct winentry *wep, int cnt, int chksum); 177 | int msdosfs_winChkName(const u_int16_t *un, int unlen, struct winentry *wep, int chksum, u_int16_t *found_name, boolean_t *case_folded); 178 | int msdosfs_getunicodefn(struct winentry *wep, u_int16_t ucfn[WIN_MAXLEN], u_int16_t *unichars, int chksum); 179 | u_int8_t msdosfs_winChksum(u_int8_t *name); 180 | int msdosfs_winSlotCnt(const u_int16_t *un, int unlen); 181 | u_char msdosfs_unicode2dos(u_int16_t uc); 182 | int msdosfs_fsync_internal(vnode_t vp, int sync, int do_dirs, vfs_context_t context); 183 | 184 | #endif /* KERNEL */ 185 | 186 | #endif /* __direntry_h_ */ 187 | -------------------------------------------------------------------------------- /Info-msdos_fs.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleGetInfoString 8 | 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | msdos 17 | CFBundlePackageType 18 | fs 19 | CFBundleShortVersionString 20 | $(MSDOSFS_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(MSDOSFS_VERSION) 25 | FSMediaTypes 26 | 27 | C12A7328-F81F-11D2-BA4B-00A0C93EC93B 28 | 29 | FSMediaProperties 30 | 31 | Content Hint 32 | C12A7328-F81F-11D2-BA4B-00A0C93EC93B 33 | Leaf 34 | 35 | 36 | FSProbeArguments 37 | -p 38 | FSProbeExecutable 39 | msdos.util 40 | FSProbeOrder 41 | 1000 42 | autodiskmount 43 | 44 | 45 | DOS_FAT_12 46 | 47 | FSMediaProperties 48 | 49 | Content Hint 50 | DOS_FAT_12 51 | Leaf 52 | 53 | 54 | FSProbeArguments 55 | -p 56 | FSProbeExecutable 57 | msdos.util 58 | FSProbeOrder 59 | 1000 60 | 61 | DOS_FAT_16 62 | 63 | FSMediaProperties 64 | 65 | Content Hint 66 | DOS_FAT_16 67 | Leaf 68 | 69 | 70 | FSProbeArguments 71 | -p 72 | FSProbeExecutable 73 | msdos.util 74 | FSProbeOrder 75 | 1000 76 | 77 | DOS_FAT_16_S 78 | 79 | FSMediaProperties 80 | 81 | Content Hint 82 | DOS_FAT_16_S 83 | Leaf 84 | 85 | 86 | FSProbeArguments 87 | -p 88 | FSProbeExecutable 89 | msdos.util 90 | FSProbeOrder 91 | 1000 92 | 93 | DOS_FAT_32 94 | 95 | FSMediaProperties 96 | 97 | Content Hint 98 | DOS_FAT_32 99 | Leaf 100 | 101 | 102 | FSProbeArguments 103 | -p 104 | FSProbeExecutable 105 | msdos.util 106 | FSProbeOrder 107 | 1000 108 | 109 | EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 110 | 111 | FSMediaProperties 112 | 113 | Content Hint 114 | EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 115 | Leaf 116 | 117 | 118 | FSProbeArguments 119 | -p 120 | FSProbeExecutable 121 | msdos.util 122 | FSProbeOrder 123 | 2000 124 | 125 | Partitionless 126 | 127 | FSMediaProperties 128 | 129 | Leaf 130 | 131 | Whole 132 | 133 | 134 | FSProbeArguments 135 | -p 136 | FSProbeExecutable 137 | msdos.util 138 | FSProbeOrder 139 | 4000 140 | 141 | Windows_FAT_16 142 | 143 | FSMediaProperties 144 | 145 | Content Hint 146 | Windows_FAT_16 147 | Leaf 148 | 149 | 150 | FSProbeArguments 151 | -p 152 | FSProbeExecutable 153 | msdos.util 154 | FSProbeOrder 155 | 1000 156 | 157 | Windows_FAT_32 158 | 159 | FSMediaProperties 160 | 161 | Content Hint 162 | Windows_FAT_32 163 | Leaf 164 | 165 | 166 | FSProbeArguments 167 | -p 168 | FSProbeExecutable 169 | msdos.util 170 | FSProbeOrder 171 | 1000 172 | 173 | 174 | FSPersonalities 175 | 176 | MS-DOS 177 | 178 | FSFormatArguments 179 | 180 | FSFormatContentMask 181 | DOS_FAT_32 182 | FSFormatExecutable 183 | newfs_msdos 184 | FSFormatMaximumSize 185 | 8796093022208 186 | FSFormatMinimumSize 187 | 32768 188 | FSMountArguments 189 | 190 | FSMountExecutable 191 | mount_msdos 192 | FSName 193 | MS-DOS (FAT) 194 | FSRepairArguments 195 | -y 196 | FSRepairExecutable 197 | fsck_msdos 198 | FSVerificationArguments 199 | -n 200 | FSVerificationExecutable 201 | fsck_msdos 202 | 203 | MS-DOS FAT12 204 | 205 | FSFormatArguments 206 | -F 12 207 | FSFormatContentMask 208 | DOS_FAT_12 209 | FSFormatExecutable 210 | newfs_msdos 211 | FSFormatMaximumSize 212 | 133169152 213 | FSFormatMinimumSize 214 | 32768 215 | FSMountArguments 216 | 217 | FSMountExecutable 218 | mount_msdos 219 | FSName 220 | MS-DOS (FAT12) 221 | FSRepairArguments 222 | -y 223 | FSRepairExecutable 224 | fsck_msdos 225 | FSSubType 226 | 0 227 | FSVerificationArguments 228 | -n 229 | FSVerificationExecutable 230 | fsck_msdos 231 | 232 | MS-DOS FAT16 233 | 234 | FSFormatArguments 235 | -F 16 236 | FSFormatContentMask 237 | DOS_FAT_16 238 | FSFormatExecutable 239 | newfs_msdos 240 | FSFormatMaximumSize 241 | 2147483648 242 | FSFormatMinimumSize 243 | 4299161 244 | FSMountArguments 245 | 246 | FSMountExecutable 247 | mount_msdos 248 | FSName 249 | MS-DOS (FAT16) 250 | FSRepairArguments 251 | -y 252 | FSRepairExecutable 253 | fsck_msdos 254 | FSSubType 255 | 1 256 | FSVerificationArguments 257 | -n 258 | FSVerificationExecutable 259 | fsck_msdos 260 | 261 | MS-DOS FAT32 262 | 263 | FSFormatArguments 264 | -F 32 265 | FSFormatContentMask 266 | DOS_FAT_32 267 | FSFormatExecutable 268 | newfs_msdos 269 | FSFormatMaximumSize 270 | 8796093022208 271 | FSFormatMinimumSize 272 | 34603008 273 | FSMountArguments 274 | 275 | FSMountExecutable 276 | mount_msdos 277 | FSName 278 | MS-DOS (FAT32) 279 | FSRepairArguments 280 | -y 281 | FSRepairExecutable 282 | fsck_msdos 283 | FSSubType 284 | 2 285 | FSVerificationArguments 286 | -n 287 | FSVerificationExecutable 288 | fsck_msdos 289 | 290 | 291 | FSImplementation 292 | 293 | UserFS 294 | kext 295 | 296 | 297 | 298 | -------------------------------------------------------------------------------- /msdos_appex/DirItem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Apple Inc. All rights reserved. 3 | */ 4 | 5 | #ifndef DirItem_h 6 | #define DirItem_h 7 | 8 | #import 9 | #import "FATItem.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @protocol DirOps 14 | 15 | /** Returns the dir block size that should be used for thie directory. */ 16 | -(uint64_t)getDirBlockSize; 17 | 18 | /** Returns the directory size. */ 19 | -(uint64_t)getDirSize; 20 | 21 | /** Returns the directory entry struct size. */ 22 | -(uint32_t)dirEntrySize; 23 | 24 | /** 25 | * Create '.' and '..' dir entries for a newly created directory. 26 | * Sub-classes should implement this method in case they need to create '.' and '..' dir entries when we create new directories. 27 | */ 28 | -(NSError *)createDotEntriesWithAttrs:(FSItemAttributes *)mkdirAttrs; 29 | 30 | /** 31 | * Update the modification time of the directory. 32 | * Sub-classes should implement this method in case they need to update the 33 | * modification time of the directory when we create/remove items in it. 34 | */ 35 | -(NSError *)updateModificationTimeOnCreateRemove; 36 | 37 | /** 38 | * Update A/M/B times of the dot ('.') dir entry if so required by the given attributes. 39 | */ 40 | -(NSError *)updateDotDirEntryTimes:(FSItemSetAttributesRequest *)attrs; 41 | /** 42 | Directory iterator. 43 | @param startOffsetInDir offset from which to start iterating. 44 | @param options special options to apply when iterating. 45 | @param reply the reply block returns iterateDirStatus, which tells the iterator whether it should continue or stop iterating the dir. 46 | In case of a failure, the reply block is called with a non-nil error and zeros/nils, and its return value is ignored. 47 | - result is the type of the found dir entry. 48 | - dirEntryOffsetInVolume is the entry's offset in the volume. 49 | - dirEntryOffset is the entry offset in the directory. 50 | - name is the entry's name. 51 | - dirEntryData is the entry's data. 52 | */ 53 | -(void)iterateFromOffset:(uint64_t)startOffsetInDir 54 | options:(iterateDirOptions)options 55 | replyHandler:(iterateDirStatus (^)(NSError *error, 56 | dirEntryType result, 57 | uint64_t dirEntryOffset, 58 | struct unistr255 * _Nullable name, 59 | DirEntryData * _Nullable dirEntryData))reply; 60 | 61 | /** 62 | Create new directory entry-set for a new item. 63 | @param unistrName new item name in UTF-16. 64 | @param itemType new item type 65 | @param firstCluster first cluster of the new item 66 | @param attrs new item attributes 67 | @param offsetInDir offset in dir for the new entry-set 68 | @param hidden true if the file is hidden, false o.w 69 | @param reply In case of success, calls reply with error = nil and the created dirEntryData object. 70 | In case of an error, calls reply with error != nil, and dirEntryData = nil. 71 | */ 72 | -(void)createEntrySetForName:(struct unistr255)unistrName 73 | itemType:(FSItemType)itemType 74 | firstCluster:(uint32_t)firstCluster 75 | attrs:(FSItemAttributes *)attrs 76 | offsetInDir:(uint64_t)offsetInDir 77 | hidden:(bool)hidden 78 | replyHandler:(void (^)(NSError * _Nullable error, 79 | DirEntryData * _Nullable dirEntryData))reply; 80 | 81 | /** 82 | Create and write directory entries to disk, based on the given data and name, at the given offset in dir. 83 | @param dirEntryData dir entry data to write and/or generate the name entries from. 84 | @param startOffsetInDir the offset in dir to which we should start writing. 85 | @param name item name to generate the name entries from. 86 | @param numberOfEntries number of entries to write. 87 | */ 88 | -(NSError *)writeDirEntriesToDisk:(DirEntryData *)dirEntryData 89 | atOffset:(uint64_t)startOffsetInDir 90 | name:(struct unistr255)name 91 | numberOfEntries:(uint32_t)numberOfEntries; 92 | 93 | /** 94 | Write the given dir entry data to disk. 95 | @param dirEntryData dir entry data to write 96 | */ 97 | -(NSError *)writeDirEntryDataToDisk:(DirEntryData *)dirEntryData; 98 | 99 | /** 100 | Mark directory entry-set as deleted for a new item. 101 | @param forItem item to mark as seleted in the directory 102 | */ 103 | -(NSError *)markDirEntriesAsDeleted:(FATItem *)forItem; 104 | 105 | -(NSError *)verifyCookieOffset:(uint32_t)offset; 106 | 107 | @end 108 | 109 | 110 | @interface DirItem : FATItem 111 | 112 | @property bool isRoot; 113 | @property uint64_t dirVersion; 114 | @property DirNameCache * _Nullable dirNameCache; 115 | @property uint32_t tableBusyCount; 116 | @property uint32_t maxRADirBlock; 117 | @property uint64_t offsetForNewEntry; 118 | @property dispatch_semaphore_t sem; 119 | 120 | /* 121 | * TODO: we have ifdef MSDOS/EXFAT_NLINK_IS_CHILD_COUNT which aren't defined anywhere. 122 | * What do we want to do about them? 123 | */ 124 | 125 | /** Returns true in case the volume is FAT12/FAT16, and this is the root directory. */ 126 | -(bool)isFat1216RootDir; 127 | 128 | /** 129 | Lookup a specific dir entry in the directory 130 | @param lookupName dir entry name to lookup 131 | @param nameCache dir name cache to lookup in. If nil, don't lookup in cache. 132 | @param lookupOffset optional hint to where to look for the dir entry. 133 | @param reply In case of a failure returns a non-nil error and dirEntryData = nil. Else, error is nil and the relevant dir entry data is returned. 134 | */ 135 | -(void)lookupDirEntryNamed:(FSFileName *)lookupName 136 | dirNameCache:(DirNameCache * _Nullable)nameCache 137 | lookupOffset:(uint64_t * _Nullable)lookupOffset 138 | replyHandler:(void (^)(NSError *error, 139 | DirEntryData *dirEntryData))reply; 140 | 141 | /** Fills the given name cache with all dir entries of the directory. */ 142 | -(NSError * _Nullable)fillNameCache:(DirNameCache *)nameCache; 143 | 144 | /** 145 | Create a new directory entry-set for a new item, look for available slots in dir to place it, and write it to disk. 146 | @param name new item name 147 | @param type new item type 148 | @param attrs new item attributes 149 | @param firstDataCluster first cluster of the new item 150 | @param reply In case of success, calls reply with error = nil, dirEntryOffsetInVolume = first dir entry offset in the volume, offsetInDir = the starting offset in dir of the newly created dir entries. 151 | In case of an error, calls reply with error != nil, dirEntryOffsetInVolume = 0 and offsetInDir = 0. 152 | */ 153 | -(void)createNewDirEntryNamed:(FSFileName *)name 154 | type:(FSItemType)type 155 | attributes:(FSItemAttributes *)attrs 156 | firstDataCluster:(uint32_t)firstDataCluster 157 | replyHandler:(void (^)(NSError * _Nullable error, 158 | uint64_t offsetInDir))reply; 159 | 160 | /** 161 | Iterate over dir entries and write their updated contents to disk if requested. 162 | @param startOffsetInDir offset in dir to start iterating from. 163 | @param numberOfEntries number of dir entries to iterate over. 164 | @param writeToDisk whether or not to write the updated dir entries to disk. 165 | @param reply in case of success, called for each dir entry we're iterating over. 166 | In case of an error, calls reply with error != nil, and dirEntry = nil. 167 | */ 168 | -(void)iterateDirEntriesAtOffset:(uint64_t)startOffsetInDir 169 | numEntries:(uint32_t)numberOfEntries 170 | shouldWriteToDisk:(bool)writeToDisk 171 | replyHandler:(void (^)(NSError * _Nullable error, void * _Nullable dirEntry))reply; 172 | 173 | /** 174 | Mark directory entry-set as deleted for a new item and update the directory modify time. 175 | Returns NSError when failed to mark the directory entries as deleted. 176 | @param forItem item to mark as seleted in the directory 177 | */ 178 | -(NSError *)markDirEntriesAsDeletedAndUpdateMtime:(FATItem *)forItem; 179 | 180 | /** Return NSError if the directory is not empty or if could not complete the check. o.w return nil */ 181 | -(NSError *)checkIfEmpty; 182 | 183 | /** 184 | Get the start offset of the dir entry for given index in the directory. 185 | @param index index number starting from zero. 186 | @param reply in case of success, called with nil error, offset of the dir entry and reachedEOF == false. 187 | In case of an error, calls reply with error != nil. In case the index >= number of entries found in the directory, 188 | called with error == nil, reachedEOF == true. 189 | */ 190 | -(void)getDirEntryOffsetByIndex:(uint32_t)index 191 | replyHandler:(void (^)(NSError * _Nullable error, uint64_t offset, bool reachedEOF))reply; 192 | 193 | @end 194 | 195 | NS_ASSUME_NONNULL_END 196 | 197 | #endif /* DirItem_h */ 198 | -------------------------------------------------------------------------------- /msdosfs.kextproj/msdosfs.kmodproj/bpb.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000-2008, 2010-2011 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 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. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | /* $FreeBSD: src/sys/msdosfs/bpb.h,v 1.7 1999/08/28 00:48:07 peter Exp $ */ 24 | /* $NetBSD: bpb.h,v 1.7 1997/11/17 15:36:24 ws Exp $ */ 25 | 26 | /* 27 | * Written by Paul Popelka (paulp@uts.amdahl.com) 28 | * 29 | * You can do anything you want with this software, just don't say you wrote 30 | * it, and don't remove this notice. 31 | * 32 | * This software is provided "as is". 33 | * 34 | * The author supplies this software to be publicly redistributed on the 35 | * understanding that the author is not responsible for the correct 36 | * functioning of this software in any circumstances and is not liable for 37 | * any damages caused by this software. 38 | * 39 | * October 1992 40 | */ 41 | 42 | /* 43 | * BIOS Parameter Block (BPB) for DOS 3.3 44 | */ 45 | struct bpb33 { 46 | u_int16_t bpbBytesPerSec; /* bytes per sector */ 47 | u_int8_t bpbSecPerClust; /* sectors per cluster */ 48 | u_int16_t bpbResSectors; /* number of reserved sectors */ 49 | u_int8_t bpbFATs; /* number of FATs */ 50 | u_int16_t bpbRootDirEnts; /* number of root directory entries */ 51 | u_int16_t bpbSectors; /* total number of sectors */ 52 | u_int8_t bpbMedia; /* media descriptor */ 53 | u_int16_t bpbFATsecs; /* number of sectors per FAT */ 54 | u_int16_t bpbSecPerTrack; /* sectors per track */ 55 | u_int16_t bpbHeads; /* number of heads */ 56 | u_int16_t bpbHiddenSecs; /* number of hidden sectors */ 57 | }; 58 | 59 | /* 60 | * BPB for DOS 5.0 The difference is bpbHiddenSecs is a short for DOS 3.3, 61 | * and bpbHugeSectors is not in the 3.3 bpb. 62 | */ 63 | struct bpb50 { 64 | u_int16_t bpbBytesPerSec; /* bytes per sector */ 65 | u_int8_t bpbSecPerClust; /* sectors per cluster */ 66 | u_int16_t bpbResSectors; /* number of reserved sectors */ 67 | u_int8_t bpbFATs; /* number of FATs */ 68 | u_int16_t bpbRootDirEnts; /* number of root directory entries */ 69 | u_int16_t bpbSectors; /* total number of sectors */ 70 | u_int8_t bpbMedia; /* media descriptor */ 71 | u_int16_t bpbFATsecs; /* number of sectors per FAT */ 72 | u_int16_t bpbSecPerTrack; /* sectors per track */ 73 | u_int16_t bpbHeads; /* number of heads */ 74 | u_int32_t bpbHiddenSecs; /* # of hidden sectors */ 75 | u_int32_t bpbHugeSectors; /* # of sectors if bpbSectors == 0 */ 76 | }; 77 | 78 | /* 79 | * BPB for DOS 7.10 (FAT32). This one has a few extensions to bpb50. 80 | */ 81 | struct bpb710 { 82 | u_int16_t bpbBytesPerSec; /* bytes per sector */ 83 | u_int8_t bpbSecPerClust; /* sectors per cluster */ 84 | u_int16_t bpbResSectors; /* number of reserved sectors */ 85 | u_int8_t bpbFATs; /* number of FATs */ 86 | u_int16_t bpbRootDirEnts; /* number of root directory entries */ 87 | u_int16_t bpbSectors; /* total number of sectors */ 88 | u_int8_t bpbMedia; /* media descriptor */ 89 | u_int16_t bpbFATsecs; /* number of sectors per FAT */ 90 | u_int16_t bpbSecPerTrack; /* sectors per track */ 91 | u_int16_t bpbHeads; /* number of heads */ 92 | u_int32_t bpbHiddenSecs; /* # of hidden sectors */ 93 | u_int32_t bpbHugeSectors; /* # of sectors if bpbSectors == 0 */ 94 | u_int32_t bpbBigFATsecs; /* like bpbFATsecs for FAT32 */ 95 | u_int16_t bpbExtFlags; /* extended flags: */ 96 | #define FATNUM 0xf /* mask for numbering active FAT */ 97 | #define FATMIRROR 0x80 /* 0 == FAT is mirrored (like it always was) */ 98 | u_int16_t bpbFSVers; /* filesystem version */ 99 | #define FSVERS 0 /* currently only 0 is understood */ 100 | u_int32_t bpbRootClust; /* start cluster for root directory */ 101 | u_int16_t bpbFSInfo; /* filesystem info structure sector */ 102 | u_int16_t bpbBackup; /* backup boot sector */ 103 | /* There is a 12 byte filler here, but we ignore it */ 104 | }; 105 | 106 | 107 | /* 108 | * The following structures represent how the bpb's look on disk. Multi-byte 109 | * integers are just character arrays of the appropriate length. This is 110 | * because the compiler forces alignment, and some of our fields aren't 111 | * properly aligned. 112 | * 113 | * XXX The little-endian code here assumes that the processor can access 114 | * 16-bit and 32-bit quantities on byte boundaries. If this is not true, 115 | * use the macros for the big-endian case. 116 | */ 117 | #include 118 | #if (BYTE_ORDER == LITTLE_ENDIAN) /* && defined(UNALIGNED_ACCESS) */ 119 | #define getuint16(x) *((u_int16_t *)(x)) 120 | #define getuint32(x) *((u_int32_t *)(x)) 121 | #define putuint16(p, v) (*((u_int16_t *)(p)) = (v)) 122 | #define putuint32(p, v) (*((u_int32_t *)(p)) = (v)) 123 | #else 124 | #define getuint16(x) (((u_int8_t *)(x))[0] + (((u_int8_t *)(x))[1] << 8)) 125 | #define getuint32(x) (((u_int8_t *)(x))[0] + (((u_int8_t *)(x))[1] << 8) \ 126 | + (((u_int8_t *)(x))[2] << 16) \ 127 | + (((u_int8_t *)(x))[3] << 24)) 128 | #define putuint16(p, v) (((u_int8_t *)(p))[0] = (v) & 0xFF, \ 129 | ((u_int8_t *)(p))[1] = ((v) >> 8) & 0xFF) 130 | #define putuint32(p, v) (((u_int8_t *)(p))[0] = (v) & 0xFF, \ 131 | ((u_int8_t *)(p))[1] = ((v) >> 8) & 0xFF, \ 132 | ((u_int8_t *)(p))[2] = ((v) >> 16) & 0xFF, \ 133 | ((u_int8_t *)(p))[3] = ((v) >> 24) & 0xFF) 134 | #endif 135 | 136 | /* 137 | * BIOS Parameter Block (BPB) for DOS 3.3 138 | */ 139 | struct byte_bpb33 { 140 | u_int8_t bpbBytesPerSec[2]; /* bytes per sector */ 141 | u_int8_t bpbSecPerClust; /* sectors per cluster */ 142 | u_int8_t bpbResSectors[2]; /* number of reserved sectors */ 143 | u_int8_t bpbFATs; /* number of FATs */ 144 | u_int8_t bpbRootDirEnts[2]; /* number of root directory entries */ 145 | u_int8_t bpbSectors[2]; /* total number of sectors */ 146 | u_int8_t bpbMedia; /* media descriptor */ 147 | u_int8_t bpbFATsecs[2]; /* number of sectors per FAT */ 148 | u_int8_t bpbSecPerTrack[2]; /* sectors per track */ 149 | u_int8_t bpbHeads[2]; /* number of heads */ 150 | u_int8_t bpbHiddenSecs[2]; /* number of hidden sectors */ 151 | }; 152 | 153 | /* 154 | * BPB for DOS 5.0 The difference is bpbHiddenSecs is a short for DOS 3.3, 155 | * and bpbHugeSectors is not in the 3.3 bpb. 156 | */ 157 | struct byte_bpb50 { 158 | u_int8_t bpbBytesPerSec[2]; /* bytes per sector */ 159 | u_int8_t bpbSecPerClust; /* sectors per cluster */ 160 | u_int8_t bpbResSectors[2]; /* number of reserved sectors */ 161 | u_int8_t bpbFATs; /* number of FATs */ 162 | u_int8_t bpbRootDirEnts[2]; /* number of root directory entries */ 163 | u_int8_t bpbSectors[2]; /* total number of sectors */ 164 | u_int8_t bpbMedia; /* media descriptor */ 165 | u_int8_t bpbFATsecs[2]; /* number of sectors per FAT */ 166 | u_int8_t bpbSecPerTrack[2]; /* sectors per track */ 167 | u_int8_t bpbHeads[2]; /* number of heads */ 168 | u_int8_t bpbHiddenSecs[4]; /* number of hidden sectors */ 169 | u_int8_t bpbHugeSectors[4]; /* # of sectors if bpbSectors == 0 */ 170 | }; 171 | 172 | /* 173 | * BPB for DOS 7.10 (FAT32). This one has a few extensions to bpb50. 174 | */ 175 | struct byte_bpb710 { 176 | u_int8_t bpbBytesPerSec[2]; /* bytes per sector */ 177 | u_int8_t bpbSecPerClust; /* sectors per cluster */ 178 | u_int8_t bpbResSectors[2]; /* number of reserved sectors */ 179 | u_int8_t bpbFATs; /* number of FATs */ 180 | u_int8_t bpbRootDirEnts[2]; /* number of root directory entries */ 181 | u_int8_t bpbSectors[2]; /* total number of sectors */ 182 | u_int8_t bpbMedia; /* media descriptor */ 183 | u_int8_t bpbFATsecs[2]; /* number of sectors per FAT */ 184 | u_int8_t bpbSecPerTrack[2]; /* sectors per track */ 185 | u_int8_t bpbHeads[2]; /* number of heads */ 186 | u_int8_t bpbHiddenSecs[4]; /* # of hidden sectors */ 187 | u_int8_t bpbHugeSectors[4]; /* # of sectors if bpbSectors == 0 */ 188 | u_int8_t bpbBigFATsecs[4]; /* like bpbFATsecs for FAT32 */ 189 | u_int8_t bpbExtFlags[2]; /* extended flags: */ 190 | u_int8_t bpbFSVers[2]; /* filesystem version */ 191 | u_int8_t bpbRootClust[4]; /* start cluster for root directory */ 192 | u_int8_t bpbFSInfo[2]; /* filesystem info structure sector */ 193 | u_int8_t bpbBackup[2]; /* backup boot sector */ 194 | /* There is a 12 byte filler here, but we ignore it */ 195 | }; 196 | 197 | /* 198 | * FAT32 FSInfo block. 199 | */ 200 | struct fsinfo { 201 | u_int8_t fsisig1[4]; 202 | u_int8_t fsifill1[480]; 203 | u_int8_t fsisig2[4]; 204 | u_int8_t fsinfree[4]; 205 | u_int8_t fsinxtfree[4]; 206 | u_int8_t fsifill2[12]; 207 | u_int8_t fsisig3[4]; 208 | }; 209 | -------------------------------------------------------------------------------- /msdos_appex/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | EXAppExtensionAttributes 6 | 7 | FSSupportsServerURLs 8 | 9 | FSSupportsBlockResources 10 | 11 | FSSupportsKernelOffloadedIO 12 | 13 | FSShortName 14 | msdos 15 | EXExtensionPointIdentifier 16 | com.apple.fskit.fsmodule 17 | EXExtensionPrincipalClass 18 | msdosFileSystem 19 | FSMediaTypes 20 | 21 | C12A7328-F81F-11D2-BA4B-00A0C93EC93B 22 | 23 | FSMediaProperties 24 | 25 | Content Hint 26 | C12A7328-F81F-11D2-BA4B-00A0C93EC93B 27 | Leaf 28 | 29 | 30 | FSProbeArguments 31 | -p 32 | FSProbeExecutable 33 | msdos.util 34 | FSProbeOrder 35 | 1000 36 | autodiskmount 37 | 38 | 39 | DOS_FAT_12 40 | 41 | FSMediaProperties 42 | 43 | Content Hint 44 | DOS_FAT_12 45 | Leaf 46 | 47 | 48 | FSProbeArguments 49 | -p 50 | FSProbeExecutable 51 | msdos.util 52 | FSProbeOrder 53 | 1000 54 | 55 | DOS_FAT_16 56 | 57 | FSMediaProperties 58 | 59 | Content Hint 60 | DOS_FAT_16 61 | Leaf 62 | 63 | 64 | FSProbeArguments 65 | -p 66 | FSProbeExecutable 67 | msdos.util 68 | FSProbeOrder 69 | 1000 70 | 71 | DOS_FAT_16_S 72 | 73 | FSMediaProperties 74 | 75 | Content Hint 76 | DOS_FAT_16_S 77 | Leaf 78 | 79 | 80 | FSProbeArguments 81 | -p 82 | FSProbeExecutable 83 | msdos.util 84 | FSProbeOrder 85 | 1000 86 | 87 | DOS_FAT_32 88 | 89 | FSMediaProperties 90 | 91 | Content Hint 92 | DOS_FAT_32 93 | Leaf 94 | 95 | 96 | FSProbeArguments 97 | -p 98 | FSProbeExecutable 99 | msdos.util 100 | FSProbeOrder 101 | 1000 102 | 103 | EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 104 | 105 | FSMediaProperties 106 | 107 | Content Hint 108 | EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 109 | Leaf 110 | 111 | 112 | FSProbeArguments 113 | -p 114 | FSProbeExecutable 115 | msdos.util 116 | FSProbeOrder 117 | 2000 118 | 119 | Partitionless 120 | 121 | FSMediaProperties 122 | 123 | Leaf 124 | 125 | Whole 126 | 127 | 128 | FSProbeArguments 129 | -p 130 | FSProbeExecutable 131 | msdos.util 132 | FSProbeOrder 133 | 4000 134 | 135 | Windows_FAT_16 136 | 137 | FSMediaProperties 138 | 139 | Content Hint 140 | Windows_FAT_16 141 | Leaf 142 | 143 | 144 | FSProbeArguments 145 | -p 146 | FSProbeExecutable 147 | msdos.util 148 | FSProbeOrder 149 | 1000 150 | 151 | Windows_FAT_32 152 | 153 | FSMediaProperties 154 | 155 | Content Hint 156 | Windows_FAT_32 157 | Leaf 158 | 159 | 160 | FSProbeArguments 161 | -p 162 | FSProbeExecutable 163 | msdos.util 164 | FSProbeOrder 165 | 1000 166 | 167 | 168 | FSPersonalities 169 | 170 | MS-DOS 171 | 172 | FSFormatArguments 173 | 174 | FSFormatContentMask 175 | DOS_FAT_32 176 | FSFormatExecutable 177 | newfs_msdos 178 | FSFormatMaximumSize 179 | 8796093022208 180 | FSFormatMinimumSize 181 | 32768 182 | FSMountArguments 183 | 184 | FSMountExecutable 185 | mount_msdos 186 | FSName 187 | MS-DOS (FAT) 188 | FSRepairArguments 189 | -y 190 | FSRepairExecutable 191 | fsck_msdos 192 | FSVerificationArguments 193 | -n 194 | FSVerificationExecutable 195 | fsck_msdos 196 | 197 | MS-DOS FAT12 198 | 199 | FSFormatArguments 200 | -F 12 201 | FSFormatContentMask 202 | DOS_FAT_12 203 | FSFormatExecutable 204 | newfs_msdos 205 | FSFormatMaximumSize 206 | 133169152 207 | FSFormatMinimumSize 208 | 32768 209 | FSMountArguments 210 | 211 | FSMountExecutable 212 | mount_msdos 213 | FSName 214 | MS-DOS (FAT12) 215 | FSRepairArguments 216 | -y 217 | FSRepairExecutable 218 | fsck_msdos 219 | FSSubType 220 | 0 221 | FSVerificationArguments 222 | -n 223 | FSVerificationExecutable 224 | fsck_msdos 225 | 226 | MS-DOS FAT16 227 | 228 | FSFormatArguments 229 | -F 16 230 | FSFormatContentMask 231 | DOS_FAT_16 232 | FSFormatExecutable 233 | newfs_msdos 234 | FSFormatMaximumSize 235 | 2147483648 236 | FSFormatMinimumSize 237 | 4299161 238 | FSMountArguments 239 | 240 | FSMountExecutable 241 | mount_msdos 242 | FSName 243 | MS-DOS (FAT16) 244 | FSRepairArguments 245 | -y 246 | FSRepairExecutable 247 | fsck_msdos 248 | FSSubType 249 | 1 250 | FSVerificationArguments 251 | -n 252 | FSVerificationExecutable 253 | fsck_msdos 254 | 255 | MS-DOS FAT32 256 | 257 | FSFormatArguments 258 | -F 32 259 | FSFormatContentMask 260 | DOS_FAT_32 261 | FSFormatExecutable 262 | newfs_msdos 263 | FSFormatMaximumSize 264 | 8796093022208 265 | FSFormatMinimumSize 266 | 34603008 267 | FSMountArguments 268 | 269 | FSMountExecutable 270 | mount_msdos 271 | FSName 272 | MS-DOS (FAT32) 273 | FSRepairArguments 274 | -y 275 | FSRepairExecutable 276 | fsck_msdos 277 | FSSubType 278 | 2 279 | FSVerificationArguments 280 | -n 281 | FSVerificationExecutable 282 | fsck_msdos 283 | 284 | 285 | FSCheckOptionSyntax 286 | 287 | shortOptions 288 | pynfqM: 289 | 290 | FSFormatOptionSyntax 291 | 292 | shortOptions 293 | NB:F:I:O:S:P:a:b:c:e:f:h:i:k:m:n:o:r:s:u:v: 294 | 295 | FSActivateOptionSyntax 296 | 297 | shortOptions 298 | u:g:m:o: 299 | 300 | 301 | 302 | 303 | -------------------------------------------------------------------------------- /msdos_appex/FATItem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Apple Inc. All rights reserved. 3 | */ 4 | 5 | #ifndef FATItem_h 6 | #define FATItem_h 7 | 8 | #import 9 | #import 10 | 11 | #import "FATVolume.h" 12 | #import "utils.h" 13 | 14 | typedef NS_ENUM(uint8_t, dirEntryType) { 15 | FATDirEntryDeleted = 0, 16 | FATDirEntryEmpty, 17 | FATDirEntryFound, 18 | FATDirEntryVolName, 19 | FATDirEntryUnknown, 20 | FATDirEntryStart, 21 | }; 22 | 23 | typedef NS_OPTIONS(uint32_t, iterateDirOptions) { 24 | iterateDirOptionSkipDotEntries = 1, // Don't call the reply block for '.' and '..' dir entries 25 | }; 26 | 27 | typedef NS_ENUM(uint8_t, iterateDirStatus) { 28 | iterateDirContinue = 0, 29 | iterateDirStop 30 | }; 31 | 32 | NS_ASSUME_NONNULL_BEGIN 33 | 34 | @interface DirEntryData : NSObject 35 | 36 | @property NSMutableData *data; 37 | @property uint16_t numberOfDirEntries; 38 | @property uint64_t firstEntryOffsetInDir; 39 | 40 | +(instancetype)dynamicCast:(id)candidate; 41 | -(instancetype)initWithData:(NSData *)data; 42 | -(void)getAccessTime:(struct timespec *)tp; 43 | -(void)setAccessTime:(struct timespec *)tp; 44 | -(void)getModifyTime:(struct timespec *)tp; 45 | -(void)setModifyTime:(struct timespec *)tp; 46 | -(void)getChangeTime:(struct timespec *)tp; 47 | -(void)setChangeTime:(struct timespec *)tp; 48 | -(void)getBirthTime:(struct timespec *)tp; 49 | -(void)setBirthTime:(struct timespec *)tp; 50 | -(uint32_t)getFirstCluster:(id)systemInfo; 51 | -(void)setFirstCluster:(uint32_t)firstCluster 52 | fileSystemInfo:(FileSystemInfo *)systemInfo; 53 | -(uint8_t *)getName; 54 | -(void)setName:(uint8_t *)name; 55 | -(uint64_t)getSize; 56 | -(void)setSize:(uint64_t)size; 57 | -(uint64_t)getValidDataLength; 58 | -(void)setValidDataLength:(uint64_t)validDataLength; 59 | -(void)setArchiveBit; 60 | 61 | -(uint64_t)calcFirstEntryOffsetInVolume:(FileSystemInfo *)systemInfo; 62 | 63 | @property (nonatomic,readonly) FSItemType type; 64 | @property (nonatomic,readonly) uint32_t bsdFlags; 65 | 66 | @end 67 | 68 | 69 | @interface FATItem : FSItem 70 | 71 | @property FATVolume *volume; 72 | 73 | @property FSFileName *name; 74 | /** 75 | Set to false upon creation, set to true if the item becomes open-unlinked. 76 | In this case, there are operations that are not allowed on the item. 77 | */ 78 | @property bool isDeleted; 79 | /** 80 | Set to false upon creation, set to true if the item becomes open-unlinked. 81 | Set to false again in inactive/reclaim, once this item is no longer counted as 82 | one of the volume's open-unlinked files. 83 | */ 84 | @property bool includedInVolumeOUFiles; 85 | 86 | @property FATItem * _Nullable parentDir; 87 | 88 | @property (nonatomic) uint32_t firstCluster; 89 | @property (nonatomic) uint32_t firstClusterInLastAllocation; 90 | @property (nonatomic) uint32_t firstClusterIndexInLastAllocation; 91 | @property uint32_t lastCluster; 92 | @property uint32_t numberOfClusters; 93 | 94 | @property DirEntryData * _Nullable entryData; 95 | 96 | @property (strong, nonatomic) dispatch_queue_t queue; 97 | 98 | +(instancetype)dynamicCast:(id)candidate; 99 | 100 | - (instancetype)init NS_UNAVAILABLE; 101 | 102 | -(instancetype)initInVolume:(FATVolume *)volume 103 | inDir:(FATItem * _Nullable)parentDir 104 | startingAt:(uint32_t)firstCluster 105 | withData:(DirEntryData * _Nullable)entryData 106 | andName:(FSFileName *)name 107 | isRoot:(bool)isRoot; 108 | 109 | -(uint64_t)getFileID; 110 | 111 | -(FSItemAttributes *)getAttributes:(nonnull FSItemGetAttributesRequest *)desired; 112 | 113 | -(NSError *)setAttributes:(nonnull FSItemSetAttributesRequest *)newAttributes; 114 | 115 | -(NSError *)flushDirEntryData; 116 | 117 | -(void)setDeleted; 118 | 119 | -(NSError *)reclaim:(bool)isInactive; 120 | 121 | /* 122 | * Symlinks have a non constant block size, so the implementation slightly 123 | * differs from the implementation for directory, where we should purge all 124 | * the blocks we get from the FATManager up to a known size. 125 | */ 126 | -(void)purgeMetaBlocksFromCache:(void (^)(NSError * _Nullable error))reply; 127 | 128 | @end 129 | 130 | 131 | @interface SymLinkItem: FATItem 132 | 133 | @property uint16_t symlinkLength; 134 | 135 | +(NSError *)createSymlinkFromContent:(nonnull NSData *)contents 136 | inBuffer:(nonnull NSMutableData *)buffer; 137 | 138 | +(void)verifyAndGetLink:(NSMutableData *)linkData 139 | replyHandler:(nonnull void (^)(NSError * _Nullable, NSString * _Nullable linkStr))reply; 140 | 141 | @end 142 | 143 | 144 | @interface FileItem : FATItem 145 | 146 | @property bool isPreAllocated; 147 | @property uint64_t writeCounter; 148 | @property NSMutableDictionary *blockmapRequests; 149 | 150 | -(instancetype)initInVolume:(FATVolume *)volume 151 | inDir:(FATItem * _Nullable)parentDir 152 | startingAt:(uint32_t)firstCluster 153 | withData:(DirEntryData * _Nullable)entryData 154 | andName:(FSFileName *)name; 155 | 156 | -(uint64_t)maxFileSize; 157 | 158 | /** 159 | Truncate the file to the given size. 160 | NOTE: this method only allocates the clusters. It doesn't update the entry data with the new file size, nor flushes it to disk. 161 | It does update the entry data with the first cluster, if needed. 162 | @param newSize The desired new file size. 163 | @param allowPartial Whether we allow to only allocate part of the needed clusters (if we have no space for all). 164 | (only relevant in case newSize > current file size). 165 | @param mustBeContig Whether we require new allocted space to be contiguous on disk or not. 166 | In case of success, returns nil, o.w. returns the error. 167 | */ 168 | -(NSError *)truncateTo:(uint64_t)newSize 169 | allowPartial:(bool)allowPartial 170 | mustBeContig:(bool)mustBeContig; 171 | 172 | /** 173 | Blockmap the given range in the file. 174 | @param offset File offset to start blockmap. 175 | @param length File length of requested mapping. 176 | @param flags blockmapFile flags. 177 | @param operationID a unique ID for this blockmapFile operation. Used for saving some context to use in completeIO. 178 | @param packer extent packer 179 | @param reply In case of an error, calling reply(error). In case of success, calling reply(nil). 180 | */ 181 | -(void)blockmapOffset:(off_t)offset 182 | length:(size_t)length 183 | flags:(FSBlockmapFlags)flags 184 | operationID:(FSOperationID)operationID 185 | packer:(FSExtentPacker *)packer 186 | replyHandler:(nonnull void (^)(NSError * _Nullable error))reply; 187 | 188 | /** 189 | completeIO the given range in the file. 190 | @param offset IO completed starting at this offset. 191 | @param length File length of completed IO. 192 | @param ioStatus Whether the IO succeeded or not. 193 | @param flags completeIO flags. 194 | @param operationID the operationID used for the corresponding blockmapFile operation. 195 | */ 196 | -(NSError *)completeIOAtOffset:(off_t)offset 197 | length:(size_t)length 198 | status:(int)ioStatus 199 | flags:(FSCompleteIOFlags)flags 200 | operationID:(FSOperationID)operationID; 201 | 202 | /** 203 | Fetch the relevant extents of the given file. 204 | @param startOffset The offset in file to start fetching the extents from. 205 | @param endOffset The offset in file to stop fetching the extents at. 206 | (we stop fetching extents when we reach this limit, even if we haven't got to endOffset). 207 | @param packer The extent packer block 208 | @param reply In case of an error, calling reply(error, nil, 0). In case of success, calling reply(nil, extentsData, numOfExtentsFetched). 209 | */ 210 | -(void)fetchFileExtentsFrom:(uint64_t)startOffset 211 | to:(uint64_t)endOffset 212 | usingBlocks:(FSExtentPacker *)packer 213 | replyHandler:(nonnull void (^)(NSError * _Nullable error))reply; 214 | 215 | /** 216 | Preallocate more bytes to the file allocated space. 217 | @param size Size in bytes to be preallocated. 218 | @param allowPartial Whether we allow to only preallocate part of the needed clusters (if we have no space for all). 219 | (only relevant in case newSize > current file size). 220 | @param mustBeContig Whether we require preallocted sace to be contiguous on disk or not. 221 | Beyond that offset, we start returning "zero-fill" extents. 222 | @param reply In case of an error, calling reply(error, 0). In case of success, calling reply(nil, AllocatedSize) when AllocatedSize can be greater then 223 | the asked size if size was rounded up to cluster size. 224 | */ 225 | -(void)preallocate:(uint64_t)size 226 | allowPartial:(bool)allowPartial 227 | mustBeContig:(bool)mustBeContig 228 | replyHandler:(nonnull void (^)(NSError * _Nullable error, 229 | uint64_t allocatedSize))reply; 230 | 231 | /** 232 | If the preallocation status of the item has changed, update the number of the 233 | volume's preallocated open files and the file's own preallocation status. 234 | @param isPreallocated The new preallocation status of the item. 235 | */ 236 | -(void)setPreAllocated:(bool)isPreallocated; 237 | 238 | @end 239 | 240 | NS_ASSUME_NONNULL_END 241 | 242 | #endif /* FATItem_h */ 243 | -------------------------------------------------------------------------------- /msdosfs.kextproj/msdosfs.kmodproj/fat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000-2008,2010-2011,2013 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 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. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | /* $FreeBSD: src/sys/msdosfs/fat.h,v 1.9 1999/12/29 04:54:53 peter Exp $ */ 24 | /* $NetBSD: fat.h,v 1.12 1997/11/17 15:36:36 ws Exp $ */ 25 | 26 | /*- 27 | * Copyright (C) 1994, 1997 Wolfgang Solfrank. 28 | * Copyright (C) 1994, 1997 TooLs GmbH. 29 | * All rights reserved. 30 | * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 31 | * 32 | * Redistribution and use in source and binary forms, with or without 33 | * modification, are permitted provided that the following conditions 34 | * are met: 35 | * 1. Redistributions of source code must retain the above copyright 36 | * notice, this list of conditions and the following disclaimer. 37 | * 2. Redistributions in binary form must reproduce the above copyright 38 | * notice, this list of conditions and the following disclaimer in the 39 | * documentation and/or other materials provided with the distribution. 40 | * 3. All advertising materials mentioning features or use of this software 41 | * must display the following acknowledgement: 42 | * This product includes software developed by TooLs GmbH. 43 | * 4. The name of TooLs GmbH may not be used to endorse or promote products 44 | * derived from this software without specific prior written permission. 45 | * 46 | * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 47 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49 | * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 50 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 51 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 52 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 53 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 54 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 55 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 | */ 57 | /* 58 | * Written by Paul Popelka (paulp@uts.amdahl.com) 59 | * 60 | * You can do anything you want with this software, just don't say you wrote 61 | * it, and don't remove this notice. 62 | * 63 | * This software is provided "as is". 64 | * 65 | * The author supplies this software to be publicly redistributed on the 66 | * understanding that the author is not responsible for the correct 67 | * functioning of this software in any circumstances and is not liable for 68 | * any damages caused by this software. 69 | * 70 | * October 1992 71 | */ 72 | 73 | 74 | /* 75 | * Some useful cluster numbers. 76 | */ 77 | #define MSDOSFSROOT 0 /* cluster 0 means the root dir */ 78 | #define CLUST_FREE 0 /* cluster 0 also means a free cluster */ 79 | #define MSDOSFSFREE CLUST_FREE 80 | #define CLUST_FIRST 2 /* first legal cluster number */ 81 | #define CLUST_RSRVD 0xfffffff6 /* reserved cluster range */ 82 | #define CLUST_BAD 0xfffffff7 /* a cluster with a defect */ 83 | #define CLUST_EOFS 0xfffffff8 /* start of eof cluster range */ 84 | #define CLUST_EOFE 0xffffffff /* end of eof cluster range */ 85 | 86 | /* 87 | * Note: FILENO_EMPTY must be larger than FAT32_MASK so that it can't accidentally 88 | * occur as a valid cluster number. 89 | */ 90 | #define FILENO_EMPTY 999999999 /* Fake file number used for empty files */ 91 | #define FILENO_ROOT 1 /* File number used for root directory of FAT12 and FAT16 */ 92 | 93 | #define FAT12_MASK 0x00000fff /* mask for 12 bit cluster numbers */ 94 | #define FAT16_MASK 0x0000ffff /* mask for 16 bit cluster numbers */ 95 | #define FAT32_MASK 0x0fffffff /* mask for FAT32 cluster numbers */ 96 | 97 | /* 98 | * MSDOSFS: 99 | * Return true if filesystem uses 12 bit fats. Microsoft Programmer's 100 | * Reference says if the maximum cluster number in a filesystem is greater 101 | * than 4078 ((CLUST_RSRVS - CLUST_FIRST) & FAT12_MASK) then we've got a 102 | * 16 bit fat filesystem. While mounting, the result of this test is stored 103 | * in pm_fatentrysize. 104 | * GEMDOS-flavour (atari): 105 | * If the filesystem is on floppy we've got a 12 bit fat filesystem, otherwise 106 | * 16 bit. We check the d_type field in the disklabel struct while mounting 107 | * and store the result in the pm_fatentrysize. Note that this kind of 108 | * detection gets flakey when mounting a vnd-device. 109 | */ 110 | #define FAT12(pmp) (pmp->pm_fatmask == FAT12_MASK) 111 | #define FAT16(pmp) (pmp->pm_fatmask == FAT16_MASK) 112 | #define FAT32(pmp) (pmp->pm_fatmask == FAT32_MASK) 113 | 114 | #define MSDOSFSEOF(pmp, cn) ((((cn) | ~(pmp)->pm_fatmask) & CLUST_EOFS) == CLUST_EOFS) 115 | 116 | /* 117 | Symbolic Links for FAT 118 | 119 | FAT does not have native support for symbolic links (symlinks). We 120 | implement them using ordinary files with a particular format. Our 121 | symlink file format is modeled after the SMB for Mac OS X implementation. 122 | 123 | Symlink files are ordinary text files that look like: 124 | 125 | XSym 126 | 1234 127 | 00112233445566778899AABBCCDDEEFF 128 | /the/sym/link/path 129 | 130 | The lines of the file are separated by ASCII newline (0x0A). The first 131 | line is a "magic" value to help identify the file. The second line is 132 | the length of the symlink itself; it is four decimal digits, with leading 133 | zeroes. The third line is the MD5 checksum of the symlink as 16 134 | hexadecimal bytes. The fourth line is the symlink, up to 1024 bytes long. 135 | If the symlink is less than 1024 bytes, then it is padded with a single 136 | newline character and as many spaces as needed to occupy 1024 bytes. 137 | 138 | The file size is exactly 1067 (= 4 + 1 + 4 + 1 + 32 + 1 + 1024) bytes. 139 | When we encounter an ordinary file whose length is 1067, we must read 140 | it to verify that the header (including length and MD5 checksum) is 141 | correct. 142 | 143 | Since the file size is constant, we use the de_FileSize field in the 144 | denode to store the actual length of the symlink. That way, we only 145 | check and parse the header once at vnode creation time. 146 | 147 | */ 148 | 149 | #ifndef SYMLINK_LINK_MAX 150 | static const char symlink_magic[5] = "XSym\n"; 151 | 152 | #define SYMLINK_LINK_MAX 1024 153 | 154 | struct symlink { 155 | char magic[5]; /* == symlink_magic */ 156 | char length[4]; /* four decimal digits */ 157 | char newline1; /* '\n' */ 158 | char md5[32]; /* MD5 hex digest of "length" bytes of "link" field */ 159 | char newline2; /* '\n' */ 160 | char link[SYMLINK_LINK_MAX]; /* "length" bytes, padded by '\n' and spaces */ 161 | }; 162 | #endif 163 | 164 | #ifdef KERNEL 165 | /* 166 | * These are the values for the function argument to the function 167 | * msdosfs_fatentry(). 168 | */ 169 | #define FAT_GET 0x0001 /* get a fat entry */ 170 | #define FAT_SET 0x0002 /* set a fat entry */ 171 | #define FAT_GET_AND_SET (FAT_GET | FAT_SET) 172 | 173 | /* 174 | * Flags to msdosfs_extendfile: 175 | */ 176 | #define DE_CLEAR 1 /* Zero out the blocks allocated */ 177 | #define DE_SYNC IO_SYNC /* 0x4 do it synchronisly...from vnode.h */ 178 | 179 | 180 | void msdosfs_fat_init(void); 181 | void msdosfs_fat_uninit(void); 182 | int msdosfs_fat_init_vol(struct msdosfsmount *pmp); 183 | void msdosfs_fat_uninit_vol(struct msdosfsmount *pmp); 184 | int msdosfs_update_fsinfo(struct msdosfsmount *pmp, int waitfor, vfs_context_t context); 185 | int msdosfs_pcbmap (struct denode *dep, uint32_t findcn, uint32_t numclusters, daddr64_t *bnp, uint32_t *cnp, uint32_t *sp); 186 | int msdosfs_pcbmap_internal(struct denode *dep, uint32_t findcn, uint32_t numclusters, daddr64_t *bnp, uint32_t *cnp, uint32_t *sp); 187 | int msdosfs_clusteralloc(struct msdosfsmount *pmp, uint32_t start, uint32_t count, uint32_t fillwith, uint32_t *retcluster, uint32_t *got); 188 | int msdosfs_fatentry(int function, struct msdosfsmount *pmp, uint32_t cluster, uint32_t *oldcontents, uint32_t newcontents); 189 | int msdosfs_freeclusterchain(struct msdosfsmount *pmp, uint32_t startchain); 190 | int msdosfs_extendfile(struct denode *dep, uint32_t count, uint32_t *numAllocated); 191 | 192 | /* [2753891] 193 | * Routine to mark a FAT16 or FAT32 volume as "clean" or "dirty" by manipulating the upper bit 194 | * of the FAT entry for cluster 1. Note that this bit is not defined for FAT12 volumes. 195 | */ 196 | int msdosfs_markvoldirty(struct msdosfsmount *pmp, int dirty); 197 | 198 | /* 199 | * Write the primary/active FAT and all directories to the device. This 200 | * skips the boot sector, FSInfo sector, and non-active copies of the FAT. 201 | */ 202 | void msdosfs_meta_flush(struct msdosfsmount *pmp, int sync); 203 | void msdosfs_meta_flush_internal(struct msdosfsmount *pmp, int sync); 204 | 205 | enum vtype msdosfs_check_link(struct denode *dep, vfs_context_t context); 206 | 207 | extern u_char l2u[256]; 208 | 209 | /* 210 | * Tunables to control delayed metadata sync. 211 | */ 212 | extern uint32_t msdosfs_meta_delay; 213 | 214 | #endif /* KERNEL */ 215 | -------------------------------------------------------------------------------- /lib_newfs_msdos/newfs_data_types.h: -------------------------------------------------------------------------------- 1 | // 2 | // newfs_data_types.h 3 | // msdosfs 4 | // The contents of this file were taken from main.c (newfs_msdos) 5 | // 6 | // Created by Kujan Lauz on 04/09/2022. 7 | // 8 | 9 | #ifndef newfs_data_types_h 10 | #define newfs_data_types_h 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #define MAXU16 0xffff /* maximum unsigned 16-bit quantity */ 32 | #define BPN 4 /* bits per nibble */ 33 | #define NPB 2 /* nibbles per byte */ 34 | 35 | #define DOSMAGIC 0xaa55 /* DOS magic number */ 36 | #define MINBPS 128 /* minimum bytes per sector */ 37 | #define MAXBPS 4096 /* maximum bytes per sector */ 38 | #define MAXSPC 128 /* maximum sectors per cluster */ 39 | #define MAXNFT 16 /* maximum number of FATs */ 40 | #define DEFBLK 4096 /* default block size */ 41 | #define DEFBLK16 2048 /* default block size FAT16 */ 42 | #define DEFRDE 512 /* default root directory entries */ 43 | #define RESFTE 2 /* reserved FAT entries */ 44 | 45 | /* 46 | * The size of our in-memory I/O buffer. This is the size of the writes we 47 | * do to the device (except perhaps a few odd sectors at the end). 48 | * 49 | * This must be a multiple of the sector size. Larger is generally faster, 50 | * but some old devices have bugs if you ask them to do more than 128KB 51 | * per I/O. 52 | */ 53 | #define IO_BUFFER_SIZE (128*1024) 54 | 55 | /* 56 | * [2873845] FAT12 volumes can have 1..4084 clusters. FAT16 can have 57 | * 4085..65524 clusters. FAT32 is 65525 clusters or more. 58 | * Since many other implementations are off by 1, 2, 4, 8, 10, or 16, 59 | * Microsoft recommends staying at least 16 clusters away from these 60 | * boundary points. They also recommend that FAT32 volumes avoid 61 | * making the bad cluster mark an allocatable cluster number. 62 | * 63 | * So, the minimum and maximum values listed below aren't the strict 64 | * limits (smaller or larger values may work on more robust implementations). 65 | * The limits below are safe limits that should be compatible with a 66 | * wide variety of implementations. 67 | */ 68 | #define MINCLS12 1 /* minimum FAT12 clusters */ 69 | #define MINCLS16 4085 /* minimum FAT16 clusters */ 70 | #define MINCLS32 65525 /* minimum FAT32 clusters */ 71 | #define MAXCLS12 4084 /* maximum FAT12 clusters */ 72 | #define MAXCLS16 65524 /* maximum FAT16 clusters */ 73 | #define MAXCLS32 0x0FFFFFF5 /* maximum FAT32 clusters */ 74 | 75 | #define BACKUP_BOOT_SECTOR 6 /* Default location for backup boot sector on FAT32 */ 76 | #define FAT32_RESERVED_SECTORS 32 77 | 78 | #define mincls(fat) ((fat) == 12 ? MINCLS12 : \ 79 | (fat) == 16 ? MINCLS16 : \ 80 | MINCLS32) 81 | 82 | #define maxcls(fat) ((fat) == 12 ? MAXCLS12 : \ 83 | (fat) == 16 ? MAXCLS16 : \ 84 | MAXCLS32) 85 | 86 | #define mk1(p, x) \ 87 | (p) = (u_int8_t)(x) 88 | 89 | #define mk2(p, x) \ 90 | (p)[0] = (u_int8_t)(x), \ 91 | (p)[1] = (u_int8_t)((x) >> 010) 92 | 93 | #define mk4(p, x) \ 94 | (p)[0] = (u_int8_t)(x), \ 95 | (p)[1] = (u_int8_t)((x) >> 010), \ 96 | (p)[2] = (u_int8_t)((x) >> 020), \ 97 | (p)[3] = (u_int8_t)((x) >> 030) 98 | 99 | #define argto1(arg, lo, msg) argtou(arg, lo, 0xff, msg) 100 | #define argto2(arg, lo, msg) argtou(arg, lo, 0xffff, msg) 101 | #define argto4(arg, lo, msg) argtou(arg, lo, 0xffffffff, msg) 102 | #define argtox(arg, lo, msg) argtou(arg, lo, UINT_MAX, msg) 103 | 104 | struct bs { 105 | u_int8_t jmp[3]; /* bootstrap entry point */ 106 | u_int8_t oem[8]; /* OEM name and version */ 107 | }; 108 | 109 | struct bsbpb { 110 | u_int8_t bps[2]; /* bytes per sector */ 111 | u_int8_t spc; /* sectors per cluster */ 112 | u_int8_t res[2]; /* reserved sectors */ 113 | u_int8_t nft; /* number of FATs */ 114 | u_int8_t rde[2]; /* root directory entries */ 115 | u_int8_t sec[2]; /* total sectors */ 116 | u_int8_t mid; /* media descriptor */ 117 | u_int8_t spf[2]; /* sectors per FAT */ 118 | u_int8_t spt[2]; /* sectors per track */ 119 | u_int8_t hds[2]; /* drive heads */ 120 | u_int8_t hid[4]; /* hidden sectors */ 121 | u_int8_t bsec[4]; /* big total sectors */ 122 | }; 123 | 124 | struct bsxbpb { 125 | u_int8_t bspf[4]; /* big sectors per FAT */ 126 | u_int8_t xflg[2]; /* FAT control flags */ 127 | u_int8_t vers[2]; /* file system version */ 128 | u_int8_t rdcl[4]; /* root directory start cluster */ 129 | u_int8_t infs[2]; /* file system info sector */ 130 | u_int8_t bkbs[2]; /* backup boot sector */ 131 | u_int8_t rsvd[12]; /* reserved */ 132 | }; 133 | 134 | struct bsx { 135 | u_int8_t drv; /* drive number */ 136 | u_int8_t rsvd; /* reserved */ 137 | u_int8_t sig; /* extended boot signature */ 138 | u_int8_t volid[4]; /* volume ID number */ 139 | u_int8_t label[11]; /* volume label */ 140 | u_int8_t type[8]; /* file system type */ 141 | }; 142 | 143 | struct de { 144 | u_int8_t namext[11]; /* name and extension */ 145 | u_int8_t attr; /* attributes */ 146 | u_int8_t rsvd[10]; /* reserved */ 147 | u_int8_t time[2]; /* creation time */ 148 | u_int8_t date[2]; /* creation date */ 149 | u_int8_t clus[2]; /* starting cluster */ 150 | u_int8_t size[4]; /* size */ 151 | }; 152 | 153 | struct bpb { 154 | u_int bps; /* bytes per sector */ 155 | u_int spc; /* sectors per cluster */ 156 | u_int res; /* reserved sectors */ 157 | u_int nft; /* number of FATs */ 158 | u_int rde; /* root directory entries */ 159 | u_int sec; /* total sectors */ 160 | u_int mid; /* media descriptor */ 161 | u_int spf; /* sectors per FAT */ 162 | u_int spt; /* sectors per track */ 163 | u_int hds; /* drive heads */ 164 | u_int hid; /* hidden sectors */ 165 | u_int bsec; /* big total sectors */ 166 | u_int bspf; /* big sectors per FAT */ 167 | u_int rdcl; /* root directory start cluster */ 168 | u_int infs; /* file system info sector */ 169 | u_int bkbs; /* backup boot sector */ 170 | u_int driveNum; /* INT 0x13 drive number (0x00 or 0x80) */ 171 | }; 172 | 173 | 174 | 175 | static u_int8_t bootcode[] = { 176 | 0xfa, /* cli */ 177 | 0x31, 0xc0, /* xor ax,ax */ 178 | 0x8e, 0xd0, /* mov ss,ax */ 179 | 0xbc, 0x00, 0x7c, /* mov sp,7c00h */ 180 | 0xfb, /* sti */ 181 | 0x8e, 0xd8, /* mov ds,ax */ 182 | 0xe8, 0x00, 0x00, /* call $ + 3 */ 183 | 0x5e, /* pop si */ 184 | 0x83, 0xc6, 0x19, /* add si,+19h */ 185 | 0xbb, 0x07, 0x00, /* mov bx,0007h */ 186 | 0xfc, /* cld */ 187 | 0xac, /* lodsb */ 188 | 0x84, 0xc0, /* test al,al */ 189 | 0x74, 0x06, /* jz $ + 8 */ 190 | 0xb4, 0x0e, /* mov ah,0eh */ 191 | 0xcd, 0x10, /* int 10h */ 192 | 0xeb, 0xf5, /* jmp $ - 9 */ 193 | 0x30, 0xe4, /* xor ah,ah */ 194 | 0xcd, 0x16, /* int 16h */ 195 | 0xcd, 0x19, /* int 19h */ 196 | 0x0d, 0x0a, 197 | 'N', 'o', 'n', '-', 's', 'y', 's', 't', 198 | 'e', 'm', ' ', 'd', 'i', 's', 'k', 199 | 0x0d, 0x0a, 200 | 'P', 'r', 'e', 's', 's', ' ', 'a', 'n', 201 | 'y', ' ', 'k', 'e', 'y', ' ', 't', 'o', 202 | ' ', 'r', 'e', 'b', 'o', 'o', 't', 203 | 0x0d, 0x0a, 204 | 0 205 | }; 206 | 207 | /* 208 | * These values define the default crossover points for selecting the default 209 | * FAT type. The intent here is to have the crossover points be the same as 210 | * Microsoft documents, at least for 512 bytes per sector devices. As much 211 | * as possible, the same crossover point (in terms of bytes per volume) is used 212 | * for larger sector sizes. But the 4.1MB crossover between FAT12 and FAT16 213 | * is not achievable for sector sizes larger than 1KB since it would result 214 | * in fewer than 4085 clusters, making FAT16 impossible; in that case, the 215 | * crossover is in terms of sectors, not bytes. 216 | * 217 | * Note that the FAT16 to FAT32 crossover is only good for sector sizes up to 218 | * and including 4KB. For larger sector sizes, there would be too few clusters 219 | * for FAT32. 220 | */ 221 | enum { 222 | MAX_SEC_FAT12_512 = 8400, /* (4.1 MB) Maximum 512 byte sectors to default to FAT12 */ 223 | MAX_SEC_FAT12 = 4200, /* Maximum sectors (>512 bytes) to default to FAT12 */ 224 | MAX_KB_FAT16 = 524288 /* (512 MiB) Maximum kilobytes to default to FAT16 */ 225 | }; 226 | 227 | /* 228 | * [2873851] Tables of default cluster sizes for FAT16 and FAT32. 229 | * 230 | * These constants are derived from Microsoft's documentation, but adjusted 231 | * to represent kilobytes of volume size, not a number of 512-byte sectors. 232 | * Also, this table uses default cluster size, not sectors per cluster, so 233 | * that it can be independent of sector size. 234 | */ 235 | 236 | struct DiskSizeToClusterSize { 237 | u_int64_t kilobytes; /* input: maximum kilobytes */ 238 | u_int32_t bytes_per_cluster; /* output: desired cluster size (in bytes) */ 239 | }; 240 | 241 | enum SDCardType { 242 | kCardTypeNone = 0, 243 | kCardTypeSDSC, 244 | kCardTypeSDHC, 245 | kCardTypeSDXC 246 | }; 247 | 248 | struct StdFormat { 249 | const char *name; 250 | struct bpb bpb; 251 | }; 252 | 253 | #endif /* newfs_data_types_h */ 254 | --------------------------------------------------------------------------------