Click here to Skip to main content
15,867,308 members
Articles / Programming Languages / C#

Accessing alternative data-streams of files on an NTFS volume

Rate me:
Please Sign up or sign in to vote.
4.85/5 (53 votes)
15 Aug 2016CPOL4 min read 500.1K   5.4K   132   86
A pair of classes to encapsulate access to NTFS alternative data streams.

Introduction

Since NT 3.1, the NTFS file system has supported multiple data-streams for files. There has never been built-in support for viewing or manipulating these additional streams, but the Windows API functions include support for them with a special file syntax: Filename.ext:StreamName. Even Win9x machines can access the alternative data streams of files on any NTFS volume they have access to, e.g., through a mapped drive. Because the Scripting.FileSystemObject and many other libraries call the CreateFile API behind the scenes, even scripts have been able to access alternative streams quite easily (although enumerating the existing streams has always been tricky).

In .NET, however, it seems someone decided to add some checking to the format of filenames. If you attempt to open a FileStream on an alternative stream, you will get a "Path Format not supported" exception. I have been unable to find any class in the CLR that provides support for alternative data streams, so I decided to roll my own.

Update

I originally wrote this code in 2002, targeting v1 of the .NET Framework. Looking at the code now, it seems quite messy, and has several bugs and problems which were mentioned in the comments. I have since completely re-written the code for .NET v3.5, and (hopefully) fixed the bugs.

The new code is not compatible with the original version. However, I have included a sample compatibility wrapper which maps the old API to the new API. You can find these files under the "other/Compatibility wrapper" folder in the download.

Bugs / Issues Fixed

  • The code now uses the FileSystemInfo class rather than the FileInfo class. This allows you to access alternate data streams attached to folders as well as files. (Suggested by Dan Elebash.)
  • The code now uses SafeFileHandle instead of IntPtr for the file handle. (Suggested by Moomansun.)
  • The code is now 64-bit compatible. (Reported by John SMith 5634552745.)
  • The code now correctly calls BackupRead with the bAbort parameter set to true after enumerating the streams. (Reported by scooter_jsm.)
  • The number of global memory allocations required to read the streams from a file has been reduced. (Suggested by scooter_jsm.)
  • v2.1: ValidateStreamName now accepts stream names which contain characters with ASCII codes between 1 and 31. (Reported by Andy Missico.)
  • v2.1: The code will now attempt to map standard IO errors to the equivalent .NET Exception type. (Suggested by Andy Missico.)

Using the Classes

The AlternateDataStreamInfo class represents the details of an individual stream, and provides methods to create, open, or delete the stream.

The static FileSystem class provides methods to retrieve the list of streams for a file, retrieve a specific stream from a file, determine whether a stream exists, and delete a specific stream.

All methods on the FileSystem class offer overloads which accept either a path or a FileSystemInfo object. The overloads which accept a FileSystemInfo object can also be invoked as extension methods.

Example:

C#
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using Trinet.Core.IO.Ntfs;

...

FileInfo file = new FileInfo(path);

// List the additional streams for a file:
foreach (AlternateDataStreamInfo s in file.ListAlternateDataStreams())
{
    Console.WriteLine("{0} - {1} bytes", s.Name, s.Size);
}

// Read the "Zone.Identifier" stream, if it exists:
if (file.AlternateDataStreamExists("Zone.Identifier"))
{
    Console.WriteLine("Found zone identifier stream:");
    
    AlternateDataStreamInfo s = 
       file.GetAlternateDataStream("Zone.Identifier",
                                   FileMode.Open);
    using (TextReader reader = s.OpenText())
    {
        Console.WriteLine(reader.ReadToEnd());
    }
    
    // Delete the stream:
    s.Delete();
}
else
{
    Console.WriteLine("No zone identifier stream found.");
}

// Alternative method to delete the stream:
file.DeleteAlternateDataStream("Zone.Identifier");

Files Included

  • The Trinet.Core.IO.Ntfs folder contains the source code.
  • The doc folder contains the documentation and FxCop project.
  • The bin folder contains the compiled assembly.
  • The other folder contains the compatibility wrapper, and a sample to recursively delete the "Zone.Identifier" stream from all files in a given path.

References

If you want more information on NTFS programming, or the C++ code I based this on, see Dino Esposito's MSDN article from March 2000: http://msdn.microsoft.com/en-us/library/ms810604.aspx [^].

