initial checkin of yaulw (locally)
This commit is contained in:
654
@integrate/Trinet.Core.IO.Ntfs/AlternateDataStreamInfo.cs
Normal file
654
@integrate/Trinet.Core.IO.Ntfs/AlternateDataStreamInfo.cs
Normal file
@@ -0,0 +1,654 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace Trinet.Core.IO.Ntfs
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the details of an alternative data stream.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{FullPath}")]
|
||||
public sealed class AlternateDataStreamInfo : IEquatable<AlternateDataStreamInfo>
|
||||
{
|
||||
#region Private Data
|
||||
|
||||
private readonly string _fullPath;
|
||||
private readonly string _filePath;
|
||||
private readonly string _streamName;
|
||||
private readonly FileStreamType _streamType;
|
||||
private readonly FileStreamAttributes _attributes;
|
||||
private readonly long _size;
|
||||
private readonly bool _exists;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AlternateDataStreamInfo"/> class.
|
||||
/// </summary>
|
||||
/// <param name="filePath">
|
||||
/// The full path of the file.
|
||||
/// This argument must not be <see langword="null"/>.
|
||||
/// </param>
|
||||
/// <param name="info">
|
||||
/// The <see cref="SafeNativeMethods.Win32StreamInfo"/> containing the stream information.
|
||||
/// </param>
|
||||
internal AlternateDataStreamInfo(string filePath, SafeNativeMethods.Win32StreamInfo info)
|
||||
{
|
||||
_filePath = filePath;
|
||||
_streamName = info.StreamName;
|
||||
_streamType = info.StreamType;
|
||||
_attributes = info.StreamAttributes;
|
||||
_size = info.StreamSize;
|
||||
_exists = true;
|
||||
|
||||
_fullPath = SafeNativeMethods.BuildStreamPath(_filePath, _streamName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AlternateDataStreamInfo"/> class.
|
||||
/// </summary>
|
||||
/// <param name="filePath">
|
||||
/// The full path of the file.
|
||||
/// This argument must not be <see langword="null"/>.
|
||||
/// </param>
|
||||
/// <param name="streamName">
|
||||
/// The name of the stream
|
||||
/// This argument must not be <see langword="null"/>.
|
||||
/// </param>
|
||||
/// <param name="fullPath">
|
||||
/// The full path of the stream.
|
||||
/// If this argument is <see langword="null"/>, it will be generated from the
|
||||
/// <paramref name="filePath"/> and <paramref name="streamName"/> arguments.
|
||||
/// </param>
|
||||
/// <param name="exists">
|
||||
/// <see langword="true"/> if the stream exists;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </param>
|
||||
internal AlternateDataStreamInfo(string filePath, string streamName, string fullPath, bool exists)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fullPath)) fullPath = SafeNativeMethods.BuildStreamPath(filePath, streamName);
|
||||
_streamType = FileStreamType.AlternateDataStream;
|
||||
|
||||
_filePath = filePath;
|
||||
_streamName = streamName;
|
||||
_fullPath = fullPath;
|
||||
_exists = exists;
|
||||
|
||||
if (_exists)
|
||||
{
|
||||
_size = SafeNativeMethods.GetFileSize(_fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Returns the full path of this stream.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The full path of this stream.
|
||||
/// </value>
|
||||
public string FullPath
|
||||
{
|
||||
get { return _fullPath; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the full path of the file which contains the stream.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The full file-system path of the file which contains the stream.
|
||||
/// </value>
|
||||
public string FilePath
|
||||
{
|
||||
get { return _filePath; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the name of the stream.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The name of the stream.
|
||||
/// </value>
|
||||
public string Name
|
||||
{
|
||||
get { return _streamName; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a flag indicating whether the specified stream exists.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <see langword="true"/> if the stream exists;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </value>
|
||||
public bool Exists
|
||||
{
|
||||
get { return _exists; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the size of the stream, in bytes.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The size of the stream, in bytes.
|
||||
/// </value>
|
||||
public long Size
|
||||
{
|
||||
get { return _size; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the type of data.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// One of the <see cref="FileStreamType"/> values.
|
||||
/// </value>
|
||||
[EditorBrowsable(EditorBrowsableState.Advanced)]
|
||||
public FileStreamType StreamType
|
||||
{
|
||||
get { return _streamType; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns attributes of the data stream.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A combination of <see cref="FileStreamAttributes"/> values.
|
||||
/// </value>
|
||||
[EditorBrowsable(EditorBrowsableState.Advanced)]
|
||||
public FileStreamAttributes Attributes
|
||||
{
|
||||
get { return _attributes; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
#region -IEquatable
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="String"/> that represents the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="String"/> that represents the current instance.
|
||||
/// </returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return this.FullPath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serves as a hash function for a particular type.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A hash code for the current <see cref="Object"/>.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var comparer = StringComparer.OrdinalIgnoreCase;
|
||||
return comparer.GetHashCode(_filePath ?? string.Empty)
|
||||
^ comparer.GetHashCode(_streamName ?? string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current object is equal to another object of the same type.
|
||||
/// </summary>
|
||||
/// <param name="obj">
|
||||
/// An object to compare with this object.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the current object is equal to the <paramref name="obj"/> parameter;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (object.ReferenceEquals(null, obj)) return false;
|
||||
if (object.ReferenceEquals(this, obj)) return true;
|
||||
|
||||
AlternateDataStreamInfo other = obj as AlternateDataStreamInfo;
|
||||
if (!object.ReferenceEquals(null, other)) return this.Equals(other);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether
|
||||
/// this instance is equal to another instance.
|
||||
/// </summary>
|
||||
/// <param name="other">
|
||||
/// The instance to compare to.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the current object is equal to the <paramref name="other"/> parameter;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public bool Equals(AlternateDataStreamInfo other)
|
||||
{
|
||||
if (object.ReferenceEquals(null, other)) return false;
|
||||
if (object.ReferenceEquals(this, other)) return true;
|
||||
|
||||
var comparer = StringComparer.OrdinalIgnoreCase;
|
||||
return comparer.Equals(this._filePath ?? string.Empty, other._filePath ?? string.Empty)
|
||||
&& comparer.Equals(this._streamName ?? string.Empty, other._streamName ?? string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The equality operator.
|
||||
/// </summary>
|
||||
/// <param name="first">
|
||||
/// The first object.
|
||||
/// </param>
|
||||
/// <param name="second">
|
||||
/// The second object.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the two objects are equal;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public static bool operator ==(AlternateDataStreamInfo first, AlternateDataStreamInfo second)
|
||||
{
|
||||
if (object.ReferenceEquals(first, second)) return true;
|
||||
if (object.ReferenceEquals(null, first)) return false;
|
||||
if (object.ReferenceEquals(null, second)) return false;
|
||||
return first.Equals(second);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The inequality operator.
|
||||
/// </summary>
|
||||
/// <param name="first">
|
||||
/// The first object.
|
||||
/// </param>
|
||||
/// <param name="second">
|
||||
/// The second object.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the two objects are not equal;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
public static bool operator !=(AlternateDataStreamInfo first, AlternateDataStreamInfo second)
|
||||
{
|
||||
if (object.ReferenceEquals(first, second)) return false;
|
||||
if (object.ReferenceEquals(null, first)) return true;
|
||||
if (object.ReferenceEquals(null, second)) return true;
|
||||
return !first.Equals(second);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region -Delete
|
||||
|
||||
/// <summary>
|
||||
/// Deletes this stream from the parent file.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the stream was deleted;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission, or the file is read-only.
|
||||
/// </exception>
|
||||
/// <exception cref="IOException">
|
||||
/// The specified file is in use.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// The path of the stream is invalid.
|
||||
/// </exception>
|
||||
public bool Delete()
|
||||
{
|
||||
const FileIOPermissionAccess permAccess = FileIOPermissionAccess.Write;
|
||||
new FileIOPermission(permAccess, _filePath).Demand();
|
||||
return SafeNativeMethods.SafeDeleteFile(this.FullPath);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region -Open
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the access to demand.
|
||||
/// </summary>
|
||||
/// <param name="mode">
|
||||
/// The <see cref="FileMode"/>.
|
||||
/// </param>
|
||||
/// <param name="access">
|
||||
/// The <see cref="FileAccess"/>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="FileIOPermissionAccess"/>.
|
||||
/// </returns>
|
||||
private static FileIOPermissionAccess CalculateAccess(FileMode mode, FileAccess access)
|
||||
{
|
||||
FileIOPermissionAccess permAccess = FileIOPermissionAccess.NoAccess;
|
||||
switch (mode)
|
||||
{
|
||||
case FileMode.Append:
|
||||
permAccess = FileIOPermissionAccess.Append;
|
||||
break;
|
||||
|
||||
case FileMode.Create:
|
||||
case FileMode.CreateNew:
|
||||
case FileMode.OpenOrCreate:
|
||||
case FileMode.Truncate:
|
||||
permAccess = FileIOPermissionAccess.Write;
|
||||
break;
|
||||
|
||||
case FileMode.Open:
|
||||
permAccess = FileIOPermissionAccess.Read;
|
||||
break;
|
||||
}
|
||||
switch (access)
|
||||
{
|
||||
case FileAccess.ReadWrite:
|
||||
permAccess |= FileIOPermissionAccess.Write;
|
||||
permAccess |= FileIOPermissionAccess.Read;
|
||||
break;
|
||||
|
||||
case FileAccess.Write:
|
||||
permAccess |= FileIOPermissionAccess.Write;
|
||||
break;
|
||||
|
||||
case FileAccess.Read:
|
||||
permAccess |= FileIOPermissionAccess.Read;
|
||||
break;
|
||||
}
|
||||
|
||||
return permAccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens this alternate data stream.
|
||||
/// </summary>
|
||||
/// <param name="mode">
|
||||
/// A <see cref="FileMode"/> value that specifies whether a stream is created if one does not exist,
|
||||
/// and determines whether the contents of existing streams are retained or overwritten.
|
||||
/// </param>
|
||||
/// <param name="access">
|
||||
/// A <see cref="FileAccess"/> value that specifies the operations that can be performed on the stream.
|
||||
/// </param>
|
||||
/// <param name="share">
|
||||
/// A <see cref="FileShare"/> value specifying the type of access other threads have to the file.
|
||||
/// </param>
|
||||
/// <param name="bufferSize">
|
||||
/// The size of the buffer to use.
|
||||
/// </param>
|
||||
/// <param name="useAsync">
|
||||
/// <see langword="true"/> to enable async-IO;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="FileStream"/> for this alternate data stream.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="bufferSize"/> is less than or equal to zero.
|
||||
/// </exception>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission, or the file is read-only.
|
||||
/// </exception>
|
||||
/// <exception cref="IOException">
|
||||
/// The specified file is in use.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// The path of the stream is invalid.
|
||||
/// </exception>
|
||||
/// <exception cref="Win32Exception">
|
||||
/// There was an error opening the stream.
|
||||
/// </exception>
|
||||
public FileStream Open(FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync)
|
||||
{
|
||||
if (0 >= bufferSize) throw new ArgumentOutOfRangeException("bufferSize", bufferSize, null);
|
||||
|
||||
FileIOPermissionAccess permAccess = CalculateAccess(mode, access);
|
||||
new FileIOPermission(permAccess, _filePath).Demand();
|
||||
|
||||
SafeNativeMethods.NativeFileFlags flags = useAsync ? SafeNativeMethods.NativeFileFlags.Overlapped : 0;
|
||||
var handle = SafeNativeMethods.SafeCreateFile(this.FullPath, access.ToNative(), share, IntPtr.Zero, mode, flags, IntPtr.Zero);
|
||||
if (handle.IsInvalid) SafeNativeMethods.ThrowLastIOError(this.FullPath);
|
||||
return new FileStream(handle, access, bufferSize, useAsync);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens this alternate data stream.
|
||||
/// </summary>
|
||||
/// <param name="mode">
|
||||
/// A <see cref="FileMode"/> value that specifies whether a stream is created if one does not exist,
|
||||
/// and determines whether the contents of existing streams are retained or overwritten.
|
||||
/// </param>
|
||||
/// <param name="access">
|
||||
/// A <see cref="FileAccess"/> value that specifies the operations that can be performed on the stream.
|
||||
/// </param>
|
||||
/// <param name="share">
|
||||
/// A <see cref="FileShare"/> value specifying the type of access other threads have to the file.
|
||||
/// </param>
|
||||
/// <param name="bufferSize">
|
||||
/// The size of the buffer to use.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="FileStream"/> for this alternate data stream.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="bufferSize"/> is less than or equal to zero.
|
||||
/// </exception>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission, or the file is read-only.
|
||||
/// </exception>
|
||||
/// <exception cref="IOException">
|
||||
/// The specified file is in use.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// The path of the stream is invalid.
|
||||
/// </exception>
|
||||
/// <exception cref="Win32Exception">
|
||||
/// There was an error opening the stream.
|
||||
/// </exception>
|
||||
public FileStream Open(FileMode mode, FileAccess access, FileShare share, int bufferSize)
|
||||
{
|
||||
return this.Open(mode, access, share, bufferSize, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens this alternate data stream.
|
||||
/// </summary>
|
||||
/// <param name="mode">
|
||||
/// A <see cref="FileMode"/> value that specifies whether a stream is created if one does not exist,
|
||||
/// and determines whether the contents of existing streams are retained or overwritten.
|
||||
/// </param>
|
||||
/// <param name="access">
|
||||
/// A <see cref="FileAccess"/> value that specifies the operations that can be performed on the stream.
|
||||
/// </param>
|
||||
/// <param name="share">
|
||||
/// A <see cref="FileShare"/> value specifying the type of access other threads have to the file.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="FileStream"/> for this alternate data stream.
|
||||
/// </returns>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission, or the file is read-only.
|
||||
/// </exception>
|
||||
/// <exception cref="IOException">
|
||||
/// The specified file is in use.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// The path of the stream is invalid.
|
||||
/// </exception>
|
||||
/// <exception cref="Win32Exception">
|
||||
/// There was an error opening the stream.
|
||||
/// </exception>
|
||||
public FileStream Open(FileMode mode, FileAccess access, FileShare share)
|
||||
{
|
||||
return this.Open(mode, access, share, SafeNativeMethods.DefaultBufferSize, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens this alternate data stream.
|
||||
/// </summary>
|
||||
/// <param name="mode">
|
||||
/// A <see cref="FileMode"/> value that specifies whether a stream is created if one does not exist,
|
||||
/// and determines whether the contents of existing streams are retained or overwritten.
|
||||
/// </param>
|
||||
/// <param name="access">
|
||||
/// A <see cref="FileAccess"/> value that specifies the operations that can be performed on the stream.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="FileStream"/> for this alternate data stream.
|
||||
/// </returns>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission, or the file is read-only.
|
||||
/// </exception>
|
||||
/// <exception cref="IOException">
|
||||
/// The specified file is in use.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// The path of the stream is invalid.
|
||||
/// </exception>
|
||||
/// <exception cref="Win32Exception">
|
||||
/// There was an error opening the stream.
|
||||
/// </exception>
|
||||
public FileStream Open(FileMode mode, FileAccess access)
|
||||
{
|
||||
return this.Open(mode, access, FileShare.None, SafeNativeMethods.DefaultBufferSize, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens this alternate data stream.
|
||||
/// </summary>
|
||||
/// <param name="mode">
|
||||
/// A <see cref="FileMode"/> value that specifies whether a stream is created if one does not exist,
|
||||
/// and determines whether the contents of existing streams are retained or overwritten.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="FileStream"/> for this alternate data stream.
|
||||
/// </returns>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission, or the file is read-only.
|
||||
/// </exception>
|
||||
/// <exception cref="IOException">
|
||||
/// The specified file is in use.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// The path of the stream is invalid.
|
||||
/// </exception>
|
||||
/// <exception cref="Win32Exception">
|
||||
/// There was an error opening the stream.
|
||||
/// </exception>
|
||||
public FileStream Open(FileMode mode)
|
||||
{
|
||||
FileAccess access = (FileMode.Append == mode) ? FileAccess.Write : FileAccess.ReadWrite;
|
||||
return this.Open(mode, access, FileShare.None, SafeNativeMethods.DefaultBufferSize, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region -OpenRead / OpenWrite / OpenText
|
||||
|
||||
/// <summary>
|
||||
/// Opens this stream for reading.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A read-only <see cref="FileStream"/> for this stream.
|
||||
/// </returns>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission, or the file is read-only.
|
||||
/// </exception>
|
||||
/// <exception cref="IOException">
|
||||
/// The specified file is in use.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// The path of the stream is invalid.
|
||||
/// </exception>
|
||||
/// <exception cref="Win32Exception">
|
||||
/// There was an error opening the stream.
|
||||
/// </exception>
|
||||
public FileStream OpenRead()
|
||||
{
|
||||
return this.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens this stream for writing.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A write-only <see cref="FileStream"/> for this stream.
|
||||
/// </returns>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission, or the file is read-only.
|
||||
/// </exception>
|
||||
/// <exception cref="IOException">
|
||||
/// The specified file is in use.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// The path of the stream is invalid.
|
||||
/// </exception>
|
||||
/// <exception cref="Win32Exception">
|
||||
/// There was an error opening the stream.
|
||||
/// </exception>
|
||||
public FileStream OpenWrite()
|
||||
{
|
||||
return this.Open(FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens this stream as a text file.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="StreamReader"/> which can be used to read the contents of this stream.
|
||||
/// </returns>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission, or the file is read-only.
|
||||
/// </exception>
|
||||
/// <exception cref="IOException">
|
||||
/// The specified file is in use.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// The path of the stream is invalid.
|
||||
/// </exception>
|
||||
/// <exception cref="Win32Exception">
|
||||
/// There was an error opening the stream.
|
||||
/// </exception>
|
||||
public StreamReader OpenText()
|
||||
{
|
||||
Stream fileStream = this.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
return new StreamReader(fileStream);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
32
@integrate/Trinet.Core.IO.Ntfs/FileStreamAttributes.cs
Normal file
32
@integrate/Trinet.Core.IO.Ntfs/FileStreamAttributes.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
|
||||
namespace Trinet.Core.IO.Ntfs
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the attributes of a file stream.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum FileStreamAttributes
|
||||
{
|
||||
/// <summary>
|
||||
/// No attributes.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
/// <summary>
|
||||
/// Set if the stream contains data that is modified when read.
|
||||
/// </summary>
|
||||
ModifiedWhenRead = 1,
|
||||
/// <summary>
|
||||
/// Set if the stream contains security data.
|
||||
/// </summary>
|
||||
ContainsSecurity = 2,
|
||||
/// <summary>
|
||||
/// Set if the stream contains properties.
|
||||
/// </summary>
|
||||
ContainsProperties = 4,
|
||||
/// <summary>
|
||||
/// Set if the stream is sparse.
|
||||
/// </summary>
|
||||
Sparse = 8,
|
||||
}
|
||||
}
|
||||
56
@integrate/Trinet.Core.IO.Ntfs/FileStreamType.cs
Normal file
56
@integrate/Trinet.Core.IO.Ntfs/FileStreamType.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
|
||||
namespace Trinet.Core.IO.Ntfs
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the type of data in a stream.
|
||||
/// </summary>
|
||||
public enum FileStreamType
|
||||
{
|
||||
/// <summary>
|
||||
/// Unknown stream type.
|
||||
/// </summary>
|
||||
Unknown = 0,
|
||||
/// <summary>
|
||||
/// Standard data.
|
||||
/// </summary>
|
||||
Data = 1,
|
||||
/// <summary>
|
||||
/// Extended attribute data.
|
||||
/// </summary>
|
||||
ExtendedAttributes = 2,
|
||||
/// <summary>
|
||||
/// Security data.
|
||||
/// </summary>
|
||||
SecurityData = 3,
|
||||
/// <summary>
|
||||
/// Alternate data stream.
|
||||
/// </summary>
|
||||
AlternateDataStream = 4,
|
||||
/// <summary>
|
||||
/// Hard link information.
|
||||
/// </summary>
|
||||
Link = 5,
|
||||
/// <summary>
|
||||
/// Property data.
|
||||
/// </summary>
|
||||
PropertyData = 6,
|
||||
/// <summary>
|
||||
/// Object identifiers.
|
||||
/// </summary>
|
||||
ObjectId = 7,
|
||||
/// <summary>
|
||||
/// Reparse points.
|
||||
/// </summary>
|
||||
ReparseData = 8,
|
||||
/// <summary>
|
||||
/// Sparse file.
|
||||
/// </summary>
|
||||
SparseBlock = 9,
|
||||
/// <summary>
|
||||
/// Transactional data.
|
||||
/// (Undocumented - BACKUP_TXFS_DATA)
|
||||
/// </summary>
|
||||
TransactionData = 10,
|
||||
}
|
||||
}
|
||||
452
@integrate/Trinet.Core.IO.Ntfs/FileSystem.cs
Normal file
452
@integrate/Trinet.Core.IO.Ntfs/FileSystem.cs
Normal file
@@ -0,0 +1,452 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace Trinet.Core.IO.Ntfs
|
||||
{
|
||||
using Resources = Properties.Resources;
|
||||
|
||||
/// <summary>
|
||||
/// File-system utilities.
|
||||
/// </summary>
|
||||
public static class FileSystem
|
||||
{
|
||||
#region Create FileSystemInfo
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="FileSystemInfo"/> for the specified path.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// The path of the file or directory.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="FileSystemInfo"/> representing the file or directory.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path"/> is <see langword="null"/> or empty.
|
||||
/// </exception>
|
||||
private static FileSystemInfo CreateInfo(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path)) throw new ArgumentNullException("path");
|
||||
|
||||
path = Path.GetFullPath(path);
|
||||
if (!File.Exists(path) && Directory.Exists(path)) return new DirectoryInfo(path);
|
||||
return new FileInfo(path);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region List Streams
|
||||
|
||||
/// <summary>
|
||||
/// <span style="font-weight:bold;color:#a00;">(Extension Method)</span><br />
|
||||
/// Returns a read-only list of alternate data streams for the specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// The <see cref="FileSystemInfo"/> to inspect.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A read-only list of <see cref="AlternateDataStreamInfo"/> objects
|
||||
/// representing the alternate data streams for the specified file, if any.
|
||||
/// If no streams are found, returns an empty list.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="FileNotFoundException">
|
||||
/// The specified <paramref name="file"/> does not exist.
|
||||
/// </exception>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
public static IList<AlternateDataStreamInfo> ListAlternateDataStreams(this FileSystemInfo file)
|
||||
{
|
||||
if (null == file) throw new ArgumentNullException("file");
|
||||
if (!file.Exists) throw new FileNotFoundException(null, file.FullName);
|
||||
|
||||
string path = file.FullName;
|
||||
new FileIOPermission(FileIOPermissionAccess.Read, path).Demand();
|
||||
|
||||
return SafeNativeMethods.ListStreams(path)
|
||||
.Select(s => new AlternateDataStreamInfo(path, s))
|
||||
.ToList().AsReadOnly();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a read-only list of alternate data streams for the specified file.
|
||||
/// </summary>
|
||||
/// <param name="filePath">
|
||||
/// The full path of the file to inspect.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A read-only list of <see cref="AlternateDataStreamInfo"/> objects
|
||||
/// representing the alternate data streams for the specified file, if any.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="filePath"/> is <see langword="null"/> or an empty string.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// <paramref name="filePath"/> is not a valid file path.
|
||||
/// </exception>
|
||||
/// <exception cref="FileNotFoundException">
|
||||
/// The specified <paramref name="filePath"/> does not exist.
|
||||
/// </exception>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
public static IList<AlternateDataStreamInfo> ListAlternateDataStreams(string filePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException("filePath");
|
||||
return CreateInfo(filePath).ListAlternateDataStreams();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream Exists
|
||||
|
||||
/// <summary>
|
||||
/// <span style="font-weight:bold;color:#a00;">(Extension Method)</span><br />
|
||||
/// Returns a flag indicating whether the specified alternate data stream exists.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// The <see cref="FileInfo"/> to inspect.
|
||||
/// </param>
|
||||
/// <param name="streamName">
|
||||
/// The name of the stream to find.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the specified stream exists;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// <paramref name="streamName"/> contains invalid characters.
|
||||
/// </exception>
|
||||
public static bool AlternateDataStreamExists(this FileSystemInfo file, string streamName)
|
||||
{
|
||||
if (null == file) throw new ArgumentNullException("file");
|
||||
SafeNativeMethods.ValidateStreamName(streamName);
|
||||
|
||||
string path = SafeNativeMethods.BuildStreamPath(file.FullName, streamName);
|
||||
return -1 != SafeNativeMethods.SafeGetFileAttributes(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a flag indicating whether the specified alternate data stream exists.
|
||||
/// </summary>
|
||||
/// <param name="filePath">
|
||||
/// The path of the file to inspect.
|
||||
/// </param>
|
||||
/// <param name="streamName">
|
||||
/// The name of the stream to find.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the specified stream exists;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="filePath"/> is <see langword="null"/> or an empty string.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// <para><paramref name="filePath"/> is not a valid file path.</para>
|
||||
/// <para>-or-</para>
|
||||
/// <para><paramref name="streamName"/> contains invalid characters.</para>
|
||||
/// </exception>
|
||||
public static bool AlternateDataStreamExists(string filePath, string streamName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException("filePath");
|
||||
return CreateInfo(filePath).AlternateDataStreamExists(streamName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Open Stream
|
||||
|
||||
/// <summary>
|
||||
/// <span style="font-weight:bold;color:#a00;">(Extension Method)</span><br />
|
||||
/// Opens an alternate data stream.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// The <see cref="FileInfo"/> which contains the stream.
|
||||
/// </param>
|
||||
/// <param name="streamName">
|
||||
/// The name of the stream to open.
|
||||
/// </param>
|
||||
/// <param name="mode">
|
||||
/// One of the <see cref="FileMode"/> values, indicating how the stream is to be opened.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// An <see cref="AlternateDataStreamInfo"/> representing the stream.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="FileNotFoundException">
|
||||
/// The specified <paramref name="file"/> was not found.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// <paramref name="streamName"/> contains invalid characters.
|
||||
/// </exception>
|
||||
/// <exception cref="NotSupportedException">
|
||||
/// <paramref name="mode"/> is either <see cref="FileMode.Truncate"/> or <see cref="FileMode.Append"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="IOException">
|
||||
/// <para><paramref name="mode"/> is <see cref="FileMode.Open"/>, and the stream doesn't exist.</para>
|
||||
/// <para>-or-</para>
|
||||
/// <para><paramref name="mode"/> is <see cref="FileMode.CreateNew"/>, and the stream already exists.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission, or the file is read-only.
|
||||
/// </exception>
|
||||
public static AlternateDataStreamInfo GetAlternateDataStream(this FileSystemInfo file, string streamName, FileMode mode)
|
||||
{
|
||||
if (null == file) throw new ArgumentNullException("file");
|
||||
if (!file.Exists) throw new FileNotFoundException(null, file.FullName);
|
||||
SafeNativeMethods.ValidateStreamName(streamName);
|
||||
|
||||
if (FileMode.Truncate == mode || FileMode.Append == mode)
|
||||
{
|
||||
throw new NotSupportedException(string.Format(Resources.Culture,
|
||||
Resources.Error_InvalidMode, mode));
|
||||
}
|
||||
|
||||
FileIOPermissionAccess permAccess = (FileMode.Open == mode) ? FileIOPermissionAccess.Read : FileIOPermissionAccess.Read | FileIOPermissionAccess.Write;
|
||||
new FileIOPermission(permAccess, file.FullName).Demand();
|
||||
|
||||
string path = SafeNativeMethods.BuildStreamPath(file.FullName, streamName);
|
||||
bool exists = -1 != SafeNativeMethods.SafeGetFileAttributes(path);
|
||||
|
||||
if (!exists && FileMode.Open == mode)
|
||||
{
|
||||
throw new IOException(string.Format(Resources.Culture,
|
||||
Resources.Error_StreamNotFound, streamName, file.Name));
|
||||
}
|
||||
if (exists && FileMode.CreateNew == mode)
|
||||
{
|
||||
throw new IOException(string.Format(Resources.Culture,
|
||||
Resources.Error_StreamExists, streamName, file.Name));
|
||||
}
|
||||
|
||||
return new AlternateDataStreamInfo(file.FullName, streamName, path, exists);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <span style="font-weight:bold;color:#a00;">(Extension Method)</span><br />
|
||||
/// Opens an alternate data stream.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// The <see cref="FileInfo"/> which contains the stream.
|
||||
/// </param>
|
||||
/// <param name="streamName">
|
||||
/// The name of the stream to open.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// An <see cref="AlternateDataStreamInfo"/> representing the stream.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="FileNotFoundException">
|
||||
/// The specified <paramref name="file"/> was not found.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// <paramref name="streamName"/> contains invalid characters.
|
||||
/// </exception>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission, or the file is read-only.
|
||||
/// </exception>
|
||||
public static AlternateDataStreamInfo GetAlternateDataStream(this FileSystemInfo file, string streamName)
|
||||
{
|
||||
return file.GetAlternateDataStream(streamName, FileMode.OpenOrCreate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an alternate data stream.
|
||||
/// </summary>
|
||||
/// <param name="filePath">
|
||||
/// The path of the file which contains the stream.
|
||||
/// </param>
|
||||
/// <param name="streamName">
|
||||
/// The name of the stream to open.
|
||||
/// </param>
|
||||
/// <param name="mode">
|
||||
/// One of the <see cref="FileMode"/> values, indicating how the stream is to be opened.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// An <see cref="AlternateDataStreamInfo"/> representing the stream.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="filePath"/> is <see langword="null"/> or an empty string.
|
||||
/// </exception>
|
||||
/// <exception cref="FileNotFoundException">
|
||||
/// The specified <paramref name="filePath"/> was not found.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// <para><paramref name="filePath"/> is not a valid file path.</para>
|
||||
/// <para>-or-</para>
|
||||
/// <para><paramref name="streamName"/> contains invalid characters.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="NotSupportedException">
|
||||
/// <paramref name="mode"/> is either <see cref="FileMode.Truncate"/> or <see cref="FileMode.Append"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="IOException">
|
||||
/// <para><paramref name="mode"/> is <see cref="FileMode.Open"/>, and the stream doesn't exist.</para>
|
||||
/// <para>-or-</para>
|
||||
/// <para><paramref name="mode"/> is <see cref="FileMode.CreateNew"/>, and the stream already exists.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission, or the file is read-only.
|
||||
/// </exception>
|
||||
public static AlternateDataStreamInfo GetAlternateDataStream(string filePath, string streamName, FileMode mode)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException("filePath");
|
||||
return CreateInfo(filePath).GetAlternateDataStream(streamName, mode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an alternate data stream.
|
||||
/// </summary>
|
||||
/// <param name="filePath">
|
||||
/// The path of the file which contains the stream.
|
||||
/// </param>
|
||||
/// <param name="streamName">
|
||||
/// The name of the stream to open.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// An <see cref="AlternateDataStreamInfo"/> representing the stream.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="filePath"/> is <see langword="null"/> or an empty string.
|
||||
/// </exception>
|
||||
/// <exception cref="FileNotFoundException">
|
||||
/// The specified <paramref name="filePath"/> was not found.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// <para><paramref name="filePath"/> is not a valid file path.</para>
|
||||
/// <para>-or-</para>
|
||||
/// <para><paramref name="streamName"/> contains invalid characters.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission, or the file is read-only.
|
||||
/// </exception>
|
||||
public static AlternateDataStreamInfo GetAlternateDataStream(string filePath, string streamName)
|
||||
{
|
||||
return GetAlternateDataStream(filePath, streamName, FileMode.OpenOrCreate);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Delete Stream
|
||||
|
||||
/// <summary>
|
||||
/// <span style="font-weight:bold;color:#a00;">(Extension Method)</span><br />
|
||||
/// Deletes the specified alternate data stream if it exists.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// The <see cref="FileInfo"/> to inspect.
|
||||
/// </param>
|
||||
/// <param name="streamName">
|
||||
/// The name of the stream to delete.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the specified stream is deleted;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// <paramref name="streamName"/> contains invalid characters.
|
||||
/// </exception>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission, or the file is read-only.
|
||||
/// </exception>
|
||||
/// <exception cref="IOException">
|
||||
/// The specified file is in use.
|
||||
/// </exception>
|
||||
public static bool DeleteAlternateDataStream(this FileSystemInfo file, string streamName)
|
||||
{
|
||||
if (null == file) throw new ArgumentNullException("file");
|
||||
SafeNativeMethods.ValidateStreamName(streamName);
|
||||
|
||||
const FileIOPermissionAccess permAccess = FileIOPermissionAccess.Write;
|
||||
new FileIOPermission(permAccess, file.FullName).Demand();
|
||||
|
||||
var result = false;
|
||||
if (file.Exists)
|
||||
{
|
||||
string path = SafeNativeMethods.BuildStreamPath(file.FullName, streamName);
|
||||
if (-1 != SafeNativeMethods.SafeGetFileAttributes(path))
|
||||
{
|
||||
result = SafeNativeMethods.SafeDeleteFile(path);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the specified alternate data stream if it exists.
|
||||
/// </summary>
|
||||
/// <param name="filePath">
|
||||
/// The path of the file to inspect.
|
||||
/// </param>
|
||||
/// <param name="streamName">
|
||||
/// The name of the stream to find.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the specified stream is deleted;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="filePath"/> is <see langword="null"/> or an empty string.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// <para><paramref name="filePath"/> is not a valid file path.</para>
|
||||
/// <para>-or-</para>
|
||||
/// <para><paramref name="streamName"/> contains invalid characters.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="SecurityException">
|
||||
/// The caller does not have the required permission.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">
|
||||
/// The caller does not have the required permission, or the file is read-only.
|
||||
/// </exception>
|
||||
/// <exception cref="IOException">
|
||||
/// The specified file is in use.
|
||||
/// </exception>
|
||||
public static bool DeleteAlternateDataStream(string filePath, string streamName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException("filePath");
|
||||
return CreateInfo(filePath).DeleteAlternateDataStream(streamName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
118
@integrate/Trinet.Core.IO.Ntfs/SafeHGlobalHandle.cs
Normal file
118
@integrate/Trinet.Core.IO.Ntfs/SafeHGlobalHandle.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Trinet.Core.IO.Ntfs
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="SafeHandle"/> for a global memory allocation.
|
||||
/// </summary>
|
||||
internal sealed class SafeHGlobalHandle : SafeHandle
|
||||
{
|
||||
#region Private Data
|
||||
|
||||
private readonly int _size;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SafeHGlobalHandle"/> class.
|
||||
/// </summary>
|
||||
/// <param name="toManage">
|
||||
/// The initial handle value.
|
||||
/// </param>
|
||||
/// <param name="size">
|
||||
/// The size of this memory block, in bytes.
|
||||
/// </param>
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
private SafeHGlobalHandle(IntPtr toManage, int size) : base(IntPtr.Zero, true)
|
||||
{
|
||||
_size = size;
|
||||
base.SetHandle(toManage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SafeHGlobalHandle"/> class.
|
||||
/// </summary>
|
||||
private SafeHGlobalHandle() : base(IntPtr.Zero, true)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the handle value is invalid.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <see langword="true"/> if the handle value is invalid;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </value>
|
||||
public override bool IsInvalid
|
||||
{
|
||||
get { return IntPtr.Zero == base.handle; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the size of this memory block.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The size of this memory block, in bytes.
|
||||
/// </value>
|
||||
public int Size
|
||||
{
|
||||
get { return _size; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Allocates memory from the unmanaged memory of the process using GlobalAlloc.
|
||||
/// </summary>
|
||||
/// <param name="bytes">
|
||||
/// The number of bytes in memory required.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="SafeHGlobalHandle"/> representing the memory.
|
||||
/// </returns>
|
||||
/// <exception cref="OutOfMemoryException">
|
||||
/// There is insufficient memory to satisfy the request.
|
||||
/// </exception>
|
||||
public static SafeHGlobalHandle Allocate(int bytes)
|
||||
{
|
||||
return new SafeHGlobalHandle(Marshal.AllocHGlobal(bytes), bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an invalid handle.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// An invalid <see cref="SafeHGlobalHandle"/>.
|
||||
/// </returns>
|
||||
public static SafeHGlobalHandle Invalid()
|
||||
{
|
||||
return new SafeHGlobalHandle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the code required to free the handle.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the handle is released successfully;
|
||||
/// otherwise, in the event of a catastrophic failure, <see langword="false"/>.
|
||||
/// In this case, it generates a releaseHandleFailed MDA Managed Debugging Assistant.
|
||||
/// </returns>
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
Marshal.FreeHGlobal(base.handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
478
@integrate/Trinet.Core.IO.Ntfs/SafeNativeMethods.cs
Normal file
478
@integrate/Trinet.Core.IO.Ntfs/SafeNativeMethods.cs
Normal file
@@ -0,0 +1,478 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Trinet.Core.IO.Ntfs
|
||||
{
|
||||
using Resources = Properties.Resources;
|
||||
|
||||
/// <summary>
|
||||
/// Safe native methods.
|
||||
/// </summary>
|
||||
internal static class SafeNativeMethods
|
||||
{
|
||||
#region Constants and flags
|
||||
|
||||
public const int MaxPath = 256;
|
||||
private const string LongPathPrefix = @"\\?\";
|
||||
public const char StreamSeparator = ':';
|
||||
public const int DefaultBufferSize = 0x1000;
|
||||
|
||||
private const int ErrorFileNotFound = 2;
|
||||
|
||||
// "Characters whose integer representations are in the range from 1 through 31,
|
||||
// except for alternate streams where these characters are allowed"
|
||||
// http://msdn.microsoft.com/en-us/library/aa365247(v=VS.85).aspx
|
||||
private static readonly char[] InvalidStreamNameChars = Path.GetInvalidFileNameChars().Where(c => c < 1 || c > 31).ToArray();
|
||||
|
||||
[Flags]
|
||||
public enum NativeFileFlags : uint
|
||||
{
|
||||
WriteThrough = 0x80000000,
|
||||
Overlapped = 0x40000000,
|
||||
NoBuffering = 0x20000000,
|
||||
RandomAccess = 0x10000000,
|
||||
SequentialScan = 0x8000000,
|
||||
DeleteOnClose = 0x4000000,
|
||||
BackupSemantics = 0x2000000,
|
||||
PosixSemantics = 0x1000000,
|
||||
OpenReparsePoint = 0x200000,
|
||||
OpenNoRecall = 0x100000
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum NativeFileAccess : uint
|
||||
{
|
||||
GenericRead = 0x80000000,
|
||||
GenericWrite = 0x40000000
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region P/Invoke Structures
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct LargeInteger
|
||||
{
|
||||
public readonly int Low;
|
||||
public readonly int High;
|
||||
|
||||
public long ToInt64()
|
||||
{
|
||||
return (this.High * 0x100000000) + this.Low;
|
||||
}
|
||||
|
||||
/*
|
||||
public static LargeInteger FromInt64(long value)
|
||||
{
|
||||
return new LargeInteger
|
||||
{
|
||||
Low = (int)(value & 0x11111111),
|
||||
High = (int)((value / 0x100000000) & 0x11111111)
|
||||
};
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct Win32StreamId
|
||||
{
|
||||
public readonly int StreamId;
|
||||
public readonly int StreamAttributes;
|
||||
public LargeInteger Size;
|
||||
public readonly int StreamNameSize;
|
||||
}
|
||||
|
||||
/*
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct FileInformationByHandle
|
||||
{
|
||||
public int dwFileAttributes;
|
||||
public LargeInteger ftCreationTime;
|
||||
public LargeInteger ftLastAccessTime;
|
||||
public LargeInteger ftLastWriteTime;
|
||||
public int dwVolumeSerialNumber;
|
||||
public LargeInteger FileSize;
|
||||
public int nNumberOfLinks;
|
||||
public LargeInteger FileIndex;
|
||||
}
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region P/Invoke Methods
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
||||
private static extern int FormatMessage(
|
||||
int dwFlags,
|
||||
IntPtr lpSource,
|
||||
int dwMessageId,
|
||||
int dwLanguageId,
|
||||
StringBuilder lpBuffer,
|
||||
int nSize,
|
||||
IntPtr vaListArguments);
|
||||
|
||||
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
private static extern int GetFileAttributes(string fileName);
|
||||
|
||||
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool GetFileSizeEx(SafeFileHandle handle, out LargeInteger size);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern int GetFileType(SafeFileHandle handle);
|
||||
|
||||
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
private static extern SafeFileHandle CreateFile(
|
||||
string name,
|
||||
NativeFileAccess access,
|
||||
FileShare share,
|
||||
IntPtr security,
|
||||
FileMode mode,
|
||||
NativeFileFlags flags,
|
||||
IntPtr template);
|
||||
|
||||
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool DeleteFile(string name);
|
||||
|
||||
[DllImport("kernel32", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool BackupRead(
|
||||
SafeFileHandle hFile,
|
||||
ref Win32StreamId pBuffer,
|
||||
int numberOfBytesToRead,
|
||||
out int numberOfBytesRead,
|
||||
[MarshalAs(UnmanagedType.Bool)] bool abort,
|
||||
[MarshalAs(UnmanagedType.Bool)] bool processSecurity,
|
||||
ref IntPtr context);
|
||||
|
||||
[DllImport("kernel32", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool BackupRead(
|
||||
SafeFileHandle hFile,
|
||||
SafeHGlobalHandle pBuffer,
|
||||
int numberOfBytesToRead,
|
||||
out int numberOfBytesRead,
|
||||
[MarshalAs(UnmanagedType.Bool)] bool abort,
|
||||
[MarshalAs(UnmanagedType.Bool)] bool processSecurity,
|
||||
ref IntPtr context);
|
||||
|
||||
[DllImport("kernel32", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool BackupSeek(
|
||||
SafeFileHandle hFile,
|
||||
int bytesToSeekLow,
|
||||
int bytesToSeekHigh,
|
||||
out int bytesSeekedLow,
|
||||
out int bytesSeekedHigh,
|
||||
ref IntPtr context);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utility Structures
|
||||
|
||||
public struct Win32StreamInfo
|
||||
{
|
||||
public FileStreamType StreamType;
|
||||
public FileStreamAttributes StreamAttributes;
|
||||
public long StreamSize;
|
||||
public string StreamName;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utility Methods
|
||||
|
||||
private static int MakeHRFromErrorCode(int errorCode)
|
||||
{
|
||||
return (-2147024896 | errorCode);
|
||||
}
|
||||
|
||||
private static string GetErrorMessage(int errorCode)
|
||||
{
|
||||
var lpBuffer = new StringBuilder(0x200);
|
||||
if (0 != FormatMessage(0x3200, IntPtr.Zero, errorCode, 0, lpBuffer, lpBuffer.Capacity, IntPtr.Zero))
|
||||
{
|
||||
return lpBuffer.ToString();
|
||||
}
|
||||
|
||||
return string.Format(Resources.Culture, Resources.Error_UnknownError, errorCode);
|
||||
}
|
||||
|
||||
private static void ThrowIOError(int errorCode, string path)
|
||||
{
|
||||
switch (errorCode)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case 2: // File not found
|
||||
{
|
||||
if (string.IsNullOrEmpty(path)) throw new FileNotFoundException();
|
||||
throw new FileNotFoundException(null, path);
|
||||
}
|
||||
case 3: // Directory not found
|
||||
{
|
||||
if (string.IsNullOrEmpty(path)) throw new DirectoryNotFoundException();
|
||||
throw new DirectoryNotFoundException(string.Format(Resources.Culture, Resources.Error_DirectoryNotFound, path));
|
||||
}
|
||||
case 5: // Access denied
|
||||
{
|
||||
if (string.IsNullOrEmpty(path)) throw new UnauthorizedAccessException();
|
||||
throw new UnauthorizedAccessException(string.Format(Resources.Culture, Resources.Error_AccessDenied_Path, path));
|
||||
}
|
||||
case 15: // Drive not found
|
||||
{
|
||||
if (string.IsNullOrEmpty(path)) throw new DriveNotFoundException();
|
||||
throw new DriveNotFoundException(string.Format(Resources.Culture, Resources.Error_DriveNotFound, path));
|
||||
}
|
||||
case 32: // Sharing violation
|
||||
{
|
||||
if (string.IsNullOrEmpty(path)) throw new IOException(GetErrorMessage(errorCode), MakeHRFromErrorCode(errorCode));
|
||||
throw new IOException(string.Format(Resources.Culture, Resources.Error_SharingViolation, path), MakeHRFromErrorCode(errorCode));
|
||||
}
|
||||
case 80: // File already exists
|
||||
{
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new IOException(string.Format(Resources.Culture, Resources.Error_FileAlreadyExists, path), MakeHRFromErrorCode(errorCode));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 87: // Invalid parameter
|
||||
{
|
||||
throw new IOException(GetErrorMessage(errorCode), MakeHRFromErrorCode(errorCode));
|
||||
}
|
||||
case 183: // File or directory already exists
|
||||
{
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new IOException(string.Format(Resources.Culture, Resources.Error_AlreadyExists, path), MakeHRFromErrorCode(errorCode));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 206: // Path too long
|
||||
{
|
||||
throw new PathTooLongException();
|
||||
}
|
||||
case 995: // Operation cancelled
|
||||
{
|
||||
throw new OperationCanceledException();
|
||||
}
|
||||
default:
|
||||
{
|
||||
Marshal.ThrowExceptionForHR(MakeHRFromErrorCode(errorCode));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ThrowLastIOError(string path)
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
if (0 != errorCode)
|
||||
{
|
||||
int hr = Marshal.GetHRForLastWin32Error();
|
||||
if (0 <= hr) throw new Win32Exception(errorCode);
|
||||
ThrowIOError(errorCode, path);
|
||||
}
|
||||
}
|
||||
|
||||
public static NativeFileAccess ToNative(this FileAccess access)
|
||||
{
|
||||
NativeFileAccess result = 0;
|
||||
if (FileAccess.Read == (FileAccess.Read & access)) result |= NativeFileAccess.GenericRead;
|
||||
if (FileAccess.Write == (FileAccess.Write & access)) result |= NativeFileAccess.GenericWrite;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string BuildStreamPath(string filePath, string streamName)
|
||||
{
|
||||
string result = filePath;
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
if (1 == result.Length) result = ".\\" + result;
|
||||
result += StreamSeparator + streamName + StreamSeparator + "$DATA";
|
||||
if (MaxPath <= result.Length) result = LongPathPrefix + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void ValidateStreamName(string streamName)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(streamName) && -1 != streamName.IndexOfAny(InvalidStreamNameChars))
|
||||
{
|
||||
throw new ArgumentException(Resources.Error_InvalidFileChars);
|
||||
}
|
||||
}
|
||||
|
||||
public static int SafeGetFileAttributes(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
|
||||
|
||||
int result = GetFileAttributes(name);
|
||||
if (-1 == result)
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
if (ErrorFileNotFound != errorCode) ThrowLastIOError(name);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool SafeDeleteFile(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
|
||||
|
||||
bool result = DeleteFile(name);
|
||||
if (!result)
|
||||
{
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
if (ErrorFileNotFound != errorCode) ThrowLastIOError(name);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static SafeFileHandle SafeCreateFile(string path, NativeFileAccess access, FileShare share, IntPtr security, FileMode mode, NativeFileFlags flags, IntPtr template)
|
||||
{
|
||||
SafeFileHandle result = CreateFile(path, access, share, security, mode, flags, template);
|
||||
if (!result.IsInvalid && 1 != GetFileType(result))
|
||||
{
|
||||
result.Dispose();
|
||||
throw new NotSupportedException(string.Format(Resources.Culture,
|
||||
Resources.Error_NonFile, path));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static long GetFileSize(string path, SafeFileHandle handle)
|
||||
{
|
||||
long result = 0L;
|
||||
if (null != handle && !handle.IsInvalid)
|
||||
{
|
||||
LargeInteger value;
|
||||
if (GetFileSizeEx(handle, out value))
|
||||
{
|
||||
result = value.ToInt64();
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowLastIOError(path);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static long GetFileSize(string path)
|
||||
{
|
||||
long result = 0L;
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
using (SafeFileHandle handle = SafeCreateFile(path, NativeFileAccess.GenericRead, FileShare.Read, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero))
|
||||
{
|
||||
result = GetFileSize(path, handle);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static IList<Win32StreamInfo> ListStreams(string filePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException("filePath");
|
||||
if (-1 != filePath.IndexOfAny(Path.GetInvalidPathChars())) throw new ArgumentException(Resources.Error_InvalidFileChars, "filePath");
|
||||
|
||||
var result = new List<Win32StreamInfo>();
|
||||
|
||||
using (SafeFileHandle hFile = SafeCreateFile(filePath, NativeFileAccess.GenericRead, FileShare.Read, IntPtr.Zero, FileMode.Open, NativeFileFlags.BackupSemantics, IntPtr.Zero))
|
||||
using (var hName = new StreamName())
|
||||
{
|
||||
if (!hFile.IsInvalid)
|
||||
{
|
||||
var streamId = new Win32StreamId();
|
||||
int dwStreamHeaderSize = Marshal.SizeOf(streamId);
|
||||
bool finished = false;
|
||||
IntPtr context = IntPtr.Zero;
|
||||
int bytesRead;
|
||||
string name;
|
||||
|
||||
try
|
||||
{
|
||||
while (!finished)
|
||||
{
|
||||
// Read the next stream header:
|
||||
if (!BackupRead(hFile, ref streamId, dwStreamHeaderSize, out bytesRead, false, false, ref context))
|
||||
{
|
||||
finished = true;
|
||||
}
|
||||
else if (dwStreamHeaderSize != bytesRead)
|
||||
{
|
||||
finished = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read the stream name:
|
||||
if (0 >= streamId.StreamNameSize)
|
||||
{
|
||||
name = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
hName.EnsureCapacity(streamId.StreamNameSize);
|
||||
if (!BackupRead(hFile, hName.MemoryBlock, streamId.StreamNameSize, out bytesRead, false, false, ref context))
|
||||
{
|
||||
name = null;
|
||||
finished = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unicode chars are 2 bytes:
|
||||
name = hName.ReadStreamName(bytesRead >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the stream info to the result:
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
result.Add(new Win32StreamInfo
|
||||
{
|
||||
StreamType = (FileStreamType)streamId.StreamId,
|
||||
StreamAttributes = (FileStreamAttributes)streamId.StreamAttributes,
|
||||
StreamSize = streamId.Size.ToInt64(),
|
||||
StreamName = name
|
||||
});
|
||||
}
|
||||
|
||||
// Skip the contents of the stream:
|
||||
int bytesSeekedLow, bytesSeekedHigh;
|
||||
if (!finished && !BackupSeek(hFile, streamId.Size.Low, streamId.Size.High, out bytesSeekedLow, out bytesSeekedHigh, ref context))
|
||||
{
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Abort the backup:
|
||||
BackupRead(hFile, hName.MemoryBlock, 0, out bytesRead, true, false, ref context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
134
@integrate/Trinet.Core.IO.Ntfs/StreamName.cs
Normal file
134
@integrate/Trinet.Core.IO.Ntfs/StreamName.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Trinet.Core.IO.Ntfs
|
||||
{
|
||||
internal sealed class StreamName : IDisposable
|
||||
{
|
||||
#region Private Data
|
||||
|
||||
private static readonly SafeHGlobalHandle _invalidBlock = SafeHGlobalHandle.Invalid();
|
||||
private SafeHGlobalHandle _memoryBlock = _invalidBlock;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StreamName"/> class.
|
||||
/// </summary>
|
||||
public StreamName()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Returns the handle to the block of memory.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The <see cref="SafeHGlobalHandle"/> representing the block of memory.
|
||||
/// </value>
|
||||
public SafeHGlobalHandle MemoryBlock
|
||||
{
|
||||
get { return _memoryBlock; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing,
|
||||
/// releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_memoryBlock.IsInvalid)
|
||||
{
|
||||
_memoryBlock.Dispose();
|
||||
_memoryBlock = _invalidBlock;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that there is sufficient memory allocated.
|
||||
/// </summary>
|
||||
/// <param name="capacity">
|
||||
/// The required capacity of the block, in bytes.
|
||||
/// </param>
|
||||
/// <exception cref="OutOfMemoryException">
|
||||
/// There is insufficient memory to satisfy the request.
|
||||
/// </exception>
|
||||
public void EnsureCapacity(int capacity)
|
||||
{
|
||||
int currentSize = _memoryBlock.IsInvalid ? 0 : _memoryBlock.Size;
|
||||
if (capacity > currentSize)
|
||||
{
|
||||
if (0 != currentSize) currentSize <<= 1;
|
||||
if (capacity > currentSize) currentSize = capacity;
|
||||
|
||||
if (!_memoryBlock.IsInvalid) _memoryBlock.Dispose();
|
||||
_memoryBlock = SafeHGlobalHandle.Allocate(currentSize);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the Unicode string from the memory block.
|
||||
/// </summary>
|
||||
/// <param name="length">
|
||||
/// The length of the string to read, in characters.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The string read from the memory block.
|
||||
/// </returns>
|
||||
public string ReadString(int length)
|
||||
{
|
||||
if (0 >= length || _memoryBlock.IsInvalid) return null;
|
||||
if (length > _memoryBlock.Size) length = _memoryBlock.Size;
|
||||
return Marshal.PtrToStringUni(_memoryBlock.DangerousGetHandle(), length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the string, and extracts the stream name.
|
||||
/// </summary>
|
||||
/// <param name="length">
|
||||
/// The length of the string to read, in characters.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The stream name.
|
||||
/// </returns>
|
||||
public string ReadStreamName(int length)
|
||||
{
|
||||
string name = this.ReadString(length);
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
// Name is of the format ":NAME:$DATA\0"
|
||||
int separatorIndex = name.IndexOf(SafeNativeMethods.StreamSeparator, 1);
|
||||
if (-1 != separatorIndex)
|
||||
{
|
||||
name = name.Substring(1, separatorIndex - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Should never happen!
|
||||
separatorIndex = name.IndexOf('\0');
|
||||
if (1 < separatorIndex)
|
||||
{
|
||||
name = name.Substring(1, separatorIndex - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
name = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user