You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-ios/SessionUtilitiesKit/General/FileSystem.swift

103 lines
4.2 KiB
Swift

// Copyright © 2024 Rangeproof Pty Ltd. All rights reserved.
import Foundation
public enum FileSystem {
/// **Note:** The max file size is 10,000,000 bytes (rather than 10MiB which would be `(10 * 1024 * 1024)`), 10,000,000
/// exactly will be fine but a single byte more will result in an error
public static let maxFileSize = 10_000_000
/// The Objective-C `OWSFileSystem` needs to be able to generate a temporary directory but we don't want to spend the time
/// to add Objective-C support to `Dependencies` since the goal is to refactor everything to Swift so this value should only be
/// assigned by the `AppContext` class when it gets initialised
internal static var temporaryDirectory: Atomic<String?> = Atomic(nil)
public static var cachesDirectoryPath: String {
return NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)[0]
}
public static func ensureDirectoryExists(
at path: String,
fileProtectionType: FileProtectionType = .completeUntilFirstUserAuthentication,
using dependencies: Dependencies = Dependencies()
) throws {
var isDirectory: ObjCBool = false
if !FileManager.default.fileExists(atPath: path, isDirectory: &isDirectory) {
try FileManager.default.createDirectory(
atPath: path,
withIntermediateDirectories: true,
attributes: nil
)
}
try protectFileOrFolder(at: path, fileProtectionType: fileProtectionType, using: dependencies)
}
public static func protectFileOrFolder(
at path: String,
fileProtectionType: FileProtectionType = .completeUntilFirstUserAuthentication,
using dependencies: Dependencies = Dependencies()
) throws {
guard FileManager.default.fileExists(atPath: path) else { return }
try FileManager.default.setAttributes(
[.protectionKey: fileProtectionType],
ofItemAtPath: path
)
var resourcesUrl: URL = URL(fileURLWithPath: path)
var resourceAttrs: URLResourceValues = URLResourceValues()
resourceAttrs.isExcludedFromBackup = true
try resourcesUrl.setResourceValues(resourceAttrs)
}
public static func fileSize(of path: String, using dependencies: Dependencies = Dependencies()) -> UInt64? {
guard let attributes: [FileAttributeKey: Any] = try? FileManager.default.attributesOfItem(atPath: path) else {
return nil
}
return (attributes[.size] as? UInt64)
}
public static func temporaryFilePath(fileExtension: String?) -> String {
let temporaryDirectory: String = {
if let temporaryDirectory: String = self.temporaryDirectory.wrappedValue {
return temporaryDirectory
}
// Not ideal but fallback to creating a new temp directory
let dirName: String = "ows_temp_\(UUID().uuidString)" // stringlint:disable
let tempDir: String = URL(fileURLWithPath: NSTemporaryDirectory())
.appendingPathComponent(dirName)
.path
try? FileSystem.ensureDirectoryExists(at: tempDir, fileProtectionType: .complete)
return tempDir
}()
var tempFileName: String = UUID().uuidString
if let fileExtension: String = fileExtension, !fileExtension.isEmpty {
tempFileName = "\(tempFileName).\(fileExtension)"
}
return URL(fileURLWithPath: temporaryDirectory)
.appendingPathComponent(tempFileName)
.path
}
public static func write(data: Data, toTemporaryFileWithExtension fileExtension: String?) throws -> String? {
let tempFilePath: String = temporaryFilePath(fileExtension: fileExtension)
try data.write(to: URL(fileURLWithPath: tempFilePath), options: .atomic)
try protectFileOrFolder(at: tempFilePath)
return tempFilePath
}
public static func deleteFile(at path: String) throws {
try FileManager.default.removeItem(atPath: path)
}
}