|
|
Comments and Discussions
|
|
 |

|
When I use this to list ADS for C:\ProgramData\TEMP I can list all 29 Data streams names but if I try to read each data value also and build with a string builder it will only return the first three even though the counter shows it is going thru all 29.
Can you only get data for at most 3 at a time ?
I may have to do like one program does and only let you get data for one at a time.
|
|
|
|

|
This article is a survivor... 2002 and still maintained? There wasn't much to start with
|
|
|
|

|
Having implemented this code in our project I must say I am very impressed with how well this works. One catch I have run into (not sure if I'm just not using it right) is that I cannot serialize/deserialize the streams because they are not actual StreamReader/StreamWriter objects. Is there a known workaround for this?
|
|
|
|
|

|
I test on 2TB Virtual Disk,it simulate a 2TB disk,1024,2048,4096 bytes/secotr,this app can not work.I found it on http://www.2tdisk.com
|
|
|
|

|
First, thank you for the project! It really works on my project!
But now I have a problem, as I declare it like this:
AlternateDataStreamInfo dataStream = FileSystem.GetAlternateDataStream("C:\123.txt", "stream1");
When I first use the function
FileStream fs = dataStream.OpenWrite()
to get a filestream, nothing unusual.
and then
fs.Close();
In another function in my project, I also declare a local var like above, but this time, when the program runs at dataStream.OpenRead(). It says that the stream is used by another process.
I wanna to find out some function to close the stream, even the Finalize() function inherited from object is missing. How to end the connection between the process and the stream?
|
|
|
|

|
I wrote some convenience extension methods for simpler read/write of metadata.
public static class FileMetaData
{
public static T GetMetaData<T>(this FileInfo fileInfo, string name)
{
T value;
string text = null;
var dataStream = fileInfo.GetAlternateDataStream(name, FileMode.OpenOrCreate);
using (var reader = dataStream.OpenText())
{
text = reader.ReadToEnd();
}
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
try
{
value = (T)converter.ConvertFromString(text);
}
catch
{
value = default(T);
}
return value;
}
public static void SetMetaData<T>(this FileInfo fileInfo, string name, T value)
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
string text = null;
text = converter.ConvertToString(value);
var dataStream = fileInfo.GetAlternateDataStream(name, FileMode.OpenOrCreate);
using (var fileStream = dataStream.OpenWrite())
using (var writer = new StreamWriter(fileStream))
{
writer.Write(text);
}
}
}
This way you can write metadata like this:
FileInfo fi = new FileInfo("path to the file");
fi.SetMetaData<int>("MyAttribute", 5);
Console.WriteLine(fi.GetMetaData<int>("MyAttribute"));
|
|
|
|

