Skip to content

Commit

Permalink
msi_dir_list: check if physical path is inside resource vault
Browse files Browse the repository at this point in the history
  • Loading branch information
lwesterhof committed May 3, 2024
1 parent 8f76339 commit 4849a9a
Showing 1 changed file with 175 additions and 62 deletions.
237 changes: 175 additions & 62 deletions src/msi_dir_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
*/

#include "irods_includes.hh"
#include "irods_ms_plugin.hpp"
#include "irods/rcMisc.h"
#include "irods/resource_administration.hpp"
#include "rsFileStat.hpp"
#include "rsGenQuery.hpp"

#include <boost/filesystem.hpp>
#include <boost/range/iterator_range.hpp>
Expand All @@ -33,14 +38,94 @@
namespace fs = boost::filesystem;
namespace pt = boost::property_tree;

int msiDirList(msParam_t* _path, msParam_t* _list, ruleExecInfo_t* _rei)
/** Internal function to get an attribute of a resource, based on its name. */
static int get_resource_attribute_by_name(rsComm_t* rsComm,
char* resource_name,
char* resource_value_out,
int column_number)
{
genQueryInp_t genQueryInp;
genQueryOut_t* genQueryOut = NULL;
sqlResult_t* resource_data;
char equalsResourceName[MAX_NAME_LEN + 1];
memset(&genQueryInp, '\0', sizeof(genQueryInp_t));
memset(&equalsResourceName, '\0', MAX_NAME_LEN + 1);

snprintf(equalsResourceName, MAX_NAME_LEN + 1, "='%s'", resource_name);
addInxVal(&genQueryInp.sqlCondInp, COL_R_RESC_NAME, equalsResourceName);
addInxIval(&genQueryInp.selectInp, column_number, 1);

genQueryInp.maxRows = 1;
genQueryOut = NULL;
int status = rsGenQuery(rsComm, &genQueryInp, &genQueryOut);

int out_status = 0;

if (status >= 0) {
if (genQueryOut->rowCnt != 1) {
out_status = CAT_UNKNOWN_RESOURCE;
}
else {
if ((resource_data = getSqlResultByInx(genQueryOut, column_number)) == NULL) {
rodsLog(LOG_ERROR,
"msi_file_checksum: getSqlResultByInx for column %d failed on lookup of %s",
column_number,
resource_name);
out_status = UNMATCHED_KEY_OR_INDEX;
}
else {
strncpy(resource_value_out, resource_data->value, MAX_NAME_LEN + 1);
out_status = 0;
}
}
}
else {
out_status = status;
}

clearGenQueryInp(&genQueryInp);
freeGenQueryOut(&genQueryOut);

return out_status;
}

/** This function converts a resource name to a resource ID.
* The resource ID is written as char array to resource_id_out.
*/
static int get_resource_id(rsComm_t* rsComm, char* resource_name, char* resource_id_out)
{
return get_resource_attribute_by_name(rsComm, resource_name, resource_id_out, COL_R_RESC_ID);
}

/** This function retrieves the vault path of a resource based on its name
* to resource_id_out.
*/
static int get_resource_vault_path(rsComm_t* rsComm, char* resource_name, char* resource_vault_path_out)
{
return get_resource_attribute_by_name(rsComm, resource_name, resource_vault_path_out, COL_R_VAULT_PATH);
}

/** This function retrieves the location of a resource based on its name
* to resource_loc_out.
*/
static int get_resource_loc(rsComm_t* rsComm, char* resource_name, char* resource_loc_out)
{
return get_resource_attribute_by_name(rsComm, resource_name, resource_loc_out, COL_R_LOC);
}

int msiDirList(msParam_t* _path, msParam_t* _rescName, msParam_t* _list, ruleExecInfo_t* _rei)
{
// Convert parameter values to C strings.
char* path_str = parseMspForStr(_path);
if (!path_str) {
return SYS_INVALID_INPUT_PARAM;
}

char* rescName = parseMspForStr(_rescName);
if (!rescName) {
return SYS_INVALID_INPUT_PARAM;
}

char* list_str = parseMspForStr(_list);
if (!list_str) {
return SYS_INVALID_INPUT_PARAM;
Expand All @@ -51,74 +136,102 @@ int msiDirList(msParam_t* _path, msParam_t* _list, ruleExecInfo_t* _rei)
return SYS_USER_NO_PERMISSION;
}

fs::path path_bp(path_str);
// Look up resource ID of resource.
char resource_id_str[MAX_NAME_LEN];
memset(&resource_id_str, '\0', MAX_NAME_LEN);
int status_resource_id = get_resource_id(_rei->rsComm, rescName, resource_id_str);

// Return error if resource does not exist
if (status_resource_id == CAT_NO_ROWS_FOUND) {
rodsLog(LOG_ERROR, "msi_dir_list: could not find resource [%s]", rescName);
return CAT_UNKNOWN_RESOURCE;
}
else if (status_resource_id < 0) {
rodsLog(LOG_ERROR,
"msi_dir_list: error while looking up resource ID of resource [%s]: %d",
rescName,
status_resource_id);
return status_resource_id;
}

fs::path physical_path_bp(path_str);
// Check that physical path exists.
if (!fs::exists(physical_path_bp)) {
rodsLog(LOG_ERROR, "msi_dir_list: physical path <%s> does not exist", path_str);
return SYS_INVALID_FILE_PATH;
}

// Check that physical path is a directory.
if (!fs::is_directory(physical_path_bp)) {
rodsLog(LOG_ERROR, "msi_dir_list: physical path <%s> is not a directory", path_str);
return SYS_INVALID_FILE_PATH;
}

// Check that canonical physical path is in resource vault path. Return error if not.
fs::path normalized_physical_path_bp = physical_path_bp.lexically_normal();
const char* normalized_physical_path_str = normalized_physical_path_bp.c_str();
if (strncmp(normalized_physical_path_str, resource_vault_path, strlen(resource_vault_path)) ||
normalized_physical_path_str[strlen(resource_vault_path)] != '/')
{
rodsLog(
LOG_ERROR, "msi_dir_list: physical path is not inside resource vault for %s", normalized_physical_path_str);
return SYS_INVALID_FILE_PATH;
}

try {
// Does path exist?
if (fs::exists(path_bp)) {
// Is path a directory?
if (fs::is_directory(path_bp)) {
pt::ptree jsonResult;
fs::directory_iterator endIter;

// Iterate through directory.
for (fs::directory_iterator iter(path_bp); iter != endIter; ++iter) {
const fs::directory_entry entry = *iter;
pt::ptree entryJson;

entryJson.put("name", entry.path().filename().string());

if (fs::is_regular_file(entry.status())) {
entryJson.put("type", "file");
}
else if (fs::is_directory(entry.status())) {
entryJson.put("type", "directory");
}
else if (fs::is_symlink(entry.symlink_status())) {
entryJson.put("type", "symlink");
}

if (fs::is_regular_file(entry.status())) {
entryJson.put("filesize", fs::file_size(entry.path()));
}

if (fs::is_directory(entry.status())) {
int numEntries = std::distance(fs::directory_iterator(entry.path()), fs::directory_iterator{});
entryJson.put("subdirectory_entries", numEntries);
}

std::time_t modifiedTime = fs::last_write_time(entry.path());
char* localModifiedTime = std::asctime(std::localtime(&modifiedTime));

// Remove trailing newline.
localModifiedTime[strcspn(localModifiedTime, "\n")] = '\0';
std::string modifiedTimestamp(localModifiedTime);

entryJson.put("modified_timestamp", modifiedTimestamp);
jsonResult.push_back(std::make_pair(entry.path().string(), entryJson));
}

std::stringstream ss;
pt::write_json(ss, jsonResult);
fillStrInMsParam(_list, ss.str().c_str());
pt::ptree jsonResult;
fs::directory_iterator endIter;

// Iterate through directory.
for (fs::directory_iterator iter(physical_path_bp); iter != endIter; ++iter) {
const fs::directory_entry entry = *iter;
pt::ptree entryJson;

entryJson.put("name", entry.path().filename().string());

if (fs::is_regular_file(entry.status())) {
entryJson.put("type", "file");
}
else {
rodsLog(LOG_ERROR, "msi_dir_list: path <%s> is not a directory", path_str);
return SYS_INVALID_FILE_PATH;
else if (fs::is_directory(entry.status())) {
entryJson.put("type", "directory");
}
else if (fs::is_symlink(entry.symlink_status())) {
entryJson.put("type", "symlink");
}

if (fs::is_regular_file(entry.status())) {
entryJson.put("filesize", fs::file_size(entry.path()));
}

if (fs::is_directory(entry.status())) {
int numEntries = std::distance(fs::directory_iterator(entry.path()), fs::directory_iterator{});
entryJson.put("subdirectory_entries", numEntries);
}

std::time_t modifiedTime = fs::last_write_time(entry.path());
char* localModifiedTime = std::asctime(std::localtime(&modifiedTime));

// Remove trailing newline.
localModifiedTime[strcspn(localModifiedTime, "\n")] = '\0';
std::string modifiedTimestamp(localModifiedTime);

entryJson.put("modified_timestamp", modifiedTimestamp);
jsonResult.push_back(std::make_pair(entry.path().string(), entryJson));
}
else {
rodsLog(LOG_ERROR, "msi_dir_list: path <%s> does not exist", path_str);
return SYS_INVALID_FILE_PATH;
}
}
catch (const fs::filesystem_error& error) {
rodsLog(LOG_ERROR, "msi_dir_list: filesystem error for <%s> - %s", path_str, error.what());
return SYS_INVALID_FILE_PATH;

std::stringstream ss;
pt::write_json(ss, jsonResult);
fillStrInMsParam(_list, ss.str().c_str());
}
}
catch (const fs::filesystem_error& error) {
rodsLog(LOG_ERROR, "msi_dir_list: filesystem error for <%s> - %s", path_str, error.what());
return SYS_INVALID_FILE_PATH;
}

_rei->status = 0;
_rei->status = 0;

return _rei->status;
return _rei->status;
}

extern "C" irods::ms_table_entry* plugin_factory()
Expand Down

0 comments on commit 4849a9a

Please sign in to comment.