private SafeFileHandle OpenHandle(FileMode mode, FileShare share, FileOptions options) { // 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 _mode = mode; _options = options; if (_useAsyncIO) { _asyncState = new AsyncState(); } // Translate the arguments into arguments for an open call. Interop.Sys.OpenFlags openFlags = PreOpenConfigurationFromOptions(mode, _access, share, options); // If the file gets created a new, we'll select the permissions for it. Most Unix utilities by default use 666 (read and // write for all), so we do the same (even though this doesn't match Windows, where by default it's possible to write out // a file and then execute it). No matter what we choose, it'll be subject to the umask applied by the system, such that the // actual permissions will typically be less than what we select here. const Interop.Sys.Permissions OpenPermissions = Interop.Sys.Permissions.S_IRUSR | Interop.Sys.Permissions.S_IWUSR | Interop.Sys.Permissions.S_IRGRP | Interop.Sys.Permissions.S_IWGRP | Interop.Sys.Permissions.S_IROTH | Interop.Sys.Permissions.S_IWOTH; // Open the file and store the safe handle. return(SafeFileHandle.Open(_path !, openFlags, (int)OpenPermissions)); }
/// <summary>Initializes a stream from an already open file handle (file descriptor).</summary> private void InitFromHandle(SafeFileHandle handle, FileAccess access, bool useAsyncIO) { if (useAsyncIO) { _asyncState = new AsyncState(); } if (CanSeekCore(handle)) // use non-virtual CanSeekCore rather than CanSeek to avoid making virtual call during ctor { SeekCore(handle, 0, SeekOrigin.Current); } }
/// <summary>Initializes a stream from an already open file handle (file descriptor).</summary> private void InitFromHandle(SafeFileHandle handle, FileAccess access, bool useAsyncIO) { if (useAsyncIO) { _asyncState = new AsyncState(); } if (handle.CanSeek) { SeekCore(handle, 0, SeekOrigin.Current); } }
private void Init(FileMode mode, string originalPath, FileOptions options) { // 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 _options = options; if (_useAsyncIO) { _asyncState = new AsyncState(); } if (mode == FileMode.Append) { // Jump to the end of the file if opened as Append. _appendStart = SeekCore(_fileHandle, 0, SeekOrigin.End); } Debug.Assert(_fileHandle.IsAsync == _useAsyncIO); }
/// <summary>Initializes a stream for reading or writing a Unix file.</summary> /// <param name="mode">How the file should be opened.</param> /// <param name="share">What other access to the file should be allowed. This is currently ignored.</param> /// <param name="originalPath">The original path specified for the FileStream.</param> /// <param name="options">Options, passed via arguments as we have no guarantee that _options field was already set.</param> /// <param name="preallocationSize">passed to posix_fallocate</param> private void Init(FileMode mode, FileShare share, string originalPath, FileOptions options, long preallocationSize) { // 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 _mode = mode; _options = options; if (_useAsyncIO) { _asyncState = new AsyncState(); } _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. Interop.Sys.LockOperations lockOperation = (share == FileShare.None) ? Interop.Sys.LockOperations.LOCK_EX : Interop.Sys.LockOperations.LOCK_SH; if (Interop.Sys.FLock(_fileHandle, lockOperation | Interop.Sys.LockOperations.LOCK_NB) < 0) { // The only error we care about is EWOULDBLOCK, which indicates that the file is currently locked by someone // else and we would block trying to access it. Other errors, such as ENOTSUP (locking isn't supported) or // EACCES (the file system doesn't allow us to lock), will only hamper FileStream's usage without providing value, // given again that this is only advisory / best-effort. Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo(); if (errorInfo.Error == Interop.Error.EWOULDBLOCK) { throw Interop.GetExceptionForIoErrno(errorInfo, _path, isDirectory: false); } } // These provide hints around how the file will be accessed. Specifying both RandomAccess // and Sequential together doesn't make sense as they are two competing options on the same spectrum, // so if both are specified, we prefer RandomAccess (behavior on Windows is unspecified if both are provided). Interop.Sys.FileAdvice fadv = (options & FileOptions.RandomAccess) != 0 ? Interop.Sys.FileAdvice.POSIX_FADV_RANDOM : (options & FileOptions.SequentialScan) != 0 ? Interop.Sys.FileAdvice.POSIX_FADV_SEQUENTIAL : 0; if (fadv != 0) { CheckFileCall(Interop.Sys.PosixFAdvise(_fileHandle, 0, 0, fadv), ignoreNotSupported: true); // just a hint. } if (mode == FileMode.Append) { // Jump to the end of the file if opened as Append. _appendStart = SeekCore(_fileHandle, 0, SeekOrigin.End); } else if (mode == FileMode.Create || mode == FileMode.Truncate) { // Truncate the file now if the file mode requires it. This ensures that the file only will be truncated // if opened successfully. if (Interop.Sys.FTruncate(_fileHandle, 0) < 0) { Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo(); if (errorInfo.Error != Interop.Error.EBADF && errorInfo.Error != Interop.Error.EINVAL) { // We know the file descriptor is valid and we know the size argument to FTruncate is correct, // so if EBADF or EINVAL is returned, it means we're dealing with a special file that can't be // truncated. Ignore the error in such cases; in all others, throw. throw Interop.GetExceptionForIoErrno(errorInfo, _path, isDirectory: false); } } } // If preallocationSize has been provided for a creatable and writeable file if (FileStreamHelpers.ShouldPreallocate(preallocationSize, _access, mode)) { int fallocateResult = Interop.Sys.PosixFAllocate(_fileHandle, 0, preallocationSize); if (fallocateResult != 0) { _fileHandle.Dispose(); Interop.Sys.Unlink(_path !); // remove the file to mimic Windows behaviour (atomic operation) if (fallocateResult == -1) { throw new IOException(SR.Format(SR.IO_DiskFull_Path_AllocationSize, _path, preallocationSize)); } Debug.Assert(fallocateResult == -2); throw new IOException(SR.Format(SR.IO_FileTooLarge_Path_AllocationSize, _path, preallocationSize)); } } }
public bool TryRemove(uint opaque, [NotNullWhen(true)] out AsyncState?state) => _statesInFlight.TryRemove(opaque, out state);