|
Hi there.
Maybe I don't get it right, but I can't get the console app "TestNTFS" from your folder "\other\Compatibility wrapper" running properly.
I always get the exception (it's a german one)
System.ComponentModel.Win32Exception was unhandled
Message=Die Syntax für den Dateinamen, Verzeichnisnamen oder die Datenträgerbezeichnung ist falsch
Source=Trinet.Core.IO.Ntfs
ErrorCode=-2147467259
NativeErrorCode=123
StackTrace:
at Trinet.Core.IO.Ntfs.SafeNativeMethods.ThrowLastWin32Error() in N:\CSharp\MemoryClones\MeMoMeSharply\trunk\Trinet.Core.IO.Ntfs\SafeNativeMethods.cs:line 182
at Trinet.Core.IO.Ntfs.SafeNativeMethods.SafeGetFileAttributes(String name) in N:\CSharp\MemoryClones\MeMoMeSharply\trunk\Trinet.Core.IO.Ntfs\SafeNativeMethods.cs:line 222
at Trinet.Core.IO.Ntfs.FileSystem.GetAlternateDataStream(FileSystemInfo file, String streamName, FileMode mode) in N:\CSharp\MemoryClones\MeMoMeSharply\trunk\Trinet.Core.IO.Ntfs\FileSystem.cs:line 231
at NTFS.FileStreams.Add(String streamName) in N:\CSharp\MemoryClones\MeMoMeSharply\trunk\Trinet.Core.IO.Ntfs.Tests\FileStreams.cs:line 138
at NTFS.Test.TestNTFS.TestStream() in N:\CSharp\MemoryClones\MeMoMeSharply\trunk\Trinet.Core.IO.Ntfs.Tests\TestNTFS.cs:line 52
at NTFS.Test.TestNTFS.Main(String[] args) in N:\CSharp\MemoryClones\MeMoMeSharply\trunk\Trinet.Core.IO.Ntfs.Tests\TestNTFS.cs:line 17
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
The above exception says: "The filename, directory name, or volume label syntax is incorrect", and I have no idea why this is so.
The testsystem is XP32 SP2 with Visual Studio 2010 (and because of VC2010 it is of course .NET 4.0).
As it was mentioned some postings below I have to admit there is something special about the drive "N:" I use. It is a mapped network drive and the VS2010 is running in an virtualized environment (VMWare).
The mapped network drive IS causing my troubles! I tried the demo app in a path "C:\\tmp" and it worked.
Some postings below there was someone with a similar problem, but as the comment says "mapped network drives are working properly" I hoped it would work out. But it does not.
Does anybody know a clean solution for this problem, if the app does not know that the drive is a mapped network drive?
Any help is appreciated!
Thanks in advance!
LZ
UPDATE #1:
Ok, I annoy you now with my progress in solving the problem. It is unsolved yet
As a first try I added a "networkdrive to UNC path" method which i borrowed here: GetUNCPath-Method
This transforms my original mapped network path from
"N:\\CSharp\\MemoryClones\\MeMoMeSharply\\trunk\\Trinet.Core.IO.Ntfs.Tests\\bin\\Debug\\test.jpg:thumb:$DATA"
to
"\\\\vmware-host\\Shared Folders\\Projekte\\CSharp\\MemoryClones\\MeMoMeSharply\\trunk\\Trinet.Core.IO.Ntfs.Tests\\bin\\Debug\\test.jpg:thumb:$DATA"
But this changed nothing. It still works on the local HDD path but not on the remote network path.
So I still need help from you, if possible
modified on Tuesday, June 15, 2010 2:43 AM
|
|
|
|
|

|
It would be nice if the library mapped the error code to the appropriate exception. Check out Microsoft's source code for .NET to see how this is done. Specifically, the WinIOError function of the __Error.cs file. (Using .NET Reflector, do a "Search Member" for WinIOError.)
internal static void WinIOError() {
int errorCode = Marshal.GetLastWin32Error();
WinIOError(errorCode, String.Empty);
}
internal static void WinIOError(int errorCode, String maybeFullPath) {
bool isInvalidPath = errorCode == Win32Native.ERROR_INVALID_NAME || errorCode == Win32Native.ERROR_BAD_PATHNAME;
String str = GetDisplayablePath(maybeFullPath, isInvalidPath);
switch (errorCode) {
case Win32Native.ERROR_FILE_NOT_FOUND:
if (str.Length == 0)
throw new FileNotFoundException(Environment.GetResourceString("IO.FileNotFound"));
else
throw new FileNotFoundException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("IO.FileNotFound_FileName"), str), str);
case Win32Native.ERROR_PATH_NOT_FOUND:
if (str.Length == 0)
throw new DirectoryNotFoundException(Environment.GetResourceString("IO.PathNotFound_NoPathName"));
else
throw new DirectoryNotFoundException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("IO.PathNotFound_Path"), str));
case Win32Native.ERROR_ACCESS_DENIED:
if (str.Length == 0)
throw new UnauthorizedAccessException(Environment.GetResourceString("UnauthorizedAccess_IODenied_NoPathName"));
else
throw new UnauthorizedAccessException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("UnauthorizedAccess_IODenied_Path"), str));
case Win32Native.ERROR_ALREADY_EXISTS:
if (str.Length == 0)
goto default;
throw new IOException(Environment.GetResourceString("IO.IO_AlreadyExists_Name", str), Win32Native.MakeHRFromErrorCode(errorCode), maybeFullPath);
case Win32Native.ERROR_FILENAME_EXCED_RANGE:
throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
case Win32Native.ERROR_INVALID_DRIVE:
throw new DriveNotFoundException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("IO.DriveNotFound_Drive"), str));
case Win32Native.ERROR_INVALID_PARAMETER:
throw new IOException(Win32Native.GetMessage(errorCode), Win32Native.MakeHRFromErrorCode(errorCode), maybeFullPath);
case Win32Native.ERROR_SHARING_VIOLATION:
if (str.Length == 0)
throw new IOException(Environment.GetResourceString("IO.IO_SharingViolation_NoFileName"), Win32Native.MakeHRFromErrorCode(errorCode), maybeFullPath);
else
throw new IOException(Environment.GetResourceString("IO.IO_SharingViolation_File", str), Win32Native.MakeHRFromErrorCode(errorCode), maybeFullPath);
case Win32Native.ERROR_FILE_EXISTS:
if (str.Length == 0)
goto default;
throw new IOException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("IO.IO_FileExists_Name"), str), Win32Native.MakeHRFromErrorCode(errorCode), maybeFullPath);
case Win32Native.ERROR_OPERATION_ABORTED:
throw new OperationCanceledException();
default:
throw new IOException(Win32Native.GetMessage(errorCode), Win32Native.MakeHRFromErrorCode(errorCode), maybeFullPath);
}
}
|
|
|
|

