大家把ntfs分區上的文件拷貝到非ntfs分區上時, 可能偶爾遇到過下面的情況, 系統提示會有數據丟失, 這是怎么回事呢?  ??? 實際上ntfs文件系統引入了"流"這個概念, 每個文件都可以有多個流, 而我們一般只使用了一個, 通過給文件分配更多的流, 可以實現某種意義上的"文件隱藏". 例如可以控制臺中使用下面的命令建立一個文本文件: dir d:>abc.txt 它列出d:根目錄的所有文件, 然后將其重定向到文件abc.txt, 現在你可以檢查一下abc.txt的大小和內容, 并記錄下來. 然后再執行下面這條命令 dir c:>abc.txt:stream.txt 執行完畢后, 檢查abc.txt, 大小和內容都沒有變化, 但其實abc.txt已經多了一個流stream.txt, 而重定向的內容就輸出到了它里面, 不信使用下面的命令看一下(注意流的名字也要以.txt結尾, 否則notepad就找不到了): notepad abc.txt:stream.txt 這樣我們就把一個文件隱藏了, dir命令看不見, 文件屬性看不到, 資源管理器也看不到, 如果不知道流的名字, notepad也是無法訪問的. ??? 實際上, 流還可以不依賴于文件, 下面的命令也是合法的(先不要試, 否則可能會有點麻煩): dir e:>:stream.txt 這是把流綁到了文件夾上, 這種流就更隱蔽了. 一般情況下要想刪除流只有將其宿主刪除, 如果你執行了剛才的命令, 并且是在根文件夾上執行的, 如果你想刪除它, 那就恭喜你要格盤了:). 不過通過寫程序還是不難刪除流的, 只要調用DeleteFile, 并提供流的名字就行了. 要想枚舉一個文件中的所有流, 目前只能通過BackupRead來完成. 我寫了一個小程序, 通過它可以枚舉、刪除、導入導出流中的數據, 下面的是它的代碼(寫的比較倉促, 可能還有一些bug, 不過主要功能都實現了, 它的名字叫nsvw, 即Ntfs Stream Viewer). #include?<windows.h>
#include?<stdio.h>
#include?<locale.h>
#include?<wchar.h>
#include?<malloc.h>
#include?<stddef.h>


enum?RUN_MODE
  {
????SHOW_USAGE?=?0,
????SHOW_STREAMS,
????DELETE_STREAMS,
????IMPORT_STREAM,
????EXPORT_STREAM,
};


LPCWSTR?g_szObj?=?NULL;
LPCWSTR?g_szStrm?=?NULL;
LPCWSTR?g_szFile?=?NULL;


int?ParseArgs(?int?argc,?LPWSTR*?argv?)
  {
????if(?argc?==?1?||?argc?==?3?)
????????return?SHOW_USAGE;

????g_szObj?=?*(argv?+?1);
????if(?argc?==?2?)
????????return?SHOW_STREAMS;

????LPCWSTR?act?=?*(argv?+?2);
????if(?act[0]?!=?L'-'?&&?act[0]?!=?L'/'?)
????????return?SHOW_USAGE;

????if(?act[1]?==?L'd'?)
????????return?DELETE_STREAMS;

????if(?argc?==?4?||?argc?>?5?)
????????return?SHOW_USAGE;

????g_szStrm?=?*(argv?+?3);
????g_szFile?=?*(argv?+?4);
????if(?act[1]?==?L'i'?)
????????return?IMPORT_STREAM;

????if(?act[1]?==?L'e'?)
????????return?EXPORT_STREAM;

????return?SHOW_USAGE;
}


int?ShowUsage()
  {
????wprintf(?L"USAGE: "
????????L"nsvw?file.a??????????????:??view?streams?in?file.a "
????????L"nsvw?file.a?-d?s1?s2? ?:??delete?stream?s1,?s2?and? ?from?file.a "
????????L"nsvw?file.a?-i?s1?file.b?:??copy?the?content?of?file.b?to?stream?s1?in?file.a "
????????L"nsvw?file.a?-e?s1?file.c?:??copy?the?content?of?stream?s1?in?file.a?to?file.c "
????????);
????return?0;
}


