Merge lp:~unity-api-team/storage-framework/merge-devel into lp:storage-framework

Proposed by Michi Henning
Status: Merged
Approved by: Michi Henning
Approved revision: 64
Merged at revision: 11
Proposed branch: lp:~unity-api-team/storage-framework/merge-devel
Merge into: lp:storage-framework
Diff against target: 14429 lines (+8069/-2223)
126 files modified
CMakeLists.txt (+5/-2)
data/provider.xml (+12/-9)
debian/bileto_pre_release_hook (+1/-1)
debian/changelog (+6/-0)
demo/provider_test/CMakeLists.txt (+0/-1)
demo/provider_test/provider-test.cpp (+55/-60)
include/unity/storage/internal/ItemMetadata.h (+4/-1)
include/unity/storage/internal/TraceMessageHandler.h (+47/-0)
include/unity/storage/internal/dbus_error.h (+32/-0)
include/unity/storage/internal/dbusmarshal.h (+44/-0)
include/unity/storage/provider/CMakeLists.txt (+2/-0)
include/unity/storage/provider/Exceptions.h (+187/-0)
include/unity/storage/provider/ProviderBase.h (+7/-3)
include/unity/storage/provider/TempfileUploadJob.h (+6/-0)
include/unity/storage/provider/internal/AccountData.h (+5/-0)
include/unity/storage/provider/internal/DBusPeerCache.h (+5/-0)
include/unity/storage/provider/internal/DownloadJobImpl.h (+0/-4)
include/unity/storage/provider/internal/Handler.h (+2/-0)
include/unity/storage/provider/internal/MainLoopExecutor.h (+1/-15)
include/unity/storage/provider/internal/PendingJobs.h (+21/-11)
include/unity/storage/provider/internal/ProviderInterface.h (+5/-0)
include/unity/storage/provider/internal/ServerImpl.h (+2/-0)
include/unity/storage/provider/internal/TempfileUploadJobImpl.h (+6/-1)
include/unity/storage/provider/internal/TestServerImpl.h (+65/-0)
include/unity/storage/provider/internal/UploadJobImpl.h (+4/-4)
include/unity/storage/provider/internal/dbusmarshal.h (+7/-0)
include/unity/storage/provider/metadata_keys.h (+19/-6)
include/unity/storage/provider/testing/CMakeLists.txt (+5/-0)
include/unity/storage/provider/testing/TestServer.h (+68/-0)
include/unity/storage/qt/client/Account.h (+1/-1)
include/unity/storage/qt/client/Exceptions.h (+13/-5)
include/unity/storage/qt/client/Item.h (+1/-1)
include/unity/storage/qt/client/Root.h (+1/-1)
include/unity/storage/qt/client/Runtime.h (+13/-0)
include/unity/storage/qt/client/Uploader.h (+8/-0)
include/unity/storage/qt/client/internal/AccountBase.h (+1/-1)
include/unity/storage/qt/client/internal/ItemBase.h (+6/-2)
include/unity/storage/qt/client/internal/RootBase.h (+1/-1)
include/unity/storage/qt/client/internal/RuntimeBase.h (+9/-4)
include/unity/storage/qt/client/internal/UploaderBase.h (+4/-1)
include/unity/storage/qt/client/internal/local_client/DownloaderImpl.h (+2/-1)
include/unity/storage/qt/client/internal/local_client/FolderImpl.h (+1/-0)
include/unity/storage/qt/client/internal/local_client/ItemImpl.h (+4/-7)
include/unity/storage/qt/client/internal/local_client/RuntimeImpl.h (+2/-0)
include/unity/storage/qt/client/internal/local_client/UploaderImpl.h (+2/-2)
include/unity/storage/qt/client/internal/local_client/storage_exception.h (+94/-0)
include/unity/storage/qt/client/internal/make_future.h (+21/-37)
include/unity/storage/qt/client/internal/remote_client/AccountImpl.h (+2/-1)
include/unity/storage/qt/client/internal/remote_client/Handler.h (+38/-2)
include/unity/storage/qt/client/internal/remote_client/ItemImpl.h (+0/-3)
include/unity/storage/qt/client/internal/remote_client/RuntimeImpl.h (+8/-0)
include/unity/storage/qt/client/internal/remote_client/UploaderImpl.h (+4/-2)
include/unity/storage/qt/client/internal/remote_client/dbusmarshal.h (+16/-17)
include/unity/storage/qt/client/internal/remote_client/validate.h (+51/-0)
src/internal/CMakeLists.txt (+5/-0)
src/internal/TraceMessageHandler.cpp (+96/-0)
src/internal/dbusmarshal.cpp (+113/-0)
src/provider/CMakeLists.txt (+48/-17)
src/provider/Exceptions.cpp (+157/-0)
src/provider/TempfileUploadJob.cpp (+5/-0)
src/provider/internal/DownloadJobImpl.cpp (+31/-15)
src/provider/internal/Handler.cpp (+84/-13)
src/provider/internal/MainLoopExecutor.cpp (+0/-4)
src/provider/internal/PendingJobs.cpp (+109/-106)
src/provider/internal/ProviderInterface.cpp (+9/-29)
src/provider/internal/ServerImpl.cpp (+7/-2)
src/provider/internal/TempfileUploadJobImpl.cpp (+21/-1)
src/provider/internal/TestServerImpl.cpp (+84/-0)
src/provider/internal/UploadJobImpl.cpp (+35/-18)
src/provider/internal/dbusmarshal.cpp (+38/-9)
src/provider/testing/TestServer.cpp (+60/-0)
src/qt/client/Account.cpp (+1/-1)
src/qt/client/CMakeLists.txt (+2/-1)
src/qt/client/Exceptions.cpp (+14/-9)
src/qt/client/Item.cpp (+1/-1)
src/qt/client/Root.cpp (+2/-1)
src/qt/client/Runtime.cpp (+6/-0)
src/qt/client/Uploader.cpp (+5/-0)
src/qt/client/internal/AccountBase.cpp (+10/-3)
src/qt/client/internal/ItemBase.cpp (+39/-4)
src/qt/client/internal/RootBase.cpp (+11/-2)
src/qt/client/internal/RuntimeBase.cpp (+0/-5)
src/qt/client/internal/UploaderBase.cpp (+11/-2)
src/qt/client/internal/local_client/AccountImpl.cpp (+16/-3)
src/qt/client/internal/local_client/CMakeLists.txt (+1/-0)
src/qt/client/internal/local_client/DownloaderImpl.cpp (+27/-13)
src/qt/client/internal/local_client/FileImpl.cpp (+25/-23)
src/qt/client/internal/local_client/FolderImpl.cpp (+79/-50)
src/qt/client/internal/local_client/ItemImpl.cpp (+148/-131)
src/qt/client/internal/local_client/RootImpl.cpp (+88/-18)
src/qt/client/internal/local_client/RuntimeImpl.cpp (+16/-1)
src/qt/client/internal/local_client/UploaderImpl.cpp (+53/-36)
src/qt/client/internal/local_client/storage_exception.cpp (+99/-0)
src/qt/client/internal/remote_client/AccountImpl.cpp (+28/-10)
src/qt/client/internal/remote_client/CMakeLists.txt (+1/-0)
src/qt/client/internal/remote_client/DownloaderImpl.cpp (+7/-5)
src/qt/client/internal/remote_client/FileImpl.cpp (+42/-26)
src/qt/client/internal/remote_client/FolderImpl.cpp (+82/-42)
src/qt/client/internal/remote_client/ItemImpl.cpp (+91/-68)
src/qt/client/internal/remote_client/RootImpl.cpp (+67/-12)
src/qt/client/internal/remote_client/RuntimeImpl.cpp (+81/-14)
src/qt/client/internal/remote_client/UploaderImpl.cpp (+32/-17)
src/qt/client/internal/remote_client/dbusmarshal.cpp (+102/-90)
src/qt/client/internal/remote_client/validate.cpp (+169/-0)
tests/CMakeLists.txt (+5/-2)
tests/headers/CMakeLists.txt (+5/-0)
tests/headers/compile_headers.py (+10/-13)
tests/local-client/local-client_test.cpp (+1794/-338)
tests/provider-AccountData/AccountData_test.cpp (+141/-0)
tests/provider-AccountData/CMakeLists.txt (+8/-0)
tests/provider-DBusPeerCache/CMakeLists.txt (+8/-0)
tests/provider-DBusPeerCache/DBusPeerCache_test.cpp (+141/-0)
tests/provider-ProviderInterface/CMakeLists.txt (+16/-0)
tests/provider-ProviderInterface/ProviderInterface_test.cpp (+789/-0)
tests/provider-ProviderInterface/TestProvider.cpp (+462/-0)
tests/provider-ProviderInterface/TestProvider.h (+65/-0)
tests/remote-client/CMakeLists.txt (+4/-3)
tests/remote-client/MockProvider.cpp (+236/-0)
tests/remote-client/MockProvider.h (+96/-0)
tests/remote-client/remote-client_test.cpp (+947/-856)
tests/utils/CMakeLists.txt (+16/-2)
tests/utils/DBusEnvironment.cpp (+5/-0)
tests/utils/DBusEnvironment.h (+1/-0)
tests/utils/ProviderFixture.cpp (+84/-0)
tests/utils/ProviderFixture.h (+50/-0)
tests/utils/fake-online-accounts-daemon.py (+2/-0)
To merge this branch: bzr merge lp:~unity-api-team/storage-framework/merge-devel
Reviewer Review Type Date Requested Status
Michi Henning (community) Approve
Review via email: mp+302665@code.launchpad.net

Commit message

Merged devel at revision 64. Lots of fixes in preparation for integration with backup service and mcloud provider.

Description of the change

Merged devel at revision 64. Lots of fixes in preparation for integration with backup service and mcloud provider.

To post a comment you must log in.
Revision history for this message
Michi Henning (michihenning) wrote :

Looks good, thanks!

review: Approve
Revision history for this message
Michi Henning (michihenning) wrote :

Oops, sorry, that wasn't meant to be approved.

57. By Michi Henning

Increased remote client coverage.

Approved by James Henstridge, unity-api-1-bot.

58. By Michi Henning

Added provider headers to unit tests.

Approved by unity-api-1-bot, James Henstridge.

59. By Michi Henning

Removed half-close on the provider side because this messes with QLocalSocket on the client side.

Approved by James Henstridge, unity-api-1-bot.

60. By Michi Henning

Increased test timeouts because CI builders are hopelessly overloaded.

Approved by unity-api-1-bot, James Henstridge.

61. By James Henstridge

Add a drain() method to UploadJob to allow the provider to read the last bit of data from the socket when the client asks to finish the upload.

Approved by unity-api-1-bot, Michi Henning.

62. By Michi Henning

Don't throw when unknown metadata key is received and log a warning instead.

Approved by unity-api-1-bot, Michi Henning, James Henstridge.

63. By Michi Henning

Removed stale debug trace. Suppressed more compile warnings from system headers that caused a lot of noise in the arm builds.

Approved by James Henstridge, unity-api-1-bot.

64. By Michi Henning

Merged devel at revision 64.

65. By Michi Henning

