101 ArgumentNullException.ThrowIfNull(path);
102 ArgumentNullException.ThrowIfNull(data);
104 cancellationToken.ThrowIfCancellationRequested();
105 var directory =
fileSystem.Path.GetDirectoryName(path) ??
throw new ArgumentException(
"path cannot be rooted!", nameof(path));
106 fileSystem.Directory.CreateDirectory(directory);
110 cancellationToken.ThrowIfCancellationRequested();
112 logger.LogTrace(
"Starting checked write to {path} ({fileType} file)", path, newFile ?
"New" :
"Pre-existing");
114 using (var file =
fileSystem.File.Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
116 cancellationToken.ThrowIfCancellationRequested();
119 if (file.Length != 0 && sha1InOut ==
null)
121 logger.LogDebug(
"Aborting checked write due to missing SHA!");
126 using (var sha1 = SHA1.Create())
128 string? GetSha1(
Stream dataToHash)
130 if (dataToHash ==
null)
133 byte[] sha1Computed = dataToHash.Length != 0
134 ? sha1.ComputeHash(dataToHash)
135 : sha1.ComputeHash(Array.Empty<
byte>());
137 return String.Join(String.Empty, sha1Computed.Select(b => b.ToString(
"x2", CultureInfo.InvariantCulture)));
140 var originalSha1 = GetSha1(file);
143 logger.LogTrace(
"Existing SHA calculated to be {sha}", originalSha1);
145 if (originalSha1 != sha1InOut && !(newFile && sha1InOut ==
null))
147 sha1InOut = originalSha1;
151 sha1InOut = GetSha1(data);
154 cancellationToken.ThrowIfCancellationRequested();
156 if (data.Length != 0)
158 logger.LogDebug(
"Writing file of length {size}", data.Length);
159 file.Seek(0, SeekOrigin.Begin);
160 data.Seek(0, SeekOrigin.Begin);
162 cancellationToken.ThrowIfCancellationRequested();
163 file.SetLength(data.Length);
168 if (data.Length == 0)
170 logger.LogDebug(
"Stream is empty, deleting file");