/* * 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 #include #include #include #include #include #include #include #include #include #include #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; } #ifndef __GNUC__ #define __FUNCTION__ "unknown" #endif int CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag) { DIR* pDir = NULL; struct dirent* pDirent = NULL; if(path == NULL) { return FAILURE; } if(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 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); } return GetFileDownLoadErrMsg(); } 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(unsigned long); 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. ******************************************************************************/ #ifdef _MSC_VER #undef CreateDirectory /* Prevent macro clashes under Windows */ #endif /* _MSC_VER */ 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); } }