Example #1
0
 public void BadChars()
 {
     Assert.Throws<ArgumentException>(() =>
     {
         var state = new FileState("|");
         var time = state.LastWriteTime;
     }
    );
 }
Example #2
0
        /// <summary>
        /// Cached implementation. Given a path, crack it open and retrieve runtimeversion for the assembly.
        /// </summary>
        /// <param name="path">Path to the assembly.</param>
        private string GetRuntimeVersion(string path)
        {
            FileState fileState = GetFileState(path);

            if (String.IsNullOrEmpty(fileState.RuntimeVersion))
            {
                fileState.RuntimeVersion = getAssemblyRuntimeVersion(path);
                isDirty = true;
            }

            return(fileState.RuntimeVersion);
        }
Example #3
0
        /// <summary>
        /// Cached implementation of GetAssemblyName.
        /// </summary>
        /// <param name="path">The path to the file</param>
        /// <returns>The assembly name.</returns>
        private AssemblyNameExtension GetAssemblyName(string path)
        {
            // If the assembly is in an FX folder and its a well-known assembly
            // then we can short-circuit the File IO involved with GetAssemblyName()
            if (redistList != null)
            {
                string extension = Path.GetExtension(path);
                if (String.Compare(extension, ".dll", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    AssemblyEntry[] assemblyNames = redistList.FindAssemblyNameFromSimpleName
                                                    (
                        Path.GetFileNameWithoutExtension(path)
                                                    );

                    for (int i = 0; i < assemblyNames.Length; ++i)
                    {
                        string filename           = Path.GetFileName(path);
                        string pathFromRedistList = Path.Combine(assemblyNames[i].FrameworkDirectory, filename);

                        if (String.Equals(path, pathFromRedistList, StringComparison.OrdinalIgnoreCase))
                        {
                            return(new AssemblyNameExtension(assemblyNames[i].FullName));
                        }
                    }
                }
            }


            // Not a well-known FX assembly so now check the cache.
            FileState fileState = GetFileState(path);

            if (fileState.Assembly == null)
            {
                fileState.Assembly = getAssemblyName(path);

                // Certain assemblies, like mscorlib may not have metadata.
                // Avoid continuously calling getAssemblyName on these files by
                // recording these as having an empty name.
                if (fileState.Assembly == null)
                {
                    fileState.Assembly = AssemblyNameExtension.UnnamedAssembly;
                }
                isDirty = true;
            }

            if (fileState.Assembly.IsUnnamedAssembly)
            {
                return(null);
            }

            return(fileState.Assembly);
        }
Example #4
0
        private FileState GetFileState(string path)
        {
            FileState state  = null;
            FileState state2 = (FileState)processWideFileStateCache[path];
            FileState state3 = (FileState)this.instanceLocalFileStateCache[path];

            if ((state2 == null) && (state3 != null))
            {
                state = state3;
                processWideFileStateCache[path] = state3;
            }
            else if ((state2 != null) && (state3 == null))
            {
                state = state2;
                this.instanceLocalFileStateCache[path] = state2;
            }
            else if ((state2 != null) && (state3 != null))
            {
                if (state2.LastModified > state3.LastModified)
                {
                    state = state2;
                    this.instanceLocalFileStateCache[path] = state2;
                }
                else
                {
                    state = state3;
                    processWideFileStateCache[path] = state3;
                }
            }
            if (state == null)
            {
                state = new FileState {
                    LastModified = this.getLastWriteTime(path)
                };
                this.instanceLocalFileStateCache[path] = state;
                processWideFileStateCache[path]        = state;
                this.isDirty = true;
                return(state);
            }
            if (this.getLastWriteTime(path) != state.LastModified)
            {
                state = new FileState {
                    LastModified = this.getLastWriteTime(path)
                };
                this.instanceLocalFileStateCache[path] = state;
                processWideFileStateCache[path]        = state;
                this.isDirty = true;
            }
            return(state);
        }
Example #5
0
        /// <summary>
        /// Copy source to destination, unless SkipUnchangedFiles is true and they are equivalent.
        /// </summary>
        /// <returns>True if the file was copied or, on SkipUnchangedFiles, the file was equivalent.</returns>
        private bool DoCopyIfNecessary(FileState sourceFileState, FileState destinationFileState, CopyFileWithState copyFile)
        {
            bool success = true;

            try
            {
                if (SkipUnchangedFiles && IsMatchingSizeAndTimeStamp(sourceFileState, destinationFileState))
                {
                    // If we got here, then the file's time and size match AND
                    // the user set the SkipUnchangedFiles flag which means we
                    // should skip matching files.
                    Log.LogMessageFromResources(
                        MessageImportance.Low,
                        "Copy.DidNotCopyBecauseOfFileMatch",
                        sourceFileState.Name,
                        destinationFileState.Name,
                        "SkipUnchangedFiles",
                        "true"
                        );
                }
                // We only do the cheap check for identicalness here, we try the more expensive check
                // of comparing the fullpaths of source and destination to see if they are identical,
                // in the exception handler lower down.
                else if (0 != String.Compare(
                             sourceFileState.Name,
                             destinationFileState.Name,
                             StringComparison.OrdinalIgnoreCase))
                {
                    success = DoCopyWithRetries(sourceFileState, destinationFileState, copyFile);
                }
            }
            catch (OperationCanceledException)
            {
                success = false;
            }
            catch (PathTooLongException e)
            {
                Log.LogErrorWithCodeFromResources("Copy.Error", sourceFileState.Name, destinationFileState.Name, e.Message);
                success = false;
            }
            catch (Exception e) when(ExceptionHandling.IsIoRelatedException(e))
            {
                Log.LogErrorWithCodeFromResources("Copy.Error", sourceFileState.Name, destinationFileState.Name, e.Message);
                success = false;
            }

            return(success);
        }
Example #6
0
        /// <summary>
        /// Ensure the read-only attribute on the specified file is off, so
        /// the file is writeable.
        /// </summary>
        private void MakeFileWriteable(FileState file, bool logActivity)
        {
            if (file.FileExists)
            {
                if (file.IsReadOnly)
                {
                    if (logActivity)
                    {
                        Log.LogMessageFromResources(MessageImportance.Low, "Copy.RemovingReadOnlyAttribute", file.Name);
                    }

                    File.SetAttributes(file.Name, FileAttributes.Normal);
                    file.Reset();
                }
            }
        }
Example #7
0
        private FileState GetFileStateFromProcessWideCache(string path, FileState template)
        {
            // When reading from the process-wide cache, we always check to see if our data
            // is up-to-date to avoid getting stale data from a previous build.
            DateTime lastModified = getLastWriteTime(path);

            // Has another build seen this file before?
            FileState state;

            if (!s_processWideFileStateCache.TryGetValue(path, out state) || state.LastModified != lastModified)
            {   // We've never seen it before, or we're out of date
                state = CreateFileState(lastModified, template);
                s_processWideFileStateCache[path] = state;
            }

            return(state);
        }
Example #8
0
        public void Exists()
        {
            string file = null;

            try
            {
                file = FileUtilities.GetTemporaryFile();
                FileInfo info = new FileInfo(file);
                FileState state = new FileState(file);

                Assert.Equal(info.Exists, state.FileExists);
            }
            finally
            {
                File.Delete(file);
            }
        }
Example #9
0
        public void Name()
        {
            string file = null;

            try
            {
                file = FileUtilities.GetTemporaryFile();
                FileInfo info = new FileInfo(file);
                FileState state = new FileState(file);

                Assert.AreEqual(info.FullName, state.Name);
            }
            finally
            {
                File.Delete(file);
            }
        }
Example #10
0
        private FileState GetFileState(string path)
        {
            // Looking up an assembly to get its metadata can be expensive for projects that reference large amounts
            // of assemblies. To avoid that expense, we remember and serialize this information betweeen runs in
            // XXXResolveAssemblyReferencesInput.cache files in the intermediate directory and also store it in an
            // process-wide cache to share between successive builds.
            //
            // To determine if this information is up-to-date, we use the last modified date of the assembly, however,
            // as calls to GetLastWriteTime can add up over hundreds and hundreds of files, we only check for
            // invalidation once per assembly per ResolveAssemblyReference session.

            FileState state = (FileState)upToDateLocalFileStateCache[path];

            if (state == null)
            {   // We haven't seen this file this ResolveAssemblyReference session
                state = ComputeFileStateFromCachesAndDisk(path);
                upToDateLocalFileStateCache[path] = state;
            }

            return(state);
        }
Example #11
0
        /// <summary>
        /// Method compares two files and returns true if their size and timestamp are identical.
        /// </summary>
        /// <param name="sourceFile">The source file</param>
        /// <param name="destinationFile">The destination file</param>
        private static bool IsMatchingSizeAndTimeStamp
        (
            FileState sourceFile,
            FileState destinationFile
        )
        {
            // If the destination doesn't exist, then it is not a matching file.
            if (!destinationFile.FileExists)
            {
                return(false);
            }

            if (sourceFile.LastWriteTimeUtcFast != destinationFile.LastWriteTimeUtcFast)
            {
                return(false);
            }

            if (sourceFile.Length != destinationFile.Length)
            {
                return(false);
            }

            return(true);
        }
Example #12
0
        /// <summary>
        /// Ensure the read-only attribute on the specified file is off, so
        /// the file is writeable.
        /// </summary>
        private void MakeFileWriteable(FileState file, bool logActivity)
        {
            if (file.FileExists)
            {
                if (file.IsReadOnly)
                {
                    if (logActivity)
                    {
                        Log.LogMessageFromResources(MessageImportance.Low, "Copy.RemovingReadOnlyAttribute", file.Name);
                    }

                    File.SetAttributes(file.Name, FileAttributes.Normal);
                    file.Reset();
                }
            }
        }
Example #13
0
        private void TryCopyViaLink(string linkComment, MessageImportance messageImportance, FileState sourceFileState, FileState destinationFileState, ref bool destinationFileExists, ref bool linkCreated, Func<string, string, bool> createLink)
        {
            // Do not log a fake command line as well, as it's superfluous, and also potentially expensive
            Log.LogMessageFromResources(MessageImportance.Normal, linkComment, sourceFileState.Name, destinationFileState.Name);

            if (!_overwriteReadOnlyFiles)
            {
                destinationFileExists = destinationFileState.FileExists;
            }

            // CreateHardLink and CreateSymbolicLink cannot overwrite an existing file or link
            // so we need to delete the existing entry before we create the hard or symbolic link.
            // We need to do a best-effort check to see if the files are the same
            // if they are the same then we won't delete, just in case they refer to the same
            // physical file on disk.
            // Since we'll fall back to a copy (below) this will fail and issue a correct
            // message in the case that the source and destination are in fact the same file.
            if (destinationFileExists && !IsMatchingSizeAndTimeStamp(sourceFileState, destinationFileState))
            {
                FileUtilities.DeleteNoThrow(destinationFileState.Name);
            }
                        
            linkCreated = createLink(sourceFileState.Name, destinationFileState.Name);

            if (!linkCreated)
            {
                int errorCode = Marshal.GetHRForLastWin32Error();
                Exception linkException = Marshal.GetExceptionForHR(errorCode);
                // This is only a message since we don't want warnings when copying to network shares etc.
                Log.LogMessageFromResources(messageImportance, "Copy.RetryingAsFileCopy", sourceFileState.Name, destinationFileState.Name, linkException.Message);
            }
        }
Example #14
0
        public void DoesNotExistLength()
        {
            string file = Guid.NewGuid().ToString("N"); // presumably doesn't exist

            Helpers.VerifyAssertThrowsSameWay(delegate () { var x = new FileInfo(file).Length; }, delegate () { var x = new FileState(file).Length; });
        }
Example #15
0
        public void DoesNotExistIsDirectory()
        {
            Assert.Throws<FileNotFoundException>(() =>
            {
                string file = Guid.NewGuid().ToString("N"); // presumably doesn't exist

                var x = new FileState(file).IsDirectory;
            }
           );
        }
Example #16
0
        public void LastWriteTimeUtcReset()
        {
            string file = null;

            try
            {
                file = FileUtilities.GetTemporaryFile();
                FileInfo info = new FileInfo(file);
                FileState state = new FileState(file);

                Assert.Equal(info.LastWriteTimeUtc, state.LastWriteTimeUtcFast);

                var time = new DateTime(2111, 1, 1);
                info.LastWriteTime = time;

                Assert.NotEqual(time.ToUniversalTime(), state.LastWriteTimeUtcFast);
                state.Reset();
                Assert.Equal(time.ToUniversalTime(), state.LastWriteTimeUtcFast);
            }
            finally
            {
                File.Delete(file);
            }
        }
Example #17
0
        public void ReadOnlyReset()
        {
            string file = null;

            try
            {
                file = FileUtilities.GetTemporaryFile();
                FileInfo info = new FileInfo(file);
                FileState state = new FileState(file);

                Assert.Equal(info.IsReadOnly, state.IsReadOnly);
                info.IsReadOnly = !info.IsReadOnly;
                state.Reset();
                Assert.Equal(true, state.IsReadOnly);
            }
            finally
            {
                (new FileInfo(file)).IsReadOnly = false;
                File.Delete(file);
            }
        }
Example #18
0
        public void AccessDenied()
        {
            string locked = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "system32\\notepad.exe");

            FileInfo info = new FileInfo(locked);
            FileState state = new FileState(locked);

            Assert.Equal(info.Exists, state.FileExists);

            if (!info.Exists)
            {
                // meh, somewhere else
                return;
            }

            Assert.Equal(info.Length, state.Length);
            Assert.Equal(info.LastWriteTime, state.LastWriteTime);
            Assert.Equal(info.LastWriteTimeUtc, state.LastWriteTimeUtcFast);
        }
