/// <summary>Initializes a stream for reading or writing a Unix file.</summary> /// <param name="path">The path to the file.</param> /// <param name="mode">How the file should be opened.</param> /// <param name="access">Whether the file will be read, written, or both.</param> /// <param name="share">What other access to the file should be allowed. This is currently ignored.</param> /// <param name="bufferSize">The size of the buffer to use when buffering.</param> /// <param name="options">Additional options for working with the file.</param> internal UnixFileStream(String path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, FileStream parent) : base(parent) { // FileStream performs most of the general argument validation. We can assume here that the arguments // are all checked and consistent (e.g. non-null-or-empty path; valid enums in mode, access, share, and options; etc.) // Store the arguments _path = path; _access = access; _mode = mode; _options = options; _bufferLength = bufferSize; _useAsyncIO = (options & FileOptions.Asynchronous) != 0; // Translate the arguments into arguments for an open call Interop.libc.OpenFlags openFlags = PreOpenConfigurationFromOptions(mode, access, options); // FileShare currently ignored Interop.libc.Permissions openPermissions = Interop.libc.Permissions.S_IRWXU; // creator has read/write/execute permissions; no permissions for anyone else // Open the file and store the safe handle. Subsequent code in this method expects the safe handle to be initialized. _fileHandle = SafeFileHandle.Open(path, openFlags, (int)openPermissions); _fileHandle.IsAsync = _useAsyncIO; // Lock the file if requested via FileShare. This is only advisory locking. FileShare.None implies an exclusive // lock on the file and all other modes use a shared lock. While this is not as granular as Windows, not mandatory, // and not atomic with file opening, it's better than nothing. try { Interop.libc.LockOperations lockOperation = (share == FileShare.None) ? Interop.libc.LockOperations.LOCK_EX : Interop.libc.LockOperations.LOCK_SH; SysCall <Interop.libc.LockOperations, int>((fd, op, _) => Interop.libc.flock(fd, op), lockOperation | Interop.libc.LockOperations.LOCK_NB); } catch { _fileHandle.Dispose(); throw; } // Support additional options after the file has been opened. // These provide hints around how the file will be accessed. Interop.libc.Advice fadv = _options == FileOptions.RandomAccess ? Interop.libc.Advice.POSIX_FADV_RANDOM : _options == FileOptions.SequentialScan ? Interop.libc.Advice.POSIX_FADV_SEQUENTIAL : 0; if (fadv != 0) { SysCall <Interop.libc.Advice, int>((fd, advice, _) => Interop.libc.posix_fadvise(fd, 0, 0, advice), fadv); } // Jump to the end of the file if opened as Append. if (_mode == FileMode.Append) { _appendStart = SeekCore(0, SeekOrigin.End); } }
/// <summary>Performs additional configuration of the opened stream based on provided options.</summary> partial void PostOpenConfigureStreamFromOptions() { // Support additional options after the file has been opened. // These provide hints around how the file will be accessed. Interop.libc.Advice fadv = _options == FileOptions.RandomAccess ? Interop.libc.Advice.POSIX_FADV_RANDOM : _options == FileOptions.SequentialScan ? Interop.libc.Advice.POSIX_FADV_SEQUENTIAL : 0; if (fadv != 0) { SysCall <Interop.libc.Advice, int>((fd, advice, _) => Interop.libc.posix_fadvise(fd, 0, 0, advice), fadv); } }