Home | History | Annotate | Download | only in tightvnc-filetransfer
      1 /*
      2  * Copyright (c) 2005 Novell, Inc.
      3  * All Rights Reserved.
      4  *
      5  * This program is free software; you can redistribute it and/or
      6  * modify it under the terms of version 2 of the GNU General Public License as
      7  * published by the Free Software Foundation.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12  * GNU General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program; if not, contact Novell, Inc.
     16  *
     17  * To contact Novell about this file by physical or electronic mail,
     18  * you may find current contact information at www.novell.com
     19  *
     20  * Author		: Rohit Kumar
     21  * Email ID	: rokumar (at) novell.com
     22  * Date		: 14th July 2005
     23  */
     24 
     25 
     26 #include <stdio.h>
     27 #include <string.h>
     28 #include <stdlib.h>
     29 #include <fcntl.h>
     30 
     31 #ifdef WIN32
     32 #include <io.h>
     33 #include <direct.h>
     34 #include <sys/utime.h>
     35 #ifdef _MSC_VER
     36 #define S_ISREG(m)	(((m) & _S_IFMT) == _S_IFREG)
     37 #define S_ISDIR(m)	(((m) & S_IFDIR) == S_IFDIR)
     38 #define S_IWUSR		S_IWRITE
     39 #define S_IRUSR		S_IREAD
     40 #define S_IWOTH		0x0000002
     41 #define S_IROTH		0x0000004
     42 #define S_IWGRP		0x0000010
     43 #define S_IRGRP		0x0000020
     44 #define mkdir(path, perms) _mkdir(path) /* Match POSIX signature */
     45 /* Prevent POSIX deprecation warnings on MSVC */
     46 #define creat _creat
     47 #define open _open
     48 #define read _read
     49 #define write _write
     50 #define close _close
     51 #define unlink _unlink
     52 #endif /* _MSC_VER */
     53 #else
     54 #include <dirent.h>
     55 #include <utime.h>
     56 #endif
     57 
     58 #include <errno.h>
     59 #include <unistd.h>
     60 #include <sys/stat.h>
     61 #include <sys/types.h>
     62 
     63 #include <rfb/rfb.h>
     64 #include "rfbtightproto.h"
     65 #include "filelistinfo.h"
     66 #include "filetransfermsg.h"
     67 #include "handlefiletransferrequest.h"
     68 
     69 #define SZ_RFBBLOCKSIZE 8192
     70 
     71 
     72 void
     73 FreeFileTransferMsg(FileTransferMsg ftm)
     74 {
     75 
     76 	if(ftm.data != NULL) {
     77 		free(ftm.data);
     78 		ftm.data = NULL;
     79 	}
     80 
     81 	ftm.length = 0;
     82 
     83 }
     84 
     85 
     86 /******************************************************************************
     87  * Methods to handle file list request.
     88  ******************************************************************************/
     89 
     90 int CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag);
     91 FileTransferMsg CreateFileListErrMsg(char flags);
     92 FileTransferMsg CreateFileListMsg(FileListInfo fileListInfo, char flags);
     93 
     94 
     95 /*
     96  * This is the method called by HandleFileListRequest to get the file list
     97  */
     98 
     99 FileTransferMsg
    100 GetFileListResponseMsg(char* path, char flags)
    101 {
    102 	FileTransferMsg fileListMsg;
    103 	FileListInfo fileListInfo;
    104 	int status = -1;
    105 
    106 	memset(&fileListMsg, 0, sizeof(FileTransferMsg));
    107 	memset(&fileListInfo, 0, sizeof(FileListInfo));
    108 
    109 
    110 	 /* fileListInfo can have null data if the folder is Empty
    111     	or if some error condition has occured.
    112     	The return value is 'failure' only if some error condition has occured.
    113 	 */
    114 	status = CreateFileListInfo(&fileListInfo, path, !(flags  & 0x10));
    115 
    116 	if(status == FAILURE) {
    117 		fileListMsg = CreateFileListErrMsg(flags);
    118 	}
    119 	else {
    120 		/* DisplayFileList(fileListInfo); For Debugging  */
    121 
    122 		fileListMsg = CreateFileListMsg(fileListInfo, flags);
    123 		FreeFileListInfo(fileListInfo);
    124 	}
    125 
    126 	return fileListMsg;
    127 }
    128 
    129 #if !defined(__GNUC__) && !defined(_MSC_VER)
    130 #define __FUNCTION__ "unknown"
    131 #endif
    132 
    133 #ifdef WIN32
    134 
    135 /* Most of the Windows version here is based on https://github.com/danielgindi/FileDir */
    136 
    137 #define FILETIME_TO_TIME_T(FILETIME) (((((__int64)FILETIME.dwLowDateTime) | (((__int64)FILETIME.dwHighDateTime) << 32)) - 116444736000000000L) / 10000000L)
    138 
    139 #ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
    140 #define IS_REGULAR_FILE_HAS_ATTRIBUTE_INTEGRITY_STREAM(dwFileAttributes) (!!(dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM))
    141 #else
    142 #define IS_REGULAR_FILE_HAS_ATTRIBUTE_INTEGRITY_STREAM(dwFileAttributes) 0
    143 #endif
    144 
    145 #ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
    146 #define IS_REGULAR_FILE_HAS_ATTRIBUTE_NO_SCRUB_DATA(dwFileAttributes) (!!(dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA))
    147 #else
    148 #define IS_REGULAR_FILE_HAS_ATTRIBUTE_NO_SCRUB_DATA(dwFileAttributes) 0
    149 #endif
    150 
    151 #define IS_REGULAR_FILE(dwFileAttributes) \
    152 	( \
    153 	!!(dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || \
    154 	( \
    155 	!(dwFileAttributes & FILE_ATTRIBUTE_DEVICE) && \
    156 	!(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && \
    157 	!(dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) && \
    158 	!IS_REGULAR_FILE_HAS_ATTRIBUTE_INTEGRITY_STREAM(dwFileAttributes) && \
    159 	!IS_REGULAR_FILE_HAS_ATTRIBUTE_NO_SCRUB_DATA(dwFileAttributes) && \
    160 	!(dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) && \
    161 	!(dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) \
    162 	) \
    163 	)
    164 
    165 #define IS_FOLDER(dwFileAttributes) (!!(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
    166 
    167 int
    168 CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag)
    169 {
    170 	int pathLen, basePathLength;
    171 	char *basePath, *pChar;
    172 	WIN32_FIND_DATAA winFindData;
    173 	HANDLE findHandle;
    174 
    175 	if(path == NULL) {
    176 		return FAILURE;
    177 	}
    178 
    179 	if(strlen(path) == 0) {
    180 		/* In this case we will send the list of entries in ftp root*/
    181 		sprintf(path, "%s%s", GetFtpRoot(), "/");
    182 	}
    183 
    184 	/* Create a search string, like C:\folder\* */
    185 
    186 	pathLen = strlen(path);
    187 	basePath = malloc(pathLen + 3);
    188 	memcpy(basePath, path, pathLen);
    189 	basePathLength = pathLen;
    190 	basePath[basePathLength] = '\\';
    191 	basePath[basePathLength + 1] = '*';
    192 	basePath[basePathLength + 2] = '\0';
    193 
    194 	/* Start a search */
    195 	memset(&winFindData, 0, sizeof(winFindData));
    196 	findHandle = FindFirstFileA(path, &winFindData);
    197 
    198 	basePath[basePathLength] = '\0'; /* Restore to a basePath + \ */
    199 	/* Convert \ to / */
    200 	for(pChar = basePath; *pChar; pChar++) {
    201 		if (*pChar == '\\') {
    202 			*pChar = '/';
    203 		}
    204 	}
    205 
    206 	/* While we can find a next file do...
    207 	   But ignore \. and '.. entries, which are current folder and parent folder respectively */
    208 	while(findHandle != INVALID_HANDLE_VALUE && winFindData.cFileName[0] == '.' &&
    209 		(winFindData.cFileName[1] == '\0' ||
    210 		(winFindData.cFileName[1] == '.' && winFindData.cFileName[2] == '\0'))) {
    211 		char fullpath[PATH_MAX];
    212 		fullpath[0] = 0;
    213 
    214 		strncpy_s(fullpath, PATH_MAX, basePath, basePathLength);
    215 		strncpy_s(fullpath + basePathLength, PATH_MAX - basePathLength, winFindData.cFileName, (int)strlen(winFindData.cFileName));
    216 
    217 		if(IS_FOLDER(winFindData.dwFileAttributes)) {
    218 			if (AddFileListItemInfo(pFileListInfo, winFindData.cFileName, -1, 0) == 0) {
    219 				rfbLog("File [%s]: Method [%s]: Add directory %s in the"
    220 					" list failed\n", __FILE__, __FUNCTION__, fullpath);
    221 				continue;
    222 			}
    223 		}
    224 		else if(IS_REGULAR_FILE(winFindData.dwFileAttributes)) {
    225 			if(flag) {
    226 				unsigned int fileSize = (winFindData.nFileSizeHigh * (MAXDWORD+1)) + winFindData.nFileSizeLow;
    227 				if(AddFileListItemInfo(pFileListInfo, winFindData.cFileName, fileSize, FILETIME_TO_TIME_T(winFindData.ftLastWriteTime)) == 0) {
    228 					rfbLog("File [%s]: Method [%s]: Add file %s in the "
    229 						"list failed\n", __FILE__, __FUNCTION__, fullpath);
    230 					continue;
    231 				}
    232 			}
    233 		}
    234 
    235 		if(FindNextFileA(findHandle, &winFindData) == 0) {
    236 			FindClose(findHandle);
    237 			findHandle = INVALID_HANDLE_VALUE;
    238 		}
    239 	}
    240 
    241 	if(findHandle != INVALID_HANDLE_VALUE) {
    242 		FindClose(findHandle);
    243 	}
    244 
    245 	free(basePath);
    246 
    247 	return SUCCESS;
    248 }
    249 
    250 #else /* WIN32 */
    251 
    252 int
    253 CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag)
    254 {
    255 	DIR* pDir = NULL;
    256 	struct dirent* pDirent = NULL;
    257 
    258 	if(path == NULL) {
    259 		return FAILURE;
    260 	}
    261 
    262 	if(strlen(path) == 0) {
    263 		/* In this case we will send the list of entries in ftp root*/
    264 		sprintf(path, "%s%s", GetFtpRoot(), "/");
    265 	}
    266 
    267 	if((pDir = opendir(path)) == NULL) {
    268 		rfbLog("File [%s]: Method [%s]: not able to open the dir\n",
    269 				__FILE__, __FUNCTION__);
    270 		return FAILURE;
    271 	}
    272 
    273 	while((pDirent = readdir(pDir))) {
    274 		if(strcmp(pDirent->d_name, ".") && strcmp(pDirent->d_name, "..")) {
    275 			struct stat stat_buf;
    276 			/*
    277 			int fpLen = sizeof(char)*(strlen(pDirent->d_name)+strlen(path)+2);
    278 			*/
    279 			char fullpath[PATH_MAX];
    280 
    281 			memset(fullpath, 0, PATH_MAX);
    282 
    283 			strcpy(fullpath, path);
    284 			if(path[strlen(path)-1] != '/')
    285 				strcat(fullpath, "/");
    286 			strcat(fullpath, pDirent->d_name);
    287 
    288 			if(stat(fullpath, &stat_buf) < 0) {
    289 				rfbLog("File [%s]: Method [%s]: Reading stat for file %s failed\n",
    290 						__FILE__, __FUNCTION__, fullpath);
    291 				continue;
    292 			}
    293 
    294 			if(S_ISDIR(stat_buf.st_mode)) {
    295 				if(AddFileListItemInfo(pFileListInfo, pDirent->d_name, -1, 0) == 0) {
    296 					rfbLog("File [%s]: Method [%s]: Add directory %s in the"
    297 							" list failed\n", __FILE__, __FUNCTION__, fullpath);
    298 					continue;
    299 				}
    300 			}
    301 			else {
    302 				if(flag) {
    303 					if(AddFileListItemInfo(pFileListInfo, pDirent->d_name,
    304 												stat_buf.st_size,
    305 												stat_buf.st_mtime) == 0) {
    306 						rfbLog("File [%s]: Method [%s]: Add file %s in the "
    307 								"list failed\n", __FILE__, __FUNCTION__, fullpath);
    308 						continue;
    309 					}
    310 				}
    311 			}
    312 		}
    313 	}
    314 	if(closedir(pDir) < 0) {
    315 	    rfbLog("File [%s]: Method [%s]: ERROR Couldn't close dir\n",
    316 	    	__FILE__, __FUNCTION__);
    317 	}
    318 
    319 	return SUCCESS;
    320 }
    321 
    322 #endif
    323 
    324 
    325 FileTransferMsg
    326 CreateFileListErrMsg(char flags)
    327 {
    328 	FileTransferMsg fileListMsg;
    329 	rfbFileListDataMsg* pFLD = NULL;
    330 	char* data = NULL;
    331 	unsigned int length = 0;
    332 
    333 	memset(&fileListMsg, 0, sizeof(FileTransferMsg));
    334 
    335 	data = (char*) calloc(sizeof(rfbFileListDataMsg), sizeof(char));
    336 	if(data == NULL) {
    337 		return fileListMsg;
    338 	}
    339 	length = sizeof(rfbFileListDataMsg) * sizeof(char);
    340 	pFLD = (rfbFileListDataMsg*) data;
    341 
    342 	pFLD->type = rfbFileListData;
    343 	pFLD->numFiles = Swap16IfLE(0);
    344 	pFLD->dataSize = Swap16IfLE(0);
    345 	pFLD->compressedSize = Swap16IfLE(0);
    346 	pFLD->flags = flags | 0x80;
    347 
    348 	fileListMsg.data = data;
    349 	fileListMsg.length = length;
    350 
    351 	return fileListMsg;
    352 }
    353 
    354 
    355 FileTransferMsg
    356 CreateFileListMsg(FileListInfo fileListInfo, char flags)
    357 {
    358 	FileTransferMsg fileListMsg;
    359 	rfbFileListDataMsg* pFLD = NULL;
    360 	char *data = NULL, *pFileNames = NULL;
    361 	unsigned int length = 0, dsSize = 0, i = 0;
    362 	FileListItemSizePtr pFileListItemSize = NULL;
    363 
    364 	memset(&fileListMsg, 0, sizeof(FileTransferMsg));
    365 	dsSize = fileListInfo.numEntries * 8;
    366 	length = sz_rfbFileListDataMsg + dsSize +
    367 			GetSumOfFileNamesLength(fileListInfo) +
    368 			fileListInfo.numEntries;
    369 
    370 	data = (char*) calloc(length, sizeof(char));
    371 	if(data == NULL) {
    372 		return fileListMsg;
    373 	}
    374 	pFLD = (rfbFileListDataMsg*) data;
    375 	pFileListItemSize = (FileListItemSizePtr) &data[sz_rfbFileListDataMsg];
    376 	pFileNames = &data[sz_rfbFileListDataMsg + dsSize];
    377 
    378 	pFLD->type            = rfbFileListData;
    379     pFLD->flags 		  = flags & 0xF0;
    380     pFLD->numFiles 		  = Swap16IfLE(fileListInfo.numEntries);
    381     pFLD->dataSize 		  = Swap16IfLE(GetSumOfFileNamesLength(fileListInfo) +
    382     									fileListInfo.numEntries);
    383     pFLD->compressedSize  = pFLD->dataSize;
    384 
    385 	for(i =0; i <fileListInfo.numEntries; i++) {
    386 		pFileListItemSize[i].size = Swap32IfLE(GetFileSizeAt(fileListInfo, i));
    387 		pFileListItemSize[i].data = Swap32IfLE(GetFileDataAt(fileListInfo, i));
    388 		strcpy(pFileNames, GetFileNameAt(fileListInfo, i));
    389 
    390 		if(i+1 < fileListInfo.numEntries)
    391 			pFileNames += strlen(pFileNames) + 1;
    392 	}
    393 
    394 	fileListMsg.data 	= data;
    395 	fileListMsg.length 	= length;
    396 
    397 	return fileListMsg;
    398 }
    399 
    400 
    401 /******************************************************************************
    402  * Methods to handle File Download Request.
    403  ******************************************************************************/
    404 
    405 FileTransferMsg CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen);
    406 FileTransferMsg CreateFileDownloadZeroSizeDataMsg(unsigned long mTime);
    407 FileTransferMsg CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile);
    408 
    409 FileTransferMsg
    410 GetFileDownLoadErrMsg()
    411 {
    412 	FileTransferMsg fileDownloadErrMsg;
    413 
    414 	char reason[] = "An internal error on the server caused download failure";
    415 	int reasonLen = strlen(reason);
    416 
    417 	memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg));
    418 
    419 	fileDownloadErrMsg = CreateFileDownloadErrMsg(reason, reasonLen);
    420 
    421 	return fileDownloadErrMsg;
    422 }
    423 
    424 
    425 FileTransferMsg
    426 GetFileDownloadReadDataErrMsg()
    427 {
    428 	char reason[] = "Cannot open file, perhaps it is absent or is a directory";
    429 	int reasonLen = strlen(reason);
    430 
    431 	return CreateFileDownloadErrMsg(reason, reasonLen);
    432 
    433 }
    434 
    435 
    436 FileTransferMsg
    437 GetFileDownloadLengthErrResponseMsg()
    438 {
    439 	char reason [] = "Path length exceeds PATH_MAX (4096) bytes";
    440 	int reasonLen = strlen(reason);
    441 
    442 	return CreateFileDownloadErrMsg(reason, reasonLen);
    443 }
    444 
    445 
    446 FileTransferMsg
    447 GetFileDownloadResponseMsgInBlocks(rfbClientPtr cl, rfbTightClientPtr rtcp)
    448 {
    449 	/* const unsigned int sz_rfbBlockSize = SZ_RFBBLOCKSIZE; */
    450     int numOfBytesRead = 0;
    451 	char pBuf[SZ_RFBBLOCKSIZE];
    452 	char* path = rtcp->rcft.rcfd.fName;
    453 
    454 	memset(pBuf, 0, SZ_RFBBLOCKSIZE);
    455 
    456 	if((rtcp->rcft.rcfd.downloadInProgress == FALSE) && (rtcp->rcft.rcfd.downloadFD == -1)) {
    457 		if((rtcp->rcft.rcfd.downloadFD = open(path, O_RDONLY)) == -1) {
    458 			rfbLog("File [%s]: Method [%s]: Error: Couldn't open file\n",
    459 					__FILE__, __FUNCTION__);
    460 			return GetFileDownloadReadDataErrMsg();
    461 		}
    462 		rtcp->rcft.rcfd.downloadInProgress = TRUE;
    463 	}
    464 	if((rtcp->rcft.rcfd.downloadInProgress == TRUE) && (rtcp->rcft.rcfd.downloadFD != -1)) {
    465 		if( (numOfBytesRead = read(rtcp->rcft.rcfd.downloadFD, pBuf, SZ_RFBBLOCKSIZE)) <= 0) {
    466 			close(rtcp->rcft.rcfd.downloadFD);
    467 			rtcp->rcft.rcfd.downloadFD = -1;
    468 			rtcp->rcft.rcfd.downloadInProgress = FALSE;
    469 			if(numOfBytesRead == 0) {
    470 				return CreateFileDownloadZeroSizeDataMsg(rtcp->rcft.rcfd.mTime);
    471 			}
    472 			return GetFileDownloadReadDataErrMsg();
    473 		}
    474 	return CreateFileDownloadBlockSizeDataMsg(numOfBytesRead, pBuf);
    475 	}
    476 	return GetFileDownLoadErrMsg();
    477 }
    478 
    479 
    480 FileTransferMsg
    481 ChkFileDownloadErr(rfbClientPtr cl, rfbTightClientPtr rtcp)
    482 {
    483     FileTransferMsg fileDownloadMsg;
    484 	struct stat stat_buf;
    485 	int sz_rfbFileSize = 0;
    486 	char* path = rtcp->rcft.rcfd.fName;
    487 
    488 	memset(&fileDownloadMsg, 0, sizeof(FileTransferMsg));
    489 
    490 	if( (path == NULL) || (strlen(path) == 0) ||
    491 		(stat(path, &stat_buf) < 0) || (!(S_ISREG(stat_buf.st_mode))) ) {
    492 
    493 			char reason[] = "Cannot open file, perhaps it is absent or is not a regular file";
    494 			int reasonLen = strlen(reason);
    495 
    496 			rfbLog("File [%s]: Method [%s]: Reading stat for path %s failed\n",
    497 					__FILE__, __FUNCTION__, path);
    498 
    499 			fileDownloadMsg = CreateFileDownloadErrMsg(reason, reasonLen);
    500 	}
    501 	else {
    502 		rtcp->rcft.rcfd.mTime = stat_buf.st_mtime;
    503 		sz_rfbFileSize = stat_buf.st_size;
    504 		if(sz_rfbFileSize <= 0) {
    505 			fileDownloadMsg = CreateFileDownloadZeroSizeDataMsg(stat_buf.st_mtime);
    506 		}
    507 
    508 	}
    509 	return fileDownloadMsg;
    510 }
    511 
    512 
    513 FileTransferMsg
    514 CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen)
    515 {
    516 	FileTransferMsg fileDownloadErrMsg;
    517 	int length = sz_rfbFileDownloadFailedMsg + reasonLen + 1;
    518 	rfbFileDownloadFailedMsg *pFDF = NULL;
    519 	char *pFollow = NULL;
    520 
    521 	char *pData = (char*) calloc(length, sizeof(char));
    522 	memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg));
    523 	if(pData == NULL) {
    524 		rfbLog("File [%s]: Method [%s]: pData is NULL\n",
    525 				__FILE__, __FUNCTION__);
    526 		return fileDownloadErrMsg;
    527 	}
    528 
    529 	pFDF = (rfbFileDownloadFailedMsg *) pData;
    530 	pFollow = &pData[sz_rfbFileDownloadFailedMsg];
    531 
    532 	pFDF->type = rfbFileDownloadFailed;
    533 	pFDF->reasonLen = Swap16IfLE(reasonLen);
    534 	memcpy(pFollow, reason, reasonLen);
    535 
    536 	fileDownloadErrMsg.data	= pData;
    537 	fileDownloadErrMsg.length	= length;
    538 
    539 	return fileDownloadErrMsg;
    540 }
    541 
    542 
    543 FileTransferMsg
    544 CreateFileDownloadZeroSizeDataMsg(unsigned long mTime)
    545 {
    546 	FileTransferMsg fileDownloadZeroSizeDataMsg;
    547 	int length = sz_rfbFileDownloadDataMsg + sizeof(unsigned long);
    548 	rfbFileDownloadDataMsg *pFDD = NULL;
    549 	char *pFollow = NULL;
    550 
    551 	char *pData = (char*) calloc(length, sizeof(char));
    552 	memset(&fileDownloadZeroSizeDataMsg, 0, sizeof(FileTransferMsg));
    553 	if(pData == NULL) {
    554 		rfbLog("File [%s]: Method [%s]: pData is NULL\n",
    555 				__FILE__, __FUNCTION__);
    556 		return fileDownloadZeroSizeDataMsg;
    557 	}
    558 
    559 	pFDD = (rfbFileDownloadDataMsg *) pData;
    560 	pFollow = &pData[sz_rfbFileDownloadDataMsg];
    561 
    562 	pFDD->type = rfbFileDownloadData;
    563 	pFDD->compressLevel = 0;
    564 	pFDD->compressedSize = Swap16IfLE(0);
    565 	pFDD->realSize = Swap16IfLE(0);
    566 
    567 	memcpy(pFollow, &mTime, sizeof(unsigned long));
    568 
    569 	fileDownloadZeroSizeDataMsg.data	= pData;
    570 	fileDownloadZeroSizeDataMsg.length	= length;
    571 
    572 	return fileDownloadZeroSizeDataMsg;
    573 
    574 }
    575 
    576 
    577 FileTransferMsg
    578 CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile)
    579 {
    580 	FileTransferMsg fileDownloadBlockSizeDataMsg;
    581 	int length = sz_rfbFileDownloadDataMsg + sizeFile;
    582 	rfbFileDownloadDataMsg *pFDD = NULL;
    583 	char *pFollow = NULL;
    584 
    585 	char *pData = (char*) calloc(length, sizeof(char));
    586 	memset(&fileDownloadBlockSizeDataMsg, 0, sizeof(FileTransferMsg));
    587 	if(NULL == pData) {
    588 		rfbLog("File [%s]: Method [%s]: pData is NULL\n",
    589 				__FILE__, __FUNCTION__);
    590 		return fileDownloadBlockSizeDataMsg;
    591 	}
    592 
    593 	pFDD = (rfbFileDownloadDataMsg *) pData;
    594 	pFollow = &pData[sz_rfbFileDownloadDataMsg];
    595 
    596 	pFDD->type = rfbFileDownloadData;
    597 	pFDD->compressLevel = 0;
    598 	pFDD->compressedSize = Swap16IfLE(sizeFile);
    599 	pFDD->realSize = Swap16IfLE(sizeFile);
    600 
    601 	memcpy(pFollow, pFile, sizeFile);
    602 
    603 	fileDownloadBlockSizeDataMsg.data	= pData;
    604 	fileDownloadBlockSizeDataMsg.length	= length;
    605 
    606 	return fileDownloadBlockSizeDataMsg;
    607 
    608 }
    609 
    610 
    611 /******************************************************************************
    612  * Methods to handle file upload request
    613  ******************************************************************************/
    614 
    615 FileTransferMsg CreateFileUploadErrMsg(char* reason, unsigned int reasonLen);
    616 
    617 FileTransferMsg
    618 GetFileUploadLengthErrResponseMsg()
    619 {
    620 	char reason [] = "Path length exceeds PATH_MAX (4096) bytes";
    621 	int reasonLen = strlen(reason);
    622 
    623 	return CreateFileUploadErrMsg(reason, reasonLen);
    624 }
    625 
    626 
    627 FileTransferMsg
    628 ChkFileUploadErr(rfbClientPtr cl, rfbTightClientPtr rtcp)
    629 {
    630     FileTransferMsg fileUploadErrMsg;
    631 
    632 	memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
    633 	if( (rtcp->rcft.rcfu.fName == NULL) ||
    634 		(strlen(rtcp->rcft.rcfu.fName) == 0) ||
    635 		((rtcp->rcft.rcfu.uploadFD = creat(rtcp->rcft.rcfu.fName,
    636 		S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1)) {
    637 
    638 			char reason[] = "Could not create file";
    639 			int reasonLen = strlen(reason);
    640 			fileUploadErrMsg = CreateFileUploadErrMsg(reason, reasonLen);
    641 	}
    642 	else
    643 		rtcp->rcft.rcfu.uploadInProgress = TRUE;
    644 
    645 	return fileUploadErrMsg;
    646 }
    647 
    648 
    649 FileTransferMsg
    650 GetFileUploadCompressedLevelErrMsg()
    651 {
    652 	char reason[] = "Server does not support data compression on upload";
    653 	int reasonLen = strlen(reason);
    654 
    655 	return CreateFileUploadErrMsg(reason, reasonLen);
    656 }
    657 
    658 
    659 FileTransferMsg
    660 ChkFileUploadWriteErr(rfbClientPtr cl, rfbTightClientPtr rtcp, char* pBuf)
    661 {
    662 	FileTransferMsg ftm;
    663 	unsigned long numOfBytesWritten = 0;
    664 
    665 	memset(&ftm, 0, sizeof(FileTransferMsg));
    666 
    667 	numOfBytesWritten = write(rtcp->rcft.rcfu.uploadFD, pBuf, rtcp->rcft.rcfu.fSize);
    668 
    669 	if(numOfBytesWritten != rtcp->rcft.rcfu.fSize) {
    670 		char reason[] = "Error writing file data";
    671 		int reasonLen = strlen(reason);
    672 		ftm = CreateFileUploadErrMsg(reason, reasonLen);
    673 		CloseUndoneFileTransfer(cl, rtcp);
    674 	}
    675 	return ftm;
    676 }
    677 
    678 
    679 void
    680 FileUpdateComplete(rfbClientPtr cl, rfbTightClientPtr rtcp)
    681 {
    682 	/* Here we are settimg the modification and access time of the file */
    683 	/* Windows code stes mod/access/creation time of the file */
    684 	struct utimbuf utb;
    685 
    686 	utb.actime = utb.modtime = rtcp->rcft.rcfu.mTime;
    687 	if(utime(rtcp->rcft.rcfu.fName, &utb) == -1) {
    688 		rfbLog("File [%s]: Method [%s]: Setting the modification/access"
    689 				" time for the file <%s> failed\n", __FILE__,
    690 				__FUNCTION__, rtcp->rcft.rcfu.fName);
    691 	}
    692 
    693 	if(rtcp->rcft.rcfu.uploadFD != -1) {
    694 		close(rtcp->rcft.rcfu.uploadFD);
    695 		rtcp->rcft.rcfu.uploadFD = -1;
    696 		rtcp->rcft.rcfu.uploadInProgress = FALSE;
    697 	}
    698 }
    699 
    700 
    701 FileTransferMsg
    702 CreateFileUploadErrMsg(char* reason, unsigned int reasonLen)
    703 {
    704 	FileTransferMsg fileUploadErrMsg;
    705 	int length = sz_rfbFileUploadCancelMsg + reasonLen;
    706 	rfbFileUploadCancelMsg *pFDF = NULL;
    707 	char *pFollow = NULL;
    708 
    709 	char *pData = (char*) calloc(length, sizeof(char));
    710 	memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
    711 	if(pData == NULL) {
    712 		rfbLog("File [%s]: Method [%s]: pData is NULL\n",
    713 				__FILE__, __FUNCTION__);
    714 		return fileUploadErrMsg;
    715 	}
    716 
    717 	pFDF = (rfbFileUploadCancelMsg *) pData;
    718 	pFollow = &pData[sz_rfbFileUploadCancelMsg];
    719 
    720 	pFDF->type = rfbFileUploadCancel;
    721 	pFDF->reasonLen = Swap16IfLE(reasonLen);
    722 	memcpy(pFollow, reason, reasonLen);
    723 
    724 	fileUploadErrMsg.data		= pData;
    725 	fileUploadErrMsg.length		= length;
    726 
    727 	return fileUploadErrMsg;
    728 }
    729 
    730 
    731 /******************************************************************************
    732  * Method to cancel File Transfer operation.
    733  ******************************************************************************/
    734 
    735 void
    736 CloseUndoneFileTransfer(rfbClientPtr cl, rfbTightClientPtr rtcp)
    737 {
    738 	/* TODO :: File Upload case is not handled currently */
    739 	/* TODO :: In case of concurrency we need to use Critical Section */
    740 
    741 	if(cl == NULL)
    742 		return;
    743 
    744 
    745 	if(rtcp->rcft.rcfu.uploadInProgress == TRUE) {
    746 		rtcp->rcft.rcfu.uploadInProgress = FALSE;
    747 
    748 		if(rtcp->rcft.rcfu.uploadFD != -1) {
    749 			close(rtcp->rcft.rcfu.uploadFD);
    750 			rtcp->rcft.rcfu.uploadFD = -1;
    751 		}
    752 
    753 		if(unlink(rtcp->rcft.rcfu.fName) == -1) {
    754 			rfbLog("File [%s]: Method [%s]: Delete operation on file <%s> failed\n",
    755 					__FILE__, __FUNCTION__, rtcp->rcft.rcfu.fName);
    756 		}
    757 
    758 		memset(rtcp->rcft.rcfu.fName, 0 , PATH_MAX);
    759 	}
    760 
    761 	if(rtcp->rcft.rcfd.downloadInProgress == TRUE) {
    762 		rtcp->rcft.rcfd.downloadInProgress = FALSE;
    763 
    764 		if(rtcp->rcft.rcfd.downloadFD != -1) {
    765 			close(rtcp->rcft.rcfd.downloadFD);
    766 			rtcp->rcft.rcfd.downloadFD = -1;
    767 		}
    768 		memset(rtcp->rcft.rcfd.fName, 0 , PATH_MAX);
    769 	}
    770 }
    771 
    772 
    773 /******************************************************************************
    774  * Method to handle create directory request.
    775  ******************************************************************************/
    776 
    777 #ifdef _MSC_VER
    778 #undef CreateDirectory /* Prevent macro clashes under Windows */
    779 #endif /* _MSC_VER */
    780 
    781 void
    782 CreateDirectory(char* dirName)
    783 {
    784 	if(dirName == NULL) return;
    785 
    786 	if(mkdir(dirName, 0700) == -1) {
    787 		rfbLog("File [%s]: Method [%s]: Create operation for directory <%s> failed\n",
    788 				__FILE__, __FUNCTION__, dirName);
    789 	}
    790 }
    791