Add truncate()/ftruncate() cross-platform implementation. (#225)

This commit is contained in:
Eugene Kabanov 2024-07-29 02:03:43 +03:00 committed by GitHub
parent 54cc67cbb8
commit 8e0e344f0f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 92 additions and 0 deletions

View File

@ -183,6 +183,8 @@ when defined(windows):
lpNewFilePointer: ptr int64,
dwMoveMethod: uint32): int32 {.
importc: "SetFilePointerEx", dynlib: "kernel32", stdcall, sideEffect.}
proc setEndOfFile(hFile: uint): int32 {.
importc: "SetEndOfFile", dynlib: "kernel32", stdcall, sideEffect.}
proc lockFileEx(hFile: uint, dwFlags, dwReserved: uint32,
nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh: uint32,
lpOverlapped: pointer): uint32 {.
@ -1341,6 +1343,45 @@ proc setFilePos*(handle: IoHandle, offset: int64,
else:
ok()
proc truncate*(handle: IoHandle, length: int64): IoResult[void] =
## Procedure cause the regular file referenced by handle ``handle`` to be
## truncated to a size of precisely ``length`` bytes.
when defined(windows):
let res1 = setFilePointerEx(uint(handle), length, nil, FILE_BEGIN)
if res1 == 0:
return err(ioLastError())
let res2 = setEndOfFile(uint(handle))
if res2 == 0:
return err(ioLastError())
ok()
else:
let res = posix.ftruncate(cint(handle), Off(length))
if res == -1:
err(ioLastError())
else:
ok()
proc truncate*(pathName: string, length: int64): IoResult[void] =
## Procedure cause the regular file referenced by path ``pathName`` to be
## truncated to a size of precisely ``length`` bytes.
when defined(windows):
let
flags = {OpenFlags.Write}
handle = openFile(pathName, flags).valueOr:
return err(error)
res = truncate(handle, length)
if res.isErr():
discard closeFile(handle)
return err(res.error)
? closeFile(handle)
ok()
else:
let res = posix.truncate(pathName, Off(length))
if res == -1:
err(ioLastError())
else:
ok()
proc checkFileSize*(value: int64): IoResult[int] =
## Checks if ``value`` fits into supported by Nim string/sequence indexing
## mechanism.

View File

@ -792,3 +792,54 @@ suite "OS Input/Output procedures test suite":
check:
res.isOk()
len(res.get()) > 0
test "truncate(IoHandle) test":
let flags = {OpenFlags.Create, OpenFlags.Write}
block:
let fdres = openFile("testtruncate1", flags)
check:
fdres.isOk()
truncate(fdres.get(), 100).isOk()
closeFile(fdres.get()).isOk()
block:
let res = getFileSize("testtruncate1")
check:
res.isOk()
res.get() == 100
block:
let fdres = openFile("testtruncate1", flags)
check:
fdres.isOk()
truncate(fdres.get(), 0).isOk()
closeFile(fdres.get()).isOk()
block:
let res = getFileSize("testtruncate1")
check:
res.isOk()
res.get() == 0
check removeFile("testtruncate1").isOk()
test "truncate(path) test":
check:
writeFile("testtruncate2", "TEST", 0o644).isOk()
truncate("testtruncate2", 200).isOk()
block:
let res = getFileSize("testtruncate2")
check:
res.isOk()
res.get() == 200
check truncate("testtruncate2", 0).isOk()
block:
let res = getFileSize("testtruncate2")
check:
res.isOk()
res.get() == 0
check removeFile("testtruncate2").isOk()