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