Skip to content

Commit

Permalink
fix: Truncate issues and add tests for SetInfo
Browse files Browse the repository at this point in the history
  • Loading branch information
amosavian committed Oct 6, 2024
1 parent bdb2a08 commit f1ea3b0
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 38 deletions.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "Dependencies/libsmb2"]
path = Dependencies/libsmb2
url = https://github.com/amosavian/libsmb2.git
url = https://github.com/sahlberg/libsmb2
66 changes: 30 additions & 36 deletions AMSMB2/AMSMB2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -919,7 +919,7 @@ public class SMB2Manager: NSObject, NSSecureCoding, Codable, NSCopying, CustomRe
- Returns: a `Data` object which contains file contents.
*/
open func contents<R: RangeExpression>(
atPath path: String, range: R? = Range<UInt64>?.none, progress: ReadProgressHandler
atPath path: String, range: R? = Range<UInt64>?.none, progress: ReadProgressHandler = nil
) async throws -> Data where R.Bound: FixedWidthInteger {
try await withCheckedThrowingContinuation { continuation in
contents(
Expand Down Expand Up @@ -1719,48 +1719,42 @@ extension SMB2Manager {
context: SMB2Context, from stream: InputStream, toPath: String,
offset: Int64? = nil, chunkSize: Int = 0, progress: WriteProgressHandler
) throws {
let file = offset == nil ? try SMB2FileHandle(forCreatingIfNotExistsAtPath: toPath, on: context) : try SMB2FileHandle(
forOutputAtPath: toPath,
on: context
)
let file: SMB2FileHandle
if let offset {
try context.truncate(toPath, toLength: .init(offset))
file = try SMB2FileHandle(forOutputAtPath: toPath, on: context)
try file.lseek(offset: offset, whence: .set)
} else {
file = try SMB2FileHandle(forCreatingIfNotExistsAtPath: toPath, on: context)
}
let chunkSize = chunkSize > 0 ? chunkSize : file.optimizedWriteSize
var totalWritten: UInt64 = 0

do {
if let offset {
try file.lseek(offset: offset, whence: .set)
try file.ftruncate(toLength: UInt64(offset))
}

try stream.withOpenStream {
while true {
let segment = try stream.readData(maxLength: chunkSize)
if segment.isEmpty {
break
}
let written = try file.pwrite(data: segment, offset: UInt64(offset ?? 0) + totalWritten)
if written != segment.count {
throw POSIXError(
.EIO, description: "Inconsistency in writing to SMB file handle."
)
}
try stream.withOpenStream {
while true {
let segment = try stream.readData(maxLength: chunkSize)
if segment.isEmpty {
break
}
let written = try file.pwrite(data: segment, offset: UInt64(offset ?? 0) + totalWritten)
if written != segment.count {
throw POSIXError(
.EIO, description: "Inconsistency in writing to SMB file handle."
)
}

totalWritten += UInt64(segment.count)
var offset = try file.lseek(offset: 0, whence: .current)
if offset > totalWritten {
offset = Int64(totalWritten)
}
if let shouldContinue = progress?(Int64(totalWritten)), !shouldContinue {
break
}
totalWritten += UInt64(segment.count)
var offset = try file.lseek(offset: 0, whence: .current)
if offset > totalWritten {
offset = Int64(totalWritten)
}
if let shouldContinue = progress?(Int64(totalWritten)), !shouldContinue {
break
}
}

try file.fsync()
} catch {
try? context.unlink(toPath)
throw error
}

try file.fsync()
}
}

Expand Down
39 changes: 39 additions & 0 deletions AMSMB2Tests/SMB2ManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,46 @@ class SMB2ManagerTests: XCTestCase {
XCTAssertEqual(initialAttribs.contentModificationDate, newAttribs.contentModificationDate)
XCTAssertEqual(newAttribs.creationDate, Date(timeIntervalSinceReferenceDate: 0))
}

func testFileRename() async throws {
let file = "renametest.dat"
let renamedFile = "renamed.dat"
let size: Int = random(max: 0x000800)
let smb = SMB2Manager(url: server, credential: credential)!
let data = randomData(size: size)

addTeardownBlock {
try? await smb.removeFile(atPath: file)
try? await smb.removeFile(atPath: renamedFile)
}

try await smb.connectShare(name: share, encrypted: encrypted)
try await smb.write(data: data, toPath: file, progress: nil)

try await smb.moveItem(atPath: file, toPath: renamedFile)
let renamedData = try await smb.contents(atPath: renamedFile)
XCTAssertEqual(data, renamedData)
}

func testFileTruncate() async throws {
let file = "trunctest.dat"
let size: Int = random(max: 0x000800)
let smb = SMB2Manager(url: server, credential: credential)!
let data = randomData(size: size)

addTeardownBlock {
try? await smb.removeFile(atPath: file)
}

try await smb.connectShare(name: share, encrypted: encrypted)
try await smb.write(data: data, toPath: file, progress: nil)

try await smb.truncateFile(atPath: file, atOffset: 0x000200)
let truncData = try await smb.contents(atPath: file)
XCTAssertEqual(truncData.count, 0x000200)
XCTAssertEqual(data.prefix(truncData.count), truncData)
}

func testListing() async throws {
let smb = SMB2Manager(url: server, credential: credential)!
try await smb.connectShare(name: share, encrypted: encrypted)
Expand Down

0 comments on commit f1ea3b0

Please sign in to comment.