int?ShowStreams()
  {
????HANDLE?hFile?=?CreateFile(?g_szObj,?GENERIC_READ,?FILE_SHARE_READ,?NULL,
????????????OPEN_EXISTING,?FILE_ATTRIBUTE_NORMAL,?NULL?);
????if(?hFile?==?INVALID_HANDLE_VALUE?)
 ???? {
????????wprintf(?L"Unable?to?open?object?"%s" ",?g_szObj?);
????????return?static_cast<int>(?GetLastError()?);
????}

 ????WIN32_STREAM_ID?wsi?=? {0};
????WCHAR?szStrmName[MAX_PATH];
????LPVOID?pContext?=?NULL;

????BOOL?bOk?=?TRUE;
????int?nCount?=?0;
????while(?bOk?)
 ???? {
????????DWORD?dwBytes?=?0;
????????LPBYTE?buf?=?reinterpret_cast<LPBYTE>(?&wsi?);
????????DWORD?dwSize?=?static_cast<DWORD>(offsetof(WIN32_STREAM_ID,?cStreamName));
????????bOk?=?BackupRead(?hFile,?buf,?dwSize,?&dwBytes,?FALSE,?FALSE,?&pContext?);
????????if(?!bOk?||?dwBytes?==?0?)
????????????break;
????????if(?wsi.dwStreamNameSize?>?0?)
 ???????? {
????????????buf?=?reinterpret_cast<LPBYTE>(?szStrmName?);
????????????dwSize?=?wsi.dwStreamNameSize;
????????????BackupRead(?hFile,?buf,?dwSize,?&dwBytes,?FALSE,?FALSE,?&pContext?);
????????????szStrmName[dwSize?/?sizeof(WCHAR)]?=?0;
????????????wprintf(?L"NAME:?"%s" SIZE:?%I64d ",?szStrmName,?wsi.Size.QuadPart?);
????????????++nCount;
????????}
????????DWORD?dw1,?dw2;
????????BackupSeek(?hFile,?wsi.Size.LowPart,?wsi.Size.HighPart,?&dw1,?&dw2,?&pContext?);
????}

????DWORD?dwError?=?GetLastError();
????::BackupRead(?hFile,?NULL,?0,?NULL,?TRUE,?FALSE,?&pContext?);
????::CloseHandle(?hFile?);

????wprintf(?L"Total?%d?stream(s). ",?nCount?);

????return?static_cast<int>(?dwError?);
}



void?BuildStreamName(?LPCWSTR?szStrm,?LPWSTR?buf,?size_t?size?)
  {
????_snwprintf(?buf,?size,?L"%s:%s",?g_szObj,?szStrm?);
????buf[size?-?1]?=?0;
}



int?DeleteStreams(?int?count,?LPWSTR*?streams?)?
  {
????const?int?nSize?=?MAX_PATH?*?2;
????WCHAR?szStrmName[nSize];
????size_t?size?=?sizeof(szStrmName)?/?sizeof(WCHAR);

????for(?int?i?=?0;?i?<?count;?++i?)
 ???? {
????????BuildStreamName(?*(streams?+?i),?szStrmName,?nSize?);
????????if(?::DeleteFileW(?szStrmName?)?)
????????????wprintf(?L"stream?%s?was?deleted. ",?*(streams?+?i)?);
????????else
????????????wprintf(?L"unable?to?delete?stream?%s. ",?*(streams?+?i)?);
????}

????return?0;
}