Example #19
0
        public void ReadOnly()
        {
            string file = null;

            try
            {
                file = FileUtilities.GetTemporaryFile();
                FileInfo info = new FileInfo(file);
                FileState state = new FileState(file);

                Assert.Equal(info.IsReadOnly, state.IsReadOnly);
            }
            finally
            {
                File.Delete(file);
            }
        }
Example #20
0
 /*
 * Method:   CopyFile
 *
 * Don't really copy the file, just count how many times this was called.
 */
 internal bool? CopyFile(FileState source, FileState destination)
 {
     ++copyCount;
     return true;
 }
Example #21
0
        public void LastWriteTimeUtc()
        {
            string file = null;

            try
            {
                file = FileUtilities.GetTemporaryFile();
                FileInfo info = new FileInfo(file);
                FileState state = new FileState(file);

                Assert.Equal(info.LastWriteTimeUtc, state.LastWriteTimeUtcFast);
            }
            finally
            {
                File.Delete(file);
            }
        }
Example #22
0
 public void BadChars()
 {
     var state = new FileState("|");
     var time = state.LastWriteTime;
 }
Example #23
0
        public void DoesNotExistIsDirectory()
        {
            string file = Guid.NewGuid().ToString("N"); // presumably doesn't exist

            var x = new FileState(file).IsDirectory;
        }
