Now for all uploaded files modification time is not changed. Small file upload refact...
authorzev <zev@radensolutions.com>
Wed, 25 Jan 2017 15:26:24 +0000 (17:26 +0200)
committerzev <zev@radensolutions.com>
Wed, 25 Jan 2017 15:26:33 +0000 (17:26 +0200)
20 files changed:
configure.ac
include/nms_agent.h
include/nms_common.h
include/nms_util.h
include/unicode.h
src/agent/core/Makefile.am
src/agent/core/dfile_info.cpp [new file with mode: 0644]
src/agent/core/nxagentd.h
src/agent/core/session.cpp
src/agent/subagents/filemgr/filemgr.cpp
src/java/client/netxms-client/src/main/java/org/netxms/client/NXCSession.java
src/libnetxms/tools.cpp
src/libnetxms/unicode.cpp
src/server/core/Makefile.am
src/server/core/dfile_info.cpp [new file with mode: 0644]
src/server/core/main.cpp
src/server/core/ps.cpp
src/server/core/session.cpp
src/server/include/nms_core.h
src/server/libnxsrv/agent.cpp

index 38871c2..7e0167c 100644 (file)
@@ -1608,7 +1608,7 @@ AC_CHECK_HEADERS([fcntl.h dirent.h sys/ioctl.h sys/sockio.h poll.h termios.h])
 AC_CHECK_HEADERS([inttypes.h memory.h stdint.h stdlib.h strings.h string.h])
 AC_CHECK_HEADERS([readline/readline.h byteswap.h sys/select.h dlfcn.h locale.h])
 AC_CHECK_HEADERS([sys/sysctl.h sys/param.h sys/user.h vm/vm_param.h syslog.h])