int?CopyStream(?LPCWSTR?szSrc,?LPCWSTR?szDst?)
  {
????int?nRet?=?0;
????HANDLE?hSrc?=?INVALID_HANDLE_VALUE,?hDst?=?INVALID_HANDLE_VALUE;
????HANDLE?hSrcFm?=?NULL,?hDstFm?=?NULL;
????PVOID?pSrc?=?NULL,?pDst?=?NULL;

????__try
 ???? {
????????hSrc?=?::CreateFile(?szSrc,?GENERIC_READ,?FILE_SHARE_READ,?NULL,?OPEN_EXISTING,?FILE_ATTRIBUTE_NORMAL,?NULL?);
????????if(?hSrc?==?INVALID_HANDLE_VALUE?)
????????????__leave;

????????DWORD?dwSize?=?::GetFileSize(?hSrc,?NULL?);
????????if(?dwSize?>?0?)
 ???????? {
????????????hSrcFm?=?::CreateFileMapping(?hSrc,?NULL,?PAGE_READONLY,?0,?0,?NULL?);
????????????if(?hSrcFm?==?NULL?)
????????????????__leave;

????????????pSrc?=?::MapViewOfFile(?hSrcFm,?FILE_MAP_READ,?0,?0,?dwSize?);
????????????if(?pSrc?==?NULL?)
????????????????__leave;
????????}

????????hDst?=?::CreateFile(?szDst,?FILE_ALL_ACCESS,?FILE_SHARE_READ,?NULL,?CREATE_ALWAYS,?FILE_ATTRIBUTE_NORMAL,?NULL?);
????????if(?hDst?==?INVALID_HANDLE_VALUE?)
????????????__leave;

????????if(?dwSize?>?0?)
 ???????? {
????????????hDstFm?=?::CreateFileMapping(?hDst,?NULL,?PAGE_READWRITE,?0,?dwSize,?NULL?);
????????????if(?hDstFm?==?NULL?)
????????????????__leave;

????????????pDst?=?::MapViewOfFile(?hDstFm,?FILE_MAP_WRITE,?0,?0,?dwSize?);
????????????if(?pDst?==?NULL?)
????????????????__leave;

????????????memcpy(?pDst,?pSrc,?dwSize?);
????????}
????????else
 ???????? {
????????????::SetFilePointer(?hDst,?0,?0,?FILE_BEGIN?);
????????????::SetEndOfFile(?hDst?);
????????}
????}
????__finally
 ???? {
????????nRet?=?static_cast<int>(?::GetLastError()?);
????}

????if(?pDst?!=?NULL?)
????????::UnmapViewOfFile(?pDst?);
????if(?pSrc?!=?NULL?)
????????::UnmapViewOfFile(?pSrc?);
????if(?hDstFm?!=?NULL?)
????????::CloseHandle(?hDstFm?);
????if(?hSrcFm?!=?NULL?)
????????::CloseHandle(?hSrcFm?);
????if(?hDst?!=?INVALID_HANDLE_VALUE?)
????????::CloseHandle(?hDst?);
????if(?hSrc?!=?INVALID_HANDLE_VALUE?)
????????::CloseHandle(?hSrc?);

????return?nRet;
}


int?ImportStream()
  {
????const?int?nSize?=?MAX_PATH?*?2;
????WCHAR?szStrmName[nSize];
????size_t?size?=?sizeof(szStrmName)?/?sizeof(WCHAR);
????BuildStreamName(?g_szStrm,?szStrmName,?nSize?);
????int?nRes?=?CopyStream(?g_szFile,?szStrmName?);
????if(?nRes?!=?0?)
????????wprintf(?L"Import?failed. "?);
????else
????????wprintf(?L"Import?completed. "?);
????return?nRes;
}


int?ExportStream()
  {
????const?int?nSize?=?MAX_PATH?*?2;
????WCHAR?szStrmName[nSize];
????size_t?size?=?sizeof(szStrmName)?/?sizeof(WCHAR);
????BuildStreamName(?g_szStrm,?szStrmName,?nSize?);
????int?nRes?=?CopyStream(?szStrmName,?g_szFile?);
????if(?nRes?!=?0?)
????????wprintf(?L"Export?failed. "?);
????else
????????wprintf(?L"Export?completed. "?);
????return?nRes;

}



int?__cdecl?wmain(?int?argc,?LPWSTR*?argv?)
  {
????int?nRetCode?=?0;

????_wsetlocale(?LC_ALL,?L".OCP"?);
????wprintf(?L"NTFS?Stream?Viewer????????VERSION?1.0 "?);

????switch(?ParseArgs(?argc,?argv?)?)
 ???? {
????case?SHOW_USAGE:
????????nRetCode?=?ShowUsage();
????????break;

????case?SHOW_STREAMS:
????????nRetCode?=?ShowStreams();
????????break;

????case?DELETE_STREAMS:
????????nRetCode?=?DeleteStreams(?argc?-?3,?argv?+?3?);
????????break;

????case?IMPORT_STREAM:
????????nRetCode?=?ImportStream();
????????break;

????case?EXPORT_STREAM:
????????nRetCode?=?ExportStream();
????????break;

????default:
????????wprintf(?L"internel?error! "?);
????????nRetCode?=?-1;
????????break;
????}

????return?nRetCode;
}

|