Skip to content

Instantly share code, notes, and snippets.

@krzyzanowskim
Last active December 18, 2022 15:18
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save krzyzanowskim/086f4f025856ea436f805c632c45e854 to your computer and use it in GitHub Desktop.
Save krzyzanowskim/086f4f025856ea436f805c632c45e854 to your computer and use it in GitHub Desktop.
// 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