// Copyright (c) 2013, IOnU Security, Inc. // Copyright (c) 2016, Sequence Logic, Inc. All rights reserved. /** * StorageNode implementation. * * NOTE: The C++ language is a little lame when it comes to 'named' enumerations. Trying to access an enumeration value using * a fully qualified name was not in the standard until C++11. Since Dev Studio versions prior to VS2012 conform to this, * you will get the following warning: * warning C4482: nonstandard extension used: enum 'sequencelogic::StorageNodeType' used in qualified name * due to the fact that this is the name of an enumeration. These can be ignored, and hopefully will dissappear when * we're up and running on VS2012. */ #include "storagenode.h" #include "storagelocation.h" #include "../cppcoreobjects/cloudguardurn.h" #include "../cppcoreobjects/permissions.h" #include "eyetime.h" #include #include #include using namespace sequencelogic; /* * Empty constructor. Create an empty storage node. */ StorageNode::StorageNode () : _pData(new JSONObject()) { } /* * Copy constructor. */ StorageNode::StorageNode (const StorageNodePtr &pNode) : _pData(new JSONObject(*pNode->_pData)) { } StorageNode::StorageNode (const StorageNode &node) : _pData(new JSONObject(*node._pData)) { } /* * Copy constructor. */ StorageNode::StorageNode (const JSONObjectPtr &pNode) : _pData(new JSONObject(*pNode)) { } StorageNode::StorageNode (const JSONObject &node) : _pData(new JSONObject(node)) { } /* * Create a StorageNode from a JSON string. */ StorageNode::StorageNode (const std::string &nodeString) : _pData(new JSONObject(nodeString)) { } StorageNode& StorageNode::operator=(const StorageNode &rhs) { if (this != &rhs) _pData.reset(new JSONObject(*rhs._pData)); return *this; } /* * Create a pending node! Caller owns the return pointer, and is responsible for cleanup! */ StorageNodePtr StorageNode::createPendingNode(const CloudGuardURN &pendingUrn, const std::string &path, const std::string &name) { StorageNodePtr pRetVal (new StorageNode()); pRetVal->setPath (path); pRetVal->setName (name); pRetVal->setType(StorageNodeType::SNT_PENDING); pRetVal->setMetaType("peer"); pRetVal->setStatus (StorageNodeStatus::pendingDownload); std::string mount = pendingUrn.getPMOID(); if (pendingUrn.getDeviceID() != "") { mount += "/"; mount += pendingUrn.getDeviceID(); } pRetVal->setMount(mount); return pRetVal; } /* * Create an empty node! Caller owns the return pointer, and is responsible for cleanup! */ StorageNodePtr StorageNode::createEmptyNode() { StorageNodePtr pRetVal (new StorageNode()); pRetVal->setName("No Results"); pRetVal->setType(StorageNodeType::SNT_EMPTY); pRetVal->setStatus(StorageNodeStatus::informational); /* These seemed to be "extra" in the Java code (i.e. no setters/getters) node.put("size", 0); node.put("description", "Refresh!"); */ return pRetVal; } /* * Set the name of this node. */ void StorageNode::setName (const std::string &name) { _pData->setJSONValue(STORAGE_NODE_NAME, name.c_str()); } /* * Get the name of this node. */ std::string StorageNode::getName () const { return _pData->getJSONString(STORAGE_NODE_NAME, getPath()); } /* * Set the version of this node. */ void StorageNode::setVersion (int nVer) { _pData->setJSONValue("version", nVer); } /* * Get the version of this node. */ int StorageNode::getVersion () const { return _pData->getJSONInt("version", -1); } std::string StorageNode::getUniqueName(const std::string& deviceId) const { if (getMount() == "s" || getMount() == "g") { CloudGuardURN urn(getURN()); if (deviceId != "" && urn.getDeviceID() != deviceId) { std::string result(urn.getDocumentID()); if (result != "") { result.append("."); } result.append(getName()); return result; } } return getName(); } /* * Set the mime type of this node. */ void StorageNode::setMimeType (const std::string &mimeType) { _pData->setJSONValue(STORAGE_NODE_MIME_TYPE, mimeType.c_str()); } /* * Get the mime type of this node. */ std::string StorageNode::getMimeType () const { return _pData->getJSONString(STORAGE_NODE_MIME_TYPE, MIME_TYPE_APP_UNKNOWN); } /* * Set the length of this node. */ void StorageNode::setLength (unsigned int length) { _pData->setJSONValue(STORAGE_NODE_LENGTH, length); } /* * Get the length of this node. */ unsigned int StorageNode::getLength () const { return _pData->getJSONUInt(STORAGE_NODE_LENGTH); } /* * Set the last access time for this node. */ void StorageNode::setLastAccessed (const EyeTime &lastAccessed) { _pData->setJSONValue(STORAGE_NODE_LAST_ACCESS, const_cast(lastAccessed).GetISO8601TimeMs()); } void StorageNode::setLastAccessed (const std::string &lastAccessed) { _pData->setJSONValue(STORAGE_NODE_LAST_ACCESS, lastAccessed.c_str()); } /* * Get the last access time for this node. */ sequencelogic::EyeTime StorageNode::getLastAccessed () const { std::string lastAccessStr = _pData->getJSONString(STORAGE_NODE_LAST_ACCESS, "1970-01-01T00:00:00.000Z"); return EyeTime(lastAccessStr.c_str()); } /* * Set the last modified time for this node. */ void StorageNode::setLastModified (const EyeTime &lastModified) { _pData->setJSONValue(STORAGE_NODE_LAST_MODIFIED, const_cast(lastModified).GetISO8601TimeMs()); } void StorageNode::setLastModified (const std::string &lastModified) { _pData->setJSONValue(STORAGE_NODE_LAST_MODIFIED, lastModified.c_str()); } /* * Get the last modified time for this node. */ sequencelogic::EyeTime StorageNode::getLastModified () const { std::string lastModifiedStr = _pData->getJSONString(STORAGE_NODE_LAST_MODIFIED, "1970-01-01T00:00:00.000Z"); return EyeTime(lastModifiedStr.c_str()); } /* * Set the last modified time for this node. */ void StorageNode::setutime (const EyeTime &utime) { _pData->setJSONValue(STORAGE_NODE_UTIME, const_cast(utime).GetISO8601TimeMs()); } void StorageNode::setutime (const std::string &lastModified) { _pData->setJSONValue(STORAGE_NODE_UTIME, lastModified.c_str()); } /* * Get the last modified time for this node. */ sequencelogic::EyeTime StorageNode::getutime () const { std::string utimeStr = _pData->getJSONString(STORAGE_NODE_UTIME, "1970-01-01T00:00:00.000Z"); return EyeTime(utimeStr.c_str()); } /* * Get the mtime for this node. */ sequencelogic::EyeTime StorageNode::getmtime () const { std::string mtimeStr = _pData->getJSONString(STORAGE_NODE_MTIME, "1970-01-01T00:00:00.000Z"); return EyeTime(mtimeStr.c_str()); } /* * Set the mtime for this node. */ void StorageNode::setmtime (const EyeTime &mtime) { _pData->setJSONValue(STORAGE_NODE_MTIME, const_cast(mtime).GetISO8601TimeMs()); } void StorageNode::setmtime (const std::string &lastModified) { _pData->setJSONValue(STORAGE_NODE_MTIME, lastModified.c_str()); } /* * Set the creation time for this node. */ void StorageNode::setCreation (const EyeTime &created) { _pData->setJSONValue(STORAGE_NODE_CREATE_TIME, const_cast(created).GetISO8601TimeMs()); } void StorageNode::setCreation (const std::string &created) { _pData->setJSONValue(STORAGE_NODE_CREATE_TIME, created.c_str()); } /* * Get the creation time for this node. */ sequencelogic::EyeTime StorageNode::getCreation () const { std::string createdStr = _pData->getJSONString(STORAGE_NODE_CREATE_TIME, "1970-01-01T00:00:00.000Z"); return EyeTime(createdStr.c_str()); } /* * Set the host for this node. */ void StorageNode::setHost (const std::string &host) { if (host == "") _pData->erase(STORAGE_NODE_HOST); else _pData->setJSONValue(STORAGE_NODE_HOST, host.c_str()); } /* * Get the host for this node. */ std::string StorageNode::getHost () const { return _pData->getJSONString(STORAGE_NODE_HOST); } /* * Set the mount. */ void StorageNode::setMount (const std::string &mount) { _pData->setJSONValue(STORAGE_NODE_MOUNT, mount.c_str()); } /* * Get the mount. */ std::string StorageNode::getMount () const { return _pData->getJSONString(STORAGE_NODE_MOUNT); } /* * Set the URN. */ void StorageNode::setURN (const std::string &mount) { _pData->setJSONValue(STORAGE_NODE_URN, mount.c_str()); } /* * Get the URN. */ std::string StorageNode::getURN () const { return _pData->getJSONString(STORAGE_NODE_URN); } /* * Set the source. */ void StorageNode::setSource (const std::string &source) { _pData->setJSONValue(STORAGE_NODE_SOURCE, source.c_str()); } /* * Get the source. */ std::string StorageNode::getSource () const { return _pData->getJSONString(STORAGE_NODE_SOURCE); } /* * Set the path. */ void StorageNode::setPath (const std::string &path) { _pData->setJSONValue(STORAGE_NODE_PATH, path.c_str()); } /* * Get the path. */ std::string StorageNode::getPath () const { return _pData->getJSONString(STORAGE_NODE_PATH); } /* * Set the folder. */ void StorageNode::setFolder (const std::string &folder) { _pData->setJSONValue(STORAGE_NODE_FOLDER, folder.c_str()); } /* * Get the folder. */ std::string StorageNode::getFolder () const { std::string result = _pData->getJSONString(STORAGE_NODE_FOLDER); //if not supplied in metadata derive folder from path + name //NOTE: This is a (hopefully) temporary work-around for backwards compatability // this routine could/should be removed when support for folder is solidified if (result.empty()) { //remove node name from end of path, case-insensitive result = getPath(); std::string workingPath = result; std::transform(workingPath.begin(), workingPath.end(), workingPath.begin(), ::tolower); std::string workingName = getName(); std::transform(workingName.begin(), workingName.end(), workingName.begin(), ::tolower); //find name at end of path std::string::size_type position = workingPath.rfind(workingName); if (position == std::string::npos) { result = ""; } else { result = result.substr(0, position); } } return result; } /* * Set the parents from a JSONArray. */ void StorageNode::setParents(const JSONArray &parents) { // Just copy the array into the node, verbaitim. if (!parents.empty()) _pData->setJSONValue(STORAGE_NODE_PARENTS, parents); } /* * Set the parent. * For some reason parents is an array with a single object in it. * The object contains an array of the grand parents. * This routine sets only the immediate parent URN */ void StorageNode::setParent (const std::string &parent) { JSONArray parents = _pData->getJSONArray(STORAGE_NODE_PARENTS); if (parents.getnumelements() > 0) { JSONObject& parentsJSON = static_cast(parents[0]); parentsJSON.setJSONValue(STORAGE_NODE_URN, parent.c_str()); } else { JSONObject newParent; newParent.setJSONValue(STORAGE_NODE_URN, parent.c_str()); JSONArray parentsArray; parentsArray.addElement(newParent); _pData->setJSONValue(STORAGE_NODE_PARENTS, parentsArray); } } /* * Get the parent. * For some reason parents is an array with a single object in it. * The object contains an array of the grand parents. * This routine returns only the immediate parent URN */ std::string StorageNode::getParent () const { std::string result; JSONArray parents = _pData->getJSONArray(STORAGE_NODE_PARENTS); if (parents.getnumelements() > 0) { const JSONObject& parentsJSON = static_cast(parents[0]); result = parentsJSON.getJSONString(STORAGE_NODE_URN); } return result; } /* * Set this node's status. */ void StorageNode::setStatus (StorageNodeStatus status) { _pData->setJSONValue(STORAGE_NODE_STATUS, StorageNodeStatusUtil::toString(status).c_str()); } void StorageNode::setStatus (const std::string &status) { _pData->setJSONValue(STORAGE_NODE_STATUS, status.c_str()); } /* * Get this node's status. */ StorageNodeStatus StorageNode::getStatus () const { return StorageNodeStatusUtil::valueOf(_pData->getJSONString(STORAGE_NODE_STATUS)); } /* * Set this node's type. */ void StorageNode::setType (StorageNodeType type) { _pData->setJSONValue(STORAGE_NODE_TYPE, StorageNodeTypeUtil::toString(type).c_str()); } void StorageNode::setType (const std::string &type) { _pData->setJSONValue(STORAGE_NODE_TYPE, type.c_str()); } /* * Get this node's type. */ StorageNodeType StorageNode::getType () const { return StorageNodeTypeUtil::valueOf(_pData->getJSONString(STORAGE_NODE_TYPE)); } /* * Set this node's meta type. */ void StorageNode::setMetaType (const std::string &metaType) { _pData->setJSONValue(STORAGE_NODE_META_TYPE, metaType.c_str()); } /* * Get this node's meta type. */ std::string StorageNode::getMetaType () const { return _pData->getJSONString(STORAGE_NODE_META_TYPE, MIME_TYPE_APP_UNKNOWN); } void StorageNode::setSignature(const std::string &sig) { _pData->setJSONValue(PERMISSION_KEY_SIGNATURE, sig.c_str()); } /* * Set this node's sync status. */ void StorageNode::setSync (bool sync) { _pData->setJSONValue(STORAGE_NODE_SYNC, sync); } /* * Get this node's sync status. */ bool StorageNode::getSync () const { return _pData->getJSONInt(STORAGE_NODE_SYNC, 1) != 0; } /* * Get this node's permissions. */ std::string StorageNode::getSignature() const { return _pData->getJSONString(PERMISSION_KEY_SIGNATURE); } /** Set/get the size of the node. */ void StorageNode::setSize(int nSize) { _pData->setJSONValue(STORAGE_NODE_SIZE, nSize); } int StorageNode::getSize() const { return _pData->getJSONInt(STORAGE_NODE_SIZE); } /** Set/get the absolute path of the node. */ void StorageNode::setAbsPath(const std::string &absPath) { _pData->setJSONValue(STORAGE_NODE_ABS_PATH, absPath.c_str()); } std::string StorageNode::getAbsPath() const { return _pData->getJSONString(STORAGE_NODE_ABS_PATH); } /** Set/get the description of the node. */ void StorageNode::setDescription(const std::string &desc) { _pData->setJSONValue(STORAGE_NODE_DESC, desc.c_str()); } std::string StorageNode::getDescription() const { return _pData->getJSONString(STORAGE_NODE_DESC); } /* * Set and get 'hash' for the node. */ void StorageNode::setHash(const std::string &hash) { _pData->setJSONValue(STORAGE_NODE_HASH, hash.c_str()); } std::string StorageNode::getHash() const { return _pData->getJSONString(STORAGE_NODE_HASH); } /** Set/get the view for the node. */ void StorageNode::setView(const std::string &view) { _pData->setJSONValue(STORAGE_NODE_VIEW, view.c_str()); } std::string StorageNode::getView() const { return _pData->getJSONString(STORAGE_NODE_VIEW); } /** Set/get the port for the node. */ void StorageNode::setPort(int nPort) { _pData->setJSONValue(STORAGE_NODE_PORT, nPort); } int StorageNode::getPort() const { return _pData->getJSONInt(STORAGE_NODE_PORT); } void StorageNode::setLocations(std::pair& p) { JSONArray locArray; std::shared_ptr p_loc = p.first.getAsJson(); std::shared_ptr p_remote_loc = p.second.getAsJson(); locArray.addElement(*p_loc); locArray.addElement( *p_remote_loc); _pData->erase(STORAGE_NODE_LOC); _pData->setJSONValue(STORAGE_NODE_LOC, locArray); } StorageLocation StorageNode::getLocation() const { JSONArray& locs_data = _pData->getJSONArray(STORAGE_NODE_LOC); for (int i = 0; i < locs_data.getnumelements(); ++i) { const JSONObject& loc_data = static_cast(locs_data[i]); StorageLocation loc(loc_data); if (loc.getType() == StorageLocation::LOCATE_TYPE::L1) { return loc; } } return (StorageLocation()); } StorageLocation StorageNode::getRemoteLocation() const { JSONArray& locs_data = _pData->getJSONArray(STORAGE_NODE_LOC); for (int i = 0; i < locs_data.getnumelements(); ++i) { const JSONObject& loc_data = static_cast(locs_data[i]); StorageLocation loc(loc_data); // TODO: A number of assumptions are in play here and need validation. // Nowhere do we force locations to be unique in the array. Also, this // assumes that the storage node has only two locations, 'here' and // 'there'. What about shared devices? if (loc.getType() != StorageLocation::LOCATE_TYPE::L1) { return loc; } } std::string bucket_id(""); return (StorageLocation(StorageLocation::LOCATE_TYPE::UNKNOWN, StorageLocation::LOCATE_KIND::UNKNOWN, bucket_id, StorageLocation::LOCATE_STATUS::FLUSHED)); } std::string StorageNode::toDebugString() const { std::string retVal; if (_pData->empty()) retVal = "NULL StorageNode object..."; else { std::stringstream retValStream; retValStream << getName() << ":\n"; retValStream << " path: '" << getPath() << "'\n type: " << StorageNodeTypeUtil::toString(getType()) << "\n mimeType: '" << getMimeType() << "'\n"; retValStream << " status: " << StorageNodeStatusUtil::toString(getStatus()) << "\n length: " << getLength() << "\n metaType: '" << getMetaType() << "'\n"; retValStream << " created: " << getCreation().GetISO8601TimeMs() << " modified: " << getLastModified().GetISO8601TimeMs() << " accessed: " << getLastAccessed().GetISO8601TimeMs(); retValStream << " host: '" << getHost() << "'\n mount: '" << getMount() << "'\n"; retValStream << "JSON string:\n" << _pData->toString() << "\n"; retVal = retValStream.str(); } return retVal; } std::string StorageNode::toString() const { return _pData->toString(); } StorageNodeVector StorageNode::getChildren() const { StorageNodeVector result; JSONArray children = _pData->getJSONArray(STORAGE_NODE_CHILDREN); for (int i = 0; i < children.getnumelements(); ++i) { const JSONObject & child = static_cast(children[i]); StorageNodePtr childPtr (new StorageNode(child)); result.push_back(childPtr); } return result; } void StorageNode::setChildren(const StorageNodeVector & children) { JSONArray childrenArray; for (StorageNodePtr child : children) { childrenArray.addElement(*(child->_pData)); } _pData->erase(STORAGE_NODE_CHILDREN); _pData->setJSONValue(STORAGE_NODE_CHILDREN, childrenArray); } void StorageNode::addChild(const StorageNode & child) { //create array if not present _pData->setJSONArray(STORAGE_NODE_CHILDREN); //add child to end of array JSONArray & childrenArray = _pData->getJSONArray(STORAGE_NODE_CHILDREN); childrenArray.addElement(*(child._pData)); } JSONObject StorageNode::getMetadata() const { return _pData->getJSONObject(STORAGE_NODE_META_DATA); } /** Set metadata associated with EyeFile pointed to by StorageNode @param metaData - metadata as string */ void StorageNode::setMetadata(const JSONObject & metadata) { _pData->setJSONValue(STORAGE_NODE_META_DATA, metadata); } /** * Merge this node with the node passed in. */ void StorageNode::mergeWith(const StorageNode &node) { _pData->mergeWith(*node._pData); } void StorageNode::mergeWith(const JSONObject &node) { _pData->mergeWith(node); } /** * Set/get permisisons. */ /* void StorageNode::setPermissions(const Permissions &perms) { JSONArray tmpPerms (perms.toString()); _pData->setJSONValue(PERMISSION_ROOT_KEY, tmpPerms); } PermissionsPtr StorageNode::getPermissions() const { if (_pData->search(PERMISSION_ROOT_KEY) != NULL) return PermissionsPtr(new Permissions(_pData->getJSONObject(PERMISSION_ROOT_KEY))); else return PermissionsPtr(NULL); } */ bool StorageNode::isRemoteFileOrDirectory (const StorageNode &obj) { StorageNodeType type = StorageNode::type(obj); return ( (isFile(obj) && (type != StorageNodeType::SNT_DEVICE_FILE)) || (type == StorageNodeType::SNT_MOUNT) || (type == StorageNodeType::SNT_REMOTE_DIRECTORY) || (type == StorageNodeType::SNT_PEER_DIRECTORY)); } /** Set/get the isDirectory bool for the node. */ void StorageNode::setIsDir(bool bIsDir) { _pData->setJSONValue(STORAGE_NODE_ISDIR, bIsDir); } bool StorageNode::getIsDir() const { return _pData->getJSONBool(STORAGE_NODE_ISDIR, false); } /** Is this node empty? @returns true if empty */ bool StorageNode::isEmpty() const { return ((_pData == NULL) || _pData->empty()); } /** Set/get the filename for the node. */ void StorageNode::setFilename(const std::string &filename) { _pData->setJSONValue(STORAGE_NODE_FILENAME, filename.c_str()); } std::string StorageNode::getFilename() const { return _pData->getJSONString(STORAGE_NODE_FILENAME); } namespace sequencelogic { std::ostream& operator<<(std::ostream &out, const StorageNode &node) { out << node.toDebugString(); return out; } }