"Fossies" - the Fresh Open Source Software Archive

Member "netxms-3.4.232/src/server/core/agent_policy.cpp" (6 Jul 2020, 19478 Bytes) of package /linux/misc/netxms-3.4.232.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "agent_policy.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.3.350_vs_3.4.178.

    1 /*
    2 ** NetXMS - Network Management System
    3 ** Copyright (C) 2003-2020 Raden Solutions
    4 **
    5 ** This program is free software; you can redistribute it and/or modify
    6 ** it under the terms of the GNU General Public License as published by
    7 ** the Free Software Foundation; either version 2 of the License, or
    8 ** (at your option) any later version.
    9 **
   10 ** This program is distributed in the hope that it will be useful,
   11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
   12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13 ** GNU General Public License for more details.
   14 **
   15 ** You should have received a copy of the GNU General Public License
   16 ** along with this program; if not, write to the Free Software
   17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   18 **
   19 ** File: agent_policy.cpp
   20 **
   21 **/
   22 
   23 #include "nxcore.h"
   24 
   25 #define DEBUG_TAG _T("agent.policy")
   26 
   27 /**
   28  * Constructor for user-initiated object creation
   29  */
   30 GenericAgentPolicy::GenericAgentPolicy(const uuid& guid, const TCHAR *type, uint32_t ownerId)
   31 {
   32    m_name[0] = 0;
   33    _tcslcpy(m_type, type, MAX_POLICY_TYPE_LEN);
   34    m_guid = guid;
   35    m_ownerId = ownerId;
   36    m_content = nullptr;
   37    m_version = 1;
   38    m_flags = 0;
   39    m_contentLock = MutexCreateFast();
   40 }
   41 
   42 /**
   43  * Constructor for user-initiated object creation
   44  */
   45 GenericAgentPolicy::GenericAgentPolicy(const TCHAR *name, const TCHAR *type, uint32_t ownerId)
   46 {
   47    _tcslcpy(m_name, name, MAX_OBJECT_NAME);
   48    _tcslcpy(m_type, type, MAX_POLICY_TYPE_LEN);
   49    m_guid = uuid::generate();
   50    m_ownerId = ownerId;
   51    m_content = nullptr;
   52    m_version = 1;
   53    m_flags = 0;
   54    m_contentLock = MutexCreateFast();
   55 }
   56 
   57 /**
   58  * Destructor
   59  */
   60 GenericAgentPolicy::~GenericAgentPolicy()
   61 {
   62    MutexDestroy(m_contentLock);
   63    MemFree(m_content);
   64 }
   65 
   66 /**
   67  * Save to database
   68  */
   69 bool GenericAgentPolicy::saveToDatabase(DB_HANDLE hdb)
   70 {
   71    DB_STATEMENT hStmt;
   72    if (!IsDatabaseRecordExist(hdb, _T("ap_common"), _T("guid"), m_guid)) //Policy can be only created. Policy type can't be changed.
   73       hStmt = DBPrepare(hdb, _T("INSERT INTO ap_common (policy_name,owner_id,policy_type,file_content,version,flags,guid) VALUES (?,?,?,?,?,?,?)"));
   74    else
   75       hStmt = DBPrepare(hdb, _T("UPDATE ap_common SET policy_name=?,owner_id=?,policy_type=?,file_content=?,version=?,flags=? WHERE guid=?"));
   76 
   77    if (hStmt == nullptr)
   78       return false;
   79 
   80    DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, m_name, DB_BIND_STATIC);
   81    DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, m_ownerId);
   82    DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, m_type, DB_BIND_STATIC);
   83    DBBind(hStmt, 4, DB_SQLTYPE_TEXT, DB_CTYPE_UTF8_STRING, m_content, DB_BIND_STATIC);
   84    DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, m_version);
   85    DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, m_flags);
   86    DBBind(hStmt, 7, DB_SQLTYPE_VARCHAR, m_guid);
   87    bool success = DBExecute(hStmt);
   88    DBFreeStatement(hStmt);
   89 
   90    return success;
   91 }
   92 
   93 /**
   94  * Delete from database
   95  */
   96 bool GenericAgentPolicy::deleteFromDatabase(DB_HANDLE hdb)
   97 {
   98    TCHAR query[256];
   99    _sntprintf(query, 256, _T("DELETE FROM ap_common WHERE guid='%s'"), (const TCHAR *)m_guid.toString());
  100    return DBQuery(hdb, query);
  101 }
  102 
  103 /**
  104  * Load from database
  105  */
  106 bool GenericAgentPolicy::loadFromDatabase(DB_HANDLE hdb)
  107 {
  108    bool success = false;
  109 
  110    TCHAR query[256];
  111    _sntprintf(query, 256, _T("SELECT policy_name,owner_id,policy_type,file_content,version,flags FROM ap_common WHERE guid='%s'"), (const TCHAR *)m_guid.toString());
  112    DB_RESULT hResult = DBSelect(hdb, query);
  113    if (hResult != nullptr)
  114    {
  115       if (DBGetNumRows(hResult) > 0)
  116       {
  117          DBGetField(hResult, 0, 0, m_name, MAX_OBJECT_NAME);
  118          m_ownerId = DBGetFieldLong(hResult, 0, 1);
  119          DBGetField(hResult, 0, 2, m_type, MAX_POLICY_TYPE_LEN);
  120          m_content = DBGetFieldUTF8(hResult, 0, 3, nullptr, 0);
  121          m_version = DBGetFieldLong(hResult, 0, 4);
  122          m_flags = DBGetFieldLong(hResult, 0, 5);
  123          success = true;
  124       }
  125       DBFreeResult(hResult);
  126    }
  127 
  128    return success;
  129 }
  130 
  131 /**
  132  * Create NXCP message with policy data
  133  */
  134 void GenericAgentPolicy::fillMessage(NXCPMessage *msg, uint32_t baseId) const
  135 {
  136    msg->setField(baseId, m_guid);
  137    msg->setField(baseId + 1, m_type);
  138    msg->setField(baseId + 2, m_name);
  139    msg->setFieldFromUtf8String(baseId + 3, CHECK_NULL_EX_A(m_content));
  140    msg->setField(baseId + 4, m_flags);
  141 }
  142 
  143 /**
  144  * Create NXCP message with policy data for notifications
  145  */
  146 void GenericAgentPolicy::fillUpdateMessage(NXCPMessage *msg) const
  147 {
  148    msg->setField(VID_GUID, m_guid);
  149    msg->setField(VID_NAME, m_name);
  150    msg->setField(VID_POLICY_TYPE, m_type);
  151    msg->setFieldFromUtf8String(VID_CONFIG_FILE_DATA, CHECK_NULL_EX_A(m_content));
  152    msg->setField(VID_FLAGS, m_flags);
  153 }
  154 
  155 /**
  156  * Modify policy from message
  157  */
  158 uint32_t GenericAgentPolicy::modifyFromMessage(const NXCPMessage& msg)
  159 {
  160    MutexLock(m_contentLock);
  161    msg.getFieldAsString(VID_NAME, m_name, MAX_DB_STRING);
  162    if (msg.isFieldExist(VID_CONFIG_FILE_DATA))
  163    {
  164       MemFree(m_content);
  165       m_content = msg.getFieldAsUtf8String(VID_CONFIG_FILE_DATA);
  166    }
  167    if (msg.isFieldExist(VID_FLAGS))
  168    {
  169       m_flags = msg.getFieldAsUInt32(VID_FLAGS);
  170    }
  171    m_version++;
  172    MutexUnlock(m_contentLock);
  173    return RCC_SUCCESS;
  174 }
  175 
  176 /**
  177  * Create deployment message
  178  */
  179 bool GenericAgentPolicy::createDeploymentMessage(NXCPMessage *msg, char *content, bool newTypeFormatSupported)
  180 {
  181    if (content == nullptr)
  182       return false;  // Policy cannot be deployed
  183 
  184    msg->setField(VID_CONFIG_FILE_DATA, reinterpret_cast<BYTE*>(content), strlen(content));
  185 
  186    if (newTypeFormatSupported)
  187    {
  188       msg->setField(VID_POLICY_TYPE, m_type);
  189    }
  190    else
  191    {
  192       if (!_tcscmp(m_type, _T("AgentConfig")))
  193       {
  194          msg->setField(VID_POLICY_TYPE, static_cast<uint16_t>(AGENT_POLICY_CONFIG));
  195       }
  196       else if (!_tcscmp(m_type, _T("LogParserConfig")))
  197       {
  198          msg->setField(VID_POLICY_TYPE, static_cast<uint16_t>(AGENT_POLICY_LOG_PARSER));
  199       }
  200       else
  201       {
  202          return false;  // This policy type is not supported by old agents
  203       }
  204    }
  205    msg->setField(VID_GUID, m_guid);
  206    msg->setField(VID_VERSION, m_version);
  207 
  208    return true;
  209 }
  210 
  211 /**
  212  * Deploy policy to agent. Default implementation calls connector's deployPolicy() method
  213  */
  214 void GenericAgentPolicy::deploy(shared_ptr<AgentPolicyDeploymentData> data)
  215 {
  216    if (data->conn == nullptr)
  217    {
  218       nxlog_debug_tag(DEBUG_TAG, 4, _T("GenericAgentPolicy::deploy(%s): failed - no connection to agent"), data->debugId);
  219       return;
  220    }
  221 
  222    bool sendUpdate = true;
  223    MutexLock(m_contentLock);
  224 
  225    if (!data->forceInstall && data->currVersion >= m_version && (m_flags & EXPAND_MACRO) == 0)
  226    {
  227       sendUpdate = false;
  228    }
  229 
  230    char *content = nullptr;
  231    if (m_flags & EXPAND_MACRO)
  232    {
  233 #ifdef UNICODE
  234       WCHAR *tmp = WideStringFromUTF8String(m_content);
  235       StringBuffer expanded = data->object->expandText(tmp, nullptr, nullptr, shared_ptr<DCObjectInfo>(), nullptr, nullptr, nullptr, nullptr);
  236       content = UTF8StringFromWideString(expanded.cstr());
  237       MemFree(tmp);
  238 #else
  239       StringBuffer expanded = data->object->expandText(m_content, nullptr, nullptr, shared_ptr<DCObjectInfo>(), nullptr, nullptr, nullptr, nullptr);
  240       content = MemCopyString(expanded.cstr());
  241 #endif
  242       BYTE newHash[MD5_DIGEST_SIZE];
  243       if (!data->forceInstall)
  244       {
  245          CalculateMD5Hash(reinterpret_cast<BYTE*>(content), strlen(content), newHash);
  246          if (!memcmp(newHash, data->currHash, MD5_DIGEST_SIZE))
  247             sendUpdate = false;
  248       }
  249    }
  250    else
  251    {
  252       content = MemCopyStringA(m_content);
  253    }
  254    MutexUnlock(m_contentLock);
  255 
  256    if (sendUpdate)
  257    {
  258       nxlog_debug_tag(DEBUG_TAG, 4, _T("Calling GenericAgentPolicy::deploy at %s (type=%s, newTypeFormat=%d)"), data->debugId, m_type, data->newTypeFormat);
  259 
  260       NXCPMessage msg(data->conn->getProtocolVersion());
  261       if (createDeploymentMessage(&msg, content, data->newTypeFormat))
  262       {
  263          uint32_t rcc = data->conn->deployPolicy(&msg);
  264          if (rcc == RCC_SUCCESS)
  265          {
  266             nxlog_debug_tag(DEBUG_TAG, 5, _T("GenericAgentPolicy::deploy(%s): policy successfully deployed"), data->debugId);
  267          }
  268          else
  269          {
  270             nxlog_debug_tag(DEBUG_TAG, 5, _T("GenericAgentPolicy::deploy(%s) policy deploy failed: %s"), data->debugId, AgentErrorCodeToText(rcc));
  271          }
  272       }
  273       else
  274       {
  275          nxlog_debug_tag(DEBUG_TAG, 5, _T("GenericAgentPolicy::deploy(%s): failed to create policy deployment message"), data->debugId);
  276       }
  277    }
  278    else
  279    {
  280       nxlog_debug_tag(DEBUG_TAG, 7, _T("GenericAgentPolicy::deploy(%s): policy not changed - nothing to install"), data->debugId);
  281    }
  282 
  283    MemFree(content);
  284 }
  285 
  286 /**
  287  * Serialize object to JSON
  288  */
  289 json_t *GenericAgentPolicy::toJson()
  290 {
  291    json_t *root = json_object();
  292    json_object_set_new(root, "guid", json_string_t(m_guid.toString()));
  293    json_object_set_new(root, "name", json_string_t(m_name));
  294    json_object_set_new(root, "type", json_string_t(m_type));
  295    json_object_set_new(root, "flags", json_integer(m_flags));
  296    json_object_set_new(root, "content", json_string(CHECK_NULL_EX_A(m_content)));
  297    return root;
  298 }
  299 
  300 /**
  301  * Update policy from imported configuration
  302  */
  303 void GenericAgentPolicy::updateFromImport(const ConfigEntry *config)
  304 {
  305    _tcslcpy(m_name, config->getSubEntryValue(_T("name"), 0, _T("Unnamed")), MAX_OBJECT_NAME);
  306    _tcslcpy(m_type, config->getSubEntryValue(_T("type"), 0, _T("Unknown")), MAX_POLICY_TYPE_LEN);
  307    m_flags = config->getSubEntryValueAsUInt(_T("flags"));
  308    const TCHAR *content = config->getSubEntryValue(_T("content"), 0, _T(""));
  309    MemFree(m_content);
  310    m_content = UTF8StringFromTString(content);
  311 }
  312 
  313 /**
  314  * Create export record
  315  */
  316 void GenericAgentPolicy::createExportRecord(StringBuffer &xml, uint32_t recordId)
  317 {
  318    xml.append(_T("\t\t\t\t<agentPolicy id=\""));
  319    xml.append(recordId);
  320    xml.append(_T("\">\n\t\t\t\t\t<guid>"));
  321    xml.append(m_guid);
  322    xml.append(_T("</guid>\n\t\t\t\t\t<name>"));
  323    xml.append(EscapeStringForXML2(m_name));
  324    xml.append(_T("</name>\n\t\t\t\t\t<type>"));
  325    xml.append(m_type);
  326    xml.append(_T("</type>\n\t\t\t\t\t<flags>"));
  327    xml.append(m_flags);
  328    xml.append(_T("</flags>\n\t\t\t\t\t<content>"));
  329    TCHAR *content = TStringFromUTF8String(CHECK_NULL_EX_A(m_content));
  330    xml.append(EscapeStringForXML2(content));
  331    MemFree(content);
  332    xml.append(_T("</content>\n"));
  333    xml.append(_T("\t\t\t\t</agentPolicy>\n"));
  334 }
  335 
  336 /**
  337  * File information
  338  */
  339 struct FileInfo
  340 {
  341    uuid guid;
  342    uuid newGuid;
  343    TCHAR *path;
  344 
  345    ~FileInfo()
  346    {
  347       MemFree(path);
  348    }
  349 };
  350 
  351 /**
  352  * Build file list from path element
  353  */
  354 static void BuildFileList(ConfigEntry *currEntry, StringBuffer *currPath, ObjectArray<FileInfo> *files, bool updateGuid)
  355 {
  356    ConfigEntry *children = currEntry->findEntry(_T("children"));
  357    if (children == nullptr)
  358       return;
  359 
  360    size_t pathPos = currPath->length();
  361    currPath->append(currEntry->getAttribute(_T("name")));
  362    currPath->append(_T("/"));
  363 
  364    ObjectArray<ConfigEntry> *elements = children->getSubEntries(_T("*"));
  365    if (elements != nullptr)
  366    {
  367       for(int i = 0; i < elements->size(); i++)
  368       {
  369          ConfigEntry *e = elements->get(i);
  370          uuid guid = e->getSubEntryValueAsUUID(_T("guid"));
  371          if (!guid.isNull())
  372          {
  373             size_t pos = currPath->length();
  374             currPath->append(e->getAttribute(_T("name")));
  375             auto f = new FileInfo;
  376             f->guid = guid;
  377             f->path = MemCopyString(currPath->cstr());
  378             files->add(f);
  379             currPath->shrink(currPath->length() - pos);
  380             if (updateGuid)
  381             {
  382                f->newGuid = uuid::generate();
  383                ObjectArray<ConfigEntry> *values = e->getSubEntries(_T("guid"));
  384                values->get(0)->setValue(f->newGuid.toString());
  385                delete values;
  386             }
  387          }
  388          else
  389          {
  390             BuildFileList(e, currPath, files, updateGuid);
  391          }
  392       }
  393       delete elements;
  394    }
  395 
  396    currPath->shrink(currPath->length() - pathPos);
  397 }
  398 
  399 /**
  400  * Modify from message and in case of duplicate - duplicate all physical files and update GUID
  401  */
  402 uint32_t FileDeliveryPolicy::modifyFromMessage(const NXCPMessage& request)
  403 {
  404    uint32_t result = GenericAgentPolicy::modifyFromMessage(request);
  405    if (result != RCC_SUCCESS)
  406       return result;
  407 
  408    if (request.getFieldAsBoolean(VID_DUPLICATE))
  409    {
  410       MutexLock(m_contentLock);
  411       ObjectArray<FileInfo> files(64, 64, Ownership::True);
  412       Config data;
  413       data.loadXmlConfigFromMemory(m_content, static_cast<int>(strlen(m_content)), nullptr, "FileDeliveryPolicy", false);
  414       ObjectArray<ConfigEntry> *rootElements = data.getSubEntries(_T("/elements"), _T("*"));
  415       if (rootElements != nullptr)
  416       {
  417          for(int i = 0; i < rootElements->size(); i++)
  418          {
  419             StringBuffer path;
  420             BuildFileList(rootElements->get(i), &path, &files, true);
  421          }
  422          delete rootElements;
  423       }
  424       MemFree(m_content);
  425       data.setTopLevelTag(_T("FileDeliveryPolicy"));
  426       m_content = data.createXml().getUTF8String();
  427       MutexUnlock(m_contentLock);
  428 
  429       for(int i = 0; i < files.size(); i++)
  430       {
  431          nxlog_debug_tag(DEBUG_TAG, 4, _T("FileDeliveryPolicy::modifyFromMessage(): copy file and update GUID from %s to %s"),
  432                   files.get(i)->guid.toString().cstr(), files.get(i)->newGuid.toString().cstr());
  433 
  434          StringBuffer sourceFile = g_netxmsdDataDir;
  435          sourceFile.append(DDIR_FILES FS_PATH_SEPARATOR _T("FileDelivery-"));
  436          sourceFile.append(files.get(i)->guid.toString());
  437 
  438          StringBuffer destinationFile = g_netxmsdDataDir;
  439          destinationFile.append(DDIR_FILES FS_PATH_SEPARATOR _T("FileDelivery-"));
  440          destinationFile.append(files.get(i)->newGuid.toString());
  441 
  442          CopyFileOrDirectory(sourceFile, destinationFile);
  443       }
  444    }
  445    return result;
  446 }
  447 
  448 /**
  449  * File delivery policy destructor
  450  * deletes all files on policy deletion
  451  */
  452 bool FileDeliveryPolicy::deleteFromDatabase(DB_HANDLE hdb)
  453 {
  454    ObjectArray<FileInfo> files(64, 64, Ownership::True);
  455    Config data;
  456    data.loadXmlConfigFromMemory(m_content, static_cast<int>(strlen(m_content)), nullptr, "FileDeliveryPolicy", false);
  457    ObjectArray<ConfigEntry> *rootElements = data.getSubEntries(_T("/elements"), _T("*"));
  458    if (rootElements != nullptr)
  459    {
  460       for(int i = 0; i < rootElements->size(); i++)
  461       {
  462          StringBuffer path;
  463          BuildFileList(rootElements->get(i), &path, &files, true);
  464       }
  465       delete rootElements;
  466    }
  467 
  468    for(int i = 0; i < files.size(); i++)
  469    {
  470       String guid = files.get(i)->guid.toString();
  471       nxlog_debug_tag(DEBUG_TAG, 4, _T("FileDeliveryPolicy::modifyFromMessage(): copy file %s and update guid"), guid.cstr());
  472 
  473       StringBuffer sourceFile = g_netxmsdDataDir;
  474       sourceFile.append(DDIR_FILES FS_PATH_SEPARATOR _T("FileDelivery-"));
  475       sourceFile.append(guid);
  476 
  477       _tremove(sourceFile);
  478    }
  479 
  480    return GenericAgentPolicy::deleteFromDatabase(hdb);
  481 }
  482 
  483 /**
  484  * Deploy file delivery policy
  485  */
  486 void FileDeliveryPolicy::deploy(shared_ptr<AgentPolicyDeploymentData> data)
  487 {
  488    nxlog_debug_tag(DEBUG_TAG, 4, _T("FileDeliveryPolicy::deploy(%s):)"), data->debugId);
  489 
  490    if (!data->newTypeFormat)
  491    {
  492       nxlog_debug_tag(DEBUG_TAG, 4, _T("FileDeliveryPolicy::deploy(%s): failed - file delivery policy not supported by agent"), data->debugId);
  493       return;
  494    }
  495 
  496    if (data->conn == nullptr)
  497    {
  498       nxlog_debug_tag(DEBUG_TAG, 4, _T("FileDeliveryPolicy::deploy(%s): failed - no connection to agent"), data->debugId);
  499       return;
  500    }
  501 
  502    MutexLock(m_contentLock);
  503    if (m_content == nullptr)
  504    {
  505       nxlog_debug_tag(DEBUG_TAG, 4, _T("FileDeliveryPolicy::deploy(%s): empty content)"), data->debugId);
  506       MutexUnlock(m_contentLock);
  507       return;
  508    }
  509 
  510    nxlog_debug_tag(DEBUG_TAG, 6, _T("FileDeliveryPolicy::deploy(%s): preparing file list"), data->debugId);
  511    ObjectArray<FileInfo> files(64, 64, Ownership::True);
  512    Config content;
  513    content.loadXmlConfigFromMemory(m_content, static_cast<int>(strlen(m_content)), nullptr, "FileDeliveryPolicy", false);
  514    MutexUnlock(m_contentLock);
  515 
  516    ObjectArray<ConfigEntry> *rootElements = content.getSubEntries(_T("/elements"), _T("*"));
  517    if (rootElements != nullptr)
  518    {
  519       for(int i = 0; i < rootElements->size(); i++)
  520       {
  521          StringBuffer path;
  522          BuildFileList(rootElements->get(i), &path, &files, false);
  523       }
  524       delete rootElements;
  525    }
  526 
  527    StringList fileRequest;
  528    for(int i = 0; i < files.size(); i++)
  529    {
  530       nxlog_debug_tag(DEBUG_TAG, 4, _T("FileDeliveryPolicy::deploy(%s): processing file path %s"), data->debugId, files.get(i)->path);
  531       fileRequest.add(files.get(i)->path);
  532    }
  533    ObjectArray<RemoteFileInfo> *remoteFiles;
  534    uint32_t rcc = data->conn->getFileSetInfo(&fileRequest, true, &remoteFiles);
  535    if (rcc != RCC_SUCCESS)
  536    {
  537       nxlog_debug_tag(DEBUG_TAG, 4, _T("FileDeliveryPolicy::deploy(%s): call to AgentConnection::getFileSetInfo failed (%s)"), data->debugId, AgentErrorCodeToText(rcc));
  538       return;
  539    }
  540 
  541    for(int i = 0; i < remoteFiles->size(); i++)
  542    {
  543       RemoteFileInfo *remoteFile = remoteFiles->get(i);
  544       if ((remoteFile->status() != ERR_SUCCESS) && (remoteFile->status() != ERR_FILE_STAT_FAILED))
  545       {
  546          nxlog_debug_tag(DEBUG_TAG, 4, _T("FileDeliveryPolicy::deploy(%s): file %s with status %d skipped"), data->debugId, remoteFile->name(), remoteFile->status());
  547          continue;
  548       }
  549 
  550       StringBuffer localFile = g_netxmsdDataDir;
  551       localFile.append(DDIR_FILES FS_PATH_SEPARATOR _T("FileDelivery-"));
  552       localFile.append(files.get(i)->guid.toString());
  553 
  554       BYTE localHash[MD5_DIGEST_SIZE];
  555       if (CalculateFileMD5Hash(localFile, localHash) && ((remoteFile->status() == ERR_FILE_STAT_FAILED) || memcmp(localHash, remoteFile->hash(), MD5_DIGEST_SIZE)))
  556       {
  557          nxlog_debug_tag(DEBUG_TAG, 5, _T("FileDeliveryPolicy::deploy(%s): uploading %s"), data->debugId, files.get(i)->path);
  558          rcc = data->conn->uploadFile(localFile, remoteFile->name(), true);
  559          nxlog_debug_tag(DEBUG_TAG, 5, _T("FileDeliveryPolicy::deploy(%s): upload completed (%s)"), data->debugId, AgentErrorCodeToText(rcc));
  560       }
  561       else
  562       {
  563          nxlog_debug_tag(DEBUG_TAG, 5, _T("FileDeliveryPolicy::deploy(%s): remote file %s and local file %s are the same, synchronization skipped"), data->debugId, remoteFile->name(), localFile.cstr());
  564       }
  565    }
  566    delete remoteFiles;
  567 
  568    nxlog_debug_tag(DEBUG_TAG, 5, _T("FileDeliveryPolicy::deploy(%s): policy successfully deployed"), data->debugId);
  569 }
  570 
  571 /**
  572  * Remove policy from agent. Will destroy provided removal data.
  573  */
  574 void RemoveAgentPolicy(const shared_ptr<AgentPolicyRemovalData>& data)
  575 {
  576    if (data->conn != nullptr)
  577    {
  578       uint32_t rcc = data->conn->uninstallPolicy(data->guid, data->policyType, data->newTypeFormat);
  579       if (rcc == ERR_SUCCESS)
  580       {
  581          nxlog_debug_tag(DEBUG_TAG, 5, _T("RemoveAgentPolicy(%s): policy successfully removed"), data->debugId);
  582       }
  583       else
  584       {
  585          nxlog_debug_tag(DEBUG_TAG, 5, _T("RemoveAgentPolicy(%s): policy removal failed: %s"), data->debugId, AgentErrorCodeToText(rcc));
  586       }
  587    }
  588    else
  589    {
  590       nxlog_debug_tag(DEBUG_TAG, 5, _T("RemoveAgentPolicy(%s): policy removal failed: no connection to agent"), data->debugId);
  591    }
  592 }