Руслан Урядинский / libuavcan

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers file_storage_backend.hpp Source File

file_storage_backend.hpp

00001 /****************************************************************************
00002 *
00003 *   Copyright (c) 2015 PX4 Development Team. All rights reserved.
00004 *      Author: Pavel Kirienko <pavel.kirienko@gmail.com>
00005 *              David Sidrane <david_s5@usa.net>
00006 *
00007 ****************************************************************************/
00008 
00009 #ifndef UAVCAN_POSIX_DYNAMIC_NODE_ID_SERVER_FILE_STORAGE_BACKEND_HPP_INCLUDED
00010 #define UAVCAN_POSIX_DYNAMIC_NODE_ID_SERVER_FILE_STORAGE_BACKEND_HPP_INCLUDED
00011 
00012 #include <sys/stat.h>
00013 #include <cstdio>
00014 #include <cstddef>
00015 #include <cstdlib>
00016 #include <cstring>
00017 #include <cerrno>
00018 #include <unistd.h>
00019 #include <fcntl.h>
00020 
00021 #include <uavcan/protocol/dynamic_node_id_server/storage_backend.hpp>
00022 
00023 namespace uavcan_posix
00024 {
00025 namespace dynamic_node_id_server
00026 {
00027 /**
00028  * This interface implements a POSIX compliant IStorageBackend interface
00029  */
00030 class FileStorageBackend : public uavcan::dynamic_node_id_server::IStorageBackend
00031 {
00032     /**
00033      * Maximum length of full path including / and key max
00034      */
00035     enum { MaxPathLength = 128 };
00036 
00037     enum { FilePermissions = 438 };     ///< 0o666
00038 
00039     /**
00040      * This type is used for the path
00041      */
00042     typedef uavcan::MakeString<MaxPathLength>::Type PathString;
00043 
00044     PathString base_path;
00045 
00046 protected:
00047     virtual String get(const String& key) const
00048     {
00049         using namespace std;
00050         PathString path = base_path.c_str();
00051         path += key;
00052         String value;
00053         int fd = open(path.c_str(), O_RDONLY);
00054         if (fd >= 0)
00055         {
00056             char buffer[MaxStringLength + 1];
00057             (void)memset(buffer, 0, sizeof(buffer));
00058             ssize_t remaining = MaxStringLength;
00059             ssize_t total_read = 0;
00060             ssize_t nread = 0;
00061             do
00062             {
00063                 nread = ::read(fd, &buffer[total_read], remaining);
00064                 if (nread > 0)
00065                 {
00066                     remaining -= nread,
00067                     total_read += nread;
00068                 }
00069             }
00070             while (nread > 0 && remaining > 0);
00071             (void)close(fd);
00072             if (total_read > 0)
00073             {
00074                 for (int i = 0; i < total_read; i++)
00075                 {
00076                     if (buffer[i] == ' ' || buffer[i] == '\n' || buffer[i] == '\r')
00077                     {
00078                         buffer[i] = '\0';
00079                         break;
00080                     }
00081                 }
00082                 value = buffer;
00083             }
00084         }
00085         return value;
00086     }
00087 
00088     virtual void set(const String& key, const String& value)
00089     {
00090         using namespace std;
00091         PathString path = base_path.c_str();
00092         path += key;
00093         int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, FilePermissions);
00094         if (fd >= 0)
00095         {
00096             ssize_t remaining = value.size();
00097             ssize_t total_written = 0;
00098             ssize_t written = 0;
00099             do
00100             {
00101                 written = write(fd, &value.c_str()[total_written], remaining);
00102                 if (written > 0)
00103                 {
00104                     total_written += written;
00105                     remaining -=  written;
00106                 }
00107             }
00108             while (written > 0 && remaining > 0);
00109 
00110             (void)fsync(fd);
00111             (void)close(fd);
00112         }
00113     }
00114 
00115 public:
00116     /**
00117      * Initializes the file based backend storage by passing a path to
00118      * the directory where the key named files will be stored.
00119      * The return value should be 0 on success.
00120      * If it is -ErrInvalidConfiguration then the the path name is too long to
00121      * accommodate the trailing slash and max key length.
00122      */
00123     int init(const PathString& path)
00124     {
00125         using namespace std;
00126 
00127         int rv = -uavcan::ErrInvalidParam;
00128 
00129         if (path.size() > 0)
00130         {
00131             base_path = path.c_str();
00132 
00133             if (base_path.back() == '/')
00134             {
00135                 base_path.pop_back();
00136             }
00137 
00138             rv = 0;
00139             struct stat sb;
00140             if (stat(base_path.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode))
00141             {
00142                 // coverity[toctou]
00143                 rv = mkdir(base_path.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
00144             }
00145             if (rv >= 0)
00146             {
00147                 base_path.push_back('/');
00148                 if ((base_path.size() + MaxStringLength) > MaxPathLength)
00149                 {
00150                     rv = -uavcan::ErrInvalidConfiguration;
00151                 }
00152             }
00153         }
00154         return rv;
00155     }
00156 };
00157 }
00158 }
00159 
00160 #endif // Include guard