2 * Copyright (c) 2005 Novell, Inc.
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.
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.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, contact Novell, Inc.
17 * To contact Novell about this file by physical or electronic mail,
18 * you may find current contact information at www.novell.com
20 * Author : Rohit Kumar
21 * Email ID : rokumar@novell.com
22 * Date : 14th July 2005
35 #include <sys/types.h>
38 #include "rfbtightproto.h"
39 #include "filelistinfo.h"
40 #include "filetransfermsg.h"
41 #include "handlefiletransferrequest.h"
43 #define SZ_RFBBLOCKSIZE 8192
47 FreeFileTransferMsg(FileTransferMsg ftm)
50 if(ftm.data != NULL) {
60 /******************************************************************************
61 * Methods to handle file list request.
62 ******************************************************************************/
64 int CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag);
65 FileTransferMsg CreateFileListErrMsg(char flags);
66 FileTransferMsg CreateFileListMsg(FileListInfo fileListInfo, char flags);
70 * This is the method called by HandleFileListRequest to get the file list
74 GetFileListResponseMsg(char* path, char flags)
76 FileTransferMsg fileListMsg;
77 FileListInfo fileListInfo;
80 memset(&fileListMsg, 0, sizeof(FileTransferMsg));
81 memset(&fileListInfo, 0, sizeof(FileListInfo));
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.
88 status = CreateFileListInfo(&fileListInfo, path, !(flags & 0x10));
90 if(status == FAILURE) {
91 fileListMsg = CreateFileListErrMsg(flags);
94 /* DisplayFileList(fileListInfo); For Debugging */
96 fileListMsg = CreateFileListMsg(fileListInfo, flags);
97 FreeFileListInfo(fileListInfo);
104 #define __FUNCTION__ "unknown"
108 CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag)
111 struct dirent* pDirent = NULL;
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(), "/");
118 if((pDir = opendir(path)) == NULL) {
119 rfbLog("File [%s]: Method [%s]: not able to open the dir\n",
120 __FILE__, __FUNCTION__);
124 while((pDirent = readdir(pDir))) {
125 if(strcmp(pDirent->d_name, ".") && strcmp(pDirent->d_name, "..")) {
126 struct stat stat_buf;
128 int fpLen = sizeof(char)*(strlen(pDirent->d_name)+strlen(path)+2);
130 char fullpath[PATH_MAX];
132 memset(fullpath, 0, PATH_MAX);
134 strcpy(fullpath, path);
135 if(path[strlen(path)-1] != '/')
136 strcat(fullpath, "/");
137 strcat(fullpath, pDirent->d_name);
139 if(stat(fullpath, &stat_buf) < 0) {
140 rfbLog("File [%s]: Method [%s]: Reading stat for file %s failed\n",
141 __FILE__, __FUNCTION__, fullpath);
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);
154 if(AddFileListItemInfo(pFileListInfo, pDirent->d_name,
156 stat_buf.st_mtime) == 0) {
157 rfbLog("File [%s]: Method [%s]: Add file %s in the "
158 "list failed\n", __FILE__, __FUNCTION__, fullpath);
165 if(closedir(pDir) < 0) {
166 rfbLog("File [%s]: Method [%s]: ERROR Couldn't close dir\n",
167 __FILE__, __FUNCTION__);
175 CreateFileListErrMsg(char flags)
177 FileTransferMsg fileListMsg;
178 rfbFileListDataMsg* pFLD = NULL;
180 unsigned int length = 0;
182 memset(&fileListMsg, 0, sizeof(FileTransferMsg));
184 data = (char*) calloc(sizeof(rfbFileListDataMsg), sizeof(char));
188 length = sizeof(rfbFileListDataMsg) * sizeof(char);
189 pFLD = (rfbFileListDataMsg*) data;
191 pFLD->type = rfbFileListData;
192 pFLD->numFiles = Swap16IfLE(0);
193 pFLD->dataSize = Swap16IfLE(0);
194 pFLD->compressedSize = Swap16IfLE(0);
195 pFLD->flags = flags | 0x80;
197 fileListMsg.data = data;
198 fileListMsg.length = length;
205 CreateFileListMsg(FileListInfo fileListInfo, char flags)
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;
213 memset(&fileListMsg, 0, sizeof(FileTransferMsg));
214 dsSize = fileListInfo.numEntries * 8;
215 length = sz_rfbFileListDataMsg + dsSize +
216 GetSumOfFileNamesLength(fileListInfo) +
217 fileListInfo.numEntries;
219 data = (char*) calloc(length, sizeof(char));
223 pFLD = (rfbFileListDataMsg*) data;
224 pFileListItemSize = (FileListItemSizePtr) &data[sz_rfbFileListDataMsg];
225 pFileNames = &data[sz_rfbFileListDataMsg + dsSize];
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;
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));
239 if(i+1 < fileListInfo.numEntries)
240 pFileNames += strlen(pFileNames) + 1;
243 fileListMsg.data = data;
244 fileListMsg.length = length;
250 /******************************************************************************
251 * Methods to handle File Download Request.
252 ******************************************************************************/
254 FileTransferMsg CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen);
255 FileTransferMsg CreateFileDownloadZeroSizeDataMsg(unsigned long mTime);
256 FileTransferMsg CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile);
259 GetFileDownLoadErrMsg()
261 FileTransferMsg fileDownloadErrMsg;
263 char reason[] = "An internal error on the server caused download failure";
264 int reasonLen = strlen(reason);
266 memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg));
268 fileDownloadErrMsg = CreateFileDownloadErrMsg(reason, reasonLen);
270 return fileDownloadErrMsg;
275 GetFileDownloadReadDataErrMsg()
277 char reason[] = "Cannot open file, perhaps it is absent or is a directory";
278 int reasonLen = strlen(reason);
280 return CreateFileDownloadErrMsg(reason, reasonLen);
286 GetFileDownloadLengthErrResponseMsg()
288 char reason [] = "Path length exceeds PATH_MAX (4096) bytes";
289 int reasonLen = strlen(reason);
291 return CreateFileDownloadErrMsg(reason, reasonLen);
296 GetFileDownloadResponseMsgInBlocks(rfbClientPtr cl, rfbTightClientPtr rtcp)
298 /* const unsigned int sz_rfbBlockSize = SZ_RFBBLOCKSIZE; */
299 int numOfBytesRead = 0;
300 char pBuf[SZ_RFBBLOCKSIZE];
301 char* path = rtcp->rcft.rcfd.fName;
303 memset(pBuf, 0, SZ_RFBBLOCKSIZE);
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__);
309 return GetFileDownloadReadDataErrMsg();
311 rtcp->rcft.rcfd.downloadInProgress = TRUE;
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);
321 return GetFileDownloadReadDataErrMsg();
323 return CreateFileDownloadBlockSizeDataMsg(numOfBytesRead, pBuf);
325 return GetFileDownLoadErrMsg();
330 ChkFileDownloadErr(rfbClientPtr cl, rfbTightClientPtr rtcp)
332 FileTransferMsg fileDownloadMsg;
333 struct stat stat_buf;
334 int sz_rfbFileSize = 0;
335 char* path = rtcp->rcft.rcfd.fName;
337 memset(&fileDownloadMsg, 0, sizeof(FileTransferMsg));
339 if( (path == NULL) || (strlen(path) == 0) ||
340 (stat(path, &stat_buf) < 0) || (!(S_ISREG(stat_buf.st_mode))) ) {
342 char reason[] = "Cannot open file, perhaps it is absent or is not a regular file";
343 int reasonLen = strlen(reason);
345 rfbLog("File [%s]: Method [%s]: Reading stat for path %s failed\n",
346 __FILE__, __FUNCTION__, path);
348 fileDownloadMsg = CreateFileDownloadErrMsg(reason, reasonLen);
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);
358 return fileDownloadMsg;
363 CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen)
365 FileTransferMsg fileDownloadErrMsg;
366 int length = sz_rfbFileDownloadFailedMsg + reasonLen + 1;
367 rfbFileDownloadFailedMsg *pFDF = NULL;
368 char *pFollow = NULL;
370 char *pData = (char*) calloc(length, sizeof(char));
371 memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg));
373 rfbLog("File [%s]: Method [%s]: pData is NULL\n",
374 __FILE__, __FUNCTION__);
375 return fileDownloadErrMsg;
378 pFDF = (rfbFileDownloadFailedMsg *) pData;
379 pFollow = &pData[sz_rfbFileDownloadFailedMsg];
381 pFDF->type = rfbFileDownloadFailed;
382 pFDF->reasonLen = Swap16IfLE(reasonLen);
383 memcpy(pFollow, reason, reasonLen);
385 fileDownloadErrMsg.data = pData;
386 fileDownloadErrMsg.length = length;
388 return fileDownloadErrMsg;
393 CreateFileDownloadZeroSizeDataMsg(unsigned long mTime)
395 FileTransferMsg fileDownloadZeroSizeDataMsg;
396 int length = sz_rfbFileDownloadDataMsg + sizeof(int);
397 rfbFileDownloadDataMsg *pFDD = NULL;
398 char *pFollow = NULL;
400 char *pData = (char*) calloc(length, sizeof(char));
401 memset(&fileDownloadZeroSizeDataMsg, 0, sizeof(FileTransferMsg));
403 rfbLog("File [%s]: Method [%s]: pData is NULL\n",
404 __FILE__, __FUNCTION__);
405 return fileDownloadZeroSizeDataMsg;
408 pFDD = (rfbFileDownloadDataMsg *) pData;
409 pFollow = &pData[sz_rfbFileDownloadDataMsg];
411 pFDD->type = rfbFileDownloadData;
412 pFDD->compressLevel = 0;
413 pFDD->compressedSize = Swap16IfLE(0);
414 pFDD->realSize = Swap16IfLE(0);
416 memcpy(pFollow, &mTime, sizeof(unsigned long));
418 fileDownloadZeroSizeDataMsg.data = pData;
419 fileDownloadZeroSizeDataMsg.length = length;
421 return fileDownloadZeroSizeDataMsg;
427 CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile)
429 FileTransferMsg fileDownloadBlockSizeDataMsg;
430 int length = sz_rfbFileDownloadDataMsg + sizeFile;
431 rfbFileDownloadDataMsg *pFDD = NULL;
432 char *pFollow = NULL;
434 char *pData = (char*) calloc(length, sizeof(char));
435 memset(&fileDownloadBlockSizeDataMsg, 0, sizeof(FileTransferMsg));
437 rfbLog("File [%s]: Method [%s]: pData is NULL\n",
438 __FILE__, __FUNCTION__);
439 return fileDownloadBlockSizeDataMsg;
442 pFDD = (rfbFileDownloadDataMsg *) pData;
443 pFollow = &pData[sz_rfbFileDownloadDataMsg];
445 pFDD->type = rfbFileDownloadData;
446 pFDD->compressLevel = 0;
447 pFDD->compressedSize = Swap16IfLE(sizeFile);
448 pFDD->realSize = Swap16IfLE(sizeFile);
450 memcpy(pFollow, pFile, sizeFile);
452 fileDownloadBlockSizeDataMsg.data = pData;
453 fileDownloadBlockSizeDataMsg.length = length;
455 return fileDownloadBlockSizeDataMsg;
460 /******************************************************************************
461 * Methods to handle file upload request
462 ******************************************************************************/
464 FileTransferMsg CreateFileUploadErrMsg(char* reason, unsigned int reasonLen);
467 GetFileUploadLengthErrResponseMsg()
469 char reason [] = "Path length exceeds PATH_MAX (4096) bytes";
470 int reasonLen = strlen(reason);
472 return CreateFileUploadErrMsg(reason, reasonLen);
477 ChkFileUploadErr(rfbClientPtr cl, rfbTightClientPtr rtcp)
479 FileTransferMsg fileUploadErrMsg;
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)) {
487 char reason[] = "Could not create file";
488 int reasonLen = strlen(reason);
489 fileUploadErrMsg = CreateFileUploadErrMsg(reason, reasonLen);
492 rtcp->rcft.rcfu.uploadInProgress = TRUE;
494 return fileUploadErrMsg;
499 GetFileUploadCompressedLevelErrMsg()
501 char reason[] = "Server does not support data compression on upload";
502 int reasonLen = strlen(reason);
504 return CreateFileUploadErrMsg(reason, reasonLen);
509 ChkFileUploadWriteErr(rfbClientPtr cl, rfbTightClientPtr rtcp, char* pBuf)
512 unsigned long numOfBytesWritten = 0;
514 memset(&ftm, 0, sizeof(FileTransferMsg));
516 numOfBytesWritten = write(rtcp->rcft.rcfu.uploadFD, pBuf, rtcp->rcft.rcfu.fSize);
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);
529 FileUpdateComplete(rfbClientPtr cl, rfbTightClientPtr rtcp)
531 /* Here we are settimg the modification and access time of the file */
532 /* Windows code stes mod/access/creation time of the file */
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);
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;
551 CreateFileUploadErrMsg(char* reason, unsigned int reasonLen)
553 FileTransferMsg fileUploadErrMsg;
554 int length = sz_rfbFileUploadCancelMsg + reasonLen;
555 rfbFileUploadCancelMsg *pFDF = NULL;
556 char *pFollow = NULL;
558 char *pData = (char*) calloc(length, sizeof(char));
559 memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
561 rfbLog("File [%s]: Method [%s]: pData is NULL\n",
562 __FILE__, __FUNCTION__);
563 return fileUploadErrMsg;
566 pFDF = (rfbFileUploadCancelMsg *) pData;
567 pFollow = &pData[sz_rfbFileUploadCancelMsg];
569 pFDF->type = rfbFileUploadCancel;
570 pFDF->reasonLen = Swap16IfLE(reasonLen);
571 memcpy(pFollow, reason, reasonLen);
573 fileUploadErrMsg.data = pData;
574 fileUploadErrMsg.length = length;
576 return fileUploadErrMsg;
580 /******************************************************************************
581 * Method to cancel File Transfer operation.
582 ******************************************************************************/
585 CloseUndoneFileTransfer(rfbClientPtr cl, rfbTightClientPtr rtcp)
587 /* TODO :: File Upload case is not handled currently */
588 /* TODO :: In case of concurrency we need to use Critical Section */
594 if(rtcp->rcft.rcfu.uploadInProgress == TRUE) {
595 rtcp->rcft.rcfu.uploadInProgress = FALSE;
597 if(rtcp->rcft.rcfu.uploadFD != -1) {
598 close(rtcp->rcft.rcfu.uploadFD);
599 rtcp->rcft.rcfu.uploadFD = -1;
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);
607 memset(rtcp->rcft.rcfu.fName, 0 , PATH_MAX);
610 if(rtcp->rcft.rcfd.downloadInProgress == TRUE) {
611 rtcp->rcft.rcfd.downloadInProgress = FALSE;
613 if(rtcp->rcft.rcfd.downloadFD != -1) {
614 close(rtcp->rcft.rcfd.downloadFD);
615 rtcp->rcft.rcfd.downloadFD = -1;
617 memset(rtcp->rcft.rcfd.fName, 0 , PATH_MAX);
622 /******************************************************************************
623 * Method to handle create directory request.
624 ******************************************************************************/
627 CreateDirectory(char* dirName)
629 if(dirName == NULL) return;
631 if(mkdir(dirName, 0700) == -1) {
632 rfbLog("File [%s]: Method [%s]: Create operation for directory <%s> failed\n",
633 __FILE__, __FUNCTION__, dirName);