Пример #1
0
        public bool ReadFsChangeBody(string path, FsChange fsChange)
        {
            var shebangPosition = 0;
            var makeExecutable  = false;

            string     tempPath        = null;
            FileStream fs              = null;
            bool       bodyReadSuccess = false;

            try
            {
                long written = 0;
                int  chunkSize;
                do
                {
                    chunkSize = ReadInt();
                    if (chunkSize < 0)
                    {
                        // error occurred in sender
                        return(false);
                    }

                    var remain = chunkSize;
                    while (remain > 0)
                    {
                        var read = BinaryReader.Read(_buffer, 0, Math.Min(BUFFER_LENGTH, remain));
                        if (read <= 0)
                        {
                            throw new EndOfStreamException($"Premature end of stream {remain}, {chunkSize}, {read})");
                        }

                        if (written == 0)
                        {
                            var directoryName = Path.GetDirectoryName(path);
                            Directory.CreateDirectory(directoryName);
                            tempPath = Path.Combine(directoryName,
                                                    "." + Path.GetFileName(path) + "." + Path.GetRandomFileName());
                            fs = new FileStream(tempPath, FileMode.CreateNew, FileAccess.Write, FileShare.Read);
                        }

                        if (PlatformHasChmod && shebangPosition < ShebangLength)
                        {
                            for (var i = 0; i < read;)
                            {
                                if (_buffer[i++] != ShebangBytes[shebangPosition++])
                                {
                                    // no shebang
                                    shebangPosition = int.MaxValue;
                                    break;
                                }
                                if (shebangPosition == ShebangLength)
                                {
                                    makeExecutable = true;
                                    break;
                                }
                            }
                        }

                        fs?.Write(_buffer, 0, read);
                        written += read;
                        remain  -= read;
                    }
                } while (chunkSize > 0);

                bodyReadSuccess = written == fsChange.Length;
                if (bodyReadSuccess && makeExecutable)
                {
                    // 0755, rwxr-xr-x
                    fs.ChangeMode(0b111_101_101);
                }

                // create empty file
                if (bodyReadSuccess && fsChange.Length == 0)
                {
                    var directoryName = Path.GetDirectoryName(path);
                    Directory.CreateDirectory(directoryName);
                    using (new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
                    {
                    }
                    File.SetLastWriteTime(path, fsChange.LastWriteTime);
                }

                return(bodyReadSuccess);
            }
            catch (Exception)
            {
                SkipFsChangeBody();
                throw;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Dispose();

                    if (bodyReadSuccess)
                    {
                        try
                        {
                            File.SetLastWriteTime(tempPath, fsChange.LastWriteTime);
                            File.Move(tempPath, path, true);
                        }
                        catch (Exception)
                        {
                            FsHelper.TryDeleteFile(tempPath);
                            throw;
                        }
                    }
                    else
                    {
                        FsHelper.TryDeleteFile(tempPath);
                    }
                }
            }
        }