History

  • v1 - 1 August 2002 - Initial release, targeting .NET 1.0.
  • v2 - 16 September 2008 - Re-written to target .NET 3.5; major changes include:
    • Replaced FileInfo with FileSystemInfo.
    • Replaced IntPtr with SafeFileHandle.
    • Made the P/Invoke calls 64-bit compatible.
    • Made the code abort the BackupRead operation after enumerating the streams.
    • Reduced the number of global memory allocations required.
  • v2.1 - 28 July 2010 - Minor fixes suggested by Andy Missico:
    • Changed ValidateStreamName to accept stream names containing characters with ASCII codes between 1 and 31 (see msdn.microsoft.com/en-us/library/aa365247).
    • Added mapping of standard IO errors to the correct .NET exceptions.
  • v2.2 - 15 August 2016 - Fix for bug reported by Member 12683101, where zero-length alternate streams prevented subsequent streams from being enumerated.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer CodeProject
United Kingdom United Kingdom
I started writing code when I was 8, with my trusty ZX Spectrum and a subscription to "Input" magazine. Spent many a happy hour in the school's computer labs with the BBC Micros and our two DOS PCs.

After a brief detour into the world of Maths, I found my way back into programming during my degree via free copies of Delphi and Visual C++ given away with computing magazines.

I went straight from my degree into my first programming job, at Trinet Ltd. Eleven years later, the company merged to become ArcomIT. Three years after that, our project manager left to set up Nevalee Business Solutions, and took me with him. Since then, we've taken on four more members of staff, and more work than you can shake a stick at. Smile | :)

Between writing custom code to integrate with Visma Business, developing web portals to streamline operations for a large multi-national customer, and maintaining RedAtlas, our general aviation airport management system, there's certainly never a dull day in the office!

Outside of work, I enjoy real ale and decent books, and when I get the chance I "tinkle the ivories" on my Technics organ.

Comments and Discussions

 
GeneralRe: error Pin
Prince iraq16-Mar-12 7:40
Prince iraq16-Mar-12 7:40 
QuestionHow to close the stream? Pin
DOSSTONED22-Feb-11 4:26
DOSSTONED22-Feb-11 4:26 
AnswerRe: How to close the stream? Pin
Richard Deeming22-Feb-11 6:15
mveRichard Deeming22-Feb-11 6:15 
GeneralRe: How to close the stream? Pin
DOSSTONED22-Feb-11 16:35
DOSSTONED22-Feb-11 16:35 
GeneralConvenience methods Pin
VenDiddy6-Aug-10 8:22
VenDiddy6-Aug-10 8:22 
GeneralExample code still not running properly on mapped network drive [modified] Pin
LastZolex14-Jun-10 11:29
LastZolex14-Jun-10 11:29 
GeneralRe: Example code still not running properly on mapped network drive Pin
Richard Deeming15-Jun-10 1:38
mveRichard Deeming15-Jun-10 1:38 
GeneralRe: Example code still not running properly on mapped network drive [modified] Pin
LastZolex15-Jun-10 2:09
LastZolex15-Jun-10 2:09 
Hi, thank you somuch for the quick answer Smile | :)

I am still investigating the cause of my problems, but it can sum up the following special circumstances in my testbed:

1. My Visual Studio is running inside a VMWare which hosts Win XP32
2. Drive N:\ is a mapped network drive inside the VMWare
3. The Filesystem is definitely NTFS and the user in XP is admin Wink | ;-)

4. The host system of the VMWare image is Windows 7 x64
5. The "physical drive" on the host has the same drive letter N:\

The special thing about this drive N:\ is that it is connected via LAN to the host machine, but this happens fully transparent via drivers, which can "fool" the OS and even the most sophisticated HDD recovery software I have used so far. They all believe that it is a physical HDD installed in the host itself. So I guess this is not the problem. (btw. it ia a "NetDisk" 351UNE by IOCell)

I am going to do a test outside the VMWare and will report after that what I found out.

My guess is that the software will work properly even on the LAN drive N:\, and I will try to run it on another network drive which is not connected via driver but via network drive mapping only.

It will take a while until I have transferred all necessary programs to the outer world, but I will tell you ASAP Smile | :)


UPDATE #1:

I used the compiled x32 executables on my windows 7 x64 on the Pseudo-Network Drive N:\ and it worked fine, nothing to complain Wink | ;-)

