mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 14:45:21 +00:00
Assorted updates and bug fixes
This commit is contained in:
@@ -2,34 +2,119 @@ import Foundation
|
||||
import SwiftSignalKit
|
||||
private typealias SignalKitTimer = SwiftSignalKit.Timer
|
||||
|
||||
struct InodeInfo {
|
||||
var inode: __darwin_ino64_t
|
||||
var timestamp: Int32
|
||||
var size: UInt32
|
||||
}
|
||||
|
||||
private func scanFiles(at path: String, olderThan minTimestamp: Int32, anyway: ((String, Int, Int32)) -> Void, unlink f: (String) -> Void) {
|
||||
guard let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: path), includingPropertiesForKeys: [.contentModificationDateKey, .isDirectoryKey, .fileSizeKey], options: [.skipsSubdirectoryDescendants], errorHandler: nil) else {
|
||||
private struct ScanFilesResult {
|
||||
var unlinkedCount = 0
|
||||
var totalSize: UInt64 = 0
|
||||
}
|
||||
|
||||
private func scanFiles(at path: String, olderThan minTimestamp: Int32, inodes: inout [InodeInfo]) -> ScanFilesResult {
|
||||
var result = ScanFilesResult()
|
||||
|
||||
if let dp = opendir(path) {
|
||||
let pathBuffer = malloc(2048).assumingMemoryBound(to: Int8.self)
|
||||
defer {
|
||||
free(pathBuffer)
|
||||
}
|
||||
|
||||
while true {
|
||||
guard let dirp = readdir(dp) else {
|
||||
break
|
||||
}
|
||||
|
||||
if strncmp(&dirp.pointee.d_name.0, ".", 1024) == 0 {
|
||||
continue
|
||||
}
|
||||
if strncmp(&dirp.pointee.d_name.0, "..", 1024) == 0 {
|
||||
continue
|
||||
}
|
||||
strncpy(pathBuffer, path, 1024)
|
||||
strncat(pathBuffer, "/", 1024)
|
||||
strncat(pathBuffer, &dirp.pointee.d_name.0, 1024)
|
||||
|
||||
//puts(pathBuffer)
|
||||
//puts("\n")
|
||||
|
||||
var value = stat()
|
||||
if stat(pathBuffer, &value) == 0 {
|
||||
if value.st_mtimespec.tv_sec < minTimestamp {
|
||||
unlink(pathBuffer)
|
||||
result.unlinkedCount += 1
|
||||
} else {
|
||||
result.totalSize += UInt64(value.st_size)
|
||||
inodes.append(InodeInfo(
|
||||
inode: value.st_ino,
|
||||
timestamp: Int32(clamping: value.st_mtimespec.tv_sec),
|
||||
size: UInt32(clamping: value.st_size)
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dp)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private func mapFiles(paths: [String], inodes: inout [InodeInfo], removeSize: UInt64) {
|
||||
var removedSize: UInt64 = 0
|
||||
|
||||
inodes.sort(by: { lhs, rhs in
|
||||
return lhs.timestamp < rhs.timestamp
|
||||
})
|
||||
|
||||
var inodesToDelete = Set<__darwin_ino64_t>()
|
||||
|
||||
for inode in inodes {
|
||||
inodesToDelete.insert(inode.inode)
|
||||
removedSize += UInt64(inode.size)
|
||||
if removedSize >= removeSize {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if inodesToDelete.isEmpty {
|
||||
return
|
||||
}
|
||||
while let item = enumerator.nextObject() {
|
||||
guard let url = item as? NSURL else {
|
||||
continue
|
||||
}
|
||||
guard let resourceValues = try? url.resourceValues(forKeys: [.contentModificationDateKey, .isDirectoryKey, .fileSizeKey]) else {
|
||||
continue
|
||||
}
|
||||
if let value = resourceValues[.isDirectoryKey] as? Bool, value {
|
||||
continue
|
||||
}
|
||||
if let value = resourceValues[.contentModificationDateKey] as? NSDate {
|
||||
var unlinked = false
|
||||
if Int32(value.timeIntervalSince1970) < minTimestamp {
|
||||
if let file = url.path {
|
||||
f(file)
|
||||
unlinked = true
|
||||
}
|
||||
}
|
||||
if let file = url.path, !unlinked {
|
||||
if let size = (resourceValues[.fileSizeKey] as? NSNumber)?.intValue {
|
||||
anyway((file, size, Int32(value.timeIntervalSince1970)))
|
||||
|
||||
let pathBuffer = malloc(2048).assumingMemoryBound(to: Int8.self)
|
||||
defer {
|
||||
free(pathBuffer)
|
||||
}
|
||||
|
||||
for path in paths {
|
||||
if let dp = opendir(path) {
|
||||
while true {
|
||||
guard let dirp = readdir(dp) else {
|
||||
break
|
||||
}
|
||||
|
||||
if strncmp(&dirp.pointee.d_name.0, ".", 1024) == 0 {
|
||||
continue
|
||||
}
|
||||
if strncmp(&dirp.pointee.d_name.0, "..", 1024) == 0 {
|
||||
continue
|
||||
}
|
||||
strncpy(pathBuffer, path, 1024)
|
||||
strncat(pathBuffer, "/", 1024)
|
||||
strncat(pathBuffer, &dirp.pointee.d_name.0, 1024)
|
||||
|
||||
//puts(pathBuffer)
|
||||
//puts("\n")
|
||||
|
||||
var value = stat()
|
||||
if stat(pathBuffer, &value) == 0 {
|
||||
if inodesToDelete.contains(value.st_ino) {
|
||||
unlink(pathBuffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,49 +174,42 @@ private final class TimeBasedCleanupImpl {
|
||||
var removedShortLivedCount: Int = 0
|
||||
var removedGeneralCount: Int = 0
|
||||
var removedGeneralLimitCount: Int = 0
|
||||
|
||||
let startTime = CFAbsoluteTimeGetCurrent()
|
||||
|
||||
var inodes: [InodeInfo] = []
|
||||
var paths: [String] = []
|
||||
|
||||
let timestamp = Int32(Date().timeIntervalSince1970)
|
||||
let bytesLimit = UInt64(gigabytesLimit) * 1024 * 1024 * 1024
|
||||
|
||||
let oldestShortLivedTimestamp = timestamp - shortLived
|
||||
let oldestGeneralTimestamp = timestamp - general
|
||||
for path in shortLivedPaths {
|
||||
scanFiles(at: path, olderThan: oldestShortLivedTimestamp, anyway: { _, _, _ in
|
||||
|
||||
}, unlink: { file in
|
||||
removedShortLivedCount += 1
|
||||
unlink(file)
|
||||
})
|
||||
let scanResult = scanFiles(at: path, olderThan: oldestShortLivedTimestamp, inodes: &inodes)
|
||||
if !paths.contains(path) {
|
||||
paths.append(path)
|
||||
}
|
||||
removedShortLivedCount += scanResult.unlinkedCount
|
||||
}
|
||||
|
||||
var checkFiles: [GeneralFile] = []
|
||||
|
||||
var totalLimitSize: UInt64 = 0
|
||||
|
||||
for path in generalPaths {
|
||||
scanFiles(at: path, olderThan: oldestGeneralTimestamp, anyway: { file, size, timestamp in
|
||||
checkFiles.append(GeneralFile(file: file, size: size, timestamp: timestamp))
|
||||
totalLimitSize += UInt64(size)
|
||||
}, unlink: { file in
|
||||
removedGeneralCount += 1
|
||||
unlink(file)
|
||||
})
|
||||
let scanResult = scanFiles(at: path, olderThan: oldestGeneralTimestamp, inodes: &inodes)
|
||||
if !paths.contains(path) {
|
||||
paths.append(path)
|
||||
}
|
||||
removedGeneralCount += scanResult.unlinkedCount
|
||||
totalLimitSize += scanResult.totalSize
|
||||
}
|
||||
|
||||
clear: for item in checkFiles.sorted(by: <) {
|
||||
if totalLimitSize > bytesLimit {
|
||||
unlink(item.file)
|
||||
removedGeneralLimitCount += 1
|
||||
if totalLimitSize > UInt64(item.size) {
|
||||
totalLimitSize -= UInt64(item.size)
|
||||
} else {
|
||||
totalLimitSize = 0
|
||||
}
|
||||
} else {
|
||||
break clear
|
||||
}
|
||||
if totalLimitSize > bytesLimit {
|
||||
mapFiles(paths: paths, inodes: &inodes, removeSize: totalLimitSize - bytesLimit)
|
||||
}
|
||||
|
||||
if removedShortLivedCount != 0 || removedGeneralCount != 0 || removedGeneralLimitCount != 0 {
|
||||
print("[TimeBasedCleanup] removed \(removedShortLivedCount) short-lived files, \(removedGeneralCount) general files, \(removedGeneralLimitCount) limit files")
|
||||
print("[TimeBasedCleanup] \(CFAbsoluteTimeGetCurrent() - startTime) s removed \(removedShortLivedCount) short-lived files, \(removedGeneralCount) general files, \(removedGeneralLimitCount) limit files")
|
||||
}
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user