NCUtilityFileSystem.swift 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. //
  2. // NCUtilityFileSystem.swift
  3. // Nextcloud
  4. //
  5. // Created by Marino Faggiana on 28/05/2020.
  6. // Copyright © 2020 Marino Faggiana. All rights reserved.
  7. //
  8. // Author Marino Faggiana <marino.faggiana@nextcloud.com>
  9. //
  10. // This program is free software: you can redistribute it and/or modify
  11. // it under the terms of the GNU General Public License as published by
  12. // the Free Software Foundation, either version 3 of the License, or
  13. // (at your option) any later version.
  14. //
  15. // This program is distributed in the hope that it will be useful,
  16. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. // GNU General Public License for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License
  21. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. //
  23. import UIKit
  24. import NextcloudKit
  25. import PhotosUI
  26. class NCUtilityFileSystem: NSObject {
  27. let fileManager = FileManager.default
  28. var directoryGroup: String {
  29. return fileManager.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroup)?.path ?? ""
  30. }
  31. var directoryDocuments: String {
  32. return NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first ?? ""
  33. }
  34. var directoryCertificates: String {
  35. guard let directoryGroup = fileManager.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroup) else { return "" }
  36. let path = directoryGroup.appendingPathComponent(NCGlobal.shared.appCertificates).path
  37. if !fileManager.fileExists(atPath: path) {
  38. do {
  39. try fileManager.createDirectory(atPath: path, withIntermediateDirectories: true)
  40. } catch { print("Error: \(error)") }
  41. }
  42. return path
  43. }
  44. var directoryUserData: String {
  45. guard let directoryGroup = fileManager.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroup) else { return "" }
  46. let path = directoryGroup.appendingPathComponent(NCGlobal.shared.appUserData).path
  47. if !fileManager.fileExists(atPath: path) {
  48. do {
  49. try fileManager.createDirectory(atPath: path, withIntermediateDirectories: true)
  50. } catch { print("Error: \(error)") }
  51. }
  52. return path
  53. }
  54. var directoryScan: String {
  55. guard let directoryGroup = fileManager.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroup) else { return "" }
  56. let path = directoryGroup.appendingPathComponent(NCGlobal.shared.appScan).path
  57. if !fileManager.fileExists(atPath: path) {
  58. do {
  59. try fileManager.createDirectory(atPath: path, withIntermediateDirectories: true)
  60. } catch { print("Error: \(error)") }
  61. }
  62. return path
  63. }
  64. var directoryProviderStorage: String {
  65. guard let directoryGroup = fileManager.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroup) else { return "" }
  66. let path = directoryGroup.appendingPathComponent(NCGlobal.shared.directoryProviderStorage).path
  67. if !fileManager.fileExists(atPath: path) {
  68. do {
  69. try fileManager.createDirectory(atPath: path, withIntermediateDirectories: true)
  70. } catch { print("Error: \(error)") }
  71. }
  72. return path
  73. }
  74. // MARK: -
  75. func getDirectoryProviderStorageOcId(_ ocId: String) -> String {
  76. let path = directoryProviderStorage + "/" + ocId
  77. if !fileManager.fileExists(atPath: path) {
  78. do {
  79. try fileManager.createDirectory(atPath: path, withIntermediateDirectories: true)
  80. } catch { print("Error: \(error)") }
  81. }
  82. return path
  83. }
  84. @objc func getDirectoryProviderStorageOcId(_ ocId: String, fileNameView: String) -> String {
  85. let path = getDirectoryProviderStorageOcId(ocId) + "/" + fileNameView
  86. if !fileManager.fileExists(atPath: path) {
  87. fileManager.createFile(atPath: path, contents: nil)
  88. }
  89. return path
  90. }
  91. func getDirectoryProviderStorageImageOcId(_ ocId: String, etag: String, ext: String) -> String {
  92. return getDirectoryProviderStorageOcId(ocId) + "/" + etag + ext
  93. }
  94. func fileProviderStorageExists(_ metadata: tableMetadata) -> Bool {
  95. let fileNamePath = getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileName)
  96. let fileNameViewPath = getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
  97. do {
  98. let fileNameAttribute = try fileManager.attributesOfItem(atPath: fileNamePath)
  99. let fileNameSize: UInt64 = fileNameAttribute[FileAttributeKey.size] as? UInt64 ?? 0
  100. let fileNameViewAttribute = try fileManager.attributesOfItem(atPath: fileNameViewPath)
  101. let fileNameViewSize: UInt64 = fileNameViewAttribute[FileAttributeKey.size] as? UInt64 ?? 0
  102. if metadata.isDirectoryE2EE == true {
  103. if (fileNameSize == metadata.size || fileNameViewSize == metadata.size) && fileNameViewSize > 0 {
  104. return true
  105. } else {
  106. return false
  107. }
  108. } else {
  109. return (fileNameViewSize == metadata.size) && metadata.size > 0
  110. }
  111. } catch { print("Error: \(error)") }
  112. return false
  113. }
  114. func fileProviderStorageSize(_ ocId: String, fileNameView: String) -> UInt64 {
  115. let fileNamePath = getDirectoryProviderStorageOcId(ocId, fileNameView: fileNameView)
  116. do {
  117. let fileNameAttribute = try fileManager.attributesOfItem(atPath: fileNamePath)
  118. let fileNameSize: UInt64 = fileNameAttribute[FileAttributeKey.size] as? UInt64 ?? 0
  119. return fileNameSize
  120. } catch { print("Error: \(error)") }
  121. return 0
  122. }
  123. func fileProviderStorageImageExists(_ ocId: String, etag: String, ext: String) -> Bool {
  124. let fileNamePath = getDirectoryProviderStorageImageOcId(ocId, etag: etag, ext: ext)
  125. do {
  126. let fileNamePathAttribute = try fileManager.attributesOfItem(atPath: fileNamePath)
  127. let fileSize: UInt64 = fileNamePathAttribute[FileAttributeKey.size] as? UInt64 ?? 0
  128. if fileSize > 0 {
  129. return true
  130. } else {
  131. return false
  132. }
  133. } catch { }
  134. return false
  135. }
  136. func fileProviderStorageImageExists(_ ocId: String, etag: String) -> Bool {
  137. if fileProviderStorageImageExists(ocId, etag: etag, ext: NCGlobal.shared.previewExt1024),
  138. fileProviderStorageImageExists(ocId, etag: etag, ext: NCGlobal.shared.previewExt512),
  139. fileProviderStorageImageExists(ocId, etag: etag, ext: NCGlobal.shared.previewExt256) {
  140. return true
  141. }
  142. return false
  143. }
  144. func createDirectoryStandard() {
  145. guard let directoryGroup = fileManager.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroup)?.path else { return }
  146. if !fileManager.fileExists(atPath: directoryDocuments) { try? fileManager.createDirectory(atPath: directoryDocuments, withIntermediateDirectories: true) }
  147. let appDatabaseNextcloud = directoryGroup + "/" + NCGlobal.shared.appDatabaseNextcloud
  148. if !fileManager.fileExists(atPath: appDatabaseNextcloud) { try? fileManager.createDirectory(atPath: appDatabaseNextcloud, withIntermediateDirectories: true) }
  149. if !fileManager.fileExists(atPath: directoryUserData) { try? fileManager.createDirectory(atPath: directoryUserData, withIntermediateDirectories: true) }
  150. if !fileManager.fileExists(atPath: directoryProviderStorage) { try? fileManager.createDirectory(atPath: directoryProviderStorage, withIntermediateDirectories: true) }
  151. let appScan = directoryGroup + "/" + NCGlobal.shared.appScan
  152. if !fileManager.fileExists(atPath: appScan) { try? fileManager.createDirectory(atPath: appScan, withIntermediateDirectories: true) }
  153. if !fileManager.fileExists(atPath: NSTemporaryDirectory()) { try? fileManager.createDirectory(atPath: NSTemporaryDirectory(), withIntermediateDirectories: true) }
  154. // Directory Excluded From Backup
  155. if let url = NSURL(string: directoryDocuments) {
  156. try? url.setResourceValue(true, forKey: URLResourceKey.isExcludedFromBackupKey)
  157. }
  158. if let url = NSURL(string: directoryGroup) {
  159. try? url.setResourceValue(true, forKey: URLResourceKey.isExcludedFromBackupKey)
  160. }
  161. }
  162. func removeGroupApplicationSupport() {
  163. let path = directoryGroup + "/" + NCGlobal.shared.appApplicationSupport
  164. try? fileManager.removeItem(atPath: path)
  165. }
  166. func removeGroupLibraryDirectory() {
  167. try? fileManager.removeItem(atPath: directoryScan)
  168. try? fileManager.removeItem(atPath: directoryUserData)
  169. }
  170. func removeGroupDirectoryProviderStorage() {
  171. try? fileManager.removeItem(atPath: directoryProviderStorage)
  172. }
  173. func removeDocumentsDirectory() {
  174. try? fileManager.removeItem(atPath: directoryDocuments)
  175. }
  176. func removeTemporaryDirectory() {
  177. try? fileManager.removeItem(atPath: NSTemporaryDirectory())
  178. }
  179. func emptyTemporaryDirectory() {
  180. do {
  181. let files = try fileManager.contentsOfDirectory(atPath: NSTemporaryDirectory())
  182. for file in files {
  183. do {
  184. try fileManager.removeItem(atPath: NSTemporaryDirectory() + "/" + file)
  185. } catch { print("Error: \(error)") }
  186. }
  187. } catch { print("Error: \(error)") }
  188. }
  189. func isDirectoryE2EE(serverUrl: String, account: String) -> Bool {
  190. return isDirectoryE2EE(session: NCSession.shared.getSession(account: account), serverUrl: serverUrl)
  191. }
  192. func isDirectoryE2EE(file: NKFile) -> Bool {
  193. let session = NCSession.Session(account: file.account, urlBase: file.urlBase, user: file.user, userId: file.userId)
  194. return isDirectoryE2EE(session: session, serverUrl: file.serverUrl)
  195. }
  196. func isDirectoryE2EE(session: NCSession.Session, serverUrl: String) -> Bool {
  197. if serverUrl == getHomeServer(session: session) || serverUrl == ".." { return false }
  198. if let directory = NCManageDatabase.shared.getTableDirectory(account: session.account, serverUrl: serverUrl) {
  199. return directory.e2eEncrypted
  200. }
  201. return false
  202. }
  203. func isDirectoryE2EETop(account: String, serverUrl: String) -> Bool {
  204. guard let serverUrl = serverUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { return false }
  205. if let url = URL(string: serverUrl)?.deletingLastPathComponent(),
  206. let serverUrl = String(url.absoluteString.dropLast()).removingPercentEncoding {
  207. if let directory = NCManageDatabase.shared.getTableDirectory(account: account, serverUrl: serverUrl) {
  208. return !directory.e2eEncrypted
  209. }
  210. }
  211. return true
  212. }
  213. func getDirectoryE2EETop(serverUrl: String, account: String) -> tableDirectory? {
  214. guard var serverUrl = serverUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { return nil }
  215. var top: tableDirectory?
  216. while let url = URL(string: serverUrl)?.deletingLastPathComponent(),
  217. let serverUrlencoding = serverUrl.removingPercentEncoding,
  218. let directory = NCManageDatabase.shared.getTableDirectory(account: account, serverUrl: serverUrlencoding) {
  219. if directory.e2eEncrypted {
  220. top = directory
  221. } else {
  222. return top
  223. }
  224. serverUrl = String(url.absoluteString.dropLast())
  225. }
  226. return top
  227. }
  228. // MARK: -
  229. func getFileSize(filePath: String) -> Int64 {
  230. do {
  231. let attributes = try fileManager.attributesOfItem(atPath: filePath)
  232. return attributes[FileAttributeKey.size] as? Int64 ?? 0
  233. } catch {
  234. print(error)
  235. }
  236. return 0
  237. }
  238. func getFileModificationDate(filePath: String) -> NSDate? {
  239. do {
  240. let attributes = try fileManager.attributesOfItem(atPath: filePath)
  241. return attributes[FileAttributeKey.modificationDate] as? NSDate
  242. } catch {
  243. print(error)
  244. }
  245. return nil
  246. }
  247. func getFileCreationDate(filePath: String) -> NSDate? {
  248. do {
  249. let attributes = try fileManager.attributesOfItem(atPath: filePath)
  250. return attributes[FileAttributeKey.creationDate] as? NSDate
  251. } catch {
  252. print(error)
  253. }
  254. return nil
  255. }
  256. func writeFile(fileURL: URL, text: String) -> Bool {
  257. do {
  258. try FileManager.default.removeItem(at: fileURL)
  259. } catch {
  260. print(error)
  261. }
  262. do {
  263. try text.write(to: fileURL, atomically: true, encoding: .utf8)
  264. return true
  265. } catch {
  266. print(error)
  267. return false
  268. }
  269. }
  270. func removeFile(atPath: String) {
  271. do {
  272. try FileManager.default.removeItem(atPath: atPath)
  273. } catch {
  274. print(error)
  275. }
  276. }
  277. @discardableResult
  278. func moveFile(atPath: String, toPath: String) -> Bool {
  279. if atPath == toPath { return true }
  280. do {
  281. try FileManager.default.removeItem(atPath: toPath)
  282. } catch {
  283. print(error)
  284. }
  285. do {
  286. try FileManager.default.copyItem(atPath: atPath, toPath: toPath)
  287. try FileManager.default.removeItem(atPath: atPath)
  288. return true
  289. } catch {
  290. print(error)
  291. return false
  292. }
  293. }
  294. @discardableResult
  295. func copyFile(atPath: String, toPath: String) -> Bool {
  296. if atPath == toPath { return true }
  297. do {
  298. try FileManager.default.removeItem(atPath: toPath)
  299. } catch {
  300. print(error)
  301. }
  302. do {
  303. try FileManager.default.copyItem(atPath: atPath, toPath: toPath)
  304. return true
  305. } catch {
  306. print(error)
  307. return false
  308. }
  309. }
  310. @discardableResult
  311. func copyFile(at: URL, to: URL) -> Bool {
  312. if at == to { return true }
  313. do {
  314. try FileManager.default.removeItem(at: to)
  315. } catch {
  316. print(error)
  317. }
  318. do {
  319. try FileManager.default.copyItem(at: at, to: to)
  320. return true
  321. } catch {
  322. print(error)
  323. return false
  324. }
  325. }
  326. func moveFileInBackground(atPath: String, toPath: String) {
  327. if atPath == toPath { return }
  328. DispatchQueue.global().async {
  329. try? FileManager.default.removeItem(atPath: toPath)
  330. try? FileManager.default.copyItem(atPath: atPath, toPath: toPath)
  331. try? FileManager.default.removeItem(atPath: atPath)
  332. }
  333. }
  334. func linkItem(atPath: String, toPath: String) {
  335. try? FileManager.default.removeItem(atPath: toPath)
  336. try? FileManager.default.linkItem(atPath: atPath, toPath: toPath)
  337. }
  338. // MARK: -
  339. func getHomeServer(session: NCSession.Session) -> String {
  340. return session.urlBase + "/remote.php/dav/files/" + session.userId
  341. }
  342. func getPath(path: String, user: String, fileName: String? = nil) -> String {
  343. var path = path.replacingOccurrences(of: "/remote.php/dav/files/" + user, with: "")
  344. if let fileName = fileName {
  345. path += fileName
  346. }
  347. return path
  348. }
  349. func deleteLastPath(serverUrlPath: String, home: String? = nil) -> String? {
  350. var returnString: String?
  351. if home == serverUrlPath { return serverUrlPath }
  352. if let serverUrlPath = serverUrlPath.urlEncoded, let url = URL(string: serverUrlPath) {
  353. if let path = url.deletingLastPathComponent().absoluteString.removingPercentEncoding {
  354. if path.last == "/" {
  355. returnString = String(path.dropLast())
  356. } else {
  357. returnString = path
  358. }
  359. }
  360. }
  361. return returnString
  362. }
  363. func stringAppendServerUrl(_ serverUrl: String, addFileName: String) -> String {
  364. if addFileName.isEmpty {
  365. return serverUrl
  366. } else if serverUrl.last == "/" {
  367. return serverUrl + addFileName
  368. } else {
  369. return serverUrl + "/" + addFileName
  370. }
  371. }
  372. func getFileNamePath(_ fileName: String, serverUrl: String, session: NCSession.Session) -> String {
  373. let home = getHomeServer(session: session)
  374. var fileNamePath = serverUrl.replacingOccurrences(of: home, with: "") + "/" + fileName
  375. if fileNamePath.first == "/" {
  376. fileNamePath.removeFirst()
  377. }
  378. return fileNamePath
  379. }
  380. func createFileName(_ fileName: String, fileDate: Date, fileType: PHAssetMediaType, notUseMask: Bool = false) -> String {
  381. var fileName = fileName
  382. let keychain = NCKeychain()
  383. var addFileNameType: Bool = keychain.fileNameType
  384. let useFileNameOriginal: Bool = keychain.fileNameOriginal
  385. var numberFileName: String = ""
  386. var fileNameType = ""
  387. let fileNameExt = (fileName as NSString).pathExtension.lowercased()
  388. /// Original FileName
  389. if useFileNameOriginal {
  390. addFileNameType = false
  391. if !notUseMask {
  392. return fileName
  393. }
  394. }
  395. /// Get counter
  396. if fileName.count > 8 {
  397. let index = fileName.index(fileName.startIndex, offsetBy: 4)
  398. numberFileName = String(fileName[index..<fileName.index(index, offsetBy: 4)])
  399. } else {
  400. numberFileName = keychain.incrementalNumber
  401. }
  402. let formatter = DateFormatter()
  403. formatter.locale = Locale(identifier: "en_US_POSIX")
  404. formatter.dateFormat = "yy-MM-dd HH-mm-ss"
  405. let fileNameDate = formatter.string(from: fileDate)
  406. switch fileType {
  407. case .image:
  408. fileNameType = NSLocalizedString("_photo_", comment: "")
  409. case .video:
  410. fileNameType = NSLocalizedString("_video_", comment: "")
  411. case .audio:
  412. fileNameType = NSLocalizedString("_audio_", comment: "")
  413. case .unknown:
  414. fileNameType = NSLocalizedString("_unknown_", comment: "")
  415. default:
  416. fileNameType = NSLocalizedString("_unknown_", comment: "")
  417. }
  418. if !keychain.fileNameMask.isEmpty, !notUseMask {
  419. fileName = keychain.fileNameMask
  420. if !fileName.isEmpty {
  421. formatter.dateFormat = "dd"
  422. let dayNumber = formatter.string(from: fileDate)
  423. formatter.dateFormat = "MMM"
  424. let month = formatter.string(from: fileDate)
  425. formatter.dateFormat = "MM"
  426. let monthNumber = formatter.string(from: fileDate)
  427. formatter.dateFormat = "yyyy"
  428. let year = formatter.string(from: fileDate)
  429. formatter.dateFormat = "yy"
  430. let yearNumber = formatter.string(from: fileDate)
  431. formatter.dateFormat = "HH"
  432. let hour24 = formatter.string(from: fileDate)
  433. formatter.dateFormat = "hh"
  434. let hour12 = formatter.string(from: fileDate)
  435. formatter.dateFormat = "mm"
  436. let minute = formatter.string(from: fileDate)
  437. formatter.dateFormat = "ss"
  438. let second = formatter.string(from: fileDate)
  439. formatter.dateFormat = "a"
  440. let ampm = formatter.string(from: fileDate)
  441. // Replace string with date
  442. fileName = fileName.replacingOccurrences(of: "DD", with: dayNumber)
  443. fileName = fileName.replacingOccurrences(of: "MMM", with: month)
  444. fileName = fileName.replacingOccurrences(of: "MM", with: monthNumber)
  445. fileName = fileName.replacingOccurrences(of: "YYYY", with: year)
  446. fileName = fileName.replacingOccurrences(of: "YY", with: yearNumber)
  447. fileName = fileName.replacingOccurrences(of: "HH", with: hour24)
  448. fileName = fileName.replacingOccurrences(of: "hh", with: hour12)
  449. fileName = fileName.replacingOccurrences(of: "mm", with: minute)
  450. fileName = fileName.replacingOccurrences(of: "ss", with: second)
  451. fileName = fileName.replacingOccurrences(of: "ampm", with: ampm)
  452. if addFileNameType {
  453. fileName = "\(fileNameType)\(fileName)\(numberFileName).\(fileNameExt)"
  454. } else {
  455. fileName = "\(fileName)\(numberFileName).\(fileNameExt)"
  456. }
  457. fileName = fileName.trimmingCharacters(in: .whitespacesAndNewlines)
  458. return fileName
  459. }
  460. }
  461. if addFileNameType {
  462. fileName = "\(fileNameType) \(fileNameDate) \(numberFileName).\(fileNameExt)"
  463. } else {
  464. fileName = "\(fileNameDate) \(numberFileName).\(fileNameExt)"
  465. }
  466. return fileName
  467. }
  468. func createFileName(_ fileName: String, serverUrl: String, account: String) -> String {
  469. var resultFileName = fileName
  470. var exitLoop = false
  471. while exitLoop == false {
  472. if NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "fileNameView == %@ AND serverUrl == %@ AND account == %@", resultFileName, serverUrl, account)) != nil {
  473. var name = NSString(string: resultFileName).deletingPathExtension
  474. let ext = NSString(string: resultFileName).pathExtension
  475. let characters = Array(name)
  476. if characters.count < 2 {
  477. if ext.isEmpty {
  478. resultFileName = name + " " + "1"
  479. } else {
  480. resultFileName = name + " " + "1" + "." + ext
  481. }
  482. } else {
  483. let space = characters[characters.count - 2]
  484. let numChar = characters[characters.count - 1]
  485. var num = Int(String(numChar))
  486. if space == " " && num != nil {
  487. name = String(name.dropLast())
  488. num = num! + 1
  489. if ext.isEmpty {
  490. resultFileName = name + "\(num!)"
  491. } else {
  492. resultFileName = name + "\(num!)" + "." + ext
  493. }
  494. } else {
  495. if ext.isEmpty {
  496. resultFileName = name + " " + "1"
  497. } else {
  498. resultFileName = name + " " + "1" + "." + ext
  499. }
  500. }
  501. }
  502. } else {
  503. exitLoop = true
  504. }
  505. }
  506. return resultFileName
  507. }
  508. func createFileNameDate(_ fileName: String, ext: String) -> String {
  509. let formatter = DateFormatter()
  510. formatter.dateFormat = "yy-MM-dd HH-mm-ss"
  511. let fileNameDate = formatter.string(from: Date())
  512. if fileName.isEmpty, !ext.isEmpty {
  513. return fileNameDate + "." + ext
  514. } else if !fileName.isEmpty, ext.isEmpty {
  515. return fileName + " " + fileNameDate
  516. } else if fileName.isEmpty, ext.isEmpty {
  517. return fileNameDate
  518. } else {
  519. return fileName + " " + fileNameDate + "." + ext
  520. }
  521. }
  522. func getDirectorySize(directory: String) -> Int64 {
  523. let url = URL(fileURLWithPath: directory)
  524. let manager = FileManager.default
  525. var totalSize: Int64 = 0
  526. if let enumerator = manager.enumerator(at: url, includingPropertiesForKeys: [.isRegularFileKey], options: []) {
  527. for case let fileURL as URL in enumerator {
  528. if let attributes = try? manager.attributesOfItem(atPath: fileURL.path) {
  529. if let size = attributes[.size] as? Int64 {
  530. totalSize += size
  531. }
  532. }
  533. }
  534. }
  535. return totalSize
  536. }
  537. func transformedSize(_ bytes: Int64) -> String {
  538. let formatter: ByteCountFormatter = ByteCountFormatter()
  539. formatter.countStyle = .binary
  540. return formatter.string(fromByteCount: bytes)
  541. }
  542. func cleanUp(directory: String, days: TimeInterval) {
  543. if days == 0 { return}
  544. let minimumDate = Date().addingTimeInterval(-days * 24 * 60 * 60)
  545. let url = URL(fileURLWithPath: directory)
  546. var offlineDir: [String] = []
  547. if let directories = NCManageDatabase.shared.getTablesDirectory(predicate: NSPredicate(format: "offline == true"), sorted: "serverUrl", ascending: true) {
  548. for directory: tableDirectory in directories {
  549. offlineDir.append(getDirectoryProviderStorageOcId(directory.ocId))
  550. }
  551. }
  552. let resultsLocalFile = NCManageDatabase.shared.getResultsTableLocalFile(predicate: NSPredicate(format: "offline == false"), sorted: "lastOpeningDate", ascending: true)
  553. let manager = FileManager.default
  554. if let enumerator = manager.enumerator(at: url, includingPropertiesForKeys: [.isRegularFileKey], options: []) {
  555. for case let fileURL as URL in enumerator {
  556. if let attributes = try? manager.attributesOfItem(atPath: fileURL.path) {
  557. if attributes[.size] as? Double == 0 { continue }
  558. if attributes[.type] as? FileAttributeType == FileAttributeType.typeDirectory { continue }
  559. if fileURL.pathExtension == "ico" { continue }
  560. // check directory offline
  561. let filter = offlineDir.filter({ fileURL.path.hasPrefix($0)})
  562. if !filter.isEmpty { continue }
  563. // -----------------------
  564. let folderURL = fileURL.deletingLastPathComponent()
  565. let ocId = folderURL.lastPathComponent
  566. if let result = resultsLocalFile?.filter({ $0.ocId == ocId }).first, (result.lastOpeningDate as Date) < minimumDate {
  567. do {
  568. try manager.removeItem(atPath: fileURL.path)
  569. } catch { }
  570. manager.createFile(atPath: fileURL.path, contents: nil, attributes: nil)
  571. NCManageDatabase.shared.deleteLocalFileOcId(ocId)
  572. }
  573. }
  574. }
  575. }
  576. }
  577. func clearCacheDirectory(_ directory: String) {
  578. if let cacheURL = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first {
  579. do {
  580. let directoryURL = cacheURL.appendingPathComponent(directory, isDirectory: true)
  581. let directoryContents = try fileManager.contentsOfDirectory(at: directoryURL, includingPropertiesForKeys: nil, options: [])
  582. for file in directoryContents {
  583. do {
  584. try fileManager.removeItem(at: file)
  585. } catch let error as NSError {
  586. debugPrint("Ooops! Something went wrong: \(error)")
  587. }
  588. }
  589. } catch let error as NSError {
  590. print(error.localizedDescription)
  591. }
  592. }
  593. }
  594. func createGranularityPath(asset: PHAsset? = nil, serverUrl: String? = nil) -> String {
  595. let autoUploadSubfolderGranularity = NCManageDatabase.shared.getAccountAutoUploadSubfolderGranularity()
  596. let dateFormatter = DateFormatter()
  597. let date = asset?.creationDate ?? Date()
  598. var path = ""
  599. dateFormatter.dateFormat = "yyyy"
  600. let year = dateFormatter.string(from: date)
  601. dateFormatter.dateFormat = "MM"
  602. let month = dateFormatter.string(from: date)
  603. dateFormatter.dateFormat = "dd"
  604. let day = dateFormatter.string(from: date)
  605. if autoUploadSubfolderGranularity == NCGlobal.shared.subfolderGranularityYearly {
  606. path = "\(year)"
  607. } else if autoUploadSubfolderGranularity == NCGlobal.shared.subfolderGranularityDaily {
  608. path = "\(year)/\(month)/\(day)"
  609. } else { // Month Granularity is default
  610. path = "\(year)/\(month)"
  611. }
  612. if let serverUrl {
  613. return serverUrl + "/" + path
  614. } else {
  615. return path
  616. }
  617. }
  618. }