Example #24
0
        public void ExistsReset()
        {
            string file = null;

            try
            {
                file = FileUtilities.GetTemporaryFile();
                FileInfo info = new FileInfo(file);
                FileState state = new FileState(file);

                Assert.AreEqual(info.Exists, state.FileExists);
                File.Delete(file);
                Assert.AreEqual(true, state.FileExists);
                state.Reset();
                Assert.AreEqual(false, state.FileExists);
            }
            finally
            {
                if (File.Exists(file))
                {
                    File.Delete(file);
                }
            }
        }
Example #25
0
        /// <summary>
        /// Copy source to destination, unless SkipUnchangedFiles is true and they are equivalent.
        /// </summary>
        /// <param name="sourceFile"></param>
        /// <param name="destinationFile"></param>
        /// <param name="copyFile"></param>
        /// <returns></returns>
        private bool DoCopyIfNecessary(FileState sourceFileState, FileState destinationFileState, CopyFileWithState copyFile)
        {
            bool success = true;

            try
            {
                if (_skipUnchangedFiles && IsMatchingSizeAndTimeStamp(sourceFileState, destinationFileState))
                {
                    // If we got here, then the file's time and size match AND
                    // the user set the SkipUnchangedFiles flag which means we
                    // should skip matching files.
                    Log.LogMessageFromResources
                    (
                        MessageImportance.Low,
                        "Copy.DidNotCopyBecauseOfFileMatch",
                        sourceFileState.Name,
                        destinationFileState.Name,
                        "SkipUnchangedFiles",
                        "true"
                    );
                }
                // We only do the cheap check for identicalness here, we try the more expensive check
                // of comparing the fullpaths of source and destination to see if they are identical,
                // in the exception handler lower down.
                else if (0 != String.Compare(sourceFileState.Name, destinationFileState.Name, StringComparison.OrdinalIgnoreCase))
                {
                    success = DoCopyWithRetries(sourceFileState, destinationFileState, copyFile);
                }
            }
            catch (PathTooLongException e)
            {
                Log.LogErrorWithCodeFromResources("Copy.Error", sourceFileState.Name, destinationFileState.Name, e.Message);
                success = false;
            }
            catch (Exception e) when (ExceptionHandling.IsIoRelatedException(e))
            {
                Log.LogErrorWithCodeFromResources("Copy.Error", sourceFileState.Name, destinationFileState.Name, e.Message);
                success = false;
            }

            return success;
        }
Example #26
0
        /// <summary>
        /// Copy one file with the appropriate number of retries if it fails.
        /// </summary>
        private bool DoCopyWithRetries(FileState sourceFileState, FileState destinationFileState, CopyFileWithState copyFile)
        {
            bool? result = null;
            int retries = 0;

            while (true && !_canceling)
            {
                try
                {
                    result = copyFile(sourceFileState, destinationFileState);
                    if (result.HasValue)
                    {
                        return result.Value;
                    }
                }
                catch (Exception e) when (ExceptionHandling.IsIoRelatedException(e))
                {
                    if (e is ArgumentException ||  // Invalid chars
                        e is NotSupportedException || // Colon in the middle of the path
                        e is PathTooLongException)
                    {
                        // No use retrying these cases
                        throw;
                    }

                    if (e is UnauthorizedAccessException || e is IOException) // Not clear why we can get one and not the other
                    {
                        int code = Marshal.GetHRForException(e);

                        LogDiagnostic("Got {0} copying {1} to {2} and HR is {3}", e.ToString(), sourceFileState.Name, destinationFileState.Name, code);
                        if (code == Microsoft.Build.Tasks.NativeMethods.ERROR_ACCESS_DENIED)
                        {
                            // ERROR_ACCESS_DENIED can either mean there's an ACL preventing us, or the file has the readonly bit set.
                            // In either case, that's likely not a race, and retrying won't help.
                            // Retrying is mainly for ERROR_SHARING_VIOLATION, where someone else is using the file right now.
                            // However, there is a limited set of circumstances where a copy failure will show up as access denied due 
                            // to a failure to reset the readonly bit properly, in which case retrying will succeed.  This seems to be 
                            // a pretty edge scenario, but since some of our internal builds appear to be hitting it, provide a secret
                            // environment variable to allow overriding the default behavior and forcing retries in this circumstance as well. 
                            if (!s_alwaysRetryCopy)
                            {
                                throw;
                            }
                            else
                            {
                                LogDiagnostic("Retrying on ERROR_ACCESS_DENIED because MSBUILDALWAYSRETRY = 1");
                            }
                        }
                    }

                    if (e is IOException && DestinationFolder != null && File.Exists(DestinationFolder.ItemSpec))
                    {
                        // We failed to create the DestinationFolder because it's an existing file. No sense retrying.
                        // We don't check for this case upstream because it'd be another hit to the filesystem.
                        throw;
                    }

                    if (e is IOException)
                    {
                        // if this was just because the source and destination files are the
                        // same file, that's not a failure.
                        // Note -- we check this exceptional case here, not before the copy, for perf.
                        if (PathsAreIdentical(sourceFileState.Name, destinationFileState.Name))
                        {
                            return true;
                        }
                    }

                    if (retries < Retries)
                    {
                        retries++;
                        Log.LogWarningWithCodeFromResources("Copy.Retrying", sourceFileState.Name, destinationFileState.Name, retries, RetryDelayMilliseconds, e.Message);

                        // if we have to retry for some reason, wipe the state -- it may not be correct anymore. 
                        destinationFileState.Reset();

                        Thread.Sleep(RetryDelayMilliseconds);
                        continue;
                    }
                    else if (Retries > 0)
                    {
                        // Exception message is logged in caller
                        Log.LogErrorWithCodeFromResources("Copy.ExceededRetries", sourceFileState.Name, destinationFileState.Name, Retries);
                        throw;
                    }
                    else
                    {
                        throw;
                    }
                }

                if (retries < Retries)
                {
                    retries++;
                    Log.LogWarningWithCodeFromResources("Copy.Retrying", sourceFileState.Name, destinationFileState.Name, retries, RetryDelayMilliseconds, String.Empty /* no details */);

                    // if we have to retry for some reason, wipe the state -- it may not be correct anymore. 
                    destinationFileState.Reset();

                    Thread.Sleep(RetryDelayMilliseconds);
                }
                else if (Retries > 0)
                {
                    Log.LogErrorWithCodeFromResources("Copy.ExceededRetries", sourceFileState.Name, destinationFileState.Name, Retries);
                    return false;
                }
                else
                {
                    return false;
                }
            }

            // Canceling
            return false;
        }
