diff --git a/libuavcan/include/uavcan/protocol/file_server.hpp b/libuavcan/include/uavcan/protocol/file_server.hpp index d525b70156..ba458cefad 100644 --- a/libuavcan/include/uavcan/protocol/file_server.hpp +++ b/libuavcan/include/uavcan/protocol/file_server.hpp @@ -20,6 +20,8 @@ namespace uavcan { /** * The file server backend should implement this interface. + * Note that error codes returned by these methods are defined in uavcan.protocol.file.Error; these are + * not the same as libuavcan-internal error codes defined in uavcan.error.hpp. */ class UAVCAN_EXPORT IFileServerBackend { @@ -136,6 +138,11 @@ class BasicFileServer resp.error.value = backend_.read(req.path.path, req.offset, resp.data.begin(), inout_size); + if (resp.error.value != protocol::file::Error::OK) + { + inout_size = 0; + } + if (inout_size > resp.data.capacity()) { UAVCAN_ASSERT(0); diff --git a/libuavcan_drivers/posix/include/uavcan_posix/basic_file_server_backend.hpp b/libuavcan_drivers/posix/include/uavcan_posix/basic_file_server_backend.hpp index c28e0cd381..c88bf8b731 100644 --- a/libuavcan_drivers/posix/include/uavcan_posix/basic_file_server_backend.hpp +++ b/libuavcan_drivers/posix/include/uavcan_posix/basic_file_server_backend.hpp @@ -36,8 +36,6 @@ class BasicFileSeverBackend : public uavcan::IFileServerBackend enum { FilePermissions = 438 }; ///< 0o666 - FirmwareCommon::BasePathString base_path; - public: /** * @@ -49,19 +47,13 @@ public: virtual int16_t getInfo(const Path& path, uint64_t& out_crc64, uint32_t& out_size, EntryType& out_type) { - enum { MaxBufferLength = 256 }; - int rv = uavcan::protocol::file::Error::INVALID_VALUE; - FirmwareCommon::PathString fw_full_path = FirmwareCommon::getFirmwareCachePath(FirmwareCommon::PathString( - base_path.c_str())); - - if (path.size() > 0 && (fw_full_path.size() + path.size()) <= FirmwareCommon::PathString::MaxSize) + if (path.size() > 0) { - fw_full_path += path; FirmwareCommon fw; - fw.getFileInfo(fw_full_path); + fw.getFileInfo(path.c_str()); out_crc64 = fw.descriptor.image_crc; out_size = fw.descriptor.image_size; // todo Using fixed flag FLAG_READABLE until we add file permission checks to return actual value. @@ -85,15 +77,11 @@ public: int rv = uavcan::protocol::file::Error::INVALID_VALUE; - FirmwareCommon::PathString fw_full_path = FirmwareCommon::getFirmwareCachePath(FirmwareCommon::PathString( - base_path.c_str())); - - if (path.size() > 0 && (fw_full_path.size() + path.size()) <= FirmwareCommon::PathString::MaxSize) + if (path.size() > 0) { - fw_full_path += path; - int fd = open(fw_full_path.c_str(), O_RDONLY); + int fd = open(path.c_str(), O_RDONLY); if (fd < 0) { @@ -128,18 +116,11 @@ public: return rv; } - /** - * Initializes the file server based back-end storage by passing a path to - * the directory where files will be stored. - */ - __attribute__((optimize("O0"))) - int init(const FirmwareCommon::BasePathString& path) - { - using namespace std; - base_path = path; - int rv = FirmwareCommon::create_fw_paths(base_path); - return rv; - } + BasicFileSeverBackend() { } + + + + }; } diff --git a/libuavcan_drivers/posix/include/uavcan_posix/dynamic_node_id_server/file_event_tracer.hpp b/libuavcan_drivers/posix/include/uavcan_posix/dynamic_node_id_server/file_event_tracer.hpp index 3398a54418..863d7465a1 100644 --- a/libuavcan_drivers/posix/include/uavcan_posix/dynamic_node_id_server/file_event_tracer.hpp +++ b/libuavcan_drivers/posix/include/uavcan_posix/dynamic_node_id_server/file_event_tracer.hpp @@ -38,6 +38,7 @@ class FileEventTracer : public uavcan::dynamic_node_id_server::IEventTracer PathString path_; +protected: virtual void onEvent(uavcan::dynamic_node_id_server::TraceCode code, uavcan::int64_t argument) { using namespace std; diff --git a/libuavcan_drivers/posix/include/uavcan_posix/dynamic_node_id_server/file_storage_backend.hpp b/libuavcan_drivers/posix/include/uavcan_posix/dynamic_node_id_server/file_storage_backend.hpp index fdf173cc13..a2834c6cfb 100644 --- a/libuavcan_drivers/posix/include/uavcan_posix/dynamic_node_id_server/file_storage_backend.hpp +++ b/libuavcan_drivers/posix/include/uavcan_posix/dynamic_node_id_server/file_storage_backend.hpp @@ -53,9 +53,9 @@ class FileStorageBackend : public uavcan::dynamic_node_id_server::IStorageBacken if (fd >= 0) { char buffer[MaxStringLength + 1]; - memset(buffer, 0, sizeof(buffer)); + (void)memset(buffer, 0, sizeof(buffer)); int len = read(fd, buffer, MaxStringLength); - close(fd); + (void)close(fd); if (len > 0) { for (int i = 0; i < len; i++) @@ -80,8 +80,9 @@ class FileStorageBackend : public uavcan::dynamic_node_id_server::IStorageBacken int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, FilePermissions); if (fd >= 0) { - write(fd, value.c_str(), value.size()); - close(fd); + (void)write(fd, value.c_str(), value.size()); + (void)fsync(fd); + (void)close(fd); } } diff --git a/libuavcan_drivers/posix/include/uavcan_posix/firmware_common.hpp b/libuavcan_drivers/posix/include/uavcan_posix/firmware_common.hpp index 6973b45f6c..33ebba88b8 100644 --- a/libuavcan_drivers/posix/include/uavcan_posix/firmware_common.hpp +++ b/libuavcan_drivers/posix/include/uavcan_posix/firmware_common.hpp @@ -17,43 +17,17 @@ #include #include +#include "firmware_path.hpp" namespace uavcan_posix { /** - * Firmware version checking logic. - * Refer to @ref FirmwareUpdateTrigger for details. + * Firmware file validation logic. */ class FirmwareCommon { - /* The folder where the files will be copied and Read from */ - - static const char* get_cache_dir_() - { - return "c"; - } - public: - enum { MaxBasePathLength = 128 }; - - /** - * This type is used for the base path - */ - typedef uavcan::MakeString::Type BasePathString; - - /** - * Maximum length of full path including / the file name - */ - enum { MaxPathLength = uavcan::protocol::file::Path::FieldTypes::path::MaxSize + MaxBasePathLength }; - - /** - * This type is used internally for the full path to file - */ - typedef uavcan::MakeString::Type PathString; - - static char getPathSeparator() { return static_cast(uavcan::protocol::file::Path::SEPARATOR); } - typedef struct app_descriptor_t { uint8_t signature[sizeof(uint64_t)]; @@ -67,51 +41,12 @@ public: app_descriptor_t descriptor; - /** - * This method Is used to get the app_descriptor_t from a firmware image - * - * @param path Complete path to the file - * - * @param add_separator Complete path with trailing separator - * - * - * @return 0 if the app_descriptor_t was found and out_descriptor - * has been updated. - * Otherwise -errno is returned - * -ENOENT Signature was not found. - */ - - static PathString getFirmwareCachePath(const PathString& p, bool add_separator = true) - { - PathString r; - r = p; - r.push_back(getPathSeparator()); - r += get_cache_dir_(); - if (add_separator) { - r.push_back(getPathSeparator()); - } - return r; - } - - - static BasePathString getFirmwareCachePath(const BasePathString& p, bool add_separator = true) - { - BasePathString r; - r = p; - r.push_back(getPathSeparator()); - r += get_cache_dir_(); - if (add_separator) { - r.push_back(getPathSeparator()); - } - return r; - } - - int getFileInfo(PathString& path) + int getFileInfo(const char *path) { enum { MaxChunk = (512 / sizeof(uint64_t)) }; int rv = -ENOENT; uint64_t chunk[MaxChunk]; - int fd = open(path.c_str(), O_RDONLY); + int fd = open(path, O_RDONLY); if (fd >= 0) { @@ -153,50 +88,6 @@ public: } - /** - * Creates the Directories were the files will be stored - */ - - static int create_fw_paths(FirmwareCommon::BasePathString& path) - { - using namespace std; - - int rv = -uavcan::ErrInvalidParam; - - if (path.size() > 0) - { - if (path.back() == FirmwareCommon::getPathSeparator()) - { - path.pop_back(); - } - - rv = 0; - struct stat sb; - if (stat(path.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) - { - rv = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IRWXO); - } - - PathString cache = getFirmwareCachePath(PathString(path.c_str()), false); - if (rv >= 0 && (stat(cache.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode))) - { - rv = mkdir(cache.c_str(), S_IRWXU | S_IRWXG | S_IRWXO); - } - - if (rv >= 0 ) - { - path.push_back(FirmwareCommon::getPathSeparator()); - if ((path.size() + uavcan::protocol::file::Path::FieldTypes::path::MaxSize) > - FirmwareCommon::MaxPathLength) - { - rv = -uavcan::ErrInvalidConfiguration; - } - } - } - return rv; - } - - private: #define APP_DESCRIPTOR_SIGNATURE_ID 'A', 'P', 'D', 'e', 's', 'c' diff --git a/libuavcan_drivers/posix/include/uavcan_posix/firmware_path.hpp b/libuavcan_drivers/posix/include/uavcan_posix/firmware_path.hpp new file mode 100644 index 0000000000..31bb0baab4 --- /dev/null +++ b/libuavcan_drivers/posix/include/uavcan_posix/firmware_path.hpp @@ -0,0 +1,171 @@ +/**************************************************************************** +* +* Copyright (c) 2015 PX4 Development Team. All rights reserved. +* Author: Pavel Kirienko +* David Sidrane +* +****************************************************************************/ + +#ifndef UAVCAN_POSIX_FIRMWARE_PATH_HPP_INCLUDED +#define UAVCAN_POSIX_FIRMWARE_PATH_HPP_INCLUDED + +#include + +#include + +namespace uavcan_posix +{ +/** + * Firmware Path Management. + */ +class FirmwarePath +{ + /* The folder where the files will be copied and Read from */ + + static const char* get_cache_dir_() + { + return "c"; + } + +public: + + enum { MaxBasePathLength = 128 }; + + /** + * This type is used for the base path + */ + typedef uavcan::MakeString::Type BasePathString; + + /** + * Maximum length of full path including / the file name + */ + enum { MaxPathLength = uavcan::protocol::file::Path::FieldTypes::path::MaxSize + MaxBasePathLength }; + + BasePathString base_path_; + BasePathString cache_path_; + + /** + * This type is used internally for the full path to file + */ + typedef uavcan::MakeString::Type PathString; + + static char getPathSeparator() { return static_cast(uavcan::protocol::file::Path::SEPARATOR); } + + + BasePathString& getFirmwareBasePath() + { + return base_path_; + } + + void setFirmwareBasePath(const char * path) + { + base_path_ = path; + } + + BasePathString& getFirmwareCachePath() + { + return cache_path_; + } + + void setFirmwareCachePath(const char *path) + { + cache_path_ = path; + + } + + + static void addSlash(BasePathString& path) + { + + if (path.back() != getPathSeparator()) + { + path.push_back(getPathSeparator()); + } + } + + static void removeSlash(BasePathString& path) + { + + if (path.back() == getPathSeparator()) + { + path.pop_back(); + } + + } + + /** + * Creates the Directories were the files will be stored + */ + + /* This is directory structure is in support of a workaround + * for the issues that FirmwareFilePath is 40 + * + * It creates a path structure: + * + * + * +---(base_path) + * +-c <----------- Files are cashed here. + */ + + int CreateFwPaths(const char *base_path) + { + using namespace std; + int rv = -uavcan::ErrInvalidParam; + + if (base_path) + { + + int len = strlen(base_path); + + if (len > 0 && len < base_path_.MaxSize) + { + + setFirmwareBasePath(base_path); + removeSlash(getFirmwareBasePath()); + const char *path = getFirmwareBasePath().c_str(); + + setFirmwareCachePath(path); + addSlash(cache_path_); + cache_path_ += get_cache_dir_(); + + rv = 0; + struct stat sb; + if (stat(path, &sb) != 0 || !S_ISDIR(sb.st_mode)) + { + rv = mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO); + } + + path = getFirmwareCachePath().c_str(); + + if (rv == 0 && (stat(path, &sb) != 0 || !S_ISDIR(sb.st_mode))) + { + rv = mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO); + } + + addSlash(getFirmwareBasePath()); + addSlash(getFirmwareCachePath()); + + + if (rv >= 0 ) + { + if ((getFirmwareCachePath().size() + uavcan::protocol::file::Path::FieldTypes::path::MaxSize) > + MaxPathLength) + { + rv = -uavcan::ErrInvalidConfiguration; + } + } + } + } + return rv; + } + + int init(const char *path) + { + return CreateFwPaths(path); + } + +}; + +} + +#endif // Include guard diff --git a/libuavcan_drivers/posix/include/uavcan_posix/firmware_version_checker.hpp b/libuavcan_drivers/posix/include/uavcan_posix/firmware_version_checker.hpp index 69c71c3a39..3066c07a18 100644 --- a/libuavcan_drivers/posix/include/uavcan_posix/firmware_version_checker.hpp +++ b/libuavcan_drivers/posix/include/uavcan_posix/firmware_version_checker.hpp @@ -18,6 +18,7 @@ #include #include + #include "firmware_common.hpp" namespace uavcan_posix @@ -30,8 +31,7 @@ class FirmwareVersionChecker : public uavcan::IFirmwareVersionChecker { enum { FilePermissions = 438 }; ///< 0o666 - FirmwareCommon::BasePathString base_path; - FirmwareCommon::BasePathString cache_path; + FirmwarePath *paths_; public: @@ -56,7 +56,7 @@ public: { /* This is a work around for two issues. * 1) FirmwareFilePath is 40 - * 2) Nuttx is using 32 for max file names. + * 2) OK using is using 32 for max file names. * * So for the file: * org.pixhawk.px4cannode-v1-0.1.59efc137.uavcan.bin @@ -72,17 +72,21 @@ public: bool rv = false; - char fname_root[FirmwareCommon::MaxBasePathLength + 1]; + char fname_root[FirmwarePath::MaxBasePathLength + 1]; int n = snprintf(fname_root, sizeof(fname_root), "%s%s/%d.%d", - base_path.c_str(), + paths_->getFirmwareBasePath().c_str(), node_info.name.c_str(), node_info.hardware_version.major, node_info.hardware_version.minor); - if (n > 0) + if (n > 0 && n < (int) sizeof(fname_root) - 2) { + FAR DIR *fwdir = opendir(fname_root); + fname_root[n++] = FirmwarePath::getPathSeparator(); + fname_root[n++] = '\0'; + if (fwdir) { FAR struct dirent *pfile; @@ -93,11 +97,10 @@ public: // Open any bin file in there. if (strstr(pfile->d_name, ".bin")) { - FirmwareCommon::PathString full_src_path = fname_root; - full_src_path.push_back(FirmwareCommon::getPathSeparator()); + FirmwarePath::PathString full_src_path = fname_root; full_src_path += pfile->d_name; - FirmwareCommon::PathString full_dst_path = cache_path.c_str(); + FirmwarePath::PathString full_dst_path = paths_->getFirmwareCachePath().c_str(); full_dst_path += pfile->d_name; /* ease the burden on the user */ @@ -107,9 +110,10 @@ public: FirmwareCommon fw; - if (cr == 0 && fw.getFileInfo(full_dst_path) == 0) + if (cr == 0 && fw.getFileInfo(full_dst_path.c_str()) == 0) { - if ((node_info.software_version.major == 0 && + if (node_info.software_version.image_crc == 0 || + (node_info.software_version.major == 0 && node_info.software_version.minor == 0) || fw.descriptor.image_crc != node_info.software_version.image_crc) @@ -173,26 +177,25 @@ public: (void)response; } - FirmwareVersionChecker() { } + FirmwareVersionChecker() : + paths_(0) + { } virtual ~FirmwareVersionChecker() { } /** - * Initializes the file server based back-end storage by passing a path to - * the directory where files will be stored. + * Initializes the Firmware File back-end storage by passing a paths object + * that maintains the directory where files will be stored. */ - __attribute__((optimize("O0"))) - int init(const char * path) + + int init(FirmwarePath& paths) { - base_path = path; - cache_path = FirmwareCommon::getFirmwareCachePath(base_path); - if (base_path.back() != FirmwareCommon::getPathSeparator()) - { - base_path.push_back(FirmwareCommon::getPathSeparator()); - } + paths_ = &paths; return 0; } + const char * getFirmwarePath() { return paths_->getFirmwareCachePath().c_str(); } + private: