UltraVNC: C++ source code analysis remote file transfer interface displays remote file system process

UltraVNC: C++ source code analysis remote file transfer interface displays remote file system process

The UltraVNC remote file transfer client is mainly processed in FileTransfer.cpp, and the server is mainly processed in vncclient.cpp.

In addition, here is a brief mention of the file attribute structure under Windows:
The first 44 bytes of WIN32_FIND_DATA represent file attributes.
The FILETIME structure holds a 64-bit unsigned file date and time value. This value represents the time in units of 100 nanoseconds since January 1, 1601.

typedef struct _WIN32_FIND_DATA {
    
    
    DWORD dwFileAttributes; //文件类型,4个字节
    FILETIME ftCreationTime; // 文件创建时间,8个字节
    FILETIME ftLastAccessTime; // 文件最后一次访问时间,8个字节
    FILETIME ftLastWriteTime; // 文件最后一次修改时间,8个字节
    DWORD nFileSizeHigh; // 文件长度高32位,指向内存地址的指针,一般是0,4个字节
    DWORD nFileSizeLow; // 文件长度低32位,内存大小,4个字节
    DWORD dwReserved0; // 系统保留,4个字节
    DWORD dwReserved1; // 系统保留,4个字节
    TCHAR cFileName[ MAX_PATH ]; // 长文件名
    TCHAR cAlternateFileName[ 14 ]; // 8.3格式文件名
} WIN32_FIND_DATA, *PWIN32_FIND_DATA;

The first part of the client file transfer interface displays remote disk information

Client requests remote disk information

//
// request the list of remote drives 
//
void FileTransfer::RequestRemoteDrives()
{
    
    
//	vnclog.Print(0, _T("RequestRemoteDrives\n"));
	if (!m_fFTAllowed) return;

	// TODO : hook error !
    rfbFileTransferMsg ft;
    ft.type = rfbFileTransfer;
	ft.contentType = rfbDirContentRequest;
    ft.contentParam = rfbRDrivesList; // List of Remote Drives please
	ft.length = 0;
    m_pCC->WriteExact((char *)&ft, sz_rfbFileTransferMsg, rfbFileTransfer);

	return;
}

The server receives the request and then obtains the system disk information.
The interface for obtaining disk information is dwLen = GetLogicalDriveStrings(256, szDrivesList);

// The client requests the content of a directory or Drives List
case rfbDirContentRequest:
	switch (msg.ft.contentParam)
	{
    
    
		// Client requests the List of Local Drives
		case rfbRDrivesList:
			{
    
    
               ...
			}
			break;

		// Client requests the content of a directory
		case rfbRDirContent:
			{
    
    
               ...
			}
			break;
	}
	break;

The server sends system disk information to the client

rfbFileTransferMsg ft;
ft.type = rfbFileTransfer;
ft.contentType = rfbDirPacket;
ft.contentParam = rfbADrivesList;
ft.length = Swap32IfLE((int)dwLen);
//adzm 2010-09 - minimize packets. SendExact flushes the queue.
m_socket->SendExactQueue((char *)&ft, sz_rfbFileTransferMsg, rfbFileTransfer);
m_socket->SendExact((char *)szDrivesList, (int)dwLen);

The client receives disk information and processes ListRemoteDrives(hWnd, Swap32IfLE(ft.length));

case rfbADrivesList:
	ListRemoteDrives(hWnd, Swap32IfLE(ft.length));
	m_fFileCommandPending = false;
	break;

The second part of the client file transfer interface displays specific information on a disk on the remote end.

The client requests the remote end to send specific folder information under a certain disk