Example #27
0
        public void IsDirectoryTrue()
        {
            var state = new FileState(Path.GetTempPath());

            Assert.Equal(true, state.IsDirectory);
        }
Example #28
0
        /// <summary>
        /// Method compares two files and returns true if their size and timestamp are identical.
        /// </summary>
        /// <param name="sourceFile">The source file</param>
        /// <param name="destinationFile">The destination file</param>
        /// <returns></returns>
        private static bool IsMatchingSizeAndTimeStamp
        (
            FileState sourceFile,
            FileState destinationFile
        )
        {
            // If the destination doesn't exists, then it is not a matching file.
            if (!destinationFile.FileExists)
            {
                return false;
            }

            if (sourceFile.LastWriteTimeUtcFast != destinationFile.LastWriteTimeUtcFast)
            {
                return false;
            }

            if (sourceFile.Length != destinationFile.Length)
            {
                return false;
            }

            return true;
        }
Example #29
0
        public void Length()
        {
            string file = null;

            try
            {
                file = FileUtilities.GetTemporaryFile();
                FileInfo info = new FileInfo(file);
                FileState state = new FileState(file);

                Assert.Equal(info.Length, state.Length);
            }
            finally
            {
                File.Delete(file);
            }
        }
Example #30
0
        private void TryCopyViaLink(string linkComment, MessageImportance messageImportance, FileState sourceFileState, FileState destinationFileState, ref bool destinationFileExists, out bool linkCreated, ref string errorMessage, Func <string, string, string, bool> createLink)
        {
            // Do not log a fake command line as well, as it's superfluous, and also potentially expensive
            Log.LogMessageFromResources(MessageImportance.Normal, linkComment, sourceFileState.Name, destinationFileState.Name);

            if (!OverwriteReadOnlyFiles)
            {
                destinationFileExists = destinationFileState.FileExists;
            }

            // CreateHardLink and CreateSymbolicLink cannot overwrite an existing file or link
            // so we need to delete the existing entry before we create the hard or symbolic link.
            if (destinationFileExists)
            {
                FileUtilities.DeleteNoThrow(destinationFileState.Name);
            }

            linkCreated = createLink(sourceFileState.Name, destinationFileState.Name, errorMessage);

            if (!linkCreated)
            {
                // This is only a message since we don't want warnings when copying to network shares etc.
                Log.LogMessageFromResources(messageImportance, "Copy.RetryingAsFileCopy", sourceFileState.Name, destinationFileState.Name, errorMessage);
            }
        }
Example #31
0
        public void LengthHuge()
        {
            var bigFile = @"d:\proj\hugefile";
            //var dummy = new string('x', 10000000);
            //using (StreamWriter w = new StreamWriter(bigFile))
            //{
            //    for (int i = 0; i < 450; i++)
            //    {
            //        w.Write(dummy);
            //    }
            //}

            Console.WriteLine((new FileState(bigFile)).Length);

            FileInfo info = new FileInfo(bigFile);
            FileState state = new FileState(bigFile);

            Assert.AreEqual(info.Exists, state.Exists);

            if (!info.Exists)
            {
                // meh, somewhere else  
                return;
            }

            Assert.AreEqual(info.Length, state.Length);
        }
Example #32
0
        /// <summary>
        /// Copy one file from source to destination. Create the target directory if necessary and
        /// leave the file read-write.
        /// </summary>
        /// <returns>Return true to indicate success, return false to indicate failure and NO retry, return NULL to indicate retry.</returns>
        private bool?CopyFileWithLogging
        (
            FileState sourceFileState,      // The source file
            FileState destinationFileState  // The destination file
        )
        {
            bool destinationFileExists = false;

            if (destinationFileState.DirectoryExists)
            {
                Log.LogErrorWithCodeFromResources("Copy.DestinationIsDirectory", sourceFileState.Name, destinationFileState.Name);
                return(false);
            }

            if (sourceFileState.DirectoryExists)
            {
                // If the source file passed in is actually a directory instead of a file, log a nice
                // error telling the user so.  Otherwise, .NET Framework's File.Copy method will throw
                // an UnauthorizedAccessException saying "access is denied", which is not very useful
                // to the user.
                Log.LogErrorWithCodeFromResources("Copy.SourceIsDirectory", sourceFileState.Name);
                return(false);
            }

            if (!sourceFileState.FileExists)
            {
                Log.LogErrorWithCodeFromResources("Copy.SourceFileNotFound", sourceFileState.Name);
                return(false);
            }

            string destinationFolder = Path.GetDirectoryName(destinationFileState.Name);

            if (!string.IsNullOrEmpty(destinationFolder) && !_directoriesKnownToExist.ContainsKey(destinationFolder))
            {
                if (!FileSystems.Default.DirectoryExists(destinationFolder))
                {
                    Log.LogMessageFromResources(MessageImportance.Normal, "Copy.CreatesDirectory", destinationFolder);
                    Directory.CreateDirectory(destinationFolder);
                }

                // It's very common for a lot of files to be copied to the same folder.
                // Eg., "c:\foo\a"->"c:\bar\a", "c:\foo\b"->"c:\bar\b" and so forth.
                // We don't want to check whether this folder exists for every single file we copy. So store which we've checked.
                _directoriesKnownToExist.TryAdd(destinationFolder, true);
            }

            if (OverwriteReadOnlyFiles)
            {
                MakeFileWriteable(destinationFileState, true);
                destinationFileExists = destinationFileState.FileExists;
            }

            bool   linkCreated  = false;
            string errorMessage = string.Empty;

            // If we want to create hard or symbolic links, then try that first
            if (UseHardlinksIfPossible)
            {
                TryCopyViaLink("Copy.HardLinkComment", MessageImportance.Normal, sourceFileState, destinationFileState, ref destinationFileExists, out linkCreated, ref errorMessage, (source, destination, errMessage) => NativeMethods.MakeHardLink(destination, source, ref errorMessage));
            }
            else if (UseSymboliclinksIfPossible)
            {
                TryCopyViaLink("Copy.SymbolicLinkComment", MessageImportance.Normal, sourceFileState, destinationFileState, ref destinationFileExists, out linkCreated, ref errorMessage, (source, destination, errMessage) => NativeMethods.MakeSymbolicLink(destination, source, ref errorMessage));
            }

            // If the link was not created (either because the user didn't want one, or because it couldn't be created)
            // then let's copy the file
            if (!linkCreated)
            {
                // Do not log a fake command line as well, as it's superfluous, and also potentially expensive
                string sourceFilePath      = FileUtilities.GetFullPathNoThrow(sourceFileState.Name);
                string destinationFilePath = FileUtilities.GetFullPathNoThrow(destinationFileState.Name);
                Log.LogMessageFromResources(MessageImportance.Normal, "Copy.FileComment", sourceFilePath, destinationFilePath);

                File.Copy(sourceFileState.Name, destinationFileState.Name, true);
            }

            destinationFileState.Reset();

            // If the destinationFile file exists, then make sure it's read-write.
            // The File.Copy command copies attributes, but our copy needs to
            // leave the file writeable.
            if (sourceFileState.IsReadOnly)
            {
                MakeFileWriteable(destinationFileState, false);
            }

            return(true);
        }
