LibVNCServer/LibVNCClient
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
filetransfermsg.c
Go to the documentation of this file.
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 #include <dirent.h>
31 #include <utime.h>
32 #include <errno.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 
37 #include <rfb/rfb.h>
38 #include "rfbtightproto.h"
39 #include "filelistinfo.h"
40 #include "filetransfermsg.h"
42 
43 #define SZ_RFBBLOCKSIZE 8192
44 
45 
46 void
48 {
49 
50  if(ftm.data != NULL) {
51  free(ftm.data);
52  ftm.data = NULL;
53  }
54 
55  ftm.length = 0;
56 
57 }
58 
59 
60 /******************************************************************************
61  * Methods to handle file list request.
62  ******************************************************************************/
63 
64 int CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag);
66 FileTransferMsg CreateFileListMsg(FileListInfo fileListInfo, char flags);
67 
68 
69 /*
70  * This is the method called by HandleFileListRequest to get the file list
71  */
72 
74 GetFileListResponseMsg(char* path, char flags)
75 {
76  FileTransferMsg fileListMsg;
77  FileListInfo fileListInfo;
78  int status = -1;
79 
80  memset(&fileListMsg, 0, sizeof(FileTransferMsg));
81  memset(&fileListInfo, 0, sizeof(FileListInfo));
82 
83 
84  /* fileListInfo can have null data if the folder is Empty
85  or if some error condition has occured.
86  The return value is 'failure' only if some error condition has occured.
87  */
88  status = CreateFileListInfo(&fileListInfo, path, !(flags & 0x10));
89 
90  if(status == FAILURE) {
91  fileListMsg = CreateFileListErrMsg(flags);
92  }
93  else {
94  /* DisplayFileList(fileListInfo); For Debugging */
95 
96  fileListMsg = CreateFileListMsg(fileListInfo, flags);
97  FreeFileListInfo(fileListInfo);
98  }
99 
100  return fileListMsg;
101 }
102 
103 #ifndef __GNUC__
104 #define __FUNCTION__ "unknown"
105 #endif
106 
107 int
108 CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag)
109 {
110  DIR* pDir = NULL;
111  struct dirent* pDirent = NULL;
112 
113  if((path == NULL) || (strlen(path) == 0)) {
114  /* In this case we will send the list of entries in ftp root*/
115  sprintf(path, "%s%s", GetFtpRoot(), "/");
116  }
117 
118  if((pDir = opendir(path)) == NULL) {
119  rfbLog("File [%s]: Method [%s]: not able to open the dir\n",
120  __FILE__, __FUNCTION__);
121  return FAILURE;
122  }
123 
124  while((pDirent = readdir(pDir))) {
125  if(strcmp(pDirent->d_name, ".") && strcmp(pDirent->d_name, "..")) {
126  struct stat stat_buf;
127  /*
128  int fpLen = sizeof(char)*(strlen(pDirent->d_name)+strlen(path)+2);
129  */
130  char fullpath[PATH_MAX];
131 
132  memset(fullpath, 0, PATH_MAX);
133 
134  strcpy(fullpath, path);
135  if(path[strlen(path)-1] != '/')
136  strcat(fullpath, "/");
137  strcat(fullpath, pDirent->d_name);
138 
139  if(stat(fullpath, &stat_buf) < 0) {
140  rfbLog("File [%s]: Method [%s]: Reading stat for file %s failed\n",
141  __FILE__, __FUNCTION__, fullpath);
142  continue;
143  }
144 
145  if(S_ISDIR(stat_buf.st_mode)) {
146  if(AddFileListItemInfo(pFileListInfo, pDirent->d_name, -1, 0) == 0) {
147  rfbLog("File [%s]: Method [%s]: Add directory %s in the"
148  " list failed\n", __FILE__, __FUNCTION__, fullpath);
149  continue;
150  }
151  }
152  else {
153  if(flag) {
154  if(AddFileListItemInfo(pFileListInfo, pDirent->d_name,
155  stat_buf.st_size,
156  stat_buf.st_mtime) == 0) {
157  rfbLog("File [%s]: Method [%s]: Add file %s in the "
158  "list failed\n", __FILE__, __FUNCTION__, fullpath);
159  continue;
160  }
161  }
162  }
163  }
164  }
165  if(closedir(pDir) < 0) {
166  rfbLog("File [%s]: Method [%s]: ERROR Couldn't close dir\n",
167  __FILE__, __FUNCTION__);
168  }
169 
170  return SUCCESS;
171 }
172 
173 
176 {
177  FileTransferMsg fileListMsg;
178  rfbFileListDataMsg* pFLD = NULL;
179  char* data = NULL;
180  unsigned int length = 0;
181 
182  memset(&fileListMsg, 0, sizeof(FileTransferMsg));
183 
184  data = (char*) calloc(sizeof(rfbFileListDataMsg), sizeof(char));
185  if(data == NULL) {
186  return fileListMsg;
187  }
188  length = sizeof(rfbFileListDataMsg) * sizeof(char);
189  pFLD = (rfbFileListDataMsg*) data;
190 
191  pFLD->type = rfbFileListData;
192  pFLD->numFiles = Swap16IfLE(0);
193  pFLD->dataSize = Swap16IfLE(0);
194  pFLD->compressedSize = Swap16IfLE(0);
195  pFLD->flags = flags | 0x80;
196 
197  fileListMsg.data = data;
198  fileListMsg.length = length;
199 
200  return fileListMsg;
201 }
202 
203 
205 CreateFileListMsg(FileListInfo fileListInfo, char flags)
206 {
207  FileTransferMsg fileListMsg;
208  rfbFileListDataMsg* pFLD = NULL;
209  char *data = NULL, *pFileNames = NULL;
210  unsigned int length = 0, dsSize = 0, i = 0;
211  FileListItemSizePtr pFileListItemSize = NULL;
212 
213  memset(&fileListMsg, 0, sizeof(FileTransferMsg));
214  dsSize = fileListInfo.numEntries * 8;
215  length = sz_rfbFileListDataMsg + dsSize +
216  GetSumOfFileNamesLength(fileListInfo) +
217  fileListInfo.numEntries;
218 
219  data = (char*) calloc(length, sizeof(char));
220  if(data == NULL) {
221  return fileListMsg;
222  }
223  pFLD = (rfbFileListDataMsg*) data;
224  pFileListItemSize = (FileListItemSizePtr) &data[sz_rfbFileListDataMsg];
225  pFileNames = &data[sz_rfbFileListDataMsg + dsSize];
226 
227  pFLD->type = rfbFileListData;
228  pFLD->flags = flags & 0xF0;
229  pFLD->numFiles = Swap16IfLE(fileListInfo.numEntries);
230  pFLD->dataSize = Swap16IfLE(GetSumOfFileNamesLength(fileListInfo) +
231  fileListInfo.numEntries);
232  pFLD->compressedSize = pFLD->dataSize;
233 
234  for(i =0; i <fileListInfo.numEntries; i++) {
235  pFileListItemSize[i].size = Swap32IfLE(GetFileSizeAt(fileListInfo, i));
236  pFileListItemSize[i].data = Swap32IfLE(GetFileDataAt(fileListInfo, i));
237  strcpy(pFileNames, GetFileNameAt(fileListInfo, i));
238 
239  if(i+1 < fileListInfo.numEntries)
240  pFileNames += strlen(pFileNames) + 1;
241  }
242 
243  fileListMsg.data = data;
244  fileListMsg.length = length;
245 
246  return fileListMsg;
247 }
248 
249 
250 /******************************************************************************
251  * Methods to handle File Download Request.
252  ******************************************************************************/
253 
254 FileTransferMsg CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen);
256 FileTransferMsg CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile);
257 
260 {
261  FileTransferMsg fileDownloadErrMsg;
262 
263  char reason[] = "An internal error on the server caused download failure";
264  int reasonLen = strlen(reason);
265 
266  memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg));
267 
268  fileDownloadErrMsg = CreateFileDownloadErrMsg(reason, reasonLen);
269 
270  return fileDownloadErrMsg;
271 }
272 
273 
276 {
277  char reason[] = "Cannot open file, perhaps it is absent or is a directory";
278  int reasonLen = strlen(reason);
279 
280  return CreateFileDownloadErrMsg(reason, reasonLen);
281 
282 }
283 
284 
287 {
288  char reason [] = "Path length exceeds PATH_MAX (4096) bytes";
289  int reasonLen = strlen(reason);
290 
291  return CreateFileDownloadErrMsg(reason, reasonLen);
292 }
293 
294 
296 GetFileDownloadResponseMsgInBlocks(rfbClientPtr cl, rfbTightClientPtr rtcp)
297 {
298  /* const unsigned int sz_rfbBlockSize = SZ_RFBBLOCKSIZE; */
299  int numOfBytesRead = 0;
300  char pBuf[SZ_RFBBLOCKSIZE];
301  char* path = rtcp->rcft.rcfd.fName;
302 
303  memset(pBuf, 0, SZ_RFBBLOCKSIZE);
304 
305  if((rtcp->rcft.rcfd.downloadInProgress == FALSE) && (rtcp->rcft.rcfd.downloadFD == -1)) {
306  if((rtcp->rcft.rcfd.downloadFD = open(path, O_RDONLY)) == -1) {
307  rfbLog("File [%s]: Method [%s]: Error: Couldn't open file\n",
308  __FILE__, __FUNCTION__);
310  }
311  rtcp->rcft.rcfd.downloadInProgress = TRUE;
312  }
313  if((rtcp->rcft.rcfd.downloadInProgress == TRUE) && (rtcp->rcft.rcfd.downloadFD != -1)) {
314  if( (numOfBytesRead = read(rtcp->rcft.rcfd.downloadFD, pBuf, SZ_RFBBLOCKSIZE)) <= 0) {
315  close(rtcp->rcft.rcfd.downloadFD);
316  rtcp->rcft.rcfd.downloadFD = -1;
317  rtcp->rcft.rcfd.downloadInProgress = FALSE;
318  if(numOfBytesRead == 0) {
319  return CreateFileDownloadZeroSizeDataMsg(rtcp->rcft.rcfd.mTime);
320  }
322  }
323  return CreateFileDownloadBlockSizeDataMsg(numOfBytesRead, pBuf);
324  }
325  return GetFileDownLoadErrMsg();
326 }
327 
328 
330 ChkFileDownloadErr(rfbClientPtr cl, rfbTightClientPtr rtcp)
331 {
332  FileTransferMsg fileDownloadMsg;
333  struct stat stat_buf;
334  int sz_rfbFileSize = 0;
335  char* path = rtcp->rcft.rcfd.fName;
336 
337  memset(&fileDownloadMsg, 0, sizeof(FileTransferMsg));
338 
339  if( (path == NULL) || (strlen(path) == 0) ||
340  (stat(path, &stat_buf) < 0) || (!(S_ISREG(stat_buf.st_mode))) ) {
341 
342  char reason[] = "Cannot open file, perhaps it is absent or is not a regular file";
343  int reasonLen = strlen(reason);
344 
345  rfbLog("File [%s]: Method [%s]: Reading stat for path %s failed\n",
346  __FILE__, __FUNCTION__, path);
347 
348  fileDownloadMsg = CreateFileDownloadErrMsg(reason, reasonLen);
349  }
350  else {
351  rtcp->rcft.rcfd.mTime = stat_buf.st_mtime;
352  sz_rfbFileSize = stat_buf.st_size;
353  if(sz_rfbFileSize <= 0) {
354  fileDownloadMsg = CreateFileDownloadZeroSizeDataMsg(stat_buf.st_mtime);
355  }
356 
357  }
358  return fileDownloadMsg;
359 }
360 
361 
363 CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen)
364 {
365  FileTransferMsg fileDownloadErrMsg;
366  int length = sz_rfbFileDownloadFailedMsg + reasonLen + 1;
367  rfbFileDownloadFailedMsg *pFDF = NULL;
368  char *pFollow = NULL;
369 
370  char *pData = (char*) calloc(length, sizeof(char));
371  memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg));
372  if(pData == NULL) {
373  rfbLog("File [%s]: Method [%s]: pData is NULL\n",
374  __FILE__, __FUNCTION__);
375  return fileDownloadErrMsg;
376  }
377 
378  pFDF = (rfbFileDownloadFailedMsg *) pData;
379  pFollow = &pData[sz_rfbFileDownloadFailedMsg];
380 
381  pFDF->type = rfbFileDownloadFailed;
382  pFDF->reasonLen = Swap16IfLE(reasonLen);
383  memcpy(pFollow, reason, reasonLen);
384 
385  fileDownloadErrMsg.data = pData;
386  fileDownloadErrMsg.length = length;
387 
388  return fileDownloadErrMsg;
389 }
390 
391 
394 {
395  FileTransferMsg fileDownloadZeroSizeDataMsg;
396  int length = sz_rfbFileDownloadDataMsg + sizeof(unsigned long);
397  rfbFileDownloadDataMsg *pFDD = NULL;
398  char *pFollow = NULL;
399 
400  char *pData = (char*) calloc(length, sizeof(char));
401  memset(&fileDownloadZeroSizeDataMsg, 0, sizeof(FileTransferMsg));
402  if(pData == NULL) {
403  rfbLog("File [%s]: Method [%s]: pData is NULL\n",
404  __FILE__, __FUNCTION__);
405  return fileDownloadZeroSizeDataMsg;
406  }
407 
408  pFDD = (rfbFileDownloadDataMsg *) pData;
409  pFollow = &pData[sz_rfbFileDownloadDataMsg];
410 
411  pFDD->type = rfbFileDownloadData;
412  pFDD->compressLevel = 0;
413  pFDD->compressedSize = Swap16IfLE(0);
414  pFDD->realSize = Swap16IfLE(0);
415 
416  memcpy(pFollow, &mTime, sizeof(unsigned long));
417 
418  fileDownloadZeroSizeDataMsg.data = pData;
419  fileDownloadZeroSizeDataMsg.length = length;
420 
421  return fileDownloadZeroSizeDataMsg;
422 
423 }
424 
425 
427 CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile)
428 {
429  FileTransferMsg fileDownloadBlockSizeDataMsg;
430  int length = sz_rfbFileDownloadDataMsg + sizeFile;
431  rfbFileDownloadDataMsg *pFDD = NULL;
432  char *pFollow = NULL;
433 
434  char *pData = (char*) calloc(length, sizeof(char));
435  memset(&fileDownloadBlockSizeDataMsg, 0, sizeof(FileTransferMsg));
436  if(NULL == pData) {
437  rfbLog("File [%s]: Method [%s]: pData is NULL\n",
438  __FILE__, __FUNCTION__);
439  return fileDownloadBlockSizeDataMsg;
440  }
441 
442  pFDD = (rfbFileDownloadDataMsg *) pData;
443  pFollow = &pData[sz_rfbFileDownloadDataMsg];
444 
445  pFDD->type = rfbFileDownloadData;
446  pFDD->compressLevel = 0;
447  pFDD->compressedSize = Swap16IfLE(sizeFile);
448  pFDD->realSize = Swap16IfLE(sizeFile);
449 
450  memcpy(pFollow, pFile, sizeFile);
451 
452  fileDownloadBlockSizeDataMsg.data = pData;
453  fileDownloadBlockSizeDataMsg.length = length;
454 
455  return fileDownloadBlockSizeDataMsg;
456 
457 }
458 
459 
460 /******************************************************************************
461  * Methods to handle file upload request
462  ******************************************************************************/
463 
464 FileTransferMsg CreateFileUploadErrMsg(char* reason, unsigned int reasonLen);
465 
468 {
469  char reason [] = "Path length exceeds PATH_MAX (4096) bytes";
470  int reasonLen = strlen(reason);
471 
472  return CreateFileUploadErrMsg(reason, reasonLen);
473 }
474 
475 
477 ChkFileUploadErr(rfbClientPtr cl, rfbTightClientPtr rtcp)
478 {
479  FileTransferMsg fileUploadErrMsg;
480 
481  memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
482  if( (rtcp->rcft.rcfu.fName == NULL) ||
483  (strlen(rtcp->rcft.rcfu.fName) == 0) ||
484  ((rtcp->rcft.rcfu.uploadFD = creat(rtcp->rcft.rcfu.fName,
485  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1)) {
486 
487  char reason[] = "Could not create file";
488  int reasonLen = strlen(reason);
489  fileUploadErrMsg = CreateFileUploadErrMsg(reason, reasonLen);
490  }
491  else
492  rtcp->rcft.rcfu.uploadInProgress = TRUE;
493 
494  return fileUploadErrMsg;
495 }
496 
497 
500 {
501  char reason[] = "Server does not support data compression on upload";
502  int reasonLen = strlen(reason);
503 
504  return CreateFileUploadErrMsg(reason, reasonLen);
505 }
506 
507 
509 ChkFileUploadWriteErr(rfbClientPtr cl, rfbTightClientPtr rtcp, char* pBuf)
510 {
511  FileTransferMsg ftm;
512  unsigned long numOfBytesWritten = 0;
513 
514  memset(&ftm, 0, sizeof(FileTransferMsg));
515 
516  numOfBytesWritten = write(rtcp->rcft.rcfu.uploadFD, pBuf, rtcp->rcft.rcfu.fSize);
517 
518  if(numOfBytesWritten != rtcp->rcft.rcfu.fSize) {
519  char reason[] = "Error writing file data";
520  int reasonLen = strlen(reason);
521  ftm = CreateFileUploadErrMsg(reason, reasonLen);
522  CloseUndoneFileTransfer(cl, rtcp);
523  }
524  return ftm;
525 }
526 
527 
528 void
529 FileUpdateComplete(rfbClientPtr cl, rfbTightClientPtr rtcp)
530 {
531  /* Here we are settimg the modification and access time of the file */
532  /* Windows code stes mod/access/creation time of the file */
533  struct utimbuf utb;
534 
535  utb.actime = utb.modtime = rtcp->rcft.rcfu.mTime;
536  if(utime(rtcp->rcft.rcfu.fName, &utb) == -1) {
537  rfbLog("File [%s]: Method [%s]: Setting the modification/access"
538  " time for the file <%s> failed\n", __FILE__,
539  __FUNCTION__, rtcp->rcft.rcfu.fName);
540  }
541 
542  if(rtcp->rcft.rcfu.uploadFD != -1) {
543  close(rtcp->rcft.rcfu.uploadFD);
544  rtcp->rcft.rcfu.uploadFD = -1;
545  rtcp->rcft.rcfu.uploadInProgress = FALSE;
546  }
547 }
548 
549 
551 CreateFileUploadErrMsg(char* reason, unsigned int reasonLen)
552 {
553  FileTransferMsg fileUploadErrMsg;
554  int length = sz_rfbFileUploadCancelMsg + reasonLen;
555  rfbFileUploadCancelMsg *pFDF = NULL;
556  char *pFollow = NULL;
557 
558  char *pData = (char*) calloc(length, sizeof(char));
559  memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
560  if(pData == NULL) {
561  rfbLog("File [%s]: Method [%s]: pData is NULL\n",
562  __FILE__, __FUNCTION__);
563  return fileUploadErrMsg;
564  }
565 
566  pFDF = (rfbFileUploadCancelMsg *) pData;
567  pFollow = &pData[sz_rfbFileUploadCancelMsg];
568 
569  pFDF->type = rfbFileUploadCancel;
570  pFDF->reasonLen = Swap16IfLE(reasonLen);
571  memcpy(pFollow, reason, reasonLen);
572 
573  fileUploadErrMsg.data = pData;
574  fileUploadErrMsg.length = length;
575 
576  return fileUploadErrMsg;
577 }
578 
579 
580 /******************************************************************************
581  * Method to cancel File Transfer operation.
582  ******************************************************************************/
583 
584 void
585 CloseUndoneFileTransfer(rfbClientPtr cl, rfbTightClientPtr rtcp)
586 {
587  /* TODO :: File Upload case is not handled currently */
588  /* TODO :: In case of concurrency we need to use Critical Section */
589 
590  if(cl == NULL)
591  return;
592 
593 
594  if(rtcp->rcft.rcfu.uploadInProgress == TRUE) {
595  rtcp->rcft.rcfu.uploadInProgress = FALSE;
596 
597  if(rtcp->rcft.rcfu.uploadFD != -1) {
598  close(rtcp->rcft.rcfu.uploadFD);
599  rtcp->rcft.rcfu.uploadFD = -1;
600  }
601 
602  if(unlink(rtcp->rcft.rcfu.fName) == -1) {
603  rfbLog("File [%s]: Method [%s]: Delete operation on file <%s> failed\n",
604  __FILE__, __FUNCTION__, rtcp->rcft.rcfu.fName);
605  }
606 
607  memset(rtcp->rcft.rcfu.fName, 0 , PATH_MAX);
608  }
609 
610  if(rtcp->rcft.rcfd.downloadInProgress == TRUE) {
611  rtcp->rcft.rcfd.downloadInProgress = FALSE;
612 
613  if(rtcp->rcft.rcfd.downloadFD != -1) {
614  close(rtcp->rcft.rcfd.downloadFD);
615  rtcp->rcft.rcfd.downloadFD = -1;
616  }
617  memset(rtcp->rcft.rcfd.fName, 0 , PATH_MAX);
618  }
619 }
620 
621 
622 /******************************************************************************
623  * Method to handle create directory request.
624  ******************************************************************************/
625 
626 void
627 CreateDirectory(char* dirName)
628 {
629  if(dirName == NULL) return;
630 
631  if(mkdir(dirName, 0700) == -1) {
632  rfbLog("File [%s]: Method [%s]: Create operation for directory <%s> failed\n",
633  __FILE__, __FUNCTION__, dirName);
634  }
635 }
636