Skip to content

Commit

Permalink
Improve API for archived file attributes.
Browse files Browse the repository at this point in the history
  • Loading branch information
weltkante committed Jan 7, 2016
1 parent e4508eb commit 543ecf1
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 160 deletions.
28 changes: 5 additions & 23 deletions sandbox-7z/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.Threading.Tasks;
using System.Windows.Forms;
using ManagedLzma.LZMA.Master.SevenZip;
using ManagedLzma.SevenZip;
using ManagedLzma.SevenZip.FileModel;

namespace sandbox_7z
{
Expand Down Expand Up @@ -276,31 +278,11 @@ private static void SetFileAttributes(string path, ManagedLzma.SevenZip.FileMode
{
if (file.Attributes.HasValue)
{
// Not all attributes make sense to restore.
// - 'Directory' attribute - can't be changed by setting the attribute (and should already be correct anyways)
// - 'Device' attribute - not supported by 7z archives, we don't have enough data to restore this attribute
// - 'Normal' attribute - that attribute has special meaning for file creation and shouldn't appear in an archive
// - 'Temporary' attribute - while this attribute may happen to be set it makes no sense to restore it; your opinion may differ, so include it if you think that its needed, but make sure you know how Windows handles the attribute and test it properly!
// - 'SparseFile' attribute - sparse files require additional handling, just setting the attribute makes no sense
// - 'ReparsePoint' attribute - not supported by 7z archives, we don't have enough data to restore this attribute
// - 'Offline' attribute - I don't know how exactly this attribute works, but I think it is set by the OS and not supposed to be set by applications
// - 'IntegrityStream' attribute - not supported by 7z archives, we don't have enough data to restore this attribute
// - 'NoScrubData' attribute - no idea what that means, better not mess with it

// TODO: follow up with an actual list of attributes supported by the reference implementation
// maybe we should make our own enum (providing conversions to/from FileAttributes enum)

const FileAttributes kAttrMask = default(FileAttributes)
| FileAttributes.Archive
| FileAttributes.ReadOnly
| FileAttributes.Hidden
//| FileAttributes.System -- not tested but probably would work
//| FileAttributes.Compressed -- not tested if it is enough to just set the attribute
//| FileAttributes.NotContentIndexed -- not tested but from the description it may make sense to restore it
;
// When calling File.SetAttributes we need to preserve existing attributes which are not part of the archive

var attr = File.GetAttributes(path);
attr = (attr & ~kAttrMask) | (file.Attributes.Value & kAttrMask);
const FileAttributes kAttrMask = ArchivedAttributesExtensions.FileAttributeMask;
attr = (attr & ~kAttrMask) | (file.Attributes.Value.ToFileAttributes() & kAttrMask);
File.SetAttributes(path, attr);
}
}
Expand Down
19 changes: 13 additions & 6 deletions shared/SevenZip/ArchiveFileModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public sealed class ArchivedFile : ArchivedItem
public long Offset { get; set; }
public long Length { get; set; }
public Checksum? Checksum { get; set; }
public FileAttributes? Attributes { get; set; }
public ArchivedAttributes? Attributes { get; set; }
public DateTime? Creation { get; set; }
public DateTime? LastWrite { get; set; }
public DateTime? LastAccess { get; set; }
Expand Down Expand Up @@ -132,12 +132,12 @@ public Builder(ArchivedFile original)
public long Offset { get; }
public long Length { get; }
public Checksum? Checksum { get; }
public FileAttributes? Attributes { get; }
public ArchivedAttributes? Attributes { get; }
public DateTime? Creation { get; }
public DateTime? LastWrite { get; }
public DateTime? LastAccess { get; }

public ArchivedFile(string FullName, string Name, DecodedStreamIndex Stream, long Offset, long Length, Checksum? Checksum, FileAttributes? Attributes, DateTime? Creation, DateTime? LastWrite, DateTime? LastAccess)
public ArchivedFile(string FullName, string Name, DecodedStreamIndex Stream, long Offset, long Length, Checksum? Checksum, ArchivedAttributes? Attributes, DateTime? Creation, DateTime? LastWrite, DateTime? LastAccess)
: base(FullName, Name)
{
this.Stream = Stream;
Expand Down Expand Up @@ -216,7 +216,7 @@ public sealed class ArchiveFileModelMetadataReader : ArchiveMetadataReader
private List<bool> mEmptyFileMarkers;
private List<bool> mDeletionMarkers;
private List<long?> mOffsets;
private List<FileAttributes?> mAttributes;
private List<ArchivedAttributes?> mAttributes;
private List<DateTime?> mCDates;
private List<DateTime?> mMDates;
private List<DateTime?> mADates;
Expand Down Expand Up @@ -296,7 +296,14 @@ public ArchiveFileModel ReadMetadata(Stream stream, PasswordStorage password)
file.Offset = mOffsets[currentFileIndex] ?? 0;

if (mAttributes != null)
file.Attributes = mAttributes[currentFileIndex];
{
var attr = mAttributes[currentFileIndex];

if (attr.HasValue && (attr.Value & ArchivedAttributesExtensions.DirectoryAttribute) != 0)
throw new InvalidDataException();

file.Attributes = attr;
}

if (mCDates != null)
file.Creation = mCDates[currentFileIndex];
Expand Down Expand Up @@ -548,7 +555,7 @@ protected override void ReadAttributes(MetadataAttributeReader data)
System.Diagnostics.Debug.Assert(mAttributes == null);
System.Diagnostics.Debug.Assert(data.Count == mItemCount);

mAttributes = new List<FileAttributes?>(data.Count);
mAttributes = new List<ArchivedAttributes?>(data.Count);
for (int i = 0; i < data.Count; i++)
mAttributes.Add(data.ReadAttributes());
}
Expand Down
12 changes: 9 additions & 3 deletions shared/SevenZip/ArchiveMetadataDataReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ internal void Complete()
public int Count => mCount;
public int Index => mIndex;

public System.IO.FileAttributes? ReadAttributes()
public ArchivedAttributes? ReadAttributes()
{
if (mReader == null)
throw new ObjectDisposedException(null);
Expand All @@ -177,9 +177,15 @@ internal void Complete()

if (mVector[mIndex])
{
var number = mReader.ReadInt32Internal();
var attr = (ArchivedAttributes)mReader.ReadInt32Internal();
mIndex += 1;
return (System.IO.FileAttributes)number;

if ((attr & ArchivedAttributesExtensions.InvalidAttributes) != 0)
throw new System.IO.InvalidDataException();

attr &= ~(ArchivedAttributesExtensions.ForbiddenAttributes | ArchivedAttributesExtensions.StrippedAttributes);

return attr;
}
else
{
Expand Down
7 changes: 7 additions & 0 deletions shared/SevenZip/ArchiveMetadataReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ public abstract class ArchiveMetadataReader
{
#region Static Methods

#if DEBUG
static ArchiveMetadataReader()
{
ArchivedAttributesExtensions.CheckArchivedAttributesConsistency();
}
#endif

/// <summary>Checks if the stream looks like a 7z archive.</summary>
public static bool CheckFileHeader(Stream stream)
{
Expand Down
64 changes: 43 additions & 21 deletions shared/SevenZip/ArchiveWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ namespace ManagedLzma.SevenZip.Writer

public sealed class ArchiveWriter : IDisposable
{
#if DEBUG
static ArchiveWriter()
{
ArchivedAttributesExtensions.CheckArchivedAttributesConsistency();
}
#endif

private static void PutInt32(byte[] buffer, int offset, int value)
{
buffer[offset] = (byte)value;
Expand Down Expand Up @@ -789,7 +796,7 @@ public abstract class ArchiveMetadataProvider
public abstract bool IsDeleted(int index);
public abstract long GetLength(int index);
public abstract Checksum? GetChecksum(int index);
public abstract FileAttributes? GetAttributes(int index);
public abstract ArchivedAttributes? GetAttributes(int index);
public abstract DateTime? GetCreationDate(int index);
public abstract DateTime? GetLastWriteDate(int index);
public abstract DateTime? GetLastAccessDate(int index);
Expand All @@ -805,7 +812,7 @@ private struct Entry
public bool IsDeleted;
public long Length;
public Checksum? Checksum;
public FileAttributes? Attributes;
public ArchivedAttributes? Attributes;
public DateTime? CreationDate;
public DateTime? LastWriteDate;
public DateTime? LastAccessDate;
Expand Down Expand Up @@ -866,35 +873,28 @@ private void CheckName(ref string name)
}
}

private void CheckAttributes(ref FileAttributes? attr, bool isFile)
private void CheckAttributes(ref ArchivedAttributes? attr, bool isFile)
{
Utilities.NeedsBetterImplementation();

if (attr.HasValue)
{
if (isFile)
{
if ((attr.Value & FileAttributes.Directory) != 0)
if ((attr.Value & ArchivedAttributesExtensions.DirectoryAttribute) != 0)
throw new InvalidOperationException("Directory attribute cannot be set on a file.");
}
else
{
// TODO: should we auto-add the directory attribute here?
attr = attr.Value | FileAttributes.Directory;
// Automatically add the directory attribute for directories.
attr = attr.Value | ArchivedAttributesExtensions.DirectoryAttribute;
}

const FileAttributes kSupported = default(FileAttributes)
| FileAttributes.Directory
| FileAttributes.Archive
| FileAttributes.ReadOnly
| FileAttributes.Hidden
//| FileAttributes.System
//| FileAttributes.Compressed
| FileAttributes.NotContentIndexed
;

if ((attr.Value & ~kSupported) != 0)
throw new NotImplementedException("Some file attributes you passed are not handled. You can work around this exception by filtering them out manually.");
if ((attr & ArchivedAttributesExtensions.InvalidAttributes) != 0)
throw new InvalidOperationException("Invalid attributes have been set.");

if ((attr & ArchivedAttributesExtensions.ForbiddenAttributes) != 0)
throw new InvalidOperationException("Some attributes are set which should not be present in a 7z archive.");

attr = attr.Value & ~ArchivedAttributesExtensions.StrippedAttributes;
}
}

Expand All @@ -920,7 +920,18 @@ private void CheckDate(ref DateTime? date)
}
}

#if !(BUILD_PORTABLE && NET_45)
public void AppendFile(string name, long length, Checksum? checksum, FileAttributes? attributes, DateTime? creationDate, DateTime? lastWriteDate, DateTime? lastAccessDate)
{
var translatedAttributes = default(ArchivedAttributes?);
if (attributes.HasValue)
translatedAttributes = (ArchivedAttributes)(int)attributes.Value;

AppendFile(name, length, checksum, translatedAttributes, creationDate, lastWriteDate, lastAccessDate);
}
#endif

public void AppendFile(string name, long length, Checksum? checksum, ArchivedAttributes? attributes, DateTime? creationDate, DateTime? lastWriteDate, DateTime? lastAccessDate)
{
if (length < 0)
throw new ArgumentOutOfRangeException(nameof(length));
Expand All @@ -947,7 +958,18 @@ public void AppendFile(string name, long length, Checksum? checksum, FileAttribu
});
}

#if !(BUILD_PORTABLE && NET_45)
public void AppendDirectory(string name, FileAttributes? attributes, DateTime? creationDate, DateTime? lastWriteDate, DateTime? lastAccessDate)
{
var translatedAttributes = default(ArchivedAttributes?);
if (attributes.HasValue)
translatedAttributes = (ArchivedAttributes)(int)attributes.Value;

AppendDirectory(name, translatedAttributes, creationDate, lastWriteDate, lastAccessDate);
}
#endif

public void AppendDirectory(string name, ArchivedAttributes? attributes, DateTime? creationDate, DateTime? lastWriteDate, DateTime? lastAccessDate)
{
CheckName(ref name);
CheckAttributes(ref attributes, false);
Expand Down Expand Up @@ -994,7 +1016,7 @@ public void AppendDirectoryDeletion(string name)
public override bool IsDeleted(int index) => mEntries[index].IsDeleted;
public override long GetLength(int index) => mEntries[index].Length;
public override Checksum? GetChecksum(int index) => mEntries[index].Checksum;
public override FileAttributes? GetAttributes(int index) => mEntries[index].Attributes;
public override ArchivedAttributes? GetAttributes(int index) => mEntries[index].Attributes;
public override DateTime? GetCreationDate(int index) => mEntries[index].CreationDate;
public override DateTime? GetLastWriteDate(int index) => mEntries[index].LastWriteDate;
public override DateTime? GetLastAccessDate(int index) => mEntries[index].LastAccessDate;
Expand Down
Loading

0 comments on commit 543ecf1

Please sign in to comment.