|
ValidateStreamName incorrectly uses Path.GetInvalidFileNameChars to validate a stream name. A stream is allow characters whose integer representations are between 1 and 31. I have included a fix, as shown below.
private static char[] _invalidStreamNameChars;
public static char[] GetInvalidStreamNameChar() {
if (_invalidStreamNameChars == null) {
List<char> oResult = new List<char>();
foreach (char i in System.IO.Path.GetInvalidFileNameChars()) {
if ((i > 0) && (i < 32)) {
} else {
oResult.Add(i);
}
}
_invalidStreamNameChars = oResult.ToArray();
}
return _invalidStreamNameChars;
}
public static void ValidateStreamName(string streamName)
{
if (!string.IsNullOrEmpty(streamName) && -1 != streamName.IndexOfAny(GetInvalidStreamNameChar()))
{
throw new ArgumentException(Resources.Error_InvalidFileChars);
}
}
|
|
|
|

|
Hi,
I am having problems accessing the alternate data stream of a network shared drive. I get the error "The filename, directory name, or volume label syntax is incorrect" when I use the method FileSystem.AlternateDataStreamExists("z:\\", "xx"). Am I doing something wrong in here. Thanks in advance for your help.
--
Vinzy
|
|
|
|

|
hi,
i am a newer,and i don't know how to use it.
how can i compile all the files in "Trinet.Core.IO.Ntfs" folder?
by the way i am using powershell
thanks
|
|
|
|

|
Does FileInfo have a method called ListAlternateDataStreams()? I can't seem to find your version either.
...................
FileInfo file = new FileInfo(path);
foreach (AlternateDataStreamInfo s in file.ListAlternateDataStreams())
...................
|
|
|
|

|
Dear friend,
i am very sorry if i am wrong. because i am new to this.
please tell me how to change the File summary information ??
i could not understand your code.
My Problem is i have own file type and i want to change the file summary through c# can u please tell me how to do that?
i searched in Google
"http://forums.asp.net/p/1050538/1483362.aspx#1483362"
from here i came to your article.
Thank you.
Joe.I
|
|
|
|

|
Hi,
I need a simple sample code to writing a alternative data stream called test with this value "hello ADS" for a file and a simple code for reading the value of that data stream (test).
Is there anybody can write it for me here.
thanks
modified on Wednesday, June 10, 2009 3:24 AM
|
|
|
|

|
On Vista SP1 it simply does not return any metadata (Count == 0), however metadata actually exists.
|
|
|
|

|
Thank you very much for this great article!
|
|
|
|