Because of this we can be sure that the drive itself is not the problem, i.e. the LAN-to-Localdrive drivers work perfectly, as does your example in this case! Smile | :)

Still to be done: use a real mapped network drive outside of the vmware and do the same test. Currently I work on my network to provide such an environment, my first test with a mapped Buffalo LAN Drive failed due to other reasons (UNC path was not available, I don't know why, working on it Stupid me! Buffalo uses a Linux filesystem, no NTFS Wink | ;-) ).

stay tuned...


UPDATE #2:

Sorry for the delay, I am absorbed at the moment by business-needs, but will come back to my problem ASAP .

Believe it or not: my current problem in testing your code on a real mapped network drive is to find a second network device to share some folders from...
I have only one big machine at home and have everything else virtualized! Wink | ;-)

So you may understand why I want to make it run inside a VM Ware! LOL!

My current guess is: VMWare is doing something strange to mapped NTFS Network drives!

UPDATE #3:

Ok, here we go.

I tried a mapped network drive OUTSIDE of a VMWare and it worked, as you expected (with UNC names only of course).

No I am really frustrated... by the VMWare, not by your code Wink | ;-) Obviously there is a difference between mapped drives in a "real" environment and such a construct in a virtualized environment.

So I have to investigate further how to circumvent my problem. Until I found a cure, I sadly cannot use your code as intended!

Thank you so much for this great piece of software and your effort to help me! If I find a solution, I will post it here, promised!!

Keep on coding Cool | :cool:

LZ

PS: I just realized that any file that is copied from inside a VMWare to the outside world via a mapped Network drive, loses all alternate streams! Phew....

modified on Saturday, June 19, 2010 8:41 AM

GeneralRe: Example code still not running properly on mapped network drive [modified] Pin
Ashutosh Bhawasinka12-Mar-12 16:51
Ashutosh Bhawasinka12-Mar-12 16:51 
GeneralThis article is a great help! Pin
LastZolex11-Jun-10 23:44
LastZolex11-Jun-10 23:44 
GeneralNeed to Map Win32Exception to Appropriate .NET Exception Pin
Andy Missico30-Mar-10 13:07
Andy Missico30-Mar-10 13:07 
GeneralRe: Need to Map Win32Exception to Appropriate .NET Exception Pin
Richard Deeming27-Jul-10 7:23
mveRichard Deeming27-Jul-10 7:23 
GeneralValidateStreamName Incorrect Uses GetInvalidFileNameChars Pin
Andy Missico30-Mar-10 12:36
Andy Missico30-Mar-10 12:36 
GeneralProblem accessing alternate data stream of a network shared drive Pin
m.vinod859-Nov-09 10:40
m.vinod859-Nov-09 10:40 
GeneralRe: Problem accessing alternate data stream of a network shared drive Pin
Richard Deeming10-Nov-09 2:02
mveRichard Deeming10-Nov-09 2:02 
GeneralRe: Problem accessing alternate data stream of a network shared drive Pin
m.vinod8510-Nov-09 5:44
m.vinod8510-Nov-09 5:44 
GeneralRe: Problem accessing alternate data stream of a network shared drive Pin
Richard Deeming10-Nov-09 6:54
mveRichard Deeming10-Nov-09 6:54 
Questionhow to compile these sourecs Pin
hefeilixin29-Sep-09 17:36
hefeilixin29-Sep-09 17:36 
AnswerRe: how to compile these sourecs Pin
Richard Deeming30-Sep-09 1:31
mveRichard Deeming30-Sep-09 1:31 
Newsanother question Pin
hefeilixin9-Oct-09 21:44
hefeilixin9-Oct-09 21:44 
GeneralRe: another question Pin
Richard Deeming12-Oct-09 1:08
mveRichard Deeming12-Oct-09 1:08 
GeneralRe: another question Pin
#realJSOP11-Feb-11 1:51
mve#realJSOP11-Feb-11 1:51 
GeneralFileInfo question Pin
Brendan Chong16-Sep-09 7:33
Brendan Chong16-Sep-09 7:33 
GeneralRe: FileInfo question Pin
Richard Deeming16-Sep-09 7:49
mveRichard Deeming16-Sep-09 7:49 
GeneralEdit File summary Pin
Joe Rozario29-Jun-09 23:55
Joe Rozario29-Jun-09 23:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.