Example #33
0
        public void NameReset()
        {
            string file = null;

            try
            {
                file = FileUtilities.GetTemporaryFile();
                FileInfo info = new FileInfo(file);
                FileState state = new FileState(file);

                Assert.Equal(info.FullName, state.Name);
                string originalName = info.FullName;
                string oldFile = file;
                file = oldFile + "2";
                File.Move(oldFile, file);
                Assert.Equal(originalName, state.Name);
                state.Reset();
                Assert.Equal(originalName, state.Name); // Name is from the constructor, didn't change
            }
            finally
            {
                File.Delete(file);
            }
        }
Example #34
0
        private void TryCopyViaLink(string linkComment, MessageImportance messageImportance, FileState sourceFileState, FileState destinationFileState, ref bool destinationFileExists, out bool linkCreated, ref string errorMessage, Func <string, string, string, bool> createLink)
        {
            // Do not log a fake command line as well, as it's superfluous, and also potentially expensive
            Log.LogMessageFromResources(MessageImportance.Normal, linkComment, sourceFileState.Name, destinationFileState.Name);

            if (!OverwriteReadOnlyFiles)
            {
                destinationFileExists = destinationFileState.FileExists;
            }

            // CreateHardLink and CreateSymbolicLink cannot overwrite an existing file or link
            // so we need to delete the existing entry before we create the hard or symbolic link.
            // We need to do a best-effort check to see if the files are the same
            // if they are the same then we won't delete, just in case they refer to the same
            // physical file on disk.
            // Since we'll fall back to a copy (below) this will fail and issue a correct
            // message in the case that the source and destination are in fact the same file.
            if (destinationFileExists && !IsMatchingSizeAndTimeStamp(sourceFileState, destinationFileState))
            {
                FileUtilities.DeleteNoThrow(destinationFileState.Name);
            }

            linkCreated = createLink(sourceFileState.Name, destinationFileState.Name, errorMessage);

            if (!linkCreated)
            {
                // This is only a message since we don't want warnings when copying to network shares etc.
                Log.LogMessageFromResources(messageImportance, "Copy.RetryingAsFileCopy", sourceFileState.Name, destinationFileState.Name, errorMessage);
            }
        }
Example #35
0
        public void LengthReset()
        {
            string file = null;

            try
            {
                file = FileUtilities.GetTemporaryFile();
                FileInfo info = new FileInfo(file);
                FileState state = new FileState(file);

                Assert.Equal(info.Length, state.Length);
                File.WriteAllText(file, "x");

                Assert.Equal(info.Length, state.Length);
                state.Reset();
                info.Refresh();
                Assert.Equal(info.Length, state.Length);
            }
            finally
            {
                File.Delete(file);
            }
        }
Example #36
0
        /// <summary>
        /// Copy one file from source to destination. Create the target directory if necessary and 
        /// leave the file read-write.
        /// </summary>
        /// <param name="sourceFile"></param>
        /// <param name="destinationFile"></param>
        /// <returns>Return true to indicate success, return false to indicate failure and NO retry, return NULL to indicate retry.</returns>
        private bool? CopyFileWithLogging
        (
            FileState sourceFileState,      // The source file
            FileState destinationFileState  // The destination file
        )
        {
            bool destinationFileExists = false;

            if (destinationFileState.DirectoryExists)
            {
                Log.LogErrorWithCodeFromResources("Copy.DestinationIsDirectory", sourceFileState.Name, destinationFileState.Name);
                return false;
            }

            if (sourceFileState.DirectoryExists)
            {
                // If the source file passed in is actually a directory instead of a file, log a nice
                // error telling the user so.  Otherwise, .NET Framework's File.Copy method will throw
                // an UnauthorizedAccessException saying "access is denied", which is not very useful
                // to the user.
                Log.LogErrorWithCodeFromResources("Copy.SourceIsDirectory", sourceFileState.Name);
                return false;
            }

            if (!sourceFileState.FileExists)
            {
                Log.LogErrorWithCodeFromResources("Copy.SourceFileNotFound", sourceFileState.Name);
                return false;
            }

            string destinationFolder = Path.GetDirectoryName(destinationFileState.Name);

            if (destinationFolder != null && destinationFolder.Length > 0 && !_directoriesKnownToExist.Contains(destinationFolder))
            {
                if (!Directory.Exists(destinationFolder))
                {
                    Log.LogMessageFromResources(MessageImportance.Normal, "Copy.CreatesDirectory", destinationFolder);
                    Directory.CreateDirectory(destinationFolder);
                }

                // It's very common for a lot of files to be copied to the same folder. 
                // Eg., "c:\foo\a"->"c:\bar\a", "c:\foo\b"->"c:\bar\b" and so forth.
                // We don't want to check whether this folder exists for every single file we copy. So store which we've checked.
                _directoriesKnownToExist.Add(destinationFolder);
            }

            if (_overwriteReadOnlyFiles)
            {
                MakeFileWriteable(destinationFileState, true);
                destinationFileExists = destinationFileState.FileExists;
            }

            bool hardLinkCreated = false;

            // If we want to create hard links, then try that first
            if (UseHardlinksIfPossible)
            {
                // Do not log a fake command line as well, as it's superfluous, and also potentially expensive
                Log.LogMessageFromResources(MessageImportance.Normal, "Copy.HardLinkComment", sourceFileState.Name, destinationFileState.Name);

                if (!_overwriteReadOnlyFiles)
                {
                    destinationFileExists = destinationFileState.FileExists;
                }

                // CreateHardLink cannot overwrite an existing file or hard link
                // so we need to delete the existing entry before we create the hard link.
                // We need to do a best-effort check to see if the files are the same
                // if they are the same then we won't delete, just in case they refer to the same
                // physical file on disk.
                // Since we'll fall back to a copy (below) this will fail and issue a correct
                // message in the case that the source and destination are in fact the same file.
                if (destinationFileExists && !IsMatchingSizeAndTimeStamp(sourceFileState, destinationFileState))
                {
                    FileUtilities.DeleteNoThrow(destinationFileState.Name);
                }

                hardLinkCreated = NativeMethods.CreateHardLink(destinationFileState.Name, sourceFileState.Name, IntPtr.Zero /* reserved, must be NULL */);

                if (!hardLinkCreated)
                {
                    int errorCode = Marshal.GetHRForLastWin32Error();
                    Exception hardLinkException = Marshal.GetExceptionForHR(errorCode);
                    // This is only a message since we don't want warnings when copying to network shares etc.
                    Log.LogMessageFromResources(MessageImportance.Low, "Copy.RetryingAsFileCopy", sourceFileState.Name, destinationFileState.Name, hardLinkException.Message);
                }
            }

            // If the hard link was not created (either because the user didn't want one, or because it couldn't be created)
            // then let's copy the file
            if (!hardLinkCreated)
            {
                // Do not log a fake command line as well, as it's superfluous, and also potentially expensive
                Log.LogMessageFromResources(MessageImportance.Normal, "Copy.FileComment", sourceFileState.Name, destinationFileState.Name);
                File.Copy(sourceFileState.Name, destinationFileState.Name, true);
            }

            destinationFileState.Reset();

            // If the destinationFile file exists, then make sure it's read-write.
            // The File.Copy command copies attributes, but our copy needs to
            // leave the file writeable.
            if (sourceFileState.IsReadOnly)
            {
                MakeFileWriteable(destinationFileState, false);
            }

            return true;
        }
