public FileStream(IntPtr handle, FileAccess access, bool ownsHandle, int bufferSize, bool isAsync) { if (access < FileAccess.Read || access > FileAccess.ReadWrite) throw new ArgumentOutOfRangeException("access", Environment.GetResourceString("ArgumentOutOfRange_Enum")); if (bufferSize <= 0) throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum")); if (handle==Win32Native.INVALID_HANDLE_VALUE) throw new ArgumentException(Environment.GetResourceString("Arg_InvalidHandle"), "handle"); int handleType = Win32Native.GetFileType(handle) & 0x7FFF; _handleProtector = new __FileStreamHandleProtector(handle, ownsHandle); _isAsync = isAsync && _canUseAsync; // On Win9x, just do the right thing. _canRead = 0 != (access & FileAccess.Read); _canWrite = 0 != (access & FileAccess.Write); _canSeek = handleType == Win32Native.FILE_TYPE_DISK; _bufferSize = bufferSize; _readPos = 0; _readLen = 0; _writePos = 0; _fileName = null; _isPipe = handleType == Win32Native.FILE_TYPE_PIPE; if (handleType != Win32Native.FILE_TYPE_PIPE) VerifyHandleIsSync(); if (_canSeek) { _pos = SeekCore(0, SeekOrigin.Current); if (_pos > Length) { _pos = SeekCore(0, SeekOrigin.End); } } else _pos = 0; }
//This exists only to support IsolatedStorageFileStream. //Any changes to FileStream must include the corresponding changes in IsolatedStorage. internal FileStream() { _fileName = null; _handleProtector = null; }
internal FileStream(String path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync, String msgPath, bool bFromProxy) { // Note: msgPath must be safe to hand back to untrusted code. _fileName = msgPath; // To handle odd cases of finalizing partially constructed objects. if (path == null) throw new ArgumentNullException("path", Environment.GetResourceString("ArgumentNull_Path")); if (path.Length == 0) throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath")); if (mode < FileMode.CreateNew || mode > FileMode.Append || access < FileAccess.Read || access > FileAccess.ReadWrite || share < FileShare.None || share > FileShare.ReadWrite) { String badArg = "mode"; if (access < FileAccess.Read || access > FileAccess.ReadWrite) badArg = "access"; if (share < FileShare.None || share > FileShare.ReadWrite) badArg = "share"; throw new ArgumentOutOfRangeException(badArg, Environment.GetResourceString("ArgumentOutOfRange_Enum")); } if (bufferSize <= 0) throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum")); int fAccess = access == FileAccess.Read? GENERIC_READ: access == FileAccess.Write? GENERIC_WRITE: GENERIC_READ | GENERIC_WRITE; // Get absolute path - Security needs this to prevent something // like trying to create a file in c:\tmp with the name // "..\WinNT\System32\ntoskrnl.exe". Store it for user convenience. String filePath = Path.GetFullPathInternal(path); _fileName = filePath; // Build up security permissions required, as well as validate we // have a sensible set of parameters. IE, creating a brand new file // for reading doesn't make much sense. FileIOPermissionAccess secAccess = FileIOPermissionAccess.NoAccess; if ((access & FileAccess.Read) != 0) { if (mode==FileMode.Append) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidAppendMode")); else secAccess = secAccess | FileIOPermissionAccess.Read; } // I can't think of any combos of FileMode we should disallow if we // don't have read access. Writing would pretty much always be valid // in those cases. if ((access & FileAccess.Write) != 0) { if (mode==FileMode.Append) secAccess = secAccess | FileIOPermissionAccess.Append; else secAccess = secAccess | FileIOPermissionAccess.Write; } else { // No write access if (mode==FileMode.Truncate || mode==FileMode.CreateNew || mode==FileMode.Create || mode==FileMode.Append) throw new ArgumentException(String.Format(Environment.GetResourceString("Argument_InvalidFileMode&AccessCombo"), mode, access)); } new FileIOPermission(secAccess, new String[] { filePath }, false, false).Demand(); bool seekToEnd = (mode==FileMode.Append); // Must use a valid Win32 constant here... if (mode == FileMode.Append) mode = FileMode.OpenOrCreate; // By default, FileStream-provided handles are not inheritable by // child processes, but with FileShare.Inheritable you can redirect // stdout from a child process to a log file from your parent, etc. Win32Native.SECURITY_ATTRIBUTES secAttrs = null; if ((share & FileShare.Inheritable) != 0) { secAttrs = new Win32Native.SECURITY_ATTRIBUTES(); secAttrs.nLength = (int)Marshal.SizeOf(secAttrs); secAttrs.bInheritHandle = 1; share &= ~FileShare.Inheritable; } // Do the right thing for whatever platform we're on. This way, // someone can easily write code that opens a file asynchronously // no matter what their platform is. IntPtr handle; if (_canUseAsync && useAsync) { handle = Win32Native.CreateFile(filePath, fAccess, share, secAttrs, mode, FILE_FLAG_OVERLAPPED, Win32Native.NULL); _isAsync = true; } else { handle = Win32Native.CreateFile(filePath, fAccess, share, secAttrs, mode, FILE_ATTRIBUTE_NORMAL, Win32Native.NULL); _isAsync = false; } if (handle != Win32Native.INVALID_HANDLE_VALUE) { _handleProtector = new __FileStreamHandleProtector(handle, true); } else { // Return a meaningful error, using the RELATIVE path to // the file to avoid returning extra information to the caller // unless they have path discovery permission, in which case // the full path is fine & useful. // NT5 oddity - when trying to open "C:\" as a FileStream, // we usually get ERROR_PATH_NOT_FOUND from the OS. We should // probably be consistent w/ every other directory. int hr = Marshal.GetLastWin32Error(); if (hr==__Error.ERROR_PATH_NOT_FOUND && filePath.Equals(Directory.InternalGetDirectoryRoot(filePath))) hr = __Error.ERROR_ACCESS_DENIED; // We need to give an exception, and preferably it would include // the fully qualified path name. Do security check here. If // we fail, give back the msgPath, which should not reveal much. bool canGiveFullPath = false; if (!bFromProxy) { try { new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { _fileName }, false, false ).Demand(); canGiveFullPath = true; } catch(SecurityException) {} } if (canGiveFullPath) __Error.WinIOError(hr, _fileName); else __Error.WinIOError(hr, msgPath); } // Disallow access to all non-file devices from the FileStream // constructors that take a String. Everyone else can call // CreateFile themselves then use the constructor that takes an // IntPtr. Disallows "con:", "com1:", "lpt1:", etc. int fileType = Win32Native.GetFileType(handle); if (fileType != Win32Native.FILE_TYPE_DISK) { _handleProtector.Close(); throw new NotSupportedException(Environment.GetResourceString("NotSupported_FileStreamOnNonFiles")); } _canRead = (access & FileAccess.Read) != 0; _canWrite = (access & FileAccess.Write) != 0; _canSeek = true; _isPipe = false; _pos = 0; _bufferSize = bufferSize; _readPos = 0; _readLen = 0; _writePos = 0; // For Append mode... if (seekToEnd) { _appendStart = SeekCore(0, SeekOrigin.End); } else { _appendStart = -1; } }
internal unsafe int WriteFileNative(__HandleProtector hp, byte[] bytes, int offset, int count, NativeOverlapped* overlapped, out int hr) { BCLDebug.Assert(offset >= 0, "offset >= 0"); BCLDebug.Assert(count >= 0, "count >= 0"); BCLDebug.Assert(bytes != null, "bytes != null"); // Don't corrupt memory when multiple threads are erroneously writing // to this stream simultaneously. (Note that the OS is reading from // the array we pass to WriteFile, but if we read beyond the end and // that memory isn't allocated, we could get an AV.) if (bytes.Length - offset < count) throw new IndexOutOfRangeException(Environment.GetResourceString("IndexOutOfRange_IORaceCondition")); // You can't use the fixed statement on an array of length 0. if (bytes.Length==0) { hr = 0; return 0; } int numBytesWritten = 0; int r = 0; bool incremented = false; try { if (hp.TryAddRef(ref incremented)) { fixed(byte* p = bytes) { r = WriteFile(hp.Handle, p + offset, count, out numBytesWritten, overlapped); } } else hr = Win32Native.ERROR_INVALID_HANDLE; // Handle was closed. } finally { if (incremented) hp.Release(); } if (r==0) { hr = Marshal.GetLastWin32Error(); // Note: we should never silently swallow an error here without some // extra work. We must make sure that BeginWriteCore won't return an // IAsyncResult that will cause EndWrite to block, since the OS won't // call AsyncFSCallback for us. if (hr==ERROR_NO_DATA) { // This handle was a pipe, and the pipe is being closed on the // other side. Let the caller handle this, since BeginWriteCore // & WriteCore need to do different things. return -1; } // For invalid handles, detect the error and mark our handle // as closed to give slightly better error messages. Also // help ensure we avoid handle recycling bugs. if (hr == Win32Native.ERROR_INVALID_HANDLE) _handleProtector.ForciblyMarkAsClosed(); return -1; } else hr = 0; return numBytesWritten; }