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@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
72void
73FreeFileTransferMsg(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
90int CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag);
91FileTransferMsg CreateFileListErrMsg(char flags);
92FileTransferMsg CreateFileListMsg(FileListInfo fileListInfo, char flags);
93
94
95/*
96 * This is the method called by HandleFileListRequest to get the file list
97 */
98
99FileTransferMsg
100GetFileListResponseMsg(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
167int
168CreateFileListInfo(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
252int
253CreateFileListInfo(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
325FileTransferMsg
326CreateFileListErrMsg(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
355FileTransferMsg
356CreateFileListMsg(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
405FileTransferMsg CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen);
406FileTransferMsg CreateFileDownloadZeroSizeDataMsg(unsigned long mTime);
407FileTransferMsg CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile);
408
409FileTransferMsg
410GetFileDownLoadErrMsg()
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
425FileTransferMsg
426GetFileDownloadReadDataErrMsg()
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
436FileTransferMsg
437GetFileDownloadLengthErrResponseMsg()
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
446FileTransferMsg
447GetFileDownloadResponseMsgInBlocks(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
480FileTransferMsg
481ChkFileDownloadErr(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
513FileTransferMsg
514CreateFileDownloadErrMsg(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
543FileTransferMsg
544CreateFileDownloadZeroSizeDataMsg(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
577FileTransferMsg
578CreateFileDownloadBlockSizeDataMsg(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
615FileTransferMsg CreateFileUploadErrMsg(char* reason, unsigned int reasonLen);
616
617FileTransferMsg
618GetFileUploadLengthErrResponseMsg()
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
627FileTransferMsg
628ChkFileUploadErr(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
649FileTransferMsg
650GetFileUploadCompressedLevelErrMsg()
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
659FileTransferMsg
660ChkFileUploadWriteErr(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
679void
680FileUpdateComplete(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
701FileTransferMsg
702CreateFileUploadErrMsg(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
735void
736CloseUndoneFileTransfer(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
781void
782CreateDirectory(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