Example #37
0
 public void LengthOnDirectory()
 {
     Helpers.VerifyAssertThrowsSameWay(delegate () { var x = new FileInfo(Path.GetTempPath()).Length; }, delegate () { var x = new FileState(Path.GetTempPath()).Length; });
 }
Example #38
0
        /// <summary>
        /// Copy one file from source to destination. Create the target directory if necessary and
        /// leave the file read-write.
        /// </summary>
        /// <param name="sourceFile"></param>
        /// <param name="destinationFile"></param>
        /// <returns>Return true to indicate success, return false to indicate failure and NO retry, return NULL to indicate retry.</returns>
        private bool?CopyFileWithLogging
        (
            FileState sourceFileState,      // The source file
            FileState destinationFileState  // The destination file
        )
        {
            bool destinationFileExists = false;

            if (destinationFileState.DirectoryExists)
            {
                Log.LogErrorWithCodeFromResources("Copy.DestinationIsDirectory", sourceFileState.Name, destinationFileState.Name);
                return(false);
            }

            if (sourceFileState.DirectoryExists)
            {
                // If the source file passed in is actually a directory instead of a file, log a nice
                // error telling the user so.  Otherwise, .NET Framework's File.Copy method will throw
                // an UnauthorizedAccessException saying "access is denied", which is not very useful
                // to the user.
                Log.LogErrorWithCodeFromResources("Copy.SourceIsDirectory", sourceFileState.Name);
                return(false);
            }

            if (!sourceFileState.FileExists)
            {
                Log.LogErrorWithCodeFromResources("Copy.SourceFileNotFound", sourceFileState.Name);
                return(false);
            }

            string destinationFolder = Path.GetDirectoryName(destinationFileState.Name);

            if (destinationFolder != null && destinationFolder.Length > 0 && !_directoriesKnownToExist.Contains(destinationFolder))
            {
                if (!Directory.Exists(destinationFolder))
                {
                    Log.LogMessageFromResources(MessageImportance.Normal, "Copy.CreatesDirectory", destinationFolder);
                    Directory.CreateDirectory(destinationFolder);
                }

                // It's very common for a lot of files to be copied to the same folder.
                // Eg., "c:\foo\a"->"c:\bar\a", "c:\foo\b"->"c:\bar\b" and so forth.
                // We don't want to check whether this folder exists for every single file we copy. So store which we've checked.
                _directoriesKnownToExist.Add(destinationFolder);
            }

            if (_overwriteReadOnlyFiles)
            {
                MakeFileWriteable(destinationFileState, true);
                destinationFileExists = destinationFileState.FileExists;
            }

            bool hardLinkCreated = false;

            // If we want to create hard links, then try that first
            if (UseHardlinksIfPossible)
            {
                // Do not log a fake command line as well, as it's superfluous, and also potentially expensive
                Log.LogMessageFromResources(MessageImportance.Normal, "Copy.HardLinkComment", sourceFileState.Name, destinationFileState.Name);

                if (!_overwriteReadOnlyFiles)
                {
                    destinationFileExists = destinationFileState.FileExists;
                }

                // CreateHardLink cannot overwrite an existing file or hard link
                // so we need to delete the existing entry before we create the hard link.
                // We need to do a best-effort check to see if the files are the same
                // if they are the same then we won't delete, just in case they refer to the same
                // physical file on disk.
                // Since we'll fall back to a copy (below) this will fail and issue a correct
                // message in the case that the source and destination are in fact the same file.
                if (destinationFileExists && !IsMatchingSizeAndTimeStamp(sourceFileState, destinationFileState))
                {
                    FileUtilities.DeleteNoThrow(destinationFileState.Name);
                }

                hardLinkCreated = NativeMethods.CreateHardLink(destinationFileState.Name, sourceFileState.Name, IntPtr.Zero /* reserved, must be NULL */);

                if (!hardLinkCreated)
                {
                    int       errorCode         = Marshal.GetHRForLastWin32Error();
                    Exception hardLinkException = Marshal.GetExceptionForHR(errorCode);
                    // This is only a message since we don't want warnings when copying to network shares etc.
                    Log.LogMessageFromResources(MessageImportance.Low, "Copy.RetryingAsFileCopy", sourceFileState.Name, destinationFileState.Name, hardLinkException.Message);
                }
            }

            // If the hard link was not created (either because the user didn't want one, or because it couldn't be created)
            // then let's copy the file
            if (!hardLinkCreated)
            {
                // Do not log a fake command line as well, as it's superfluous, and also potentially expensive
                Log.LogMessageFromResources(MessageImportance.Normal, "Copy.FileComment", sourceFileState.Name, destinationFileState.Name);
                File.Copy(sourceFileState.Name, destinationFileState.Name, true);
            }

            destinationFileState.Reset();

            // If the destinationFile file exists, then make sure it's read-write.
            // The File.Copy command copies attributes, but our copy needs to
            // leave the file writeable.
            if (sourceFileState.IsReadOnly)
            {
                MakeFileWriteable(destinationFileState, false);
            }

            return(true);
        }
