Last active
December 18, 2022 15:18
-
-
Save krzyzanowskim/086f4f025856ea436f805c632c45e854 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Marcin Krzyzanowski | |
// blog.krzyzanowskim.com | |
import Foundation | |
extension URLResourceKey { | |
static let bookmarkAllPropertiesKey = URLResourceKey("NSURLBookmarkAllPropertiesKey") | |
static let fileIDKey = URLResourceKey("_NSURLFileIDKey") | |
static let inode = URLResourceKey.fileIDKey | |
} | |
private func getInode(for fileURL: URL) throws -> Int { | |
// ls -i /tmp/file.txt | |
var tmp = fileURL | |
tmp.removeCachedResourceValue(forKey: .inode) | |
return try fileURL.resourceValues(forKeys: [.inode]).allValues[.inode] as! Int | |
} | |
private func checkAtomicWrite(for fileURL: URL) throws -> (Int, Int) { | |
let inodeBefore = try getInode(for: fileURL) | |
try "foobar".write(to: fileURL, atomically: true, encoding: .utf8) | |
let inodeAfter = try getInode(for: fileURL) | |
return (inodeBefore, inodeAfter) | |
} | |
private func checkNonAtomicWrite(for fileURL: URL) throws -> (Int, Int) { | |
let inodeBefore = try getInode(for: fileURL) | |
try "foobar".write(to: fileURL, atomically: false, encoding: .utf8) | |
let inodeAfter = try getInode(for: fileURL) | |
return (inodeBefore, inodeAfter) | |
} | |
// Check inode values | |
let fileURL = URL(fileURLWithPath: "/tmp/file.txt") | |
// Create empty file | |
if FileManager.default.fileExists(atPath: fileURL.path) { | |
FileManager.default.removeItem(at: fileURL) | |
} | |
FileManager.default.createFile(atPath: fileURL.path, contents: nil, attributes: nil) | |
// Test inode changes | |
let (inodeBeforeAtomic, inodeAfterAtomic) = try checkAtomicWrite(for: fileURL) | |
if (inodeBeforeAtomic != inodeAfterAtomic) { | |
print("[Atomic] inode value changed: \(inodeBeforeAtomic) -> \(inodeAfterAtomic)") | |
} | |
let (inodeBeforeNonAtomic, inodeAfterNonAtomic) = try checkNonAtomicWrite(for: fileURL) | |
if (inodeBeforeNonAtomic != inodeAfterNonAtomic) { | |
print("[Non atomic] inode value changed: \(inodeBeforeNonAtomic) -> \(inodeAfterNonAtomic)") | |
} | |
// Check bookmarks | |
do { | |
// Create bookmark | |
let bookmark = try fileURL.bookmarkData() | |
// Modify file | |
try "foobar".write(to: fileURL, atomically: true, encoding: .utf8) | |
// Move file to /tmp/file.txt.bak | |
try FileManager.default.moveItem(at: fileURL, to: fileURL.appendingPathExtension("bak")) | |
// Try to use bookmark 💥 Error: The file doesn’t exist. | |
var bookmarkIsStale = false | |
try URL(resolvingBookmarkData: bookmark, bookmarkDataIsStale: &bookmarkIsStale) | |
} catch { | |
print(error) | |
} | |
// Cleanup | |
FileManager.default.removeItem(at: fileURL.appendingPathExtension("bak")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment