Implement buildFileTable interface
The buildFileTable interface will be used by the ReadFileIntoMemory
and WriteFileFromMemory commands to get the file table and map the
file handle to the file path.
Change-Id: Ibdc01737d8925ef918c4fbe2919108d96a2807ab
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/configure.ac b/configure.ac
index 53d9228..ae5fcba 100644
--- a/configure.ac
+++ b/configure.ac
@@ -44,6 +44,8 @@
AC_SUBST([OESDK_TESTCASE_FLAGS], [$testcase_flags])
)
+AC_DEFINE(FILE_TABLE_JSON, "/var/lib/pldm/fileTable.json", [JSON file containing file info for File I/O])
+
# Create configured output
AC_CONFIG_FILES([Makefile libpldm/Makefile libpldmresponder/Makefile test/Makefile])
AC_OUTPUT
diff --git a/libpldmresponder/file_io.cpp b/libpldmresponder/file_io.cpp
index 9cf093c..50c3f1d 100644
--- a/libpldmresponder/file_io.cpp
+++ b/libpldmresponder/file_io.cpp
@@ -1,5 +1,9 @@
+#include "config.h"
+
#include "file_io.hpp"
+#include "file_table.hpp"
+
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
@@ -132,7 +136,6 @@
uint32_t offset = 0;
uint32_t length = 0;
uint64_t address = 0;
- fs::path path("");
Response response((sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES), 0);
auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
@@ -147,7 +150,24 @@
decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
&length, &address);
- if (!fs::exists(path))
+ using namespace pldm::filetable;
+ auto& table = buildFileTable(FILE_TABLE_JSON);
+ FileEntry value{};
+
+ try
+ {
+ value = table.at(fileHandle);
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>("File handle does not exist in the file table",
+ entry("HANDLE=%d", fileHandle));
+ encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
+ PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
+ return response;
+ }
+
+ if (!fs::exists(value.fsPath))
{
log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
@@ -155,7 +175,7 @@
return response;
}
- auto fileSize = fs::file_size(path);
+ auto fileSize = fs::file_size(value.fsPath);
if (offset >= fileSize)
{
log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
@@ -181,8 +201,8 @@
using namespace dma;
DMA intf;
- return transferAll<DMA>(&intf, PLDM_READ_FILE_INTO_MEMORY, path, offset,
- length, address, true);
+ return transferAll<DMA>(&intf, PLDM_READ_FILE_INTO_MEMORY, value.fsPath,
+ offset, length, address, true);
}
Response writeFileFromMemory(const uint8_t* request, size_t payloadLength)
@@ -191,7 +211,6 @@
uint32_t offset = 0;
uint32_t length = 0;
uint64_t address = 0;
- fs::path path("");
Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
@@ -215,7 +234,24 @@
return response;
}
- if (!fs::exists(path))
+ using namespace pldm::filetable;
+ auto& table = buildFileTable(FILE_TABLE_JSON);
+ FileEntry value{};
+
+ try
+ {
+ value = table.at(fileHandle);
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>("File handle does not exist in the file table",
+ entry("HANDLE=%d", fileHandle));
+ encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
+ PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
+ return response;
+ }
+
+ if (!fs::exists(value.fsPath))
{
log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
@@ -223,7 +259,7 @@
return response;
}
- auto fileSize = fs::file_size(path);
+ auto fileSize = fs::file_size(value.fsPath);
if (offset >= fileSize)
{
log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
@@ -235,8 +271,8 @@
using namespace dma;
DMA intf;
- return transferAll<DMA>(&intf, PLDM_WRITE_FILE_FROM_MEMORY, path, offset,
- length, address, false);
+ return transferAll<DMA>(&intf, PLDM_WRITE_FILE_FROM_MEMORY, value.fsPath,
+ offset, length, address, false);
}
} // namespace responder
diff --git a/libpldmresponder/file_table.cpp b/libpldmresponder/file_table.cpp
index 85f417c..9264f21 100644
--- a/libpldmresponder/file_table.cpp
+++ b/libpldmresponder/file_table.cpp
@@ -115,5 +115,15 @@
return table;
}
+FileTable& buildFileTable(const std::string& fileTablePath)
+{
+ static FileTable table;
+ if (table.isEmpty())
+ {
+ table = std::move(FileTable(fileTablePath));
+ }
+ return table;
+}
+
} // namespace filetable
} // namespace pldm
diff --git a/libpldmresponder/file_table.hpp b/libpldmresponder/file_table.hpp
index 385f57b..4b82f29 100644
--- a/libpldmresponder/file_table.hpp
+++ b/libpldmresponder/file_table.hpp
@@ -111,5 +111,15 @@
uint32_t checkSum = 0;
};
+/** @brief Build the file attribute table if not already built using the
+ * file table config.
+ *
+ * @param[in] fileTablePath - path of the file table config
+ *
+ * @return FileTable& - Reference to instance of file table
+ */
+
+FileTable& buildFileTable(const std::string& fileTablePath);
+
} // namespace filetable
} // namespace pldm
diff --git a/test/libpldmresponder_fileio_test.cpp b/test/libpldmresponder_fileio_test.cpp
index 424e09c..2c5f90e 100644
--- a/test/libpldmresponder_fileio_test.cpp
+++ b/test/libpldmresponder_fileio_test.cpp
@@ -233,6 +233,118 @@
ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
}
+TEST_F(TestFileTable, ReadFileInvalidFileHandle)
+{
+ // Invalid file handle in the file table
+ uint32_t fileHandle = 2;
+ uint32_t offset = 0;
+ uint32_t length = 0;
+ uint64_t address = 0;
+
+ std::array<uint8_t, PLDM_RW_FILE_MEM_REQ_BYTES> requestMsg{};
+ memcpy(requestMsg.data(), &fileHandle, sizeof(fileHandle));
+ memcpy(requestMsg.data() + sizeof(fileHandle), &offset, sizeof(offset));
+ memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset), &length,
+ sizeof(length));
+ memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset) +
+ sizeof(length),
+ &address, sizeof(address));
+
+ using namespace pldm::filetable;
+ // Initialise the file table with 2 valid file handles 0 & 1.
+ auto& table = buildFileTable(fileTableConfig.c_str());
+
+ auto response = readFileIntoMemory(requestMsg.data(), requestMsg.size());
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE);
+ // Clear the file table contents.
+ table.clear();
+}
+
+TEST_F(TestFileTable, ReadFileInvalidOffset)
+{
+ uint32_t fileHandle = 0;
+ // The file size is 1024, so the offset is invalid
+ uint32_t offset = 1024;
+ uint32_t length = 0;
+ uint64_t address = 0;
+
+ std::array<uint8_t, PLDM_RW_FILE_MEM_REQ_BYTES> requestMsg{};
+ memcpy(requestMsg.data(), &fileHandle, sizeof(fileHandle));
+ memcpy(requestMsg.data() + sizeof(fileHandle), &offset, sizeof(offset));
+ memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset), &length,
+ sizeof(length));
+ memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset) +
+ sizeof(length),
+ &address, sizeof(address));
+
+ using namespace pldm::filetable;
+ auto& table = buildFileTable(fileTableConfig.c_str());
+
+ auto response = readFileIntoMemory(requestMsg.data(), requestMsg.size());
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE);
+ // Clear the file table contents.
+ table.clear();
+}
+
+TEST_F(TestFileTable, ReadFileInvalidLength)
+{
+ uint32_t fileHandle = 0;
+ uint32_t offset = 100;
+ // Length should be a multiple of dma min size(16)
+ uint32_t length = 10;
+ uint64_t address = 0;
+
+ std::array<uint8_t, PLDM_RW_FILE_MEM_REQ_BYTES> requestMsg{};
+ memcpy(requestMsg.data(), &fileHandle, sizeof(fileHandle));
+ memcpy(requestMsg.data() + sizeof(fileHandle), &offset, sizeof(offset));
+ memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset), &length,
+ sizeof(length));
+ memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset) +
+ sizeof(length),
+ &address, sizeof(address));
+
+ using namespace pldm::filetable;
+ auto& table = buildFileTable(fileTableConfig.c_str());
+
+ auto response = readFileIntoMemory(requestMsg.data(), requestMsg.size());
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_READ_LENGTH);
+ // Clear the file table contents.
+ table.clear();
+}
+
+TEST_F(TestFileTable, ReadFileInvalidEffectiveLength)
+{
+ uint32_t fileHandle = 0;
+ // valid offset
+ uint32_t offset = 100;
+ // length + offset exceeds the size, so effective length is
+ // filesize(1024) - offset(100). The effective length is not a multiple of
+ // DMA min size(16)
+ uint32_t length = 1024;
+ uint64_t address = 0;
+
+ std::array<uint8_t, PLDM_RW_FILE_MEM_REQ_BYTES> requestMsg{};
+ memcpy(requestMsg.data(), &fileHandle, sizeof(fileHandle));
+ memcpy(requestMsg.data() + sizeof(fileHandle), &offset, sizeof(offset));
+ memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset), &length,
+ sizeof(length));
+ memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset) +
+ sizeof(length),
+ &address, sizeof(address));
+
+ using namespace pldm::filetable;
+ auto& table = buildFileTable(fileTableConfig.c_str());
+
+ auto response = readFileIntoMemory(requestMsg.data(), requestMsg.size());
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_READ_LENGTH);
+ // Clear the file table contents.
+ table.clear();
+}
+
TEST(WriteFileFromMemory, BadPath)
{
uint32_t fileHandle = 0;
@@ -260,6 +372,62 @@
ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_WRITE_LENGTH);
}
+TEST_F(TestFileTable, WriteFileInvalidFileHandle)
+{
+ // Invalid file handle in the file table
+ uint32_t fileHandle = 2;
+ uint32_t offset = 0;
+ uint32_t length = 16;
+ uint64_t address = 0;
+
+ std::array<uint8_t, PLDM_RW_FILE_MEM_REQ_BYTES> requestMsg{};
+ memcpy(requestMsg.data(), &fileHandle, sizeof(fileHandle));
+ memcpy(requestMsg.data() + sizeof(fileHandle), &offset, sizeof(offset));
+ memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset), &length,
+ sizeof(length));
+ memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset) +
+ sizeof(length),
+ &address, sizeof(address));
+
+ using namespace pldm::filetable;
+ // Initialise the file table with 2 valid file handles 0 & 1.
+ auto& table = buildFileTable(fileTableConfig.c_str());
+
+ auto response = writeFileFromMemory(requestMsg.data(), requestMsg.size());
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE);
+ // Clear the file table contents.
+ table.clear();
+}
+
+TEST_F(TestFileTable, WriteFileInvalidOffset)
+{
+ uint32_t fileHandle = 0;
+ // The file size is 1024, so the offset is invalid
+ uint32_t offset = 1024;
+ uint32_t length = 16;
+ uint64_t address = 0;
+
+ std::array<uint8_t, PLDM_RW_FILE_MEM_REQ_BYTES> requestMsg{};
+ memcpy(requestMsg.data(), &fileHandle, sizeof(fileHandle));
+ memcpy(requestMsg.data() + sizeof(fileHandle), &offset, sizeof(offset));
+ memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset), &length,
+ sizeof(length));
+ memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset) +
+ sizeof(length),
+ &address, sizeof(address));
+
+ using namespace pldm::filetable;
+ // Initialise the file table with 2 valid file handles 0 & 1.
+ auto& table = buildFileTable(TestFileTable::fileTableConfig.c_str());
+
+ auto response = writeFileFromMemory(requestMsg.data(), requestMsg.size());
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE);
+ // Clear the file table contents.
+ table.clear();
+}
+
TEST(FileTable, ConfigNotExist)
{
logs.clear();