Example #39
0
        /// <summary>
        /// Retrieve the file state object for this path. Create if necessary.
        /// </summary>
        /// <param name="path">The name of the file.</param>
        /// <returns>The file state object.</returns>
        private FileState GetFileState(string path)
        {
            // Is it in the process-wide cache?
            FileState cacheFileState = null;
            FileState processFileState = null;
            SystemState.s_processWideFileStateCache.TryGetValue(path, out processFileState);
            FileState instanceLocalFileState = instanceLocalFileState = (FileState)_instanceLocalFileStateCache[path];

            // Sync the caches.
            if (processFileState == null && instanceLocalFileState != null)
            {
                cacheFileState = instanceLocalFileState;
                SystemState.s_processWideFileStateCache.TryAdd(path, instanceLocalFileState);
            }
            else if (processFileState != null && instanceLocalFileState == null)
            {
                cacheFileState = processFileState;
                _instanceLocalFileStateCache[path] = processFileState;
            }
            else if (processFileState != null && instanceLocalFileState != null)
            {
                if (processFileState.LastModified > instanceLocalFileState.LastModified)
                {
                    cacheFileState = processFileState;
                    _instanceLocalFileStateCache[path] = processFileState;
                }
                else
                {
                    cacheFileState = instanceLocalFileState;
                    SystemState.s_processWideFileStateCache.TryAdd(path, instanceLocalFileState);
                }
            }

            // Still no--need to create.            
            if (cacheFileState == null) // Or check time stamp
            {
                cacheFileState = new FileState();
                cacheFileState.LastModified = _getLastWriteTime(path);
                _instanceLocalFileStateCache[path] = cacheFileState;
                SystemState.s_processWideFileStateCache.TryAdd(path, cacheFileState);
                _isDirty = true;
            }
            else
            {
                // If time stamps have changed, then purge.
                DateTime lastModified = _getLastWriteTime(path);
                if (lastModified != cacheFileState.LastModified)
                {
                    cacheFileState = new FileState();
                    cacheFileState.LastModified = _getLastWriteTime(path);
                    _instanceLocalFileStateCache[path] = cacheFileState;
                    SystemState.s_processWideFileStateCache.TryAdd(path, cacheFileState);
                    _isDirty = true;
                }
            }

            return cacheFileState;
        }
Example #40
0
        /// <summary>
        /// Copy one file with the appropriate number of retries if it fails.
        /// </summary>
        private bool DoCopyWithRetries(FileState sourceFileState, FileState destinationFileState, CopyFileWithState copyFile)
        {
            int retries = 0;

            while (!_cancellationTokenSource.IsCancellationRequested)
            {
                try
                {
                    bool?result = copyFile(sourceFileState, destinationFileState);
                    if (result.HasValue)
                    {
                        return(result.Value);
                    }
                }
                catch (OperationCanceledException)
                {
                    break;
                }
                catch (Exception e) when(ExceptionHandling.IsIoRelatedException(e))
                {
                    if (e is ArgumentException ||     // Invalid chars
                        e is NotSupportedException || // Colon in the middle of the path
                        e is PathTooLongException)
                    {
                        // No use retrying these cases
                        throw;
                    }

                    if (e is UnauthorizedAccessException || e is IOException) // Not clear why we can get one and not the other
                    {
                        int code = Marshal.GetHRForException(e);

                        LogDiagnostic("Got {0} copying {1} to {2} and HR is {3}", e.ToString(), sourceFileState.Name, destinationFileState.Name, code);
                        if (code == NativeMethods.ERROR_ACCESS_DENIED)
                        {
                            // ERROR_ACCESS_DENIED can either mean there's an ACL preventing us, or the file has the readonly bit set.
                            // In either case, that's likely not a race, and retrying won't help.
                            // Retrying is mainly for ERROR_SHARING_VIOLATION, where someone else is using the file right now.
                            // However, there is a limited set of circumstances where a copy failure will show up as access denied due
                            // to a failure to reset the readonly bit properly, in which case retrying will succeed.  This seems to be
                            // a pretty edge scenario, but since some of our internal builds appear to be hitting it, provide a secret
                            // environment variable to allow overriding the default behavior and forcing retries in this circumstance as well.
                            if (!s_alwaysRetryCopy)
                            {
                                throw;
                            }
                            else
                            {
                                LogDiagnostic("Retrying on ERROR_ACCESS_DENIED because MSBUILDALWAYSRETRY = 1");
                            }
                        }
                    }

                    if (e is IOException && DestinationFolder != null && FileSystems.Default.FileExists(DestinationFolder.ItemSpec))
                    {
                        // We failed to create the DestinationFolder because it's an existing file. No sense retrying.
                        // We don't check for this case upstream because it'd be another hit to the filesystem.
                        throw;
                    }

                    if (e is IOException)
                    {
                        // if this was just because the source and destination files are the
                        // same file, that's not a failure.
                        // Note -- we check this exceptional case here, not before the copy, for perf.
                        if (PathsAreIdentical(sourceFileState.Name, destinationFileState.Name))
                        {
                            return(true);
                        }
                    }

                    if (retries < Retries)
                    {
                        retries++;
                        Log.LogWarningWithCodeFromResources("Copy.Retrying", sourceFileState.Name,
                                                            destinationFileState.Name, retries, RetryDelayMilliseconds, e.Message,
                                                            GetLockedFileMessage(destinationFileState.Name));

                        // if we have to retry for some reason, wipe the state -- it may not be correct anymore.
                        destinationFileState.Reset();

                        Thread.Sleep(RetryDelayMilliseconds);
                        continue;
                    }
                    else if (Retries > 0)
                    {
                        // Exception message is logged in caller
                        Log.LogErrorWithCodeFromResources("Copy.ExceededRetries", sourceFileState.Name,
                                                          destinationFileState.Name, Retries, GetLockedFileMessage(destinationFileState.Name));
                        throw;
                    }
                    else
                    {
                        throw;
                    }
                }

                if (retries < Retries)
                {
                    retries++;
                    Log.LogWarningWithCodeFromResources("Copy.Retrying", sourceFileState.Name,
                                                        destinationFileState.Name, retries, RetryDelayMilliseconds, String.Empty /* no details */,
                                                        GetLockedFileMessage(destinationFileState.Name));

                    // if we have to retry for some reason, wipe the state -- it may not be correct anymore.
                    destinationFileState.Reset();

                    Thread.Sleep(RetryDelayMilliseconds);
                }
                else if (Retries > 0)
                {
                    Log.LogErrorWithCodeFromResources("Copy.ExceededRetries", sourceFileState.Name,
                                                      destinationFileState.Name, Retries, GetLockedFileMessage(destinationFileState.Name));
                    return(false);
                }
                else
                {
                    return(false);
                }
            }

            // Canceling
            return(false);
        }
