Fix OpenFlags.Append mode for io2.openFile() (#226)

* Initial commit.

* Fix Windows version.

* Remove debugging echoes.

* Fix Posix version.

* Add one more test.
This commit is contained in:
Eugene Kabanov 2024-08-02 08:32:31 +03:00 committed by GitHub
parent 8e0e344f0f
commit af07b0a70d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 156 additions and 46 deletions

View File

@ -32,6 +32,7 @@ when defined(windows):
FILE_FLAG_OVERLAPPED = 0x40000000'u32 FILE_FLAG_OVERLAPPED = 0x40000000'u32
FILE_SHARE_READ = 0x00000001'u32 FILE_SHARE_READ = 0x00000001'u32
FILE_SHARE_WRITE = 0x00000002'u32 FILE_SHARE_WRITE = 0x00000002'u32
FILE_APPEND_DATA = 0x00000004'u32
FILE_FLAG_NO_BUFFERING = 0x20000000'u32 FILE_FLAG_NO_BUFFERING = 0x20000000'u32
FILE_ATTRIBUTE_READONLY = 0x00000001'u32 FILE_ATTRIBUTE_READONLY = 0x00000001'u32
@ -1012,7 +1013,14 @@ proc openFile*(pathName: string, flags: set[OpenFlags],
if OpenFlags.Truncate in flags: if OpenFlags.Truncate in flags:
cflags = cflags or posix.O_TRUNC cflags = cflags or posix.O_TRUNC
if OpenFlags.Append in flags: if OpenFlags.Append in flags:
cflags = cflags or posix.O_APPEND if ((cflags and posix.O_WRONLY) != 0) or ((cflags and posix.O_RDWR) != 0):
cflags = cflags or posix.O_APPEND
else:
if ((cflags and posix.O_RDONLY) != 0):
cflags = cflags and not(posix.O_RDONLY)
cflags = cflags or posix.O_APPEND or O_RDWR
else:
cflags = cflags or posix.O_APPEND or O_WRONLY
when defined(linux) or defined(freebsd) or defined(netbsd) or when defined(linux) or defined(freebsd) or defined(netbsd) or
defined(dragonflybsd): defined(dragonflybsd):
if OpenFlags.Direct in flags: if OpenFlags.Direct in flags:
@ -1053,7 +1061,7 @@ proc openFile*(pathName: string, flags: set[OpenFlags],
var var
dwAccess: uint32 dwAccess: uint32
dwShareMode: uint32 dwShareMode: uint32
dwCreation: uint32 dwCreation: uint32 = OPEN_EXISTING
dwFlags: uint32 dwFlags: uint32
var sa = SECURITY_ATTRIBUTES( var sa = SECURITY_ATTRIBUTES(
@ -1062,36 +1070,37 @@ proc openFile*(pathName: string, flags: set[OpenFlags],
bInheritHandle: 0 bInheritHandle: 0
) )
if (OpenFlags.Write in flags) and (OpenFlags.Read in flags): if OpenFlags.Write in flags:
dwAccess = dwAccess or (GENERIC_READ or GENERIC_WRITE) dwAccess = dwAccess or GENERIC_WRITE
else: if OpenFlags.Read in flags:
if OpenFlags.Write in flags: dwAccess = dwAccess or GENERIC_READ
dwAccess = dwAccess or GENERIC_WRITE if OpenFlags.Append in flags:
else: dwAccess = dwAccess or FILE_APPEND_DATA
dwAccess = dwAccess or GENERIC_READ
if {OpenFlags.Create, OpenFlags.Exclusive} <= flags: if OpenFlags.Truncate in flags:
dwCreation = dwCreation or CREATE_NEW
elif OpenFlags.Truncate in flags:
if OpenFlags.Create in flags: if OpenFlags.Create in flags:
dwCreation = dwCreation or CREATE_ALWAYS dwCreation = dwCreation or CREATE_ALWAYS
elif OpenFlags.Read notin flags: else:
dwCreation = dwCreation or TRUNCATE_EXISTING dwCreation = dwCreation or TRUNCATE_EXISTING
elif OpenFlags.Append in flags:
dwCreation = dwCreation or OPEN_EXISTING if {OpenFlags.Create} == flags or
elif OpenFlags.Create in flags: {OpenFlags.Create, OpenFlags.Exclusive} == flags:
dwCreation = dwCreation or OPEN_ALWAYS dwCreation = dwCreation or CREATE_NEW
else: else:
dwCreation = dwCreation or OPEN_EXISTING if OpenFlags.Create in flags:
dwCreation = dwCreation and not(OPEN_EXISTING)
dwCreation = dwCreation or OPEN_ALWAYS
if dwCreation == OPEN_EXISTING and if dwCreation == OPEN_EXISTING and
((dwAccess and (GENERIC_READ or GENERIC_WRITE)) == GENERIC_READ): ((dwAccess and GENERIC_READ) == GENERIC_READ):
dwShareMode = dwShareMode or FILE_SHARE_READ if OpenFlags.Exclusive notin flags:
dwShareMode = dwShareMode or FILE_SHARE_READ
if OpenFlags.ShareRead in flags: if OpenFlags.Exclusive notin flags:
dwShareMode = dwShareMode or FILE_SHARE_READ if OpenFlags.ShareRead in flags:
if OpenFlags.ShareWrite in flags: dwShareMode = dwShareMode or FILE_SHARE_READ
dwShareMode = dwShareMode or FILE_SHARE_WRITE if OpenFlags.ShareWrite in flags:
dwShareMode = dwShareMode or FILE_SHARE_WRITE
if OpenFlags.NonBlock in flags: if OpenFlags.NonBlock in flags:
dwFlags = dwFlags or FILE_FLAG_OVERLAPPED dwFlags = dwFlags or FILE_FLAG_OVERLAPPED

View File

@ -406,35 +406,136 @@ suite "OS Input/Output procedures test suite":
removeFile("testblob6").isOk() removeFile("testblob6").isOk()
test "openFile()/readFile()/writeFile() test": test "openFile()/readFile()/writeFile() test":
var buffer = newString(10) var buffer = newString(100)
let flags = {OpenFlags.Write, OpenFlags.Truncate, OpenFlags.Create}
var fdres = openFile("testfile.txt", flags) block:
check: let
fdres.isOk() flags = {OpenFlags.Write, OpenFlags.Truncate, OpenFlags.Create}
readFile(fdres.get(), buffer).isErr() fdres = openFile("testfile.txt", flags)
writeFile(fdres.get(), "TEST").isOk() check:
readFile(fdres.get(), buffer).isErr() fdres.isOk()
closeFile(fdres.get()).isOk() readFile(fdres.get(), buffer).isErr()
writeFile(fdres.get(), "TEST1").isOk()
readFile(fdres.get(), buffer).isErr()
closeFile(fdres.get()).isOk()
fdres = openFile("testfile.txt", {OpenFlags.Read}) block:
check: let fdres = openFile("testfile.txt", {OpenFlags.Read})
fdres.isOk() check fdres.isOk()
readFile(fdres.get(), buffer).isOk() let res1 = readFile(fdres.get(), buffer)
writeFile(fdres.get(), "TEST2").isErr() check:
readFile(fdres.get(), buffer).isOk() res1.isOk()
closeFile(fdres.get()).isOk() res1.get() == uint(5)
writeFile(fdres.get(), "TEST2").isErr()
let res2 = readFile(fdres.get(), buffer)
check:
res2.isOk()
res2.get() == uint(0)
closeFile(fdres.get()).isOk()
fdres = openFile("testfile.txt", {OpenFlags.Read, OpenFlags.Write}) block:
check: let fdres = openFile("testfile.txt", {OpenFlags.Read, OpenFlags.Write})
fdres.isOk() check fdres.isOk()
readFile(fdres.get(), buffer).isOk() let res1 = readFile(fdres.get(), buffer)
writeFile(fdres.get(), "TEST2").isOk() check:
closeFile(fdres.get()).isOk() res1.isOk()
res1.get() == uint(5)
writeFile(fdres.get(), "TEST3").isOk()
closeFile(fdres.get()).isOk()
block:
let fdres = openFile("testfile.txt", {OpenFlags.Read})
check fdres.isOk()
let res1 = readFile(fdres.get(), buffer)
check:
res1.isOk()
res1.get() == uint(10)
buffer[0 .. 9] == "TEST1TEST3"
closeFile(fdres.get()).isOk()
block:
let fdres = openFile("testfile.txt", {OpenFlags.Write})
check:
fdres.isOk()
writeFile(fdres.get(), "TEST2").isOk()
closeFile(fdres.get()).isOk()
block:
let fdres = openFile("testfile.txt", {OpenFlags.Read})
check fdres.isOk()
let res1 = readFile(fdres.get(), buffer)
check:
res1.isOk()
res1.get() == uint(10)
buffer[0 .. 9] == "TEST2TEST3"
closeFile(fdres.get()).isOk()
block:
let fdres = openFile("testfile.txt", {OpenFlags.Append})
check:
fdres.isOk()
writeFile(fdres.get(), "TEST4").isOk()
closeFile(fdres.get()).isOk()
block:
let fdres = openFile("testfile.txt", {OpenFlags.Append})
check:
fdres.isOk()
writeFile(fdres.get(), "TEST5").isOk()
closeFile(fdres.get()).isOk()
block:
let fdres = openFile("testfile.txt", {OpenFlags.Read})
check fdres.isOk()
let res = readFile(fdres.get(), buffer)
check:
res.isOk()
res.get() == 20
buffer[0 .. 19] == "TEST2TEST3TEST4TEST5"
closeFile(fdres.get()).isOk()
check: check:
removeFile("testfile.txt").isOk() removeFile("testfile.txt").isOk()
# Create file if not exists and append data to file.
block:
let fdres = openFile("testfile.txt", {OpenFlags.Append, OpenFlags.Create})
check:
fdres.isOk()
writeFile(fdres.get(), "TEST1").isOk()
closeFile(fdres.get()).isOk()
block:
let fdres = openFile("testfile.txt", {OpenFlags.Append, OpenFlags.Create})
check:
fdres.isOk()
writeFile(fdres.get(), "TEST2").isOk()
closeFile(fdres.get()).isOk()
block:
let fdres = openFile("testfile.txt", {OpenFlags.Read})
check fdres.isOk()
let res = readFile(fdres.get(), buffer)
check:
res.isOk()
res.get() == 10
buffer[0 .. 9] == "TEST1TEST2"
closeFile(fdres.get()).isOk()
check:
removeFile("testfile.txt").isOk()
# Open nonexisting file with different flags.
check:
openFile("testfile.txt", {OpenFlags.Append}).isErr()
openFile("testfile.txt", {OpenFlags.Read}).isErr()
openFile("testfile.txt", {OpenFlags.Write}).isErr()
openFile("testfile.txt", {OpenFlags.Read, OpenFlags.Write}).isErr()
openFile("testfile.txt", {OpenFlags.Read, OpenFlags.Write,
OpenFlags.Append}).isErr()
test "toString(set[Permission]) test": test "toString(set[Permission]) test":
let emptyMask: set[Permission] = {} let emptyMask: set[Permission] = {}
check: check: