无法使用OSXFUSE.framework设置NSFileSystemFileNumber

时间:2019-08-01 08:44:55

标签: swift macos fuse

我正在尝试创建带有保险丝的内存文件系统。
我在Mac OS 10.14.4上安装了FUSE for macOS 3.10.2
我使用xcode 10.2.1创建了swift项目并与OSXFUSE.framework

链接

我给每个文件和目录随机生成一个数字,并在attributeOfItem回调函数中设置systemFileNumber属性。
我以为这是inode值,所以我对硬链接文件使用了相同的值,但是, 我的随机数根本没有用。
我错过了什么吗?

下面是我的代码。
谢谢。

import Foundation

let DIRECTORY_ITEM_SIZE = 32
let FILE_SYSTEM_BLOCK_SIZE = 512

var usedSystemFileNumbers: [UInt64] = []

class FileItemInfo {
    var name: String = ""
    var type: FileAttributeType = .typeUnknown
    var dateModification: Date? = nil
    var permission: UInt16? = nil
    var ownerAccountId: UInt32? = nil
    var groupOwnerAccountId: UInt32? = nil
    var systemFileNumber: UInt64
    var dateCreation: Date? = nil
    var dateBackup: Date? = nil
    var dateChange: Date? = nil
    var dateAccess: Date? = nil
    var flags: UInt32? = nil
    var hardLinkTarget: [FileItemInfo] = []

    private var _internalHardLinkSource: FileItemInfo? = nil
    var hardLinkSource: FileItemInfo? {
        get {
            return _internalHardLinkSource
        }
        set(value) {
            if nil != value {
                if let index = usedSystemFileNumbers.firstIndex(of: self.systemFileNumber) {
                    usedSystemFileNumbers.remove(at: index)
                }

                self.systemFileNumber = 0
                _internalHardLinkSource = value
            }
        }
    }

    private var _internalSize: UInt64 = 0
    var size: UInt64 {
        get {
            return _internalSize
        }
    }

    private var _internalData: Data? = nil
    var data: Data? {
        get {
            return _internalData
        }
        set(value) {
            if nil != value {
                _internalData = value
                _internalSize = UInt64(value!.count)
            }
        }
    }

    public init(_ name: String, type: FileAttributeType, dateModification: Date? = nil, permission: UInt16? = nil, ownerAccountId: UInt32? = nil, groupOwnerAccountId: UInt32? = nil, dateCreation: Date? = nil, dateBackup: Date? = nil, dateChange: Date? = nil, dateAccess: Date? = nil, flags: UInt32? = nil, data: Data? = nil, hardLinkSource: FileItemInfo? = nil, hardLinkTarget: [FileItemInfo] = []) {
        self.name = name
        self.type = type
        self.dateModification = dateModification
        self.permission = permission
        self.ownerAccountId = ownerAccountId
        self.groupOwnerAccountId = groupOwnerAccountId
        self.dateCreation = dateCreation
        self.dateBackup = dateBackup
        self.dateChange = dateChange
        self.dateAccess = dateAccess
        self.flags = flags

        var gen = SystemRandomNumberGenerator()
        var number = gen.next()
        while 0 == number || usedSystemFileNumbers.contains(number) {
            number = gen.next()
        }
        usedSystemFileNumbers.append(number)
        self.systemFileNumber = number

        self.hardLinkSource = hardLinkSource
        self.hardLinkTarget = hardLinkTarget

        self.data = data
    }
}

class FileTree {
    var this: FileItemInfo
    var children: [FileTree]

    public init(_ item: FileItemInfo, children: [FileTree] = []) {
        self.this = item
        self.children = children
    }
}

var root = FileItemInfo("/", type: .typeDirectory)
var root_subdir = FileItemInfo("subdir", type: .typeDirectory)
var root_file = FileItemInfo("file", type: .typeRegular)
var root_hardLinkToFile = FileItemInfo("hard_link_to_file", type: .typeRegular)
root_hardLinkToFile.hardLinkSource = root_file
root_file.hardLinkTarget.append(root_hardLinkToFile)

root_file.data = Data(repeating: 68, count: 2789)

var tree = FileTree(root)
tree.children.append(FileTree(root_subdir))
tree.children.append(FileTree(root_file))
tree.children.append(FileTree(root_hardLinkToFile))

