Add ability to open a file for writing (#975)

* Add ability to open a file for writing

Motivation:
Users can use NonBlockingFileIO for reading files, but if one wants to
write a file, there is no way to achieve that, apart from opening file
manually. I think having to inits to open files for reading and writing
would be convinient.

Modifications:
Allow to open files for writing.

Result:
Users can now open files for writing and reading in the same way.
This commit is contained in:
Artem Redkin 2019-04-29 16:17:14 +01:00 committed by Johannes Weiss
parent 12654afd21
commit 93b8807c5d
2 changed files with 67 additions and 5 deletions

View File

@ -81,12 +81,57 @@ public final class NIOFileHandle: FileDescriptor {
}
extension NIOFileHandle {
/// `Mode` represents file access modes.
public struct Mode: OptionSet {
public let rawValue: UInt8
public init(rawValue: UInt8) {
self.rawValue = rawValue
}
internal var posixFlags: CInt {
switch self {
case [.read, .write]:
return O_RDWR
case .read:
return O_RDONLY
case .write:
return O_WRONLY
default:
preconditionFailure("Unsupported mode value")
}
}
/// Opens file for reading
public static let read = Mode(rawValue: 1 << 0)
/// Opens file for writing
public static let write = Mode(rawValue: 1 << 1)
}
/// `Flags` allows to specify additional flags to `Mode`, such as permission for file creation.
public struct Flags {
internal var posixMode: mode_t
internal var posixFlags: CInt
public static let `default` = Flags(posixMode: 0, posixFlags: 0)
/// Allows file creation when opening file for writing. File owner is set to the effective user ID of the process.
///
/// - parameters:
/// - posixMode: `file mode` applied when file is created. Default permissions are: read and write for file owner, read for owners group and others.
public static func allowFileCreation(posixMode: mode_t = S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH) -> Flags {
return Flags(posixMode: posixMode, posixFlags: O_CREAT)
}
}
/// Open a new `NIOFileHandle`.
///
/// - parameters:
/// - path: the path of the file to open. The ownership of the file descriptor is transferred to this `NIOFileHandle` and so it will be closed once `close` is called.
public convenience init(path: String) throws {
let fd = try Posix.open(file: path, oFlag: O_RDONLY | O_CLOEXEC)
/// - path: The path of the file to open. The ownership of the file descriptor is transferred to this `NIOFileHandle` and so it will be closed once `close` is called.
/// - mode: Access mode. Default mode is `.read`.
/// - flags: Additional POSIX flags.
public convenience init(path: String, mode: Mode = .read, flags: Flags = .default) throws {
let fd = try Posix.open(file: path, oFlag: mode.posixFlags | O_CLOEXEC | flags.posixFlags, mode: flags.posixMode)
self.init(descriptor: fd)
}
}

View File

@ -253,7 +253,7 @@ public struct NonBlockingFileIO {
}
}
/// Open the file at `path` on a private thread pool which is separate from any `EventLoop` thread.
/// Open the file at `path` for reading on a private thread pool which is separate from any `EventLoop` thread.
///
/// This function will return (a future) of the `NIOFileHandle` associated with the file opened and a `FileRegion`
/// comprising of the whole file. The caller must close the returned `NIOFileHandle` when it's no longer needed.
@ -261,7 +261,7 @@ public struct NonBlockingFileIO {
/// - note: The reason this returns the `NIOFileHandle` and the `FileRegion` is that both the opening of a file as well as the querying of its size are blocking.
///
/// - parameters:
/// - path: The path of the file to be opened.
/// - path: The path of the file to be opened for reading.
/// - eventLoop: The `EventLoop` on which the returned `EventLoopFuture` will fire.
/// - returns: An `EventLoopFuture` containing the `NIOFileHandle` and the `FileRegion` comprising the whole file.
public func openFile(path: String, eventLoop: EventLoop) -> EventLoopFuture<(NIOFileHandle, FileRegion)> {
@ -277,4 +277,21 @@ public struct NonBlockingFileIO {
}
}
/// Open the file at `path` with specified access mode and POSIX flags on a private thread pool which is separate from any `EventLoop` thread.
///
/// This function will return (a future) of the `NIOFileHandle` associated with the file opened.
/// The caller must close the returned `NIOFileHandle` when it's no longer needed.
///
/// - parameters:
/// - path: The path of the file to be opened for writing.
/// - mode: File access mode.
/// - flags: Additional POSIX flags.
/// - eventLoop: The `EventLoop` on which the returned `EventLoopFuture` will fire.
/// - returns: An `EventLoopFuture` containing the `NIOFileHandle` and the `FileRegion` comprising the whole file.
public func openFile(path: String, mode: NIOFileHandle.Mode, flags: NIOFileHandle.Flags = .default, eventLoop: EventLoop) -> EventLoopFuture<NIOFileHandle> {
return self.threadPool.runIfActive(eventLoop: eventLoop) {
return try NIOFileHandle(path: path, mode: mode, flags: flags)
}
}
}