63
throw DestroyedException(); // TODO
66
QFuture<QVariantMap> ItemImpl::get_metadata() const
68
QFutureInterface<QVariantMap> qf;
71
qf.reportException(DestroyedException()); // TODO
74
return QFuture<QVariantMap>(); // TODO
77
QFuture<QDateTime> ItemImpl::last_modified_time() const
79
QFutureInterface<QDateTime> qf;
82
qf.reportException(DestroyedException()); // TODO
88
auto mtime = boost::filesystem::last_write_time(identity_.toStdString());
93
catch (std::exception const&)
95
qf.reportException(StorageException()); // TODO
69
throw RuntimeDestroyedException();
72
ItemType ItemImpl::type() const
76
throw DestroyedException(); // TODO
81
QVariantMap ItemImpl::metadata() const
85
throw DestroyedException(); // TODO
90
QDateTime ItemImpl::last_modified_time() const
94
throw DestroyedException(); // TODO
97
lock_guard<mutex> lock(mutex_);
98
return modified_time_;
101
void ItemImpl::update_modified_time()
103
lock_guard<mutex> lock(mutex_);
104
auto mtime = boost::filesystem::last_write_time(native_identity().toStdString());
105
modified_time_ = QDateTime::fromTime_t(mtime);
111
using namespace boost::filesystem;
113
void copy_recursively(path const& source, path const& target)
115
auto s = status(source);
116
if (is_regular_file(s))
118
copy_file(source, target);
121
else if (is_directory(s))
123
copy_directory(source, target); // Poorly named in boost; this creates the target dir without recursion
124
for (directory_iterator it(source); it != directory_iterator(); ++it)
126
path source_entry = it->path();
127
path target_entry = target;
128
target_entry /= source_entry.filename();
129
copy_recursively(source_entry, target_entry);
134
// Ignore everything that's not a directory or file.
140
QFuture<shared_ptr<Item>> ItemImpl::copy(shared_ptr<Folder> const& new_parent, QString const& new_name)
142
using namespace boost::filesystem;
146
QFutureInterface<shared_ptr<Item>> qf;
147
qf.reportException(DestroyedException()); // TODO
152
auto This = static_pointer_cast<ItemImpl>(shared_from_this()); // Keep this item alive while the lambda is alive.
153
auto copy = [This, new_parent, new_name]() -> Item::SPtr
157
if (new_parent->p_->destroyed_)
159
throw DestroyedException(); // TODO
161
if (This->root()->account() != new_parent->root()->account())
163
// Can't do cross-account copy.
164
throw StorageException(); // TODO
167
path source_path = This->native_identity().toStdString();
168
path parent_path = new_parent->native_identity().toStdString();
169
path target_path = parent_path;
170
path sanitized_name = sanitize(new_name);
171
target_path /= sanitized_name;
173
if (This->type_ == ItemType::file)
175
copy_file(source_path, target_path);
176
return FileImpl::make_file(QString::fromStdString(target_path.native()), new_parent->p_->root_);
179
// Allow only one recursive copy per account at a time, otherwise source and destination
180
// sub-trees for recursive copies could potentially overlap, creating chaos due to iterator invalidation.
181
auto root_impl = static_pointer_cast<Root>(This->root_.lock());
184
throw RuntimeDestroyedException();
187
auto guard = root_impl->account()->p_->get_copy_guard();
189
if (exists(target_path))
191
throw StorageException(); // TODO
194
// For recursive copy, we create a temporary directory in lieu of target_path and recursively copy
195
// everything into the temporary directory. This ensures that we don't invalidate directory iterators
196
// by creating things while we are iterating, potentially getting trapped in an infinite loop.
197
path tmp_path = canonical(parent_path);
198
tmp_path /= unique_path(".%%%%-%%%%-%%%%-%%%%");
199
create_directories(tmp_path);
200
for (directory_iterator it(source_path); it != directory_iterator(); ++it)
202
if (tmp_path.compare(canonical(it->path())) == 0)
204
continue; // Don't recurse into the temporary directory
206
file_status s = it->status();
207
if (is_directory(s) || is_regular_file(s))
209
path source_entry = it->path();
210
path target_entry = tmp_path;
211
target_entry /= source_entry.filename();
212
copy_recursively(source_entry, target_entry);
215
rename(tmp_path, target_path);
216
return FolderImpl::make_folder(QString::fromStdString(target_path.native()), new_parent->p_->root_);
218
catch (std::exception const&)
220
throw StorageException(); // TODO
223
return QtConcurrent::run(copy);
226
QFuture<shared_ptr<Item>> ItemImpl::move(shared_ptr<Folder> const& new_parent, QString const& new_name)
230
QFutureInterface<shared_ptr<Item>> qf;
231
qf.reportException(DestroyedException()); // TODO
236
auto This = static_pointer_cast<ItemImpl>(shared_from_this()); // Keep this item alive while the lambda is alive.
237
auto move = [This, new_parent, new_name]() -> Item::SPtr
239
using namespace boost::filesystem;
243
if (new_parent->p_->destroyed_)
245
throw DestroyedException(); // TODO
247
if (This->root()->account() != new_parent->root()->account())
249
// Can't do cross-account move.
250
throw StorageException(); // TODO
252
if (This->type_ == ItemType::root)
254
// Can't move a root.
255
throw StorageException(); // TODO
258
path target_path = new_parent->native_identity().toStdString();
259
target_path /= sanitize(new_name);
260
if (exists(target_path))
262
throw StorageException(); // TODO
264
rename(This->native_identity().toStdString(), target_path);
265
This->destroyed_ = true;
266
if (This->type_ == ItemType::folder)
268
return FolderImpl::make_folder(QString::fromStdString(target_path.native()), new_parent->p_->root_);
270
return FileImpl::make_file(QString::fromStdString(target_path.native()), new_parent->p_->root_);
272
catch (std::exception const&)
274
throw StorageException(); // TODO
277
return QtConcurrent::run(move);
280
QFuture<QVector<Folder::SPtr>> ItemImpl::parents() const
282
QFutureInterface<QVector<Folder::SPtr>> qf;
285
qf.reportException(DestroyedException());
290
Root::SPtr root = root_.lock();
293
throw RuntimeDestroyedException();
296
using namespace boost::filesystem;
298
// We do this synchronously because we don't need to hit the file system.
299
path p = native_identity().toStdString();
300
QString parent_path = QString::fromStdString(p.parent_path().native());
302
QVector<Folder::SPtr> results;
303
if (parent_path != root->p_->identity_)
305
results.append(FolderImpl::make_folder(parent_path, root_));
309
results.append(root);
311
qf.reportResult(results);
97
313
return qf.future();
100
common::ItemType ItemImpl::type() const
316
QVector<QString> ItemImpl::parent_ids() const
104
throw DestroyedException(); // TODO
320
throw DestroyedException();
110
QFuture<shared_ptr<Item>> copy(shared_ptr<Folder> const& new_parent, QString const& new_name)
112
return QFuture<shared_ptr<Item>>(); // TODO
115
QFuture<shared_ptr<Item>> move(shared_ptr<Folder> const& new_parent, QString const& new_name)
117
return QFuture<shared_ptr<Item>>(); // TODO
323
using namespace boost::filesystem;
325
// We do this synchronously because we don't need to hit the file system.
326
path p = native_identity().toStdString();
327
QString parent_path = QString::fromStdString(p.parent_path().native());
329
QVector<QString> results;
330
results.append(parent_path);
120
334
QFuture<void> ItemImpl::destroy()
122
QFutureInterface<void> qf;
125
qf.reportException(DestroyedException()); // TODO
338
QFutureInterface<void> qf;
339
qf.reportException(DestroyedException());
126
341
return qf.future();
128
return QFuture<QString>(); // TODO
344
auto This = shared_from_this(); // Keep this item alive while the lambda is alive.
345
auto destroy = [This]()
347
using namespace boost::filesystem;
351
remove_all(This->identity_.toStdString());
352
This->destroyed_ = true;
354
catch (std::exception const& e)
356
throw StorageException(); // TODO
359
return QtConcurrent::run(destroy);
131
362
void ItemImpl::set_root(weak_ptr<Root> p)