func getFileTree(byPath: String) -> FileTree? {
    var tokens = byPath.components(separatedBy: "/")

    if let first = tokens.first {
        if "" == first {
            tokens = Array(tokens.dropFirst())
        }
    }
    if let last = tokens.last {
        if "" == last {
            tokens = Array(tokens.dropLast())
        }
    }

    var cursor: FileTree? = tree

    var currentDir: String = "/"

    if !tokens.isEmpty {
        for token in tokens {
            print("finding \"\(token)\" under \"\(currentDir)\"")
            cursor = cursor?.children.first {$0.this.name == token}
            guard let _ = cursor else {
                print("failed.")
                return nil
            }
            currentDir += "/\(token)"
        }
    }

    return cursor
}

class FuseDelegator : NSObject {
    override func willMount() {
        print("\(Date().description) :: willMount called.")
    }

    override func willUnmount() {
        print("\(Date().description) :: willUnmount called.")
    }

    override func contentsOfDirectory(atPath path: String!) throws -> [Any] {
        guard let pathUnwrap = path else {
            throw NSError(domain: #function, code: #line, userInfo: nil)
        }

        print("\n\n------------------------------------------------------------")
        print("\(Date().description) :: contentsOfDirectory called. \"\(pathUnwrap)\"")

        guard let found = getFileTree(byPath: pathUnwrap) else {
            print("error.")
            throw NSError(domain: #function, code: #line, userInfo: nil)
        }

        print("~~~~~~~~~~~ found ~~~~~~~~~~~~~")

        let result = found.children.map {$0.this.name}
        print("result = \(result)")
        return result
    }

    override func attributesOfItem(atPath path: String!, userData: Any!) throws -> [AnyHashable : Any] {
        guard let pathUnwrap = path else {
            throw NSError(domain: #function, code: #line, userInfo: nil)
        }

        print("\(Date().description) :: attributesOfItem called. \"\(pathUnwrap)\" \"\(userData)\"")

        guard let foundTree = getFileTree(byPath: pathUnwrap) else {
            print("error.")
            throw NSError(domain: #function, code: #line, userInfo: nil)
        }

        print("~~~~~~~~~~~ found ~~~~~~~~~~~~~")

        var found = foundTree.this
        while .typeDirectory != found.type && nil != found.hardLinkSource {
            found = found.hardLinkSource!
            print("hard link to \"\(found.name)\" filenumber \(found.systemFileNumber)")
        }

        var result: [AnyHashable : Any] = [FileAttributeKey.type : found.type]
        print("type : \(found.type)")

        var fileSize: UInt64 = 0

        switch found.type {
        case .typeDirectory:
            fileSize = UInt64(2 + foundTree.children.count) * UInt64(DIRECTORY_ITEM_SIZE)
            result.updateValue(fileSize, forKey: FileAttributeKey.size)
            print("size : \(fileSize)")
        default:
            fileSize = found.size
            result.updateValue(fileSize, forKey: FileAttributeKey.size)
            print("size : \(fileSize)")
        }

        if let date = found.dateModification {
            result.updateValue(date, forKey: FileAttributeKey.modificationDate)
            print("mod date : \(date)")
        }

        switch found.type {
        case .typeDirectory:
            let count = 2 + foundTree.children.count
            result.updateValue(count, forKey: FileAttributeKey.referenceCount)
            print("reference count : \(count)")
        default:
            let count = 1 + found.hardLinkTarget.count
            result.updateValue(count, forKey: FileAttributeKey.referenceCount)
            print("reference count : \(count)")
        }

        if let permission = found.permission {
            result.updateValue(permission, forKey: FileAttributeKey.posixPermissions)
            print("posix permission : \(permission)")
        }

        if let ownerUid = found.ownerAccountId {
            result.updateValue(ownerUid, forKey: FileAttributeKey.ownerAccountID)
            print("owner account id \(ownerUid)")
        }

        if let ownerGid = found.groupOwnerAccountId {
            result.updateValue(ownerGid, forKey: FileAttributeKey.groupOwnerAccountID)
            print("group owner account id \(ownerGid)")
        }

        result.updateValue(found.systemFileNumber, forKey: FileAttributeKey.systemFileNumber)
        print("system file number \(found.systemFileNumber)")

        if let date = found.dateCreation {
            result.updateValue(date, forKey: FileAttributeKey.creationDate)
            print("create date : \(date)")
        }

        if let date = found.dateBackup {
            result.updateValue(date, forKey: kGMUserFileSystemFileBackupDateKey)
            print("backup date : \(date)")
        }

        if let date = found.dateChange {
            result.updateValue(date, forKey: kGMUserFileSystemFileChangeDateKey)
            print("change date : \(date)")
        }

        if let date = found.dateAccess {
            result.updateValue(date, forKey: kGMUserFileSystemFileAccessDateKey)
            print("access date : \(date)")
        }

        if let flags = found.flags {
            result.updateValue(flags, forKey: kGMUserFileSystemFileFlagsKey)
            print("flags : \(String(format: "%o", flags))")
        }

        var sizeInBlocks = fileSize / UInt64(FILE_SYSTEM_BLOCK_SIZE)
        let rest = fileSize % UInt64(FILE_SYSTEM_BLOCK_SIZE)
        if 0 < rest {
            sizeInBlocks += 1
        }

        result.updateValue(sizeInBlocks, forKey: kGMUserFileSystemFileSizeInBlocksKey)
        print("size in blocks : \(sizeInBlocks)")

        return result
    }

}

class Observer {
    @objc func didMount(noti: Notification) {
        print("============================================================")
        print("\(Date().description) !!!! mounted !!!! \(noti) !!!!")
        print("============================================================")
    }

    @objc func mountFailed(noti: Notification) {
        print("============================================================")
        print("\(Date().description) !!!! mount failed !!!! \(noti) !!!!")
        print("============================================================")
    }

    @objc func unmounted(noti: Notification) {
        print("============================================================")
        print("\(Date().description) !!!!unmounted !!!! \(noti) !!!!")
        print("============================================================")
    }
}

let observer = Observer()
NotificationCenter.default.addObserver(observer, selector: #selector(Observer.didMount), name: NSNotification.Name(rawValue: kGMUserFileSystemDidMount), object: nil)
NotificationCenter.default.addObserver(observer, selector: #selector(Observer.mountFailed), name: NSNotification.Name(rawValue: kGMUserFileSystemMountFailed), object: nil)
NotificationCenter.default.addObserver(observer, selector: #selector(Observer.unmounted), name: NSNotification.Name(rawValue: kGMUserFileSystemDidUnmount), object: nil)

let delegator = FuseDelegator()
let test = GMUserFileSystem.init(delegate: delegator, isThreadSafe: false)

test?.mount(atPath: "/Volumes/inMemoryFuse", withOptions: ["nolocalcaches", "noubc"], shouldForeground: true, detachNewThread: false)

defer {
    test?.unmount()
}

signal(SIGINT) { s in test?.unmount(); exit(0) }

while true {
    sleep(1)
}

保险丝委托味精

------------------------------------------------------------
2019-08-01 08:18:02 +0000 :: contentsOfDirectory called. "/"
~~~~~~~~~~~ found ~~~~~~~~~~~~~
result = ["subdir", "file", "hard_link_to_file"]
2019-08-01 08:18:02 +0000 :: attributesOfItem called. "/subdir" "nil"
finding "subdir" under "/"
~~~~~~~~~~~ found ~~~~~~~~~~~~~
type : NSFileAttributeType(_rawValue: NSFileTypeDirectory)
size : 64
reference count : 2
system file number 1974617016092975998
size in blocks : 1
2019-08-01 08:18:02 +0000 :: attributesOfItem called. "/file" "nil"
finding "file" under "/"
~~~~~~~~~~~ found ~~~~~~~~~~~~~
type : NSFileAttributeType(_rawValue: NSFileTypeRegular)
size : 2789
reference count : 2
system file number 7083229264230220976
size in blocks : 6
2019-08-01 08:18:02 +0000 :: attributesOfItem called. "/._file" "nil"
finding "._file" under "/"
failed.
error.
2019-08-01 08:18:02 +0000 :: attributesOfItem called. "/hard_link_to_file" "nil"
finding "hard_link_to_file" under "/"
~~~~~~~~~~~ found ~~~~~~~~~~~~~
hard link to "file" filenumber 7083229264230220976
type : NSFileAttributeType(_rawValue: NSFileTypeRegular)
size : 2789
reference count : 2
system file number 7083229264230220976
size in blocks : 6

结果

$ ls -lhid /Volumes/inMemoryFuse
1 drwxrwxr-x@ 5 idid  staff   160B  1  1  1970 /Volumes/inMemoryFuse


$ ls -lhi /Volumes/inMemoryFuse/
total 24
3 -rwxrwxr-x  2 idid  staff   2.7K  1  1  1970 file
4 -rwxrwxr-x  2 idid  staff   2.7K  1  1  1970 hard_link_to_file
2 drwxrwxr-x  2 idid  staff    64B  1  1  1970 subdir

0 个答案:

没有答案