Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 73 #100

Merged
merged 1 commit into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions DSI/globus_gridftp_server_iRODS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ extern "C" {
#include <irods/thread_pool.hpp>
#include <irods/filesystem.hpp>
#include <irods/base64.hpp>
#include <irods/touch.h>

// boost includes
#include <boost/algorithm/string.hpp>
Expand Down Expand Up @@ -212,6 +213,7 @@ int convert_base64_to_hex_string(const std::string& base64_str, const int& bit_c
return 0;
}

// removes all trailing slashes and replaces consecutive slashes with a single slash
int
iRODS_l_reduce_path(
char * path)
Expand Down Expand Up @@ -282,6 +284,9 @@ struct globus_l_gfs_iRODS_handle_t
uint64_t irods_parallel_file_size_threshold_bytes;

bool first_write_done;

// added to get file modification time from client
time_t utime;
JustinKyleJames marked this conversation as resolved.
Show resolved Hide resolved
};

std::condition_variable outstanding_cntr_cv;
Expand Down Expand Up @@ -2041,6 +2046,18 @@ globus_l_gfs_iRODS_recv(
}
}

result = globus_gridftp_server_get_recv_modification_time(op, &iRODS_handle->utime);
if(result != GLOBUS_SUCCESS)
{
// continue but don't modify utime
globus_gfs_log_result(GLOBUS_GFS_LOG_WARN, "iRODS: Error getting modtime, skipping: ", result);
iRODS_handle->utime = -1;
}
else
{
globus_gfs_log_message(GLOBUS_GFS_LOG_INFO,"iRODS: globus_gridftp_server_get_recv_modification_time returned %lld.\n", static_cast<long long>(iRODS_handle->utime));
}

// the main thread is the first writer so thread_pool starts number_of_irods_write_threads-1 threads
irods::thread_pool threads{number_of_irods_write_threads-1};

Expand Down Expand Up @@ -2180,6 +2197,19 @@ globus_l_gfs_iRODS_recv(
memset (&dataObjCloseInp, 0, sizeof (dataObjCloseInp));
dataObjCloseInp.l1descInx = iRODS_handle->fd;
rcDataObjClose(iRODS_handle->conn, &dataObjCloseInp);

// update the modify time if preservation option selected
if (iRODS_handle->utime > 0)
{
nlohmann::json json_input;
json_input["logical_path"] = collection;
json_input["options"]["no_create"] = true;
json_input["options"]["seconds_since_epoch"] = iRODS_handle->utime;
if (const auto ec = rc_touch(iRODS_handle->conn, json_input.dump().c_str()); ec < 0) {
globus_gfs_log_message(GLOBUS_GFS_LOG_ERR,
"iRODS: Caught error (%d) trying to update the modify time for [%s]. Continuing without updating modify time.\n", ec, collection);
}
}

free(collection);
collection = nullptr;
Expand Down
39 changes: 39 additions & 0 deletions tests/globus_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,45 @@ def test_file_rename_with_ftp(self):
ftp.login(user='user1', passwd='pass')
ftp.delete(f'/tempZone/home/user1/{filename2}')

def test_preserve_file_modification_time(self):
filename = f'{inspect.currentframe().f_code.co_name}1'
modify_time = '19710827010000'
korydraughn marked this conversation as resolved.
Show resolved Hide resolved

try:
make_arbitrary_file(filename, 100*1024)
with FTP() as ftp:
ftp.connect(host='localhost', port=2811)
ftp.login(user='user1', passwd='pass')

# tell the server to send a hardcoded file modification time
ftp.sendcmd(f'site storattr modify={modify_time};')

# write the file that will be renamed
with open(filename,'rb') as f:
ftp.storbinary(f'STOR /tempZone/home/user1/{filename}', f)

# check the file modification time
with FTP() as ftp:
ftp.connect(host='localhost', port=2811)
ftp.login(user='user1', passwd='pass')

rv = ftp.mlsd(f'/tempZone/home/user1/{filename}', facts=['modify'])

# mlsd returns a generator object yielding a tuple of two elements for every file found in path.
# First element is the file name, the second one is a dictionary containing facts about the file name.
entry = next(rv)
self.assertEqual(f'/tempZone/home/user1/{filename}', entry[0])
self.assertEqual(modify_time, entry[1]['modify'])

finally:
os.remove(filename)

# remove file via ftp
with FTP() as ftp:
ftp.connect(host='localhost', port=2811)
ftp.login(user='user1', passwd='pass')
ftp.delete(f'/tempZone/home/user1/{filename}')

def test_directory_creation_renaming_removal_with_ftp(self):
filename = f'{inspect.currentframe().f_code.co_name}1'

Expand Down