Zeal 瞬间文件分割工具完整源码 2/15
/************************************************************************/
/* Zeal 0.11 In-place file splitter
/* By Roger 2008.11.29 http://rogerfd.cn
/* Change log:
/* 2009.2.12 v0.11 fixes a bug when open file with . in dir
/************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <windows.h>
#include <Shlobj.h>
#pragma pack(push, 1)
typedef struct _fat32_boot_sector
{
BYTE u1[11];
WORD bytes_per_sector;
BYTE sectors_per_cluster;
WORD reserved_sectors_count;
BYTE fats_count;
BYTE u2[11];
DWORD hidden_sectors;
DWORD total_sectors_2;
DWORD sectors_per_fat32;
BYTE u3[4];
DWORD rootdir_cluster;
BYTE u4[34];
char type[8];
BYTE u5[420];
WORD end_flag;
}fat32_boot_sector;
typedef struct _dir_item
{
char name[8];
char ext[3];
BYTE attr;
BYTE reserved;
BYTE create_time_ms;
WORD create_time;
WORD create_date;
WORD last_access_time_ms;
WORD first_cluster_high;
WORD last_access_time;
WORD last_access_date;
WORD first_cluster_low;
DWORD size;
}dir_item;
#pragma pack(pop)
#define MAX_BLOCK 127
class zeal
{
public:
zeal ()
{
m_bDebug = false;
m_bOpen = false;
m_arryFatCache = NULL;
};
~zeal ()
{
};
void set_debug (bool debug)
{
m_bDebug = debug;
}
int cut (const char* szFile, unsigned int count);
int restore (const char* szFile);
private:
int open (char vol);
void close ();
DWORD get_fat (DWORD fat_index);
int set_fat (DWORD fat_index, DWORD fat_value);
int create_empty_file (const char* szFile);
int find_item (DWORD dir_cluster, const char* szShortName, OUT DWORD& first_cluster);
int set_item (DWORD dir_cluster, const char* szShortName, DWORD size, DWORD firstcluster);
DWORD get_last_fat (DWORD fat_index);
void msg_debug (const char* msg, ...);
void msg_error (const char* msg, ...);
int m_vol;
bool m_bDebug;
bool m_bOpen;
HANDLE m_hVol;
DWORD m_OffsetFat1;
DWORD m_OffsetFat2;
DWORD m_OffsetCluster0;
DWORD m_OffsetRootdir;
DWORD m_ClusterSize;
PDWORD m_arryFatCache;
fat32_boot_sector m_BootSector;
};
void zeal::msg_debug (const char* msg, ...)
{
if (!m_bDebug)
{
return;
}
va_list arg;
va_start (arg, msg);
vprintf (msg, arg);
va_end (arg);
}
void zeal::msg_error (const char* msg, ...)
{
va_list arg;
va_start (arg, msg);
vprintf (msg, arg);
va_end (arg);
}
int zeal::create_empty_file (const char* szFile)
{
msg_debug ("creating %s ... \n", szFile);
HANDLE h = CreateFile (szFile, 0, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
if (h == INVALID_HANDLE_VALUE)
{
return -1;
}
CloseHandle (h);
return 0;
}
void strncpy_no_null (char* to, const char* from, int maxchar)
{
for (int i = 0; i < maxchar; ++i)
{
if (from[i] == 0)
{
break;
}
to [i] = from [i];
}
}
void merge_short_name (const char* name, const char* ext, char* shortname)
{
memset (shortname, ' ', 11);
strncpy_no_null (shortname, name, 8);
strncpy_no_null (shortname + 8, ext+1, 3);
}
DWORD get_file_size (const char* szFile)
{
HANDLE hFile = CreateFile (szFile, 0,
FILE_SHARE_WRITE|FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
return 0;
}
DWORD dwLSize;
dwLSize = GetFileSize (hFile, NULL);
CloseHandle (hFile);
return dwLSize;
}
DWORD zeal::get_fat (DWORD index)
{
DWORD off = (m_OffsetFat1 + 4*index) & ~0x1FF;
if (!m_bOpen)
{
goto failed;
}
if (index * m_BootSector.sectors_per_cluster + m_OffsetCluster0/512 > m_BootSector.total_sectors_2)
{
msg_error ("get_fat() error: invalid param!\n");
goto failed;
}
if (m_arryFatCache[index] != 1)
{
return m_arryFatCache[index] & 0x0FFFFFFF;
}
if (off != SetFilePointer (m_hVol, off, 0, FILE_BEGIN))
{
msg_error ("SetFilePointer failed!\n");
goto failed;
}
DWORD read, fat;
DWORD buf[128];
if (!ReadFile (m_hVol, (PBYTE)buf, 512, &read, NULL) || read != 512)
{
msg_error ("ReadFile failed!\n");
goto failed;
}
fat = buf [(m_OffsetFat1/4 + index) % 128];
memcpy ((PBYTE)m
_arryFatCache + 4*index - ((m_OffsetFat1 + 4*index) & 0x1FF), buf, 512);
return fat & 0x0FFFFFFF;
failed:
return ~0;
}
DWORD zeal::get_last_fat (DWORD fat_index)
{
DWORD cluster = fat_index;
DWORD next_cluster;
while (TRUE)
{
next_cluster = get_fat (cluster);
if (next_cluster >= 0xFFFFFF8 && next_cluster <=0xFFFFFFF)
{
return cluster;
}
cluster = next_cluster;
}
}
int zeal::set_fat (DWORD fat_index, DWORD fat_value)
{
DWORD off = (m_OffsetFat1 + 4*fat_index) & ~0x1FF;
if (!m_bOpen)
{
goto failed;
}
if (fat_index * m_BootSector.sectors_per_cluster + m_OffsetCluster0/512 > m_BootSector.total_sectors_2)
{
msg_error ("get_fat() error: invalid param!\n");
goto failed;
}
if (off != SetFilePointer (m_hVol, off, 0, FILE_BEGIN))
{
msg_error ("SetFilePointer failed!\n");
goto failed;
}
DWORD read;
DWORD buf[128];
if (!ReadFile (m_hVol, (PBYTE)buf, 512, &read, NULL) || read != 512)
{
msg_error ("ReadFile failed!\n");
goto failed;
}
buf [(m_OffsetFat1/4 + fat_index) % 128] = fat_value;
if (off != SetFilePointer (m_hVol, off, 0, FILE_BEGIN))
{
goto failed;
}
if (!WriteFile (m_hVol, (PBYTE)buf, 512, &read, NULL) || read != 512)
{
msg_error ("WriteFile failed!\n");
goto t>failed;
}
off = (m_OffsetFat2 + 4*fat_index) & ~0x1FF;
if (off != SetFilePointer (m_hVol, off, 0, FILE_BEGIN))
{
msg_error ("SetFilePointer failed!\n");
goto failed;
}
if (!WriteFile (m_hVol, (PBYTE)buf, 512, &read, NULL) || read != 512)
{
msg_error ("WriteFile failed!\n");
goto failed;
}
return 0;
failed:
return -1;
}
int zeal::set_item (DWORD dir_cluster, const char* szShortName, DWORD size, DWORD firstcluster)
{
if (!m_bOpen)
{
return -1;
}
msg_debug ("try to find %s in 0x%x cluster\n", szShortName, dir_cluster);
DWORD cluster = dir_cluster;
LARGE_INTEGER toMove, moved;
PBYTE buf = new BYTE [m_ClusterSize];
for (;;)
{
toMove.QuadPart = cluster * m_ClusterSize + m_OffsetCluster0;
if (!SetFilePointerEx (m_hVol, toMove, &moved, FILE_BEGIN))
{
msg_error ("SetFilePointerEx failed!\n");
goto failed;
}
DWORD read;
if (!ReadFile (m_hVol, buf, m_ClusterSize, &read, NULL) || read != m_ClusterSize)
{
msg_error ("ReadFile failed!\n");
goto failed;
}
dir_item *pItem = (dir_item*) buf;
for (DWORD i = 0; i < m_ClusterSize/32; ++i, ++pItem)
{
msg_debug ("%d name: %0.11s\n", i, pItem->name);
if (pItem->name[0] == 0)
{
msg_error ("file %s not found!\n", szShortName);
goto failed;
}
if (!strnicmp (pItem->name, szShortName, 11))
{
pItem->size = size;
pItem->first_cluster_low = WORD(firstcluster & 0xFFFF);
pItem->first_cluster_high = WORD(firstcluster >> 16);
if (!SetFilePointerEx (m_hVol, toMove, &moved, FILE_BEGIN))
{
msg_error ("SetFilePointerEx failed!\n");
goto failed;
}
DWORD writen;
if (!WriteFile (m_hVol, buf, m_ClusterSize, &writen, NULL) || writen != m_ClusterSize)
{
msg_error ("WriteFile failed!\n");
goto failed;
}
return 0;
}
}
cluster = get_fat (cluster);
if ((0xFFFFFF8 & cluster) == 0xFFFFFF8)
{
msg_error ("file %s not found!\n", szShortName);
goto failed;
}
msg_debug ("try next cluster %X... \n", cluster);
}
failed:
delete[] buf;
return -1;
}
int zeal::find_item (DWORD dir_cluster, const char* szShortName, OUT DWORD& first_cluster)
{
if (!m_bOpen)
{
return -1;
}
msg_debug ("try to find %s in 0x%x cluster\n", szShortName, dir_cluster);
DWORD cluster = dir_cluster;
LARGE_INTEGER toMove, moved;
PBYTE buf = new BYTE [m_ClusterSize];
char name[11];
memset (name, ' ', 11);
strncpy_no_null (name, szShortName, 11);
for (;;)
{
toMove.QuadPart = cluster * m_ClusterSize + m_OffsetCluster0;
if (!SetFilePointerEx (m_hVol, toMove, &moved, FILE_BEGIN))
{
msg_error ("SetFilePointerEx failed!\n");
goto failed;
}
DWORD read;
if (!ReadFile (m_hVol, buf, m_ClusterSize, &read, NULL) || read != m_ClusterSize)
{
msg_error ("ReadFile failed!\n");
goto failed;
}
dir_item *pItem = (dir_item*) buf;
for (DWORD i = 0; i < m_ClusterSize/32; ++i, ++pItem)
{
msg_debug ("%d name: %0.11s\n", i, pItem->name);
if (pItem->name[0] == 0)
{
msg_error ("file %s not found!\n", szShortName);
goto failed;
}
if (!strnicmp (pItem->name, name, 11))
{
first_cluster = (pItem->first_cluster_high << 16) + pItem->first_cluster_low;
msg_debug ("%0.11s found at 0x%x cluster!\n", name, first_cluster);
delete[] buf;
return 0;
}
}
cluster = get_fat (cluster);
if (cluster < 2 || cluster > 0xFFFFFEF)
{
msg_error ("file %s not found!\n", szShortName);
goto failed;
}
}
failed:
delete[] buf;
return -1;
}
int zeal::restore (const char* szFile)
{
char drv[4], shortname[12], path[MAX_PATH], filename[MAX_PATH], ext[MAX_PATH];
char oripath[MAX_PATH] = {0}, shortpath[MAX_PATH], newpath[MAX_PATH];
DWORD count, i, ret;
char *p, *subdir;
DWORD firstclusters[MAX_BLOCK color="#000080">+1], lastclusters[MAX_BLOCK+1];
DWORD cluster = 2, nextcluster, dirCluster, filesize = 0;
DWORD startTime = GetTickCount ();
_splitpath (szFile, drv, path, filename, ext);
if (stricmp (ext, ".zeal"))
{
msg_error ("Not generated by zeal!\n");
goto failed;
}
p = strstr (filename, ".part");
if (!p)
{
msg_error ("Not generated by zeal!\n");
goto failed;
}
if (sscanf (p + 5, "%*d-%d", &count) != 1)
{
msg_error ("Not generated by zeal!\n");
goto failed;
}
memcpy (oripath, szFile, strstr (szFile, ".part") - szFile);
msg_debug ("ori file path: %s\n", oripath);
if (!_access (oripath, 0))
{
msg_error ("%s already exists!\n", oripath);
goto failed;
}
for (i = 1; i <= count; ++i)
{
sprintf (newpath, "%s.part%d-%d.zeal", oripath, i, count);
ret = get_file_size (newpath);
if (ret == 0)
{
msg_error ("%s missing!\n", newpath);
goto failed;
}
filesize += ret;
}
if (open (drv[0]))
{
msg_error ("failed to open %s!\n", drv);
goto failed;
}
// check size a again, to avoid this, make block size align to 64KB
for (i = 1; i < count; ++i)
{
sprintf (newpath, "%s.part%d-%d.zeal", oripath, i, count);
ret = get_file_size (newpath);
r="#0000FF">if (ret & (m_ClusterSize-1))
{
msg_error ("file size alignment error!\n");
goto failed;
}
}
sprintf (newpath, "%s.part%d-%d.zeal", oripath, 1, count);
if(!GetShortPathName(newpath, shortpath, MAX_PATH))
{
msg_error ("GetShortPathName (%s) failed!\n", newpath);
goto failed;
}
_splitpath (shortpath, drv, path, filename, ext);
subdir = strtok (path, "\\");
while (subdir != NULL)
{
_splitpath (subdir, NULL, NULL, filename, ext);
merge_short_name (filename, ext, shortname);
if (find_item (cluster, shortname, nextcluster))
{
msg_error ("find_item failed!\n");
goto failed;
}
cluster = nextcluster;
subdir = strtok (NULL, "\\");
}
dirCluster = cluster;
for (i = 1; i <= count; ++i)
{
sprintf (newpath, "%s.part%d-%d.zeal", oripath, i, count);
if(!GetShortPathName(newpath, shortpath, MAX_PATH))
{
msg_error ("GetShortPathName (%s) failed!\n", newpath);
goto failed;
}
_splitpath (shortpath, drv, path, filename, ext);
merge_short_name (filename, ext, shortname);
if (find_item (dirCluster, shortname, cluster))
{
msg_error ("find_item failed!\n");
goto failed;
}
if (i == 1)
{
if (set_item (dirCluster, shortname, filesize, cluster))
{
msg_error
("set_item failed!\n");
goto failed;
}
}
else
{
if (set_item (dirCluster, shortname, 0, 0))
{
msg_error ("set_item failed!\n");
goto failed;
}
}
firstclusters[i] = cluster;
lastclusters [i] = get_last_fat (cluster);
}
for (i = 1; i < count; ++i)
{
if (set_fat (lastclusters[i], firstclusters[i+1]))
{
msg_error ("set_item failed!\n");
goto failed;
}
}
close ();
for (i = 1; i <= count; ++i)
{
sprintf (newpath, "%s.part%d-%d.zeal", oripath, i, count);
if (i == 1)
{
if (rename (newpath, oripath))
{
msg_error ("rename %s failed!\n", newpath);
goto failed;
}
}
else
{
if (remove (newpath))
{
msg_error ("remove %s failed!\n", newpath);
goto failed;
}
}
}
SHChangeNotify (SHCNE_ALLEVENTS, 0, 0, 0);
printf ("Done! %d ms used\n", GetTickCount () - startTime);
return 0;
failed:
SHChangeNotify (SHCNE_ALLEVENTS, 0, 0, 0);
close ();
return -1;
}
int zeal::cut (const char* szFile, unsigned int count)
{
char drv[4], path[MAX_PATH], filename[MAX_PATH], ext[MAX_PATH];
char shortpath[MAX_PATH], newpath[MAX_PATH];
char shortname[12] = { ont>0};
DWORD nSize, nCluster, nLastCluster, nLastSize, dirCluster, i, j;
DWORD size = get_file_size (szFile);
DWORD firstclusters[MAX_BLOCK+1], lastclusters[MAX_BLOCK+1];
char* subdir;
DWORD cluster = 2, nextcluster;
DWORD startTime = GetTickCount ();
bool files_created = false;
if (count < 2)
{
msg_error ("Nothing to do ?\n");
goto failed;
}
if (count > MAX_BLOCK)
{
msg_error ("Too many blocks! Max %d\n", MAX_BLOCK);
goto failed;
}
if(!GetShortPathName(szFile, shortpath, MAX_PATH))
{
msg_error ("GetShortPathName (%s) failed!\n", szFile);
goto failed;
}
_splitpath (shortpath, drv, path, filename, ext);
// check if files already exists
for (i = 1; i <= count; ++i)
{
sprintf (newpath, "%s.part%d-%d.zeal", szFile, i, count);
if (!_access (newpath, 0))
{
msg_error ("%s already exists!\n", newpath);
goto failed;
}
if (i!=1 && create_empty_file (newpath))
{
msg_error ("Failed to create %s!\n", newpath);
goto failed;
}
}
files_created = true;
if (open (drv[0]))
{
msg_error ("failed to open %s!\n", drv);
goto failed;
}
if (size < m_ClusterSize * count)
{
msg_error ("Block size < %d, exit!\n", m_ClusterSize);
goto failed;
}
// size per block, down align to m_ClusterSize
nSize = (size / count) & ~(m_ClusterSize -
1);
// clusters per block
nCluster = nSize / m_ClusterSize;
// size of last block
nLastSize = size - (count-1)*nSize;
// clusters of last block
nLastCluster = (nLastSize + m_ClusterSize - 1) / m_ClusterSize;
subdir = strtok (path, "\\");
while (subdir != NULL)
{
_splitpath (subdir, NULL, NULL, filename, ext);
merge_short_name (filename, ext, shortname);
if (find_item (cluster, shortname, nextcluster))
{
msg_error ("find_item failed!\n");
goto failed;
}
cluster = nextcluster;
subdir = strtok (NULL, "\\");
}
dirCluster = cluster;
_splitpath (shortpath, drv, path, filename, ext);
merge_short_name (filename, ext, shortname);
if (find_item (dirCluster, shortname, nextcluster))
{
msg_error ("find_item failed!\n");
goto failed;
}
// now nextcluster is the first content of the file
firstclusters[1] = nextcluster;
cluster = nextcluster;
for (i = 2; i <= count; ++i)
{
for (j = 0; j < nCluster; ++j)
{
if (j == nCluster - 1)
{
lastclusters[i-1] = cluster;
}
cluster = get_fat (cluster);
if (cluster < 0x2 || cluster > 0xFFFFFEF)
{
msg_error ("Error parsing fat!\n");
goto failed;
}
}
firstclusters[i] = cluster;
}
// set the others
for (i = 2; i color="#000080">< count; ++i)
{
sprintf (newpath, "%s.part%d-%d.zeal", szFile, i, count);
if(!GetShortPathName(newpath, shortpath, MAX_PATH))
{
printf ("GetShortPathName (%s) failed!\n", newpath);
goto failed;
}
_splitpath (shortpath, drv, path, filename, ext);
merge_short_name (filename, ext, shortname);
if (set_item (dirCluster, shortname, nSize, firstclusters[i]))
{
msg_error ("set_item failed!\n");
goto failed;
}
if (set_fat (lastclusters[i], 0x0FFFFFFF))
{
msg_error ("set_fat failed!\n");
goto failed;
}
}
// set the last one
sprintf (newpath, "%s.part%d-%d.zeal", szFile, i, count);
if(!GetShortPathName(newpath, shortpath, MAX_PATH))
{
msg_error ("GetShortPathName (%s) failed!\n", newpath);
goto failed;
}
_splitpath (shortpath, drv, path, filename, ext);
merge_short_name (filename, ext, shortname);
if (set_item (dirCluster, shortname, nLastSize, firstclusters[count]))
{
msg_error ("set_item failed!\n");
goto failed;
}
// set the first part
if(!GetShortPathName(szFile, shortpath, MAX_PATH))
{
msg_error ("GetShortPathName (%s) failed!\n", newpath);
goto failed;
}
_splitpath (shortpath, drv, path, filename, ext);
merge_short_name (filename, ext, shortname);
if (set_item (dirCluster, shortname, nSize, firstclusters[1]))
{
msg_error (<
/font>"set_item failed!\n");
goto failed;
}
if (set_fat (lastclusters[1], 0x0FFFFFFF))
{
msg_error ("set_fat failed!\n");
goto failed;
}
close ();
sprintf (newpath, "%s.part%d-%d.zeal", szFile, 1, count);
if (rename (szFile, newpath))
{
msg_error ("Rename failed!\n");
goto failed;
}
SHChangeNotify (SHCNE_ALLEVENTS, 0, 0, 0);
printf ("Done! %d ms used\n", GetTickCount () - startTime);
return 0;
failed:
close ();
if (files_created)
{
for (i = 2; i <= count; ++i)
{
sprintf (newpath, "%s.part%d-%d.zeal", szFile, i, count);
remove (newpath);
}
}
return -1;
}
int zeal::open (char vol)
{
if (m_bOpen)
{
close ();
}
char volname[] = "\\\\.\\A:";
volname[4] = vol;
m_hVol = CreateFile (volname,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING,
NULL
);
if (m_hVol == INVALID_HANDLE_VALUE)
{
msg_error ("failed to open %s!\n", volname);
goto failed;
}
DWORD ret, read, i;
ret = ReadFile (m_hVol, (PVOID)&m_BootSector, 512, &read, NULL);
if (!ret || read != 512)
{
msg_error ("ReadFile failed!\n");
goto failed;
}
if (strnicmp(m_BootSector.type, "FAT32 ", 8)
||
m_BootSector.end_flag != 0xAA55)
{
msg_error ("Only FAT32 is supported now, NTFS support will come later\n");
goto failed;
}
if (m_BootSector.bytes_per_sector != 512)
{
msg_error ("Error: sector size %d!\n", m_BootSector.bytes_per_sector);
goto failed;
}
m_ClusterSize = 512 * m_BootSector.sectors_per_cluster;
m_OffsetFat1 = m_BootSector.reserved_sectors_count * 512;
m_OffsetFat2 = m_OffsetFat1 + m_BootSector.sectors_per_fat32 * 512;
m_OffsetCluster0 = m_OffsetFat2 + m_BootSector.sectors_per_fat32 * 512 - 2 * m_ClusterSize;
m_OffsetRootdir = m_OffsetCluster0 + m_BootSector.rootdir_cluster * m_ClusterSize;
m_vol = vol;
m_bOpen = true;
m_arryFatCache = new DWORD [m_BootSector.sectors_per_fat32 * 128];
for (i = 0; i < m_BootSector.sectors_per_fat32 * 128; ++i)
{
m_arryFatCache[i] = 1;
}
return 0;
failed:
if (m_hVol != INVALID_HANDLE_VALUE)
{
CloseHandle (m_hVol);
}
return -1;
}
void zeal::close ()
{
if (m_bOpen)
{
CloseHandle (m_hVol);
delete[] m_arryFatCache;
}
m_bOpen = false;
}
void Logo ()
{
puts ("Roger's Zeal for fat32");
puts ("Version: 0.11");
puts ("Mailto : roger99707@163.com");
puts ("Blog : http://rogerfd.cn\n");
}
void Usage ()
{
puts ("Zeal is a in-place file spiltter ");
puts ("Usage: zeal.exe file_to_split(full path) count ");
puts (" zeal.exe file_to_restore(any piece) ");
}
int main (int argc, char* argv[])
{
Logo ();
zeal z;
if (argc < 2 <
/font>|| argc > 3)
{
Usage ();
return 0;
}
#ifdef _DEBUG
z.set_debug (true);
#else
z.set_debug (false);
#endif
if (argc == 3)
{
z.cut (argv[1], atoi(argv[2]));
}
if (argc == 2)
{
z.restore (argv[1]);
}
return 0;
}
目前有0条回应
Comment
Trackback