Merged devel at revision 68.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2016-07-22 08:38:24 +0000
3+++ CMakeLists.txt 2016-09-09 02:13:43 +0000
4@@ -17,7 +17,7 @@
5 # These two should be incremented when the ABI changes.
6 set(SF_CLIENT_SOVERSION "0")
7 execute_process(
8- COMMAND /bin/sh ${CMAKE_CURRENT_SOURCE_DIR}/get-provider-soversion.sh
9+ COMMAND /bin/sh ${CMAKE_CURRENT_SOURCE_DIR}/tools/get-provider-soversion.sh
10 OUTPUT_VARIABLE SF_PROVIDER_SOVERSION
11 OUTPUT_STRIP_TRAILING_WHITESPACE
12 RESULT_VARIABLE result)
13@@ -108,7 +108,7 @@
14
15 include(GNUInstallDirs)
16
17-find_package(Boost COMPONENTS filesystem system thread REQUIRED)
18+find_package(Boost 1.56 COMPONENTS filesystem system thread REQUIRED)
19 find_package(Qt5Concurrent REQUIRED)
20 find_package(Qt5Core REQUIRED)
21 find_package(Qt5DBus REQUIRED)
22@@ -130,8 +130,11 @@
23 enable_coverage_report(
24 TARGETS
25 qt-client-lib-common
26+ storage-framework-common-internal
27 storage-framework-qt-client
28 storage-framework-qt-local-client
29+ sf-provider-objects
30+ storage-framework-provider
31 FILTER
32 ${CMAKE_SOURCE_DIR}/tests/*
33 ${CMAKE_BINARY_DIR}/*
34
35=== modified file 'data/provider.xml'
36--- data/provider.xml 2016-07-11 07:17:04 +0000
37+++ data/provider.xml 2016-09-09 02:13:43 +0000
38@@ -5,14 +5,17 @@
39 com.canonical.StorageFramework.Provider:
40 @short_description: Interface providing access to a storage account
41
42- For methods dealing with metadata, the representation
43- "(ssssia{sv})" is used, where the struct members are:
44+ For methods returning metadata, the representation
45+ "(sasssia{sv})" is used, where the struct members are:
46 - item_id
47- - parent_id
48+ - parent_ids
49 - name
50 - etag
51 - type (enum: file, folder, root)
52 - metadata
53+
54+ Note that parent_ids is a sequence of IDs instead of a single ID to allow the client to
55+ navigate items in Google Drive, which permits more than one parent for a file or folder.
56 -->
57 <interface name="com.canonical.StorageFramework.Provider">
58 <!--
59@@ -25,7 +28,7 @@
60 of files, this list will contain a single item.
61 -->
62 <method name="Roots">
63- <arg type="a(ssssia{sv})" name="roots" direction="out"/>
64+ <arg type="a(sasssia{sv})" name="roots" direction="out"/>
65 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QList&lt;unity::storage::internal::ItemMetadata&gt;"/>
66 </method>
67
68@@ -45,7 +48,7 @@
69 <method name="List">
70 <arg type="s" name="item_id" direction="in"/>
71 <arg type="s" name="page_token" direction="in"/>
72- <arg type="a(ssssia{sv})" name="children" direction="out"/>
73+ <arg type="a(sasssia{sv})" name="children" direction="out"/>
74 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QList&lt;unity::storage::internal::ItemMetadata&gt;"/>
75 <arg type="s" name="next_token" direction="out"/>
76 </method>
77@@ -60,7 +63,7 @@
78 <method name="Lookup">
79 <arg type="s" name="parent_id" direction="in"/>
80 <arg type="s" name="name" direction="in"/>
81- <arg type="a(ssssia{sv})" name="items" direction="out"/>
82+ <arg type="a(sasssia{sv})" name="items" direction="out"/>
83 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QList&lt;unity::storage::internal::ItemMetadata&gt;"/>
84 </method>
85
86@@ -72,7 +75,7 @@
87 -->
88 <method name="Metadata">
89 <arg type="s" name="item_id" direction="in"/>
90- <arg type="(ssssia{sv})" name="metadata" direction="out"/>
91+ <arg type="(sasssia{sv})" name="metadata" direction="out"/>
92 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="unity::storage::internal::ItemMetadata"/>
93 </method>
94
95@@ -86,7 +89,7 @@
96 <method name="CreateFolder">
97 <arg type="s" name="parent_id" direction="in"/>
98 <arg type="s" name="name" direction="in"/>
99- <arg type="(ssssia{sv})" name="metadata" direction="out"/>
100+ <arg type="(sasssia{sv})" name="metadata" direction="out"/>
101 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="unity::storage::internal::ItemMetadata"/>
102 </method>
103
104@@ -160,7 +163,7 @@
105 -->
106 <method name="FinishUpload">
107 <arg type="s" name="upload_id" direction="in"/>
108- <arg type="(ssssia{sv})" name="metadata" direction="out"/>
109+ <arg type="(sasssia{sv})" name="metadata" direction="out"/>
110 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="unity::storage::internal::ItemMetadata"/>
111 </method>
112
113
114=== modified file 'debian/bileto_pre_release_hook'
115--- debian/bileto_pre_release_hook 2016-07-22 04:23:08 +0000
116+++ debian/bileto_pre_release_hook 2016-09-09 02:13:43 +0000
117@@ -2,7 +2,7 @@
118
119 set -eu
120
121-soversion=$(sh ./get-provider-soversion.sh)
122+soversion=$(sh ./tools/get-provider-soversion.sh)
123
124 infile=./debian/control.in
125 outfile=./debian/control
126
127=== modified file 'debian/changelog'
128--- debian/changelog 2016-08-04 07:20:09 +0000
129+++ debian/changelog 2016-09-09 02:13:43 +0000
130@@ -1,3 +1,9 @@
131+storage-framework (0.1+16.10.20160804.1-0ubuntu2) UNRELEASED; urgency=medium
132+
133+ * Merged devel at revision 64.
134+
135+ -- Michi Henning <michi.henning@canonical.com> Fri, 26 Aug 2016 14:03:02 +1000
136+
137 storage-framework (0.1+16.10.20160804.1-0ubuntu1) yakkety; urgency=medium
138
139 [ Michi Henning ]
140
141=== modified file 'demo/provider_test/CMakeLists.txt'
142--- demo/provider_test/CMakeLists.txt 2016-05-23 02:27:16 +0000
143+++ demo/provider_test/CMakeLists.txt 2016-09-09 02:13:43 +0000
144@@ -1,4 +1,3 @@
145-
146 add_definitions(-DBOOST_THREAD_VERSION=4)
147
148 add_executable(provider-test provider-test.cpp)
149
150=== modified file 'demo/provider_test/provider-test.cpp'
151--- demo/provider_test/provider-test.cpp 2016-07-26 03:30:05 +0000
152+++ demo/provider_test/provider-test.cpp 2016-09-09 02:13:43 +0000
153@@ -17,6 +17,8 @@
154 */
155
156 #include <unity/storage/provider/DownloadJob.h>
157+#include <unity/storage/provider/Exceptions.h>
158+#include <unity/storage/provider/metadata_keys.h>
159 #include <unity/storage/provider/ProviderBase.h>
160 #include <unity/storage/provider/Server.h>
161 #include <unity/storage/provider/TempfileUploadJob.h>
162@@ -32,47 +34,8 @@
163 using namespace unity::storage::provider;
164 using namespace std;
165
166-#if BOOST_VERSION >= 105600
167 using boost::make_ready_future;
168 using boost::make_exceptional_future;
169-#else
170-namespace
171-{
172-
173-boost::future<void> make_ready_future()
174-{
175- boost::promise<void> p;
176- p.set_value();
177- return p.get_future();
178-}
179-
180-template <typename T>
181-boost::future<T> make_ready_future(T& value)
182-{
183- boost::promise<T> p;
184- p.set_value(value);
185- return p.get_future();
186-}
187-
188-template <typename T>
189-boost::future<T> make_ready_future(T&& value)
190-{
191- boost::promise<T> p;
192- p.set_value(std::move(value));
193- return p.get_future();
194-}
195-
196-template <typename T, typename E>
197-boost::future<T> make_exceptional_future(E const& ex)
198-{
199- boost::promise<T> p;
200- p.set_exception(boost::copy_exception(ex));
201- return p.get_future();
202-}
203-
204-}
205-#endif
206-
207
208 class MyProvider : public ProviderBase
209 {
210@@ -140,7 +103,7 @@
211 printf("roots() called by %s (%d)\n", ctx.security_label.c_str(), ctx.pid);
212 fflush(stdout);
213 ItemList roots = {
214- {"root_id", "", "Root", "etag", ItemType::root, {}},
215+ {"root_id", {}, "Root", "etag", ItemType::root, {}},
216 };
217 return make_ready_future<ItemList>(roots);
218 }
219@@ -153,14 +116,20 @@
220 fflush(stdout);
221 if (item_id != "root_id")
222 {
223- return make_exceptional_future<tuple<ItemList,string>>(runtime_error("unknown folder"));
224+ string msg = string("Item::list(): no such item: \"") + item_id + "\"";
225+ return make_exceptional_future<tuple<ItemList,string>>(NotExistsException(msg, item_id));
226 }
227 if (page_token != "")
228 {
229- return make_exceptional_future<tuple<ItemList,string>>(runtime_error("unknown page token"));
230+ string msg = string("Item::list(): invalid page token: \"") + page_token + "\"";
231+ return make_exceptional_future<tuple<ItemList,string>>(LogicException(msg));
232 }
233- ItemList children = {
234- {"child_id", "root_id", "Child", "etag", ItemType::file, {}}
235+ ItemList children =
236+ {
237+ {
238+ "child_id", { "root_id" }, "Child", "etag", ItemType::file,
239+ { { SIZE_IN_BYTES, 0 }, { LAST_MODIFIED_TIME, "2007-04-05T14:30Z" } }
240+ }
241 };
242 boost::promise<tuple<ItemList,string>> p;
243 p.set_value(make_tuple(children, string()));
244@@ -172,12 +141,20 @@
245 {
246 printf("lookup('%s', '%s') called by %s (%d)\n", parent_id.c_str(), name.c_str(), ctx.security_label.c_str(), ctx.pid);
247 fflush(stdout);
248- if (parent_id != "root_id" || name != "Child")
249- {
250- return make_exceptional_future<ItemList>(runtime_error("file not found"));
251- }
252- ItemList children = {
253- {"child_id", "root_id", "Child", "etag", ItemType::file, {}}
254+ if (parent_id != "root_id")
255+ {
256+ string msg = string("Folder::lookup(): no such item: \"") + parent_id + "\"";
257+ return make_exceptional_future<ItemList>(NotExistsException(msg, parent_id));
258+ }
259+ if (name != "Child")
260+ {
261+ string msg = string("Folder::lookup(): no such item: \"") + name + "\"";
262+ return make_exceptional_future<ItemList>(NotExistsException(msg, name));
263+ }
264+ ItemList children =
265+ {
266+ { "child_id", { "root_id" }, "Child", "etag", ItemType::file,
267+ { { SIZE_IN_BYTES, 0 }, { LAST_MODIFIED_TIME, "2007-04-05T14:30Z" } } }
268 };
269 return make_ready_future<ItemList>(children);
270 }
271@@ -189,15 +166,24 @@
272 fflush(stdout);
273 if (item_id == "root_id")
274 {
275- Item metadata{"root_id", "", "Root", "etag", ItemType::root, {}};
276+ Item metadata{"root_id", {}, "Root", "etag", ItemType::root, {}};
277 return make_ready_future<Item>(metadata);
278 }
279 else if (item_id == "child_id")
280 {
281- Item metadata{"child_id", "root_id", "Child", "etag", ItemType::file, {}};
282- return make_ready_future<Item>(metadata);
283- }
284- return make_exceptional_future<Item>(runtime_error("no such file"));
285+ Item metadata
286+ {
287+ "child_id", { "root_id" }, "Child", "etag", ItemType::file,
288+ { { SIZE_IN_BYTES, 0 }, { LAST_MODIFIED_TIME, "2007-04-05T14:30Z" } }
289+ };
290+ return make_ready_future<Item>(metadata);
291+ }
292+ else if (item_id == "child_folder_id")
293+ {
294+ Item metadata{"child_folder_id", { "root_id" }, "Child_Folder", "etag", ItemType::folder, {}};
295+ return make_ready_future<Item>(metadata);
296+ }
297+ return make_exceptional_future<Item>(NotExistsException("metadata(): no such item: " + item_id, item_id));
298 }
299
300 boost::future<Item> MyProvider::create_folder(
301@@ -206,7 +192,7 @@
302 {
303 printf("create_folder('%s', '%s') called by %s (%d)\n", parent_id.c_str(), name.c_str(), ctx.security_label.c_str(), ctx.pid);
304 fflush(stdout);
305- Item metadata{"new_folder_id", parent_id, name, "etag", ItemType::folder, {}};
306+ Item metadata{"new_folder_id", { parent_id }, name, "etag", ItemType::folder, {}};
307 return make_ready_future<Item>(metadata);
308 }
309
310@@ -242,7 +228,12 @@
311
312 unique_ptr<DownloadJob> job(new MyDownloadJob(make_job_id()));
313 const char contents[] = "Hello world";
314- write(job->write_socket(), contents, sizeof(contents));
315+ if (write(job->write_socket(), contents, sizeof(contents)) != sizeof(contents))
316+ {
317+ ResourceException e("download(): write failed", errno);
318+ job->report_error(make_exception_ptr(e));
319+ return make_exceptional_future<unique_ptr<DownloadJob>>(e);
320+ }
321 job->report_complete();
322 return make_ready_future(std::move(job));
323 }
324@@ -261,7 +252,7 @@
325 {
326 printf("move('%s', '%s', '%s') called by %s (%d)\n", item_id.c_str(), new_parent_id.c_str(), new_name.c_str(), ctx.security_label.c_str(), ctx.pid);
327 fflush(stdout);
328- Item metadata{item_id, new_parent_id, new_name, "etag", ItemType::file, {}};
329+ Item metadata{item_id, { new_parent_id }, new_name, "etag", ItemType::file, {}};
330 return make_ready_future(metadata);
331 }
332
333@@ -271,7 +262,7 @@
334 {
335 printf("copy('%s', '%s', '%s') called by %s (%d)\n", item_id.c_str(), new_parent_id.c_str(), new_name.c_str(), ctx.security_label.c_str(), ctx.pid);
336 fflush(stdout);
337- Item metadata{"new_item_id", new_parent_id, new_name, "etag", ItemType::file, {}};
338+ Item metadata{"new_item_id", { new_parent_id }, new_name, "etag", ItemType::file, {}};
339 return make_ready_future(metadata);
340 }
341
342@@ -294,7 +285,11 @@
343 unlink(new_filename.c_str());
344 link(old_filename.c_str(), new_filename.c_str());
345
346- Item metadata{"some_id", "", "some_upload", "etag", ItemType::file, {}};
347+ Item metadata
348+ {
349+ "some_id", { "root_id" }, "some_upload", "etag", ItemType::file,
350+ { { SIZE_IN_BYTES, 10 }, { LAST_MODIFIED_TIME, "2011-04-05T14:30:10.005Z" } }
351+ };
352 return make_ready_future(metadata);
353 }
354
355
356=== modified file 'include/unity/storage/internal/ItemMetadata.h'
357--- include/unity/storage/internal/ItemMetadata.h 2016-07-12 02:22:05 +0000
358+++ include/unity/storage/internal/ItemMetadata.h 2016-09-09 02:13:43 +0000
359@@ -21,9 +21,12 @@
360 #include <unity/storage/common.h>
361
362 #pragma GCC diagnostic push
363+#pragma GCC diagnostic ignored "-Wcast-align"
364 #pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
365+#pragma GCC diagnostic ignored "-Wswitch-default"
366 #include <QMap>
367 #include <QVariant>
368+#include <QVector>
369 #pragma GCC diagnostic pop
370
371 namespace unity
372@@ -36,7 +39,7 @@
373 struct ItemMetadata
374 {
375 QString item_id;
376- QString parent_id;
377+ QVector<QString> parent_ids;
378 QString name;
379 QString etag;
380 ItemType type;
381
382=== added file 'include/unity/storage/internal/TraceMessageHandler.h'
383--- include/unity/storage/internal/TraceMessageHandler.h 1970-01-01 00:00:00 +0000
384+++ include/unity/storage/internal/TraceMessageHandler.h 2016-09-09 02:13:43 +0000
385@@ -0,0 +1,47 @@
386+/*
387+ * Copyright (C) 2015 Canonical Ltd
388+ *
389+ * This program is free software: you can redistribute it and/or modify
390+ * it under the terms of the GNU Lesser General Public License version 3 as
391+ * published by the Free Software Foundation.
392+ *
393+ * This program is distributed in the hope that it will be useful,
394+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
395+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
396+ * GNU Lesser General Public License for more details.
397+ *
398+ * You should have received a copy of the GNU Lesser General Public License
399+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
400+ *
401+ * Authors: Michi Henning <michi.henning@canonical.com>
402+ */
403+
404+#pragma once
405+
406+#pragma GCC diagnostic push
407+#pragma GCC diagnostic ignored "-Wcast-align"
408+#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
409+#pragma GCC diagnostic ignored "-Wswitch-default"
410+#include <QDebug>
411+#pragma GCC diagnostic pop
412+
413+namespace unity
414+{
415+namespace storage
416+{
417+namespace internal
418+{
419+
420+class TraceMessageHandler final
421+{
422+public:
423+ TraceMessageHandler(std::string const& prog_name);
424+ ~TraceMessageHandler();
425+
426+private:
427+ QtMessageHandler old_message_handler_;
428+};
429+
430+} // namespace internal
431+} // namespace storage
432+} // namespace unity
433
434=== added file 'include/unity/storage/internal/dbus_error.h'
435--- include/unity/storage/internal/dbus_error.h 1970-01-01 00:00:00 +0000
436+++ include/unity/storage/internal/dbus_error.h 2016-09-09 02:13:43 +0000
437@@ -0,0 +1,32 @@
438+/*
439+ * Copyright (C) 2016 Canonical Ltd
440+ *
441+ * This program is free software: you can redistribute it and/or modify
442+ * it under the terms of the GNU Lesser General Public License version 3 as
443+ * published by the Free Software Foundation.
444+ *
445+ * This program is distributed in the hope that it will be useful,
446+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
447+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
448+ * GNU Lesser General Public License for more details.
449+ *
450+ * You should have received a copy of the GNU Lesser General Public License
451+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
452+ *
453+ * Authors: Michi Henning <michi.henning@canonical.com>
454+ */
455+
456+#pragma once
457+
458+namespace unity
459+{
460+namespace storage
461+{
462+namespace internal
463+{
464+
465+constexpr char DBUS_ERROR_PREFIX[] = "com.canonical.StorageFramework.";
466+
467+} // namespace internal
468+} // namespace storage
469+} // namespace unity
470
471=== added file 'include/unity/storage/internal/dbusmarshal.h'
472--- include/unity/storage/internal/dbusmarshal.h 1970-01-01 00:00:00 +0000
473+++ include/unity/storage/internal/dbusmarshal.h 2016-09-09 02:13:43 +0000
474@@ -0,0 +1,44 @@
475+/*
476+ * Copyright (C) 2016 Canonical Ltd
477+ *
478+ * This program is free software: you can redistribute it and/or modify
479+ * it under the terms of the GNU Lesser General Public License version 3 as
480+ * published by the Free Software Foundation.
481+ *
482+ * This program is distributed in the hope that it will be useful,
483+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
484+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
485+ * GNU Lesser General Public License for more details.
486+ *
487+ * You should have received a copy of the GNU Lesser General Public License
488+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
489+ *
490+ * Authors: Michi Henning <michi.henning@canonical.com>
491+ */
492+
493+#pragma once
494+
495+#include <unity/storage/internal/ItemMetadata.h>
496+
497+#include <QDBusArgument>
498+#include <QMetaType>
499+
500+namespace unity
501+{
502+namespace storage
503+{
504+namespace internal
505+{
506+
507+QDBusArgument& operator<<(QDBusArgument& argument, ItemMetadata const& metadata);
508+QDBusArgument const& operator>>(QDBusArgument const& argument, ItemMetadata& metadata);
509+
510+QDBusArgument& operator<<(QDBusArgument& argument, QList<ItemMetadata> const& md_list);
511+QDBusArgument const& operator>>(QDBusArgument const& argument, QList<ItemMetadata>& md_list);
512+
513+} // namespace internal
514+} // storage
515+} // unity
516+
517+Q_DECLARE_METATYPE(unity::storage::internal::ItemMetadata)
518+Q_DECLARE_METATYPE(QList<unity::storage::internal::ItemMetadata>)
519
520=== modified file 'include/unity/storage/provider/CMakeLists.txt'
521--- include/unity/storage/provider/CMakeLists.txt 2016-07-11 03:28:40 +0000
522+++ include/unity/storage/provider/CMakeLists.txt 2016-09-09 02:13:43 +0000
523@@ -3,3 +3,5 @@
524
525 install(FILES ${provider_headers}
526 DESTINATION ${provider_base_includedir}/${includeprefix})
527+
528+add_subdirectory(testing)
529
530=== added file 'include/unity/storage/provider/Exceptions.h'
531--- include/unity/storage/provider/Exceptions.h 1970-01-01 00:00:00 +0000
532+++ include/unity/storage/provider/Exceptions.h 2016-09-09 02:13:43 +0000
533@@ -0,0 +1,187 @@
534+/*
535+ * Copyright (C) 2016 Canonical Ltd
536+ *
537+ * This program is free software: you can redistribute it and/or modify
538+ * it under the terms of the GNU Lesser General Public License version 3 as
539+ * published by the Free Software Foundation.
540+ *
541+ * This program is distributed in the hope that it will be useful,
542+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
543+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
544+ * GNU Lesser General Public License for more details.
545+ *
546+ * You should have received a copy of the GNU Lesser General Public License
547+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
548+ *
549+ * Authors: Michi Henning <michi.henning@canonical.com>
550+ */
551+
552+#pragma once
553+
554+#include <unity/storage/visibility.h>
555+
556+#include <string>
557+
558+namespace unity
559+{
560+namespace storage
561+{
562+namespace provider
563+{
564+
565+// Note: Adding new exception types also requires updating the marshaling and
566+// unmarshaling code for exceptions in the client and server APIs.
567+
568+/**
569+\brief Base exception class for all server-side exceptions.
570+*/
571+class UNITY_STORAGE_EXPORT StorageException : public std::exception
572+{
573+public:
574+ StorageException(std::string const& exception_type, std::string const& error_message);
575+ ~StorageException();
576+
577+ virtual char const* what() const noexcept override;
578+
579+ std::string type() const;
580+ std::string error_message() const;
581+
582+private:
583+ std::string what_string_;
584+ std::string type_;
585+ std::string error_message_;
586+};
587+
588+/**
589+\brief Indicates errors in the communication between the storage provider and the cloud service.
590+*/
591+class UNITY_STORAGE_EXPORT RemoteCommsException : public StorageException
592+{
593+public:
594+ RemoteCommsException(std::string const& error_message);
595+ ~RemoteCommsException();
596+};
597+
598+/**
599+\brief Indicates that an item does not exist or could not be found.
600+*/
601+class UNITY_STORAGE_EXPORT NotExistsException : public StorageException
602+{
603+public:
604+ NotExistsException(std::string const& error_message, std::string const& key);
605+ ~NotExistsException();
606+
607+ std::string key() const;
608+
609+private:
610+ std::string key_;
611+};
612+
613+/**
614+\brief Indicates that an item cannot be created because it exists already.
615+*/
616+class UNITY_STORAGE_EXPORT ExistsException : public StorageException
617+{
618+public:
619+ ExistsException(std::string const& error_message, std::string const& identity, std::string const& name);
620+ ~ExistsException();
621+
622+ std::string native_identity() const;
623+ std::string name() const;
624+
625+private:
626+ std::string identity_;
627+ std::string name_;
628+};
629+
630+/**
631+\brief Indicates that an upload detected a version mismatch.
632+*/
633+class UNITY_STORAGE_EXPORT ConflictException : public StorageException
634+{
635+public:
636+ ConflictException(std::string const& error_message);
637+ ~ConflictException();
638+};
639+
640+/**
641+\brief Indicates that an operation failed because of a permission problem.
642+*/
643+class UNITY_STORAGE_EXPORT PermissionException : public StorageException
644+{
645+public:
646+ PermissionException(std::string const& error_message);
647+ ~PermissionException();
648+};
649+
650+/**
651+\brief Indicates that an update failed because the provider ran out of space.
652+*/
653+class UNITY_STORAGE_EXPORT QuotaException : public StorageException
654+{
655+public:
656+ QuotaException(std::string const& error_message);
657+ ~QuotaException();
658+};
659+
660+/**
661+\brief Indicates that an upload or download was cancelled before it could complete.
662+*/
663+class UNITY_STORAGE_EXPORT CancelledException : public StorageException
664+{
665+public:
666+ CancelledException(std::string const& error_message);
667+ ~CancelledException();
668+};
669+
670+/**
671+\brief Indicates incorrect use of the API, such as calling methods in the wrong order.
672+*/
673+class UNITY_STORAGE_EXPORT LogicException : public StorageException
674+{
675+public:
676+ LogicException(std::string const& error_message);
677+ ~LogicException();
678+};
679+
680+/**
681+\brief Indicates an invalid parameter, such as a negative value when a positive one was
682+expected, or a string that does not parse correctly or is empty when it should be non-empty.
683+*/
684+class UNITY_STORAGE_EXPORT InvalidArgumentException : public StorageException
685+{
686+public:
687+ InvalidArgumentException(std::string const& error_message);
688+ ~InvalidArgumentException();
689+};
690+
691+/**
692+\brief Indicates a system error, such as failure to create a file or folder,
693+or any other (usually non-recoverable) kind of error that should not arise during normal operation.
694+*/
695+class UNITY_STORAGE_EXPORT ResourceException : public StorageException
696+{
697+public:
698+ ResourceException(std::string const& error_message, int error_code);
699+ ~ResourceException();
700+
701+ int error_code() const noexcept;
702+
703+private:
704+ int error_code_;
705+};
706+
707+/**
708+\brief Indicates that the server side caught an exception that does not derive from
709+StorageException, such as a std::exception, or caught some other unknown type (such as `int`).
710+*/
711+class UNITY_STORAGE_EXPORT UnknownException : public StorageException
712+{
713+public:
714+ UnknownException(std::string const& error_message);
715+ ~UnknownException();
716+};
717+
718+} // namespace provider
719+} // namespace storage
720+} // namespace unity
721
722=== modified file 'include/unity/storage/provider/ProviderBase.h'
723--- include/unity/storage/provider/ProviderBase.h 2016-07-14 00:17:14 +0000
724+++ include/unity/storage/provider/ProviderBase.h 2016-09-09 02:13:43 +0000
725@@ -23,6 +23,7 @@
726 #include <unity/storage/provider/Credentials.h>
727
728 #include <boost/thread/future.hpp>
729+#include <boost/variant.hpp>
730
731 #include <sys/types.h>
732 #include <string>
733@@ -48,15 +49,18 @@
734 Credentials credentials;
735 };
736
737+// Note: When growing the set of supported variant types, add new types
738+// to the *end* of the list, and update the marshaling code in dbusmarshal.cpp.
739+typedef boost::variant<std::string, int64_t> MetadataValue;
740+
741 struct UNITY_STORAGE_EXPORT Item
742 {
743 std::string item_id;
744- std::string parent_id;
745+ std::vector<std::string> parent_ids;
746 std::string name;
747 std::string etag;
748 unity::storage::ItemType type;
749- // Should be map<string,variant>
750- std::map<std::string,std::string> metadata;
751+ std::map<std::string, MetadataValue> metadata;
752 };
753
754 typedef std::vector<Item> ItemList;
755
756=== modified file 'include/unity/storage/provider/TempfileUploadJob.h'
757--- include/unity/storage/provider/TempfileUploadJob.h 2016-07-12 02:22:05 +0000
758+++ include/unity/storage/provider/TempfileUploadJob.h 2016-09-09 02:13:43 +0000
759@@ -44,6 +44,12 @@
760
761 std::string file_name() const;
762
763+ // This function should be called from your finish()
764+ // implementation to read the remaining data from the socket. If
765+ // the client has not closed the socket as expected, LogicError
766+ // will be thrown.
767+ void drain();
768+
769 protected:
770 TempfileUploadJob(internal::TempfileUploadJobImpl *p) UNITY_STORAGE_HIDDEN;
771 };
772
773=== modified file 'include/unity/storage/provider/internal/AccountData.h'
774--- include/unity/storage/provider/internal/AccountData.h 2016-07-12 02:22:05 +0000
775+++ include/unity/storage/provider/internal/AccountData.h 2016-09-09 02:13:43 +0000
776@@ -20,10 +20,15 @@
777
778 #include <unity/storage/provider/Credentials.h>
779
780+#pragma GCC diagnostic push
781+#pragma GCC diagnostic ignored "-Wcast-align"
782+#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
783+#pragma GCC diagnostic ignored "-Wswitch-default"
784 #include <OnlineAccounts/Account>
785 #include <OnlineAccounts/PendingCallWatcher>
786 #include <QObject>
787 #include <QDBusConnection>
788+#pragma GCC diagnostic pop
789
790 #include <string>
791
792
793=== modified file 'include/unity/storage/provider/internal/DBusPeerCache.h'
794--- include/unity/storage/provider/internal/DBusPeerCache.h 2016-07-12 02:22:05 +0000
795+++ include/unity/storage/provider/internal/DBusPeerCache.h 2016-09-09 02:13:43 +0000
796@@ -20,8 +20,13 @@
797 #pragma once
798
799 #include <boost/thread/future.hpp>
800+#pragma GCC diagnostic push
801+#pragma GCC diagnostic ignored "-Wcast-align"
802+#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
803+#pragma GCC diagnostic ignored "-Wswitch-default"
804 #include <QDBusConnection>
805 #include <QDBusPendingReply>
806+#pragma GCC diagnostic pop
807 #include <QString>
808
809 #include <functional>
810
811=== modified file 'include/unity/storage/provider/internal/DownloadJobImpl.h'
812--- include/unity/storage/provider/internal/DownloadJobImpl.h 2016-07-12 02:22:05 +0000
813+++ include/unity/storage/provider/internal/DownloadJobImpl.h 2016-09-09 02:13:43 +0000
814@@ -48,9 +48,6 @@
815 int write_socket() const;
816 int take_read_socket();
817
818- std::string const& sender_bus_name() const;
819- void set_sender_bus_name(std::string const& bus_name);
820-
821 void report_complete();
822 void report_error(std::exception_ptr p);
823 boost::future<void> finish(DownloadJob& job);
824@@ -63,7 +60,6 @@
825 std::string const download_id_;
826 int read_socket_ = -1;
827 int write_socket_ = -1;
828- std::string sender_bus_name_;
829
830 std::mutex completion_lock_;
831 bool completed_ = false;
832
833=== modified file 'include/unity/storage/provider/internal/Handler.h'
834--- include/unity/storage/provider/internal/Handler.h 2016-07-19 07:08:50 +0000
835+++ include/unity/storage/provider/internal/Handler.h 2016-09-09 02:13:43 +0000
836@@ -63,6 +63,8 @@
837 void finished();
838
839 private:
840+ void marshal_exception(std::exception_ptr ep);
841+
842 std::shared_ptr<AccountData> const account_;
843 Callback const callback_;
844 QDBusConnection const bus_;
845
846=== modified file 'include/unity/storage/provider/internal/MainLoopExecutor.h'
847--- include/unity/storage/provider/internal/MainLoopExecutor.h 2016-07-19 03:26:36 +0000
848+++ include/unity/storage/provider/internal/MainLoopExecutor.h 2016-09-09 02:13:43 +0000
849@@ -19,13 +19,7 @@
850 #pragma once
851
852 #include <boost/version.hpp>
853-
854-#if BOOST_VERSION >= 105600
855-# define SF_SUPPORTS_EXECUTORS
856-#endif
857-#ifdef SF_SUPPORTS_EXECUTORS
858-# include <boost/thread/executor.hpp>
859-#endif
860+#include <boost/thread/executor.hpp>
861 #include <QObject>
862
863 #include <functional>
864@@ -39,8 +33,6 @@
865 namespace internal
866 {
867
868-#ifdef SF_SUPPORTS_EXECUTORS
869-
870 /* Declare future continuations like so to execute within the event
871 * loop if possible:
872 *
873@@ -72,12 +64,6 @@
874 Q_DISABLE_COPY(MainLoopExecutor)
875 };
876
877-#else
878-
879-#define EXEC_IN_MAIN /*nothing*/
880-
881-#endif
882-
883 }
884 }
885 }
886
887=== modified file 'include/unity/storage/provider/internal/PendingJobs.h'
888--- include/unity/storage/provider/internal/PendingJobs.h 2016-07-12 02:22:05 +0000
889+++ include/unity/storage/provider/internal/PendingJobs.h 2016-09-09 02:13:43 +0000
890@@ -18,14 +18,21 @@
891
892 #pragma once
893
894+#pragma GCC diagnostic push
895+#pragma GCC diagnostic ignored "-Wcast-align"
896+#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
897+#pragma GCC diagnostic ignored "-Wswitch-default"
898 #include <QDBusConnection>
899 #include <QDBusServiceWatcher>
900 #include <QObject>
901+#include <QString>
902+#pragma GCC diagnostic pop
903
904 #include <map>
905 #include <memory>
906 #include <mutex>
907 #include <string>
908+#include <utility>
909
910 namespace unity
911 {
912@@ -49,27 +56,30 @@
913 explicit PendingJobs(QDBusConnection const& bus, QObject *parent=nullptr);
914 virtual ~PendingJobs();
915
916- void add_download(std::unique_ptr<DownloadJob> &&job);
917- std::shared_ptr<DownloadJob> get_download(std::string const& download_id);
918- std::shared_ptr<DownloadJob> remove_download(std::string const& download_id);
919+ void add_download(QString const& client_bus_name, std::unique_ptr<DownloadJob> &&job);
920+ std::shared_ptr<DownloadJob> remove_download(QString const& client_bus_name, std::string const& download_id);
921
922- void add_upload(std::unique_ptr<UploadJob> &&job);
923- std::shared_ptr<UploadJob> get_upload(std::string const& upload_id);
924- std::shared_ptr<UploadJob> remove_upload(std::string const& upload_id);
925+ void add_upload(QString const& client_bus_name, std::unique_ptr<UploadJob> &&job);
926+ std::shared_ptr<UploadJob> remove_upload(QString const& client_bus_name, std::string const& upload_id);
927
928 private Q_SLOTS:
929 void service_disconnected(QString const& service_name);
930
931 private:
932- void watch_peer(std::string const& bus_name);
933- void unwatch_peer(std::string const& bus_name);
934+ void watch_peer(QString const& bus_name);
935+ void unwatch_peer(QString const& bus_name);
936+
937+ template <typename Job>
938+ void cancel_job(std::shared_ptr<Job> const& job,
939+ std::string const& identifier);
940
941 std::mutex lock_;
942- std::map<std::string,std::shared_ptr<UploadJob>> uploads_;
943- std::map<std::string,std::shared_ptr<DownloadJob>> downloads_;
944+ // Key is client_bus_name and upload or download ID.
945+ std::map<std::pair<QString,std::string>,std::shared_ptr<UploadJob>> uploads_;
946+ std::map<std::pair<QString,std::string>,std::shared_ptr<DownloadJob>> downloads_;
947
948 QDBusServiceWatcher watcher_;
949- std::map<std::string,int> services_;
950+ std::map<QString,int> services_;
951
952 Q_DISABLE_COPY(PendingJobs)
953 };
954
955=== modified file 'include/unity/storage/provider/internal/ProviderInterface.h'
956--- include/unity/storage/provider/internal/ProviderInterface.h 2016-07-14 00:17:14 +0000
957+++ include/unity/storage/provider/internal/ProviderInterface.h 2016-09-09 02:13:43 +0000
958@@ -21,11 +21,16 @@
959 #include <unity/storage/internal/ItemMetadata.h>
960 #include <unity/storage/provider/internal/Handler.h>
961
962+#pragma GCC diagnostic push
963+#pragma GCC diagnostic ignored "-Wcast-align"
964+#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
965+#pragma GCC diagnostic ignored "-Wswitch-default"
966 #include <QObject>
967 #include <QList>
968 #include <QDBusConnection>
969 #include <QDBusContext>
970 #include <QDBusUnixFileDescriptor>
971+#pragma GCC diagnostic pop
972
973 #include <map>
974 #include <memory>
975
976=== modified file 'include/unity/storage/provider/internal/ServerImpl.h'
977--- include/unity/storage/provider/internal/ServerImpl.h 2016-07-12 02:22:05 +0000
978+++ include/unity/storage/provider/internal/ServerImpl.h 2016-09-09 02:13:43 +0000
979@@ -19,6 +19,7 @@
980 #pragma once
981
982 #include <unity/storage/provider/Server.h>
983+#include <unity/storage/internal/TraceMessageHandler.h>
984 #include <unity/storage/provider/internal/DBusPeerCache.h>
985 #include <unity/storage/provider/internal/ProviderInterface.h>
986
987@@ -58,6 +59,7 @@
988 ServerBase* const server_;
989 std::string const bus_name_;
990 std::string const service_id_;
991+ unity::storage::internal::TraceMessageHandler trace_message_handler_;
992
993 std::unique_ptr<QCoreApplication> app_;
994 std::unique_ptr<OnlineAccounts::Manager> manager_;
995
996=== modified file 'include/unity/storage/provider/internal/TempfileUploadJobImpl.h'
997--- include/unity/storage/provider/internal/TempfileUploadJobImpl.h 2016-07-12 02:22:05 +0000
998+++ include/unity/storage/provider/internal/TempfileUploadJobImpl.h 2016-09-09 02:13:43 +0000
999@@ -20,8 +20,12 @@
1000
1001 #include <unity/storage/provider/internal/UploadJobImpl.h>
1002
1003+#pragma GCC diagnostic push
1004+#pragma GCC diagnostic ignored "-Wcast-align"
1005+#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
1006 #include <QLocalSocket>
1007 #include <QTemporaryFile>
1008+#pragma GCC diagnostic pop
1009
1010 #include <memory>
1011 #include <string>
1012@@ -43,6 +47,7 @@
1013 virtual ~TempfileUploadJobImpl();
1014
1015 void complete_init() override;
1016+ void drain();
1017
1018 std::string file_name() const;
1019
1020@@ -51,8 +56,8 @@
1021 void on_read_channel_finished();
1022
1023 private:
1024+ std::unique_ptr<QTemporaryFile> tmpfile_;
1025 std::unique_ptr<QLocalSocket> reader_;
1026- std::unique_ptr<QTemporaryFile> tmpfile_;
1027
1028 Q_DISABLE_COPY(TempfileUploadJobImpl)
1029 };
1030
1031=== added file 'include/unity/storage/provider/internal/TestServerImpl.h'
1032--- include/unity/storage/provider/internal/TestServerImpl.h 1970-01-01 00:00:00 +0000
1033+++ include/unity/storage/provider/internal/TestServerImpl.h 2016-09-09 02:13:43 +0000
1034@@ -0,0 +1,65 @@
1035+/*
1036+ * Copyright (C) 2016 Canonical Ltd
1037+ *
1038+ * This program is free software: you can redistribute it and/or modify
1039+ * it under the terms of the GNU Lesser General Public License version 3 as
1040+ * published by the Free Software Foundation.
1041+ *
1042+ * This program is distributed in the hope that it will be useful,
1043+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1044+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1045+ * GNU Lesser General Public License for more details.
1046+ *
1047+ * You should have received a copy of the GNU Lesser General Public License
1048+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1049+ *
1050+ * Authors: James Henstridge <james.henstridge@canonical.com>
1051+ */
1052+
1053+#pragma once
1054+
1055+#include <unity/storage/provider/testing/TestServer.h>
1056+
1057+#pragma GCC diagnostic push
1058+#pragma GCC diagnostic ignored "-Wcast-align"
1059+#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
1060+#include <QDBusConnection>
1061+#pragma GCC diagnostic pop
1062+
1063+#include <memory>
1064+#include <string>
1065+
1066+namespace unity
1067+{
1068+namespace storage
1069+{
1070+namespace provider
1071+{
1072+namespace internal
1073+{
1074+
1075+class ProviderInterface;
1076+
1077+class TestServerImpl
1078+{
1079+public:
1080+ TestServerImpl(std::unique_ptr<ProviderBase>&& provider,
1081+ OnlineAccounts::Account* account,
1082+ QDBusConnection const& connection,
1083+ std::string const& object_path);
1084+ ~TestServerImpl();
1085+
1086+ QDBusConnection const& connection() const;
1087+ std::string const& object_path() const;
1088+
1089+private:
1090+ QDBusConnection connection_;
1091+ std::string const object_path_;
1092+
1093+ std::unique_ptr<ProviderInterface> interface_;
1094+};
1095+
1096+}
1097+}
1098+}
1099+}
1100
1101=== modified file 'include/unity/storage/provider/internal/UploadJobImpl.h'
1102--- include/unity/storage/provider/internal/UploadJobImpl.h 2016-07-12 02:22:05 +0000
1103+++ include/unity/storage/provider/internal/UploadJobImpl.h 2016-09-09 02:13:43 +0000
1104@@ -21,7 +21,11 @@
1105 #include <unity/storage/provider/ProviderBase.h>
1106
1107 #include <boost/thread/future.hpp>
1108+#pragma GCC diagnostic push
1109+#pragma GCC diagnostic ignored "-Wcast-align"
1110+#pragma GCC diagnostic ignored "-Wswitch-default"
1111 #include <QObject>
1112+#pragma GCC diagnostic pop
1113
1114 #include <exception>
1115 #include <mutex>
1116@@ -49,9 +53,6 @@
1117 int read_socket() const;
1118 int take_write_socket();
1119
1120- std::string const& sender_bus_name() const;
1121- void set_sender_bus_name(std::string const& bus_name);
1122-
1123 void report_error(std::exception_ptr p);
1124 boost::future<Item> finish(UploadJob& job);
1125 boost::future<void> cancel(UploadJob& job);
1126@@ -63,7 +64,6 @@
1127 std::string const upload_id_;
1128 int read_socket_ = -1;
1129 int write_socket_ = -1;
1130- std::string sender_bus_name_;
1131
1132 std::mutex completion_lock_;
1133 bool completed_ = false;
1134
1135=== modified file 'include/unity/storage/provider/internal/dbusmarshal.h'
1136--- include/unity/storage/provider/internal/dbusmarshal.h 2016-07-12 02:22:05 +0000
1137+++ include/unity/storage/provider/internal/dbusmarshal.h 2016-09-09 02:13:43 +0000
1138@@ -18,8 +18,15 @@
1139
1140 #pragma once
1141
1142+#include <unity/storage/provider/ProviderBase.h>
1143+
1144+#pragma GCC diagnostic push
1145+#pragma GCC diagnostic ignored "-Wcast-align"
1146+#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
1147 #include <QDBusArgument>
1148 #include <QVariant>
1149+#pragma GCC diagnostic pop
1150+
1151 #include <vector>
1152
1153 namespace unity
1154
1155=== renamed file 'include/unity/storage/internal/MetadataKeys.h' => 'include/unity/storage/provider/metadata_keys.h'
1156--- include/unity/storage/internal/MetadataKeys.h 2016-07-14 00:25:40 +0000
1157+++ include/unity/storage/provider/metadata_keys.h 2016-09-09 02:13:43 +0000
1158@@ -18,15 +18,28 @@
1159
1160 #pragma once
1161
1162+#include <unordered_map>
1163+
1164 namespace unity
1165 {
1166 namespace storage
1167 {
1168-namespace internal
1169-{
1170-
1171-static char constexpr CREATION_TIME[] = "creation_time";
1172-
1173-} // namespace internal
1174+namespace provider
1175+{
1176+
1177+static char constexpr SIZE_IN_BYTES[] = "size_in_bytes"; // int64_t, >= 0
1178+static char constexpr CREATION_TIME[] = "creation_time"; // String, ISO 8601 format
1179+static char constexpr LAST_MODIFIED_TIME[] = "last_modified_time"; // String, ISO 8601 format
1180+
1181+enum class MetadataType { int64, iso_8601_date_time };
1182+
1183+static std::unordered_map<std::string, MetadataType> known_metadata =
1184+{
1185+ { SIZE_IN_BYTES, MetadataType::int64 },
1186+ { CREATION_TIME, MetadataType::iso_8601_date_time },
1187+ { LAST_MODIFIED_TIME, MetadataType::iso_8601_date_time }
1188+};
1189+
1190+} // namespace provider
1191 } // namespace storage
1192 } // namespace unity
1193
1194=== added directory 'include/unity/storage/provider/testing'
1195=== added file 'include/unity/storage/provider/testing/CMakeLists.txt'
1196--- include/unity/storage/provider/testing/CMakeLists.txt 1970-01-01 00:00:00 +0000
1197+++ include/unity/storage/provider/testing/CMakeLists.txt 2016-09-09 02:13:43 +0000
1198@@ -0,0 +1,5 @@
1199+set(includeprefix unity/storage/provider/testing)
1200+file(GLOB provider_headers *.h)
1201+
1202+install(FILES ${provider_headers}
1203+ DESTINATION ${provider_base_includedir}/${includeprefix})
1204
1205=== added file 'include/unity/storage/provider/testing/TestServer.h'
1206--- include/unity/storage/provider/testing/TestServer.h 1970-01-01 00:00:00 +0000
1207+++ include/unity/storage/provider/testing/TestServer.h 2016-09-09 02:13:43 +0000
1208@@ -0,0 +1,68 @@
1209+/*
1210+ * Copyright (C) 2016 Canonical Ltd
1211+ *
1212+ * This program is free software: you can redistribute it and/or modify
1213+ * it under the terms of the GNU Lesser General Public License version 3 as
1214+ * published by the Free Software Foundation.
1215+ *
1216+ * This program is distributed in the hope that it will be useful,
1217+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1218+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1219+ * GNU Lesser General Public License for more details.
1220+ *
1221+ * You should have received a copy of the GNU Lesser General Public License
1222+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1223+ *
1224+ * Authors: James Henstridge <james.henstridge@canonical.com>
1225+ */
1226+
1227+#pragma once
1228+
1229+#include <unity/storage/visibility.h>
1230+
1231+#include <memory>
1232+#include <string>
1233+
1234+namespace OnlineAccounts
1235+{
1236+class Account;
1237+}
1238+class QDBusConnection;
1239+
1240+namespace unity
1241+{
1242+namespace storage
1243+{
1244+namespace provider
1245+{
1246+
1247+class ProviderBase;
1248+
1249+namespace internal
1250+{
1251+class TestServerImpl;
1252+}
1253+
1254+namespace testing
1255+{
1256+
1257+class UNITY_STORAGE_EXPORT TestServer
1258+{
1259+public:
1260+ TestServer(std::unique_ptr<ProviderBase>&& provider,
1261+ OnlineAccounts::Account* account,
1262+ QDBusConnection const& connection,
1263+ std::string const& object_path);
1264+ ~TestServer();
1265+
1266+ QDBusConnection const& connection() const;
1267+ std::string const& object_path() const;
1268+
1269+private:
1270+ std::unique_ptr<internal::TestServerImpl> p_;
1271+};
1272+
1273+}
1274+}
1275+}
1276+}
1277
1278=== modified file 'include/unity/storage/qt/client/Account.h'
1279--- include/unity/storage/qt/client/Account.h 2016-07-22 02:35:12 +0000
1280+++ include/unity/storage/qt/client/Account.h 2016-09-09 02:13:43 +0000
1281@@ -77,7 +77,7 @@
1282
1283 typedef std::shared_ptr<Account> SPtr;
1284
1285- Runtime* runtime() const;
1286+ std::shared_ptr<Runtime> runtime() const;
1287
1288 QString owner() const;
1289 QString owner_id() const;
1290
1291=== modified file 'include/unity/storage/qt/client/Exceptions.h'
1292--- include/unity/storage/qt/client/Exceptions.h 2016-07-22 02:35:12 +0000
1293+++ include/unity/storage/qt/client/Exceptions.h 2016-09-09 02:13:43 +0000
1294@@ -20,7 +20,10 @@
1295
1296 #include <unity/storage/visibility.h>
1297
1298+#pragma GCC diagnostic push
1299+#pragma GCC diagnostic ignored "-Wcast-align"
1300 #include <QException>
1301+#pragma GCC diagnostic pop
1302 #include <QString>
1303
1304 namespace unity
1305@@ -46,6 +49,8 @@
1306
1307 virtual char const* what() const noexcept override;
1308
1309+ QString error_message() const;
1310+
1311 private:
1312 std::string what_string_;
1313 QString error_message_;
1314@@ -83,18 +88,16 @@
1315 class UNITY_STORAGE_EXPORT DeletedException : public StorageException
1316 {
1317 public:
1318- DeletedException(QString const& error_message, QString const& identity_, QString const& name_);
1319+ DeletedException(QString const& error_message, QString const& identity_);
1320 ~DeletedException();
1321
1322 virtual DeletedException* clone() const override;
1323 virtual void raise() const override;
1324
1325 QString native_identity() const;
1326- QString name() const;
1327
1328 private:
1329 QString identity_;
1330- QString name_;
1331 };
1332
1333 /**
1334@@ -228,17 +231,22 @@
1335 };
1336
1337 /**
1338-\brief Indicates a system error, such as failure to to create a file or folder,
1339+\brief Indicates a system error, such as failure to create a file or folder,
1340 or any other (usually non-recoverable) kind of error that should not arise during normal operation.
1341 */
1342 class UNITY_STORAGE_EXPORT ResourceException : public StorageException
1343 {
1344 public:
1345- ResourceException(QString const& error_message);
1346+ ResourceException(QString const& error_message, int error_code);
1347 ~ResourceException();
1348
1349 virtual ResourceException* clone() const override;
1350 virtual void raise() const override;
1351+
1352+ int error_code() const noexcept;
1353+
1354+private:
1355+ int error_code_;
1356 };
1357
1358 } // namespace client
1359
1360=== modified file 'include/unity/storage/qt/client/Item.h'
1361--- include/unity/storage/qt/client/Item.h 2016-07-22 02:45:24 +0000
1362+++ include/unity/storage/qt/client/Item.h 2016-09-09 02:13:43 +0000
1363@@ -103,7 +103,7 @@
1364
1365 If this item is a root, the returned pointer points at this item.
1366 */
1367- Root* root() const;
1368+ std::shared_ptr<Root> root() const;
1369
1370 /**
1371 \brief Returns the type of the item.
1372
1373=== modified file 'include/unity/storage/qt/client/Root.h'
1374--- include/unity/storage/qt/client/Root.h 2016-07-12 02:22:05 +0000
1375+++ include/unity/storage/qt/client/Root.h 2016-09-09 02:13:43 +0000
1376@@ -70,7 +70,7 @@
1377 /**
1378 \brief Returns the account for this root.
1379 */
1380- Account* account() const;
1381+ std::shared_ptr<Account> account() const;
1382
1383 QFuture<int64_t> free_space_bytes() const;
1384 QFuture<int64_t> used_space_bytes() const;
1385
1386=== modified file 'include/unity/storage/qt/client/Runtime.h'
1387--- include/unity/storage/qt/client/Runtime.h 2016-07-22 02:35:12 +0000
1388+++ include/unity/storage/qt/client/Runtime.h 2016-09-09 02:13:43 +0000
1389@@ -44,6 +44,7 @@
1390 namespace internal
1391 {
1392
1393+class AccountBase;
1394 class RuntimeBase;
1395
1396 namespace remote_client
1397@@ -95,11 +96,23 @@
1398
1399 QFuture<QVector<std::shared_ptr<Account>>> accounts();
1400
1401+ /// @cond
1402+ /**
1403+ \brief Creates an Account object pointing at (bus_name, object_path)
1404+
1405+ This method is intended for use in tests, where you want to talk
1406+ to a provider that has already been set up on the bus.
1407+ */
1408+ std::shared_ptr<Account> make_test_account(QString const& bus_name,
1409+ QString const& object_path);
1410+ /// @endcond
1411+
1412 private:
1413 Runtime(internal::RuntimeBase* p) UNITY_STORAGE_HIDDEN;
1414
1415 std::shared_ptr<internal::RuntimeBase> p_;
1416
1417+ friend class internal::AccountBase;
1418 friend class internal::remote_client::AccountImpl;
1419 };
1420
1421
1422=== modified file 'include/unity/storage/qt/client/Uploader.h'
1423--- include/unity/storage/qt/client/Uploader.h 2016-07-22 02:35:12 +0000
1424+++ include/unity/storage/qt/client/Uploader.h 2016-09-09 02:13:43 +0000
1425@@ -92,6 +92,14 @@
1426 std::shared_ptr<QLocalSocket> socket() const;
1427
1428 /**
1429+ \brief Returns the size that was passed to Folder::create_file() or File::create_uploader().
1430+
1431+ \return The number of bytes that the uploader expects to be written to the `QLocalSocket` returned
1432+ from socket().
1433+ */
1434+ int64_t size() const;
1435+
1436+ /**
1437 \brief Finalizes the upload.
1438
1439 Once you have written the file contents to the socket returned by socket(), you must call finish_upload(),
1440
1441=== modified file 'include/unity/storage/qt/client/internal/AccountBase.h'
1442--- include/unity/storage/qt/client/internal/AccountBase.h 2016-07-22 02:35:12 +0000
1443+++ include/unity/storage/qt/client/internal/AccountBase.h 2016-09-09 02:13:43 +0000
1444@@ -52,7 +52,7 @@
1445 AccountBase(AccountBase const&) = delete;
1446 AccountBase& operator=(AccountBase const&) = delete;
1447
1448- Runtime* runtime() const;
1449+ std::shared_ptr<Runtime> runtime() const;
1450 virtual QString owner() const = 0;
1451 virtual QString owner_id() const = 0;
1452 virtual QString description() const = 0;
1453
1454=== modified file 'include/unity/storage/qt/client/internal/ItemBase.h'
1455--- include/unity/storage/qt/client/internal/ItemBase.h 2016-07-27 02:19:17 +0000
1456+++ include/unity/storage/qt/client/internal/ItemBase.h 2016-09-09 02:13:43 +0000
1457@@ -20,10 +20,10 @@
1458
1459 #include <unity/storage/common.h>
1460
1461-#include <QDateTime>
1462 #pragma GCC diagnostic push
1463 #pragma GCC diagnostic ignored "-Wcast-align"
1464 #pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
1465+#include <QDateTime>
1466 #include <QFuture>
1467 #pragma GCC diagnostic pop
1468 #include <QVariantMap>
1469@@ -60,7 +60,7 @@
1470
1471 QString native_identity() const;
1472 ItemType type() const;
1473- Root* root() const;
1474+ std::shared_ptr<Root> root() const;
1475
1476 virtual QString name() const = 0;
1477 virtual QString etag() const = 0;
1478@@ -82,10 +82,14 @@
1479 void set_public_instance(std::weak_ptr<Item> p);
1480
1481 protected:
1482+ std::shared_ptr<Root> get_root() const noexcept;
1483+ void throw_if_destroyed(QString const& method) const;
1484+
1485 const QString identity_;
1486 const ItemType type_;
1487 std::weak_ptr<Root> root_;
1488 std::weak_ptr<Item> public_instance_;
1489+ bool deleted_ = false;
1490
1491 friend class ItemImpl;
1492 };
1493
1494=== modified file 'include/unity/storage/qt/client/internal/RootBase.h'
1495--- include/unity/storage/qt/client/internal/RootBase.h 2016-07-12 02:22:05 +0000
1496+++ include/unity/storage/qt/client/internal/RootBase.h 2016-09-09 02:13:43 +0000
1497@@ -46,7 +46,7 @@
1498 public:
1499 RootBase(QString const& identity, std::weak_ptr<Account> const& account);
1500
1501- Account* account() const;
1502+ std::shared_ptr<Account> account() const;
1503 virtual QFuture<int64_t> free_space_bytes() const = 0;
1504 virtual QFuture<int64_t> used_space_bytes() const = 0;
1505 virtual QFuture<Item::SPtr> get(QString native_identity) const = 0;
1506
1507=== modified file 'include/unity/storage/qt/client/internal/RuntimeBase.h'
1508--- include/unity/storage/qt/client/internal/RuntimeBase.h 2016-07-22 02:35:12 +0000
1509+++ include/unity/storage/qt/client/internal/RuntimeBase.h 2016-09-09 02:13:43 +0000
1510@@ -25,7 +25,6 @@
1511 #pragma GCC diagnostic pop
1512 #include <QVector>
1513
1514-#include <atomic>
1515 #include <memory>
1516
1517 namespace unity
1518@@ -43,23 +42,29 @@
1519 namespace internal
1520 {
1521
1522+class AccountBase;
1523+
1524 class RuntimeBase : public QObject
1525 {
1526 public:
1527- RuntimeBase();
1528+ RuntimeBase() = default;
1529 virtual ~RuntimeBase() = default;
1530 RuntimeBase(RuntimeBase const&) = delete;
1531 RuntimeBase& operator=(RuntimeBase const&) = delete;
1532
1533 virtual void shutdown() = 0;
1534 virtual QFuture<QVector<std::shared_ptr<Account>>> accounts() = 0;
1535+ virtual std::shared_ptr<Account> make_test_account(QString const& bus_name,
1536+ QString const& object_path) = 0;
1537
1538 void set_public_instance(std::weak_ptr<Runtime> p);
1539
1540 protected:
1541- std::atomic_bool destroyed_;
1542- QVector<std::shared_ptr<Account>> accounts_; // Immutable once set
1543+ bool destroyed_ = false;
1544+ QVector<std::shared_ptr<Account>> accounts_;
1545 std::weak_ptr<Runtime> public_instance_; // Immutable once set
1546+
1547+ friend class unity::storage::qt::client::internal::AccountBase;
1548 };
1549
1550 } // namespace internal
1551
1552=== modified file 'include/unity/storage/qt/client/internal/UploaderBase.h'
1553--- include/unity/storage/qt/client/internal/UploaderBase.h 2016-07-22 02:35:12 +0000
1554+++ include/unity/storage/qt/client/internal/UploaderBase.h 2016-09-09 02:13:43 +0000
1555@@ -47,7 +47,7 @@
1556 class UploaderBase : public QObject
1557 {
1558 public:
1559- UploaderBase(ConflictPolicy policy);
1560+ UploaderBase(ConflictPolicy policy, int64_t size);
1561 UploaderBase(UploaderBase&) = delete;
1562 UploaderBase& operator=(UploaderBase const&) = delete;
1563
1564@@ -55,8 +55,11 @@
1565 virtual QFuture<std::shared_ptr<File>> finish_upload() = 0;
1566 virtual QFuture<void> cancel() noexcept = 0;
1567
1568+ int64_t size() const;
1569+
1570 protected:
1571 ConflictPolicy policy_;
1572+ int64_t size_;
1573 };
1574
1575 } // namespace internal
1576
1577=== modified file 'include/unity/storage/qt/client/internal/local_client/DownloaderImpl.h'
1578--- include/unity/storage/qt/client/internal/local_client/DownloaderImpl.h 2016-07-14 04:50:36 +0000
1579+++ include/unity/storage/qt/client/internal/local_client/DownloaderImpl.h 2016-09-09 02:13:43 +0000
1580@@ -60,7 +60,7 @@
1581
1582 private:
1583 void read_and_write_chunk();
1584- void handle_error(QString const& msg);
1585+ void handle_error(QString const& msg, int error_code);
1586
1587 enum State { in_progress, finalized, cancelled, error };
1588
1589@@ -73,6 +73,7 @@
1590 QFutureInterface<void>& worker_initialized_;
1591 qint64 bytes_to_write_;
1592 QString error_msg_;
1593+ int error_code_ = 0;
1594 };
1595
1596 class DownloadThread : public QThread
1597
1598=== modified file 'include/unity/storage/qt/client/internal/local_client/FolderImpl.h'
1599--- include/unity/storage/qt/client/internal/local_client/FolderImpl.h 2016-07-14 00:17:14 +0000
1600+++ include/unity/storage/qt/client/internal/local_client/FolderImpl.h 2016-09-09 02:13:43 +0000
1601@@ -40,6 +40,7 @@
1602 FolderImpl(QString const& identity);
1603 FolderImpl(QString const& identity, ItemType type);
1604
1605+ virtual QString name() const override;
1606 QFuture<QVector<std::shared_ptr<Item>>> list() const override;
1607 QFuture<QVector<std::shared_ptr<Item>>> lookup(QString const& name) const override;
1608 QFuture<std::shared_ptr<Folder>> create_folder(QString const& name) override;
1609
1610=== modified file 'include/unity/storage/qt/client/internal/local_client/ItemImpl.h'
1611--- include/unity/storage/qt/client/internal/local_client/ItemImpl.h 2016-07-27 02:19:17 +0000
1612+++ include/unity/storage/qt/client/internal/local_client/ItemImpl.h 2016-09-09 02:13:43 +0000
1613@@ -47,7 +47,6 @@
1614 ItemImpl(QString const& identity, ItemType type);
1615 virtual ~ItemImpl();
1616
1617- virtual QString name() const override;
1618 virtual QString etag() const override;
1619 virtual QVariantMap metadata() const override;
1620 virtual QDateTime last_modified_time() const override;
1621@@ -65,20 +64,18 @@
1622 void set_timestamps() noexcept;
1623 bool has_conflict() const noexcept;
1624
1625- std::unique_lock<std::mutex> get_lock();
1626-
1627 protected:
1628 static boost::filesystem::path sanitize(QString const& name, QString const& method);
1629 static bool is_reserved_path(boost::filesystem::path const& path) noexcept;
1630
1631- DeletedException deleted_ex(QString const& method) const noexcept;
1632-
1633- bool deleted_;
1634 QString name_;
1635 QString etag_;
1636 QDateTime modified_time_;
1637 QVariantMap metadata_;
1638- std::mutex mutable mutex_;
1639+ std::recursive_mutex mutable mutex_;
1640+
1641+private:
1642+ static void copy_recursively(boost::filesystem::path const& source, boost::filesystem::path const& target);
1643 };
1644
1645 } // namespace local_client
1646
1647=== modified file 'include/unity/storage/qt/client/internal/local_client/RuntimeImpl.h'
1648--- include/unity/storage/qt/client/internal/local_client/RuntimeImpl.h 2016-07-12 02:22:05 +0000
1649+++ include/unity/storage/qt/client/internal/local_client/RuntimeImpl.h 2016-09-09 02:13:43 +0000
1650@@ -41,6 +41,8 @@
1651
1652 virtual void shutdown() override;
1653 virtual QFuture<QVector<std::shared_ptr<Account>>> accounts() override;
1654+ virtual std::shared_ptr<Account> make_test_account(QString const& bus_name,
1655+ QString const& object_path) override;
1656 };
1657
1658 } // namespace local_client
1659
1660=== modified file 'include/unity/storage/qt/client/internal/local_client/UploaderImpl.h'
1661--- include/unity/storage/qt/client/internal/local_client/UploaderImpl.h 2016-07-26 01:51:26 +0000
1662+++ include/unity/storage/qt/client/internal/local_client/UploaderImpl.h 2016-09-09 02:13:43 +0000
1663@@ -68,12 +68,11 @@
1664 private Q_SLOTS:
1665 void on_bytes_ready();
1666 void on_read_channel_finished();
1667- void on_error();
1668
1669 private:
1670 void read_and_write_chunk();
1671 void finalize();
1672- void handle_error(QString const& msg);
1673+ void handle_error(QString const& msg, int error_code);
1674
1675 enum State { in_progress, finalized, cancelled, error };
1676
1677@@ -91,6 +90,7 @@
1678 QFutureInterface<std::shared_ptr<File>>& qf_;
1679 QFutureInterface<void>& worker_initialized_;
1680 QString error_msg_;
1681+ int error_code_ = 0;
1682 bool use_linkat_ = true;
1683 };
1684
1685
1686=== added file 'include/unity/storage/qt/client/internal/local_client/storage_exception.h'
1687--- include/unity/storage/qt/client/internal/local_client/storage_exception.h 1970-01-01 00:00:00 +0000
1688+++ include/unity/storage/qt/client/internal/local_client/storage_exception.h 2016-09-09 02:13:43 +0000
1689@@ -0,0 +1,94 @@
1690+/*
1691+ * Copyright (C) 2016 Canonical Ltd
1692+ *
1693+ * This program is free software: you can redistribute it and/or modify
1694+ * it under the terms of the GNU Lesser General Public License version 3 as
1695+ * published by the Free Software Foundation.
1696+ *
1697+ * This program is distributed in the hope that it will be useful,
1698+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1699+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1700+ * GNU Lesser General Public License for more details.
1701+ *
1702+ * You should have received a copy of the GNU Lesser General Public License
1703+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1704+ *
1705+ * Authors: Michi Henning <michi.henning@canonical.com>
1706+ */
1707+
1708+#pragma once
1709+
1710+#include <unity/storage/qt/client/Exceptions.h>
1711+#include <unity/storage/qt/client/internal/local_client/boost_filesystem.h>
1712+
1713+#pragma GCC diagnostic push
1714+#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
1715+#pragma GCC diagnostic ignored "-Wcast-align"
1716+#include <QFuture>
1717+#pragma GCC diagnostic pop
1718+#include <QFutureInterface>
1719+
1720+class QString;
1721+
1722+namespace unity
1723+{
1724+namespace storage
1725+{
1726+namespace qt
1727+{
1728+namespace client
1729+{
1730+namespace internal
1731+{
1732+namespace local_client
1733+{
1734+
1735+void throw_storage_exception(QString const& method,
1736+ std::exception_ptr ep) __attribute__ ((noreturn));
1737+
1738+void throw_storage_exception(QString const& method,
1739+ std::exception_ptr ep,
1740+ QString const& key) __attribute__ ((noreturn));
1741+
1742+template<typename T>
1743+QFuture<T> make_exceptional_future(QString const& method, std::exception_ptr ep)
1744+{
1745+ try
1746+ {
1747+ throw_storage_exception(method, ep);
1748+ }
1749+ catch (StorageException const& e)
1750+ {
1751+ QFutureInterface<T> qf;
1752+ qf.reportException(e);
1753+ qf.reportFinished();
1754+ return qf.future();
1755+ }
1756+ abort(); // Impossible. // LCOV_EXCL_LINE
1757+}
1758+
1759+template<typename T>
1760+QFuture<T> make_exceptional_future(QString const& method,
1761+ std::exception_ptr ep,
1762+ QString const& key)
1763+{
1764+ try
1765+ {
1766+ throw_storage_exception(method, ep, key);
1767+ }
1768+ catch (StorageException const& e)
1769+ {
1770+ QFutureInterface<T> qf;
1771+ qf.reportException(e);
1772+ qf.reportFinished();
1773+ return qf.future();
1774+ }
1775+ abort(); // Impossible. // LCOV_EXCL_LINE
1776+}
1777+
1778+} // namespace local_client
1779+} // namespace internal
1780+} // namespace client
1781+} // namespace qt
1782+} // namespace storage
1783+} // namespace unity
1784
1785=== renamed file 'include/unity/storage/qt/client/internal/local_client/tmpfile-prefix.h' => 'include/unity/storage/qt/client/internal/local_client/tmpfile_prefix.h'
1786=== modified file 'include/unity/storage/qt/client/internal/make_future.h'
1787--- include/unity/storage/qt/client/internal/make_future.h 2016-07-22 02:35:12 +0000
1788+++ include/unity/storage/qt/client/internal/make_future.h 2016-09-09 02:13:43 +0000
1789@@ -36,40 +36,30 @@
1790 namespace internal
1791 {
1792
1793+template<typename T>
1794+QFuture<T>
1795+__attribute__ ((warn_unused_result))
1796+make_ready_future(T const& val)
1797+{
1798+ QFutureInterface<T> qf;
1799+ qf.reportResult(val);
1800+ qf.reportFinished();
1801+ return qf.future();
1802+}
1803+
1804 template<typename T = void>
1805-QFuture<T> make_ready_future()
1806+QFuture<T>
1807+__attribute__ ((warn_unused_result))
1808+make_ready_future()
1809 {
1810 QFutureInterface<void> qf;
1811- qf.reportFinished();
1812- return qf.future();
1813-}
1814-
1815-template<typename T = void>
1816-QFuture<T> make_ready_future(QFutureInterface<T> qf)
1817-{
1818- qf.reportFinished();
1819- return qf.future();
1820-}
1821-
1822-template<typename T>
1823-QFuture<T> make_ready_future(T const& val)
1824-{
1825- QFutureInterface<T> qf;
1826- qf.reportResult(val);
1827- qf.reportFinished();
1828- return qf.future();
1829-}
1830-
1831-template<typename T>
1832-QFuture<T> make_ready_future(QFutureInterface<T> qf, T const& val)
1833-{
1834- qf.reportResult(val);
1835- qf.reportFinished();
1836- return qf.future();
1837+ return make_ready_future(qf);
1838 }
1839
1840 template<typename E>
1841-QFuture<void> make_exceptional_future(E const& ex)
1842+QFuture<void>
1843+__attribute__
1844+((warn_unused_result)) make_exceptional_future(E const& ex)
1845 {
1846 QFutureInterface<void> qf;
1847 qf.reportException(ex);
1848@@ -78,7 +68,9 @@
1849 }
1850
1851 template<typename T, typename E>
1852-QFuture<T> make_exceptional_future(E const& ex)
1853+QFuture<T>
1854+__attribute__ ((warn_unused_result))
1855+make_exceptional_future(E const& ex)
1856 {
1857 QFutureInterface<T> qf;
1858 qf.reportException(ex);
1859@@ -86,14 +78,6 @@
1860 return qf.future();
1861 }
1862
1863-template<typename T, typename E>
1864-QFuture<T> make_exceptional_future(QFutureInterface<T> qf, E const& ex)
1865-{
1866- qf.reportException(ex);
1867- qf.reportFinished();
1868- return qf.future();
1869-}
1870-
1871 } // namespace internal
1872 } // namespace client
1873 } // namespace qt
1874
1875=== modified file 'include/unity/storage/qt/client/internal/remote_client/AccountImpl.h'
1876--- include/unity/storage/qt/client/internal/remote_client/AccountImpl.h 2016-07-15 03:56:14 +0000
1877+++ include/unity/storage/qt/client/internal/remote_client/AccountImpl.h 2016-09-09 02:13:43 +0000
1878@@ -39,7 +39,8 @@
1879 {
1880 public:
1881 AccountImpl(std::weak_ptr<Runtime> const& runtime,
1882- int account_id,
1883+ QString const& bus_name,
1884+ QString const& object_path,
1885 QString const& owner,
1886 QString const& owner_id,
1887 QString const& description);
1888
1889=== modified file 'include/unity/storage/qt/client/internal/remote_client/Handler.h'
1890--- include/unity/storage/qt/client/internal/remote_client/Handler.h 2016-07-15 03:58:35 +0000
1891+++ include/unity/storage/qt/client/internal/remote_client/Handler.h 2016-09-09 02:13:43 +0000
1892@@ -20,10 +20,13 @@
1893
1894 #include <unity/storage/qt/client/Exceptions.h>
1895 #include <unity/storage/qt/client/internal/make_future.h>
1896+#include <unity/storage/qt/client/internal/remote_client/dbusmarshal.h>
1897 #include <unity/storage/qt/client/internal/remote_client/HandlerBase.h>
1898
1899 #include <QDBusPendingReply>
1900
1901+#include <cassert>
1902+
1903 namespace unity
1904 {
1905 namespace storage
1906@@ -72,8 +75,41 @@
1907 {
1908 if (call.isError())
1909 {
1910- qDebug() << call.error().message(); // TODO, remove this
1911- make_exceptional_future<T>(ResourceException("DBus error return"));
1912+ try
1913+ {
1914+ auto ep = unmarshal_exception(call);
1915+ std::rethrow_exception(ep);
1916+ }
1917+ // We catch some exceptions that are "surprising" so we can log those.
1918+ catch (LocalCommsException const& e)
1919+ {
1920+ qCritical() << "provider exception:" << e.what();
1921+ qf_.reportException(e);
1922+ qf_.reportFinished();
1923+ }
1924+ catch (RemoteCommsException const& e)
1925+ {
1926+ qCritical() << "provider exception:" << e.what();
1927+ qf_.reportException(e);
1928+ qf_.reportFinished();
1929+ }
1930+ catch (ResourceException const& e)
1931+ {
1932+ qCritical() << "provider exception:" << e.what();
1933+ qf_.reportException(e);
1934+ qf_.reportFinished();
1935+ }
1936+ catch (StorageException const& e)
1937+ {
1938+ qf_.reportException(e);
1939+ qf_.reportFinished();
1940+ }
1941+ // LCOV_EXCL_START
1942+ catch (...)
1943+ {
1944+ abort(); // Impossible.
1945+ }
1946+ // LCOV_EXCL_STOP
1947 return;
1948 }
1949 // TODO: See HACK above. Should just be closure(call, qf_);
1950
1951=== modified file 'include/unity/storage/qt/client/internal/remote_client/ItemImpl.h'
1952--- include/unity/storage/qt/client/internal/remote_client/ItemImpl.h 2016-07-22 00:17:24 +0000
1953+++ include/unity/storage/qt/client/internal/remote_client/ItemImpl.h 2016-09-09 02:13:43 +0000
1954@@ -66,9 +66,6 @@
1955 static std::shared_ptr<Item> make_item(storage::internal::ItemMetadata const& md, std::weak_ptr<Root> root);
1956
1957 protected:
1958- DeletedException deleted_ex(QString const& method) const noexcept;
1959-
1960- bool deleted_ = false;
1961 storage::internal::ItemMetadata md_;
1962
1963 friend class DeleteHandler;
1964
1965=== modified file 'include/unity/storage/qt/client/internal/remote_client/RuntimeImpl.h'
1966--- include/unity/storage/qt/client/internal/remote_client/RuntimeImpl.h 2016-07-22 00:17:24 +0000
1967+++ include/unity/storage/qt/client/internal/remote_client/RuntimeImpl.h 2016-09-09 02:13:43 +0000
1968@@ -50,6 +50,8 @@
1969
1970 virtual void shutdown() override;
1971 virtual QFuture<QVector<std::shared_ptr<Account>>> accounts() override;
1972+ virtual std::shared_ptr<Account> make_test_account(QString const& bus_name,
1973+ QString const& object_path) override;
1974
1975 QDBusConnection& connection();
1976
1977@@ -58,6 +60,12 @@
1978 virtual void timeout();
1979
1980 private:
1981+ std::shared_ptr<Account> make_account(QString const& bus_name,
1982+ QString const& object_path,
1983+ QString const& owner,
1984+ QString const& owner_id,
1985+ QString const& description);
1986+
1987 QDBusConnection conn_;
1988 std::unique_ptr<OnlineAccounts::Manager> manager_; // TODO: Hack until we can use the registry
1989 QTimer timer_;
1990
1991=== modified file 'include/unity/storage/qt/client/internal/remote_client/UploaderImpl.h'
1992--- include/unity/storage/qt/client/internal/remote_client/UploaderImpl.h 2016-07-22 00:17:24 +0000
1993+++ include/unity/storage/qt/client/internal/remote_client/UploaderImpl.h 2016-09-09 02:13:43 +0000
1994@@ -65,13 +65,15 @@
1995 std::shared_ptr<ProviderInterface> const& provider);
1996
1997 private:
1998+ enum State { uploading, finalized };
1999+
2000 QString upload_id_;
2001 QDBusUnixFileDescriptor fd_;
2002- int64_t size_;
2003 QString old_etag_;
2004- std::weak_ptr<Root> root_;
2005+ std::shared_ptr<Root> root_;
2006 std::shared_ptr<ProviderInterface> provider_;
2007 std::shared_ptr<QLocalSocket> write_socket_;
2008+ State state_;
2009 };
2010
2011 } // namespace remote_client
2012
2013=== modified file 'include/unity/storage/qt/client/internal/remote_client/dbusmarshal.h'
2014--- include/unity/storage/qt/client/internal/remote_client/dbusmarshal.h 2016-07-12 02:22:05 +0000
2015+++ include/unity/storage/qt/client/internal/remote_client/dbusmarshal.h 2016-09-09 02:13:43 +0000
2016@@ -18,29 +18,28 @@
2017
2018 #pragma once
2019
2020-#include <unity/storage/internal/ItemMetadata.h>
2021+#include <exception>
2022
2023-#include <QDBusArgument>
2024-#include <QMetaType>
2025-#include <QVariant>
2026+class QDBusPendingCallWatcher;
2027
2028 namespace unity
2029 {
2030 namespace storage
2031 {
2032+namespace qt
2033+{
2034+namespace client
2035+{
2036 namespace internal
2037 {
2038-
2039-struct ItemMetadata;
2040-QDBusArgument& operator<<(QDBusArgument& argument, storage::internal::ItemMetadata const& metadata);
2041-QDBusArgument const& operator>>(QDBusArgument const& argument, storage::internal::ItemMetadata& metadata);
2042-
2043-QDBusArgument& operator<<(QDBusArgument& argument, QList<storage::internal::ItemMetadata> const& md_list);
2044-QDBusArgument const& operator>>(QDBusArgument const& argument, QList<storage::internal::ItemMetadata>& md_list);
2045-
2046+namespace remote_client
2047+{
2048+
2049+std::exception_ptr unmarshal_exception(QDBusPendingCallWatcher const& call);
2050+
2051+} // namespace remote_client
2052 } // namespace internal
2053-} // namespace storage
2054-} // namespace unity
2055-
2056-Q_DECLARE_METATYPE(unity::storage::internal::ItemMetadata)
2057-Q_DECLARE_METATYPE(QList<unity::storage::internal::ItemMetadata>)
2058+} // client
2059+} // qt
2060+} // storage
2061+} // unity
2062
2063=== added file 'include/unity/storage/qt/client/internal/remote_client/validate.h'
2064--- include/unity/storage/qt/client/internal/remote_client/validate.h 1970-01-01 00:00:00 +0000
2065+++ include/unity/storage/qt/client/internal/remote_client/validate.h 2016-09-09 02:13:43 +0000
2066@@ -0,0 +1,51 @@
2067+/*
2068+ * Copyright (C) 2016 Canonical Ltd
2069+ *
2070+ * This program is free software: you can redistribute it and/or modify
2071+ * it under the terms of the GNU Lesser General Public License version 3 as
2072+ * published by the Free Software Foundation.
2073+ *
2074+ * This program is distributed in the hope that it will be useful,
2075+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2076+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2077+ * GNU Lesser General Public License for more details.
2078+ *
2079+ * You should have received a copy of the GNU Lesser General Public License
2080+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2081+ *
2082+ * Authors: Michi Henning <michi.henning@canonical.com>
2083+ */
2084+
2085+#pragma once
2086+
2087+#include <QString>
2088+
2089+namespace unity
2090+{
2091+namespace storage
2092+{
2093+
2094+namespace internal
2095+{
2096+
2097+class ItemMetadata;
2098+
2099+} // namespace internal
2100+
2101+namespace qt
2102+{
2103+namespace client
2104+{
2105+namespace internal
2106+{
2107+namespace remote_client
2108+{
2109+
2110+void validate(QString const& method, unity::storage::internal::ItemMetadata const& md);
2111+
2112+} // namespace remote_client
2113+} // namespace internal
2114+} // namespace client
2115+} // namespace qt
2116+} // namespace storage
2117+} // namespace unity
2118
2119=== modified file 'src/internal/CMakeLists.txt'
2120--- src/internal/CMakeLists.txt 2016-07-06 00:59:42 +0000
2121+++ src/internal/CMakeLists.txt 2016-09-09 02:13:43 +0000
2122@@ -1,5 +1,10 @@
2123 set(src
2124+ dbusmarshal.cpp
2125 safe_strerror.cpp
2126+ TraceMessageHandler.cpp
2127 )
2128
2129 add_library(storage-framework-common-internal STATIC ${src})
2130+target_link_libraries(storage-framework-common-internal
2131+ Qt5::DBus
2132+)
2133
2134=== added file 'src/internal/TraceMessageHandler.cpp'
2135--- src/internal/TraceMessageHandler.cpp 1970-01-01 00:00:00 +0000
2136+++ src/internal/TraceMessageHandler.cpp 2016-09-09 02:13:43 +0000
2137@@ -0,0 +1,96 @@
2138+/*
2139+ * Copyright (C) 2015 Canonical Ltd
2140+ *
2141+ * This program is free software: you can redistribute it and/or modify
2142+ * it under the terms of the GNU Lesser General Public License version 3 as
2143+ * published by the Free Software Foundation.
2144+ *
2145+ * This program is distributed in the hope that it will be useful,
2146+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2147+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2148+ * GNU Lesser General Public License for more details.
2149+ *
2150+ * You should have received a copy of the GNU Lesser General Public License
2151+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2152+ *
2153+ * Authors: Michi Henning <michi.henning@canonical.com>
2154+ */
2155+
2156+#include <unity/storage/internal/TraceMessageHandler.h>
2157+
2158+#include <chrono>
2159+#include <mutex>
2160+
2161+using namespace std;
2162+
2163+namespace unity
2164+{
2165+namespace storage
2166+{
2167+namespace internal
2168+{
2169+namespace
2170+{
2171+
2172+string prefix;
2173+
2174+void trace_message_handler(QtMsgType type, const QMessageLogContext& /*context*/, const QString& msg)
2175+{
2176+ using namespace std;
2177+ using namespace std::chrono;
2178+
2179+ static recursive_mutex mutex;
2180+ lock_guard<decltype(mutex)> lock(mutex);
2181+
2182+ auto now = system_clock::now();
2183+ auto sys_time = system_clock::to_time_t(now);
2184+ struct tm local_time;
2185+ localtime_r(&sys_time, &local_time);
2186+ int msecs = duration_cast<milliseconds>(now.time_since_epoch()).count() % 1000;
2187+
2188+ if (!prefix.empty())
2189+ {
2190+ fprintf(stderr, "%s: ", prefix.c_str());
2191+ }
2192+ char buf[100];
2193+ strftime(buf, sizeof(buf), "%T", &local_time);
2194+ fprintf(stderr, "[%s.%03d]", buf, msecs);
2195+ switch (type)
2196+ {
2197+ case QtWarningMsg:
2198+ fputs(" Warning:", stderr);
2199+ break;
2200+ case QtCriticalMsg:
2201+ fputs(" Critical:", stderr);
2202+ break;
2203+ // LCOV_EXCL_START
2204+ case QtFatalMsg:
2205+ fputs(" Fatal:", stderr);
2206+ break;
2207+ // LCOV_EXCL_STOP
2208+ default:
2209+ break; // No label for debug messages.
2210+ }
2211+ fprintf(stderr, " %s\n", msg.toLocal8Bit().constData());
2212+ if (type == QtFatalMsg)
2213+ {
2214+ abort(); // LCOV_EXCL_LINE
2215+ }
2216+}
2217+
2218+} // namespace
2219+
2220+TraceMessageHandler::TraceMessageHandler(string const& prog_name)
2221+{
2222+ prefix = prog_name;
2223+ old_message_handler_ = qInstallMessageHandler(trace_message_handler);
2224+}
2225+
2226+TraceMessageHandler::~TraceMessageHandler()
2227+{
2228+ qInstallMessageHandler(old_message_handler_);
2229+}
2230+
2231+} // namespace internal
2232+} // namespace storage
2233+} // namespace unity
2234
2235=== added file 'src/internal/dbusmarshal.cpp'
2236--- src/internal/dbusmarshal.cpp 1970-01-01 00:00:00 +0000
2237+++ src/internal/dbusmarshal.cpp 2016-09-09 02:13:43 +0000
2238@@ -0,0 +1,113 @@
2239+/*
2240+ * Copyright (C) 2016 Canonical Ltd
2241+ *
2242+ * This program is free software: you can redistribute it and/or modify
2243+ * it under the terms of the GNU Lesser General Public License version 3 as
2244+ * published by the Free Software Foundation.
2245+ *
2246+ * This program is distributed in the hope that it will be useful,
2247+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2248+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2249+ * GNU Lesser General Public License for more details.
2250+ *
2251+ * You should have received a copy of the GNU Lesser General Public License
2252+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2253+ *
2254+ * Authors: Michi Henning <michi.henning@canonical.com>
2255+ */
2256+
2257+#include <unity/storage/internal/dbusmarshal.h>
2258+
2259+#include <QDebug>
2260+
2261+using namespace unity::storage::internal;
2262+using namespace std;
2263+
2264+namespace unity
2265+{
2266+namespace storage
2267+{
2268+namespace internal
2269+{
2270+
2271+QDBusArgument& operator<<(QDBusArgument& argument, storage::internal::ItemMetadata const& metadata)
2272+{
2273+ argument.beginStructure();
2274+ argument << metadata.item_id;
2275+ argument << metadata.parent_ids;
2276+ argument << metadata.name;
2277+ argument << metadata.etag;
2278+ argument << static_cast<int32_t>(metadata.type);
2279+ argument.beginMap(QVariant::String, qMetaTypeId<QDBusVariant>());
2280+ decltype(ItemMetadata::metadata)::const_iterator i = metadata.metadata.constBegin();
2281+ while (i != metadata.metadata.constEnd())
2282+ {
2283+ argument.beginMapEntry();
2284+ argument << i.key() << QDBusVariant(i.value());
2285+ argument.endMapEntry();
2286+ ++i;
2287+ }
2288+ argument.endMap();
2289+ argument.endStructure();
2290+ return argument;
2291+}
2292+
2293+QDBusArgument const& operator>>(QDBusArgument const& argument, storage::internal::ItemMetadata& metadata)
2294+{
2295+ argument.beginStructure();
2296+ argument >> metadata.item_id;
2297+ argument >> metadata.parent_ids;
2298+ argument >> metadata.name;
2299+ argument >> metadata.etag;
2300+ int32_t enum_val;
2301+ argument >> enum_val;
2302+ if (enum_val < 0 || enum_val >= int(ItemType::LAST_ENTRY__))
2303+ {
2304+ qCritical() << "unmarshaling error: impossible ItemType value: " + QString::number(enum_val);
2305+ return argument; // Forces error
2306+ }
2307+ metadata.type = static_cast<ItemType>(enum_val);
2308+ metadata.metadata.clear();
2309+ argument.beginMap();
2310+ while (!argument.atEnd())
2311+ {
2312+ QString key;
2313+ QVariant value;
2314+ argument.beginMapEntry();
2315+ argument >> key >> value;
2316+ argument.endMapEntry();
2317+ metadata.metadata.insert(key, value);
2318+ }
2319+ argument.endMap();
2320+ argument.endStructure();
2321+ return argument;
2322+}
2323+
2324+QDBusArgument& operator<<(QDBusArgument& argument, QList<storage::internal::ItemMetadata> const& md_list)
2325+{
2326+ argument.beginArray(qMetaTypeId<storage::internal::ItemMetadata>());
2327+ for (auto const& md : md_list)
2328+ {
2329+ argument << md;
2330+ }
2331+ argument.endArray();
2332+ return argument;
2333+}
2334+
2335+QDBusArgument const& operator>>(QDBusArgument const& argument, QList<storage::internal::ItemMetadata>& md_list)
2336+{
2337+ md_list.clear();
2338+ argument.beginArray();
2339+ while (!argument.atEnd())
2340+ {
2341+ ItemMetadata imd;
2342+ argument >> imd;
2343+ md_list.append(imd);
2344+ }
2345+ argument.endArray();
2346+ return argument;
2347+}
2348+
2349+} // namespace internal
2350+} // namespace storage
2351+} // namespace unity
2352
2353=== modified file 'src/provider/CMakeLists.txt'
2354--- src/provider/CMakeLists.txt 2016-07-22 03:29:45 +0000
2355+++ src/provider/CMakeLists.txt 2016-09-09 02:13:43 +0000
2356@@ -1,9 +1,3 @@
2357-
2358-add_definitions(
2359- -DBOOST_THREAD_VERSION=4
2360- -DBOOST_THREAD_PROVIDES_EXECUTORS
2361- ${APPARMOR_DEPS_CFLAGS}
2362- ${ONLINEACCOUNTS_DEPS_CFLAGS})
2363 include_directories(${CMAKE_CURRENT_BINARY_DIR})
2364
2365 qt5_add_dbus_adaptor(generated_files ${CMAKE_SOURCE_DIR}/data/provider.xml unity/storage/provider/internal/ProviderInterface.h unity::storage::provider::internal::ProviderInterface)
2366@@ -12,16 +6,20 @@
2367 qt5_add_dbus_interface(generated_files bus.xml businterface)
2368
2369 set_source_files_properties(${generated_files} PROPERTIES
2370- COMPILE_FLAGS "-Wno-ctor-dtor-privacy -Wmissing-field-initializers"
2371- GENERATED TRUE
2372+ COMPILE_FLAGS "-Wno-ctor-dtor-privacy -Wmissing-field-initializers"
2373+ GENERATED TRUE
2374 )
2375
2376-add_library(storage-framework-provider SHARED
2377+add_custom_target(sf-provider-generated-files DEPENDS ${generated_files})
2378+
2379+add_library(sf-provider-objects OBJECT
2380 DownloadJob.cpp
2381+ Exceptions.cpp
2382 ProviderBase.cpp
2383 Server.cpp
2384 TempfileUploadJob.cpp
2385 UploadJob.cpp
2386+ testing/TestServer.cpp
2387 internal/AccountData.cpp
2388 internal/DBusPeerCache.cpp
2389 internal/DownloadJobImpl.cpp
2390@@ -31,6 +29,7 @@
2391 internal/ProviderInterface.cpp
2392 internal/ServerImpl.cpp
2393 internal/TempfileUploadJobImpl.cpp
2394+ internal/TestServerImpl.cpp
2395 internal/UploadJobImpl.cpp
2396 internal/dbusmarshal.cpp
2397 ${CMAKE_SOURCE_DIR}/include/unity/storage/provider/internal/AccountData.h
2398@@ -42,6 +41,23 @@
2399 ${CMAKE_SOURCE_DIR}/include/unity/storage/provider/internal/ServerImpl.h
2400 ${CMAKE_SOURCE_DIR}/include/unity/storage/provider/internal/TempfileUploadJobImpl.h
2401 ${CMAKE_SOURCE_DIR}/include/unity/storage/provider/internal/UploadJobImpl.h
2402+)
2403+add_dependencies(sf-provider-objects sf-provider-generated-files)
2404+set_target_properties(sf-provider-objects PROPERTIES
2405+ AUTOMOC TRUE
2406+)
2407+target_compile_options(sf-provider-objects PUBLIC
2408+ -DBOOST_THREAD_VERSION=4
2409+ -DBOOST_THREAD_PROVIDES_EXECUTORS
2410+ ${APPARMOR_DEPS_CFLAGS}
2411+ ${ONLINEACCOUNTS_DEPS_CFLAGS})
2412+target_include_directories(sf-provider-objects PRIVATE
2413+ ${Qt5DBus_INCLUDE_DIRS}
2414+ ${Qt5Network_INCLUDE_DIRS}
2415+)
2416+
2417+add_library(storage-framework-provider SHARED
2418+ $<TARGET_OBJECTS:sf-provider-objects>
2419 ${generated_files})
2420
2421 set_target_properties(storage-framework-provider PROPERTIES
2422@@ -51,7 +67,10 @@
2423 SOVERSION ${SF_PROVIDER_SOVERSION}
2424 VERSION ${SF_PROVIDER_LIBVERSION}
2425 )
2426+target_compile_options(storage-framework-provider PUBLIC
2427+ $<TARGET_PROPERTY:sf-provider-objects,COMPILE_OPTIONS>)
2428 target_link_libraries(storage-framework-provider
2429+ storage-framework-common-internal
2430 Qt5::Core
2431 Qt5::DBus
2432 Qt5::Network
2433@@ -60,19 +79,31 @@
2434 ${ONLINEACCOUNTS_DEPS_LDFLAGS}
2435 )
2436
2437-# moc does not know how to interpret the preprocessor logic in
2438-# MainLoopExecutor.h, so we reproduce it here.
2439-if(Boost_VERSION GREATER "105599")
2440- set_target_properties(storage-framework-provider PROPERTIES
2441- AUTOMOC_MOC_OPTIONS "-DSF_SUPPORTS_EXECUTORS"
2442- )
2443-endif()
2444-
2445 install(
2446 TARGETS storage-framework-provider
2447 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
2448 )
2449
2450+# Build a static version of the library so that tests have access to
2451+# hidden visibility symbols.
2452+add_library(storage-framework-provider-static STATIC
2453+ $<TARGET_OBJECTS:sf-provider-objects>
2454+ ${generated_files})
2455+set_target_properties(storage-framework-provider-static PROPERTIES
2456+ AUTOMOC TRUE
2457+ )
2458+target_compile_options(storage-framework-provider-static PUBLIC
2459+ $<TARGET_PROPERTY:sf-provider-objects,COMPILE_OPTIONS>)
2460+target_link_libraries(storage-framework-provider-static
2461+ storage-framework-common-internal
2462+ Qt5::Core
2463+ Qt5::DBus
2464+ Qt5::Network
2465+ ${Boost_LIBRARIES}
2466+ ${APPARMOR_DEPS_LDFLAGS}
2467+ ${ONLINEACCOUNTS_DEPS_LDFLAGS}
2468+)
2469+
2470 configure_file(
2471 storage-framework-provider.pc.in
2472 storage-framework-provider-${SF_PROVIDER_API_VERSION}.pc
2473
2474=== added file 'src/provider/Exceptions.cpp'
2475--- src/provider/Exceptions.cpp 1970-01-01 00:00:00 +0000
2476+++ src/provider/Exceptions.cpp 2016-09-09 02:13:43 +0000
2477@@ -0,0 +1,157 @@
2478+/*
2479+ * Copyright (C) 2016 Canonical Ltd
2480+ *
2481+ * This program is free software: you can redistribute it and/or modify
2482+ * it under the terms of the GNU Lesser General Public License version 3 as
2483+ * published by the Free Software Foundation.
2484+ *
2485+ * This program is distributed in the hope that it will be useful,
2486+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2487+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2488+ * GNU Lesser General Public License for more details.
2489+ *
2490+ * You should have received a copy of the GNU Lesser General Public License
2491+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2492+ *
2493+ * Authors: Michi Henning <michi.henning@canonical.com>
2494+ */
2495+
2496+#include <unity/storage/provider/Exceptions.h>
2497+
2498+using namespace std;
2499+
2500+namespace unity
2501+{
2502+namespace storage
2503+{
2504+namespace provider
2505+{
2506+
2507+StorageException::StorageException(std::string const& exception_type, string const& error_message)
2508+ : what_string_(string(exception_type) + ": " + error_message)
2509+ , type_(exception_type)
2510+ , error_message_(error_message)
2511+{
2512+}
2513+
2514+StorageException::~StorageException() = default;
2515+
2516+char const* StorageException::what() const noexcept
2517+{
2518+ return what_string_.c_str();
2519+}
2520+
2521+string StorageException::type() const
2522+{
2523+ return type_;
2524+}
2525+
2526+string StorageException::error_message() const
2527+{
2528+ return error_message_;
2529+}
2530+
2531+RemoteCommsException::RemoteCommsException(string const& error_message)
2532+ : StorageException("RemoteCommsException", error_message)
2533+{
2534+}
2535+
2536+RemoteCommsException::~RemoteCommsException() = default;
2537+
2538+NotExistsException::NotExistsException(string const& error_message, string const& key)
2539+ : StorageException("NotExistsException", error_message)
2540+ , key_(key)
2541+{
2542+}
2543+
2544+NotExistsException::~NotExistsException() = default;
2545+
2546+string NotExistsException::key() const
2547+{
2548+ return key_;
2549+}
2550+
2551+ExistsException::ExistsException(string const& error_message, string const& identity, string const& name)
2552+ : StorageException("ExistsException", error_message)
2553+ , identity_(identity)
2554+ , name_(name)
2555+{
2556+}
2557+
2558+ExistsException::~ExistsException() = default;
2559+
2560+string ExistsException::native_identity() const
2561+{
2562+ return identity_;
2563+}
2564+
2565+string ExistsException::name() const
2566+{
2567+ return name_;
2568+}
2569+
2570+ConflictException::ConflictException(string const& error_message)
2571+ : StorageException("ConflictException", error_message)
2572+{
2573+}
2574+
2575+ConflictException::~ConflictException() = default;
2576+
2577+PermissionException::PermissionException(string const& error_message)
2578+ : StorageException("PermissionException", error_message)
2579+{
2580+}
2581+
2582+PermissionException::~PermissionException() = default;
2583+
2584+QuotaException::QuotaException(string const& error_message)
2585+ : StorageException("QuotaException", error_message)
2586+{
2587+}
2588+
2589+QuotaException::~QuotaException() = default;
2590+
2591+CancelledException::CancelledException(string const& error_message)
2592+ : StorageException("CancelledException", error_message)
2593+{
2594+}
2595+
2596+CancelledException::~CancelledException() = default;
2597+
2598+LogicException::LogicException(string const& error_message)
2599+ : StorageException("LogicException", error_message)
2600+{
2601+}
2602+
2603+LogicException::~LogicException() = default;
2604+
2605+InvalidArgumentException::InvalidArgumentException(string const& error_message)
2606+ : StorageException("InvalidArgumentException", error_message)
2607+{
2608+}
2609+
2610+InvalidArgumentException::~InvalidArgumentException() = default;
2611+
2612+ResourceException::ResourceException(string const& error_message, int error_code)
2613+ : StorageException("ResourceException", error_message)
2614+ , error_code_(error_code)
2615+{
2616+}
2617+
2618+ResourceException::~ResourceException() = default;
2619+
2620+int ResourceException::error_code() const noexcept
2621+{
2622+ return error_code_;
2623+}
2624+
2625+UnknownException::UnknownException(string const& error_message)
2626+ : StorageException("UnknownException", error_message)
2627+{
2628+}
2629+
2630+UnknownException::~UnknownException() = default;
2631+
2632+} // namespace provider
2633+} // namespace storage
2634+} // namespace unity
2635
2636=== modified file 'src/provider/TempfileUploadJob.cpp'
2637--- src/provider/TempfileUploadJob.cpp 2016-07-12 02:22:05 +0000
2638+++ src/provider/TempfileUploadJob.cpp 2016-09-09 02:13:43 +0000
2639@@ -40,6 +40,11 @@
2640
2641 TempfileUploadJob::~TempfileUploadJob() = default;
2642
2643+void TempfileUploadJob::drain()
2644+{
2645+ static_cast<internal::TempfileUploadJobImpl*>(p_)->drain();
2646+}
2647+
2648 string TempfileUploadJob::file_name() const
2649 {
2650 return static_cast<internal::TempfileUploadJobImpl*>(p_)->file_name();
2651
2652=== modified file 'src/provider/internal/DownloadJobImpl.cpp'
2653--- src/provider/internal/DownloadJobImpl.cpp 2016-07-12 02:22:05 +0000
2654+++ src/provider/internal/DownloadJobImpl.cpp 2016-09-09 02:13:43 +0000
2655@@ -17,7 +17,9 @@
2656 */
2657
2658 #include <unity/storage/provider/internal/DownloadJobImpl.h>
2659+#include <unity/storage/internal/safe_strerror.h>
2660 #include <unity/storage/provider/DownloadJob.h>
2661+#include <unity/storage/provider/Exceptions.h>
2662
2663 #include <sys/socket.h>
2664 #include <sys/types.h>
2665@@ -26,6 +28,7 @@
2666 #include <stdexcept>
2667
2668 using namespace std;
2669+using namespace unity::storage::internal;
2670
2671 namespace unity
2672 {
2673@@ -42,18 +45,30 @@
2674 int socks[2];
2675 if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) < 0)
2676 {
2677- throw runtime_error("could not create socketpair");
2678+ int error_code = errno;
2679+ string msg = "could not create socketpair: " + safe_strerror(error_code);
2680+ throw ResourceException(msg, error_code);
2681 }
2682 read_socket_ = socks[0];
2683 write_socket_ = socks[1];
2684+
2685+#if 0
2686+ // TODO: We should be able to half-close the write channel of the read socket and the read channel of
2687+ // the write socket. But, if we do, QLocalSocket indicates that everything was closed, which causes
2688+ // failures on the client side. We suspect a QLocalSocket bug -- need to investigate.
2689 if (shutdown(read_socket_, SHUT_WR) < 0)
2690 {
2691- throw runtime_error("Could not shut down write channel on read socket");
2692+ int error_code = errno;
2693+ string msg = "Could not shut down write channel on read socket" + safe_strerror(error_code);
2694+ throw ResourceException(msg, error_code);
2695 }
2696 if (shutdown(write_socket_, SHUT_RD) < 0)
2697 {
2698- throw runtime_error("Could not shut down read channel on write socket");
2699+ int error_code = errno;
2700+ string msg = "Could not shut down read channel on write socket: " + safe_strerror(error_code);
2701+ throw ResourceException(msg, error_code);
2702 }
2703+#endif
2704 }
2705
2706 DownloadJobImpl::~DownloadJobImpl()
2707@@ -90,17 +105,6 @@
2708 return sock;
2709 }
2710
2711-string const& DownloadJobImpl::sender_bus_name() const
2712-{
2713- return sender_bus_name_;
2714-}
2715-
2716-void DownloadJobImpl::set_sender_bus_name(string const& bus_name)
2717-{
2718- assert(bus_name[0] == ':');
2719- sender_bus_name_ = bus_name;
2720-}
2721-
2722 void DownloadJobImpl::report_complete()
2723 {
2724 if (write_socket_ >= 0)
2725@@ -124,7 +128,19 @@
2726
2727 lock_guard<mutex> guard(completion_lock_);
2728 completed_ = true;
2729- completion_promise_.set_exception(p);
2730+ // Convert std::exception_ptr to boost::exception_ptr
2731+ try
2732+ {
2733+ std::rethrow_exception(p);
2734+ }
2735+ catch (StorageException const& e)
2736+ {
2737+ completion_promise_.set_exception(e);
2738+ }
2739+ catch (...)
2740+ {
2741+ completion_promise_.set_exception(boost::current_exception());
2742+ }
2743 }
2744
2745 boost::future<void> DownloadJobImpl::finish(DownloadJob& job)
2746
2747=== modified file 'src/provider/internal/Handler.cpp'
2748--- src/provider/internal/Handler.cpp 2016-07-20 02:20:53 +0000
2749+++ src/provider/internal/Handler.cpp 2016-09-09 02:13:43 +0000
2750@@ -17,20 +17,26 @@
2751 */
2752
2753 #include <unity/storage/provider/internal/Handler.h>
2754+
2755+#include <unity/storage/internal/dbus_error.h>
2756 #include <unity/storage/provider/internal/AccountData.h>
2757+#include <unity/storage/provider/internal/dbusmarshal.h>
2758 #include <unity/storage/provider/internal/DBusPeerCache.h>
2759 #include <unity/storage/provider/internal/MainLoopExecutor.h>
2760 #include <unity/storage/provider/ProviderBase.h>
2761+#include <unity/storage/provider/Exceptions.h>
2762+
2763+#pragma GCC diagnostic push
2764+#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
2765+#pragma GCC diagnostic ignored "-Wswitch-default"
2766+#include <QDebug>
2767+#pragma GCC diagnostic pop
2768
2769 #include <stdexcept>
2770
2771+using namespace unity::storage::internal;
2772 using namespace std;
2773
2774-namespace
2775-{
2776-char const ERROR[] = "com.canonical.StorageFramework.Provider.Error";
2777-}
2778-
2779 namespace unity
2780 {
2781 namespace storage
2782@@ -53,7 +59,8 @@
2783 auto peer_future = account_->dbus_peer().get(message_.service());
2784 creds_future_ = peer_future.then(
2785 EXEC_IN_MAIN
2786- [this](decltype(peer_future) f) {
2787+ [this](decltype(peer_future) f)
2788+ {
2789 auto info = f.get();
2790 if (info.valid)
2791 {
2792@@ -64,8 +71,10 @@
2793 }
2794 else
2795 {
2796- reply_ = message_.createErrorReply(
2797- ERROR, "Handler::begin(): could not retrieve credentials");
2798+ string msg = "Handler::begin(): could not retrieve credentials";
2799+ qDebug() << QString::fromStdString(msg);
2800+ auto ep = make_exception_ptr(PermissionException(msg));
2801+ marshal_exception(ep);
2802 QMetaObject::invokeMethod(this, "send_reply",
2803 Qt::QueuedConnection);
2804 }
2805@@ -75,23 +84,29 @@
2806 void Handler::credentials_received()
2807 {
2808 boost::future<QDBusMessage> msg_future;
2809- try {
2810+ try
2811+ {
2812 msg_future = callback_(account_, context_, message_);
2813- } catch (std::exception const& e) {
2814- reply_ = message_.createErrorReply(ERROR, e.what());
2815+ }
2816+ catch (std::exception const& e)
2817+ {
2818+ qDebug() << "provider method threw an exception:" << e.what();
2819+ marshal_exception(current_exception());
2820 QMetaObject::invokeMethod(this, "send_reply", Qt::QueuedConnection);
2821 return;
2822 }
2823 reply_future_ = msg_future.then(
2824 EXEC_IN_MAIN
2825- [this](decltype(msg_future) f) {
2826+ [this](decltype(msg_future) f)
2827+ {
2828 try
2829 {
2830 reply_ = f.get();
2831 }
2832 catch (std::exception const& e)
2833 {
2834- reply_ = message_.createErrorReply(ERROR, e.what());
2835+ qDebug() << e.what();
2836+ marshal_exception(current_exception());
2837 }
2838 QMetaObject::invokeMethod(this, "send_reply", Qt::QueuedConnection);
2839 });
2840@@ -103,6 +118,62 @@
2841 Q_EMIT finished();
2842 }
2843
2844+void Handler::marshal_exception(exception_ptr ep)
2845+{
2846+ try
2847+ {
2848+ rethrow_exception(ep);
2849+ }
2850+ catch (StorageException const& e)
2851+ {
2852+ reply_ = message_.createErrorReply(QString(DBUS_ERROR_PREFIX) + QString::fromStdString(e.type()),
2853+ QString::fromStdString(e.error_message()));
2854+ try
2855+ {
2856+ throw;
2857+ }
2858+ catch (NotExistsException const& e)
2859+ {
2860+ reply_ << QVariant(QString::fromStdString(e.key()));
2861+ }
2862+ catch (ExistsException const& e)
2863+ {
2864+ reply_ << QVariant(QString::fromStdString(e.native_identity()));
2865+ reply_ << QVariant(QString::fromStdString(e.name()));
2866+ }
2867+ catch (ResourceException const& e)
2868+ {
2869+ qDebug() << e.what();
2870+ reply_ << QVariant(e.error_code());
2871+ }
2872+ catch (RemoteCommsException const& e)
2873+ {
2874+ qDebug() << e.what();
2875+ }
2876+ catch (UnknownException const& e)
2877+ {
2878+ qDebug() << e.what();
2879+ }
2880+ catch (StorageException const&)
2881+ {
2882+ // Some other sub-type of StorageException without additional data members,
2883+ // and we don't want to log this (not surprising) exception.
2884+ }
2885+ }
2886+ catch (std::exception const& e)
2887+ {
2888+ QString msg = QString("unknown exception thrown by provider: ") + e.what();
2889+ qDebug() << msg;
2890+ reply_ = message_.createErrorReply(QString(DBUS_ERROR_PREFIX) + "UnknownException", msg);
2891+ }
2892+ catch (...)
2893+ {
2894+ QString msg = "unknown exception thrown by provider";
2895+ qDebug() << msg;
2896+ reply_ = message_.createErrorReply(QString(DBUS_ERROR_PREFIX) + "UnknownException", msg);
2897+ }
2898+}
2899+
2900 }
2901 }
2902 }
2903
2904=== modified file 'src/provider/internal/MainLoopExecutor.cpp'
2905--- src/provider/internal/MainLoopExecutor.cpp 2016-07-19 03:29:15 +0000
2906+++ src/provider/internal/MainLoopExecutor.cpp 2016-09-09 02:13:43 +0000
2907@@ -23,8 +23,6 @@
2908
2909 #include <stdexcept>
2910
2911-#ifdef SF_SUPPORTS_EXECUTORS
2912-
2913 namespace {
2914
2915 class WorkEvent : public QEvent {
2916@@ -107,5 +105,3 @@
2917 }
2918 }
2919 }
2920-
2921-#endif /* SF_SUPPORTS_EXECUTORS */
2922
2923=== modified file 'src/provider/internal/PendingJobs.cpp'
2924--- src/provider/internal/PendingJobs.cpp 2016-07-19 03:26:36 +0000
2925+++ src/provider/internal/PendingJobs.cpp 2016-09-09 02:13:43 +0000
2926@@ -18,6 +18,7 @@
2927
2928 #include <unity/storage/provider/internal/PendingJobs.h>
2929 #include <unity/storage/provider/DownloadJob.h>
2930+#include <unity/storage/provider/Exceptions.h>
2931 #include <unity/storage/provider/UploadJob.h>
2932 #include <unity/storage/provider/internal/DownloadJobImpl.h>
2933 #include <unity/storage/provider/internal/MainLoopExecutor.h>
2934@@ -47,67 +48,79 @@
2935 this, &PendingJobs::service_disconnected);
2936 }
2937
2938-PendingJobs::~PendingJobs() = default;
2939+PendingJobs::~PendingJobs()
2940+{
2941+ for (const auto& pair : downloads_)
2942+ {
2943+ cancel_job(pair.second, "download " + pair.second->download_id());
2944+ }
2945+ for (const auto& pair : uploads_)
2946+ {
2947+ cancel_job(pair.second, "upload " + pair.second->upload_id());
2948+ }
2949+}
2950
2951-void PendingJobs::add_download(unique_ptr<DownloadJob> &&job)
2952+void PendingJobs::add_download(QString const& client_bus_name,
2953+ unique_ptr<DownloadJob> &&job)
2954 {
2955 lock_guard<mutex> guard(lock_);
2956
2957- assert(!job->p_->sender_bus_name().empty());
2958- assert(downloads_.find(job->download_id()) == downloads_.end());
2959+ assert(!client_bus_name.isEmpty() && client_bus_name[0] == ':');
2960+ const auto job_id = make_pair(client_bus_name, job->download_id());
2961+ assert(downloads_.find(job_id) == downloads_.end());
2962
2963 shared_ptr<DownloadJob> j(std::move(job));
2964- downloads_.emplace(j->download_id(), j);
2965- watch_peer(j->p_->sender_bus_name());
2966-}
2967-
2968-std::shared_ptr<DownloadJob> PendingJobs::get_download(std::string const& download_id)
2969-{
2970- lock_guard<mutex> guard(lock_);
2971-
2972- return downloads_.at(download_id);
2973-}
2974-
2975-std::shared_ptr<DownloadJob> PendingJobs::remove_download(std::string const& download_id)
2976-{
2977- lock_guard<mutex> guard(lock_);
2978-
2979- auto job = downloads_.at(download_id);
2980- downloads_.erase(download_id);
2981- unwatch_peer(job->p_->sender_bus_name());
2982+ downloads_.emplace(job_id, j);
2983+ watch_peer(client_bus_name);
2984+}
2985+
2986+shared_ptr<DownloadJob> PendingJobs::remove_download(QString const& client_bus_name,
2987+ string const& download_id)
2988+{
2989+ lock_guard<mutex> guard(lock_);
2990+
2991+ auto it = downloads_.find({client_bus_name, download_id});
2992+ if (it == downloads_.cend())
2993+ {
2994+ throw LogicException("No such download: " + download_id);
2995+ }
2996+ auto job = it->second;
2997+ downloads_.erase(it);
2998+ unwatch_peer(client_bus_name);
2999 return job;
3000 }
3001
3002-void PendingJobs::add_upload(unique_ptr<UploadJob> &&job)
3003+void PendingJobs::add_upload(QString const& client_bus_name,
3004+ unique_ptr<UploadJob> &&job)
3005 {
3006 lock_guard<mutex> guard(lock_);
3007
3008- assert(!job->p_->sender_bus_name().empty());
3009- assert(uploads_.find(job->upload_id()) == uploads_.end());
3010+ assert(!client_bus_name.isEmpty() && client_bus_name[0] == ':');
3011+ const auto job_id = make_pair(client_bus_name, job->upload_id());
3012+ assert(uploads_.find(job_id) == uploads_.end());
3013
3014 shared_ptr<UploadJob> j(std::move(job));
3015- uploads_.emplace(j->upload_id(), j);
3016- watch_peer(j->p_->sender_bus_name());
3017-}
3018-
3019-std::shared_ptr<UploadJob> PendingJobs::get_upload(std::string const& upload_id)
3020-{
3021- lock_guard<mutex> guard(lock_);
3022-
3023- return uploads_.at(upload_id);
3024-}
3025-
3026-std::shared_ptr<UploadJob> PendingJobs::remove_upload(std::string const& upload_id)
3027-{
3028- lock_guard<mutex> guard(lock_);
3029-
3030- auto job = uploads_.at(upload_id);
3031- uploads_.erase(upload_id);
3032- unwatch_peer(job->p_->sender_bus_name());
3033+ uploads_.emplace(job_id, j);
3034+ watch_peer(client_bus_name);
3035+}
3036+
3037+shared_ptr<UploadJob> PendingJobs::remove_upload(QString const& client_bus_name,
3038+ string const& upload_id)
3039+{
3040+ lock_guard<mutex> guard(lock_);
3041+
3042+ auto it = uploads_.find({client_bus_name, upload_id});
3043+ if (it == uploads_.cend())
3044+ {
3045+ throw LogicException("No such upload: " + upload_id);
3046+ }
3047+ auto job = it->second;
3048+ uploads_.erase(it);
3049+ unwatch_peer(client_bus_name);
3050 return job;
3051 }
3052
3053-void PendingJobs::watch_peer(string const& bus_name)
3054+void PendingJobs::watch_peer(QString const& bus_name)
3055 {
3056 auto it = services_.find(bus_name);
3057 if (it != services_.end())
3058@@ -116,12 +129,12 @@
3059 }
3060 else
3061 {
3062- watcher_.addWatchedService(QString::fromStdString(bus_name));
3063+ watcher_.addWatchedService(bus_name);
3064 services_[bus_name] = 1;
3065 }
3066 }
3067
3068-void PendingJobs::unwatch_peer(string const& bus_name)
3069+void PendingJobs::unwatch_peer(QString const& bus_name)
3070 {
3071 auto it = services_.find(bus_name);
3072 if (it == services_.end())
3073@@ -132,72 +145,62 @@
3074 if (it->second == 0)
3075 {
3076 services_.erase(it);
3077- watcher_.removeWatchedService(QString::fromStdString(bus_name));
3078+ watcher_.removeWatchedService(bus_name);
3079 }
3080 }
3081
3082 void PendingJobs::service_disconnected(QString const& service_name)
3083 {
3084 lock_guard<mutex> guard(lock_);
3085- string const bus_name = service_name.toStdString();
3086-
3087- for (auto it = downloads_.cbegin(); it != downloads_.cend(); )
3088- {
3089- if (it->second->p_->sender_bus_name() == bus_name)
3090- {
3091- auto job = it->second;
3092- it = downloads_.erase(it);
3093- auto f = job->p_->cancel(*job);
3094- // This continuation also ensures that the job remains
3095- // alive until the cancel method has completed.
3096- f.then(
3097- EXEC_IN_MAIN
3098- [job](decltype(f) f) {
3099- try
3100- {
3101- f.get();
3102- }
3103- catch (std::exception const& e)
3104- {
3105- fprintf(stderr, "Error cancelling download job '%s': %s\n",
3106- job->download_id().c_str(), e.what());
3107- }
3108- });
3109- }
3110- else
3111- {
3112- ++it;
3113- }
3114- }
3115-
3116- for (auto it = uploads_.cbegin(); it != uploads_.cend(); )
3117- {
3118- if (it->second->p_->sender_bus_name() == bus_name)
3119- {
3120- auto job = it->second;
3121- it = uploads_.erase(it);
3122- auto f = job->p_->cancel(*job);
3123- // This continuation also ensures that the job remains
3124- // alive until the cancel method has completed.
3125- f.then(
3126- EXEC_IN_MAIN
3127- [job](decltype(f) f) {
3128- try
3129- {
3130- f.get();
3131- }
3132- catch (std::exception const& e)
3133- {
3134- fprintf(stderr, "Error cancelling upload job '%s': %s\n",
3135- job->upload_id().c_str(), e.what());
3136- }
3137- });
3138- }
3139- else
3140- {
3141- ++it;
3142- }
3143- }
3144+
3145+ services_.erase(service_name);
3146+ watcher_.removeWatchedService(service_name);
3147+
3148+ const auto lower = make_pair(service_name, string());
3149+
3150+ for (auto it = downloads_.lower_bound(lower);
3151+ it != downloads_.cend() && it->first.first == service_name; )
3152+ {
3153+ auto job = it->second;
3154+ it = downloads_.erase(it);
3155+ cancel_job(job, "download " + job->download_id());
3156+ }
3157+
3158+ for (auto it = uploads_.lower_bound(lower);
3159+ it != uploads_.cend() && it->first.first == service_name; )
3160+ {
3161+ auto job = it->second;
3162+ it = uploads_.erase(it);
3163+ cancel_job(job, "upload " + job->upload_id());
3164+ }
3165+}
3166+
3167+template<typename Job>
3168+void PendingJobs::cancel_job(shared_ptr<Job> const& job, string const& identifier)
3169+{
3170+ auto f = job->p_->cancel(*job);
3171+ // This continuation also ensures that the job remains
3172+ // alive until the cancel method has completed.
3173+ auto cancel_future = std::make_shared<boost::future<void>>();
3174+ *cancel_future = f.then(
3175+ EXEC_IN_MAIN
3176+ [job, identifier, cancel_future](decltype(f) f) {
3177+ try
3178+ {
3179+ f.get();
3180+ }
3181+ catch (std::exception const& e)
3182+ {
3183+ fprintf(stderr, "Error cancelling job '%s': %s\n",
3184+ identifier.c_str(), e.what());
3185+ }
3186+
3187+ // Break the reference cycle between the continuation
3188+ // future and closure, while making sure the future
3189+ // survives long enough to be marked ready.
3190+ auto fut = std::make_shared<boost::future<void>>(std::move(*cancel_future));
3191+ MainLoopExecutor::instance().submit([fut]{});
3192+ });
3193 }
3194
3195 }
3196
3197=== modified file 'src/provider/internal/ProviderInterface.cpp'
3198--- src/provider/internal/ProviderInterface.cpp 2016-07-21 12:48:40 +0000
3199+++ src/provider/internal/ProviderInterface.cpp 2016-09-09 02:13:43 +0000
3200@@ -18,6 +18,7 @@
3201
3202 #include <unity/storage/provider/internal/ProviderInterface.h>
3203 #include <unity/storage/provider/DownloadJob.h>
3204+#include <unity/storage/provider/Exceptions.h>
3205 #include <unity/storage/provider/ProviderBase.h>
3206 #include <unity/storage/provider/UploadJob.h>
3207 #include <unity/storage/provider/internal/AccountData.h>
3208@@ -171,15 +172,13 @@
3209 EXEC_IN_MAIN
3210 [account, message](decltype(f) f) -> QDBusMessage {
3211 auto job = f.get();
3212- job->p_->set_sender_bus_name(message.service().toStdString());
3213-
3214 auto upload_id = QString::fromStdString(job->upload_id());
3215 QDBusUnixFileDescriptor file_desc;
3216 int fd = job->p_->take_write_socket();
3217 file_desc.setFileDescriptor(fd);
3218 close(fd);
3219
3220- account->jobs().add_upload(std::move(job));
3221+ account->jobs().add_upload(message.service(), std::move(job));
3222 return message.createReply({
3223 QVariant(upload_id),
3224 QVariant::fromValue(file_desc),
3225@@ -198,15 +197,13 @@
3226 EXEC_IN_MAIN
3227 [account, message](decltype(f) f) -> QDBusMessage {
3228 auto job = f.get();
3229- job->p_->set_sender_bus_name(message.service().toStdString());
3230-
3231 auto upload_id = QString::fromStdString(job->upload_id());
3232 QDBusUnixFileDescriptor file_desc;
3233 int fd = job->p_->take_write_socket();
3234 file_desc.setFileDescriptor(fd);
3235 close(fd);
3236
3237- account->jobs().add_upload(std::move(job));
3238+ account->jobs().add_upload(message.service(), std::move(job));
3239 return message.createReply({
3240 QVariant(upload_id),
3241 QVariant::fromValue(file_desc),
3242@@ -219,15 +216,10 @@
3243 ProviderInterface::IMD ProviderInterface::FinishUpload(QString const& upload_id)
3244 {
3245 queue_request([upload_id](shared_ptr<AccountData> const& account, Context const& /*ctx*/, QDBusMessage const& message) {
3246- // Throws if job is not available
3247- auto job = account->jobs().get_upload(upload_id.toStdString());
3248- if (job->p_->sender_bus_name() != message.service().toStdString())
3249- {
3250- throw runtime_error("Upload job belongs to a different client");
3251- }
3252 // FIXME: removing the job at this point means we can't
3253 // cancel during finish().
3254- account->jobs().remove_upload(upload_id.toStdString());
3255+ // Throws if job is not available
3256+ auto job = account->jobs().remove_upload(message.service(), upload_id.toStdString());
3257 auto f = job->p_->finish(*job);
3258 return f.then(
3259 EXEC_IN_MAIN
3260@@ -243,12 +235,7 @@
3261 {
3262 queue_request([upload_id](shared_ptr<AccountData> const& account, Context const& /*ctx*/, QDBusMessage const& message) {
3263 // Throws if job is not available
3264- auto job = account->jobs().get_upload(upload_id.toStdString());
3265- if (job->p_->sender_bus_name() != message.service().toStdString())
3266- {
3267- throw runtime_error("Upload job belongs to a different client");
3268- }
3269- account->jobs().remove_upload(upload_id.toStdString());
3270+ auto job = account->jobs().remove_upload(message.service(), upload_id.toStdString());
3271 auto f = job->p_->cancel(*job);
3272 return f.then(
3273 EXEC_IN_MAIN
3274@@ -268,15 +255,13 @@
3275 EXEC_IN_MAIN
3276 [account, message](decltype(f) f) -> QDBusMessage {
3277 auto job = f.get();
3278- job->p_->set_sender_bus_name(message.service().toStdString());
3279-
3280 auto download_id = QString::fromStdString(job->download_id());
3281 QDBusUnixFileDescriptor file_desc;
3282 int fd = job->p_->take_read_socket();
3283 file_desc.setFileDescriptor(fd);
3284 close(fd);
3285
3286- account->jobs().add_download(std::move(job));
3287+ account->jobs().add_download(message.service(), std::move(job));
3288 return message.createReply({
3289 QVariant(download_id),
3290 QVariant::fromValue(file_desc),
3291@@ -289,15 +274,10 @@
3292 void ProviderInterface::FinishDownload(QString const& download_id)
3293 {
3294 queue_request([download_id](shared_ptr<AccountData> const& account, Context const& /*ctx*/, QDBusMessage const& message) {
3295- // Throws if job is not available
3296- auto job = account->jobs().get_download(download_id.toStdString());
3297- if (job->p_->sender_bus_name() != message.service().toStdString())
3298- {
3299- throw runtime_error("Download job belongs to a different client");
3300- }
3301 // FIXME: removing the job at this point means we can't
3302 // cancel during finish().
3303- account->jobs().remove_download(download_id.toStdString());
3304+ // Throws if job is not available
3305+ auto job = account->jobs().remove_download(message.service(), download_id.toStdString());
3306 auto f = job->p_->finish(*job);
3307 return f.then(
3308 EXEC_IN_MAIN
3309
3310=== modified file 'src/provider/internal/ServerImpl.cpp'
3311--- src/provider/internal/ServerImpl.cpp 2016-07-21 04:00:29 +0000
3312+++ src/provider/internal/ServerImpl.cpp 2016-09-09 02:13:43 +0000
3313@@ -17,6 +17,7 @@
3314 */
3315
3316 #include <unity/storage/provider/internal/ServerImpl.h>
3317+#include <unity/storage/provider/Exceptions.h>
3318 #include <unity/storage/provider/ProviderBase.h>
3319 #include <unity/storage/provider/internal/AccountData.h>
3320 #include <unity/storage/provider/internal/MainLoopExecutor.h>
3321@@ -37,7 +38,10 @@
3322 {
3323
3324 ServerImpl::ServerImpl(ServerBase* server, string const& bus_name, string const& account_service_id)
3325- : server_(server), bus_name_(bus_name), service_id_(account_service_id)
3326+ : server_(server)
3327+ , bus_name_(bus_name)
3328+ , service_id_(account_service_id)
3329+ , trace_message_handler_("storage_provider")
3330 {
3331 qDBusRegisterMetaType<Item>();
3332 qDBusRegisterMetaType<std::vector<Item>>();
3333@@ -85,7 +89,8 @@
3334
3335 if (!bus.registerService(QString::fromStdString(bus_name_)))
3336 {
3337- throw runtime_error("Could not acquire bus name: " + bus_name_);
3338+ string msg = string("Could not acquire bus name: ") + bus_name_ + ": " + bus.lastError().message().toStdString();
3339+ throw ResourceException(msg, int(bus.lastError().type()));
3340 }
3341 // TODO: claim bus name
3342 qDebug() << "Bus unique name:" << bus.baseService();
3343
3344=== modified file 'src/provider/internal/TempfileUploadJobImpl.cpp'
3345--- src/provider/internal/TempfileUploadJobImpl.cpp 2016-07-12 02:22:05 +0000
3346+++ src/provider/internal/TempfileUploadJobImpl.cpp 2016-09-09 02:13:43 +0000
3347@@ -17,9 +17,10 @@
3348 */
3349
3350 #include <unity/storage/provider/internal/TempfileUploadJobImpl.h>
3351+#include <unity/storage/provider/Exceptions.h>
3352
3353 #include <cassert>
3354-#include <stdexcept>
3355+#include <exception>
3356
3357 using namespace std;
3358
3359@@ -64,6 +65,25 @@
3360 return tmpfile_->fileName().toStdString();
3361 }
3362
3363+void TempfileUploadJobImpl::drain()
3364+{
3365+ while (true)
3366+ {
3367+ if (!tmpfile_->isOpen())
3368+ {
3369+ break;
3370+ }
3371+ if (!reader_->waitForReadyRead(0))
3372+ {
3373+ // Nothing was available to read: is the read channel still open?
3374+ if (tmpfile_->isOpen())
3375+ {
3376+ throw LogicException("Socket not closed");
3377+ }
3378+ }
3379+ }
3380+}
3381+
3382 void TempfileUploadJobImpl::on_ready_read()
3383 {
3384 char buffer[4096];
3385
3386=== added file 'src/provider/internal/TestServerImpl.cpp'
3387--- src/provider/internal/TestServerImpl.cpp 1970-01-01 00:00:00 +0000
3388+++ src/provider/internal/TestServerImpl.cpp 2016-09-09 02:13:43 +0000
3389@@ -0,0 +1,84 @@
3390+/*
3391+ * Copyright (C) 2016 Canonical Ltd
3392+ *
3393+ * This program is free software: you can redistribute it and/or modify
3394+ * it under the terms of the GNU Lesser General Public License version 3 as
3395+ * published by the Free Software Foundation.
3396+ *
3397+ * This program is distributed in the hope that it will be useful,
3398+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3399+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3400+ * GNU Lesser General Public License for more details.
3401+ *
3402+ * You should have received a copy of the GNU Lesser General Public License
3403+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3404+ *
3405+ * Authors: James Henstridge <james.henstridge@canonical.com>
3406+ */
3407+
3408+#include <unity/storage/provider/internal/TestServerImpl.h>
3409+#include <unity/storage/provider/Exceptions.h>
3410+#include <unity/storage/provider/ProviderBase.h>
3411+#include <unity/storage/provider/internal/AccountData.h>
3412+#include <unity/storage/provider/internal/DBusPeerCache.h>
3413+#include <unity/storage/provider/internal/ProviderInterface.h>
3414+#include <unity/storage/provider/internal/dbusmarshal.h>
3415+#include "provideradaptor.h"
3416+
3417+#include <OnlineAccounts/Account>
3418+
3419+#include <stdexcept>
3420+
3421+using namespace std;
3422+
3423+namespace unity
3424+{
3425+namespace storage
3426+{
3427+namespace provider
3428+{
3429+namespace internal
3430+{
3431+
3432+TestServerImpl::TestServerImpl(unique_ptr<ProviderBase>&& provider,
3433+ OnlineAccounts::Account* account,
3434+ QDBusConnection const& connection,
3435+ string const& object_path)
3436+ : connection_(connection), object_path_(object_path)
3437+{
3438+ qDBusRegisterMetaType<Item>();
3439+ qDBusRegisterMetaType<std::vector<Item>>();
3440+
3441+ auto peer_cache = make_shared<DBusPeerCache>(connection_);
3442+ auto account_data = make_shared<AccountData>(
3443+ move(provider), peer_cache, connection_, account);
3444+ interface_.reset(new ProviderInterface(account_data));
3445+ new ProviderAdaptor(interface_.get());
3446+
3447+ if (!connection_.registerObject(QString::fromStdString(object_path_),
3448+ interface_.get()))
3449+ {
3450+ string msg = "Could not register provider on connection: " + connection_.lastError().message().toStdString();
3451+ throw ResourceException(msg, int(connection_.lastError().type()));
3452+ }
3453+}
3454+
3455+TestServerImpl::~TestServerImpl()
3456+{
3457+ connection_.unregisterObject(QString::fromStdString(object_path_));
3458+}
3459+
3460+QDBusConnection const& TestServerImpl::connection() const
3461+{
3462+ return connection_;
3463+}
3464+
3465+string const& TestServerImpl::object_path() const
3466+{
3467+ return object_path_;
3468+}
3469+
3470+}
3471+}
3472+}
3473+}
3474
3475=== modified file 'src/provider/internal/UploadJobImpl.cpp'
3476--- src/provider/internal/UploadJobImpl.cpp 2016-07-12 02:22:05 +0000
3477+++ src/provider/internal/UploadJobImpl.cpp 2016-09-09 02:13:43 +0000
3478@@ -17,7 +17,10 @@
3479 */
3480
3481 #include <unity/storage/provider/internal/UploadJobImpl.h>
3482+#include <unity/storage/internal/safe_strerror.h>
3483+#include <unity/storage/provider/Exceptions.h>
3484 #include <unity/storage/provider/UploadJob.h>
3485+#include <unity/storage/provider/internal/MainLoopExecutor.h>
3486
3487 #include <sys/socket.h>
3488 #include <sys/types.h>
3489@@ -26,6 +29,7 @@
3490 #include <stdexcept>
3491
3492 using namespace std;
3493+using namespace unity::storage::internal;
3494
3495 namespace unity
3496 {
3497@@ -42,18 +46,30 @@
3498 int socks[2];
3499 if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) < 0)
3500 {
3501- throw runtime_error("could not create socketpair");
3502+ int error_code = errno;
3503+ string msg = "could not create socketpair: " + safe_strerror(error_code);
3504+ throw ResourceException(msg, error_code);
3505 }
3506 read_socket_ = socks[0];
3507 write_socket_ = socks[1];
3508+
3509+#if 0
3510+ // TODO: We should be able to half-close the write channel of the read socket, and the read channel of
3511+ // the write socket. But, if we do, QLocalSocket indicates that everything was closed, which causes
3512+ // failures on the client side. We suspect a QLocalSocket bug -- need to investigate.
3513 if (shutdown(read_socket_, SHUT_WR) < 0)
3514 {
3515- throw runtime_error("Could not shut down write channel on read socket");
3516+ int error_code = errno;
3517+ string msg = "could not shut down write channel on read socket: " + safe_strerror(error_code);
3518+ throw ResourceException(msg, error_code);
3519 }
3520 if (shutdown(write_socket_, SHUT_RD) < 0)
3521 {
3522- throw runtime_error("Could not shut down read channel on write socket");
3523+ int error_code = errno;
3524+ string msg = "Could not shut down read channel on write socket" + safe_strerror(error_code);
3525+ throw ResourceException(msg, error_code);
3526 }
3527+#endif
3528 }
3529
3530 UploadJobImpl::~UploadJobImpl()
3531@@ -72,7 +88,7 @@
3532 {
3533 }
3534
3535-std::string const& UploadJobImpl::upload_id() const
3536+string const& UploadJobImpl::upload_id() const
3537 {
3538 return upload_id_;
3539 }
3540@@ -90,28 +106,29 @@
3541 return sock;
3542 }
3543
3544-string const& UploadJobImpl::sender_bus_name() const
3545-{
3546- return sender_bus_name_;
3547-}
3548-
3549-void UploadJobImpl::set_sender_bus_name(string const& bus_name)
3550-{
3551- assert(bus_name[0] == ':');
3552- sender_bus_name_ = bus_name;
3553-}
3554-
3555-void UploadJobImpl::report_error(std::exception_ptr p)
3556+void UploadJobImpl::report_error(exception_ptr p)
3557 {
3558 if (read_socket_ >= 0)
3559 {
3560- close(write_socket_);
3561+ close(read_socket_);
3562 read_socket_ = -1;
3563 }
3564
3565 lock_guard<mutex> guard(completion_lock_);
3566 completed_ = true;
3567- completion_promise_.set_exception(p);
3568+ // Convert std::exception_ptr to boost::exception_ptr
3569+ try
3570+ {
3571+ rethrow_exception(p);
3572+ }
3573+ catch (StorageException const& e)
3574+ {
3575+ completion_promise_.set_exception(e);
3576+ }
3577+ catch (...)
3578+ {
3579+ completion_promise_.set_exception(boost::current_exception());
3580+ }
3581 }
3582
3583 boost::future<Item> UploadJobImpl::finish(UploadJob& job)
3584
3585=== modified file 'src/provider/internal/dbusmarshal.cpp'
3586--- src/provider/internal/dbusmarshal.cpp 2016-07-21 12:48:40 +0000
3587+++ src/provider/internal/dbusmarshal.cpp 2016-09-09 02:13:43 +0000
3588@@ -31,29 +31,57 @@
3589 namespace provider
3590 {
3591
3592+namespace
3593+{
3594+
3595+QDBusVariant to_qdbus_variant(MetadataValue const& v)
3596+{
3597+ switch (v.which())
3598+ {
3599+ case 0:
3600+ return QDBusVariant(QString::fromStdString(boost::get<string>(v)));
3601+ case 1:
3602+ return QDBusVariant(qlonglong(boost::get<int64_t>(v)));
3603+ default:
3604+ abort(); // Impossible. // LCOV_EXCL_LINE
3605+ }
3606+}
3607+
3608+} // namespace
3609+
3610 QDBusArgument& operator<<(QDBusArgument& argument, Item const& item)
3611 {
3612 argument.beginStructure();
3613 argument << QString::fromStdString(item.item_id);
3614- argument << QString::fromStdString(item.parent_id);
3615+ {
3616+ argument.beginArray(qMetaTypeId<QString>());
3617+ for (auto const& id : item.parent_ids)
3618+ {
3619+ argument << QString::fromStdString(id);
3620+ }
3621+ argument.endArray();
3622+ }
3623 argument << QString::fromStdString(item.name);
3624 argument << QString::fromStdString(item.etag);
3625 argument << static_cast<int32_t>(item.type);
3626- argument.beginMap(QVariant::String, qMetaTypeId<QDBusVariant>());
3627- for (auto const& pair : item.metadata)
3628 {
3629- argument.beginMapEntry();
3630- argument << QString::fromStdString(pair.first) << QDBusVariant(QString::fromStdString(pair.second));
3631- argument.endMapEntry();
3632+ argument.beginMap(QVariant::String, qMetaTypeId<QDBusVariant>());
3633+ for (auto const& pair : item.metadata)
3634+ {
3635+ argument.beginMapEntry();
3636+ argument << QString::fromStdString(pair.first) << to_qdbus_variant(pair.second);
3637+ argument.endMapEntry();
3638+ }
3639+ argument.endMap();
3640 }
3641- argument.endMap();
3642 argument.endStructure();
3643 return argument;
3644 }
3645
3646 QDBusArgument const& operator>>(QDBusArgument const&, Item&)
3647 {
3648- throw std::runtime_error("Item decode not implemented");
3649+ // We don't expect to ever have to unmarshal anything, only marshal it.
3650+ qFatal("unexpected call to operator>>(QDBusArgument const&, Item&)"); // LCOV_EXCL_LINE
3651 }
3652
3653 QDBusArgument& operator<<(QDBusArgument& argument, ItemList const& items)
3654@@ -69,7 +97,8 @@
3655
3656 QDBusArgument const& operator>>(QDBusArgument const&, ItemList&)
3657 {
3658- throw std::runtime_error("std::vector<Item> decode not implemented");
3659+ // We don't expect to ever have to unmarshal anything, only marshal it.
3660+ qFatal("unexpected call to operator>>(QDBusArgument const&, ItemList&)"); // LCOV_EXCL_LINE
3661 }
3662
3663 }
3664
3665=== added directory 'src/provider/testing'
3666=== added file 'src/provider/testing/TestServer.cpp'
3667--- src/provider/testing/TestServer.cpp 1970-01-01 00:00:00 +0000
3668+++ src/provider/testing/TestServer.cpp 2016-09-09 02:13:43 +0000
3669@@ -0,0 +1,60 @@
3670+/*
3671+ * Copyright (C) 2016 Canonical Ltd
3672+ *
3673+ * This program is free software: you can redistribute it and/or modify
3674+ * it under the terms of the GNU Lesser General Public License version 3 as
3675+ * published by the Free Software Foundation.
3676+ *
3677+ * This program is distributed in the hope that it will be useful,
3678+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3679+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3680+ * GNU Lesser General Public License for more details.
3681+ *
3682+ * You should have received a copy of the GNU Lesser General Public License
3683+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3684+ *
3685+ * Authors: James Henstridge <james.henstridge@canonical.com>
3686+ */
3687+
3688+#include <unity/storage/provider/testing/TestServer.h>
3689+#include <unity/storage/provider/internal/TestServerImpl.h>
3690+#include <unity/storage/provider/ProviderBase.h>
3691+
3692+#include <OnlineAccounts/Account>
3693+
3694+using namespace std;
3695+
3696+namespace unity
3697+{
3698+namespace storage
3699+{
3700+namespace provider
3701+{
3702+namespace testing
3703+{
3704+
3705+TestServer::TestServer(unique_ptr<ProviderBase>&& provider,
3706+ OnlineAccounts::Account* account,
3707+ QDBusConnection const& connection,
3708+ string const& object_path)
3709+ : p_(new internal::TestServerImpl(move(provider), account,
3710+ connection, object_path))
3711+{
3712+}
3713+
3714+TestServer::~TestServer() = default;
3715+
3716+QDBusConnection const& TestServer::connection() const
3717+{
3718+ return p_->connection();
3719+}
3720+
3721+string const& TestServer::object_path() const
3722+{
3723+ return p_->object_path();
3724+}
3725+
3726+}
3727+}
3728+}
3729+}
3730
3731=== modified file 'src/qt/client/Account.cpp'
3732--- src/qt/client/Account.cpp 2016-07-12 02:22:05 +0000
3733+++ src/qt/client/Account.cpp 2016-09-09 02:13:43 +0000
3734@@ -41,7 +41,7 @@
3735
3736 Account::~Account() = default;
3737
3738-Runtime* Account::runtime() const
3739+shared_ptr<Runtime> Account::runtime() const
3740 {
3741 return p_->runtime();
3742 }
3743
3744=== modified file 'src/qt/client/CMakeLists.txt'
3745--- src/qt/client/CMakeLists.txt 2016-07-27 02:19:17 +0000
3746+++ src/qt/client/CMakeLists.txt 2016-09-09 02:13:43 +0000
3747@@ -80,7 +80,7 @@
3748 # Build the remote client library
3749 set_source_files_properties(${CMAKE_SOURCE_DIR}/data/provider.xml PROPERTIES
3750 CLASSNAME ProviderInterface
3751- INCLUDE unity/storage/qt/client/internal/remote_client/dbusmarshal.h
3752+ INCLUDE unity/storage/internal/dbusmarshal.h
3753 )
3754
3755 qt5_add_dbus_interface(generated_files
3756@@ -109,6 +109,7 @@
3757 VERSION ${SF_CLIENT_LIBVERSION}
3758 )
3759 target_link_libraries(storage-framework-qt-client
3760+ storage-framework-common-internal
3761 Qt5::Concurrent
3762 Qt5::Core
3763 Qt5::DBus
3764
3765=== modified file 'src/qt/client/Exceptions.cpp'
3766--- src/qt/client/Exceptions.cpp 2016-07-22 01:45:39 +0000
3767+++ src/qt/client/Exceptions.cpp 2016-09-09 02:13:43 +0000
3768@@ -42,6 +42,11 @@
3769 return what_string_.c_str();
3770 }
3771
3772+QString StorageException::error_message() const
3773+{
3774+ return error_message_;
3775+}
3776+
3777 LocalCommsException::LocalCommsException(QString const& error_message)
3778 : StorageException("LocalCommsException", error_message)
3779 {
3780@@ -76,10 +81,9 @@
3781 throw *this;
3782 }
3783
3784-DeletedException::DeletedException(QString const& error_message, QString const& identity, QString const& name)
3785+DeletedException::DeletedException(QString const& error_message, QString const& identity)
3786 : StorageException("DeletedException", error_message)
3787 , identity_(identity)
3788- , name_(name)
3789 {
3790 }
3791
3792@@ -100,13 +104,8 @@
3793 return identity_;
3794 }
3795
3796-QString DeletedException::name() const
3797-{
3798- return name_;
3799-}
3800-
3801 RuntimeDestroyedException::RuntimeDestroyedException(QString const& method)
3802- : StorageException("RuntimeDestroyedException", method + ": Runtime was destroyed previously")
3803+ : StorageException("RuntimeDestroyedException", method + ": runtime was destroyed previously")
3804 {
3805 }
3806
3807@@ -276,8 +275,9 @@
3808 throw *this;
3809 }
3810
3811-ResourceException::ResourceException(QString const& error_message)
3812+ResourceException::ResourceException(QString const& error_message, int error_code)
3813 : StorageException("ResourceException", error_message)
3814+ , error_code_(error_code)
3815 {
3816 }
3817
3818@@ -293,6 +293,11 @@
3819 throw *this;
3820 }
3821
3822+int ResourceException::error_code() const noexcept
3823+{
3824+ return error_code_;
3825+}
3826+
3827 } // namespace client
3828 } // namespace qt
3829 } // namespace storage
3830
3831=== modified file 'src/qt/client/Item.cpp'
3832--- src/qt/client/Item.cpp 2016-07-14 00:25:40 +0000
3833+++ src/qt/client/Item.cpp 2016-09-09 02:13:43 +0000
3834@@ -51,7 +51,7 @@
3835 return p_->name();
3836 }
3837
3838-Root* Item::root() const
3839+shared_ptr<Root> Item::root() const
3840 {
3841 return p_->root();
3842 }
3843
3844=== modified file 'src/qt/client/Root.cpp'
3845--- src/qt/client/Root.cpp 2016-07-12 02:22:05 +0000
3846+++ src/qt/client/Root.cpp 2016-09-09 02:13:43 +0000
3847@@ -30,6 +30,7 @@
3848 {
3849
3850 using namespace internal;
3851+using namespace std;
3852
3853 Root::Root(RootBase* p)
3854 : Folder(p)
3855@@ -38,7 +39,7 @@
3856
3857 Root::~Root() = default;
3858
3859-Account* Root::account() const
3860+shared_ptr<Account> Root::account() const
3861 {
3862 return dynamic_cast<RootBase*>(p_.get())->account();
3863 }
3864
3865=== modified file 'src/qt/client/Runtime.cpp'
3866--- src/qt/client/Runtime.cpp 2016-07-21 04:00:29 +0000
3867+++ src/qt/client/Runtime.cpp 2016-09-09 02:13:43 +0000
3868@@ -64,6 +64,12 @@
3869 return p_->accounts();
3870 }
3871
3872+shared_ptr<Account> Runtime::make_test_account(QString const& bus_name,
3873+ QString const& object_path)
3874+{
3875+ return p_->make_test_account(bus_name, object_path);
3876+}
3877+
3878 } // namespace client
3879 } // namespace qt
3880 } // namespace storage
3881
3882=== modified file 'src/qt/client/Uploader.cpp'
3883--- src/qt/client/Uploader.cpp 2016-07-12 02:22:05 +0000
3884+++ src/qt/client/Uploader.cpp 2016-09-09 02:13:43 +0000
3885@@ -46,6 +46,11 @@
3886 return p_->socket();
3887 }
3888
3889+int64_t Uploader::size() const
3890+{
3891+ return p_->size();
3892+}
3893+
3894 QFuture<shared_ptr<File>> Uploader::finish_upload()
3895 {
3896 return p_->finish_upload();
3897
3898=== modified file 'src/qt/client/internal/AccountBase.cpp'
3899--- src/qt/client/internal/AccountBase.cpp 2016-07-14 04:50:36 +0000
3900+++ src/qt/client/internal/AccountBase.cpp 2016-09-09 02:13:43 +0000
3901@@ -19,6 +19,8 @@
3902 #include <unity/storage/qt/client/internal/AccountBase.h>
3903
3904 #include <unity/storage/qt/client/Exceptions.h>
3905+#include <unity/storage/qt/client/internal/RuntimeBase.h>
3906+#include <unity/storage/qt/client/Runtime.h>
3907
3908 #include <cassert>
3909
3910@@ -42,13 +44,18 @@
3911 assert(runtime.lock());
3912 }
3913
3914-Runtime* AccountBase::runtime() const
3915+shared_ptr<Runtime> AccountBase::runtime() const
3916 {
3917 if (auto runtime = runtime_.lock())
3918 {
3919- return runtime.get();
3920+ auto runtime_base = runtime->p_;
3921+ if (runtime_base->destroyed_)
3922+ {
3923+ throw RuntimeDestroyedException("Account::runtime()");
3924+ }
3925+ return runtime;
3926 }
3927- throw RuntimeDestroyedException("AccountBase::runtime()");
3928+ throw RuntimeDestroyedException("Account::runtime()");
3929 }
3930
3931 void AccountBase::set_public_instance(weak_ptr<Account> const& p)
3932
3933=== modified file 'src/qt/client/internal/ItemBase.cpp'
3934--- src/qt/client/internal/ItemBase.cpp 2016-07-14 04:50:36 +0000
3935+++ src/qt/client/internal/ItemBase.cpp 2016-09-09 02:13:43 +0000
3936@@ -18,7 +18,9 @@
3937
3938 #include <unity/storage/qt/client/internal/ItemBase.h>
3939
3940+#include <unity/storage/qt/client/Account.h>
3941 #include <unity/storage/qt/client/Exceptions.h>
3942+#include <unity/storage/qt/client/Root.h>
3943
3944 #include <cassert>
3945
3946@@ -46,21 +48,24 @@
3947
3948 QString ItemBase::native_identity() const
3949 {
3950+ throw_if_destroyed("Item::native_identity()");
3951 return identity_;
3952 }
3953
3954 ItemType ItemBase::type() const
3955 {
3956+ throw_if_destroyed("Item::type()");
3957 return type_;
3958 }
3959
3960-Root* ItemBase::root() const
3961+shared_ptr<Root> ItemBase::root() const
3962 {
3963- if (auto r = root_.lock())
3964+ auto root = get_root();
3965+ if (!root)
3966 {
3967- return r.get();
3968+ throw RuntimeDestroyedException("Item::root()");
3969 }
3970- throw RuntimeDestroyedException("Item::root()");
3971+ return root;
3972 }
3973
3974 void ItemBase::set_root(std::weak_ptr<Root> root)
3975@@ -75,6 +80,36 @@
3976 public_instance_ = p;
3977 }
3978
3979+shared_ptr<Root> ItemBase::get_root() const noexcept
3980+{
3981+ try
3982+ {
3983+ auto root = root_.lock();
3984+ if (root)
3985+ {
3986+ root->account(); // Throws if either account or runtime has been destroyed.
3987+ return root;
3988+ }
3989+ }
3990+ catch (RuntimeDestroyedException const&)
3991+ {
3992+ }
3993+ return nullptr;
3994+}
3995+
3996+void ItemBase::throw_if_destroyed(QString const& method) const
3997+{
3998+ if (deleted_)
3999+ {
4000+ QString msg = method + ": \"" + identity_ + "\" was deleted previously";
4001+ throw DeletedException(msg, identity_);
4002+ }
4003+ if (!get_root())
4004+ {
4005+ throw RuntimeDestroyedException(method);
4006+ }
4007+}
4008+
4009 } // namespace internal
4010 } // namespace client
4011 } // namespace qt
4012
4013=== modified file 'src/qt/client/internal/RootBase.cpp'
4014--- src/qt/client/internal/RootBase.cpp 2016-07-27 02:19:17 +0000
4015+++ src/qt/client/internal/RootBase.cpp 2016-09-09 02:13:43 +0000
4016@@ -18,6 +18,7 @@
4017
4018 #include <unity/storage/qt/client/internal/RootBase.h>
4019
4020+#include <unity/storage/qt/client/Account.h>
4021 #include <unity/storage/qt/client/Exceptions.h>
4022
4023 #include <cassert>
4024@@ -43,11 +44,19 @@
4025 assert(account.lock());
4026 }
4027
4028-Account* RootBase::account() const
4029+shared_ptr<Account> RootBase::account() const
4030 {
4031 if (auto acc = account_.lock())
4032 {
4033- return acc.get();
4034+ try
4035+ {
4036+ acc->runtime();
4037+ }
4038+ catch (RuntimeDestroyedException const&)
4039+ {
4040+ throw RuntimeDestroyedException("Root::account()");
4041+ }
4042+ return acc;
4043 }
4044 throw RuntimeDestroyedException("Root::account()");
4045 }
4046
4047=== modified file 'src/qt/client/internal/RuntimeBase.cpp'
4048--- src/qt/client/internal/RuntimeBase.cpp 2016-07-12 02:22:05 +0000
4049+++ src/qt/client/internal/RuntimeBase.cpp 2016-09-09 02:13:43 +0000
4050@@ -34,11 +34,6 @@
4051 namespace internal
4052 {
4053
4054-RuntimeBase::RuntimeBase()
4055- : destroyed_(false)
4056-{
4057-}
4058-
4059 void RuntimeBase::set_public_instance(weak_ptr<Runtime> p)
4060 {
4061 assert(p.lock());
4062
4063=== modified file 'src/qt/client/internal/UploaderBase.cpp'
4064--- src/qt/client/internal/UploaderBase.cpp 2016-07-22 01:45:39 +0000
4065+++ src/qt/client/internal/UploaderBase.cpp 2016-09-09 02:13:43 +0000
4066@@ -25,6 +25,8 @@
4067 #include <QFuture>
4068 #pragma GCC diagnostic pop
4069
4070+#include <cassert>
4071+
4072 using namespace std;
4073
4074 namespace unity
4075@@ -38,9 +40,16 @@
4076 namespace internal
4077 {
4078
4079-UploaderBase::UploaderBase(ConflictPolicy policy)
4080+UploaderBase::UploaderBase(ConflictPolicy policy, int64_t size)
4081 : policy_(policy)
4082-{
4083+ , size_(size)
4084+{
4085+ assert(size >= 0);
4086+}
4087+
4088+int64_t UploaderBase::size() const
4089+{
4090+ return size_;
4091 }
4092
4093 } // namespace internal
4094
4095=== modified file 'src/qt/client/internal/local_client/AccountImpl.cpp'
4096--- src/qt/client/internal/local_client/AccountImpl.cpp 2016-07-14 04:50:36 +0000
4097+++ src/qt/client/internal/local_client/AccountImpl.cpp 2016-09-09 02:13:43 +0000
4098@@ -67,7 +67,7 @@
4099 if (ec)
4100 {
4101 QString msg = "Account::roots(): Cannot stat " + QString(dir) + ": " + QString::fromStdString(ec.message());
4102- throw ResourceException(msg);
4103+ throw ResourceException(msg, errno);
4104 }
4105 if (!is_dir)
4106 {
4107@@ -85,7 +85,7 @@
4108 {
4109 QString msg = "Account::roots(): Cannot create " + QString(dir) + ": "
4110 + QString::fromStdString(ec.message());
4111- throw ResourceException(msg);
4112+ throw ResourceException(msg, ec.value());
4113 }
4114 }
4115 return data_dir;
4116@@ -109,22 +109,32 @@
4117
4118 QString AccountImpl::owner() const
4119 {
4120+ runtime(); // Throws RuntimeDestroyedException if runtime was destroyed.
4121 return owner_;
4122 }
4123
4124 QString AccountImpl::owner_id() const
4125 {
4126+ runtime(); // Throws RuntimeDestroyedException if runtime was destroyed.
4127 return owner_id_;
4128 }
4129
4130 QString AccountImpl::description() const
4131 {
4132+ runtime(); // Throws RuntimeDestroyedException if runtime was destroyed.
4133 return description_;
4134 }
4135
4136 QFuture<QVector<Root::SPtr>> AccountImpl::roots()
4137 {
4138- using namespace boost::filesystem;
4139+ try
4140+ {
4141+ runtime(); // Throws RuntimeDestroyedException if runtime was destroyed.
4142+ }
4143+ catch (RuntimeDestroyedException const& e)
4144+ {
4145+ return make_exceptional_future<QVector<Root::SPtr>>(e);
4146+ }
4147
4148 if (!roots_.isEmpty())
4149 {
4150@@ -132,6 +142,9 @@
4151 }
4152
4153 // Create the root on first access.
4154+
4155+ using namespace boost::filesystem;
4156+
4157 auto rpath = canonical(get_data_dir()).native();
4158 auto root = RootImpl::make_root(QString::fromStdString(rpath), public_instance_);
4159 roots_.append(root);
4160
4161=== modified file 'src/qt/client/internal/local_client/CMakeLists.txt'
4162--- src/qt/client/internal/local_client/CMakeLists.txt 2016-07-22 00:17:24 +0000
4163+++ src/qt/client/internal/local_client/CMakeLists.txt 2016-09-09 02:13:43 +0000
4164@@ -7,6 +7,7 @@
4165 ${CMAKE_CURRENT_SOURCE_DIR}/RootImpl.cpp
4166 ${CMAKE_CURRENT_SOURCE_DIR}/Runtime_create.cpp
4167 ${CMAKE_CURRENT_SOURCE_DIR}/RuntimeImpl.cpp
4168+ ${CMAKE_CURRENT_SOURCE_DIR}/storage_exception.cpp
4169 ${CMAKE_CURRENT_SOURCE_DIR}/UploaderImpl.cpp
4170 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/client/internal/local_client/DownloaderImpl.h
4171 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/client/internal/local_client/UploaderImpl.h
4172
4173=== modified file 'src/qt/client/internal/local_client/DownloaderImpl.cpp'
4174--- src/qt/client/internal/local_client/DownloaderImpl.cpp 2016-07-22 00:17:24 +0000
4175+++ src/qt/client/internal/local_client/DownloaderImpl.cpp 2016-09-09 02:13:43 +0000
4176@@ -23,7 +23,10 @@
4177 #include <unity/storage/qt/client/File.h>
4178 #include <unity/storage/qt/client/internal/make_future.h>
4179
4180+#pragma GCC diagnostic push
4181+#pragma GCC diagnostic ignored "-Wcast-align"
4182 #include <QLocalSocket>
4183+#pragma GCC diagnostic pop
4184
4185 #include <cassert>
4186
4187@@ -79,8 +82,10 @@
4188 input_file_.reset(new QFile(filename_));
4189 if (!input_file_->open(QIODevice::ReadOnly))
4190 {
4191- handle_error("cannot open " + filename_ + ": " + input_file_->errorString());
4192+ // LCOV_EXCL_START
4193+ handle_error("cannot open " + filename_ + ": " + input_file_->errorString(), input_file_->error());
4194 return;
4195+ // LCOV_EXCL_STOP
4196 }
4197 bytes_to_write_ = input_file_->size();
4198
4199@@ -116,7 +121,7 @@
4200 + QString::number(written) + " byte";
4201 msg += written == 1 ? " was" : "s were";
4202 msg += " consumed.";
4203- make_exceptional_future(qf_, LogicException(msg));
4204+ qf_.reportException(LogicException(msg));
4205 }
4206 else
4207 {
4208@@ -131,12 +136,12 @@
4209 case cancelled:
4210 {
4211 QString msg = "Downloader::finish_download(): download of " + filename_ + " was cancelled";
4212- make_exceptional_future(qf_, CancelledException(msg));
4213+ qf_.reportException(CancelledException(msg));
4214 break;
4215 }
4216 case error:
4217 {
4218- make_exceptional_future(qf_, ResourceException(error_msg_));
4219+ qf_.reportException(ResourceException(error_msg_, error_code_));
4220 break;
4221 }
4222 default:
4223@@ -144,7 +149,7 @@
4224 abort(); // LCOV_EXCL_LINE // Impossible
4225 }
4226 }
4227- make_ready_future(qf_);
4228+ qf_.reportFinished();
4229 QThread::currentThread()->quit();
4230 }
4231
4232@@ -189,7 +194,8 @@
4233
4234 void DownloadWorker::on_error()
4235 {
4236- handle_error(write_socket_->errorString());
4237+ disconnect(write_socket_.get(), nullptr, this, nullptr);
4238+ handle_error(write_socket_->errorString(), write_socket_->error());
4239 }
4240
4241 // Read the next chunk of data from the input file and write it to the socket.
4242@@ -203,25 +209,31 @@
4243 auto bytes_read = input_file_->read(buf.data(), buf.size());
4244 if (bytes_read == -1)
4245 {
4246- handle_error(filename_ + ": read error: " + input_file_->errorString());
4247+ // LCOV_EXCL_START
4248+ handle_error(filename_ + ": read error: " + input_file_->errorString(), input_file_->error());
4249 return;
4250+ // LCOV_EXCL_STOP
4251 }
4252 buf.resize(bytes_read);
4253
4254 auto bytes_written = write_socket_->write(buf);
4255 if (bytes_written == -1)
4256 {
4257- handle_error(filename_ + ": socket error: " + write_socket_->errorString());
4258+ // LCOV_EXCL_START
4259+ handle_error(filename_ + ": socket error: " + write_socket_->errorString(), write_socket_->error());
4260+ // LCOV_EXCL_STOP
4261 }
4262 else if (bytes_written != bytes_read)
4263 {
4264+ // LCOV_EXCL_START
4265 QString msg = filename_ + ": write error, requested " + bytes_read + " B, but wrote only "
4266 + bytes_written + " B.";
4267- handle_error(msg);
4268+ handle_error(msg, 0);
4269+ // LCOV_EXCL_STOP
4270 }
4271 }
4272
4273-void DownloadWorker::handle_error(QString const& msg)
4274+void DownloadWorker::handle_error(QString const& msg, int error_code)
4275 {
4276 if (state_ == in_progress)
4277 {
4278@@ -229,6 +241,7 @@
4279 }
4280 state_ = error;
4281 error_msg_ = "Downloader: " + msg;
4282+ error_code_ = error_code;
4283 do_finish();
4284 }
4285
4286@@ -245,17 +258,18 @@
4287
4288 DownloaderImpl::DownloaderImpl(weak_ptr<File> file)
4289 : DownloaderBase(file)
4290- , read_socket_(new QLocalSocket)
4291+ , read_socket_(new QLocalSocket, [](QLocalSocket* s){ s->deleteLater(); })
4292 {
4293 // Set up socket pair.
4294 int fds[2];
4295- int rc = socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fds);
4296+ int rc = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
4297 if (rc == -1)
4298 {
4299 // LCOV_EXCL_START
4300 QString msg = "Downloader: cannot create socket pair: "
4301 + QString::fromStdString(storage::internal::safe_strerror(errno));
4302- make_exceptional_future(qf_, ResourceException(msg));
4303+ qf_.reportException(ResourceException(msg, errno));
4304+ qf_.reportFinished();
4305 return;
4306 // LCOV_EXCL_STOP
4307 }
4308
4309=== modified file 'src/qt/client/internal/local_client/FileImpl.cpp'
4310--- src/qt/client/internal/local_client/FileImpl.cpp 2016-07-22 01:45:39 +0000
4311+++ src/qt/client/internal/local_client/FileImpl.cpp 2016-09-09 02:13:43 +0000
4312@@ -22,6 +22,7 @@
4313 #include <unity/storage/qt/client/Exceptions.h>
4314 #include <unity/storage/qt/client/File.h>
4315 #include <unity/storage/qt/client/internal/local_client/DownloaderImpl.h>
4316+#include <unity/storage/qt/client/internal/local_client/storage_exception.h>
4317 #include <unity/storage/qt/client/internal/local_client/UploaderImpl.h>
4318 #include <unity/storage/qt/client/internal/make_future.h>
4319 #include <unity/storage/qt/client/Uploader.h>
4320@@ -50,47 +51,44 @@
4321
4322 QString FileImpl::name() const
4323 {
4324- lock_guard<mutex> guard(mutex_);
4325+ lock_guard<decltype(mutex_)> guard(mutex_);
4326
4327- if (deleted_)
4328- {
4329- throw deleted_ex("File::name()");
4330- }
4331+ throw_if_destroyed("File::name()");
4332 return name_;
4333 }
4334
4335 int64_t FileImpl::size() const
4336 {
4337- lock_guard<mutex> guard(mutex_);
4338-
4339- if (deleted_)
4340- {
4341- throw deleted_ex("File::size()");
4342- }
4343-
4344+ lock_guard<decltype(mutex_)> guard(mutex_);
4345+
4346+ throw_if_destroyed("File::size()");
4347 try
4348 {
4349 boost::filesystem::path p = identity_.toStdString();
4350 return file_size(p);
4351 }
4352- catch (std::exception const& e)
4353+ catch (std::exception const&)
4354 {
4355- throw ResourceException(e.what());
4356+ throw_storage_exception(QString("File::size()"), current_exception());
4357 }
4358 }
4359
4360 QFuture<Uploader::SPtr> FileImpl::create_uploader(ConflictPolicy policy, int64_t size)
4361 {
4362- lock_guard<mutex> guard(mutex_);
4363+ lock_guard<decltype(mutex_)> guard(mutex_);
4364
4365- if (deleted_)
4366- {
4367- return make_exceptional_future<Uploader::SPtr>(deleted_ex("File::create_uploader()"));
4368+ try
4369+ {
4370+ throw_if_destroyed("File::create_uploader()");
4371+ }
4372+ catch (StorageException const& e)
4373+ {
4374+ return internal::make_exceptional_future<Uploader::SPtr>(e);
4375 }
4376 if (size < 0)
4377 {
4378 QString msg = "File::create_uploader(): size must be >= 0";
4379- return make_exceptional_future<shared_ptr<Uploader>>(InvalidArgumentException(msg));
4380+ return internal::make_exceptional_future<shared_ptr<Uploader>>(InvalidArgumentException(msg));
4381 }
4382
4383 auto file = dynamic_pointer_cast<File>(public_instance_.lock());
4384@@ -102,11 +100,15 @@
4385
4386 QFuture<Downloader::SPtr> FileImpl::create_downloader()
4387 {
4388- lock_guard<mutex> guard(mutex_);
4389+ lock_guard<decltype(mutex_)> guard(mutex_);
4390
4391- if (deleted_)
4392- {
4393- return make_exceptional_future<Downloader::SPtr>(deleted_ex("File::create_downloader()"));
4394+ try
4395+ {
4396+ throw_if_destroyed("File::create_downloader()");
4397+ }
4398+ catch (StorageException const& e)
4399+ {
4400+ return internal::make_exceptional_future<Downloader::SPtr>(e);
4401 }
4402
4403 auto pi = public_instance_.lock();
4404
4405=== modified file 'src/qt/client/internal/local_client/FolderImpl.cpp'
4406--- src/qt/client/internal/local_client/FolderImpl.cpp 2016-07-22 01:45:39 +0000
4407+++ src/qt/client/internal/local_client/FolderImpl.cpp 2016-09-09 02:13:43 +0000
4408@@ -24,7 +24,8 @@
4409 #include <unity/storage/qt/client/Uploader.h>
4410 #include <unity/storage/qt/client/internal/make_future.h>
4411 #include <unity/storage/qt/client/internal/local_client/FileImpl.h>
4412-#include <unity/storage/qt/client/internal/local_client/tmpfile-prefix.h>
4413+#include <unity/storage/qt/client/internal/local_client/storage_exception.h>
4414+#include <unity/storage/qt/client/internal/local_client/tmpfile_prefix.h>
4415 #include <unity/storage/qt/client/internal/local_client/UploaderImpl.h>
4416
4417 #include <boost/algorithm/string/predicate.hpp>
4418@@ -62,22 +63,36 @@
4419 {
4420 }
4421
4422+QString FolderImpl::name() const
4423+{
4424+ lock_guard<decltype(mutex_)> guard(mutex_);
4425+
4426+ throw_if_destroyed("Item::name()");
4427+ return name_;
4428+}
4429+
4430 QFuture<QVector<Item::SPtr>> FolderImpl::list() const
4431 {
4432+ try
4433+ {
4434+ throw_if_destroyed("Folder::list()");
4435+ }
4436+ catch (StorageException const& e)
4437+ {
4438+ return internal::make_exceptional_future<QVector<Item::SPtr>>(e);
4439+ }
4440+
4441 auto This = dynamic_pointer_cast<FolderImpl const>(shared_from_this()); // Keep this folder alive while the lambda is alive.
4442 auto list = [This]()
4443 {
4444- lock_guard<mutex> guard(This->mutex_);
4445-
4446- if (This->deleted_)
4447- {
4448- throw This->deleted_ex("Folder::list()");
4449- }
4450-
4451+ lock_guard<decltype(mutex_)> guard(This->mutex_);
4452+
4453+ This->throw_if_destroyed("Folder::list()");
4454 try
4455 {
4456 using namespace boost::filesystem;
4457
4458+ auto root = This->root_.lock();
4459 QVector<Item::SPtr> results;
4460 for (directory_iterator it(This->native_identity().toStdString()); it != directory_iterator(); ++it)
4461 {
4462@@ -90,11 +105,11 @@
4463 QString path = QString::fromStdString(dirent.path().native());
4464 if (is_directory(s))
4465 {
4466- results.append(make_folder(path, This->root_));
4467+ results.append(make_folder(path, root));
4468 }
4469 else if (is_regular_file(s))
4470 {
4471- results.append(FileImpl::make_file(path, This->root_));
4472+ results.append(FileImpl::make_file(path, root));
4473 }
4474 else
4475 {
4476@@ -103,9 +118,9 @@
4477 }
4478 return results;
4479 }
4480- catch (std::exception const& e)
4481+ catch (std::exception const&)
4482 {
4483- throw ResourceException(QString("Folder::list(): ") + e.what());
4484+ throw_storage_exception("Folder::list()", current_exception());
4485 }
4486 };
4487 return QtConcurrent::run(list);
4488@@ -113,49 +128,51 @@
4489
4490 QFuture<QVector<Item::SPtr>> FolderImpl::lookup(QString const& name) const
4491 {
4492+ try
4493+ {
4494+ throw_if_destroyed("Folder::lookup()");
4495+ }
4496+ catch (StorageException const& e)
4497+ {
4498+ return internal::make_exceptional_future<QVector<Item::SPtr>>(e);
4499+ }
4500+
4501 auto This = dynamic_pointer_cast<FolderImpl const>(shared_from_this()); // Keep this folder alive while the lambda is alive.
4502 auto lookup = [This, name]() -> QVector<Item::SPtr>
4503 {
4504- lock_guard<mutex> guard(This->mutex_);
4505-
4506- if (This->deleted_)
4507- {
4508- throw This->deleted_ex("Folder::lookup()");
4509- }
4510-
4511+ lock_guard<decltype(mutex_)> guard(This->mutex_);
4512+
4513+ This->throw_if_destroyed("Folder::lookup()"); // LCOV_EXCL_LINE
4514 try
4515 {
4516 using namespace boost::filesystem;
4517
4518+ auto root = This->root_.lock();
4519 path p = This->native_identity().toStdString();
4520 auto sanitized_name = sanitize(name, "Folder::lookup()");
4521 if (is_reserved_path(sanitized_name))
4522 {
4523- throw NotExistsException("Folder::lookup(): no such item: " + name, name);
4524+ throw NotExistsException("Folder::lookup(): no such item: \"" + name + "\"", name);
4525 }
4526 p /= sanitized_name;
4527 file_status s = status(p);
4528 if (is_directory(s))
4529 {
4530 QVector<Item::SPtr> v;
4531- v.append(make_folder(QString::fromStdString(p.native()), This->root_));
4532+ v.append(make_folder(QString::fromStdString(p.native()), root));
4533 return v;
4534 }
4535 if (is_regular_file(s))
4536 {
4537 QVector<Item::SPtr> v;
4538- v.append(FileImpl::make_file(QString::fromStdString(p.native()), This->root_));
4539+ v.append(FileImpl::make_file(QString::fromStdString(p.native()), root));
4540 return v;
4541 }
4542- throw NotExistsException("Folder::lookup(): no such item: " + name, name);
4543- }
4544- catch (StorageException const&)
4545- {
4546- throw;
4547- }
4548- catch (std::exception const& e)
4549- {
4550- throw ResourceException(QString("Folder::lookup(): ") + e.what());
4551+ throw NotExistsException("Folder::lookup(): no such item: \"" + name + "\"", name);
4552+ }
4553+ catch (std::exception const&)
4554+ {
4555+ throw_storage_exception("Folder::lookup()", current_exception());
4556 }
4557 };
4558 return QtConcurrent::run(lookup);
4559@@ -163,12 +180,15 @@
4560
4561 QFuture<Folder::SPtr> FolderImpl::create_folder(QString const& name)
4562 {
4563- lock_guard<mutex> guard(mutex_);
4564+ lock_guard<decltype(mutex_)> guard(mutex_);
4565
4566- QFutureInterface<Folder::SPtr> qf;
4567- if (deleted_)
4568- {
4569- return make_exceptional_future<Folder::SPtr>(deleted_ex("Folder::create_folder()"));
4570+ try
4571+ {
4572+ throw_if_destroyed("Folder::create_folder()");
4573+ }
4574+ catch (StorageException const& e)
4575+ {
4576+ return internal::make_exceptional_future<Folder::SPtr>(e);
4577 }
4578
4579 try
4580@@ -179,31 +199,40 @@
4581 auto sanitized_name = sanitize(name, "Folder::create_folder()");
4582 if (is_reserved_path(sanitized_name))
4583 {
4584- QString msg = "Folder::create_folder(): names beginning with " + QString(TMPFILE_PREFIX) + " are reserved";
4585- return make_exceptional_future<Folder::SPtr>(InvalidArgumentException(msg));
4586+ QString msg = "Folder::create_folder(): names beginning with \"" + QString(TMPFILE_PREFIX) + "\" are reserved";
4587+ throw InvalidArgumentException(msg);
4588 }
4589 p /= sanitized_name;
4590+ if (exists(p))
4591+ {
4592+ QString msg = "Folder::create_folder(): item with name \"" + name + "\" exists already";
4593+ throw ExistsException(msg, native_identity() + "/" + name, name);
4594+ }
4595 create_directory(p);
4596 return make_ready_future(make_folder(QString::fromStdString(p.native()), root_));
4597 }
4598- catch (std::exception const& e)
4599+ catch (std::exception const&)
4600 {
4601- return make_exceptional_future<Folder::SPtr>(ResourceException(QString("Folder::create_folder: ") + e.what()));
4602+ return make_exceptional_future<Folder::SPtr>("Folder::create_folder()", current_exception());
4603 }
4604 }
4605
4606 QFuture<shared_ptr<Uploader>> FolderImpl::create_file(QString const& name, int64_t size)
4607 {
4608- unique_lock<mutex> guard(mutex_);
4609+ lock_guard<decltype(mutex_)> guard(mutex_);
4610
4611- if (deleted_)
4612- {
4613- return make_exceptional_future<Uploader::SPtr>(deleted_ex("Folder::create_file()"));
4614+ try
4615+ {
4616+ throw_if_destroyed("Folder::create_file()");
4617+ }
4618+ catch (StorageException const& e)
4619+ {
4620+ return internal::make_exceptional_future<shared_ptr<Uploader>>(e);
4621 }
4622 if (size < 0)
4623 {
4624 QString msg = "Folder::create_file(): size must be >= 0";
4625- return make_exceptional_future<shared_ptr<Uploader>>(InvalidArgumentException(msg));
4626+ return internal::make_exceptional_future<shared_ptr<Uploader>>(InvalidArgumentException(msg));
4627 }
4628
4629 try
4630@@ -214,14 +243,14 @@
4631 auto sanitized_name = sanitize(name, "Folder::create_file()");
4632 if (is_reserved_path(sanitized_name))
4633 {
4634- QString msg = "Folder::create_file(): names beginning with " + QString(TMPFILE_PREFIX) + " are reserved";
4635- return make_exceptional_future<Uploader::SPtr>(InvalidArgumentException(msg));
4636+ QString msg = "Folder::create_file(): names beginning with \"" + QString(TMPFILE_PREFIX) + "\" are reserved";
4637+ throw InvalidArgumentException(msg);
4638 }
4639 p /= sanitized_name;
4640 if (exists(p))
4641 {
4642 QString msg = "Folder::create_file(): item with name \"" + name + "\" exists already";
4643- return make_exceptional_future<Uploader::SPtr>(ExistsException(msg, native_identity(), name));
4644+ throw ExistsException(msg, native_identity() + "/" + name, name);
4645 }
4646 auto impl = new UploaderImpl(shared_ptr<File>(),
4647 size,
4648@@ -231,9 +260,9 @@
4649 Uploader::SPtr uploader(new Uploader(impl));
4650 return make_ready_future(uploader);
4651 }
4652- catch (std::exception const& e)
4653+ catch (std::exception const&)
4654 {
4655- return make_exceptional_future<Uploader::SPtr>(ResourceException(QString("Folder::create_file: ") + e.what()));
4656+ return make_exceptional_future<Uploader::SPtr>("Folder::create_file()", current_exception());
4657 }
4658 }
4659
4660
4661=== modified file 'src/qt/client/internal/local_client/ItemImpl.cpp'
4662--- src/qt/client/internal/local_client/ItemImpl.cpp 2016-07-22 00:17:24 +0000
4663+++ src/qt/client/internal/local_client/ItemImpl.cpp 2016-09-09 02:13:43 +0000
4664@@ -21,14 +21,16 @@
4665 #include <unity/storage/internal/safe_strerror.h>
4666 #include <unity/storage/qt/client/Account.h>
4667 #include <unity/storage/qt/client/Exceptions.h>
4668-#include <unity/storage/qt/client/internal/make_future.h>
4669 #include <unity/storage/qt/client/internal/local_client/AccountImpl.h>
4670 #include <unity/storage/qt/client/internal/local_client/FileImpl.h>
4671 #include <unity/storage/qt/client/internal/local_client/RootImpl.h>
4672-#include <unity/storage/qt/client/internal/local_client/tmpfile-prefix.h>
4673+#include <unity/storage/qt/client/internal/local_client/storage_exception.h>
4674+#include <unity/storage/qt/client/internal/local_client/tmpfile_prefix.h>
4675+#include <unity/storage/qt/client/internal/make_future.h>
4676
4677 #include <boost/algorithm/string/predicate.hpp>
4678 #pragma GCC diagnostic push
4679+#pragma GCC diagnostic ignored "-Wcast-align"
4680 #pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
4681 #include <QtConcurrent>
4682 #pragma GCC diagnostic pop
4683@@ -54,7 +56,6 @@
4684
4685 ItemImpl::ItemImpl(QString const& identity, ItemType type)
4686 : ItemBase(identity, type)
4687- , deleted_(false)
4688 {
4689 assert(!identity.isEmpty());
4690 auto path = boost::filesystem::canonical(identity.toStdString());
4691@@ -64,102 +65,70 @@
4692
4693 ItemImpl::~ItemImpl() = default;
4694
4695-QString ItemImpl::name() const
4696-{
4697- lock_guard<mutex> guard(mutex_);
4698-
4699- if (deleted_)
4700- {
4701- throw deleted_ex("Item::name()");
4702- }
4703- return name_;
4704-}
4705-
4706 QString ItemImpl::etag() const
4707 {
4708- lock_guard<mutex> guard(mutex_);
4709+ lock_guard<decltype(mutex_)> guard(mutex_);
4710
4711- if (deleted_)
4712- {
4713- throw deleted_ex("Item::etag()");
4714- }
4715+ throw_if_destroyed("Item::etag()");
4716 return etag_;
4717 }
4718
4719 QVariantMap ItemImpl::metadata() const
4720 {
4721- lock_guard<mutex> guard(mutex_);
4722+ lock_guard<decltype(mutex_)> guard(mutex_);
4723
4724- if (deleted_)
4725- {
4726- throw deleted_ex("Item::metadata()");
4727- }
4728+ throw_if_destroyed("Item::metadata()");
4729 return metadata_;
4730 }
4731
4732 QDateTime ItemImpl::last_modified_time() const
4733 {
4734- lock_guard<mutex> guard(mutex_);
4735+ lock_guard<decltype(mutex_)> guard(mutex_);
4736
4737- if (deleted_)
4738- {
4739- throw deleted_ex("Item::last_modified_time()");
4740- }
4741+ throw_if_destroyed("Item::last_modified_time()");
4742 return modified_time_;
4743 }
4744
4745-namespace
4746-{
4747-
4748-using namespace boost::filesystem;
4749-
4750-void copy_recursively(path const& source, path const& target)
4751-{
4752- auto s = status(source);
4753- if (is_regular_file(s))
4754- {
4755- copy_file(source, target);
4756- return;
4757- }
4758- else if (is_directory(s))
4759- {
4760- copy_directory(source, target); // Poorly named in boost; this creates the target dir without recursion
4761- for (directory_iterator it(source); it != directory_iterator(); ++it)
4762- {
4763- path source_entry = it->path();
4764- path target_entry = target;
4765- target_entry /= source_entry.filename();
4766- copy_recursively(source_entry, target_entry);
4767- }
4768- }
4769- else
4770- {
4771- // Ignore everything that's not a directory or file.
4772- }
4773-}
4774-
4775-} // namespace
4776-
4777 QFuture<shared_ptr<Item>> ItemImpl::copy(shared_ptr<Folder> const& new_parent, QString const& new_name)
4778 {
4779+ if (!new_parent)
4780+ {
4781+ QString msg = "Item::copy(): new_parent cannot be nullptr";
4782+ return internal::make_exceptional_future<shared_ptr<Item>>(InvalidArgumentException(msg));
4783+ }
4784+ auto new_parent_impl = dynamic_pointer_cast<FolderImpl>(new_parent->p_);
4785+
4786+ lock(mutex_, new_parent_impl->mutex_);
4787+ lock_guard<decltype(mutex_)> this_guard(mutex_, std::adopt_lock);
4788+ lock_guard<decltype(mutex_)> other_guard(new_parent_impl->mutex_, adopt_lock);
4789+
4790+ try
4791+ {
4792+ throw_if_destroyed("Item::copy()");
4793+ new_parent_impl->throw_if_destroyed("Item::copy()");
4794+ }
4795+ catch (StorageException const& e)
4796+ {
4797+ return internal::make_exceptional_future<shared_ptr<Item>>(e);
4798+ }
4799+
4800 auto This = dynamic_pointer_cast<ItemImpl>(shared_from_this()); // Keep this item alive while the lambda is alive.
4801 auto copy = [This, new_parent, new_name]() -> Item::SPtr
4802 {
4803 auto new_parent_impl = dynamic_pointer_cast<FolderImpl>(new_parent->p_);
4804
4805 lock(This->mutex_, new_parent_impl->mutex_);
4806- lock_guard<mutex> this_guard(This->mutex_, std::adopt_lock);
4807- lock_guard<mutex> other_guard(new_parent_impl->mutex_, adopt_lock);
4808-
4809- if (This->deleted_ || new_parent_impl->deleted_)
4810- {
4811- throw This->deleted_ex("Item::copy");
4812- }
4813-
4814- if (This->root()->account() != new_parent->root()->account())
4815+ lock_guard<decltype(mutex_)> this_guard(This->mutex_, std::adopt_lock);
4816+ lock_guard<decltype(mutex_)> other_guard(new_parent_impl->mutex_, adopt_lock);
4817+
4818+ This->throw_if_destroyed("Item::copy()");
4819+ new_parent_impl->throw_if_destroyed("Item::copy()");
4820+
4821+ // TODO: This needs to deeply compare account identity because the client may have refreshed the accounts list.
4822+ if (This->root()->account() != new_parent->root()->account()) // Throws if account or runtime were destroyed.
4823 {
4824 // Can't do cross-account copy.
4825- QString msg = QString("Item::copy(): Source (") + This->name_ + ") and target ("
4826+ QString msg = QString("Item::copy(): source (") + This->name_ + ") and target ("
4827 + new_name + ") must belong to the same account";
4828 throw LogicException(msg);
4829 }
4830@@ -175,22 +144,22 @@
4831 target_path /= sanitized_name;
4832 if (is_reserved_path(target_path))
4833 {
4834- QString msg = "Item::copy(): names beginning with " + QString(TMPFILE_PREFIX) + " are reserved";
4835+ QString msg = "Item::copy(): names beginning with \"" + QString(TMPFILE_PREFIX) + "\" are reserved";
4836 throw InvalidArgumentException(msg);
4837 }
4838
4839+ if (exists(target_path))
4840+ {
4841+ QString msg = "Item::copy(): item with name \"" + new_name + "\" exists already";
4842+ throw ExistsException(msg, This->identity_, This->name_);
4843+ }
4844+
4845 if (This->type_ == ItemType::file)
4846 {
4847 copy_file(source_path, target_path);
4848 return FileImpl::make_file(QString::fromStdString(target_path.native()), new_parent_impl->root_);
4849 }
4850
4851- if (exists(target_path))
4852- {
4853- QString msg = "Item::copy(): item with name \"" + new_name + "\" exists already";
4854- throw ExistsException(msg, This->identity_, This->name_);
4855- }
4856-
4857 // For recursive copy, we create a temporary directory in lieu of target_path and recursively copy
4858 // everything into the temporary directory. This ensures that we don't invalidate directory iterators
4859 // by creating things while we are iterating, potentially getting trapped in an infinite loop.
4860@@ -199,7 +168,7 @@
4861 create_directories(tmp_path);
4862 for (directory_iterator it(source_path); it != directory_iterator(); ++it)
4863 {
4864- if (tmp_path.compare(canonical(it->path())) == 0)
4865+ if (is_reserved_path(it->path()))
4866 {
4867 continue; // Don't recurse into the temporary directory
4868 }
4869@@ -209,15 +178,15 @@
4870 path source_entry = it->path();
4871 path target_entry = tmp_path;
4872 target_entry /= source_entry.filename();
4873- copy_recursively(source_entry, target_entry);
4874+ ItemImpl::copy_recursively(source_entry, target_entry);
4875 }
4876 }
4877 rename(tmp_path, target_path);
4878 return FolderImpl::make_folder(QString::fromStdString(target_path.native()), new_parent_impl->root_);
4879 }
4880- catch (std::exception const& e)
4881+ catch (std::exception const&)
4882 {
4883- throw ResourceException(QString("Item::copy(): ") + e.what());
4884+ throw_storage_exception("Item::copy()", current_exception());
4885 }
4886 };
4887 return QtConcurrent::run(copy);
4888@@ -225,31 +194,51 @@
4889
4890 QFuture<shared_ptr<Item>> ItemImpl::move(shared_ptr<Folder> const& new_parent, QString const& new_name)
4891 {
4892+ if (!new_parent)
4893+ {
4894+ QString msg = "Item::move(): new_parent cannot be nullptr";
4895+ return internal::make_exceptional_future<shared_ptr<Item>>(InvalidArgumentException(msg));
4896+ }
4897+ auto new_parent_impl = dynamic_pointer_cast<FolderImpl>(new_parent->p_);
4898+
4899+ lock(mutex_, new_parent_impl->mutex_);
4900+ lock_guard<decltype(mutex_)> this_guard(mutex_, std::adopt_lock);
4901+ lock_guard<decltype(mutex_)> other_guard(new_parent_impl->mutex_, adopt_lock);
4902+
4903+ try
4904+ {
4905+ throw_if_destroyed("Item::move()");
4906+ new_parent_impl->throw_if_destroyed("Item::move()");
4907+ }
4908+ catch (StorageException const& e)
4909+ {
4910+ return internal::make_exceptional_future<shared_ptr<Item>>(e);
4911+ }
4912+
4913 auto This = dynamic_pointer_cast<ItemImpl>(shared_from_this()); // Keep this item alive while the lambda is alive.
4914 auto move = [This, new_parent, new_name]() -> Item::SPtr
4915 {
4916 auto new_parent_impl = dynamic_pointer_cast<FolderImpl>(new_parent->p_);
4917
4918 lock(This->mutex_, new_parent_impl->mutex_);
4919- lock_guard<mutex> this_guard(This->mutex_, std::adopt_lock);
4920- lock_guard<mutex> other_guard(new_parent_impl->mutex_, adopt_lock);
4921-
4922- if (This->deleted_ || new_parent_impl->deleted_)
4923- {
4924- throw This->deleted_ex("Item::move");
4925- }
4926-
4927- if (This->root()->account() != new_parent->root()->account())
4928+ lock_guard<decltype(mutex_)> this_guard(This->mutex_, std::adopt_lock);
4929+ lock_guard<decltype(mutex_)> other_guard(new_parent_impl->mutex_, adopt_lock);
4930+
4931+ This->throw_if_destroyed("Item::move()");
4932+ new_parent_impl->throw_if_destroyed("Item::move()");
4933+
4934+ // TODO: This needs to deeply compare account identity because the client may have refreshed the accounts list.
4935+ if (This->root()->account() != new_parent->root()->account()) // Throws if account or runtime were destroyed.
4936 {
4937 // Can't do cross-account move.
4938- QString msg = QString("Item::move(): Source (") + This->name_ + ") and target ("
4939+ QString msg = QString("Item::move(): source (") + This->name_ + ") and target ("
4940 + new_name + ") must belong to the same account";
4941 throw LogicException(msg);
4942 }
4943 if (This->type_ == ItemType::root)
4944 {
4945 // Can't move a root.
4946- throw LogicException("Item::move(): Cannot move root folder");
4947+ throw LogicException("Item::move(): cannot move root folder");
4948 }
4949
4950 try
4951@@ -265,7 +254,7 @@
4952 }
4953 if (is_reserved_path(target_path))
4954 {
4955- QString msg = "Item::move(): names beginning with " + QString(TMPFILE_PREFIX) + " are reserved";
4956+ QString msg = "Item::move(): names beginning with \"" + QString(TMPFILE_PREFIX) + "\" are reserved";
4957 throw InvalidArgumentException(msg);
4958 }
4959 rename(This->native_identity().toStdString(), target_path);
4960@@ -276,9 +265,9 @@
4961 }
4962 return FileImpl::make_file(QString::fromStdString(target_path.native()), new_parent_impl->root_);
4963 }
4964- catch (std::exception const& e)
4965+ catch (std::exception const&)
4966 {
4967- throw ResourceException(QString("Item::move(): ") + e.what());
4968+ throw_storage_exception(QString("Item::move(): "), current_exception());
4969 }
4970 };
4971 return QtConcurrent::run(move);
4972@@ -286,18 +275,15 @@
4973
4974 QFuture<QVector<Folder::SPtr>> ItemImpl::parents() const
4975 {
4976- lock_guard<mutex> guard(mutex_);
4977+ lock_guard<decltype(mutex_)> guard(mutex_);
4978
4979- QFutureInterface<QVector<Folder::SPtr>> qf;
4980- if (deleted_)
4981+ try
4982 {
4983- return make_exceptional_future<QVector<Folder::SPtr>>(deleted_ex("Item::parents()"));
4984+ throw_if_destroyed("Item::parents()");
4985 }
4986-
4987- Root::SPtr root = root_.lock();
4988- if (!root)
4989+ catch (StorageException const& e)
4990 {
4991- return make_exceptional_future<QVector<Folder::SPtr>>(RuntimeDestroyedException("Item::parents()"));
4992+ return internal::make_exceptional_future<QVector<Folder::SPtr>>(e);
4993 }
4994
4995 using namespace boost::filesystem;
4996@@ -306,10 +292,11 @@
4997 path p = native_identity().toStdString();
4998 QString parent_path = QString::fromStdString(p.parent_path().native());
4999
5000+ auto root = root_.lock();
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: