-
Notifications
You must be signed in to change notification settings - Fork 199
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(storage): Fixing watchOS crash when dealing with big files (#3389)
- Loading branch information
Showing
14 changed files
with
134 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/FileHandle+UInt64.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// | ||
// Copyright Amazon.com Inc. or its affiliates. | ||
// All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
import Foundation | ||
|
||
extension FileHandle { | ||
/// Reads data synchronously up to the specified number of bytes. | ||
/// - Parameter bytes: The number of bytes to read from the file handle. | ||
/// - Parameter bytesReadLimit: The maximum number of bytes that can be read at a time. Defaults to `Int.max`. | ||
/// - Returns: The data available through the receiver up to a maximum of length bytes, or the maximum size that can be represented by a Data object. | ||
/// - Throws: An error if attempts to determine the file-handle type fail or if attempts to read from the file or channel fail. | ||
func read(bytes: UInt64, bytesReadLimit: Int = Int.max) throws -> Data { | ||
// Read as much as it's possible considering the `bytesReadLimit` maximum | ||
let bytesRead = bytes <= bytesReadLimit ? Int(bytes) : bytesReadLimit | ||
guard var data = try readData(upToCount: bytesRead) else { | ||
// There is no more data to read from the file | ||
return Data() | ||
} | ||
|
||
// If there's remaining bytes to read, do it and append to the current data | ||
let remainingBytes = bytes - UInt64(bytesRead) | ||
if remainingBytes > 0 { | ||
try data.append(read( | ||
bytes: remainingBytes, | ||
bytesReadLimit: bytesReadLimit | ||
)) | ||
} | ||
|
||
return data | ||
} | ||
|
||
private func readData(upToCount length: Int) throws -> Data? { | ||
if #available(iOS 13.4, macOS 10.15.4, tvOS 13.4, *) { | ||
return try read(upToCount: length) | ||
} else { | ||
return readData(ofLength: length) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Support/Internal/FileHandleTests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// | ||
// Copyright Amazon.com Inc. or its affiliates. | ||
// All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
import XCTest | ||
@testable import AWSS3StoragePlugin | ||
|
||
class FileHandleTests: XCTestCase { | ||
|
||
/// Given: A FileHandle and a file | ||
/// When: `read(bytes:bytesReadLimit)` is invoked with `bytesReadLimit` being lower than `bytes` | ||
/// Then: Only `bytesReadLimit` bytes will be read at a time, but all `bytes` will be read and returned | ||
func testRead_withBytesHigherThanLimit_shouldSucceedByReadingMultipleTimes() throws { | ||
let sourceString = "012345678910" // 11 bytes | ||
let sourceData = sourceString.data(using: .utf8)! | ||
let sourceFile = try createFile(from: sourceData) | ||
XCTAssertEqual(try StorageRequestUtils.getSize(sourceFile), UInt64(sourceString.count)) | ||
|
||
let fileSystem = FileSystem() | ||
let bytesReadLimit = 2 | ||
|
||
let fileHandle = try FileHandle(forReadingFrom: sourceFile) | ||
let firstPartData = try fileHandle.read(bytes: 5, bytesReadLimit: bytesReadLimit) | ||
let firstPartString = String(decoding: firstPartData, as: UTF8.self) | ||
XCTAssertEqual(firstPartString, "01234") // i.e. the first 5 bytes | ||
|
||
let secondPartData = try fileHandle.read(bytes: 5, bytesReadLimit: bytesReadLimit) | ||
let secondPartString = String(decoding: secondPartData, as: UTF8.self) | ||
XCTAssertEqual(secondPartString, "56789") // i.e. the second 5 bytes | ||
|
||
let thirdPartData = try fileHandle.read(bytes: 5, bytesReadLimit: bytesReadLimit) | ||
let thirdPartString = String(decoding: thirdPartData, as: UTF8.self) | ||
XCTAssertEqual(thirdPartString, "10") // i.e. the remaining bytes | ||
|
||
try FileManager.default.removeItem(at: sourceFile) | ||
} | ||
|
||
private func createFile(from data: Data) throws -> URL { | ||
let fileUrl = try FileManager.default.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: true) | ||
.appendingPathComponent("\(UUID().uuidString).tmp") | ||
try data.write(to: fileUrl, options: .atomic) | ||
return fileUrl | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters