summaryrefslogtreecommitdiffstats
path: root/libvncserver/tightvnc-filetransfer/filetransfermsg.c
diff options
context:
space:
mode:
Diffstat (limited to 'libvncserver/tightvnc-filetransfer/filetransfermsg.c')
-rw-r--r--libvncserver/tightvnc-filetransfer/filetransfermsg.c632
1 files changed, 632 insertions, 0 deletions
diff --git a/libvncserver/tightvnc-filetransfer/filetransfermsg.c b/libvncserver/tightvnc-filetransfer/filetransfermsg.c
new file mode 100644
index 0000000..6a3a39e
--- /dev/null
+++ b/libvncserver/tightvnc-filetransfer/filetransfermsg.c
@@ -0,0 +1,632 @@
+/*
+ * Copyright (c) 2005 Novell, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail,
+ * you may find current contact information at www.novell.com
+ *
+ * Author : Rohit Kumar
+ * Email ID : rokumar@novell.com
+ * Date : 14th July 2005
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <utime.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <rfb/rfb.h>
+#include "rfbtightproto.h"
+#include "filelistinfo.h"
+#include "filetransfermsg.h"
+#include "handlefiletransferrequest.h"
+
+#define SZ_RFBBLOCKSIZE 8192
+
+
+void
+FreeFileTransferMsg(FileTransferMsg ftm)
+{
+
+ if(ftm.data != NULL) {
+ free(ftm.data);
+ ftm.data = NULL;
+ }
+
+ ftm.length = 0;
+
+}
+
+
+/******************************************************************************
+ * Methods to handle file list request.
+ ******************************************************************************/
+
+int CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag);
+FileTransferMsg CreateFileListErrMsg(char flags);
+FileTransferMsg CreateFileListMsg(FileListInfo fileListInfo, char flags);
+
+
+/*
+ * This is the method called by HandleFileListRequest to get the file list
+ */
+
+FileTransferMsg
+GetFileListResponseMsg(char* path, char flags)
+{
+ FileTransferMsg fileListMsg;
+ FileListInfo fileListInfo;
+ int status = -1;
+
+ memset(&fileListMsg, 0, sizeof(FileTransferMsg));
+ memset(&fileListInfo, 0, sizeof(FileListInfo));
+
+
+ /* fileListInfo can have null data if the folder is Empty
+ or if some error condition has occured.
+ The return value is 'failure' only if some error condition has occured.
+ */
+ status = CreateFileListInfo(&fileListInfo, path, !(flags & 0x10));
+
+ if(status == FAILURE) {
+ fileListMsg = CreateFileListErrMsg(flags);
+ }
+ else {
+ /* DisplayFileList(fileListInfo); For Debugging */
+
+ fileListMsg = CreateFileListMsg(fileListInfo, flags);
+ FreeFileListInfo(fileListInfo);
+ }
+
+ return fileListMsg;
+}
+
+
+int
+CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag)
+{
+ DIR* pDir = NULL;
+ struct dirent* pDirent = NULL;
+
+ if((path == NULL) || (strlen(path) == 0)) {
+ /* In this case we will send the list of entries in ftp root*/
+ sprintf(path, "%s%s", GetFtpRoot(), "/");
+ }
+
+ if((pDir = opendir(path)) == NULL) {
+ rfbLog("File [%s]: Method [%s]: not able to open the dir\n",
+ __FILE__, __FUNCTION__);
+ return FAILURE;
+ }
+
+ while((pDirent = readdir(pDir))) {
+ if(strcmp(pDirent->d_name, ".") && strcmp(pDirent->d_name, "..")) {
+ struct stat stat_buf;
+ /*
+ int fpLen = sizeof(char)*(strlen(pDirent->d_name)+strlen(path)+2);
+ */
+ char fullpath[PATH_MAX];
+
+ memset(fullpath, 0, PATH_MAX);
+
+ strcpy(fullpath, path);
+ if(path[strlen(path)-1] != '/')
+ strcat(fullpath, "/");
+ strcat(fullpath, pDirent->d_name);
+
+ if(stat(fullpath, &stat_buf) < 0) {
+ rfbLog("File [%s]: Method [%s]: Reading stat for file %s failed\n",
+ __FILE__, __FUNCTION__, fullpath);
+ continue;
+ }
+
+ if(S_ISDIR(stat_buf.st_mode)) {
+ if(AddFileListItemInfo(pFileListInfo, pDirent->d_name, -1, 0) == 0) {
+ rfbLog("File [%s]: Method [%s]: Add directory %s in the"
+ " list failed\n", __FILE__, __FUNCTION__, fullpath);
+ continue;
+ }
+ }
+ else {
+ if(flag) {
+ if(AddFileListItemInfo(pFileListInfo, pDirent->d_name,
+ stat_buf.st_size,
+ stat_buf.st_mtime) == 0) {
+ rfbLog("File [%s]: Method [%s]: Add file %s in the "
+ "list failed\n", __FILE__, __FUNCTION__, fullpath);
+ continue;
+ }
+ }
+ }
+ }
+ }
+ if(closedir(pDir) < 0) {
+ rfbLog("File [%s]: Method [%s]: ERROR Couldn't close dir\n",
+ __FILE__, __FUNCTION__);
+ }
+
+ return SUCCESS;
+}
+
+
+FileTransferMsg
+CreateFileListErrMsg(char flags)
+{
+ FileTransferMsg fileListMsg;
+ rfbFileListDataMsg* pFLD = NULL;
+ char* data = NULL;
+ unsigned int length = 0;
+
+ memset(&fileListMsg, 0, sizeof(FileTransferMsg));
+
+ data = (char*) calloc(sizeof(rfbFileListDataMsg), sizeof(char));
+ if(data == NULL) {
+ return fileListMsg;
+ }
+ length = sizeof(rfbFileListDataMsg) * sizeof(char);
+ pFLD = (rfbFileListDataMsg*) data;
+
+ pFLD->type = rfbFileListData;
+ pFLD->numFiles = Swap16IfLE(0);
+ pFLD->dataSize = Swap16IfLE(0);
+ pFLD->compressedSize = Swap16IfLE(0);
+ pFLD->flags = flags | 0x80;
+
+ fileListMsg.data = data;
+ fileListMsg.length = length;
+
+ return fileListMsg;
+}
+
+
+FileTransferMsg
+CreateFileListMsg(FileListInfo fileListInfo, char flags)
+{
+ FileTransferMsg fileListMsg;
+ rfbFileListDataMsg* pFLD = NULL;
+ char *data = NULL, *pFileNames = NULL;
+ unsigned int length = 0, dsSize = 0, i = 0;
+ FileListItemSizePtr pFileListItemSize = NULL;
+
+ memset(&fileListMsg, 0, sizeof(FileTransferMsg));
+ dsSize = fileListInfo.numEntries * 8;
+ length = sz_rfbFileListDataMsg + dsSize +
+ GetSumOfFileNamesLength(fileListInfo) +
+ fileListInfo.numEntries;
+
+ data = (char*) calloc(length, sizeof(char));
+ if(data == NULL) {
+ return fileListMsg;
+ }
+ pFLD = (rfbFileListDataMsg*) data;
+ pFileListItemSize = (FileListItemSizePtr) &data[sz_rfbFileListDataMsg];
+ pFileNames = &data[sz_rfbFileListDataMsg + dsSize];
+
+ pFLD->type = rfbFileListData;
+ pFLD->flags = flags & 0xF0;
+ pFLD->numFiles = Swap16IfLE(fileListInfo.numEntries);
+ pFLD->dataSize = Swap16IfLE(GetSumOfFileNamesLength(fileListInfo) +
+ fileListInfo.numEntries);
+ pFLD->compressedSize = pFLD->dataSize;
+
+ for(i =0; i <fileListInfo.numEntries; i++) {
+ pFileListItemSize[i].size = Swap32IfLE(GetFileSizeAt(fileListInfo, i));
+ pFileListItemSize[i].data = Swap32IfLE(GetFileDataAt(fileListInfo, i));
+ strcpy(pFileNames, GetFileNameAt(fileListInfo, i));
+
+ if(i+1 < fileListInfo.numEntries)
+ pFileNames += strlen(pFileNames) + 1;
+ }
+
+ fileListMsg.data = data;
+ fileListMsg.length = length;
+
+ return fileListMsg;
+}
+
+
+/******************************************************************************
+ * Methods to handle File Download Request.
+ ******************************************************************************/
+
+FileTransferMsg CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen);
+FileTransferMsg CreateFileDownloadZeroSizeDataMsg(unsigned long mTime);
+FileTransferMsg CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile);
+
+FileTransferMsg
+GetFileDownLoadErrMsg()
+{
+ FileTransferMsg fileDownloadErrMsg;
+
+ char reason[] = "An internal error on the server caused download failure";
+ int reasonLen = strlen(reason);
+
+ memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg));
+
+ fileDownloadErrMsg = CreateFileDownloadErrMsg(reason, reasonLen);
+
+ return fileDownloadErrMsg;
+}
+
+
+FileTransferMsg
+GetFileDownloadReadDataErrMsg()
+{
+ char reason[] = "Cannot open file, perhaps it is absent or is a directory";
+ int reasonLen = strlen(reason);
+
+ return CreateFileDownloadErrMsg(reason, reasonLen);
+
+}
+
+
+FileTransferMsg
+GetFileDownloadLengthErrResponseMsg()
+{
+ char reason [] = "Path length exceeds PATH_MAX (4096) bytes";
+ int reasonLen = strlen(reason);
+
+ return CreateFileDownloadErrMsg(reason, reasonLen);
+}
+
+
+FileTransferMsg
+GetFileDownloadResponseMsgInBlocks(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ //const unsigned int sz_rfbBlockSize = SZ_RFBBLOCKSIZE;
+ int numOfBytesRead = 0;
+ char pBuf[SZ_RFBBLOCKSIZE];
+ char* path = rtcp->rcft.rcfd.fName;
+
+ memset(pBuf, 0, SZ_RFBBLOCKSIZE);
+
+ if((rtcp->rcft.rcfd.downloadInProgress == FALSE) && (rtcp->rcft.rcfd.downloadFD == -1)) {
+ if((rtcp->rcft.rcfd.downloadFD = open(path, O_RDONLY)) == -1) {
+ rfbLog("File [%s]: Method [%s]: Error: Couldn't open file\n",
+ __FILE__, __FUNCTION__);
+ return GetFileDownloadReadDataErrMsg();
+ }
+ rtcp->rcft.rcfd.downloadInProgress = TRUE;
+ }
+ if((rtcp->rcft.rcfd.downloadInProgress == TRUE) && (rtcp->rcft.rcfd.downloadFD != -1)) {
+ if( (numOfBytesRead = read(rtcp->rcft.rcfd.downloadFD, pBuf, SZ_RFBBLOCKSIZE)) <= 0) {
+ close(rtcp->rcft.rcfd.downloadFD);
+ rtcp->rcft.rcfd.downloadFD = -1;
+ rtcp->rcft.rcfd.downloadInProgress = FALSE;
+ if(numOfBytesRead == 0) {
+ return CreateFileDownloadZeroSizeDataMsg(rtcp->rcft.rcfd.mTime);
+ }
+ return GetFileDownloadReadDataErrMsg();
+ }
+ return CreateFileDownloadBlockSizeDataMsg(numOfBytesRead, pBuf);
+ }
+}
+
+
+FileTransferMsg
+ChkFileDownloadErr(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ FileTransferMsg fileDownloadMsg;
+ struct stat stat_buf;
+ int sz_rfbFileSize = 0;
+ char* path = rtcp->rcft.rcfd.fName;
+
+ memset(&fileDownloadMsg, 0, sizeof(FileTransferMsg));
+
+ if( (path == NULL) || (strlen(path) == 0) ||
+ (stat(path, &stat_buf) < 0) || (!(S_ISREG(stat_buf.st_mode))) ) {
+
+ char reason[] = "Cannot open file, perhaps it is absent or is not a regular file";
+ int reasonLen = strlen(reason);
+
+ rfbLog("File [%s]: Method [%s]: Reading stat for path %s failed\n",
+ __FILE__, __FUNCTION__, path);
+
+ fileDownloadMsg = CreateFileDownloadErrMsg(reason, reasonLen);
+ }
+ else {
+ rtcp->rcft.rcfd.mTime = stat_buf.st_mtime;
+ sz_rfbFileSize = stat_buf.st_size;
+ if(sz_rfbFileSize <= 0) {
+ fileDownloadMsg = CreateFileDownloadZeroSizeDataMsg(stat_buf.st_mtime);
+ }
+
+ }
+ return fileDownloadMsg;
+}
+
+
+FileTransferMsg
+CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen)
+{
+ FileTransferMsg fileDownloadErrMsg;
+ int length = sz_rfbFileDownloadFailedMsg + reasonLen + 1;
+ rfbFileDownloadFailedMsg *pFDF = NULL;
+ char *pFollow = NULL;
+
+ char *pData = (char*) calloc(length, sizeof(char));
+ memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg));
+ if(pData == NULL) {
+ rfbLog("File [%s]: Method [%s]: pData is NULL\n",
+ __FILE__, __FUNCTION__);
+ return fileDownloadErrMsg;
+ }
+
+ pFDF = (rfbFileDownloadFailedMsg *) pData;
+ pFollow = &pData[sz_rfbFileDownloadFailedMsg];
+
+ pFDF->type = rfbFileDownloadFailed;
+ pFDF->reasonLen = Swap16IfLE(reasonLen);
+ memcpy(pFollow, reason, reasonLen);
+
+ fileDownloadErrMsg.data = pData;
+ fileDownloadErrMsg.length = length;
+
+ return fileDownloadErrMsg;
+}
+
+
+FileTransferMsg
+CreateFileDownloadZeroSizeDataMsg(unsigned long mTime)
+{
+ FileTransferMsg fileDownloadZeroSizeDataMsg;
+ int length = sz_rfbFileDownloadDataMsg + sizeof(int);
+ rfbFileDownloadDataMsg *pFDD = NULL;
+ char *pFollow = NULL;
+
+ char *pData = (char*) calloc(length, sizeof(char));
+ memset(&fileDownloadZeroSizeDataMsg, 0, sizeof(FileTransferMsg));
+ if(pData == NULL) {
+ rfbLog("File [%s]: Method [%s]: pData is NULL\n",
+ __FILE__, __FUNCTION__);
+ return fileDownloadZeroSizeDataMsg;
+ }
+
+ pFDD = (rfbFileDownloadDataMsg *) pData;
+ pFollow = &pData[sz_rfbFileDownloadDataMsg];
+
+ pFDD->type = rfbFileDownloadData;
+ pFDD->compressLevel = 0;
+ pFDD->compressedSize = Swap16IfLE(0);
+ pFDD->realSize = Swap16IfLE(0);
+
+ memcpy(pFollow, &mTime, sizeof(unsigned long));
+
+ fileDownloadZeroSizeDataMsg.data = pData;
+ fileDownloadZeroSizeDataMsg.length = length;
+
+ return fileDownloadZeroSizeDataMsg;
+
+}
+
+
+FileTransferMsg
+CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile)
+{
+ FileTransferMsg fileDownloadBlockSizeDataMsg;
+ int length = sz_rfbFileDownloadDataMsg + sizeFile;
+ rfbFileDownloadDataMsg *pFDD = NULL;
+ char *pFollow = NULL;
+
+ char *pData = (char*) calloc(length, sizeof(char));
+ memset(&fileDownloadBlockSizeDataMsg, 0, sizeof(FileTransferMsg));
+ if(NULL == pData) {
+ rfbLog("File [%s]: Method [%s]: pData is NULL\n",
+ __FILE__, __FUNCTION__);
+ return fileDownloadBlockSizeDataMsg;
+ }
+
+ pFDD = (rfbFileDownloadDataMsg *) pData;
+ pFollow = &pData[sz_rfbFileDownloadDataMsg];
+
+ pFDD->type = rfbFileDownloadData;
+ pFDD->compressLevel = 0;
+ pFDD->compressedSize = Swap16IfLE(sizeFile);
+ pFDD->realSize = Swap16IfLE(sizeFile);
+
+ memcpy(pFollow, pFile, sizeFile);
+
+ fileDownloadBlockSizeDataMsg.data = pData;
+ fileDownloadBlockSizeDataMsg.length = length;
+
+ return fileDownloadBlockSizeDataMsg;
+
+}
+
+
+/******************************************************************************
+ * Methods to handle file upload request
+ ******************************************************************************/
+
+FileTransferMsg CreateFileUploadErrMsg(char* reason, unsigned int reasonLen);
+
+FileTransferMsg
+GetFileUploadLengthErrResponseMsg()
+{
+ char reason [] = "Path length exceeds PATH_MAX (4096) bytes";
+ int reasonLen = strlen(reason);
+
+ return CreateFileUploadErrMsg(reason, reasonLen);
+}
+
+
+FileTransferMsg
+ChkFileUploadErr(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ FileTransferMsg fileUploadErrMsg;
+
+ memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
+ if( (rtcp->rcft.rcfu.fName == NULL) ||
+ (strlen(rtcp->rcft.rcfu.fName) == 0) ||
+ ((rtcp->rcft.rcfu.uploadFD = creat(rtcp->rcft.rcfu.fName,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1)) {
+
+ char reason[] = "Could not create file";
+ int reasonLen = strlen(reason);
+ fileUploadErrMsg = CreateFileUploadErrMsg(reason, reasonLen);
+ }
+ else
+ rtcp->rcft.rcfu.uploadInProgress = TRUE;
+
+ return fileUploadErrMsg;
+}
+
+
+FileTransferMsg
+GetFileUploadCompressedLevelErrMsg()
+{
+ char reason[] = "Server does not support data compression on upload";
+ int reasonLen = strlen(reason);
+
+ return CreateFileUploadErrMsg(reason, reasonLen);
+}
+
+
+FileTransferMsg
+ChkFileUploadWriteErr(rfbClientPtr cl, rfbTightClientPtr rtcp, char* pBuf)
+{
+ FileTransferMsg ftm;
+ unsigned long numOfBytesWritten = 0;
+
+ memset(&ftm, 0, sizeof(FileTransferMsg));
+
+ numOfBytesWritten = write(rtcp->rcft.rcfu.uploadFD, pBuf, rtcp->rcft.rcfu.fSize);
+
+ if(numOfBytesWritten != rtcp->rcft.rcfu.fSize) {
+ char reason[] = "Error writing file data";
+ int reasonLen = strlen(reason);
+ ftm = CreateFileUploadErrMsg(reason, reasonLen);
+ CloseUndoneFileTransfer(cl, rtcp);
+ }
+ return ftm;
+}
+
+
+void
+FileUpdateComplete(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ /* Here we are settimg the modification and access time of the file */
+ /* Windows code stes mod/access/creation time of the file */
+ struct utimbuf utb;
+
+ utb.actime = utb.modtime = rtcp->rcft.rcfu.mTime;
+ if(utime(rtcp->rcft.rcfu.fName, &utb) == -1) {
+ rfbLog("File [%s]: Method [%s]: Setting the modification/access"
+ " time for the file <%s> failed\n", __FILE__,
+ __FUNCTION__, rtcp->rcft.rcfu.fName);
+ }
+
+ if(rtcp->rcft.rcfu.uploadFD != -1) {
+ close(rtcp->rcft.rcfu.uploadFD);
+ rtcp->rcft.rcfu.uploadFD = -1;
+ rtcp->rcft.rcfu.uploadInProgress = FALSE;
+ }
+}
+
+
+FileTransferMsg
+CreateFileUploadErrMsg(char* reason, unsigned int reasonLen)
+{
+ FileTransferMsg fileUploadErrMsg;
+ int length = sz_rfbFileUploadCancelMsg + reasonLen;
+ rfbFileUploadCancelMsg *pFDF = NULL;
+ char *pFollow = NULL;
+
+ char *pData = (char*) calloc(length, sizeof(char));
+ memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
+ if(pData == NULL) {
+ rfbLog("File [%s]: Method [%s]: pData is NULL\n",
+ __FILE__, __FUNCTION__);
+ return fileUploadErrMsg;
+ }
+
+ pFDF = (rfbFileUploadCancelMsg *) pData;
+ pFollow = &pData[sz_rfbFileUploadCancelMsg];
+
+ pFDF->type = rfbFileUploadCancel;
+ pFDF->reasonLen = Swap16IfLE(reasonLen);
+ memcpy(pFollow, reason, reasonLen);
+
+ fileUploadErrMsg.data = pData;
+ fileUploadErrMsg.length = length;
+
+ return fileUploadErrMsg;
+}
+
+
+/******************************************************************************
+ * Method to cancel File Transfer operation.
+ ******************************************************************************/
+
+void
+CloseUndoneFileTransfer(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ /* TODO :: File Upload case is not handled currently */
+ /* TODO :: In case of concurrency we need to use Critical Section */
+
+ if(cl == NULL)
+ return;
+
+
+ if(rtcp->rcft.rcfu.uploadInProgress == TRUE) {
+ rtcp->rcft.rcfu.uploadInProgress = FALSE;
+
+ if(rtcp->rcft.rcfu.uploadFD != -1) {
+ close(rtcp->rcft.rcfu.uploadFD);
+ rtcp->rcft.rcfu.uploadFD = -1;
+ }
+
+ if(unlink(rtcp->rcft.rcfu.fName) == -1) {
+ rfbLog("File [%s]: Method [%s]: Delete operation on file <%s> failed\n",
+ __FILE__, __FUNCTION__, rtcp->rcft.rcfu.fName);
+ }
+
+ memset(rtcp->rcft.rcfu.fName, 0 , PATH_MAX);
+ }
+
+ if(rtcp->rcft.rcfd.downloadInProgress == TRUE) {
+ rtcp->rcft.rcfd.downloadInProgress = FALSE;
+
+ if(rtcp->rcft.rcfd.downloadFD != -1) {
+ close(rtcp->rcft.rcfd.downloadFD);
+ rtcp->rcft.rcfd.downloadFD = -1;
+ }
+ memset(rtcp->rcft.rcfd.fName, 0 , PATH_MAX);
+ }
+}
+
+
+/******************************************************************************
+ * Method to handle create directory request.
+ ******************************************************************************/
+
+void
+CreateDirectory(char* dirName)
+{
+ if(dirName == NULL) return;
+
+ if(mkdir(dirName, 0700) == -1) {
+ rfbLog("File [%s]: Method [%s]: Create operation for directory <%s> failed\n",
+ __FILE__, __FUNCTION__, dirName);
+ }
+}
+