blob: 2d1d96a9b48199c39a801c3525fc78fbcfe1684a [file] [log] [blame]
Alexander Afanasyev026eaf32013-02-23 16:37:14 -08001/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013 University of California, Los Angeles
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
19 * Zhenkai Zhu <zhenkai@cs.ucla.edu>
20 */
21
22#include "state-server.h"
23#include "logging.h"
24#include <boost/make_shared.hpp>
25#include <utility>
26#include "task.h"
27#include "periodic-task.h"
28#include "simple-interval-generator.h"
29#include <boost/lexical_cast.hpp>
Alexander Afanasyeve1c95042013-02-27 01:02:36 -080030#include <boost/date_time/posix_time/posix_time.hpp>
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080031
32INIT_LOGGER ("StateServer");
33
34using namespace Ccnx;
35using namespace std;
36using namespace boost;
37
38StateServer::StateServer(CcnxWrapperPtr ccnx, ActionLogPtr actionLog,
39 const boost::filesystem::path &rootDir,
40 const Ccnx::Name &userName, const std::string &sharedFolderName,
41 const std::string &appName,
42 ObjectManager &objectManager,
43 int freshness/* = -1*/)
44 : m_ccnx(ccnx)
45 , m_actionLog(actionLog)
46 , m_objectManager (objectManager)
47 , m_rootDir(rootDir)
48 , m_freshness(freshness)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -080049 , m_executor (1)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080050 , m_userName (userName)
51 , m_sharedFolderName (sharedFolderName)
52 , m_appName (appName)
53{
54 // may be later /localhost should be replaced with /%C1.M.S.localhost
55
56 // <PREFIX_INFO> = /localhost/<user's-device-name>/"chronoshare"/"info"
Alexander Afanasyev95f9f552013-02-26 23:05:20 -080057 m_PREFIX_INFO = Name ("/localhost")(m_userName)("chronoshare")(m_sharedFolderName)("info");
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080058
59 // <PREFIX_CMD> = /localhost/<user's-device-name>/"chronoshare"/"cmd"
Alexander Afanasyev95f9f552013-02-26 23:05:20 -080060 m_PREFIX_CMD = Name ("/localhost")(m_userName)("chronoshare")(m_sharedFolderName)("cmd");
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080061
Alexander Afanasyev95f9f552013-02-26 23:05:20 -080062 m_executor.start ();
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080063
64 registerPrefixes ();
65}
66
67StateServer::~StateServer()
68{
Alexander Afanasyev95f9f552013-02-26 23:05:20 -080069 m_executor.shutdown ();
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080070
71 deregisterPrefixes ();
72}
73
74void
75StateServer::registerPrefixes ()
76{
77 // currently supporting limited number of command.
78 // will be extended to support all planned commands later
79
Alexander Afanasyev3c95c852013-03-01 18:58:50 -080080 // <PREFIX_INFO>/"actions"/"all"/<segment> get list of all actions
Alexander Afanasyev95f9f552013-02-26 23:05:20 -080081 m_ccnx->setInterestFilter (Name (m_PREFIX_INFO)("actions")("folder"), bind(&StateServer::info_actions_folder, this, _1));
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -080082 m_ccnx->setInterestFilter (Name (m_PREFIX_INFO)("actions")("file"), bind(&StateServer::info_actions_file, this, _1));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080083
Alexander Afanasyev3c95c852013-03-01 18:58:50 -080084 // <PREFIX_INFO>/"filestate"/"all"/<segment>
Alexander Afanasyev94240b52013-02-27 11:57:29 -080085 m_ccnx->setInterestFilter (Name (m_PREFIX_INFO)("files")("folder"), bind(&StateServer::info_files_folder, this, _1));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080086
87 // <PREFIX_CMD>/"restore"/"file"/<one-component-relative-file-name>/<version>/<file-hash>
88 m_ccnx->setInterestFilter (Name (m_PREFIX_CMD)("restore")("file"), bind(&StateServer::cmd_restore_file, this, _1));
89}
90
91void
92StateServer::deregisterPrefixes ()
93{
Alexander Afanasyev95f9f552013-02-26 23:05:20 -080094 m_ccnx->clearInterestFilter (Name (m_PREFIX_INFO)("actions")("folder"));
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -080095 m_ccnx->clearInterestFilter (Name (m_PREFIX_INFO)("actions")("file"));
Alexander Afanasyev94240b52013-02-27 11:57:29 -080096 m_ccnx->clearInterestFilter (Name (m_PREFIX_INFO)("files")("folder"));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -080097 m_ccnx->clearInterestFilter (Name (m_PREFIX_CMD) ("restore")("file"));
98}
99
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800100void
101StateServer::formatActionJson (json_spirit::Array &actions,
102 const Ccnx::Name &name, sqlite3_int64 seq_no, const ActionItem &action)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800103{
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800104/*
105 * {
106 * "id": {
107 * "userName": "<NDN-NAME-OF-THE-USER>",
108 * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
109 * },
110 * "timestamp": "<ACTION-TIMESTAMP>",
111 * "filename": "<FILENAME>",
112 *
113 * "action": "UPDATE | DELETE",
114 *
115 * // only if update
116 * "update": {
117 * "hash": "<FILE-HASH>",
118 * "timestamp": "<FILE-TIMESTAMP>",
119 * "chmod": "<FILE-MODE>",
120 * "segNum": "<NUMBER-OF-SEGMENTS (~file size)>"
121 * },
122 *
123 * // if parent_device_name is set
124 * "parentId": {
125 * "userName": "<NDN-NAME-OF-THE-USER>",
126 * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
127 * }
128 * }
129 */
130
131 using namespace json_spirit;
132 using namespace boost::posix_time;
133
134 Object json;
135 Object id;
136
137 id.push_back (Pair ("userName", boost::lexical_cast<string> (name)));
Alexander Afanasyev95f4e922013-03-17 18:09:36 -0700138 id.push_back (Pair ("seqNo", static_cast<int64_t> (seq_no)));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800139
140 json.push_back (Pair ("id", id));
141
Alexander Afanasyev46bd8062013-02-27 23:59:15 -0800142 json.push_back (Pair ("timestamp", to_iso_extended_string (from_time_t (action.timestamp ()))));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800143 json.push_back (Pair ("filename", action.filename ()));
Alexander Afanasyevf63a5142013-02-28 02:21:42 -0800144 json.push_back (Pair ("version", action.version ()));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800145 json.push_back (Pair ("action", (action.action () == 0) ? "UPDATE" : "DELETE"));
146
147 if (action.action () == 0)
148 {
149 Object update;
150 update.push_back (Pair ("hash", boost::lexical_cast<string> (Hash (action.file_hash ().c_str (), action.file_hash ().size ()))));
Alexander Afanasyev46bd8062013-02-27 23:59:15 -0800151 update.push_back (Pair ("timestamp", to_iso_extended_string (from_time_t (action.mtime ()))));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800152
153 ostringstream chmod;
154 chmod << setbase (8) << setfill ('0') << setw (4) << action.mode ();
155 update.push_back (Pair ("chmod", chmod.str ()));
156
157 update.push_back (Pair ("segNum", action.seg_num ()));
158 json.push_back (Pair ("update", update));
159 }
160
161 if (action.has_parent_device_name ())
162 {
163 Object parentId;
164 Ccnx::Name parent_device_name (action.parent_device_name ().c_str (), action.parent_device_name ().size ());
165 id.push_back (Pair ("userName", boost::lexical_cast<string> (parent_device_name)));
166 id.push_back (Pair ("seqNo", action.parent_seq_no ()));
167
168 json.push_back (Pair ("parentId", parentId));
169 }
170
171 actions.push_back (json);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800172}
173
174void
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800175StateServer::info_actions_folder (const Name &interest)
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800176{
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800177 if (interest.size () - m_PREFIX_INFO.size () != 3 &&
178 interest.size () - m_PREFIX_INFO.size () != 4)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800179 {
180 _LOG_DEBUG ("Invalid interest: " << interest);
181 return;
182 }
183
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800184 _LOG_DEBUG (">> info_actions_folder: " << interest);
185 m_executor.execute (bind (&StateServer::info_actions_fileOrFolder_Execute, this, interest, true));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800186}
187
188void
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800189StateServer::info_actions_file (const Name &interest)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800190{
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800191 if (interest.size () - m_PREFIX_INFO.size () != 3 &&
192 interest.size () - m_PREFIX_INFO.size () != 4)
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800193 {
194 _LOG_DEBUG ("Invalid interest: " << interest);
195 return;
196 }
197
198 _LOG_DEBUG (">> info_actions_file: " << interest);
199 m_executor.execute (bind (&StateServer::info_actions_fileOrFolder_Execute, this, interest, false));
200}
201
202
203void
204StateServer::info_actions_fileOrFolder_Execute (const Ccnx::Name &interest, bool isFolder/* = true*/)
205{
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800206 // <PREFIX_INFO>/"actions"/"folder|file"/<folder|file>/<offset> get list of all actions
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800207
208 try
209 {
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800210 int offset = interest.getCompFromBackAsInt (0);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800211
212 /// @todo !!! add security checking
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800213
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800214 string fileOrFolderName;
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800215 if (interest.size () - m_PREFIX_INFO.size () == 4)
216 fileOrFolderName = interest.getCompFromBackAsString (1);
217 else // == 3
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800218 fileOrFolderName = "";
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800219/*
220 * {
221 * "actions": [
222 * ...
223 * ],
224 *
225 * // only if there are more actions available
226 * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-ACTION>"
227 * }
228 */
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800229
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800230 using namespace json_spirit;
231 Object json;
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800232
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800233 Array actions;
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800234 bool more;
235 if (isFolder)
236 {
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800237 more = m_actionLog->LookupActionsInFolderRecursively
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800238 (boost::bind (StateServer::formatActionJson, boost::ref(actions), _1, _2, _3),
239 fileOrFolderName, offset*10, 10);
240 }
241 else
242 {
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800243 more = m_actionLog->LookupActionsForFile
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800244 (boost::bind (StateServer::formatActionJson, boost::ref(actions), _1, _2, _3),
245 fileOrFolderName, offset*10, 10);
246 }
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800247
248 json.push_back (Pair ("actions", actions));
249
250 if (more)
251 {
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800252 json.push_back (Pair ("more", lexical_cast<string> (offset + 1)));
253 // Ccnx::Name more = Name (interest.getPartialName (0, interest.size () - 1))(offset + 1);
254 // json.push_back (Pair ("more", lexical_cast<string> (more)));
Alexander Afanasyeve1c95042013-02-27 01:02:36 -0800255 }
256
257 ostringstream os;
258 write_stream (Value (json), os, pretty_print | raw_utf8);
259 m_ccnx->publishData (interest, os.str (), 1);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800260 }
261 catch (Ccnx::NameException &ne)
262 {
263 // ignore any unexpected interests and errors
264 _LOG_ERROR (*boost::get_error_info<Ccnx::error_info_str>(ne));
265 }
266}
267
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800268void
269StateServer::formatFilestateJson (json_spirit::Array &files, const FileItem &file)
270{
271/**
272 * {
273 * "filestate": [
274 * {
275 * "filename": "<FILENAME>",
276 * "owner": {
277 * "userName": "<NDN-NAME-OF-THE-USER>",
278 * "seqNo": "<SEQ_NO_OF_THE_ACTION>"
279 * },
280 *
281 * "hash": "<FILE-HASH>",
282 * "timestamp": "<FILE-TIMESTAMP>",
283 * "chmod": "<FILE-MODE>",
284 * "segNum": "<NUMBER-OF-SEGMENTS (~file size)>"
285 * }, ...,
286 * ]
287 *
288 * // only if there are more actions available
289 * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-FILESTATE>"
290 * }
291 */
292 using namespace json_spirit;
293 using namespace boost::posix_time;
294
295 Object json;
296
297 json.push_back (Pair ("filename", file.filename ()));
298 json.push_back (Pair ("version", file.version ()));
299 {
300 Object owner;
301 Ccnx::Name device_name (file.device_name ().c_str (), file.device_name ().size ());
302 owner.push_back (Pair ("userName", boost::lexical_cast<string> (device_name)));
303 owner.push_back (Pair ("seqNo", file.seq_no ()));
304
305 json.push_back (Pair ("owner", owner));
306 }
307
308 json.push_back (Pair ("hash", boost::lexical_cast<string> (Hash (file.file_hash ().c_str (), file.file_hash ().size ()))));
Alexander Afanasyev46bd8062013-02-27 23:59:15 -0800309 json.push_back (Pair ("timestamp", to_iso_extended_string (from_time_t (file.mtime ()))));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800310
311 ostringstream chmod;
312 chmod << setbase (8) << setfill ('0') << setw (4) << file.mode ();
313 json.push_back (Pair ("chmod", chmod.str ()));
314
315 json.push_back (Pair ("segNum", file.seg_num ()));
316
317 files.push_back (json);
318}
319
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800320void debugFileState (const FileItem &file)
321{
322 std::cout << file.filename () << std::endl;
323}
324
325void
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800326StateServer::info_files_folder (const Ccnx::Name &interest)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800327{
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800328 if (interest.size () - m_PREFIX_INFO.size () != 3 &&
329 interest.size () - m_PREFIX_INFO.size () != 4)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800330 {
331 _LOG_DEBUG ("Invalid interest: " << interest << ", " << interest.size () - m_PREFIX_INFO.size ());
332 return;
333 }
334
Alexander Afanasyev39dbc4b2013-03-01 10:39:23 -0800335 _LOG_DEBUG (">> info_files_folder: " << interest);
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800336 m_executor.execute (bind (&StateServer::info_files_folder_Execute, this, interest));
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800337}
338
339
340void
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800341StateServer::info_files_folder_Execute (const Ccnx::Name &interest)
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800342{
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800343 // <PREFIX_INFO>/"filestate"/"folder"/<one-component-relative-folder-name>/<offset>
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800344 try
345 {
346 int offset = interest.getCompFromBackAsInt (0);
347
348 // /// @todo !!! add security checking
349
350 string folder;
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800351 if (interest.size () - m_PREFIX_INFO.size () == 4)
352 folder = interest.getCompFromBackAsString (1);
353 else // == 3
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800354 folder = "";
355
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800356/*
357 * {
358 * "files": [
359 * ...
360 * ],
361 *
362 * // only if there are more actions available
363 * "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-ACTION>"
364 * }
365 */
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800366
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800367 using namespace json_spirit;
368 Object json;
369
370 Array files;
371 bool more = m_actionLog
372 ->GetFileState ()
373 ->LookupFilesInFolderRecursively
374 (boost::bind (StateServer::formatFilestateJson, boost::ref (files), _1),
375 folder, offset*10, 10);
376
377 json.push_back (Pair ("files", files));
378
379 if (more)
380 {
Alexander Afanasyev3c95c852013-03-01 18:58:50 -0800381 json.push_back (Pair ("more", lexical_cast<string> (offset + 1)));
382 // Ccnx::Name more = Name (interest.getPartialName (0, interest.size () - 1))(offset + 1);
383 // json.push_back (Pair ("more", lexical_cast<string> (more)));
Alexander Afanasyev94240b52013-02-27 11:57:29 -0800384 }
385
386 ostringstream os;
387 write_stream (Value (json), os, pretty_print | raw_utf8);
388 m_ccnx->publishData (interest, os.str (), 1);
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800389 }
390 catch (Ccnx::NameException &ne)
391 {
392 // ignore any unexpected interests and errors
393 _LOG_ERROR (*boost::get_error_info<Ccnx::error_info_str>(ne));
394 }
395}
396
397
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800398void
399StateServer::cmd_restore_file (const Ccnx::Name &interest)
400{
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800401 if (interest.size () - m_PREFIX_CMD.size () != 4 &&
402 interest.size () - m_PREFIX_CMD.size () != 5)
403 {
404 _LOG_DEBUG ("Invalid interest: " << interest);
405 return;
406 }
407
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800408 _LOG_DEBUG (">> cmd_restore_file: " << interest);
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800409 m_executor.execute (bind (&StateServer::cmd_restore_file_Execute, this, interest));
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800410}
411
412void
413StateServer::cmd_restore_file_Execute (const Ccnx::Name &interest)
414{
415 // <PREFIX_CMD>/"restore"/"file"/<one-component-relative-file-name>/<version>/<file-hash>
416
417 /// @todo !!! add security checking
418
419 try
420 {
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800421 FileItemPtr file;
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800422
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800423 if (interest.size () - m_PREFIX_CMD.size () == 5)
424 {
425 Hash hash (head(interest.getCompFromBack (0)), interest.getCompFromBack (0).size());
426 int64_t version = interest.getCompFromBackAsInt (1);
427 string filename = interest.getCompFromBackAsString (2); // should be safe even with full relative path
428
429 file = m_actionLog->LookupAction (filename, version, hash);
430 if (!file)
431 {
432 _LOG_ERROR ("Requested file is not found: [" << filename << "] version [" << version << "] hash [" << hash.shortHash () << "]");
433 }
434 }
435 else
436 {
437 int64_t version = interest.getCompFromBackAsInt (0);
438 string filename = interest.getCompFromBackAsString (1); // should be safe even with full relative path
439
440 file = m_actionLog->LookupAction (filename, version, Hash (0,0));
441 if (!file)
442 {
443 _LOG_ERROR ("Requested file is not found: [" << filename << "] version [" << version << "]");
444 }
445 }
446
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800447 if (!file)
448 {
449 m_ccnx->publishData (interest, "FAIL: Requested file is not found", 1);
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800450 return;
451 }
452
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800453 Hash hash = Hash (file->file_hash ().c_str (), file->file_hash ().size ());
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800454
455 ///////////////////
456 // now the magic //
457 ///////////////////
458
Alexander Afanasyev95f9f552013-02-26 23:05:20 -0800459 boost::filesystem::path filePath = m_rootDir / file->filename ();
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800460 Name deviceName (file->device_name ().c_str (), file->device_name ().size ());
461
462 try
463 {
464 if (filesystem::exists (filePath) &&
465 filesystem::last_write_time (filePath) == file->mtime () &&
Alexander Afanasyevf8ff5e12013-07-11 13:57:32 -0700466#if BOOST_VERSION >= 104900
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800467 filesystem::status (filePath).permissions () == static_cast<filesystem::perms> (file->mode ()) &&
Alexander Afanasyevf8ff5e12013-07-11 13:57:32 -0700468#endif
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800469 *Hash::FromFileContent (filePath) == hash)
470 {
471 m_ccnx->publishData (interest, "OK: File already exists", 1);
472 _LOG_DEBUG ("Asking to assemble a file, but file already exists on a filesystem");
473 return;
474 }
475 }
476 catch (filesystem::filesystem_error &error)
477 {
478 m_ccnx->publishData (interest, "FAIL: File operation failed", 1);
479 _LOG_ERROR ("File operations failed on [" << filePath << "] (ignoring)");
480 }
481
482 _LOG_TRACE ("Restoring file [" << filePath << "]");
483 if (m_objectManager.objectsToLocalFile (deviceName, hash, filePath))
484 {
485 last_write_time (filePath, file->mtime ());
Alexander Afanasyevf8ff5e12013-07-11 13:57:32 -0700486#if BOOST_VERSION >= 104900
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800487 permissions (filePath, static_cast<filesystem::perms> (file->mode ()));
Alexander Afanasyevf8ff5e12013-07-11 13:57:32 -0700488#endif
Alexander Afanasyev026eaf32013-02-23 16:37:14 -0800489 m_ccnx->publishData (interest, "OK", 1);
490 }
491 else
492 {
493 m_ccnx->publishData (interest, "FAIL: Unknown error while restoring file", 1);
494 }
495 }
496 catch (Ccnx::NameException &ne)
497 {
498 // ignore any unexpected interests and errors
499 _LOG_ERROR(*boost::get_error_info<Ccnx::error_info_str>(ne));
500 }
501}