Files

39 lines
1.8 KiB
Swift

import Foundation
/// One current file and one bounded archive. The owning process serializes writes.
struct BoundedLog {
let url: URL
var maxBytes = 5 * 1024 * 1024
func append(_ line: String) throws {
let files = FileManager.default
try files.createDirectory(at: url.deletingLastPathComponent(), withIntermediateDirectories: true)
if !files.fileExists(atPath: url.path) {
guard files.createFile(atPath: url.path, contents: nil, attributes: [.posixPermissions: 0o600]) else {
throw CocoaError(.fileWriteUnknown)
}
}
try files.setAttributes([.posixPermissions: 0o600], ofItemAtPath: url.path)
let handle = try FileHandle(forUpdating: url)
defer { try? handle.close() }
let size = try handle.seekToEnd()
let data = Data(line.utf8).suffix(maxBytes)
let archive = url.appendingPathExtension("1")
var archiveSize: UInt64 = 0
if files.fileExists(atPath: archive.path) {
try files.setAttributes([.posixPermissions: 0o600], ofItemAtPath: archive.path)
archiveSize = (try files.attributesOfItem(atPath: archive.path)[.size] as? NSNumber)?.uint64Value ?? 0
}
if size + UInt64(data.count) > UInt64(maxBytes) || archiveSize > UInt64(maxBytes) {
try handle.seek(toOffset: size > UInt64(maxBytes) ? size - UInt64(maxBytes) : 0)
let tail = try handle.read(upToCount: maxBytes) ?? Data()
guard files.createFile(atPath: archive.path, contents: tail, attributes: [.posixPermissions: 0o600]) else {
throw CocoaError(.fileWriteUnknown)
}
try handle.truncate(atOffset: 0)
try handle.seek(toOffset: 0)
}
try handle.write(contentsOf: data)
}
}