Esempio n. 1
0
        public FileLock(Log log, params string[] filenames)
        {
            _locks = new LockFile[filenames.Length];

            for (int i = 0; i < _locks.Length; i++)
            {
                Disk.CreateDirectory(log, Path.GetDirectoryName(filenames[i]));
                _locks[i] = new LockFile(filenames[i] + ".lock");
            }

            for (int tries = 1; !TryAcquireAll(); tries++)
            {
                if (tries == 2000)
                {
                    throw new TimeoutException("Failed to lock " + this + "; aborting after " + tries + " tries");
                }
                if (tries % 50 == 0)
                {
                    log.Warning("Failed to lock " + this + "; retrying...");
                }

                // Spin wait while another process owns the file(s),
                // Some randomness helps with race conditions
                Thread.Sleep(Rand.Next(200, 500));
            }
        }
Esempio n. 2
0
        public static string GetFile(Log log, string url)
        {
            var dst = GetFileName(url);

            // 1) Early out if the file exists locally
            if (File.Exists(dst))
            {
                Disk.TouchFile(log, dst);
                return(dst);
            }

            Disk.CreateDirectory(log, StuffDirectory);

            try
            {
                // Use a set to avoid repeating errors
                var errors = new HashSet <string>();

                for (int tries = 0;; tries++)
                {
                    // 2) Download the file from URL
                    log.WriteLine("Downloading " + url + (
                                      tries > 0
                                ? " (retry " + tries + "...)"
                                : null
                                      ), ConsoleColor.Blue);

                    try
                    {
                        using (var client = new StuffWebClient())
                            client.DownloadFile(url, dst);
                        return(dst);
                    }
                    catch (Exception e)
                    {
                        // Fail the 10th time, or unless WebException
                        if (tries >= 10 || !(e is WebException))
                        {
                            // Print previous errors, before rethrowing
                            foreach (var s in errors)
                            {
                                log.Error(s);
                            }
                            throw;
                        }

                        errors.Add(e.Message);
                        Thread.Sleep(500);
                    }
                }
            }
            catch
            {
                Disk.DeleteFile(log, dst);
                throw;
            }
        }
Esempio n. 3
0
        void InstallItem(KeyValuePair <string, object> item)
        {
            var itemKey    = item.Key.Replace('/', Path.DirectorySeparatorChar);
            var components = itemKey.Split(Path.DirectorySeparatorChar);

            if (components.Contains(".") || components.Contains(".."))
            {
                throw new FormatException(item.Key + ": '.' or '..' are not valid in directory names");
            }

            var itemFile  = Path.Combine(_parentDirectory, ".uno", "stuff", itemKey);
            var targetDir = Path.Combine(_parentDirectory, itemKey);
            var itemValue = item.Value?.ToString();

            if (string.IsNullOrEmpty(itemValue) ||
                IsItemUpToDate(Log, targetDir, itemFile, itemValue, _flags))
            {
                return;
            }

            using (new FileLock(Log, itemFile, DownloadCache.GetFileName(itemValue)))
            {
                if (IsItemUpToDate(Log, targetDir, itemFile, itemValue, _flags))
                {
                    return;
                }

                for (int tries = 0;; tries++)
                {
                    Log.Verbose("Extracting " + targetDir.ToRelativePath().Quote(), ConsoleColor.DarkGray);

                    // Support local files (e.g. from .STUFF-UPLOAD files)
                    var localFile = Path.Combine(_parentDirectory, itemValue);
                    var isLocal   = File.Exists(localFile);
                    var file      = isLocal
                        ? localFile
                        : DownloadCache.GetFile(Log, itemValue);

                    Disk.DeleteDirectory(Log, targetDir);
                    Disk.CreateDirectory(Log, targetDir);

                    try
                    {
                        if (PlatformDetection.IsWindows)
                        {
                            LongPathZipFile.ExtractToDirectory(file, targetDir);
                        }
                        else
                        {
                            // Use system tar/unzip to preserve file permissions and links
                            // (ZipFile doesn't handle this)
                            if (Path.GetFileName(file).ToUpper().EndsWith(".TAR.GZ"))
                            {
                                Shell.Untar(Log, file, targetDir);
                            }
                            else
                            {
                                Shell.Unzip(Log, file, targetDir);
                            }

                            // Make sure files extracted are writable so we can touch them
                            Shell.Chmod(Log, "+w", targetDir);
                            Disk.TouchAllFiles(Log, targetDir);
                        }

                        Disk.CreateDirectory(Log, Path.GetDirectoryName(itemFile));
                        File.WriteAllText(itemFile, itemValue);
                        break;
                    }
                    catch (UnauthorizedAccessException)
                    {
                        // Don't try more if we get this
                        throw;
                    }
                    catch
                    {
                        // Delete any installed files
                        Disk.DeleteFile(Log, itemFile);
                        Disk.DeleteDirectory(Log, targetDir);

                        if (isLocal)
                        {
                            throw;
                        }

                        // Delete the cached download too
                        Disk.DeleteFile(Log, file);

                        // Redownload, and try just one more time to be sure
                        // This might fix the problem if the cached file was corrupt
                        if (tries > 0)
                        {
                            throw;
                        }

                        Thread.Sleep(150);
                    }
                }
            }
        }