以文本方式查看主题

-  计算机科学论坛  (http://bbs.xml.org.cn/index.asp)
--  『 C/C++编程思想 』  (http://bbs.xml.org.cn/list.asp?boardid=61)
----  操作稀疏文件源代码  (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=75798)


--  作者:卷积内核
--  发布时间:6/29/2009 11:14:00 AM

--  操作稀疏文件源代码
#define _WIN32_WINNT   0x0500   // Windows 2000 or later

#include <windows.h>
#include <stdio.h>


#define ALLOWED_ATTRIBUTES (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)


void PrintError(DWORD dwErr) {
char szMsg[256];
DWORD dwFlags = FORMAT_MESSAGE_IGNORE_INSERTS |
                  FORMAT_MESSAGE_MAX_WIDTH_MASK |
                  FORMAT_MESSAGE_FROM_SYSTEM;

if (!::FormatMessage(dwFlags, NULL, dwErr, 0, szMsg, sizeof(szMsg), NULL)) strcpy(szMsg, "Unknown error.");
printf(szMsg);
printf("\n");
}


void CopyRange(HANDLE hFrom, HANDLE hTo, LARGE_INTEGER iPos, LARGE_INTEGER iSize) {
BYTE buf[64*1024];
DWORD dwBytesRead, dwBytesWritten;

LONG iPosHigh = iPos.HighPart;
DWORD dr = ::SetFilePointer(hFrom, iPos.LowPart, &iPosHigh, FILE_BEGIN);
if (dr == INVALID_SET_FILE_POINTER) {
   dr = ::GetLastError();
   if (dr != NO_ERROR) throw dr;
}

iPosHigh = iPos.HighPart;
dr = ::SetFilePointer(hTo, iPos.LowPart, &iPosHigh, FILE_BEGIN);
if (dr == INVALID_SET_FILE_POINTER) {
   dr = ::GetLastError();
   if (dr != NO_ERROR) throw dr;
}

while (iSize.QuadPart > 0) {
   if (!::ReadFile(hFrom, buf, (DWORD)min(sizeof(buf), iSize.QuadPart), &dwBytesRead, NULL)) throw ::GetLastError();
   if (!::WriteFile(hTo, buf, dwBytesRead, &dwBytesWritten, NULL)) throw ::GetLastError();
   if (dwBytesWritten < dwBytesRead) throw (DWORD)ERROR_HANDLE_DISK_FULL;
   iSize.QuadPart -= dwBytesRead;
}
}


void main(int argc, char *argv[]) {
HANDLE hInFile, hOutFile;
int iRetCode = EXIT_SUCCESS;

if (argc != 3) {
    printf("\nStream copy program:.\n\nUsage:\n CS fromstream tostream\n\nExample:\n CS c:\\some.txt d:\\file.dat:text\n\n");
    exit(EXIT_SUCCESS);
}

try {
   BY_HANDLE_FILE_INFORMATION bhfi;
   char szPath[MAX_PATH], szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szFName[_MAX_FNAME], szExt[_MAX_EXT];
   LPSTR pszName;
   char szVolName[MAX_PATH], szFSName[MAX_PATH];
   DWORD dwSN, dwMaxLen, dwVolFlags;
   BOOL bSparseCopy = TRUE;
   DWORD dr;

   // Source drive supports sparse files?
   if (!::GetFullPathName(argv[1], MAX_PATH, szPath, &pszName)) throw ::GetLastError();
   _splitpath(szPath, szDrive, szDir, szFName, szExt);
   if (strlen(szDrive)) {
    strcat(szDrive, "\\");
    if (!::GetVolumeInformation(szDrive, szVolName, MAX_PATH, &dwSN, &dwMaxLen, &dwVolFlags, szFSName, MAX_PATH)) throw ::GetLastError();
    bSparseCopy = dwVolFlags & FILE_SUPPORTS_SPARSE_FILES;
   }

   // Target drive supports sparse files?
   if (bSparseCopy) {   // No need to check if source drive does not support
    if (!::GetFullPathName(argv[2], MAX_PATH, szPath, &pszName)) throw ::GetLastError();
    _splitpath(szPath, szDrive, szDir, szFName, szExt);
    if (strlen(szDrive)) {
     strcat(szDrive, "\\");
     if (!::GetVolumeInformation(szDrive, szVolName, MAX_PATH, &dwSN, &dwMaxLen, &dwVolFlags, szFSName, MAX_PATH)) throw ::GetLastError();
     bSparseCopy = dwVolFlags & FILE_SUPPORTS_SPARSE_FILES;
    }
   }

    hInFile = ::CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
    if (hInFile == INVALID_HANDLE_VALUE) throw ::GetLastError();

   if (!::GetFileInformationByHandle(hInFile, &bhfi)) throw ::GetLastError();
   bSparseCopy = bSparseCopy && (bhfi.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE); // Check if the source file is sparse

    hOutFile = ::CreateFile(argv[2], GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
    if (hOutFile == INVALID_HANDLE_VALUE) throw ::GetLastError();

   if (bSparseCopy) {
    // Perform sparse-aware copy

    // Get file size
    LARGE_INTEGER iFileSize;
    iFileSize.LowPart = ::GetFileSize(hInFile, (LPDWORD)&iFileSize.HighPart);
    if (iFileSize.LowPart == (DWORD)-1) {
     dr = ::GetLastError();
     if (dr != NO_ERROR) throw dr;
    }

    DWORD dwTemp;
    if (!::DeviceIoControl(hOutFile, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwTemp, NULL)) throw ::GetLastError();

    // Main loop querying and copying allocated area ranges
    FILE_ALLOCATED_RANGE_BUFFER queryrange;
    FILE_ALLOCATED_RANGE_BUFFER ranges[1024];
    DWORD nbytes, n, i;
    BOOL br;

    queryrange.FileOffset.QuadPart = 0;
    queryrange.Length = iFileSize;

    do { // This loop executes more than once only if the file has more than 1024 allocated areas
     br = ::DeviceIoControl(hInFile, FSCTL_QUERY_ALLOCATED_RANGES, &queryrange, sizeof(queryrange), ranges, sizeof(ranges), &nbytes, NULL);
     if (!br) {
      dr = ::GetLastError();
      if (dr != ERROR_MORE_DATA) throw dr;
     }

     n = nbytes / sizeof(FILE_ALLOCATED_RANGE_BUFFER);   // Calculate the number of records returned
     for (i=0; i<n; i++)   // Main loop
      CopyRange(hInFile, hOutFile, ranges[i].FileOffset, ranges[i].Length);

     // Set starting address and size for the next query
     if (!br && n > 0) {
      queryrange.FileOffset.QuadPart = ranges[n-1].FileOffset.QuadPart + ranges[n-1].Length.QuadPart;
      queryrange.Length.QuadPart = iFileSize.QuadPart - queryrange.FileOffset.QuadPart;
     }
    } while (!br); // Continue loop if ERROR_MORE_DATA

    // Set end of file (required because there can be a sparse area in the end)
    dr = ::SetFilePointer(hOutFile, iFileSize.LowPart, &iFileSize.HighPart, FILE_BEGIN);
    if (dr == INVALID_SET_FILE_POINTER) {
     dr = ::GetLastError();
     if (dr != NO_ERROR) throw dr;
    }
    if (!::SetEndOfFile(hOutFile)) throw ::GetLastError();
   }

   else {
    // Not a sparse file, or sparse copy is impossible
    BYTE buf[64*1024];
    DWORD dwBytesRead, dwBytesWritten;

    do {
     if (!::ReadFile(hInFile, buf, sizeof(buf), &dwBytesRead, NULL)) throw ::GetLastError();
     if (dwBytesRead) {
      if (!::WriteFile(hOutFile, buf, dwBytesRead, &dwBytesWritten, NULL)) throw ::GetLastError();
      if (dwBytesWritten < dwBytesRead) throw (DWORD)ERROR_HANDLE_DISK_FULL;
     }
    } while (dwBytesRead == sizeof(buf));
   }

    ::CloseHandle(hInFile);

   // Set output file attributes
   if (!::SetFileTime(hOutFile, &bhfi.ftCreationTime, &bhfi.ftLastAccessTime, &bhfi.ftLastWriteTime)) throw ::GetLastError();
    ::CloseHandle(hOutFile);
   if (!::SetFileAttributes(argv[2], bhfi.dwFileAttributes & ALLOWED_ATTRIBUTES)) throw ::GetLastError();
}
catch (DWORD dwErrCode) {
    PrintError(dwErrCode);
    iRetCode = EXIT_FAILURE;
}

exit(iRetCode);
}


W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
46.875ms