//
// Request the contents of a remote directory
//
void FileTransfer::RequestRemoteDirectoryContent(HWND hWnd, LPSTR szPath)
{
    
    
//	vnclog.Print(0, _T("RequestRemoteDirectoryContent\n"));
	if (!m_fFTAllowed)
	{
    
    
		m_fFileCommandPending = false;
		return;
	}

	char ofDir[MAX_PATH];
	char ofDirT[MAX_PATH];
	int nSelected = -1;
	int nCount = 0;
	HWND hWndRemoteList = GetDlgItem(hWnd, IDC_REMOTE_FILELIST);

	ofDir[0] = '\0';
	ofDirT[0] = '\0';

	if (lstrlen(szPath) == 0)
	{
    
    
		nCount = ListView_GetItemCount(hWndRemoteList);
		for (nSelected = 0; nSelected < nCount; nSelected++)
		{
    
    
			if(ListView_GetItemState(hWndRemoteList, nSelected, LVIS_SELECTED) & LVIS_SELECTED)
			{
    
    
				LVITEM Item;
				Item.mask = LVIF_TEXT;
				Item.iItem = nSelected;
				Item.iSubItem = 0;
				Item.pszText = ofDirT;
				Item.cchTextMax = MAX_PATH;
				ListView_GetItem(hWndRemoteList, &Item);
				break;
			}
		}
	}
	else
	{
    
    
		if (!IsShortcutFolder(szPath))
			szPath[6] = '\0';
		// szPath always contains a drive letter (X:) or (..)
		strcpy(ofDirT, szPath);
		// In the case of (..) we keep the current path intact
		char szUpDirMask[16];
		sprintf(szUpDirMask, "%s..%s", rfbDirPrefix, rfbDirSuffix);
		if (strcmp(ofDirT, szUpDirMask))
			SetDlgItemText(hWnd, IDC_CURR_REMOTE, "");
	}

	if (nSelected == nCount || lstrlen(ofDirT) == 0)
	{
    
    
		GetDlgItemText(hWnd, IDC_CURR_REMOTE, ofDirT, sizeof(ofDirT));
		if (strlen(ofDirT) == 0) 
		{
    
    
			m_fFileCommandPending = false;
			return; 
		}
	}
	else
	{
    
    
		if (ofDirT[0] == rfbDirPrefix[0] && ofDirT[1] == rfbDirPrefix[1])
		{
    
    
			strncpy(ofDir, ofDirT + 2, strlen(ofDirT) - 3); 
			ofDir[strlen(ofDirT) - 4] = '\0';
		}
		else
		{
    
    
			m_fFileCommandPending = false;
			return;
		}

		GetDlgItemText(hWnd, IDC_CURR_REMOTE, ofDirT, sizeof(ofDirT));
		if (!_stricmp(ofDir, ".."))
		{
    
    	
			char* p;
			ofDirT[strlen(ofDirT) - 1] = '\0';
			p = strrchr(ofDirT, '\\');
			if (p == NULL)
			{
    
    
				m_fFileCommandPending = false;
				return;
			}
			*p = '\0';
		}
		else
			strcat(ofDirT, ofDir);
		strcat(ofDirT, "\\");
		SetDlgItemText(hWnd, IDC_CURR_REMOTE, ofDirT);
	}
	strcpy(ofDir, ofDirT);

	// Todo: In case of shortcuts dir, do a translation here !

	// Select the good drive in the drives combo box (the first time only)
	int nIndex = SendDlgItemMessage(hWnd, IDC_REMOTE_DRIVECB, CB_GETCURSEL, 0, 0L);
	if (nIndex == LB_ERR)
	{
    
    
	    char szDrive[5];
		strcpy(szDrive, rfbDirPrefix);
	    strncat(szDrive, ofDir, 2);
	    nIndex = SendDlgItemMessage(hWnd, IDC_REMOTE_DRIVECB, CB_FINDSTRING, -1, (LPARAM)(LPSTR)szDrive); 
	    SendDlgItemMessage(hWnd, IDC_REMOTE_DRIVECB, CB_SETCURSEL, nIndex, 0L);
	}

	ListView_DeleteAllItems(hWndRemoteList);

    rfbFileTransferMsg ft;
    ft.type = rfbFileTransfer;
	ft.contentType = rfbDirContentRequest;
    ft.contentParam = rfbRDirContent; // Directory content please
	ft.length = Swap32IfLE(strlen(ofDir));
	//adzm 2010-09
    m_pCC->WriteExactQueue((char *)&ft, sz_rfbFileTransferMsg, rfbFileTransfer);
	m_pCC->WriteExact((char *)ofDir, strlen(ofDir));

	return;
}

The server receives the request and then obtains the folder information

// The client requests the content of a directory or Drives List
case rfbDirContentRequest:
	switch (msg.ft.contentParam)
	{
    
    
		// Client requests the List of Local Drives
		case rfbRDrivesList:
			{
    
    
               ...
			}
			break;

		// Client requests the content of a directory
		case rfbRDirContent:
			{
    
    
               ...
			}
			break;
	}
	break;

Main methods to obtain folder contents

WIN32_FIND_DATA fd;
HANDLE ff;
BOOL fRet = TRUE;

ff = FindFirstFile(szDir, &fd);
while ( fRet )
{
    
    
    ...
    /*这里依次把文件夹下每个文件或者目录信息发送到客户端*/
    ....
	fRet = FindNextFile(ff, &fd);
}
FindClose(ff);

Finally, the server sends the end flag

// End of the transfer
ft.contentParam = 0;
ft.length = Swap32IfLE(0);
m_socket->SendExact((char *)&ft, sz_rfbFileTransferMsg, rfbFileTransfer);

The client receives the server folder information. There are two functions
PopulateRemoteListBox(hWnd, Swap32IfLE(ft.length)); update the current directory displayed on the remote side of the file transfer interface
ReceiveDirectoryItem(hWnd, Swap32IfLE(ft.length)); update the file The remote end of the transmission interface displays specific directory information

case rfbDirPacket:
	switch (ft.contentParam)
	{
    
    
	// Response to a rfbRDrivesList request
	case rfbADrivesList:
		ListRemoteDrives(hWnd, Swap32IfLE(ft.length));
		m_fFileCommandPending = false;
		break;

	// Response to a rfbRDirContent request 
	case rfbADirectory:
	case rfbAFile:
		if (!m_fDirectoryReceptionRunning)
			PopulateRemoteListBox(hWnd, Swap32IfLE(ft.length));
		else
			ReceiveDirectoryItem(hWnd, Swap32IfLE(ft.length));
		break;
	default: // This is bad. Add rfbADirectoryEnd instead...
		if (m_fDirectoryReceptionRunning)
		{
    
    
			FinishDirectoryReception();
			m_fFileCommandPending = false;
		}
		break;

	}
	break;

Guess you like

Origin blog.csdn.net/qq_33594636/article/details/131973573