// Unix specific implementation of the method that reads an entry from disk and writes it into the archive stream. partial void ReadFileFromDiskAndWriteToArchiveStreamAsEntry(string fullPath, string entryName) { Interop.Sys.FileStatus status = default; status.Mode = default; status.Dev = default; Interop.CheckIo(Interop.Sys.LStat(fullPath, out status)); TarEntryType entryType = (status.Mode & (uint)Interop.Sys.FileTypes.S_IFMT) switch { // Hard links are treated as regular files. // Unix socket files do not get added to tar files. Interop.Sys.FileTypes.S_IFBLK => TarEntryType.BlockDevice, Interop.Sys.FileTypes.S_IFCHR => TarEntryType.CharacterDevice, Interop.Sys.FileTypes.S_IFIFO => TarEntryType.Fifo, Interop.Sys.FileTypes.S_IFLNK => TarEntryType.SymbolicLink, Interop.Sys.FileTypes.S_IFREG => Format is TarFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile, Interop.Sys.FileTypes.S_IFDIR => TarEntryType.Directory, _ => throw new IOException(string.Format(SR.TarUnsupportedFile, fullPath)), }; FileSystemInfo info = entryType is TarEntryType.Directory ? new DirectoryInfo(fullPath) : new FileInfo(fullPath); TarEntry entry = Format switch { TarFormat.V7 => new V7TarEntry(entryType, entryName), TarFormat.Ustar => new UstarTarEntry(entryType, entryName), TarFormat.Pax => new PaxTarEntry(entryType, entryName), TarFormat.Gnu => new GnuTarEntry(entryType, entryName), _ => throw new FormatException(string.Format(SR.TarInvalidFormat, Format)), }; if (entryType is TarEntryType.BlockDevice or TarEntryType.CharacterDevice) { uint major; uint minor; unsafe { Interop.Sys.GetDeviceIdentifiers((ulong)status.RDev, &major, &minor); } entry._header._devMajor = (int)major; entry._header._devMinor = (int)minor; } entry._header._mTime = TarHelpers.GetDateTimeFromSecondsSinceEpoch(status.MTime); entry._header._aTime = TarHelpers.GetDateTimeFromSecondsSinceEpoch(status.ATime); entry._header._cTime = TarHelpers.GetDateTimeFromSecondsSinceEpoch(status.CTime); entry._header._mode = (status.Mode & 4095); // First 12 bits // Uid and UName entry._header._uid = (int)status.Uid; if (!_userIdentifiers.TryGetValue(status.Uid, out string?uName)) { uName = Interop.Sys.GetUserNameFromPasswd(status.Uid); _userIdentifiers.Add(status.Uid, uName); } entry._header._uName = uName; // Gid and GName entry._header._gid = (int)status.Gid; if (!_groupIdentifiers.TryGetValue(status.Gid, out string?gName)) { gName = Interop.Sys.GetGroupName(status.Gid); _groupIdentifiers.Add(status.Gid, gName); } entry._header._gName = gName; if (entry.EntryType == TarEntryType.SymbolicLink) { entry.LinkName = info.LinkTarget ?? string.Empty; } if (entry.EntryType is TarEntryType.RegularFile or TarEntryType.V7RegularFile) { Debug.Assert(entry._header._dataStream == null); entry._header._dataStream = File.OpenRead(fullPath); } WriteEntry(entry); if (entry._header._dataStream != null) { entry._header._dataStream.Dispose(); } }
// Windows specific implementation of the method that reads an entry from disk and writes it into the archive stream. partial void ReadFileFromDiskAndWriteToArchiveStreamAsEntry(string fullPath, string entryName) { TarEntryType entryType; FileAttributes attributes = File.GetAttributes(fullPath); if (attributes.HasFlag(FileAttributes.ReparsePoint)) { entryType = TarEntryType.SymbolicLink; } else if (attributes.HasFlag(FileAttributes.Directory)) { entryType = TarEntryType.Directory; } else if (attributes.HasFlag(FileAttributes.Normal) || attributes.HasFlag(FileAttributes.Archive)) { entryType = Format is TarEntryFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile; } else { throw new IOException(string.Format(SR.TarUnsupportedFile, fullPath)); } TarEntry entry = Format switch { TarEntryFormat.V7 => new V7TarEntry(entryType, entryName), TarEntryFormat.Ustar => new UstarTarEntry(entryType, entryName), TarEntryFormat.Pax => new PaxTarEntry(entryType, entryName), TarEntryFormat.Gnu => new GnuTarEntry(entryType, entryName), _ => throw new FormatException(string.Format(SR.TarInvalidFormat, Format)), }; FileSystemInfo info = attributes.HasFlag(FileAttributes.Directory) ? new DirectoryInfo(fullPath) : new FileInfo(fullPath); entry._header._mTime = new DateTimeOffset(info.LastWriteTimeUtc); entry._header._aTime = new DateTimeOffset(info.LastAccessTimeUtc); entry._header._cTime = new DateTimeOffset(info.LastWriteTimeUtc); // There is no "change time" property entry.Mode = DefaultWindowsMode; if (entry.EntryType == TarEntryType.SymbolicLink) { entry.LinkName = info.LinkTarget ?? string.Empty; } if (entry.EntryType is TarEntryType.RegularFile or TarEntryType.V7RegularFile) { FileStreamOptions options = new() { Mode = FileMode.Open, Access = FileAccess.Read, Share = FileShare.Read, Options = FileOptions.None }; Debug.Assert(entry._header._dataStream == null); entry._header._dataStream = File.Open(fullPath, options); } WriteEntry(entry); if (entry._header._dataStream != null) { entry._header._dataStream.Dispose(); } } }