Example #41
0
 public void BadTooLongLastWriteTime()
 {
     Helpers.VerifyAssertThrowsSameWay(
         delegate () { var x = new FileInfo(new String('x', 5000)).LastWriteTime; },
         delegate () { var x = new FileState(new String('x', 5000)).LastWriteTime; });
 }
Example #42
0
            /// <summary>
            /// Pretend to be File.Copy.
            /// </summary>
            internal bool? Copy(FileState source, FileState destination)
            {
                _tries++;

                // 2nd and subsequent copies always succeed
                if (_filesCopiedSuccessfully.Count > 0 || _countOfSuccess == _tries)
                {
                    Console.WriteLine("Copied {0} to {1} OK", source, destination);
                    _filesCopiedSuccessfully.Add(source);
                    return true;
                }

                if (_throwOnFailure)
                {
                    throw new IOException("oops");
                }
                else
                {
                    return null;
                }
            }
Example #43
0
        private FileState ComputeFileStateFromCachesAndDisk(string path)
        {
            // Is it in the process-wide cache?
            FileState cacheFileState   = null;
            FileState processFileState = null;

            s_processWideFileStateCache.TryGetValue(path, out processFileState);
            FileState instanceLocalFileState = (FileState)instanceLocalFileStateCache[path];

            // Sync the caches.
            if (processFileState == null && instanceLocalFileState != null)
            {
                cacheFileState = instanceLocalFileState;
                SystemState.s_processWideFileStateCache[path] = instanceLocalFileState;
            }
            else if (processFileState != null && instanceLocalFileState == null)
            {
                cacheFileState = processFileState;
                instanceLocalFileStateCache[path] = processFileState;
            }
            else if (processFileState != null && instanceLocalFileState != null)
            {
                if (processFileState.LastModified > instanceLocalFileState.LastModified)
                {
                    cacheFileState = processFileState;
                    instanceLocalFileStateCache[path] = processFileState;
                }
                else
                {
                    cacheFileState = instanceLocalFileState;
                    SystemState.s_processWideFileStateCache[path] = instanceLocalFileState;
                }
            }

            bool isLastModifiedCached = instanceLocalLastModifiedCache.TryGetValue(path, out DateTime lastModified);

            if (!isLastModifiedCached)
            {
                lastModified = getLastWriteTime(path);
                instanceLocalLastModifiedCache[path] = lastModified;
            }

            // Still no--need to create.
            if (cacheFileState == null) // Or check time stamp
            {
                cacheFileState = new FileState(lastModified);
                instanceLocalFileStateCache[path]             = cacheFileState;
                SystemState.s_processWideFileStateCache[path] = cacheFileState;
                isDirty = true;
            }
            else
            {
                // If time stamps have changed, then purge.
                if (lastModified != cacheFileState.LastModified)
                {
                    cacheFileState = new FileState(lastModified);
                    instanceLocalFileStateCache[path]             = cacheFileState;
                    SystemState.s_processWideFileStateCache[path] = cacheFileState;
                    isDirty = true;
                }
            }

            return(cacheFileState);
        }
Example #44
0
        /// <summary>
        /// Copy one file from source to destination. Create the target directory if necessary and 
        /// leave the file read-write.
        /// </summary>
        /// <param name="sourceFile"></param>
        /// <param name="destinationFile"></param>
        /// <returns>Return true to indicate success, return false to indicate failure and NO retry, return NULL to indicate retry.</returns>
        private bool? CopyFileWithLogging
        (
            FileState sourceFileState,      // The source file
            FileState destinationFileState  // The destination file
        )
        {
            bool destinationFileExists = false;

            if (destinationFileState.DirectoryExists)
            {
                Log.LogErrorWithCodeFromResources("Copy.DestinationIsDirectory", sourceFileState.Name, destinationFileState.Name);
                return false;
            }

            if (sourceFileState.DirectoryExists)
            {
                // If the source file passed in is actually a directory instead of a file, log a nice
                // error telling the user so.  Otherwise, .NET Framework's File.Copy method will throw
                // an UnauthorizedAccessException saying "access is denied", which is not very useful
                // to the user.
                Log.LogErrorWithCodeFromResources("Copy.SourceIsDirectory", sourceFileState.Name);
                return false;
            }

            if (!sourceFileState.FileExists)
            {
                Log.LogErrorWithCodeFromResources("Copy.SourceFileNotFound", sourceFileState.Name);
                return false;
            }

            string destinationFolder = Path.GetDirectoryName(destinationFileState.Name);

            if (destinationFolder != null && destinationFolder.Length > 0 && !_directoriesKnownToExist.Contains(destinationFolder))
            {
                if (!Directory.Exists(destinationFolder))
                {
                    Log.LogMessageFromResources(MessageImportance.Normal, "Copy.CreatesDirectory", destinationFolder);
                    Directory.CreateDirectory(destinationFolder);
                }

                // It's very common for a lot of files to be copied to the same folder. 
                // Eg., "c:\foo\a"->"c:\bar\a", "c:\foo\b"->"c:\bar\b" and so forth.
                // We don't want to check whether this folder exists for every single file we copy. So store which we've checked.
                _directoriesKnownToExist.Add(destinationFolder);
            }

            if (_overwriteReadOnlyFiles)
            {
                MakeFileWriteable(destinationFileState, true);
                destinationFileExists = destinationFileState.FileExists;
            }

            bool linkCreated = false;

            // If we want to create hard or symbolic links, then try that first
            if (UseHardlinksIfPossible)
                TryCopyViaLink("Copy.HardLinkComment", MessageImportance.High, sourceFileState, destinationFileState, ref destinationFileExists, ref linkCreated, (source, destination) => NativeMethods.CreateHardLink(destination, source, IntPtr.Zero /* reserved, must be NULL */));
            else if (UseSymboliclinksIfPossible)
                TryCopyViaLink("Copy.SymbolicLinkComment", MessageImportance.High, sourceFileState, destinationFileState, ref destinationFileExists, ref linkCreated, (source, destination) => NativeMethods.CreateSymbolicLink(destination, source, SymbolicLink.File));

            // If the link was not created (either because the user didn't want one, or because it couldn't be created)
            // then let's copy the file
            if (!linkCreated)
            {
                // Do not log a fake command line as well, as it's superfluous, and also potentially expensive
                Log.LogMessageFromResources(MessageImportance.Normal, "Copy.FileComment", sourceFileState.Name, destinationFileState.Name);
                File.Copy(sourceFileState.Name, destinationFileState.Name, true);
            }

            destinationFileState.Reset();

            // If the destinationFile file exists, then make sure it's read-write.
            // The File.Copy command copies attributes, but our copy needs to
            // leave the file writeable.
            if (sourceFileState.IsReadOnly)
            {
                MakeFileWriteable(destinationFileState, false);
            }

            return true;
        }