Exemplo n.º 1
0
        private static unsafe void Preallocate(string fullPath, long preallocationSize, SafeFileHandle fileHandle)
        {
            // preallocationSize must be ignored for non-seekable files, unsupported file systems
            // and other failures other than ERROR_DISK_FULL and ERROR_FILE_TOO_LARGE
            if (!FileStreamHelpers.TrySetFileLength(fileHandle, preallocationSize, out int errorCode) &&
                errorCode == Interop.Errors.ERROR_DISK_FULL || errorCode == Interop.Errors.ERROR_FILE_TOO_LARGE)
            {
                // Windows does not modify the file size if the request can't be satisfied in atomic way.
                // posix_fallocate (Unix) implementation might consume all available disk space and fail after that.
                // To ensure that the behaviour is the same for every OS (no incomplete or empty file), we close the handle and delete the file.
                fileHandle.Dispose();
                Interop.Kernel32.DeleteFile(fullPath);

                throw new IOException(SR.Format(errorCode == Interop.Errors.ERROR_DISK_FULL ? SR.IO_DiskFull_Path_AllocationSize : SR.IO_FileTooLarge_Path_AllocationSize, fullPath, preallocationSize));
            }
        }
Exemplo n.º 2
0
        internal static unsafe SafeFileHandle Open(string fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, long preallocationSize)
        {
            using (DisableMediaInsertionPrompt.Create())
            {
                // we don't use NtCreateFile as there is no public and reliable way
                // of converting DOS to NT file paths (RtlDosPathNameToRelativeNtPathName_U_WithStatus is not documented)
                SafeFileHandle fileHandle = CreateFile(fullPath, mode, access, share, options);

                if (FileStreamHelpers.ShouldPreallocate(preallocationSize, access, mode))
                {
                    Preallocate(fullPath, preallocationSize, fileHandle);
                }

                fileHandle.InitThreadPoolBindingIfNeeded();

                return(fileHandle);
            }
        }
Exemplo n.º 3
0
        private void Init(string path, FileMode mode, FileAccess access, FileShare share, FileOptions options, long preallocationSize)
        {
            IsAsync = (options & FileOptions.Asynchronous) != 0;

            // 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(this, 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)
            {
                FileStreamHelpers.CheckFileCall(Interop.Sys.PosixFAdvise(this, 0, 0, fadv), path,
                                                ignoreNotSupported: true); // just a hint.
            }

            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(this, 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(this, 0, preallocationSize);
                if (fallocateResult != 0)
                {
                    Dispose();
                    Interop.Sys.Unlink(path !); // remove the file to mimic Windows behaviour (atomic operation)

                    Debug.Assert(fallocateResult == -1 || fallocateResult == -2);
                    throw new IOException(SR.Format(
                                              fallocateResult == -1 ? SR.IO_DiskFull_Path_AllocationSize : SR.IO_FileTooLarge_Path_AllocationSize,
                                              path,
                                              preallocationSize));
                }
            }
        }