Beispiel #1
0
        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;
        }
Beispiel #2
0
 //This exists only to support IsolatedStorageFileStream.
 //Any changes to FileStream must include the corresponding changes in IsolatedStorage.
 internal FileStream() { 
     _fileName = null;
     _handleProtector = null;
 }
Beispiel #3
0
        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;
            }
        }
Beispiel #4
0
        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;          
        }