Esempio n. 1
0
        /// <summary>
        /// Ensure we have the data.
        /// Does not throw for nonexistence.
        /// </summary>
        private void EnsurePopulated()
        {
            if (_dataIsGood == null)
            {
                _dataIsGood = false;
                _filename   = FileUtilities.AttemptToShortenPath(_filename); // This is no-op unless the path actually is too long
                _data       = new NativeMethodsShared.WIN32_FILE_ATTRIBUTE_DATA();

                // THIS COPIED FROM THE BCL:
                //
                // For floppy drives, normally the OS will pop up a dialog saying
                // there is no disk in drive A:, please insert one.  We don't want that.
                // SetErrorMode will let us disable this, but we should set the error
                // mode back, since this may have wide-ranging effects.
                int oldMode = NativeMethodsShared.SetErrorMode(1 /* ErrorModes.SEM_FAILCRITICALERRORS */);

                bool success = false;
                _fileOrDirectoryExists = true;

                try
                {
                    success = NativeMethodsShared.GetFileAttributesEx(_filename, 0, ref _data);

                    if (!success)
                    {
                        int error = Marshal.GetLastWin32Error();

                        // File not found is the most common case, for example we're copying
                        // somewhere without a file yet. Don't do something like FileInfo.Exists to
                        // get a nice error, or we're doing IO again! Don't even format our own string:
                        // that turns out to be unacceptably expensive here as well. Set a flag for this particular case.
                        //
                        // Also, when not under debugger (!) it will give error == 3 for path too long. Make that consistently throw instead.
                        if ((error == 2 /* ERROR_FILE_NOT_FOUND */ || error == 3 /* ERROR_PATH_NOT_FOUND */) &&
                            _filename.Length <= NativeMethodsShared.MAX_PATH)
                        {
                            _fileOrDirectoryExists = false;
                            return;
                        }

                        // Throw nice message as far as we can. At this point IO is OK.
                        var length = new FileInfo(_filename).Length;

                        // Otherwise this will give at least something
                        NativeMethodsShared.ThrowExceptionForErrorCode(error);
                        ErrorUtilities.ThrowInternalErrorUnreachable();
                    }
                }
                finally
                {
                    NativeMethodsShared.SetErrorMode(oldMode);
                }

                _dataIsGood = true;
            }
        }
Esempio n. 2
0
            /// <summary>
            /// Constructor gets the data for the filename.
            /// On Win32 it uses native means. Otherwise,
            /// uses standard .NET FileInfo/DirInfo
            /// </summary>
            public FileDirInfo(string filename)
            {
                Exists = false;

                // If file/directory does not exist, return 12 midnight 1/1/1601.
                LastWriteTimeUtc = new DateTime(1601, 1, 1);

                _filename = FileUtilities.AttemptToShortenPath(filename); // This is no-op unless the path actually is too long

                int oldMode = 0;

                if (NativeMethodsShared.IsWindows)
                {
                    // THIS COPIED FROM THE BCL:
                    //
                    // For floppy drives, normally the OS will pop up a dialog saying
                    // there is no disk in drive A:, please insert one.  We don't want that.
                    // SetErrorMode will let us disable this, but we should set the error
                    // mode back, since this may have wide-ranging effects.
                    oldMode = NativeMethodsShared.SetErrorMode(1 /* ErrorModes.SEM_FAILCRITICALERRORS */);
                }

                try
                {
                    if (NativeMethodsShared.IsWindows)
                    {
                        var  data    = new NativeMethodsShared.WIN32_FILE_ATTRIBUTE_DATA();
                        bool success = NativeMethodsShared.GetFileAttributesEx(_filename, 0, ref data);

                        if (!success)
                        {
                            int error = Marshal.GetLastWin32Error();

                            // File not found is the most common case, for example we're copying
                            // somewhere without a file yet. Don't do something like FileInfo.Exists to
                            // get a nice error, or we're doing IO again! Don't even format our own string:
                            // that turns out to be unacceptably expensive here as well. Set a flag for this particular case.
                            //
                            // Also, when not under debugger (!) it will give error == 3 for path too long. Make that consistently throw instead.
                            if ((error == 2 /* ERROR_FILE_NOT_FOUND */ || error == 3 /* ERROR_PATH_NOT_FOUND */) &&
                                _filename.Length <= NativeMethodsShared.MAX_PATH)
                            {
                                Exists = false;
                                return;
                            }

                            // Throw nice message as far as we can. At this point IO is OK.
                            Length = new FileInfo(_filename).Length;

                            // Otherwise this will give at least something
                            NativeMethodsShared.ThrowExceptionForErrorCode(error);
                            ErrorUtilities.ThrowInternalErrorUnreachable();
                        }

                        Exists      = true;
                        IsDirectory = (data.fileAttributes & NativeMethodsShared.FILE_ATTRIBUTE_DIRECTORY) != 0;
                        IsReadOnly  = !IsDirectory &&
                                      (data.fileAttributes & NativeMethodsShared.FILE_ATTRIBUTE_READONLY) != 0;
                        LastWriteTimeUtc =
                            DateTime.FromFileTimeUtc(((long)data.ftLastWriteTimeHigh << 0x20) | data.ftLastWriteTimeLow);
                        Length = IsDirectory ? 0 : (((long)data.fileSizeHigh << 0x20) | data.fileSizeLow);
                    }
                    else
                    {
                        // Check if we have a directory
                        IsDirectory = Directory.Exists(_filename);
                        Exists      = IsDirectory;

                        // If not exists, see if this is a file
                        if (!Exists)
                        {
                            Exists = File.Exists(_filename);
                        }

                        if (IsDirectory)
                        {
                            // Use DirectoryInfo to get the last write date
                            var directoryInfo = new DirectoryInfo(_filename);
                            IsReadOnly       = false;
                            LastWriteTimeUtc = directoryInfo.LastWriteTimeUtc;
                        }
                        else if (Exists)
                        {
                            // Use FileInfo to get readonly and last write date
                            var fileInfo = new FileInfo(_filename);
                            IsReadOnly       = fileInfo.IsReadOnly;
                            LastWriteTimeUtc = fileInfo.LastWriteTimeUtc;
                            Length           = fileInfo.Length;
                        }
                    }
                }
                catch (Exception ex)
                {
                    // Save the exception thrown and assume the file does not exist
                    _exceptionThrown = ex;
                    Exists           = false;
                }
                finally
                {
                    // Reset the error mode on Windows
                    if (NativeMethodsShared.IsWindows)
                    {
                        NativeMethodsShared.SetErrorMode(oldMode);
                    }
                }
            }