-AC_CHECK_HEADERS([grp.h pwd.h malloc.h stdbool.h])
+AC_CHECK_HEADERS([grp.h pwd.h malloc.h stdbool.h utime.h])
 AC_CHECK_HEADERS([net/if.h net/if_arp.h net/if_dl.h net/if_types.h],,,
 [[#ifdef HAVE_SYS_TYPES_H
 # include <sys/types.h>
@@ -1975,7 +1975,7 @@ AC_CHECK_FUNCS([strrchr strlwr strtok_r strtol strtoul strtoll strtoull setlocal
 AC_CHECK_FUNCS([tolower if_nametoindex daemon mmap strerror_r scandir uname poll])
 AC_CHECK_FUNCS([usleep nanosleep gmtime_r localtime_r stat64 fstat64 lstat64])
 AC_CHECK_FUNCS([fopen64 strptime timegm gethostbyname2_r getaddrinfo rand_r])
-AC_CHECK_FUNCS([itoa _itoa isatty getgrnam getpwnam malloc_info malloc_trim])
+AC_CHECK_FUNCS([itoa _itoa isatty getgrnam getpwnam malloc_info malloc_trim utime])
 
 AC_CHECK_DECLS([nanosleep, daemon, strerror])
 
@@ -2332,7 +2332,7 @@ AC_CHECK_FUNCS([wcslwr wcserror wcserror_r wfopen wfopen64 fputws putws])
 AC_CHECK_FUNCS([wopen wstat waccess wgetenv wrename wunlink wremove wchdir])
 AC_CHECK_FUNCS([wmkdir wrmdir wsystem wmkstemp wpopen wctime wchmod vwscanf])
 AC_CHECK_FUNCS([vswscanf vfwscanf wcscasecmp wcsncasecmp wcstombs wcsrtombs])
-AC_CHECK_FUNCS([mbstowcs mbsrtowcs itow _itow wcsftime wcstok])
+AC_CHECK_FUNCS([mbstowcs mbsrtowcs itow _itow wcsftime wcstok wutime])
 
 AC_CHECK_DECLS([putws],,,[
 #if HAVE_WCHAR_H
index 98f7e31..3e202df 100644 (file)
@@ -510,7 +510,7 @@ public:
    virtual UINT32 doRequest(NXCPMessage *msg, UINT32 timeout) = 0;
    virtual NXCPMessage *doRequestEx(NXCPMessage *msg, UINT32 timeout) = 0;
    virtual UINT32 generateRequestId() = 0;
-   virtual UINT32 openFile(TCHAR* nameOfFile, UINT32 requestId) = 0;
+   virtual UINT32 openFile(TCHAR* nameOfFile, UINT32 requestId, time_t fileModTime = 0) = 0;
    virtual void debugPrintf(int level, const TCHAR *format, ...) = 0;
 };
 
index b16e95f..76dfc2e 100644 (file)
@@ -221,6 +221,7 @@ typedef int bool;
 #define HAVE_WCSLEN             1
 #define HAVE_WCSNCPY            1
 #define HAVE_WCSDUP             1
+#define HAVE_WUTIME             1
 
 #ifndef va_copy
 #define va_copy(x,y)            (x = y)
@@ -237,6 +238,7 @@ typedef int bool;
 
 #ifndef UNDER_CE
 #include <sys/stat.h>
+#include <sys/utime.h>
 #include <process.h>
 #include <io.h>
 #include <fcntl.h>
@@ -554,6 +556,10 @@ using std::wcsncasecmp;
 #include <sys/types.h>
 #endif
 
+#if HAVE_UTIME_H
+#include <utime.h>
+#endif
+
 #if HAVE_SYS_INT_TYPES_H
 #include <sys/int_types.h>
 #endif
index d036f4d..31bf454 100644 (file)
@@ -1821,6 +1821,7 @@ bool LIBNETXMS_EXPORTABLE RegexpMatchW(const WCHAR *str, const WCHAR *expr, bool
 
 const TCHAR LIBNETXMS_EXPORTABLE *ExpandFileName(const TCHAR *name, TCHAR *buffer, size_t bufSize, bool allowShellCommand);
 BOOL LIBNETXMS_EXPORTABLE CreateFolder(const TCHAR *directory);
+bool LIBNETXMS_EXPORTABLE SetLastModificationTime(TCHAR *fileName, time_t lastModDate);
 TCHAR LIBNETXMS_EXPORTABLE *Trim(TCHAR *str);
 bool LIBNETXMS_EXPORTABLE MatchString(const TCHAR *pattern, const TCHAR *str, bool matchCase);
 TCHAR LIBNETXMS_EXPORTABLE **SplitString(const TCHAR *source, TCHAR sep, int *numStrings);
@@ -1969,6 +1970,9 @@ int wchdir(const WCHAR *_path);
 #if !HAVE_WMKDIR
 int wmkdir(const WCHAR *_path, int mode);
 #endif
+#if !HAVE_WUTIME
+int wutime(const WCHAR *_path, struct utimbuf *buf);
+#endif
 #if !HAVE_WRMDIR
 int wrmdir(const WCHAR *_path);
 #endif
index 180813a..0aadbc0 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
 ** NetXMS - Network Management System
 ** Copyright (C) 2003-2010 Victor Kirhenshtein
 **
 #define _tmkdir   wmkdir
 #define _tchdir   wchdir
 #define _trmdir   wrmdir
+#define _tutime   wutime
 #define _tcserror wcserror
 #define _tcserror_r wcserror_r
 #define _tsystem  wsystem
 #define _tmkdir   mkdir
 #define _tchdir   chdir
 #define _trmdir   rmdir
+#define _tutime   utime
 #define _tcserror strerror
 #define _tcserror_r strerror_r
 #define _tsystem  system
index 8463bd3..13d3ca2 100644 (file)
@@ -1,7 +1,7 @@
 AM_CPPFLAGS=-I@top_srcdir@/include
 bin_PROGRAMS = nxagentd
 nxagentd_SOURCES = messages.c actions.cpp appagent.cpp comm.cpp config.cpp \
-                   ctrl.cpp datacoll.cpp dcsnmp.cpp dbupgrade.cpp epp.cpp \
+                   ctrl.cpp datacoll.cpp dcsnmp.cpp dbupgrade.cpp dfile_info.cpp epp.cpp \
                    exec.cpp extagent.cpp getparam.cpp localdb.cpp master.cpp \
                    nxagentd.cpp policy.cpp push.cpp register.cpp sa.cpp \
                    sd.cpp session.cpp snmpproxy.cpp snmptrapproxy.cpp \
diff --git a/src/agent/core/dfile_info.cpp b/src/agent/core/dfile_info.cpp
new file mode 100644 (file)
index 0000000..246926d
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+** NetXMS - Network Management System
+** Copyright (C) 2017 Raden Solutions
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** 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, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: dfile_info.cpp
+**
+**/
+
+#include "nxagentd.h"
+
+#ifdef _WIN32
+#define write  _write
+#define close  _close
+#endif
+
+/**
+ * Constructor for DownloadFileInfo class only stores given data
+ */
+DownloadFileInfo::DownloadFileInfo(const TCHAR *name, time_t lastModTime)
+{
+   m_fileName = _tcsdup(name);
+   m_lastModTime = lastModTime;
+}
+
+/**
+ * Destructor
+ */
+DownloadFileInfo::~DownloadFileInfo()
+{
+   if(m_file != -1)
+      close(false);
+
+   delete m_fileName;
+}
+
+/**
+ * Opens file and returns if it was successfully
+ */
+bool DownloadFileInfo::open()
+{
+   m_file = _topen(m_fileName, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IRUSR | S_IWUSR);
+   return m_file != -1;
+}
+
+/**
+ * Function that writes incoming data to file
+ */
+bool DownloadFileInfo::write(const BYTE *data, int dataSize)
+{
+   return ::write(m_file, data, dataSize) == dataSize;
+}
+
+/**
+ * Closes file and changes it's date if required
+ */
+void DownloadFileInfo::close(bool success)
+{
+   ::close(m_file);
+   m_file = -1;
+
+   if(m_lastModTime != 0)
+      SetLastModificationTime(m_fileName, m_lastModTime);
+
+   // Remove received file in case of failure
+   if (!success)
+      _tunlink(m_fileName);
+}
index 2a0e156..3b6c1a3 100644 (file)
@@ -302,6 +302,24 @@ struct PendingRequest
    }
 };
 
+/**
+ * Class that stores information about file that will be received
+ */
+class DownloadFileInfo
+{
+private:
+   TCHAR *m_fileName;
+   time_t m_lastModTime;
+   int m_file;
+
+public:
+   DownloadFileInfo(const TCHAR *name, time_t lastModTime = 0);
+   ~DownloadFileInfo();
+   bool open();
+   bool write(const BYTE *data, int dataSize);
+   void close(bool success);
+};
+
 /**
  * Communication session
  */
@@ -328,8 +346,7 @@ private:
    bool m_acceptFileUpdates;
    bool m_ipv6Aware;
    bool m_bulkReconciliationSupported;
-   int m_hCurrFile;
-   UINT32 m_fileRqId;
+   HashMap<UINT32, DownloadFileInfo> m_downloadFileMap;
    StreamCompressor *m_compressor;
        NXCPEncryptionContext *m_pCtx;
    time_t m_ts;               // Last activity timestamp
@@ -392,7 +409,7 @@ public:
    virtual bool isBulkReconciliationSupported() { return m_bulkReconciliationSupported; }
    virtual bool isIPv6Aware() { return m_ipv6Aware; }
 
-   virtual UINT32 openFile(TCHAR *nameOfFile, UINT32 requestId);
+   virtual UINT32 openFile(TCHAR *nameOfFile, UINT32 requestId, time_t fileModTime = 0);
 
    virtual void debugPrintf(int level, const TCHAR *format, ...);
 
@@ -436,7 +453,7 @@ public:
    virtual UINT32 doRequest(NXCPMessage *msg, UINT32 timeout) { return RCC_NOT_IMPLEMENTED; }
    virtual NXCPMessage *doRequestEx(NXCPMessage *msg, UINT32 timeout) { return NULL; }
    virtual UINT32 generateRequestId() { return 0; }
-   virtual UINT32 openFile(TCHAR *fileName, UINT32 requestId) { return ERR_INTERNAL_ERROR; }
+   virtual UINT32 openFile(TCHAR *fileName, UINT32 requestId, time_t fileModTime = 0) { return ERR_INTERNAL_ERROR; }
    virtual void debugPrintf(int level, const TCHAR *format, ...);
 };
 
index b5e0d46..ead6fa7 100644 (file)
@@ -113,7 +113,7 @@ THREAD_RESULT THREAD_CALL CommSession::proxyReadThreadStarter(void *pArg)
 /**
  * Client session class constructor
  */
-CommSession::CommSession(SOCKET hSocket, const InetAddress &serverAddr, bool masterServer, bool controlServer)
+CommSession::CommSession(SOCKET hSocket, const InetAddress &serverAddr, bool masterServer, bool controlServer) : m_downloadFileMap(true)
 {
    m_id = InterlockedIncrement(&s_sessionId);
    m_index = INVALID_INDEX;
@@ -136,8 +136,6 @@ CommSession::CommSession(SOCKET hSocket, const InetAddress &serverAddr, bool mas
    m_ipv6Aware = false;
    m_bulkReconciliationSupported = false;
    m_disconnected = false;
-   m_hCurrFile = -1;
-   m_fileRqId = 0;
    m_compressor = NULL;
    m_pCtx = NULL;
    m_ts = time(NULL);
@@ -169,9 +167,6 @@ CommSession::~CommSession()
       if (p != INVALID_POINTER_VALUE)
          delete (NXCPMessage *)p;
    delete m_processingQueue;
-
-   if (m_hCurrFile != -1)
-      close(m_hCurrFile);
    delete m_compressor;
        if ((m_pCtx != NULL) && (m_pCtx != PROXY_ENCRYPTION_CTX))
                m_pCtx->decRefCount();
@@ -273,7 +268,8 @@ void CommSession::readThread()
 
             if (msg->getCode() == CMD_FILE_DATA)
             {
-               if ((m_hCurrFile != -1) && (m_fileRqId == msg->getId()))
+               DownloadFileInfo *dInfo = m_downloadFileMap.get(msg->getId());
+               if (dInfo != NULL)
                {
                   const BYTE *data;
                   int dataSize;
@@ -308,14 +304,14 @@ void CommSession::readThread()
                      dataSize = (int)msg->getBinaryDataSize();
                   }
 
-                  if ((dataSize >= 0) && (write(m_hCurrFile, data, dataSize) == dataSize))
+                  if ((dataSize >= 0) && dInfo->write(data, dataSize))
                   {
                      if (msg->isEndOfFile())
                      {
                         NXCPMessage response;
 
-                        close(m_hCurrFile);
-                        m_hCurrFile = -1;
+                        dInfo->close(true);
+                        m_downloadFileMap.remove(msg->getId());
                         delete_and_null(m_compressor);
 
                         response.setCode(CMD_REQUEST_COMPLETED);
@@ -329,8 +325,8 @@ void CommSession::readThread()
                      // I/O error
                      NXCPMessage response;
 
-                     close(m_hCurrFile);
-                     m_hCurrFile = -1;
+                     dInfo->close(false);
+                     m_downloadFileMap.remove(msg->getId());
                      delete_and_null(m_compressor);
 
                      response.setCode(CMD_REQUEST_COMPLETED);
@@ -928,26 +924,21 @@ void CommSession::recvFile(NXCPMessage *pRequest, NXCPMessage *pMsg)
 /**
  * Open file for writing
  */
-UINT32 CommSession::openFile(TCHAR *szFullPath, UINT32 requestId)
+UINT32 CommSession::openFile(TCHAR *szFullPath, UINT32 requestId, time_t fileModTime)
 {
-   if (m_hCurrFile != -1)
+   DownloadFileInfo *fInfo = new DownloadFileInfo(szFullPath, fileModTime);
+   debugPrintf(5, _T("CommSession::recvFile(): Writing to local file \"%s\""), szFullPath);
+
+   if (!fInfo->open())
    {
-      return ERR_RESOURCE_BUSY;
+      delete fInfo;
+      debugPrintf(2, _T("CommSession::recvFile(): Error opening file \"%s\" for writing (%s)"), szFullPath, _tcserror(errno));
+      return ERR_IO_FAILURE;
    }
    else
    {
-      debugPrintf(5, _T("CommSession::recvFile(): Writing to local file \"%s\""), szFullPath);
-      m_hCurrFile = _topen(szFullPath, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0600);
-      if (m_hCurrFile == -1)
-      {
-         debugPrintf(2, _T("CommSession::recvFile(): Error opening file \"%s\" for writing (%s)"), szFullPath, _tcserror(errno));
-         return ERR_IO_FAILURE;
-      }
-      else
-      {
-         m_fileRqId = requestId;
-         return ERR_SUCCESS;
-      }
+      m_downloadFileMap.set(requestId, fInfo);
+      return ERR_SUCCESS;
    }
 }
 
index 8f4407b..09eab91 100644 (file)
@@ -827,7 +827,7 @@ static BOOL ProcessCommands(UINT32 command, NXCPMessage *request, NXCPMessage *r
 
          if (CheckFullPath(name, false, true) && session->isMasterServer())
          {
-            response->setField(VID_RCC, session->openFile(name, request->getId()));
+            response->setField(VID_RCC, session->openFile(name, request->getId(), request->getFieldAsTime(VID_DATE)));
          }
          else
          {
index ea815d8..0d006df 100644 (file)
@@ -7655,6 +7655,7 @@ public class NXCSession
          serverFileName = localFile.getName();
       }
       msg.setField(NXCPCodes.VID_FILE_NAME, serverFileName);
+      msg.setField(NXCPCodes.VID_DATE, new Date(localFile.lastModified()));
       sendMessage(msg);
       waitForRCC(msg.getMessageId());
       sendFile(msg.getMessageId(), localFile, listener);
@@ -7678,6 +7679,7 @@ public class NXCSession
       }
       msg.setField(NXCPCodes.VID_FILE_NAME, agentFileName);
       msg.setFieldInt32(NXCPCodes.VID_OBJECT_ID, (int) nodeId);
+      msg.setField(NXCPCodes.VID_DATE, new Date(localFile.lastModified()));
       sendMessage(msg);
       waitForRCC(msg.getMessageId());
       sendFile(msg.getMessageId(), localFile, listener);
index 42b294d..9c97b03 100644 (file)
@@ -702,6 +702,23 @@ BOOL LIBNETXMS_EXPORTABLE CreateFolder(const TCHAR *directory)
    return result;
 }
 
+/**
+ * Set last modification time to file
+ */
+bool SetLastModificationTime(TCHAR *fileName, time_t lastModDate)
+{
+   bool success = false;
+#ifdef _WIN32
+   struct _utimbuf ut;
+#else
+   struct utimbuf ut;
+#endif // _WIN32
+   ut.actime = lastModDate;
+   ut.modtime = lastModDate;
+   success = _tutime(fileName, &ut) == 0;
+   return success;
+}
+
 /**
  * Get current time in milliseconds
  * Based on timeval.h by Wu Yongwei
index 7bec128..111d645 100644 (file)
@@ -42,7 +42,7 @@ bool LIBNETXMS_EXPORTABLE SetDefaultCodepage(const char *cp)
    if (cd != (iconv_t)(-1))
    {
       iconv_close(cd);
-#endif         
+#endif
       strncpy(g_cpDefault, cp, MAX_CODEPAGE_LEN);
       g_cpDefault[MAX_CODEPAGE_LEN - 1] = 0;
       rc = true;
@@ -806,6 +806,19 @@ int wmkdir(const WCHAR *_path, int mode)
 
 #endif
 
+#if !HAVE_WUTIME
+
+int wutime(const WCHAR *_path, utimbuf *buf)
+{
+   char path[MAX_PATH];
+
+   WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
+      _path, -1, path, MAX_PATH, NULL, NULL);
+   return utime(path, buf);
+}
+
+#endif
+
 #if !HAVE_WGETENV
 
 WCHAR *wgetenv(const WCHAR *_string)
index 70e502b..5e50b97 100644 (file)
@@ -13,7 +13,7 @@ libnxcore_la_SOURCES =  accesspoint.cpp acl.cpp actions.cpp addrlist.cpp \
                        container.cpp correlate.cpp dashboard.cpp datacoll.cpp dbwrite.cpp \
                        dc_nxsl.cpp dcitem.cpp dcithreshold.cpp dcivalue.cpp \
                        dcobject.cpp dcst.cpp dctable.cpp dctarget.cpp \
-                       dctcolumn.cpp dctthreshold.cpp debug.cpp \
+                       dctcolumn.cpp dctthreshold.cpp debug.cpp dfile_info.cpp \
                        download_job.cpp ef.cpp email.cpp entirenet.cpp \
                        epp.cpp events.cpp evproc.cpp fdb.cpp \
                        filemonitoring.cpp graph.cpp hdlink.cpp hk.cpp id.cpp \
diff --git a/src/server/core/dfile_info.cpp b/src/server/core/dfile_info.cpp
new file mode 100644 (file)
index 0000000..d29fa57
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+** NetXMS - Network Management System
+** Copyright (C) 2017 Raden Solutions
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** 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, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** File: dfile_info.cpp
+**
+**/
+
+#include "nxcore.h"
+
+#ifdef _WIN32
+#define write  _write
+#define close  _close
+#endif
+
+/**
+ * Constructor for DownloadFileInfo class only stores given data
+ */
+DownloadFileInfo::DownloadFileInfo(const TCHAR *name, UINT32 uploadCommand, time_t lastModTime)
+{
+   m_fileName = _tcsdup(name);
+   m_uploadCommand = uploadCommand;
+   m_lastModTime = lastModTime;
+}
+
+/**
+ * Destructor
+ */
+DownloadFileInfo::~DownloadFileInfo()
+{
+   if(m_file != -1)
+      close(false);
+
+   delete m_fileName;
+}
+
+/**
+ * Opens file and returns if it was successfully
+ */
+bool DownloadFileInfo::open()
+{
+   m_file = _topen(m_fileName, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IRUSR | S_IWUSR);
+   return m_file != -1;
+}
+
+/**
+ * Set upload data for package
+ */
+void DownloadFileInfo::setUploadData(UINT32 data)
+{
+   m_uploadData = data;
+}
+/**
+ * Set downloadable image guid
+ */
+void DownloadFileInfo::setGUID(uuid_t guid)
+{
+   memcpy(m_uploadImageGuid, guid, UUID_LENGTH);
+}
+
+/**
+ * Update database information about agent package
+ */
+void DownloadFileInfo::updateAgentPkgDBInfo(const TCHAR *description, const TCHAR *pkgName, const TCHAR *pkgVersion, const TCHAR *platform, const TCHAR *cleanFileName)
+{
+   TCHAR *escDescr = EncodeSQLString(description);
+   TCHAR szQuery[2048];
+   _sntprintf(szQuery, 2048, _T("INSERT INTO agent_pkg (pkg_id,pkg_name,")
+                                _T("version,description,platform,pkg_file) ")
+                                _T("VALUES (%d,'%s','%s','%s','%s','%s')"),
+              m_uploadData, pkgName, pkgVersion, escDescr,
+              platform, cleanFileName);
+   free(escDescr);
+
+   DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
+   DBQuery(hdb, szQuery);
+   DBConnectionPoolReleaseConnection(hdb);
+}
+
+/**
+ * Function that writes incoming data to file
+ */
+bool DownloadFileInfo::write(const BYTE *data, int dataSize)
+{
+   return ::write(m_file, data, dataSize) == dataSize;
+}
+
+
+/**
+ * Callback for sending image library update notifications
+ */
+static void ImageLibraryUpdateCallback(ClientSession *pSession, void *pArg)
+{
+       pSession->onLibraryImageChange((uuid_t *)pArg, false);
+}
+
+/**
+ * Closes file and changes it's date if required
+ */
+void DownloadFileInfo::close(bool success)
+{
+   ::close(m_file);
+   m_file = -1;
+
+   switch(m_uploadCommand)
+   {
+   case CMD_INSTALL_PACKAGE:
+      if (!success)
+      {
+         DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
+         TCHAR szQuery[256];
+         _sntprintf(szQuery, 256, _T("DELETE FROM agent_pkg WHERE pkg_id=%d"), m_uploadData);
+         DBQuery(hdb, szQuery);
+         DBConnectionPoolReleaseConnection(hdb);
+      }
+      break;
+   case CMD_MODIFY_IMAGE:
+      EnumerateClientSessions(ImageLibraryUpdateCallback, (void *)&m_uploadImageGuid);
+      break;
+   case CMD_UPLOAD_FILE:
+      if(m_lastModTime != 0)
+         SetLastModificationTime(m_fileName, m_lastModTime);
+      break;
+   default:
+      break;
+   }
+
+
+   // Remove received file in case of failure
+   if (!success)
+      _tunlink(m_fileName);
+}
index 393376d..f04859b 100644 (file)
@@ -1027,7 +1027,6 @@ void NXCORE_EXPORTABLE Shutdown()
 
        StopSyslogServer();
        StopHouseKeeper();
-       PersistentStorageDestroy();
 
        // Wait for critical threads
        ThreadJoin(m_thPollManager);
@@ -1054,6 +1053,7 @@ void NXCORE_EXPORTABLE Shutdown()
        nxlog_debug(1, _T("Database writer stopped"));
 
        CleanupUsers();
+       PersistentStorageDestroy();
 
        // Remove database lock
        UnlockDB();
index 5d13d8f..ffeb2d6 100644 (file)
@@ -94,7 +94,6 @@ bool DeletePersistentStorageValue(const TCHAR *key)
       return false;
    MutexLock(s_lockPStorage);
    bool success = s_persistentStorage.contains(key);
-   s_persistentStorage.remove(key);
    if(success)
    {
       s_persistentStorage.remove(key);
index c539c29..8cd1516 100644 (file)
@@ -27,8 +27,6 @@
 
 #ifdef _WIN32
 #include <psapi.h>
-#define write  _write
-#define close  _close
 #else
 #include <dirent.h>
 #endif
@@ -113,14 +111,6 @@ static void DeleteCallback(NetObj* obj, void *data)
    ((AgentConnection *)obj)->decRefCount();
 }
 
-/**
- * Callback for sending image library update notifications
- */
-static void ImageLibraryUpdateCallback(ClientSession *pSession, void *pArg)
-{
-       pSession->onLibraryImageChange((uuid_t *)pArg, false);
-}
-
 /**
  * Callback for sending image library delete notifications
  */
@@ -237,7 +227,7 @@ THREAD_RESULT THREAD_CALL ClientSession::updateThreadStarter(void *pArg)
 /**
  * Client session class constructor
  */
-ClientSession::ClientSession(SOCKET hSocket, struct sockaddr *addr)
+ClientSession::ClientSession(SOCKET hSocket, struct sockaddr *addr) : m_downloadFileMap(true)
 {
    m_pSendQueue = new Queue;
    m_pMessageQueue = new Queue;
@@ -279,15 +269,11 @@ ClientSession::ClientSession(SOCKET hSocket, struct sockaddr *addr)
    m_pOpenDCIList = NULL;
    m_ppEPPRuleList = NULL;
    m_wCurrentCmd = 0;
-   m_hCurrFile = -1;
-   m_dwFileRqId = 0;
-   m_dwUploadCommand = 0;
    m_dwNumRecordsToUpload = 0;
    m_dwRecordsUploaded = 0;
    m_refCount = 0;
    m_dwEncryptionRqId = 0;
    m_dwEncryptionResult = 0;
-   m_dwUploadData = 0;
    m_condEncryptionSetup = INVALID_CONDITION_HANDLE;
        m_console = NULL;
    m_loginTime = time(NULL);
@@ -443,26 +429,25 @@ void ClientSession::readThread()
          if ((msg->getCode() == CMD_FILE_DATA) ||
              (msg->getCode() == CMD_ABORT_FILE_TRANSFER))
          {
-            if ((m_hCurrFile != -1) && (m_dwFileRqId == msg->getId()))
+            DownloadFileInfo *dInfo = m_downloadFileMap.get(msg->getId());
+            if (dInfo != NULL)
             {
                if (msg->getCode() == CMD_FILE_DATA)
                {
-                  if (write(m_hCurrFile, msg->getBinaryData(), (int)msg->getBinaryDataSize()) == (int)msg->getBinaryDataSize())
+                  if (dInfo->write(msg->getBinaryData(), (int)msg->getBinaryDataSize()))
                   {
                      if (msg->isEndOfFile())
                      {
                                                                debugPrintf(6, _T("Got end of file marker"));
                         NXCPMessage response;
 
-                        close(m_hCurrFile);
-                        m_hCurrFile = -1;
-
                         response.setCode(CMD_REQUEST_COMPLETED);
                         response.setId(msg->getId());
                         response.setField(VID_RCC, RCC_SUCCESS);
                         sendMessage(&response);
 
-                        onFileUpload(TRUE);
+                        dInfo->close(true);
+                        m_downloadFileMap.remove(msg->getId());
                      }
                   }
                   else
@@ -471,24 +456,20 @@ void ClientSession::readThread()
                      // I/O error
                      NXCPMessage response;
 
-                     close(m_hCurrFile);
-                     m_hCurrFile = -1;
-
                      response.setCode(CMD_REQUEST_COMPLETED);
                      response.setId(msg->getId());
                      response.setField(VID_RCC, RCC_IO_ERROR);
                      sendMessage(&response);
 
-                     onFileUpload(FALSE);
+                     dInfo->close(false);
+                     m_downloadFileMap.remove(msg->getId());
                   }
                }
                else
                {
                   // Abort current file transfer because of client's problem
-                  close(m_hCurrFile);
-                  m_hCurrFile = -1;
-
-                  onFileUpload(FALSE);
+                  dInfo->close(false);
+                  m_downloadFileMap.remove(msg->getId());
                }
             }
             else
@@ -590,14 +571,6 @@ void ClientSession::readThread()
    ThreadJoin(m_hWriteThread);
    ThreadJoin(m_hProcessingThread);
 
-   // Abort current file upload operation, if any
-   if (m_hCurrFile != -1)
-   {
-      close(m_hCurrFile);
-      m_hCurrFile = -1;
-      onFileUpload(FALSE);
-   }
-
    // remove all pending file transfers from reporting server
    RemovePendingFileTransferRequests(this);
 
@@ -1563,36 +1536,6 @@ void ClientSession::respondToKeepalive(UINT32 dwRqId)
    sendMessage(&msg);
 }
 
-/**
- * Process received file
- */
-void ClientSession::onFileUpload(BOOL bSuccess)
-{
-  // Do processing specific to command initiated file upload
-  switch(m_dwUploadCommand)
-  {
-    case CMD_INSTALL_PACKAGE:
-      if (!bSuccess)
-      {
-         DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
-         TCHAR szQuery[256];
-         _sntprintf(szQuery, 256, _T("DELETE FROM agent_pkg WHERE pkg_id=%d"), m_dwUploadData);
-         DBQuery(hdb, szQuery);
-         DBConnectionPoolReleaseConnection(hdb);
-      }
-      break;
-    case CMD_MODIFY_IMAGE:
-      EnumerateClientSessions(ImageLibraryUpdateCallback, (void *)&m_uploadImageGuid);
-      break;
-    default:
-      break;
-  }
-
-  // Remove received file in case of failure
-  if (!bSuccess)
-    _tunlink(m_szCurrFileName);
-}
-
 /**
  * Send message to client
  */
@@ -6896,8 +6839,7 @@ void ClientSession::InstallPackage(NXCPMessage *pRequest)
    NXCPMessage msg;
    TCHAR szPkgName[MAX_PACKAGE_NAME_LEN], szDescription[MAX_DB_STRING];
    TCHAR szPkgVersion[MAX_AGENT_VERSION_LEN], szFileName[MAX_DB_STRING];
-   TCHAR szPlatform[MAX_PLATFORM_NAME_LEN], *pszEscDescr;
-   TCHAR szQuery[2048];
+   TCHAR szPlatform[MAX_PLATFORM_NAME_LEN];
 
    // Prepare response message
    msg.setCode(CMD_REQUEST_COMPLETED);
@@ -6927,43 +6869,29 @@ void ClientSession::InstallPackage(NXCPMessage *pRequest)
                // Check for duplicate file name
                if (!IsPackageFileExist(pszCleanFileName))
                {
-                  // Prepare for file receive
-                  if (m_hCurrFile == -1)
+                  TCHAR fullFileName[MAX_PATH];
+                  _tcscpy(fullFileName, g_netxmsdDataDir);
+                  _tcscat(fullFileName, DDIR_PACKAGES);
+                  _tcscat(fullFileName, FS_PATH_SEPARATOR);
+                  _tcscat(fullFileName, pszCleanFileName);
+
+                  DownloadFileInfo *fInfo = new DownloadFileInfo(fullFileName, CMD_INSTALL_PACKAGE);
+
+                  if (fInfo->open())
                   {
-                     _tcscpy(m_szCurrFileName, g_netxmsdDataDir);
-                     _tcscat(m_szCurrFileName, DDIR_PACKAGES);
-                     _tcscat(m_szCurrFileName, FS_PATH_SEPARATOR);
-                     _tcscat(m_szCurrFileName, pszCleanFileName);
-                     m_hCurrFile = _topen(m_szCurrFileName, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IRUSR | S_IWUSR);
-                     if (m_hCurrFile != -1)
-                     {
-                        m_dwFileRqId = pRequest->getId();
-                        m_dwUploadCommand = CMD_INSTALL_PACKAGE;
-                        m_dwUploadData = CreateUniqueId(IDG_PACKAGE);
-                        msg.setField(VID_RCC, RCC_SUCCESS);
-                        msg.setField(VID_PACKAGE_ID, m_dwUploadData);
-
-                        // Create record in database
-                        pszEscDescr = EncodeSQLString(szDescription);
-                        _sntprintf(szQuery, 2048, _T("INSERT INTO agent_pkg (pkg_id,pkg_name,")
-                                                     _T("version,description,platform,pkg_file) ")
-                                                     _T("VALUES (%d,'%s','%s','%s','%s','%s')"),
-                                   m_dwUploadData, szPkgName, szPkgVersion, pszEscDescr,
-                                   szPlatform, pszCleanFileName);
-                        free(pszEscDescr);
-
-                        DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
-                        DBQuery(hdb, szQuery);
-                        DBConnectionPoolReleaseConnection(hdb);
-                     }
-                     else
-                     {
-                        msg.setField(VID_RCC, RCC_IO_ERROR);
-                     }
+                     UINT32 uploadData = CreateUniqueId(IDG_PACKAGE);
+                     fInfo->setUploadData(uploadData);
+                     m_downloadFileMap.set(pRequest->getId(), fInfo);
+                     msg.setField(VID_RCC, RCC_SUCCESS);
+                     msg.setField(VID_PACKAGE_ID, uploadData);
+
+                     // Create record in database
+                     fInfo->updateAgentPkgDBInfo(szDescription, szPkgName, szPkgVersion, szPlatform, pszCleanFileName);
                   }
                   else
                   {
-                     msg.setField(VID_RCC, RCC_RESOURCE_BUSY);
+                     delete fInfo;
+                     msg.setField(VID_RCC, RCC_IO_ERROR);
                   }
                }
                else
@@ -12307,24 +12235,16 @@ void ClientSession::updateLibraryImage(NXCPMessage *request)
                                        _sntprintf(absFileName, MAX_PATH, _T("%s%s%s%s"), g_netxmsdDataDir, DDIR_IMAGES, FS_PATH_SEPARATOR, guidText);
                                        DbgPrintf(5, _T("updateLibraryImage: guid=%s, absFileName=%s"), guidText, absFileName);
 
-                                       if (m_hCurrFile == -1)
-                                       {
-                                               m_hCurrFile = _topen(absFileName, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IRUSR | S_IWUSR);
-                                               if (m_hCurrFile != -1)
-                                               {
-                                                       m_dwFileRqId = request->getId();
-                                                       m_dwUploadCommand = CMD_MODIFY_IMAGE;
-                     memcpy(m_uploadImageGuid, guid, UUID_LENGTH);
-                                               }
-                                               else
-                                               {
-                                                       rcc = RCC_IO_ERROR;
-                                               }
-                                       }
-                                       else
-                                       {
-                                               rcc = RCC_RESOURCE_BUSY;
-                                       }
+               DownloadFileInfo *dInfo = new DownloadFileInfo(absFileName, CMD_MODIFY_IMAGE);
+               if (dInfo->open())
+               {
+                  dInfo->setGUID(guid);
+                  m_downloadFileMap.set(request->getId(), dInfo);
+               }
+               else
+               {
+                  rcc = RCC_IO_ERROR;
+               }
                                }
                                else
                                {
@@ -12892,35 +12812,29 @@ void ClientSession::receiveFile(NXCPMessage *request)
        if (m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_SERVER_FILES)
    {
                TCHAR fileName[MAX_PATH];
+               TCHAR fullPath[MAX_PATH];
 
       request->getFieldAsString(VID_FILE_NAME, fileName, MAX_PATH);
       const TCHAR *cleanFileName = GetCleanFileName(fileName);
+      _tcscpy(fullPath, g_netxmsdDataDir);
+      _tcscat(fullPath, DDIR_FILES);
+      _tcscat(fullPath, FS_PATH_SEPARATOR);
+      _tcscat(fullPath, cleanFileName);
 
-      // Prepare for file receive
-      if (m_hCurrFile == -1)
+      DownloadFileInfo *fInfo = new DownloadFileInfo(fullPath, CMD_UPLOAD_FILE, request->getFieldAsTime(VID_DATE));
+
+      if (fInfo->open())
       {
-         _tcscpy(m_szCurrFileName, g_netxmsdDataDir);
-                       _tcscat(m_szCurrFileName, DDIR_FILES);
-         _tcscat(m_szCurrFileName, FS_PATH_SEPARATOR);
-         _tcscat(m_szCurrFileName, cleanFileName);
-         m_hCurrFile = _topen(m_szCurrFileName, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IRUSR | S_IWUSR);
-         if (m_hCurrFile != -1)
-         {
-            m_dwFileRqId = request->getId();
-            m_dwUploadCommand = CMD_UPLOAD_FILE;
-            msg.setField(VID_RCC, RCC_SUCCESS);
-            WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_workstation, m_id, 0,
-               _T("Started upload of file \"%s\" to server"), fileName);
-            NotifyClientSessions(NX_NOTIFY_FILE_LIST_CHANGED, 0);
-         }
-         else
-         {
-            msg.setField(VID_RCC, RCC_IO_ERROR);
-         }
+         m_downloadFileMap.set(request->getId(), fInfo);
+         msg.setField(VID_RCC, RCC_SUCCESS);
+         WriteAuditLog(AUDIT_SYSCFG, TRUE, m_dwUserId, m_workstation, m_id, 0,
+            _T("Started upload of file \"%s\" to server"), fileName);
+         NotifyClientSessions(NX_NOTIFY_FILE_LIST_CHANGED, 0);
       }
       else
       {
-         msg.setField(VID_RCC, RCC_RESOURCE_BUSY);
+         delete fInfo;
+         msg.setField(VID_RCC, RCC_IO_ERROR);
       }
    }
    else
@@ -12948,16 +12862,17 @@ void ClientSession::deleteFile(NXCPMessage *request)
        if (m_dwSystemAccess & SYSTEM_ACCESS_MANAGE_SERVER_FILES)
    {
                TCHAR fileName[MAX_PATH];
+               TCHAR fullPath[MAX_PATH];
 
       request->getFieldAsString(VID_FILE_NAME, fileName, MAX_PATH);
       const TCHAR *cleanFileName = GetCleanFileName(fileName);
 
-      _tcscpy(m_szCurrFileName, g_netxmsdDataDir);
-      _tcscat(m_szCurrFileName, DDIR_FILES);
-      _tcscat(m_szCurrFileName, FS_PATH_SEPARATOR);
-      _tcscat(m_szCurrFileName, cleanFileName);
+      _tcscpy(fullPath, g_netxmsdDataDir);
+      _tcscat(fullPath, DDIR_FILES);
+      _tcscat(fullPath, FS_PATH_SEPARATOR);
+      _tcscat(fullPath, cleanFileName);
 
-      if (_tunlink(m_szCurrFileName) == 0)
+      if (_tunlink(fullPath) == 0)
       {
          NotifyClientSessions(NX_NOTIFY_FILE_LIST_CHANGED, 0);
          msg.setField(VID_RCC, RCC_SUCCESS);
index 906e154..5dafeb5 100644 (file)
@@ -392,6 +392,30 @@ public:
  */
 #define DECLARE_THREAD_STARTER(func) static void ThreadStarter_##func(void *);
 
+/**
+ * Class that stores information about file that will be received
+ */
+class DownloadFileInfo
+{
+private:
+   TCHAR *m_fileName;
+   time_t m_lastModTime;
+   int m_file;
+   UINT32 m_uploadCommand;
+   UINT32 m_uploadData;
+   uuid_t m_uploadImageGuid;
+
+public:
+   DownloadFileInfo(const TCHAR *name, UINT32 uploadCommand, time_t lastModTime = 0);
+   ~DownloadFileInfo();
+   bool open();
+   void setUploadData(UINT32 data);
+   void setGUID(uuid_t guid);
+   void updateAgentPkgDBInfo(const TCHAR *description, const TCHAR *pkgName, const TCHAR *pkgVersion, const TCHAR *platform, const TCHAR *cleanFileName);
+   bool write(const BYTE *data, int dataSize);
+   void close(bool success);
+};
+
 /**
  * Client (user) session
  */
@@ -436,12 +460,7 @@ private:
    UINT32 m_dwNumRecordsToUpload; // Number of records to be uploaded
    UINT32 m_dwRecordsUploaded;
    EPRule **m_ppEPPRuleList;   // List of loaded EPP rules
-   int m_hCurrFile;
-   UINT32 m_dwFileRqId;
-   UINT32 m_dwUploadCommand;
-   UINT32 m_dwUploadData;
-   uuid_t m_uploadImageGuid;
-   TCHAR m_szCurrFileName[MAX_PATH];
+   HashMap<UINT32, DownloadFileInfo> m_downloadFileMap;
    VolatileCounter m_refCount;
    UINT32 m_dwEncryptionRqId;
    UINT32 m_dwEncryptionResult;
index 3a0fa0b..8404a90 100644 (file)
@@ -32,6 +32,8 @@
 #define _tell(f) lseek(f,0,SEEK_CUR)
 #endif
 
+#include <nxstat.h>
+
 /**
  * Constants
  */
@@ -1331,8 +1333,15 @@ UINT32 AgentConnection::uploadFile(const TCHAR *localFile, const TCHAR *destinat
    }
    else
    {
+      time_t lastModTime = 0;
+      NX_STAT_STRUCT st;
+      if (CALL_STAT(localFile, &st) == 0)
+      {
+         lastModTime = st.st_mtime;
+      }
       msg.setCode(CMD_FILEMGR_UPLOAD);
                msg.setField(VID_FILE_NAME, destinationFile);
+               msg.setFieldFromTime(VID_DATE, lastModTime);
    }
 
    if (sendMessage(&msg))