|
According the the documentation on BackupRead(),
"lpContext [out]
Pointer to a variable that receives a pointer to an internal data structure used by BackupRead to maintain context information during a backup operation.
You must set the variable pointed to by lpContext to NULL before the first call to BackupRead for the specified file or directory. The function allocates memory for the data structure, and then sets the variable to point to that structure. You must not change lpContext or the variable that it points to between calls to BackupRead.
To release the memory used by the data structure, call BackupRead with the bAbort parameter set to TRUE when the backup operation is complete."
Also,
"bAbort [in]
Indicates whether you have finished using BackupRead on the handle. While you are backing up the file, specify this parameter as FALSE. Once you are done using BackupRead, you must call BackupRead one more time specifying TRUE for this parameter and passing the appropriate lpContext. lpContext must be passed when bAbort is TRUE; all other parameters are ignored."
Note the last statement in te first quote of the documentation: "To release the memory...". You need to call BackupRead with bAbort set to true when you are finished with the context to free the memory allocated for the context data structure.
I use alternate streams on millions of files and when I'm verifying that the alternate streams that are supposed to exist actaully do, and contain the correct information, I can use up a lot of memory.
This is a bug. I've fixed it in the code I use.
Here is snippet I added after the while(continue) { } statement to close down the BackupRead()
Kernel32.BackupRead(hFile, ref sid, dwStreamHeaderSize, ref lRead, true, false, ref Context);
I also had to move the definition of lRead but this argument is ignored.
There is also a small performance enhancement that could be achieved by moving the
"IntPtr pName = Marshal.AllocHGlobal(sid.dwStreamNameSize);" outside the while loop and moving the
"Marshal.FreeHGlobal(pName);" to the finally block. The only requirement would be to allocate enough memory for the largest alternate stream name.
scooter_jsm
|
|
|
|

|
Just an advisory for the unwary: this code is not 64-bit compatible (e.g. use of int's instead of IntPtr's). It may run inside the IDE but will crash hard if you run it straight from the command line.
|
|
|
|
|

|
First off nice article and sample code. Everything works great but I was wondering how you would read/write/delete ADS from folders instead of just files. Any help would be appriciated, I know you can do it using the command line method, just not sure how to accomplish this in code.
Thanks.
|
|
|
|

|
I am having problem using your example.
When I retrieve substream using StreamInfo.open() sometimes I get null stream. When I check StreamInfo object that I am getting stream from it shows non zero size data in it so looks like data is there. I added few millisecond delay and retry and that works for some time but eventually I have same problem.
Do you have any idea why this could happen?
|
|
|
|

|
I needed to make one small change to the code to get it to work with multiple streams. At the bottom of initStreams(), in the code that was
//Skip the stream contents
int l = 0; int h = 0;
Continue = Kernel32.BackupSeek(hFile, sid.Size.Low, sid.Size.High, ref l, ref h, ref Context);
I needed to remove the assignment of Continue to get it to work (by the way, all of my streams were of a zero length during my testing)
//Skip the stream contents
int l = 0; int h = 0;
Kernel32.BackupSeek(hFile, sid.Size.Low, sid.Size.High, ref l, ref h, ref Context);
The code then falls out of the loop at the top in the first BackupRead
//Read the next stream header
int lRead = 0;
Continue = Kernel32.BackupRead(hFile, ref sid, dwStreamHeaderSize, ref lRead, false, false, ref Context);
if (Continue && lRead == dwStreamHeaderSize)
{
...
}
else break;
|
|
|
|

|
from the MSDN article:
"When you copy a multi-stream file on non-NTFS volumes, only the main stream is copied. This means you lose your extra data, because they can't come up again even if you copy the file back to an NTFS disk"
That's quite the limitation!
|
|
|
|

|
Very good, does anyone know if M$ is planning to drop support for alternate streams in files?
"When the only tool you have is a hammer, a sore thumb you will have."
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
A pair of classes to encapsulate access to NTFS alternative data streams.
| Type | Article |
| Licence | CPOL |
| First Posted | 31 Jul 2002 |
| Views | 205,068 |
| Downloads | 2,633 |
| Bookmarked | 97 times |
|
|