Comparar commits

..

126 Commits

Autor SHA1 Mensagem Data
Olivier Goffart 305a4ceb9c Parallel chunk upload: Fix a off-by-one while saving the done chunk in the DB
We should assume that the chunk currently uploading is NOT done (hence the -1)

il task 405

cherry pick from commit 3dd8ce08b8
2015-02-04 18:59:01 +01:00
Olivier Goffart e718148b05 PropagateUploadFileQNAM::slotUploadProgress: Fix inverted condition 2014-12-19 16:40:55 +01:00
Markus Goetz caaec4a99f Propagator: Guard access to BandwidthManager
Shouls fix #2623
2014-12-17 15:42:00 +01:00
Markus Goetz a88b46137a Propagator: Improve handling for HTTP 423 Locked
It's a soft error and we want to display oC's <s:message>
2014-12-17 14:44:18 +01:00
Olivier Goffart 7a436498f9 Direct download URL: Pass the information about resuming to the GET job 2014-12-16 16:16:31 +01:00
Markus Goetz fc96459997 Bandwidth: Fix issue with removed download jobs
The measuring broke when a job that is currently measuring was removed.
2014-12-04 15:16:27 +01:00
Markus Goetz 19ca3150de Networkjobs: Fix build 2014-12-04 14:33:27 +01:00
Markus Goetz d8326b76ea NetworkJobs: Set timeout to 5 minutes everywhere.
(cherry picked from commit b7485106ef)

Conflicts:
	src/mirall/networkjobs.cpp
	src/mirall/propagator_qnam.cpp
2014-12-04 14:10:59 +01:00
Olivier Goffart fbe5e8ff5a propagator: always emit the ready signal even if it was already emitted
In case of parallel chunking, new jobs are not started when it is emited for
the parallel chunks are already taking all the lines.  It was emitted again when
the chunks were not going in parallel anymore but this has no effect.

I think it's safe to always emit it, because even if we start several neon job
in parellel because of that, they should queue in their thread

This change do not need to go to mirall master because the scheduling is different
2014-12-04 12:15:00 +01:00
Markus Goetz 8febd90f2a Propagator: Be less verbose 2014-10-08 09:07:29 +02:00
Markus Goetz bf18ecae13 Propagator: Fix bw limiting bug, be less verbose in logging 2014-10-07 17:42:50 +02:00
Markus Goetz 89971925ca Propagator: Be more verbose about propagator choice 2014-10-07 14:55:30 +02:00
Markus Goetz 2ba007ee4f CMake: Add else() case for Qt detection 2014-10-07 14:46:55 +02:00
Markus Goetz d1cc3c34c9 Propagator: Relative download limit 2014-10-07 14:46:55 +02:00
Markus Goetz de79f9338a Propagator: Bandwidth limiting for new propagator 2014-10-07 14:46:55 +02:00
Olivier Goffart 5471bfd5a8 No need to update mtime and etag after a move
The server keeps the mtime and etag anyway.
And changing the mtime also changes the etag and so make other clients re-download
the file instead of detecting the move
2014-10-07 09:13:13 +02:00
Markus Goetz 1543899795 Upload Chunking: Fix progress DB values 2014-09-25 11:32:54 +02:00
Markus Goetz 6d94acee8f permissions: Fix root properties if no permissions used 2014-09-25 10:24:51 +02:00
Olivier Goffart 9ae4d45243 Restart the sync when we detect we need to redo a sync
Fixes #1968
Relates #2038

(cherry picked from commit a84b7dc27e)

Conflicts:
	src/mirall/owncloudpropagator.h
	src/mirall/propagator_qnam.cpp
	src/mirall/syncengine.h
2014-09-19 11:51:17 +02:00
Olivier Goffart 1cd5681967 permissions: Remember the permissions for the root folder 2014-09-19 10:58:52 +02:00
Olivier Goffart 7c36e5c0e6 parallel chunk upload: allow "true" for the value of OWNCLOUD_PARALLEL_CHUNK 2014-09-18 14:29:38 +02:00
Olivier Goffart 1b62ed1e7e Parallel chunk upload: Fix progress 2014-09-18 12:36:30 +02:00
Olivier Goffart 66595a3597 Parallel chunk uploads
This does not include progress indicator
2014-09-16 17:40:42 +02:00
Markus Goetz 4960890d70 Propagator: Commit the DB for Poll Jobs 2014-09-11 12:05:35 +02:00
Olivier Goffart 76f0f3cbf2 csync_vio_local on windows: fix overflow when computing the size of file > 4GiB
MAXDWORD is 0xFFFFFFFF, so if we add one, it overflows and is 0.
We need to cast it to 64 bits before
2014-09-11 11:10:58 +02:00
Markus Goetz f5f04bcc4b SyncEngine: Always return _renameTarget in destination() if possible
We want to do this since the instruction is actually ERORR, not RENAME.
2014-09-05 10:07:24 +02:00
Olivier Goffart c232411e96 uploading: make sure to cast to uint64 to avoid integer overflow 2014-09-04 13:46:01 +02:00
Markus Goetz 7ec0c52439 Poll URL: Use trimmed() on response 2014-08-29 13:58:33 +02:00
Markus Goetz 2aef6a2174 Poll URL: Don't delete from DB in case of 503 2014-08-28 13:44:21 +02:00
Markus Goetz 6e0330ff65 SyncEngine: Error out if we don't have a sync dir 2014-08-28 11:47:40 +02:00
Markus Goetz 3aa7178382 PollJob: Increase timeout 2014-08-28 11:27:08 +02:00
Markus Goetz b037e6356e TokenCredentials, DirectDownload: Rework cookie handling
That way we don't override QNAM's cookie jar behaviour
2014-08-22 13:46:22 +02:00
Markus Goetz 824628061b Propagator: Don't have cookies overriden by QNetworkCookieJar
The direct download feature has its own cookies, don't let QNAM override them.
2014-08-22 12:12:46 +02:00
Markus Goetz 449abace66 CSync: Ignore OS X files with hidden flag 2014-08-21 16:43:24 +02:00
Markus Goetz 8cd1d43798 TokenCredentials: Don't overwrite Cookie header
If the request already had a cookie header, there was a reason for it.
Don't blindly overwrite it.
2014-08-11 15:40:12 +02:00
Markus Goetz acd3df33b6 Merge branch 'long_running_put' into il 2014-08-08 12:00:26 +02:00
Markus Goetz 1bc8fd9b49 CMake: Don't need translations with token auth compile 2014-08-08 11:59:14 +02:00
Klaas Freitag 12f5e4b46e csync oC Util: set field flag correctly to avoid etag memleak.
The fields varialbe should contain or'ed flags of the fields set
in the csync_vio_file_stat_t struct. The problem was that the field
for CSYNC_VIO_FILE_STAT_FIELDS_PERM was assigned rather than or'ed
which makes the release function for the struct not freeing the
etag memory => memleak.
2014-08-07 23:14:21 +02:00
Olivier Goffart 21783ecef7 SyncEngine: fix permission detection of moves
Two problems:
- "M" was used instead of "V"
- The extraction of the parent folder of the destination was wrong
2014-08-07 14:27:27 +02:00
Olivier Goffart 6d24bd0361 journaldb: Fix that fileid might be missing in the db
When recovering from a inalid move operation, we call
avoidReadFromDbOnNextSync. This will remove the fileid from the db so
we don't detect a move on the next sync.  But we want the next sync to fetch
the file id again, and this can only happen if we don't read them
from the db and do the actual PROPFIND, this is done by avoidReadFromDbOnNextSync

However, if there is propagation in that source directory later, it
will overide the invalid etag with the real one and we will not uissue the PROPFIND
to fetch the fileid.
We must therefore also protect the future write to the DB when calling
avoidReadFromDbOnNextSync
2014-08-07 12:14:45 +02:00
Markus Goetz 22c1629dd3 SyncEngine: Keep csync_journal with proper values for fileId and remotePerm
Before this patch, we had a lot of empty rows because we created
the SyncFileItems with the wrong(=local) data.
2014-08-07 10:14:14 +02:00
Olivier Goffart 8df14ee845 Long running put: fix some bugs 2014-07-29 22:56:36 +02:00
Olivier Goffart 550d6d66d1 Long Running Put: Better error reporting 2014-07-29 15:51:22 +02:00
Olivier Goffart 7480d34742 Long Running Put: store into the database so they can be resumed at startup 2014-07-28 15:37:37 +02:00
Olivier Goffart 04cc513bbd Poll for long running PUT: WIP
Some PUT, may take a long time on the server to process (for example, the
last chunk). It may take more time that the timeout.
So in that case the server may reply with an url that we can poll for the etag

This patch is still work in progress
2014-07-25 13:30:48 +02:00
Markus Goetz f004d5085d Merge remote-tracking branch 'origin/1.6' into il
Conflicts:
	VERSION.cmake
2014-07-25 12:37:27 +02:00
Olivier Goffart 81d786733d Merge remote-tracking branch 'origin/1.6' into il
Conflicts:
	VERSION.cmake
	src/mirall/propagator_qnam.cpp
	src/mirall/propagator_qnam.h
2014-07-18 16:59:29 +02:00
Olivier Goffart 336e74b992 csync_owncloud: fix the name of the permissions property 2014-07-18 16:52:04 +02:00
Olivier Goffart 8961e61f60 Merge branch '1.6' into il
Conflicts:
	VERSION.cmake
	src/mirall/syncengine.cpp
	src/mirall/syncengine.h
2014-07-16 09:57:40 +02:00
Olivier Goffart 3477ea0eeb Fix build with TOKEN_ONLY_AUTH
It was broken by commit 6ff38d8005
2014-07-10 15:26:55 +02:00
Olivier Goffart 2f284209d8 Permissions: When moving is not allowed, fallback to delete and upload
We decided that we never want to rename a directory behind the
back of the user as the user may be using files in the directory
during the sync.
If moving is not allowed, we just erase the inode form the database so
the next sync will try to do an upload and delete and recover from there
using normal resolution.

This also add some code to update the inode back to the db when it is detected
as changed.
2014-06-27 15:30:08 +02:00
Olivier Goffart 09881040a3 Permissions: fix restoring subdirectories
The sync item vector must be sorted before we call checkForPermission
2014-06-27 13:34:15 +02:00
Olivier Goffart 9066ad5790 t7.pl: Test that deleting a directory restores it and all its sub directories 2014-06-27 11:31:35 +02:00
Olivier Goffart 62d0e670dc Add t7.pl Test for operation of files with restrictions 2014-06-27 11:22:53 +02:00
Olivier Goffart 48864a6921 httpcredentials: Remove useless mutex
The mutex is not shared with any thread, so it is totaly useless.

Yes: there are possible races here. (with the account, but also with the
user and password)
2014-06-25 12:15:30 +02:00
Olivier Goffart 92f07cb60f Enable C++11
In order to avoid the warning
 warning: anonymous variadic macros were introduced in C99
Due to the use of variadic macro in the qDebug macro in Qt 5.3

C++11 requires a space between string literal and macro to avoid the
ambiguity with user defined litteral
2014-06-25 12:01:27 +02:00
Olivier Goffart fbadadc377 propagator: Fix folder duplication if the folder is renamed on the server while uploading
While uploading a new folder, if the folder is renamed on the server
when still uploading, the result will be that the files that are already
uploaded will end up in the new filder name, but the file that were
not still are in the old folder.

After renaming, all the new uploads wil fail with an error on this sync
because the parent directory don't exist.
But they were uploaded with the old name in the next sync because
the renaming was not detected because the file id was not in the DB

Fix the problem by fetching the file id always when creating a new
directory, on the next sync, and saving it in the database ummediatly

https://github.com/owncloud/enterprise/issues/191
2014-06-24 12:00:13 +02:00
Olivier Goffart 8de3bda0b1 csync_update: update the permission in the db when they change
The current code only update the permissions in the DB when
the permission becomes non-empty.
Now we update the permission each time they change.

That way the code is the same for file id and permission so it is
simpler.
2014-06-24 11:10:50 +02:00
Olivier Goffart 3c4f410a4e cmake compilation flags: don't define -Wdeclaration-after-statement
We are in 2014, let me use C99 already.
2014-06-24 11:02:58 +02:00
Olivier Goffart 9c0a21a5fb Permission: keep a space if the permission is empty
To distinguish no permission present to nothing is allowed.
That was the intention of the old code but it did not work as
the first if was always taken
2014-06-24 10:52:42 +02:00
Olivier Goffart b735dc07d6 Permissions: Consider and empty remotePerms from csync as NULL
Since remotePerm from csync is never NULL (as it is a buffer),
we consider that if it is empty, there was no permission set
(and therefore everything is allowed)

csync will put a space in the permission if any permission was set
2014-06-23 15:05:48 +02:00
Olivier Goffart 68c902e60b propagator: Fix restoring directory
If the result of a restored directory is SoftError, this prevent
to sync the rest of the directory

Therefore, we introduced a new status Restored,  which means that
the job was a success, but is a restoration and therefore should be
seen as a warning
2014-06-23 13:56:17 +02:00
Olivier Goffart e19214c3c4 permissions: record them even if the instruction is NONE
when the instruction is NONE, we may return from this function
before having registered the permission in the SyncEngine::_remotePerms
hash.
Move the code a bit up.
2014-06-23 13:35:34 +02:00
Olivier Goffart 02704cdf74 Merge remote-tracking branch 'origin/1.6' into il
Conflicts:
	VERSION.cmake
	csync/src/csync_statedb.c
	src/mirall/syncengine.cpp
	src/mirall/syncfileitem.h
2014-06-23 12:48:34 +02:00
Markus Goetz 71a901a24e TokenCredentials: Fix cookie behaviour
parseCookies did not work as expected. Now we just hard-set the
token credentials into the Cookie header for QNAM jobs.
This is the same behaviour as for neon jobs.

(cherry picked from commit 855a8c0a335f76b82b8e647a8c5a4ae692065d3b)
2014-06-19 14:41:47 +02:00
Olivier Goffart 02355696ff engine: When restoring the file, use the mtime and fileid from the server
Important to switch the things around as we are going to write them in the DB
2014-06-18 16:15:14 +02:00
Olivier Goffart 38254125c9 csync: fix the size in strncpy for the remote perms
We must only do strncpy with size one smaller than
the size of the buffer in order to leave at least
one '\0' at the end
2014-06-18 15:56:13 +02:00
Olivier Goffart e5b3363ecf csync_statedb: remove noisy output 2014-06-18 15:40:26 +02:00
Olivier Goffart c759e8bb8f permission: read them from the tree 2014-06-17 14:50:24 +02:00
Olivier Goffart b83f6c0b3a sync engine: try to respect permission
This is still Work in progress
2014-06-17 14:44:58 +02:00
Olivier Goffart ade92d8ac1 csync test: fix warning 2014-06-17 14:16:42 +02:00
Markus Goetz a5967e4ecd CSync: Fix win32 compile 2014-06-16 16:53:10 +02:00
Olivier Goffart 2f361278d2 Merge remote-tracking branch 'origin/1.6' into 'il' 2014-06-16 16:41:48 +02:00
Markus Goetz 319cf76417 CSync: Move compiler ifdef outwards 2014-06-16 16:26:00 +02:00
Markus Goetz be7b08b50a CMake: Fix token auth compile 2014-06-16 15:34:46 +02:00
Markus Goetz 61999a67cd CSync: Give ctx to proxy callback
This fixes a crash.
2014-06-13 15:36:00 +02:00
Olivier Goffart 2caa69e0cb blacklist: use the _ERROR instruction instead of _IGNORE
When something is in the blacklist, still use the _ERROR instruction
that way the applications can still report errors for blacklisted
items
2014-06-13 11:19:31 +02:00
Olivier Goffart 18e9357aaf network limits: Fix warning
About the order of initialization
2014-06-07 12:20:54 +02:00
Olivier Goffart 46b8260693 network limits: Do not read them from the config file in the engine
Do that from the folder, because the engine can be used in app where
the MirallConfigFile is not accessible
2014-06-07 12:09:22 +02:00
Olivier Goffart d5bd3190d4 csync unit tests: fix cimpilation 2014-06-07 12:08:58 +02:00
Markus Goetz 8dbfcd782b CSync: Fetch permissions from server for whole tree on server update 2014-06-06 17:10:07 +02:00
Markus Goetz 70ff928381 CSync & statedb: Parse 'perm' from server
ownCloud 6 sends this.
2014-06-06 15:24:17 +02:00
Markus Goetz b48ab79a92 CSync & statedb: Remove uid/gid
Columns are still in the DB as we don't want to break any compatibility.
2014-06-06 13:41:16 +02:00
Markus Goetz 9a7fbd4f71 csync_owncloud: Parse properties in one function 2014-06-06 13:41:16 +02:00
Jenkins for ownCloud ef3b4956ad [tx-robot] updated from transifex 2014-06-06 01:25:21 -04:00
Markus Goetz fd4642d827 Folder: Don't add ignored files on startup
Before each sync is enough.
(We could do it at startup only, but so far it is good to have
it at each sync so we can easier see stuff in the log)
2014-06-05 17:50:18 +02:00
Olivier Goffart 6dd248e527 csync: fix warnings
warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
2014-06-05 15:48:53 +02:00
Olivier Goffart 7d00c3646a csync: remove unused variable 2014-06-05 15:45:15 +02:00
Olivier Goffart e355e12385 Fix crash in tests 2014-06-05 15:43:27 +02:00
Markus Goetz 34b31c0146 CSync: Fix test compile
The previously applied pull request apparantly broke the compile
because it re-ordered entries in the CMakeLists
2014-06-05 14:22:10 +02:00
Daniel Molkentin 3934fa019e SocketAPI: proper name for pipe on windows 2014-06-05 12:02:57 +02:00
Daniel Molkentin dc53e96f92 [Janitor] Bump version on master to 1.7.0prealpha 2014-06-05 12:02:00 +02:00
Daniel Molkentin 7fcf6f9f79 Merge branch '1.6' 2014-06-05 12:01:50 +02:00
Olivier Goffart bd48ab23c3 Merge pull request #1835 from zizzfizzix/cmake_fixes
A little CMake cleanup
2014-06-05 11:48:40 +02:00
Markus Goetz 4e28ba73bb Windows: Fix build harder. 2014-06-05 10:13:20 +02:00
Jenkins for ownCloud 16cb37ecd0 [tx-robot] updated from transifex 2014-06-05 01:25:23 -04:00
Markus Goetz d4d630b2e9 Windows: Fix build 2014-06-04 12:47:17 +02:00
Markus Goetz 2ff27cdd63 Merge pull request #1844 from owncloud/csyncStdlibReduction
Csync reduction

Reviewed offline by @dragotin
2014-06-04 11:28:35 +02:00
Markus Goetz 2f81167164 CSync: Remove more unused things 2014-06-04 11:19:09 +02:00
Markus Goetz 6897c5d41f CSync: Always have statedb enabled 2014-06-04 11:06:41 +02:00
Markus Goetz 233450d850 CSync: Remove config dir setting 2014-06-04 10:56:56 +02:00
Markus Goetz 7428a8fa63 CSync: Remove unused std functions 2014-06-04 10:33:19 +02:00
Markus Goetz 18359d7871 StateDB: Remove _csync_win32_hide_file and use other implementation 2014-06-04 09:46:31 +02:00
Jenkins for ownCloud df12a58e3d [tx-robot] updated from transifex 2014-06-04 01:25:24 -04:00
Kuba Serafinowski 4b3d124b5a put man docs in the correct /man1 directory
man doesn't work here when the docs are in a /man directory
2014-06-04 00:10:18 +03:00
Kuba Serafinowski 51e941e7b5 look for Sparkle only on OS X 2014-06-04 00:10:17 +03:00
Kuba Serafinowski 62ea6f316f don't look for CMocka if we're not building unit tests 2014-06-04 00:10:16 +03:00
Olivier Goffart 4cb9b3a85b Test: fix compilation 2014-06-03 17:54:43 +02:00
Olivier Goffart 806ab8ea46 csync: remove the local mode
It is no longer used for a long time
2014-06-03 17:52:07 +02:00
Olivier Goffart 582a8fe7fd Merge branch '1.6' 2014-06-03 17:27:12 +02:00
Olivier Goffart 08ca8b54b1 test fles with '%' and '#' 2014-06-03 17:27:06 +02:00
Olivier Goffart abafbef985 Optimize move
Do not send the mtime for each file without a directory, because the server now keeps it
2014-06-03 17:27:06 +02:00
Markus Goetz 06863ca9c6 Merge pull request #1839 from owncloud/directDownload
Direct download URL support + global variable refactoring

Reviewed offline by @dragotin
2014-06-03 16:44:05 +02:00
Markus Goetz e49b8981dd CSync: Shorten WebDAV property name 2014-06-03 16:41:57 +02:00
Markus Goetz 2e91557c28 CSync: Rename callback functions 2014-06-03 15:01:35 +02:00
Markus Goetz 4d4eab8b1c CSync & Propagator: Support a direct download URL
This is for server file backends that support sending a
direct URL.
2014-06-03 14:55:34 +02:00
Markus Goetz 4d4ae9374b CSync: Remove old defines 2014-06-03 11:51:12 +02:00
Markus Goetz b8e20b412c CSync: We can access the context directly 2014-06-03 11:51:12 +02:00
Markus Goetz e36f3c5b10 CSync: Remove one VIO layering 2014-06-03 11:51:12 +02:00
Markus Goetz 8a55f831f4 CSync: Use context instead of global variable 2014-06-03 11:51:12 +02:00
Markus Goetz 0dcc9be5c1 CSync: Remove owncloud_stat
We get already all metadata with the readdir
2014-06-03 11:51:12 +02:00
Markus Goetz 5ee00a8df7 CSync: Simplify csync_owncloud stat/resource handling 2014-06-03 11:51:12 +02:00
Klaas Freitag 1af3d3f18b More descriptive error message when querying the database without hit. 2014-06-03 09:50:09 +02:00
Klaas Freitag f54248c0a7 Minor cleanups and changes 2014-06-03 09:50:09 +02:00
Klaas Freitag 2911c0e1c4 Add a recursiveFolderStatus method 2014-06-03 09:50:09 +02:00
Klaas Freitag 16d35c1489 Avoid crash on csync_ctx is NULL. 2014-06-03 09:50:09 +02:00
142 arquivos alterados com 4204 adições e 4589 exclusões
+1 -1
Ver Arquivo
@@ -3,4 +3,4 @@
url = https://github.com/owncloud/documentation
[submodule "src/3rdparty/qtmacgoodies"]
path = src/3rdparty/qtmacgoodies
url = git://github.com/guruz/qtmacgoodies.git
url = git://github.com/shadone/qtmacgoodies.git
+4 -1
Ver Arquivo
@@ -108,7 +108,10 @@ if(NOT TOKEN_AUTH_ONLY)
endif()
endif()
Find_package(Sparkle)
if(APPLE)
find_package(Sparkle)
endif(APPLE)
if(UNIX)
find_package(INotify REQUIRED)
else()
+1 -10
Ver Arquivo
@@ -1,15 +1,6 @@
ChangeLog
=========
version 1.6.3 (release 2014-09-03)
* Fixed updater on OS X
* Fixed memory leak in SSL button that could lead to quick memory draining
* Fixed upload problem with files >4 GB
* MacOSX, Linux: Bring Settings window to front properly
* Branded clients: If no configuration is detected, try to import the data
from a previously configured community edition.
version 1.6.2 (release 2014-07-28 )
* Limit the HTTP buffer size when downloading to limit memory consumption.
version 1.6.2 (release 2014-07-x )
* Another small mem leak fixed in HTTP Credentials.
* Fix local file name clash detection for MacOSX.
* Limit maximum wait time to ten seconds in network limiting.
+3 -3
Ver Arquivo
@@ -1,10 +1,10 @@
set( MIRALL_VERSION_MAJOR 1 )
set( MIRALL_VERSION_MINOR 6 )
set( MIRALL_VERSION_PATCH 3 )
set( MIRALL_VERSION_MINOR 7 )
set( MIRALL_VERSION_PATCH 0 )
set( MIRALL_SOVERSION 0 )
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
set( MIRALL_VERSION_SUFFIX "") #e.g. beta1, beta2, rc1
set( MIRALL_VERSION_SUFFIX "prealpha") #e.g. beta1, beta2, rc1
endif( NOT DEFINED MIRALL_VERSION_SUFFIX )
if( NOT DEFINED MIRALL_VERSION_BUILD )
+1 -1
Ver Arquivo
@@ -13,7 +13,7 @@ if (${CMAKE_C_COMPILER_ID} MATCHES "(GNU|Clang)")
if (NOT CSYNC_STATIC_COMPILE_DIR)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -pedantic -pedantic-errors")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wshadow -Wmissing-prototypes -Wdeclaration-after-statement")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wshadow -Wmissing-prototypes")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunused -Wfloat-equal -Wpointer-arith -Wwrite-strings -Wformat-security")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-format-attribute")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-format-attribute -D_GNU_SOURCE")
+9 -3
Ver Arquivo
@@ -19,10 +19,11 @@ if( Qt5Core_FOUND )
find_package(Qt5PrintSupport REQUIRED)
find_package(Qt5Quick REQUIRED)
find_package(Qt5Widgets REQUIRED)
if(APPLE)
find_package(Qt5MacExtras REQUIRED)
endif(APPLE)
endif()
if(APPLE)
find_package(Qt5MacExtras REQUIRED)
endif(APPLE)
else( Qt5Core_FOUND )
if(WIN32 OR APPLE)
message(FATAL_ERROR "Qt 5 not found, but application depends on Qt5 on Windows and Mac OS X")
@@ -65,10 +66,15 @@ endif()
qt5_add_resources(${ARGN})
endmacro()
if(NOT TOKEN_AUTH_ONLY)
find_package(Qt5LinguistTools REQUIRED)
macro(qt_add_translation)
qt5_add_translation(${ARGN})
endmacro()
else()
macro(qt_add_translation)
endmacro()
endif()
macro(qt_add_dbus_interface)
qt5_add_dbus_interface(${ARGN})
+2
Ver Arquivo
@@ -6,9 +6,11 @@ if(CMAKE_COMPILER_IS_GNUCXX)
else(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long")
endif(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif(CMAKE_COMPILER_IS_GNUCXX)
if(CMAKE_CXX_COMPILER MATCHES "clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif(CMAKE_CXX_COMPILER MATCHES "clang")
# TODO: handle msvc compilers warnings?
+7 -7
Ver Arquivo
@@ -27,10 +27,6 @@ include(MacroCopyFile)
if (NOT WIN32)
find_package(Iconv)
endif (NOT WIN32)
find_package(CMocka)
if (CMOCKA_FOUND AND UNIT_TESTING)
include(AddCMockaTest)
endif (CMOCKA_FOUND AND UNIT_TESTING)
include(ConfigureChecks.cmake)
@@ -47,9 +43,13 @@ endif (MEM_NULL_TESTS)
add_subdirectory(src)
if (CMOCKA_FOUND AND UNIT_TESTING)
add_subdirectory(tests)
endif (CMOCKA_FOUND AND UNIT_TESTING)
if (UNIT_TESTING)
find_package(CMocka)
if (CMOCKA_FOUND)
include(AddCMockaTest)
add_subdirectory(tests)
endif (CMOCKA_FOUND)
endif (UNIT_TESTING)
configure_file(config_csync.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_csync.h)
configure_file(config_test.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_test.h)
+2 -2
Ver Arquivo
@@ -96,10 +96,10 @@ include_directories(
)
add_library(${CSYNC_LIBRARY} SHARED ${csync_SRCS})
add_library(${CSYNC_LIBRARY}_static STATIC ${csync_SRCS})
#add_library(${CSYNC_LIBRARY}_static STATIC ${csync_SRCS})
target_link_libraries(${CSYNC_LIBRARY} ${CSYNC_LINK_LIBRARIES})
target_link_libraries(${CSYNC_LIBRARY}_static ${CSYNC_LINK_LIBRARIES})
#target_link_libraries(${CSYNC_LIBRARY}_static ${CSYNC_LINK_LIBRARIES})
set_target_properties(
${CSYNC_LIBRARY}
+32 -164
Ver Arquivo
@@ -96,8 +96,6 @@ static int _data_cmp(const void *key, const void *data) {
int csync_create(CSYNC **csync, const char *local, const char *remote) {
CSYNC *ctx;
size_t len = 0;
char *home;
int rc;
ctx = c_malloc(sizeof(CSYNC));
if (ctx == NULL) {
@@ -129,31 +127,6 @@ int csync_create(CSYNC **csync, const char *local, const char *remote) {
}
ctx->status_code = CSYNC_STATUS_OK;
ctx->options.local_only_mode = false;
ctx->pwd.uid = getuid();
ctx->pwd.euid = geteuid();
home = csync_get_user_home_dir();
if (home == NULL) {
SAFE_FREE(ctx->local.uri);
SAFE_FREE(ctx->remote.uri);
SAFE_FREE(ctx);
errno = ENOMEM;
ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
return -1;
}
rc = asprintf(&ctx->options.config_dir, "%s/%s", home, CSYNC_CONF_DIR);
SAFE_FREE(home);
if (rc < 0) {
SAFE_FREE(ctx->local.uri);
SAFE_FREE(ctx->remote.uri);
SAFE_FREE(ctx);
errno = ENOMEM;
ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
return -1;
}
ctx->local.list = 0;
ctx->remote.list = 0;
@@ -167,7 +140,6 @@ int csync_create(CSYNC **csync, const char *local, const char *remote) {
int csync_init(CSYNC *ctx) {
int rc;
char *config = NULL;
if (ctx == NULL) {
errno = EBADF;
@@ -190,12 +162,8 @@ int csync_init(CSYNC *ctx) {
ctx->local.type = LOCAL_REPLICA;
if ( !ctx->options.local_only_mode) {
owncloud_init(csync_get_userdata(ctx));
ctx->remote.type = REMOTE_REPLICA;
} else {
ctx->remote.type = LOCAL_REPLICA;
}
owncloud_init(ctx);
ctx->remote.type = REMOTE_REPLICA;
if (c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp) < 0) {
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
@@ -209,9 +177,9 @@ int csync_init(CSYNC *ctx) {
goto out;
}
ctx->status = CSYNC_STATUS_INIT;
ctx->remote.root_perms = 0;
csync_set_module_property(ctx, "csync_context", ctx);
ctx->status = CSYNC_STATUS_INIT;
/* initialize random generator */
srand(time(NULL));
@@ -219,7 +187,6 @@ int csync_init(CSYNC *ctx) {
rc = 0;
out:
SAFE_FREE(config);
return rc;
}
@@ -234,7 +201,6 @@ int csync_update(CSYNC *ctx) {
ctx->status_code = CSYNC_STATUS_OK;
/* create/load statedb */
if (! csync_is_statedb_disabled(ctx)) {
rc = asprintf(&ctx->statedb.file, "%s/.csync_journal.db",
ctx->local.uri);
if (rc < 0) {
@@ -248,7 +214,6 @@ int csync_update(CSYNC *ctx) {
rc = -1;
return rc;
}
}
ctx->status_code = CSYNC_STATUS_OK;
@@ -278,27 +243,25 @@ int csync_update(CSYNC *ctx) {
csync_memstat_check();
/* update detection for remote replica */
if( ! ctx->options.local_only_mode ) {
csync_gettime(&start);
ctx->current = REMOTE_REPLICA;
ctx->replica = ctx->remote.type;
csync_gettime(&start);
ctx->current = REMOTE_REPLICA;
ctx->replica = ctx->remote.type;
rc = csync_ftw(ctx, ctx->remote.uri, csync_walker, MAX_DEPTH);
if (rc < 0) {
if(ctx->status_code == CSYNC_STATUS_OK)
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
return -1;
}
csync_gettime(&finish);
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
"Update detection for remote replica took %.2f seconds "
"walking %zu files.",
c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
csync_memstat_check();
rc = csync_ftw(ctx, ctx->remote.uri, csync_walker, MAX_DEPTH);
if (rc < 0) {
if(ctx->status_code == CSYNC_STATUS_OK)
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
return -1;
}
csync_gettime(&finish);
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
"Update detection for remote replica took %.2f seconds "
"walking %zu files.",
c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
csync_memstat_check();
ctx->status |= CSYNC_STATUS_UPDATE;
return 0;
@@ -431,14 +394,15 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
trav.path = cur->path;
trav.size = cur->size;
trav.modtime = cur->modtime;
trav.uid = cur->uid;
trav.gid = cur->gid;
trav.mode = cur->mode;
trav.type = cur->type;
trav.instruction = cur->instruction;
trav.rename_path = cur->destpath;
trav.etag = cur->etag;
trav.file_id = cur->file_id;
trav.remotePerm = cur->remotePerm;
trav.directDownloadUrl = cur->directDownloadUrl;
trav.directDownloadCookies = cur->directDownloadCookies;
trav.inode = cur->inode;
trav.error_status = cur->error_status;
@@ -461,7 +425,7 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
rc = (*visitor)(&trav, twctx->userdata);
cur->instruction = trav.instruction;
if (trav.etag != cur->etag) {
if (trav.etag != cur->etag) { // FIXME It would be nice to have this documented
SAFE_FREE(cur->etag);
cur->etag = c_strdup(trav.etag);
}
@@ -594,6 +558,7 @@ static void _csync_clean_ctx(CSYNC *ctx)
ctx->local.ignored_cleanup = 0;
SAFE_FREE(ctx->statedb.file);
SAFE_FREE(ctx->remote.root_perms);
}
int csync_commit(CSYNC *ctx) {
@@ -612,7 +577,7 @@ int csync_commit(CSYNC *ctx) {
}
ctx->statedb.db = NULL;
rc = csync_vio_commit(ctx);
rc = owncloud_commit(ctx);
if (rc < 0) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "commit failed: %s",
ctx->error_string ? ctx->error_string : "");
@@ -671,9 +636,10 @@ int csync_destroy(CSYNC *ctx) {
SAFE_FREE(ctx->local.uri);
SAFE_FREE(ctx->remote.uri);
SAFE_FREE(ctx->options.config_dir);
SAFE_FREE(ctx->error_string);
owncloud_destroy(ctx);
#ifdef WITH_ICONV
c_close_iconv();
#endif
@@ -705,70 +671,6 @@ void csync_clear_exclude_list(CSYNC *ctx)
csync_exclude_clear(ctx);
}
const char *csync_get_config_dir(CSYNC *ctx) {
if (ctx == NULL) {
return NULL;
}
return ctx->options.config_dir;
}
int csync_set_config_dir(CSYNC *ctx, const char *path) {
if (ctx == NULL || path == NULL) {
return -1;
}
SAFE_FREE(ctx->options.config_dir);
ctx->options.config_dir = c_strdup(path);
if (ctx->options.config_dir == NULL) {
ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
return -1;
}
return 0;
}
int csync_enable_statedb(CSYNC *ctx) {
if (ctx == NULL) {
return -1;
}
ctx->status_code = CSYNC_STATUS_OK;
if (ctx->status & CSYNC_STATUS_INIT) {
fprintf(stderr, "This function must be called before initialization.");
ctx->status_code = CSYNC_STATUS_CSYNC_STATUS_ERROR;
return -1;
}
ctx->statedb.disabled = 0;
return 0;
}
int csync_disable_statedb(CSYNC *ctx) {
if (ctx == NULL) {
return -1;
}
ctx->status_code = CSYNC_STATUS_OK;
if (ctx->status & CSYNC_STATUS_INIT) {
fprintf(stderr, "This function must be called before initialization.");
ctx->status_code = CSYNC_STATUS_CSYNC_STATUS_ERROR;
return -1;
}
ctx->statedb.disabled = 1;
return 0;
}
int csync_is_statedb_disabled(CSYNC *ctx) {
if (ctx == NULL) {
return -1;
}
return ctx->statedb.disabled;
}
int csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb) {
if (ctx == NULL || cb == NULL) {
return -1;
@@ -784,15 +686,6 @@ int csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb) {
return 0;
}
const char *csync_get_statedb_file(CSYNC *ctx) {
if (ctx == NULL) {
return NULL;
}
ctx->status_code = CSYNC_STATUS_OK;
return c_strdup(ctx->statedb.file);
}
void *csync_get_userdata(CSYNC *ctx) {
if (ctx == NULL) {
return NULL;
@@ -836,33 +729,6 @@ CSYNC_STATUS csync_get_status(CSYNC *ctx) {
return ctx->status_code;
}
int csync_set_local_only(CSYNC *ctx, bool local_only) {
if (ctx == NULL) {
return -1;
}
ctx->status_code = CSYNC_STATUS_OK;
if (ctx->status & CSYNC_STATUS_INIT) {
fprintf(stderr, "csync_set_local_only: This function must be called before initialization.");
ctx->status_code = CSYNC_STATUS_CSYNC_STATUS_ERROR;
return -1;
}
ctx->options.local_only_mode=local_only;
return 0;
}
bool csync_get_local_only(CSYNC *ctx) {
if (ctx == NULL) {
return -1;
}
ctx->status_code = CSYNC_STATUS_OK;
return ctx->options.local_only_mode;
}
const char *csync_get_status_string(CSYNC *ctx)
{
return csync_vio_get_status_string(ctx);
@@ -907,6 +773,8 @@ int csync_abort_requested(CSYNC *ctx)
void csync_file_stat_free(csync_file_stat_t *st)
{
if (st) {
SAFE_FREE(st->directDownloadUrl);
SAFE_FREE(st->directDownloadCookies);
SAFE_FREE(st->etag);
SAFE_FREE(st->destpath);
SAFE_FREE(st);
@@ -915,7 +783,7 @@ void csync_file_stat_free(csync_file_stat_t *st)
int csync_set_module_property(CSYNC* ctx, const char* key, void* value)
{
return csync_vio_set_property(ctx, key, value);
return owncloud_set_property(ctx, key, value);
}
+4 -104
Ver Arquivo
@@ -44,13 +44,6 @@
extern "C" {
#endif
/*
* csync file declarations
*/
#define CSYNC_CONF_DIR ".ocsync"
#define CSYNC_CONF_FILE "ocsync.conf"
#define CSYNC_EXCLUDE_FILE "ocsync_exclude.conf"
/**
* Instruction enum. In the file traversal structure, it describes
* the csync state of a file.
@@ -59,7 +52,7 @@ enum csync_status_codes_e {
CSYNC_STATUS_OK = 0,
CSYNC_STATUS_ERROR = 1024, /* don't use this code,
just use in csync_status_ok */
*/
CSYNC_STATUS_UNSUCCESSFUL,
CSYNC_STATUS_NO_LOCK, /* OBSOLETE does not happen anymore */
CSYNC_STATUS_STATEDB_LOAD_ERROR,
@@ -172,13 +165,6 @@ struct csync_tree_walk_file_s {
int64_t size;
int64_t inode;
time_t modtime;
#ifdef _WIN32
uint32_t uid;
uint32_t gid;
#else
uid_t uid;
gid_t gid;
#endif
mode_t mode;
enum csync_ftw_type_e type;
enum csync_instructions_e instruction;
@@ -189,6 +175,9 @@ struct csync_tree_walk_file_s {
const char *rename_path;
const char *etag;
const char *file_id;
const char *remotePerm;
char *directDownloadUrl;
char *directDownloadCookies;
struct {
int64_t size;
time_t modtime;
@@ -214,14 +203,6 @@ typedef void (*csync_log_callback) (int verbosity,
const char *buffer,
void *userdata);
/**
* @brief Check internal csync status.
*
* @param csync The context to check.
*
* @return true if status is error free, false for error states.
*/
bool csync_status_ok(CSYNC *ctx);
/**
* @brief Allocate a csync context.
@@ -333,62 +314,6 @@ int csync_add_exclude_list(CSYNC *ctx, const char *path);
*/
void csync_clear_exclude_list(CSYNC *ctx);
/**
* @brief Get the config directory.
*
* @param ctx The csync context.
*
* @return The path of the config directory or NULL on error.
*/
const char *csync_get_config_dir(CSYNC *ctx);
/**
* @brief Change the config directory.
*
* @param ctx The csync context.
*
* @param path The path to the new config directory.
*
* @return 0 on success, less than 0 if an error occured.
*/
int csync_set_config_dir(CSYNC *ctx, const char *path);
/**
* @brief Remove the complete config directory.
*
* @param ctx The csync context.
*
* @return 0 on success, less than 0 if an error occured.
*/
int csync_remove_config_dir(CSYNC *ctx);
/**
* @brief Enable the usage of the statedb. It is enabled by default.
*
* @param ctx The csync context.
*
* @return 0 on success, less than 0 if an error occured.
*/
int csync_enable_statedb(CSYNC *ctx);
/**
* @brief Disable the usage of the statedb. It is enabled by default.
*
* @param ctx The csync context.
*
* @return 0 on success, less than 0 if an error occured.
*/
int csync_disable_statedb(CSYNC *ctx);
/**
* @brief Check if the statedb usage is enabled.
*
* @param ctx The csync context.
*
* @return 1 if it is enabled, 0 if it is disabled.
*/
int csync_is_statedb_disabled(CSYNC *ctx);
/**
* @brief Get the userdata saved in the context.
*
@@ -481,31 +406,6 @@ void *csync_get_log_userdata(void);
*/
int csync_set_log_userdata(void *data);
/**
* @brief Get the path of the statedb file used.
*
* @param ctx The csync context.
*
* @return The path to the statedb file, NULL if an error occured.
*/
const char *csync_get_statedb_file(CSYNC *ctx);
/**
* @brief Flag to tell csync that only a local run is intended. Call before csync_init
*
* @param local_only Bool flag to indicate local only mode.
*
* @return 0 on success, less than 0 if an error occured.
*/
int csync_set_local_only( CSYNC *ctx, bool local_only );
/**
* @brief Retrieve the flag to tell csync that only a local run is intended.
*
* @return 1: stay local only, 0: local and remote mode
*/
bool csync_get_local_only( CSYNC *ctx );
/* Used for special modes or debugging */
CSYNC_STATUS csync_get_status(CSYNC *ctx);
+7 -1
Ver Arquivo
@@ -20,12 +20,18 @@
#include "config_csync.h"
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "c_lib.h"
#include "c_private.h"
#include "csync_private.h"
#include "csync_exclude.h"
@@ -217,7 +223,7 @@ CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype) {
SAFE_FREE(bname);
SAFE_FREE(dname);
if (ctx->excludes == NULL) {
if (ctx == NULL || ctx->excludes == NULL) {
goto out;
}
-46
Ver Arquivo
@@ -47,52 +47,6 @@
#include "csync_macros.h"
#include "csync_log.h"
#ifdef _WIN32
char *csync_get_user_home_dir(void) {
wchar_t tmp[MAX_PATH];
char *szPath = NULL;
if( SHGetFolderPathW( NULL,
CSIDL_PROFILE|CSIDL_FLAG_CREATE,
NULL,
0,
tmp) == S_OK ) {
szPath = c_utf8_from_locale(tmp);
return szPath;
}
return NULL;
}
#else /* ************* !WIN32 ************ */
#ifndef NSS_BUFLEN_PASSWD
#define NSS_BUFLEN_PASSWD 4096
#endif /* NSS_BUFLEN_PASSWD */
char *csync_get_user_home_dir(void) {
const char *envp;
struct passwd pwd;
struct passwd *pwdbuf;
char buf[NSS_BUFLEN_PASSWD];
int rc;
envp = getenv("HOME");
if (envp != NULL && envp[0] != '\0') {
return c_strdup(envp);
}
/* Still nothing found, read the password file */
rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
if (rc != 0) {
return c_strdup(pwd.pw_dir);
}
return NULL;
}
#endif /* ************* WIN32 ************ */
#ifdef HAVE_FNMATCH
#include <fnmatch.h>
-2
Ver Arquivo
@@ -35,8 +35,6 @@
#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
#endif
char *csync_get_user_home_dir(void);
int csync_fnmatch(__const char *__pattern, __const char *__name, int __flags);
/**
+165 -400
Ver Arquivo
@@ -20,79 +20,10 @@
*/
#include "csync_owncloud.h"
#include "csync_owncloud_private.h"
#include <inttypes.h>
/*
* free the fetchCtx
*/
static void free_fetchCtx( struct listdir_context *ctx )
{
struct resource *newres, *res;
if( ! ctx ) return;
newres = ctx->list;
res = newres;
ctx->ref--;
if (ctx->ref > 0) return;
SAFE_FREE(ctx->target);
while( res ) {
SAFE_FREE(res->uri);
SAFE_FREE(res->name);
SAFE_FREE(res->md5);
memset( res->file_id, 0, FILE_ID_BUF_SIZE+1 );
newres = res->next;
SAFE_FREE(res);
res = newres;
}
SAFE_FREE(ctx);
}
/*
* local variables.
*/
struct dav_session_s dav_session; /* The DAV Session, initialised in dav_connect */
int _connected = 0; /* flag to indicate if a connection exists, ie.
the dav_session is valid */
void *_userdata;
long long chunked_total_size = 0;
long long chunked_done = 0;
struct listdir_context *propfind_cache = 0;
bool is_first_propfind = true;
csync_vio_file_stat_t _stat_cache;
/* id cache, cache the ETag: header of a GET request */
struct { char *uri; char *id; } _id_cache = { NULL, NULL };
static void clean_caches() {
clear_propfind_recursive_cache();
free_fetchCtx(propfind_cache);
propfind_cache = NULL;
SAFE_FREE(_stat_cache.name);
SAFE_FREE(_stat_cache.etag );
memset( _stat_cache.file_id, 0, FILE_ID_BUF_SIZE+1 );
SAFE_FREE(_id_cache.uri);
SAFE_FREE(_id_cache.id);
}
#define PUT_BUFFER_SIZE 1024*5
char _buffer[PUT_BUFFER_SIZE];
/*
* helper method to build up a user text for SSL problems, called from the
@@ -116,7 +47,7 @@ static void addSSLWarning( char *ptr, const char *warn, int len )
* it to the csync callback to ask the user.
*/
#define LEN 4096
static int verify_sslcert(void *userdata, int failures,
static int ssl_callback_by_neon(void *userdata, int failures,
const ne_ssl_certificate *certificate)
{
char problem[LEN];
@@ -124,8 +55,8 @@ static int verify_sslcert(void *userdata, int failures,
int ret = -1;
const ne_ssl_certificate *cert = certificate;
csync_auth_callback authcb = NULL;
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
(void) userdata;
memset( problem, 0, LEN );
while( cert ) {
@@ -161,14 +92,14 @@ static int verify_sslcert(void *userdata, int failures,
}
addSSLWarning( problem, "Do you want to accept the certificate chain anyway?\nAnswer yes to do so and take the risk: ", LEN );
if( dav_session.csync_ctx ) {
authcb = csync_get_auth_callback( dav_session.csync_ctx );
if( ctx->csync_ctx ) {
authcb = csync_get_auth_callback( ctx->csync_ctx );
}
if( authcb ){
/* call the csync callback */
DEBUG_WEBDAV("Call the csync callback for SSL problems");
memset( buf, 0, NE_ABUFSIZ );
(*authcb) ( problem, buf, NE_ABUFSIZ-1, 1, 0, _userdata );
(*authcb) ( problem, buf, NE_ABUFSIZ-1, 1, 0, csync_get_userdata(ctx->csync_ctx) );
if( buf[0] == 'y' || buf[0] == 'Y') {
ret = 0;
} else {
@@ -184,41 +115,39 @@ static int verify_sslcert(void *userdata, int failures,
* Authentication callback. Is set by ne_set_server_auth to be called
* from the neon lib to authenticate a request.
*/
static int ne_auth( void *userdata, const char *realm, int attempt,
static int authentication_callback_by_neon( void *userdata, const char *realm, int attempt,
char *username, char *password)
{
char buf[NE_ABUFSIZ];
csync_auth_callback authcb = NULL;
int re = attempt;
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
(void) userdata;
(void) realm;
/* DEBUG_WEBDAV( "Authentication required %s", realm ); */
if( username && password ) {
DEBUG_WEBDAV( "Authentication required %s", username );
if( dav_session.user ) {
if( ctx->dav_session.user ) {
/* allow user without password */
if( strlen( dav_session.user ) < NE_ABUFSIZ ) {
strcpy( username, dav_session.user );
if( strlen( ctx->dav_session.user ) < NE_ABUFSIZ ) {
strcpy( username, ctx->dav_session.user );
}
if( dav_session.pwd && strlen( dav_session.pwd ) < NE_ABUFSIZ ) {
strcpy( password, dav_session.pwd );
if( ctx->dav_session.pwd && strlen( ctx->dav_session.pwd ) < NE_ABUFSIZ ) {
strcpy( password, ctx->dav_session.pwd );
}
} else {
if( dav_session.csync_ctx ) {
authcb = csync_get_auth_callback( dav_session.csync_ctx );
}
authcb = csync_get_auth_callback( ctx->csync_ctx );
if( authcb != NULL ){
/* call the csync callback */
DEBUG_WEBDAV("Call the csync callback for %s", realm );
memset( buf, 0, NE_ABUFSIZ );
(*authcb) ("Enter your username: ", buf, NE_ABUFSIZ-1, 1, 0, _userdata );
(*authcb) ("Enter your username: ", buf, NE_ABUFSIZ-1, 1, 0, csync_get_userdata(ctx->csync_ctx) );
if( strlen(buf) < NE_ABUFSIZ ) {
strcpy( username, buf );
}
memset( buf, 0, NE_ABUFSIZ );
(*authcb) ("Enter your password: ", buf, NE_ABUFSIZ-1, 0, 0, _userdata );
(*authcb) ("Enter your password: ", buf, NE_ABUFSIZ-1, 0, 0, csync_get_userdata(ctx->csync_ctx) );
if( strlen(buf) < NE_ABUFSIZ) {
strcpy( password, buf );
}
@@ -235,15 +164,15 @@ static int ne_auth( void *userdata, const char *realm, int attempt,
* from the neon lib to authenticate against a proxy. The data to authenticate
* against comes from mirall throught vio_module_init function.
*/
static int ne_proxy_auth( void *userdata, const char *realm, int attempt,
static int proxy_authentication_callback_by_neon( void *userdata, const char *realm, int attempt,
char *username, char *password)
{
(void) userdata;
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
(void) realm;
if( dav_session.proxy_user && strlen( dav_session.proxy_user ) < NE_ABUFSIZ) {
strcpy( username, dav_session.proxy_user );
if( dav_session.proxy_pwd && strlen( dav_session.proxy_pwd ) < NE_ABUFSIZ) {
strcpy( password, dav_session.proxy_pwd );
if( ctx->dav_session.proxy_user && strlen( ctx->dav_session.proxy_user ) < NE_ABUFSIZ) {
strcpy( username, ctx->dav_session.proxy_user );
if( ctx->dav_session.proxy_pwd && strlen( ctx->dav_session.proxy_pwd ) < NE_ABUFSIZ) {
strcpy( password, ctx->dav_session.proxy_pwd );
}
}
/* NTLM needs several attempts */
@@ -251,42 +180,42 @@ static int ne_proxy_auth( void *userdata, const char *realm, int attempt,
}
/* Configure the proxy depending on the variables */
static int configureProxy( ne_session *session )
static int configureProxy( csync_owncloud_ctx_t *ctx, ne_session *session )
{
int port = 8080;
int re = -1;
if( ! session ) return -1;
if( ! dav_session.proxy_type ) return 0; /* Go by NoProxy per default */
if( ! ctx->dav_session.proxy_type ) return 0; /* Go by NoProxy per default */
if( dav_session.proxy_port > 0 ) {
port = dav_session.proxy_port;
if( ctx->dav_session.proxy_port > 0 ) {
port = ctx->dav_session.proxy_port;
}
if( c_streq(dav_session.proxy_type, "NoProxy" )) {
if( c_streq(ctx->dav_session.proxy_type, "NoProxy" )) {
DEBUG_WEBDAV("No proxy configured.");
re = 0;
} else if( c_streq(dav_session.proxy_type, "DefaultProxy") ||
c_streq(dav_session.proxy_type, "HttpProxy") ||
c_streq(dav_session.proxy_type, "HttpCachingProxy") ||
c_streq(dav_session.proxy_type, "Socks5Proxy")) {
} else if( c_streq(ctx->dav_session.proxy_type, "DefaultProxy") ||
c_streq(ctx->dav_session.proxy_type, "HttpProxy") ||
c_streq(ctx->dav_session.proxy_type, "HttpCachingProxy") ||
c_streq(ctx->dav_session.proxy_type, "Socks5Proxy")) {
if( dav_session.proxy_host ) {
DEBUG_WEBDAV("%s at %s:%d", dav_session.proxy_type, dav_session.proxy_host, port );
if (c_streq(dav_session.proxy_type, "Socks5Proxy")) {
ne_session_socks_proxy(session, NE_SOCK_SOCKSV5, dav_session.proxy_host, port,
dav_session.proxy_user, dav_session.proxy_pwd);
if( ctx->dav_session.proxy_host ) {
DEBUG_WEBDAV("%s at %s:%d", ctx->dav_session.proxy_type, ctx->dav_session.proxy_host, port );
if (c_streq(ctx->dav_session.proxy_type, "Socks5Proxy")) {
ne_session_socks_proxy(session, NE_SOCK_SOCKSV5, ctx->dav_session.proxy_host, port,
ctx->dav_session.proxy_user, ctx->dav_session.proxy_pwd);
} else {
ne_session_proxy(session, dav_session.proxy_host, port );
ne_session_proxy(session, ctx->dav_session.proxy_host, port );
}
re = 2;
} else {
DEBUG_WEBDAV("%s requested but no proxy host defined.", dav_session.proxy_type );
DEBUG_WEBDAV("%s requested but no proxy host defined.", ctx->dav_session.proxy_type );
/* we used to try ne_system_session_proxy here, but we should rather err out
to behave exactly like the caller. */
}
} else {
DEBUG_WEBDAV( "Unsupported Proxy: %s", dav_session.proxy_type );
DEBUG_WEBDAV( "Unsupported Proxy: %s", ctx->dav_session.proxy_type );
}
return re;
@@ -303,9 +232,9 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
const char *sc = NULL;
char *key = NULL;
(void) userdata;
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
if (dav_session.session_key)
if (ctx->dav_session.session_key)
return; /* We already have a session cookie, and we should ignore other ones */
if(!(status && req)) return;
@@ -373,8 +302,8 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
}
if( key ) {
DEBUG_WEBDAV("----> Session-key: %s", key);
SAFE_FREE(dav_session.session_key);
dav_session.session_key = key;
SAFE_FREE(ctx->dav_session.session_key);
ctx->dav_session.session_key = key;
}
}
@@ -385,13 +314,14 @@ static void post_request_hook(ne_request *req, void *userdata, const ne_status *
static void request_created_hook(ne_request *req, void *userdata,
const char *method, const char *requri)
{
(void) userdata;
// FIXME Can possibly be merged with pre_send_hook
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
(void) method;
(void) requri;
if( !req ) return;
if(dav_session.proxy_type) {
if(ctx->dav_session.proxy_type) {
/* required for NTLM */
ne_add_request_header(req, "Proxy-Connection", "Keep-Alive");
}
@@ -404,12 +334,12 @@ static void request_created_hook(ne_request *req, void *userdata,
static void pre_send_hook(ne_request *req, void *userdata,
ne_buffer *header)
{
(void) userdata;
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
if( !req ) return;
if(dav_session.session_key) {
ne_buffer_concat(header, "Cookie: ", dav_session.session_key, "\r\n", NULL);
if(ctx->dav_session.session_key) {
ne_buffer_concat(header, "Cookie: ", ctx->dav_session.session_key, "\r\n", NULL);
} else {
DEBUG_WEBDAV("csync pre_send_hook We don't have a Auth Cookie (session_key), this is wrong!");
}
@@ -419,16 +349,15 @@ static int post_send_hook(ne_request *req, void *userdata,
const ne_status *status)
{
const char *location;
(void) userdata;
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
(void) status;
location = ne_get_response_header(req, "Location");
if( !location ) return NE_OK;
if( dav_session.redir_callback ) {
if( dav_session.redir_callback( dav_session.csync_ctx, location ) ) {
if( ctx->dav_session.redir_callback ) {
if( ctx->dav_session.redir_callback( ctx->csync_ctx, location ) ) {
return NE_REDIRECT;
} else {
return NE_RETRY;
@@ -438,37 +367,12 @@ static int post_send_hook(ne_request *req, void *userdata,
return NE_REDIRECT;
}
// as per http://sourceforge.net/p/predef/wiki/OperatingSystems/
// extend as required
static const char* get_platform() {
#if defined (_WIN32)
return "Windows";
#elif defined(__APPLE__)
return "Macintosh";
#elif defined(__gnu_linux__)
return "Linux";
#elif defined(__DragonFly__)
/* might also define __FreeBSD__ */
return "DragonFlyBSD";
#elif defined(__FreeBSD__)
return "FreeBSD";
#elif defined(__NetBSD__)
return "NetBSD";
#elif defined(__OpenBSD__)
return "OpenBSD";
#elif defined(sun) || defined(__sun)
return "Solaris";
#else
return "Unknown OS";
#endif
}
/*
* Connect to a DAV server
* This function sets the flag _connected if the connection is established
* and returns if the flag is set, so calling it frequently is save.
*/
static int dav_connect(const char *base_url) {
static int dav_connect(csync_owncloud_ctx_t *ctx, const char *base_url) {
int useSSL = 0;
int rc;
char protocol[6] = {'\0'};
@@ -479,11 +383,14 @@ static int dav_connect(const char *base_url) {
unsigned int port = 0;
int proxystate = -1;
if (_connected) {
if (ctx->_connected) {
return 0;
}
rc = c_parse_uri( base_url, &scheme, &dav_session.user, &dav_session.pwd, &host, &port, &path );
rc = c_parse_uri( base_url, &scheme,
&ctx->dav_session.user,
&ctx->dav_session.pwd,
&host, &port, &path );
if( rc < 0 ) {
DEBUG_WEBDAV("Failed to parse uri %s", base_url );
goto out;
@@ -505,29 +412,29 @@ static int dav_connect(const char *base_url) {
goto out;
}
DEBUG_WEBDAV("* user %s", dav_session.user ? dav_session.user : "");
DEBUG_WEBDAV("* user %s", ctx->dav_session.user ? ctx->dav_session.user : "");
if (port == 0) {
port = ne_uri_defaultport(protocol);
}
dav_session.ctx = ne_session_create( protocol, host, port);
ctx->dav_session.ctx = ne_session_create( protocol, host, port);
if (dav_session.ctx == NULL) {
if (ctx->dav_session.ctx == NULL) {
DEBUG_WEBDAV("Session create with protocol %s failed", protocol );
rc = -1;
goto out;
}
if (dav_session.read_timeout != 0) {
ne_set_read_timeout(dav_session.ctx, dav_session.read_timeout);
DEBUG_WEBDAV("Timeout set to %u seconds", dav_session.read_timeout );
if (ctx->dav_session.read_timeout != 0) {
ne_set_read_timeout(ctx->dav_session.ctx, ctx->dav_session.read_timeout);
DEBUG_WEBDAV("Timeout set to %u seconds", ctx->dav_session.read_timeout );
}
snprintf( uaBuf, sizeof(uaBuf), "Mozilla/5.0 (%s) csyncoC/%s",
get_platform(), CSYNC_STRINGIFY( LIBCSYNC_VERSION ));
ne_set_useragent( dav_session.ctx, uaBuf);
ne_set_server_auth(dav_session.ctx, ne_auth, 0 );
csync_owncloud_get_platform(), CSYNC_STRINGIFY( LIBCSYNC_VERSION ));
ne_set_useragent( ctx->dav_session.ctx, uaBuf);
ne_set_server_auth(ctx->dav_session.ctx, authentication_callback_by_neon, ctx);
if( useSSL ) {
if (!ne_has_support(NE_FEATURE_SSL)) {
@@ -536,28 +443,28 @@ static int dav_connect(const char *base_url) {
goto out;
}
ne_ssl_trust_default_ca( dav_session.ctx );
ne_ssl_set_verify( dav_session.ctx, verify_sslcert, 0 );
ne_ssl_trust_default_ca( ctx->dav_session.ctx );
ne_ssl_set_verify( ctx->dav_session.ctx, ssl_callback_by_neon, ctx);
}
/* Hook called when a request is created. It sets the proxy connection header. */
ne_hook_create_request( dav_session.ctx, request_created_hook, NULL );
ne_hook_create_request( ctx->dav_session.ctx, request_created_hook, ctx );
/* Hook called after response headers are read. It gets the Session ID. */
ne_hook_post_headers( dav_session.ctx, post_request_hook, NULL );
ne_hook_post_headers( ctx->dav_session.ctx, post_request_hook, ctx );
/* Hook called before a request is sent. It sets the cookies. */
ne_hook_pre_send( dav_session.ctx, pre_send_hook, NULL );
ne_hook_pre_send( ctx->dav_session.ctx, pre_send_hook, ctx );
/* Hook called after request is dispatched. Used for handling possible redirections. */
ne_hook_post_send( dav_session.ctx, post_send_hook, NULL );
ne_hook_post_send( ctx->dav_session.ctx, post_send_hook, ctx );
/* Proxy support */
proxystate = configureProxy( dav_session.ctx );
proxystate = configureProxy( ctx, ctx->dav_session.ctx );
if( proxystate < 0 ) {
DEBUG_WEBDAV("Error: Proxy-Configuration failed.");
} else if( proxystate > 0 ) {
ne_set_proxy_auth( dav_session.ctx, ne_proxy_auth, 0 );
ne_set_proxy_auth( ctx->dav_session.ctx, proxy_authentication_callback_by_neon, ctx );
}
_connected = 1;
ctx->_connected = 1;
rc = 0;
out:
SAFE_FREE(path);
@@ -573,24 +480,16 @@ out:
* and fills a resource struct and stores it to the result list which
* is stored in the listdir_context.
*/
static void results(void *userdata,
static void propfind_results_callback(void *userdata,
const ne_uri *uri,
const ne_prop_result_set *set)
{
struct listdir_context *fetchCtx = userdata;
struct resource *newres = 0;
const char *clength, *modtime = NULL;
const char *resourcetype = NULL;
const char *md5sum = NULL;
const char *file_id = NULL;
const ne_status *status = NULL;
char *path = ne_path_unescape( uri->path );
(void) status;
if( ! fetchCtx ) {
DEBUG_WEBDAV("No valid fetchContext");
return;
}
if( ! fetchCtx->target ) {
DEBUG_WEBDAV("error: target must not be zero!" );
@@ -599,37 +498,9 @@ static void results(void *userdata,
/* Fill the resource structure with the data about the file */
newres = c_malloc(sizeof(struct resource));
ZERO_STRUCTP(newres);
newres->uri = path; /* no need to strdup because ne_path_unescape already allocates */
newres->name = c_basename( path );
modtime = ne_propset_value( set, &ls_props[0] );
clength = ne_propset_value( set, &ls_props[1] );
resourcetype = ne_propset_value( set, &ls_props[2] );
md5sum = ne_propset_value( set, &ls_props[3] );
file_id = ne_propset_value( set, &ls_props[4] );
newres->type = resr_normal;
if( clength == NULL && resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
newres->type = resr_collection;
}
if (modtime) {
newres->modtime = oc_httpdate_parse(modtime);
}
/* DEBUG_WEBDAV("Parsing Modtime: %s -> %llu", modtime, (unsigned long long) newres->modtime ); */
newres->size = 0;
if (clength) {
newres->size = atoll(clength);
/* DEBUG_WEBDAV("Parsed File size for %s from %s: %lld", newres->name, clength, (long long)newres->size ); */
}
if( md5sum ) {
newres->md5 = csync_normalize_etag(md5sum);
}
csync_vio_set_file_id(newres->file_id, file_id);
fill_webdav_properties_into_resource(newres, set);
/* prepend the new resource to the result list */
newres->next = fetchCtx->list;
@@ -643,7 +514,7 @@ static void results(void *userdata,
/*
* fetches a resource list from the WebDAV server. This is equivalent to list dir.
*/
static struct listdir_context *fetch_resource_list(const char *uri, int depth)
static struct listdir_context *fetch_resource_list(csync_owncloud_ctx_t *ctx, const char *uri, int depth)
{
struct listdir_context *fetchCtx;
int ret = 0;
@@ -657,12 +528,12 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
/* The old legacy one-level PROPFIND cache. Also gets filled
by the recursive cache if 'infinity' did not suceed. */
if (propfind_cache) {
if (c_streq(curi, propfind_cache->target)) {
if (ctx->propfind_cache) {
if (c_streq(curi, ctx->propfind_cache->target)) {
DEBUG_WEBDAV("fetch_resource_list Using simple PROPFIND cache %s", curi);
propfind_cache->ref++;
ctx->propfind_cache->ref++;
SAFE_FREE(curi);
return propfind_cache;
return ctx->propfind_cache;
}
}
@@ -678,10 +549,10 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
fetchCtx->ref = 1;
/* do a propfind request and parse the results in the results function, set as callback */
hdl = ne_propfind_create(dav_session.ctx, curi, depth);
hdl = ne_propfind_create(ctx->dav_session.ctx, curi, depth);
if(hdl) {
ret = ne_propfind_named(hdl, ls_props, results, fetchCtx);
ret = ne_propfind_named(hdl, ls_props, propfind_results_callback, fetchCtx);
request = ne_propfind_get_request( hdl );
req_status = ne_get_status( request );
}
@@ -694,14 +565,14 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
req_status->reason_phrase);
ret = NE_CONNECT;
set_error_message(req_status->reason_phrase);
set_error_message(ctx, req_status->reason_phrase);
}
DEBUG_WEBDAV("Simple propfind result code %d.", req_status ? req_status->code : -1);
} else {
if( ret == NE_ERROR && req_status->code == 404) {
errno = ENOENT;
} else {
set_errno_from_neon_errcode(ret);
set_errno_from_neon_errcode(ctx, ret);
}
}
@@ -716,18 +587,18 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
content_type ? content_type: "<empty>");
errno = ERRNO_WRONG_CONTENT;
set_error_message("Server error: PROPFIND reply is not XML formatted!");
set_error_message(ctx, "Server error: PROPFIND reply is not XML formatted!");
ret = NE_CONNECT;
}
}
if( ret != NE_OK ) {
const char *err = NULL;
set_errno_from_neon_errcode(ret);
set_errno_from_neon_errcode(ctx, ret);
err = ne_get_error( dav_session.ctx );
err = ne_get_error( ctx->dav_session.ctx );
if(err) {
set_error_message(err);
set_error_message(ctx, err);
}
DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
}
@@ -740,19 +611,19 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
return NULL;
}
free_fetchCtx(propfind_cache);
propfind_cache = fetchCtx;
propfind_cache->ref++;
free_fetchCtx(ctx->propfind_cache);
ctx->propfind_cache = fetchCtx;
ctx->propfind_cache->ref++;
return fetchCtx;
}
static struct listdir_context *fetch_resource_list_attempts(const char *uri, int depth)
static struct listdir_context *fetch_resource_list_attempts(csync_owncloud_ctx_t *ctx, const char *uri, int depth)
{
int i;
struct listdir_context *fetchCtx = NULL;
for(i = 0; i < 10; ++i) {
fetchCtx = fetch_resource_list(uri, depth);
fetchCtx = fetch_resource_list(ctx, uri, depth);
if(fetchCtx) break;
/* only loop in case the content is not XML formatted. Otherwise for every
* non successful stat (for non existing directories) its tried 10 times. */
@@ -764,165 +635,39 @@ static struct listdir_context *fetch_resource_list_attempts(const char *uri, int
return fetchCtx;
}
static void fill_stat_cache( csync_vio_file_stat_t *lfs ) {
if( _stat_cache.name ) SAFE_FREE(_stat_cache.name);
if( _stat_cache.etag ) SAFE_FREE(_stat_cache.etag );
if( !lfs) return;
_stat_cache.name = c_strdup(lfs->name);
_stat_cache.mtime = lfs->mtime;
_stat_cache.fields = lfs->fields;
_stat_cache.type = lfs->type;
_stat_cache.size = lfs->size;
csync_vio_file_stat_set_file_id(&_stat_cache, lfs->file_id);
if( lfs->etag ) {
_stat_cache.etag = c_strdup(lfs->etag);
}
}
/*
* file functions
*/
int owncloud_stat(const char *uri, csync_vio_file_stat_t *buf) {
/* get props:
* modtime
* creattime
* size
*/
csync_vio_file_stat_t *lfs = NULL;
struct listdir_context *fetchCtx = NULL;
char *decodedUri = NULL;
int len = 0;
errno = 0;
buf->name = c_basename(uri);
if (buf->name == NULL) {
errno = ENOMEM;
return -1;
}
if( _stat_cache.name && strcmp( buf->name, _stat_cache.name ) == 0 ) {
buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
buf->fields = _stat_cache.fields;
buf->type = _stat_cache.type;
buf->mtime = _stat_cache.mtime;
buf->size = _stat_cache.size;
buf->mode = _stat_perms( _stat_cache.type );
buf->etag = NULL;
if( _stat_cache.etag ) {
buf->etag = c_strdup( _stat_cache.etag );
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;
}
csync_vio_file_stat_set_file_id( buf, _stat_cache.file_id );
return 0;
}
DEBUG_WEBDAV("owncloud_stat => Could not find in stat cache %s", uri);
/* fetch data via a propfind call. */
/* fetchCtx = fetch_resource_list( uri, NE_DEPTH_ONE); */
fetchCtx = fetch_resource_list_attempts( uri, NE_DEPTH_ONE);
DEBUG_WEBDAV("=> Errno after fetch resource list for %s: %d", uri, errno);
if (!fetchCtx) {
return -1;
}
if( fetchCtx ) {
struct resource *res = fetchCtx->list;
while( res ) {
/* remove trailing slashes */
len = strlen(res->uri);
while( len > 0 && res->uri[len-1] == '/' ) --len;
decodedUri = ne_path_unescape( fetchCtx->target ); /* allocates memory */
/* Only do the comparaison of the part of the string without the trailing
slashes, and make sure decodedUri is not too large */
if( strncmp(res->uri, decodedUri, len ) == 0 && decodedUri[len] == '\0') {
SAFE_FREE( decodedUri );
break;
}
res = res->next;
SAFE_FREE( decodedUri );
}
if( res ) {
DEBUG_WEBDAV("Working on file %s", res->name );
} else {
DEBUG_WEBDAV("ERROR: Result struct not valid!");
}
lfs = resourceToFileStat( res );
if( lfs ) {
buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;
buf->fields = lfs->fields;
buf->type = lfs->type;
buf->mtime = lfs->mtime;
buf->size = lfs->size;
buf->mode = _stat_perms( lfs->type );
buf->etag = NULL;
if( lfs->etag ) {
buf->etag = c_strdup( lfs->etag );
}
csync_vio_file_stat_set_file_id( buf, lfs->file_id );
/* fill the static stat buf as input for the stat function */
csync_vio_file_stat_destroy( lfs );
}
free_fetchCtx( fetchCtx );
}
DEBUG_WEBDAV("STAT result from propfind: %s, mtime: %llu", buf->name ? buf->name:"NULL",
(unsigned long long) buf->mtime );
return 0;
}
/*
* directory functions
*/
csync_vio_handle_t *owncloud_opendir(const char *uri) {
csync_vio_handle_t *owncloud_opendir(CSYNC *ctx, const char *uri) {
struct listdir_context *fetchCtx = NULL;
char *curi = NULL;
DEBUG_WEBDAV("opendir method called on %s", uri );
if (dav_connect( uri ) < 0) {
if (dav_connect( ctx->owncloud_context, uri ) < 0) {
DEBUG_WEBDAV("connection failed");
return NULL;
}
curi = _cleanPath( uri );
if (is_first_propfind && !dav_session.no_recursive_propfind) {
is_first_propfind = false;
if (ctx->owncloud_context->is_first_propfind && !ctx->owncloud_context->dav_session.no_recursive_propfind) {
ctx->owncloud_context->is_first_propfind = false;
// Try to fill it
fill_recursive_propfind_cache(uri, curi);
fill_recursive_propfind_cache(ctx->owncloud_context, uri, curi);
}
if (propfind_recursive_cache) {
if (ctx->owncloud_context->propfind_recursive_cache) {
// Try to fetch from recursive cache (if we have one)
fetchCtx = get_listdir_context_from_recursive_cache(curi);
fetchCtx = get_listdir_context_from_recursive_cache(ctx->owncloud_context, curi);
}
SAFE_FREE(curi);
is_first_propfind = false;
ctx->owncloud_context->is_first_propfind = false;
if (fetchCtx) {
return fetchCtx;
}
/* fetchCtx = fetch_resource_list( uri, NE_DEPTH_ONE ); */
fetchCtx = fetch_resource_list_attempts( uri, NE_DEPTH_ONE);
fetchCtx = fetch_resource_list_attempts( ctx->owncloud_context, uri, NE_DEPTH_ONE);
if( !fetchCtx ) {
/* errno is set properly in fetch_resource_list */
DEBUG_WEBDAV("Errno set to %d", errno);
@@ -935,17 +680,16 @@ csync_vio_handle_t *owncloud_opendir(const char *uri) {
/* no freeing of curi because its part of the fetchCtx and gets freed later */
}
int owncloud_closedir(csync_vio_handle_t *dhandle) {
int owncloud_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
struct listdir_context *fetchCtx = dhandle;
free_fetchCtx(fetchCtx);
(void)ctx;
return 0;
}
csync_vio_file_stat_t *owncloud_readdir(csync_vio_handle_t *dhandle) {
csync_vio_file_stat_t *owncloud_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
struct listdir_context *fetchCtx = dhandle;
(void)ctx;
// DEBUG_WEBDAV("owncloud_readdir" );
// DEBUG_WEBDAV("owncloud_readdir %s ", fetchCtx->target);
@@ -971,10 +715,20 @@ csync_vio_file_stat_t *owncloud_readdir(csync_vio_handle_t *dhandle) {
*/
escaped_path = ne_path_escape( currResource->uri );
if (ne_path_compare(fetchCtx->target, escaped_path) != 0) {
csync_vio_file_stat_t* lfs = resourceToFileStat(currResource);
fill_stat_cache(lfs);
// Convert the resource for the caller
csync_vio_file_stat_t* lfs = csync_vio_file_stat_new();
resourceToFileStat(lfs, currResource);
SAFE_FREE( escaped_path );
return lfs;
} else {
/* The first item is the root item, memorize its permissions */
if (!ctx->remote.root_perms) {
if (strlen(currResource->remotePerm) > 0) {
/* Only copy if permissions contain something. Empty string means server didn't return them */
ctx->remote.root_perms = c_strdup(currResource->remotePerm);
}
}
}
/* This is the target URI */
@@ -984,39 +738,55 @@ csync_vio_file_stat_t *owncloud_readdir(csync_vio_handle_t *dhandle) {
return NULL;
}
char *owncloud_error_string(void)
char *owncloud_error_string(CSYNC* ctx)
{
return dav_session.error_string;
return ctx->owncloud_context->dav_session.error_string;
}
int owncloud_commit(void) {
int owncloud_commit(CSYNC* ctx) {
if (!ctx->owncloud_context) {
return 0;
}
clean_caches();
clear_propfind_recursive_cache(ctx->owncloud_context);
if( dav_session.ctx ) {
ne_forget_auth(dav_session.ctx);
ne_session_destroy( dav_session.ctx );
}
free_fetchCtx(ctx->owncloud_context->propfind_cache);
ctx->owncloud_context->propfind_cache = NULL;
if( ctx->owncloud_context->dav_session.ctx ) {
ne_forget_auth(ctx->owncloud_context->dav_session.ctx);
ne_session_destroy(ctx->owncloud_context->dav_session.ctx );
ctx->owncloud_context->dav_session.ctx = 0;
}
ctx->owncloud_context->is_first_propfind = true;
/* DEBUG_WEBDAV( "********** vio_module_shutdown" ); */
dav_session.ctx = 0;
ctx->owncloud_context->dav_session.ctx = 0;
// ne_sock_exit();
_connected = 0; /* triggers dav_connect to go through the whole neon setup */
ctx->owncloud_context->_connected = 0; /* triggers dav_connect to go through the whole neon setup */
SAFE_FREE( dav_session.user );
SAFE_FREE( dav_session.pwd );
SAFE_FREE( dav_session.session_key);
SAFE_FREE( dav_session.error_string );
SAFE_FREE( ctx->owncloud_context->dav_session.user );
SAFE_FREE( ctx->owncloud_context->dav_session.pwd );
SAFE_FREE( ctx->owncloud_context->dav_session.session_key);
SAFE_FREE( ctx->owncloud_context->dav_session.error_string );
return 0;
}
int owncloud_set_property(const char *key, void *data) {
void owncloud_destroy(CSYNC* ctx)
{
owncloud_commit(ctx);
SAFE_FREE(ctx->owncloud_context);
ctx->owncloud_context = 0;
}
int owncloud_set_property(CSYNC* ctx, const char *key, void *data) {
#define READ_STRING_PROPERTY(P) \
if (c_streq(key, #P)) { \
SAFE_FREE(dav_session.P); \
dav_session.P = c_strdup((const char*)data); \
SAFE_FREE(ctx->owncloud_context->dav_session.P); \
ctx->owncloud_context->dav_session.P = c_strdup((const char*)data); \
return 0; \
}
READ_STRING_PROPERTY(session_key)
@@ -1027,48 +797,43 @@ int owncloud_set_property(const char *key, void *data) {
#undef READ_STRING_PROPERTY
if (c_streq(key, "proxy_port")) {
dav_session.proxy_port = *(int*)(data);
ctx->owncloud_context->dav_session.proxy_port = *(int*)(data);
return 0;
}
if (c_streq(key, "read_timeout") || c_streq(key, "timeout")) {
dav_session.read_timeout = *(int*)(data);
return 0;
}
if( c_streq(key, "csync_context")) {
dav_session.csync_ctx = data;
ctx->owncloud_context->dav_session.read_timeout = *(int*)(data);
return 0;
}
if( c_streq(key, "get_dav_session")) {
/* Give the ne_session to the caller */
*(ne_session**)data = dav_session.ctx;
*(ne_session**)data = ctx->owncloud_context->dav_session.ctx;
return 0;
}
if( c_streq(key, "no_recursive_propfind")) {
dav_session.no_recursive_propfind = *(bool*)(data);
ctx->owncloud_context->dav_session.no_recursive_propfind = *(bool*)(data);
return 0;
}
if( c_streq(key, "redirect_callback")) {
if (data) {
csync_owncloud_redirect_callback_t* cb_wrapper = data;
dav_session.redir_callback = *cb_wrapper;
ctx->owncloud_context->dav_session.redir_callback = *cb_wrapper;
} else {
dav_session.redir_callback = NULL;
ctx->owncloud_context->dav_session.redir_callback = NULL;
}
}
return -1;
}
void owncloud_init(void *userdata) {
void owncloud_init(CSYNC* ctx) {
_userdata = userdata;
_connected = 0; /* triggers dav_connect to go through the whole neon setup */
memset(&dav_session, 0, sizeof(dav_session));
ctx->owncloud_context = c_malloc( sizeof( struct csync_owncloud_ctx_s ));
ctx->owncloud_context->csync_ctx = ctx; // back reference
ctx->owncloud_context->is_first_propfind = true;
/* Disable it, Mirall can enable it for the first sync (= no DB)*/
dav_session.no_recursive_propfind = true;
ctx->owncloud_context->dav_session.no_recursive_propfind = true;
}
/* vim: set ts=4 sw=4 et cindent: */
+9 -150
Ver Arquivo
@@ -21,159 +21,18 @@
#ifndef CSYNC_OWNCLOUD_H
#define CSYNC_OWNCLOUD_H
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "config_csync.h"
#ifdef NEON_WITH_LFS /* Switch on LFS in libneon. Never remove the NE_LFS! */
#define NE_LFS
#endif
#include <neon/ne_basic.h>
#include <neon/ne_socket.h>
#include <neon/ne_session.h>
#include <neon/ne_request.h>
#include <neon/ne_props.h>
#include <neon/ne_auth.h>
#include <neon/ne_dates.h>
#include <neon/ne_compress.h>
#include <neon/ne_redirect.h>
#include "c_rbtree.h"
#include "c_lib.h"
#include "csync.h"
#include "csync_misc.h"
#include "csync_macros.h"
#include "c_private.h"
#include "httpbf.h"
#include "vio/csync_vio_file_stat.h"
#include "vio/csync_vio.h"
#include "csync_log.h"
#define DEBUG_WEBDAV(...) csync_log( 9, "oc_module", __VA_ARGS__);
enum resource_type {
resr_normal = 0,
resr_collection,
resr_reference,
resr_error
};
/* Struct to store data for each resource found during an opendir operation.
* It represents a single file entry.
*/
typedef struct resource {
char *uri; /* The complete uri */
char *name; /* The filename only */
enum resource_type type;
int64_t size;
time_t modtime;
char* md5;
char file_id[FILE_ID_BUF_SIZE+1];
struct resource *next;
} resource;
/* Struct to hold the context of a WebDAV PropFind operation to fetch
* a directory listing from the server.
*/
struct listdir_context {
struct resource *list; /* The list of result resources */
struct resource *currResource; /* A pointer to the current resource */
char *target; /* Request-URI of the PROPFIND */
unsigned int result_count; /* number of elements stored in list */
int ref; /* reference count, only destroy when it reaches 0 */
};
/* Our cache, key is a char* */
extern c_rbtree_t *propfind_recursive_cache;
/* Values are propfind_recursive_element: */
struct propfind_recursive_element {
struct resource *self;
struct resource *children;
struct propfind_recursive_element *parent;
};
typedef struct propfind_recursive_element propfind_recursive_element_t;
void clear_propfind_recursive_cache(void);
struct listdir_context *get_listdir_context_from_recursive_cache(const char *curi);
void fill_recursive_propfind_cache(const char *uri, const char *curi);
struct listdir_context *get_listdir_context_from_cache(const char *curi);
void fetch_resource_list_recursive(const char *uri, const char *curi);
typedef int (*csync_owncloud_redirect_callback_t)(CSYNC* ctx, const char* uri);
/* Struct with the WebDAV session */
struct dav_session_s {
ne_session *ctx;
char *user;
char *pwd;
char *proxy_type;
char *proxy_host;
int proxy_port;
char *proxy_user;
char *proxy_pwd;
char *session_key;
char *error_string;
int read_timeout;
CSYNC *csync_ctx;
bool no_recursive_propfind;
csync_owncloud_redirect_callback_t redir_callback;
};
extern struct dav_session_s dav_session;
/* The list of properties that is fetched in PropFind on a collection */
static const ne_propname ls_props[] = {
{ "DAV:", "getlastmodified" },
{ "DAV:", "getcontentlength" },
{ "DAV:", "resourcetype" },
{ "DAV:", "getetag"},
{ "http://owncloud.org/ns", "id"},
{ NULL, NULL }
};
void set_errno_from_http_errcode( int err );
void set_error_message( const char *msg );
void set_errno_from_neon_errcode( int neon_code );
int http_result_code_from_session(void);
void set_errno_from_session(void);
time_t oc_httpdate_parse( const char *date );
char *_cleanPath( const char* uri );
int _stat_perms( int type );
csync_vio_file_stat_t *resourceToFileStat( struct resource *res );
// Public API from vio
csync_vio_handle_t *owncloud_opendir(const char *uri);
csync_vio_file_stat_t *owncloud_readdir(csync_vio_handle_t *dhandle);
int owncloud_closedir(csync_vio_handle_t *dhandle);
int owncloud_stat(const char *uri, csync_vio_file_stat_t *buf);
int owncloud_commit(void);
char *owncloud_error_string(void);
void owncloud_init(void *userdata);
int owncloud_set_property(const char *key, void *data);
// Public API used by csync
csync_vio_handle_t *owncloud_opendir(CSYNC* ctx, const char *uri);
csync_vio_file_stat_t *owncloud_readdir(CSYNC* ctx, csync_vio_handle_t *dhandle);
int owncloud_closedir(CSYNC* ctx, csync_vio_handle_t *dhandle);
int owncloud_commit(CSYNC* ctx);
void owncloud_destroy(CSYNC* ctx);
char *owncloud_error_string(CSYNC* ctx);
void owncloud_init(CSYNC* ctx);
int owncloud_set_property(CSYNC* ctx, const char *key, void *data);
#endif /* CSYNC_OWNCLOUD_H */
+201
Ver Arquivo
@@ -0,0 +1,201 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2011 by Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2012 by Klaas Freitag <freitag@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef CSYNC_OWNCLOUD_PRIVATE_H
#define CSYNC_OWNCLOUD_PRIVATE_H
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "config_csync.h"
#ifdef NEON_WITH_LFS /* Switch on LFS in libneon. Never remove the NE_LFS! */
#define NE_LFS
#endif
#include <neon/ne_basic.h>
#include <neon/ne_socket.h>
#include <neon/ne_session.h>
#include <neon/ne_request.h>
#include <neon/ne_props.h>
#include <neon/ne_auth.h>
#include <neon/ne_dates.h>
#include <neon/ne_compress.h>
#include <neon/ne_redirect.h>
#include "c_rbtree.h"
#include "c_lib.h"
#include "csync.h"
#include "csync_misc.h"
#include "csync_macros.h"
#include "c_private.h"
#include "httpbf.h"
#include "vio/csync_vio_file_stat.h"
#include "vio/csync_vio.h"
#include "csync_log.h"
#include "csync_owncloud.h"
#define DEBUG_WEBDAV(...) csync_log( 9, "oc_module", __VA_ARGS__);
typedef int (*csync_owncloud_redirect_callback_t)(CSYNC* ctx, const char* uri);
/* Struct with the WebDAV session */
struct dav_session_s {
ne_session *ctx;
char *user;
char *pwd;
char *proxy_type;
char *proxy_host;
int proxy_port;
char *proxy_user;
char *proxy_pwd;
char *session_key;
char *error_string;
int read_timeout;
bool no_recursive_propfind;
csync_owncloud_redirect_callback_t redir_callback;
};
struct csync_owncloud_ctx_s {
CSYNC *csync_ctx;
// For the PROPFIND results
bool is_first_propfind;
struct listdir_context *propfind_cache;
c_rbtree_t *propfind_recursive_cache;
int propfind_recursive_cache_depth;
int propfind_recursive_cache_file_count;
int propfind_recursive_cache_folder_count;
// For the WebDAV connection
struct dav_session_s dav_session; /* The DAV Session, initialised in dav_connect */
int _connected; /* flag to indicate if a connection exists, ie.
the dav_session is valid */
};
typedef struct csync_owncloud_ctx_s csync_owncloud_ctx_t;
//typedef csync_owncloud_ctx_t* csync_owncloud_ctx_p;
enum resource_type {
resr_normal = 0,
resr_collection,
resr_reference,
resr_error
};
/* The list of properties that is fetched in PropFind on a collection */
static const ne_propname ls_props[] = {
{ "DAV:", "getlastmodified" },
{ "DAV:", "getcontentlength" },
{ "DAV:", "resourcetype" },
{ "DAV:", "getetag"},
{ "http://owncloud.org/ns", "id"},
{ "http://owncloud.org/ns", "dDU"},
{ "http://owncloud.org/ns", "dDC"},
{ "http://owncloud.org/ns", "permissions"},
{ NULL, NULL }
};
/* Struct to store data for each resource found during an opendir operation.
* It represents a single file entry.
*/
typedef struct resource {
char *uri; /* The complete uri */
char *name; /* The filename only */
enum resource_type type;
int64_t size;
time_t modtime;
char* md5;
char file_id[FILE_ID_BUF_SIZE+1];
// Those two are optional from the server. We can use those URL to download the file directly
// without going through the ownCloud instance.
char *directDownloadUrl;
char *directDownloadCookies;
// See https://github.com/owncloud/core/issues/8322
char remotePerm[REMOTE_PERM_BUF_SIZE+1];
struct resource *next;
} resource;
/* Struct to hold the context of a WebDAV PropFind operation to fetch
* a directory listing from the server.
*/
struct listdir_context {
struct resource *list; /* The list of result resources */
struct resource *currResource; /* A pointer to the current resource */
char *target; /* Request-URI of the PROPFIND */
unsigned int result_count; /* number of elements stored in list */
int ref; /* reference count, only destroy when it reaches 0 */
};
/* Values are propfind_recursive_element: */
struct propfind_recursive_element {
struct resource *self;
struct resource *children;
struct propfind_recursive_element *parent;
};
typedef struct propfind_recursive_element propfind_recursive_element_t;
void clear_propfind_recursive_cache(csync_owncloud_ctx_t *ctx);
struct listdir_context *get_listdir_context_from_recursive_cache(csync_owncloud_ctx_t *ctx, const char *curi);
void fill_recursive_propfind_cache(csync_owncloud_ctx_t *ctx, const char *uri, const char *curi);
struct listdir_context *get_listdir_context_from_cache(csync_owncloud_ctx_t *ctx, const char *curi);
void fetch_resource_list_recursive(csync_owncloud_ctx_t *ctx, const char *uri, const char *curi);
void set_errno_from_http_errcode( int err );
void set_error_message( csync_owncloud_ctx_t *ctx, const char *msg );
void set_errno_from_neon_errcode(csync_owncloud_ctx_t *ctx, int neon_code );
int http_result_code_from_session(csync_owncloud_ctx_t *ctx);
void set_errno_from_session(csync_owncloud_ctx_t *ctx);
time_t oc_httpdate_parse( const char *date );
char *_cleanPath( const char* uri );
void fill_webdav_properties_into_resource(struct resource* newres, const ne_prop_result_set *set);
void resourceToFileStat( csync_vio_file_stat_t *lfs, struct resource *res );
void resource_free(struct resource* o);
struct resource* resource_dup(struct resource* o);
void free_fetchCtx( struct listdir_context *ctx );
const char* csync_owncloud_get_platform(void);
#endif // CSYNC_OWNCLOUD_PRIVATE_H
+39 -105
Ver Arquivo
@@ -20,42 +20,7 @@
*/
#include "csync_owncloud.h"
c_rbtree_t *propfind_recursive_cache = NULL;
int propfind_recursive_cache_depth = 0;
int propfind_recursive_cache_file_count = 0;
int propfind_recursive_cache_folder_count = 0;
static struct resource* resource_dup(struct resource* o) {
struct resource *r = c_malloc (sizeof( struct resource ));
ZERO_STRUCTP(r);
r->uri = c_strdup(o->uri);
r->name = c_strdup(o->name);
r->type = o->type;
r->size = o->size;
r->modtime = o->modtime;
if( o->md5 ) {
r->md5 = c_strdup(o->md5);
}
r->next = o->next;
csync_vio_set_file_id(r->file_id, o->file_id);
return r;
}
static void resource_free(struct resource* o) {
struct resource* old = NULL;
while (o)
{
old = o;
o = o->next;
SAFE_FREE(old->uri);
SAFE_FREE(old->name);
SAFE_FREE(old->md5);
SAFE_FREE(old);
}
}
#include "csync_owncloud_private.h"
static void _tree_destructor(void *data) {
propfind_recursive_element_t *element = data;
@@ -64,27 +29,27 @@ static void _tree_destructor(void *data) {
SAFE_FREE(element);
}
void clear_propfind_recursive_cache(void)
void clear_propfind_recursive_cache(csync_owncloud_ctx_t *ctx)
{
if (propfind_recursive_cache) {
if (ctx->propfind_recursive_cache) {
DEBUG_WEBDAV("clear_propfind_recursive_cache Invalidating..");
c_rbtree_destroy(propfind_recursive_cache, _tree_destructor);
propfind_recursive_cache = NULL;
c_rbtree_destroy(ctx->propfind_recursive_cache, _tree_destructor);
ctx->propfind_recursive_cache = NULL;
}
}
struct listdir_context *get_listdir_context_from_recursive_cache(const char *curi)
struct listdir_context *get_listdir_context_from_recursive_cache(csync_owncloud_ctx_t *ctx, const char *curi)
{
propfind_recursive_element_t *element = NULL;
struct listdir_context *fetchCtx = NULL;
struct resource *iterator, *r;
if (!propfind_recursive_cache) {
if (!ctx->propfind_recursive_cache) {
DEBUG_WEBDAV("get_listdir_context_from_recursive_cache No cache");
return NULL;
}
element = c_rbtree_node_data(c_rbtree_find(propfind_recursive_cache, curi));
element = c_rbtree_node_data(c_rbtree_find(ctx->propfind_recursive_cache, curi));
if (!element) {
DEBUG_WEBDAV("get_listdir_context_from_recursive_cache No element %s in cache found", curi);
return NULL;
@@ -128,83 +93,53 @@ static int _data_cmp(const void *a, const void *b) {
const propfind_recursive_element_t *elementB = b;
return ne_path_compare(elementA->self->uri, elementB->self->uri);
}
static void propfind_results_recursive(void *userdata,
static void propfind_results_recursive_callback(void *userdata,
const ne_uri *uri,
const ne_prop_result_set *set)
{
struct resource *newres = 0;
const char *clength, *modtime, *file_id = NULL;
const char *resourcetype = NULL;
const char *md5sum = NULL;
const ne_status *status = NULL;
char *path = ne_path_unescape( uri->path );
char *parentPath;
char *propfindRootUri = (char*) userdata;
propfind_recursive_element_t *element = NULL;
propfind_recursive_element_t *pElement = NULL;
int depth = 0;
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
(void) status;
(void) propfindRootUri;
if (!propfind_recursive_cache) {
c_rbtree_create(&propfind_recursive_cache, _key_cmp, _data_cmp);
if (!ctx->propfind_recursive_cache) {
c_rbtree_create(&ctx->propfind_recursive_cache, _key_cmp, _data_cmp);
}
/* Fill the resource structure with the data about the file */
newres = c_malloc(sizeof(struct resource));
ZERO_STRUCTP(newres);
newres->uri = path; /* no need to strdup because ne_path_unescape already allocates */
newres->name = c_basename( path );
fill_webdav_properties_into_resource(newres, set);
modtime = ne_propset_value( set, &ls_props[0] );
clength = ne_propset_value( set, &ls_props[1] );
resourcetype = ne_propset_value( set, &ls_props[2] );
md5sum = ne_propset_value( set, &ls_props[3] );
file_id = ne_propset_value( set, &ls_props[4] );
newres->type = resr_normal;
if( resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
newres->type = resr_collection;
propfind_recursive_cache_folder_count++;
if( newres->type == resr_collection) {
ctx->propfind_recursive_cache_folder_count++;
} else {
/* DEBUG_WEBDAV("propfind_results_recursive %s [%d]", newres->uri, newres->type); */
propfind_recursive_cache_file_count++;
ctx->propfind_recursive_cache_file_count++;
}
if (modtime) {
newres->modtime = oc_httpdate_parse(modtime);
}
/* DEBUG_WEBDAV("Parsing Modtime: %s -> %llu", modtime, (unsigned long long) newres->modtime ); */
newres->size = 0;
if (clength) {
newres->size = atoll(clength);
/* DEBUG_WEBDAV("Parsed File size for %s from %s: %lld", newres->name, clength, (long long)newres->size ); */
}
if( md5sum ) {
newres->md5 = csync_normalize_etag(md5sum);
}
csync_vio_set_file_id(newres->file_id, file_id);
/*
DEBUG_WEBDAV("propfind_results_recursive %s [%s] %s", newres->uri, newres->type == resr_collection ? "collection" : "file", newres->md5);
*/
/* Create new item in rb tree */
if (newres->type == resr_collection) {
DEBUG_WEBDAV("propfind_results_recursive %s is a folder", newres->uri);
/* Check if in rb tree */
element = c_rbtree_node_data(c_rbtree_find(propfind_recursive_cache,uri->path));
element = c_rbtree_node_data(c_rbtree_find(ctx->propfind_recursive_cache,uri->path));
/* If not, create a new item and insert it */
if (!element) {
element = c_malloc(sizeof(propfind_recursive_element_t));
element->self = resource_dup(newres);
element->self->next = 0;
element->children = NULL;
element->parent = NULL;
c_rbtree_insert(propfind_recursive_cache, element);
c_rbtree_insert(ctx->propfind_recursive_cache, element);
/* DEBUG_WEBDAV("results_recursive Added collection %s", newres->uri); */
}
}
@@ -214,7 +149,7 @@ static void propfind_results_recursive(void *userdata,
if (parentPath) {
propfind_recursive_element_t *parentElement = NULL;
parentElement = c_rbtree_node_data(c_rbtree_find(propfind_recursive_cache,parentPath));
parentElement = c_rbtree_node_data(c_rbtree_find(ctx->propfind_recursive_cache,parentPath));
free(parentPath);
if (parentElement) {
@@ -230,9 +165,9 @@ static void propfind_results_recursive(void *userdata,
depth++;
pElement = pElement->parent;
}
if (depth > propfind_recursive_cache_depth) {
if (depth > ctx->propfind_recursive_cache_depth) {
DEBUG_WEBDAV("propfind_results_recursive %s new maximum tree depth %d", newres->uri, depth);
propfind_recursive_cache_depth = depth;
ctx->propfind_recursive_cache_depth = depth;
}
/* DEBUG_WEBDAV("results_recursive Added child %s to collection %s", newres->uri, element->self->uri); */
@@ -244,7 +179,7 @@ static void propfind_results_recursive(void *userdata,
newres = NULL;
}
void fetch_resource_list_recursive(const char *uri, const char *curi)
void fetch_resource_list_recursive(csync_owncloud_ctx_t *ctx, const char *uri, const char *curi)
{
int ret = 0;
ne_propfind_handler *hdl = NULL;
@@ -256,10 +191,10 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
DEBUG_WEBDAV("fetch_resource_list_recursive Starting recursive propfind %s %s", uri, curi);
/* do a propfind request and parse the results in the results function, set as callback */
hdl = ne_propfind_create(dav_session.ctx, curi, depth);
hdl = ne_propfind_create(ctx->dav_session.ctx, curi, depth);
if(hdl) {
ret = ne_propfind_named(hdl, ls_props, propfind_results_recursive, (void*)curi);
ret = ne_propfind_named(hdl, ls_props, propfind_results_recursive_callback, ctx);
request = ne_propfind_get_request( hdl );
req_status = ne_get_status( request );
}
@@ -271,14 +206,14 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
DEBUG_WEBDAV("ERROR: Request failed: status %d (%s)", req_status->code,
req_status->reason_phrase);
ret = NE_CONNECT;
set_error_message(req_status->reason_phrase);
set_error_message(ctx, req_status->reason_phrase);
}
DEBUG_WEBDAV("Recursive propfind result code %d.", req_status ? req_status->code : 0);
} else {
if( ret == NE_ERROR && req_status->code == 404) {
errno = ENOENT;
} else {
set_errno_from_neon_errcode(ret);
set_errno_from_neon_errcode(ctx, ret);
}
}
@@ -293,7 +228,7 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
DEBUG_WEBDAV("ERROR: Content type of propfind request not XML: %s.",
content_type ? content_type: "<empty>");
errno = ERRNO_WRONG_CONTENT;
set_error_message("Server error: PROPFIND reply is not XML formatted!");
set_error_message(ctx, "Server error: PROPFIND reply is not XML formatted!");
ret = NE_CONNECT;
}
}
@@ -301,7 +236,7 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
if( ret != NE_OK ) {
const char *err = NULL;
err = ne_get_error( dav_session.ctx );
err = ne_get_error( ctx->dav_session.ctx );
DEBUG_WEBDAV("WRN: propfind named failed with %d, request error: %s", ret, err ? err : "<nil>");
}
@@ -316,22 +251,21 @@ void fetch_resource_list_recursive(const char *uri, const char *curi)
}
/* Called by owncloud_opendir()->fetch_resource_list() to fill the cache */
extern struct listdir_context *propfind_cache;
void fill_recursive_propfind_cache(const char *uri, const char *curi) {
fetch_resource_list_recursive(uri, curi);
void fill_recursive_propfind_cache(csync_owncloud_ctx_t *ctx, const char *uri, const char *curi) {
fetch_resource_list_recursive(ctx, uri, curi);
if (propfind_recursive_cache_depth <= 2) {
if (ctx->propfind_recursive_cache_depth <= 2) {
DEBUG_WEBDAV("fill_recursive_propfind_cache %s Server maybe did not give us an 'infinity' depth result", curi);
/* transform the cache to the normal cache in propfind_cache */
propfind_cache = get_listdir_context_from_recursive_cache(curi);
ctx->propfind_cache = get_listdir_context_from_recursive_cache(ctx, curi);
/* clear the cache, it is bogus since the server returned only results for Depth 1 */
clear_propfind_recursive_cache();
clear_propfind_recursive_cache(ctx);
} else {
DEBUG_WEBDAV("fill_recursive_propfind_cache %s We received %d elements deep for 'infinity' depth (%d folders, %d files)",
curi,
propfind_recursive_cache_depth,
propfind_recursive_cache_folder_count,
propfind_recursive_cache_file_count);
ctx->propfind_recursive_cache_depth,
ctx->propfind_recursive_cache_folder_count,
ctx->propfind_recursive_cache_file_count);
}
}
+183 -43
Ver Arquivo
@@ -20,13 +20,15 @@
*/
#include "csync_owncloud.h"
#include "csync_owncloud_private.h"
#include "csync_misc.h"
void set_error_message( const char *msg )
void set_error_message( csync_owncloud_ctx_t *ctx, const char *msg )
{
SAFE_FREE(dav_session.error_string);
SAFE_FREE(ctx->dav_session.error_string);
if( msg )
dav_session.error_string = c_strdup(msg);
ctx->dav_session.error_string = c_strdup(msg);
}
void set_errno_from_http_errcode( int err ) {
@@ -104,12 +106,12 @@ void set_errno_from_http_errcode( int err ) {
errno = new_errno;
}
int http_result_code_from_session() {
const char *p = ne_get_error( dav_session.ctx );
int http_result_code_from_session(csync_owncloud_ctx_t *ctx) {
const char *p = ne_get_error( ctx->dav_session.ctx );
char *q;
int err;
set_error_message(p); /* remember the error message */
set_error_message(ctx, p); /* remember the error message */
err = strtol(p, &q, 10);
if (p == q) {
@@ -118,8 +120,8 @@ int http_result_code_from_session() {
return err;
}
void set_errno_from_session() {
int err = http_result_code_from_session();
void set_errno_from_session(csync_owncloud_ctx_t *ctx) {
int err = http_result_code_from_session(ctx);
if( err == EIO || err == ERRNO_ERROR_STRING) {
errno = err;
@@ -128,7 +130,7 @@ void set_errno_from_session() {
}
}
void set_errno_from_neon_errcode( int neon_code ) {
void set_errno_from_neon_errcode(csync_owncloud_ctx_t *ctx, int neon_code ) {
if( neon_code != NE_OK ) {
DEBUG_WEBDAV("Neon error code was %d", neon_code);
@@ -137,7 +139,7 @@ void set_errno_from_neon_errcode( int neon_code ) {
switch(neon_code) {
case NE_OK: /* Success, but still the possiblity of problems */
case NE_ERROR: /* Generic error; use ne_get_error(session) for message */
set_errno_from_session(); /* Something wrong with http communication */
set_errno_from_session(ctx); /* Something wrong with http communication */
break;
case NE_LOOKUP: /* Server or proxy hostname lookup failed */
errno = ERRNO_LOOKUP_ERROR;
@@ -279,19 +281,9 @@ time_t oc_httpdate_parse( const char *date ) {
/*
* helper: convert a resource struct to file_stat struct.
*/
csync_vio_file_stat_t *resourceToFileStat( struct resource *res )
void resourceToFileStat(csync_vio_file_stat_t *lfs, struct resource *res )
{
csync_vio_file_stat_t *lfs = NULL;
if( ! res ) {
return NULL;
}
lfs = c_malloc(sizeof(csync_vio_file_stat_t));
if (lfs == NULL) {
errno = ENOMEM;
return NULL;
}
ZERO_STRUCTP(lfs);
lfs->name = c_strdup( res->name );
@@ -312,30 +304,178 @@ csync_vio_file_stat_t *resourceToFileStat( struct resource *res )
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
if( res->md5 ) {
lfs->etag = c_strdup(res->md5);
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;
}
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;
csync_vio_file_stat_set_file_id(lfs, res->file_id);
return lfs;
}
/* WebDAV does not deliver permissions. Set a default here. */
int _stat_perms( int type ) {
int ret = 0;
if( type == CSYNC_VIO_FILE_TYPE_DIRECTORY ) {
/* DEBUG_WEBDAV("Setting mode in stat (dir)"); */
/* directory permissions */
ret = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR /* directory, rwx for user */
| S_IRGRP | S_IXGRP /* rx for group */
| S_IROTH | S_IXOTH; /* rx for others */
} else {
/* regualar file permissions */
/* DEBUG_WEBDAV("Setting mode in stat (file)"); */
ret = S_IFREG | S_IRUSR | S_IWUSR /* regular file, user read & write */
| S_IRGRP /* group read perm */
| S_IROTH; /* others read perm */
if (res->directDownloadUrl) {
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL;
lfs->directDownloadUrl = c_strdup(res->directDownloadUrl);
}
if (res->directDownloadCookies) {
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES;
lfs->directDownloadCookies = c_strdup(res->directDownloadCookies);
}
if (strlen(res->remotePerm) > 0) {
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERM;
strncpy(lfs->remotePerm, res->remotePerm, sizeof(lfs->remotePerm));
}
return ret;
}
void fill_webdav_properties_into_resource(struct resource* newres, const ne_prop_result_set *set)
{
const char *clength, *modtime, *file_id = NULL;
const char *directDownloadUrl = NULL;
const char *directDownloadCookies = NULL;
const char *resourcetype = NULL;
const char *etag = NULL;
const char *perm = NULL;
modtime = ne_propset_value( set, &ls_props[0] );
clength = ne_propset_value( set, &ls_props[1] );
resourcetype = ne_propset_value( set, &ls_props[2] );
etag = ne_propset_value( set, &ls_props[3] );
file_id = ne_propset_value( set, &ls_props[4] );
directDownloadUrl = ne_propset_value( set, &ls_props[5] );
directDownloadCookies = ne_propset_value( set, &ls_props[6] );
perm = ne_propset_value( set, &ls_props[7] );
if( resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
newres->type = resr_collection;
} else {
newres->type = resr_normal;
}
if (modtime) {
newres->modtime = oc_httpdate_parse(modtime);
}
/* DEBUG_WEBDAV("Parsing Modtime: %s -> %llu", modtime, (unsigned long long) newres->modtime ); */
newres->size = 0;
if (clength) {
newres->size = atoll(clength);
/* DEBUG_WEBDAV("Parsed File size for %s from %s: %lld", newres->name, clength, (long long)newres->size ); */
}
if( etag ) {
newres->md5 = csync_normalize_etag(etag);
}
csync_vio_set_file_id(newres->file_id, file_id);
/*
DEBUG_WEBDAV("propfind_results_recursive %s [%s] %s", newres->uri, newres->type == resr_collection ? "collection" : "file", newres->md5);
*/
if (directDownloadUrl) {
newres->directDownloadUrl = c_strdup(directDownloadUrl);
}
if (directDownloadCookies) {
newres->directDownloadCookies = c_strdup(directDownloadCookies);
}
/* DEBUG_WEBDAV("fill_webdav_properties_into_resource %s >%p< ", newres->name, perm ); */
if (perm && !perm[0]) {
// special meaning for our code: server returned permissions but are empty
// meaning only reading is allowed for this resource
newres->remotePerm[0] = ' ';
// see _csync_detect_update()
} else if (perm && strlen(perm) < sizeof(newres->remotePerm)) {
strncpy(newres->remotePerm, perm, sizeof(newres->remotePerm));
} else {
// old server, keep newres->remotePerm empty
}
}
struct resource* resource_dup(struct resource* o) {
struct resource *r = c_malloc (sizeof( struct resource ));
ZERO_STRUCTP(r);
r->uri = c_strdup(o->uri);
r->name = c_strdup(o->name);
r->type = o->type;
r->size = o->size;
r->modtime = o->modtime;
if( o->md5 ) {
r->md5 = c_strdup(o->md5);
}
if (o->directDownloadUrl) {
r->directDownloadUrl = c_strdup(o->directDownloadUrl);
}
if (o->directDownloadCookies) {
r->directDownloadCookies = c_strdup(o->directDownloadCookies);
}
if (o->remotePerm) {
strncpy(r->remotePerm, o->remotePerm, sizeof(r->remotePerm));
}
r->next = o->next;
csync_vio_set_file_id(r->file_id, o->file_id);
return r;
}
void resource_free(struct resource* o) {
struct resource* old = NULL;
while (o)
{
old = o;
o = o->next;
SAFE_FREE(old->uri);
SAFE_FREE(old->name);
SAFE_FREE(old->md5);
SAFE_FREE(old->directDownloadUrl);
SAFE_FREE(old->directDownloadCookies);
SAFE_FREE(old);
}
}
void free_fetchCtx( struct listdir_context *ctx )
{
struct resource *newres, *res;
if( ! ctx ) return;
newres = ctx->list;
res = newres;
ctx->ref--;
if (ctx->ref > 0) return;
SAFE_FREE(ctx->target);
while( res ) {
SAFE_FREE(res->uri);
SAFE_FREE(res->name);
SAFE_FREE(res->md5);
memset( res->file_id, 0, FILE_ID_BUF_SIZE+1 );
SAFE_FREE(res->directDownloadUrl);
SAFE_FREE(res->directDownloadCookies);
newres = res->next;
SAFE_FREE(res);
res = newres;
}
SAFE_FREE(ctx);
}
// as per http://sourceforge.net/p/predef/wiki/OperatingSystems/
// extend as required
const char* csync_owncloud_get_platform() {
#if defined (_WIN32)
return "Windows";
#elif defined(__APPLE__)
return "Macintosh";
#elif defined(__gnu_linux__)
return "Linux";
#elif defined(__DragonFly__)
/* might also define __FreeBSD__ */
return "DragonFlyBSD";
#elif defined(__FreeBSD__)
return "FreeBSD";
#elif defined(__NetBSD__)
return "NetBSD";
#elif defined(__OpenBSD__)
return "OpenBSD";
#elif defined(sun) || defined(__sun)
return "Solaris";
#else
return "Unknown OS";
#endif
}
+13 -27
Ver Arquivo
@@ -61,18 +61,6 @@
*/
#define MAX_DEPTH 50
/**
* Maximum time difference between two replicas in seconds
*/
#define MAX_TIME_DIFFERENCE 10
/**
* Maximum size of a buffer for transfer
*/
#ifndef MAX_XFER_BUF_SIZE
#define MAX_XFER_BUF_SIZE (16 * 1024)
#endif
#define CSYNC_STATUS_INIT 1 << 0
#define CSYNC_STATUS_UPDATE 1 << 1
#define CSYNC_STATUS_RECONCILE 1 << 2
@@ -90,6 +78,8 @@ enum csync_replica_e {
typedef struct csync_file_stat_s csync_file_stat_t;
struct csync_owncloud_ctx_s; // csync_owncloud.c
/**
* @brief csync public structure
*/
@@ -104,7 +94,6 @@ struct csync_s {
char *file;
sqlite3 *db;
int exists;
int disabled;
sqlite3_stmt* by_hash_stmt;
sqlite3_stmt* by_fileid_stmt;
@@ -126,22 +115,15 @@ struct csync_s {
enum csync_replica_e type;
int read_from_db;
c_list_t *ignored_cleanup;
const char *root_perms; /* Permission of the root folder. (Since the root folder is not in the db tree, we need to keep a separate entry.) */
} remote;
struct {
int sync_symbolic_links;
char *config_dir;
bool local_only_mode;
int timeout;
#if defined(HAVE_ICONV) && defined(WITH_ICONV)
iconv_t iconv_cd;
#endif
} options;
#if defined(HAVE_ICONV) && defined(WITH_ICONV)
struct {
uid_t uid;
uid_t euid;
} pwd;
iconv_t iconv_cd;
} options;
#endif
/* replica we are currently walking */
enum csync_replica_e current;
@@ -162,6 +144,8 @@ struct csync_s {
volatile int abort;
void *rename_info;
int read_from_db_disabled;
struct csync_owncloud_ctx_s *owncloud_context;
};
@@ -174,8 +158,6 @@ struct csync_file_stat_s {
int64_t size; /* u64 */
size_t pathlen; /* u64 */
uint64_t inode; /* u64 */
uid_t uid; /* u32 */
gid_t gid; /* u32 */
mode_t mode; /* u32 */
int nlink; /* u32 */
int type; /* u32 */
@@ -185,6 +167,10 @@ struct csync_file_stat_s {
char *destpath; /* for renames */
const char *etag;
char file_id[FILE_ID_BUF_SIZE+1]; /* the ownCloud file id is fixed width of 21 byte. */
char *directDownloadUrl;
char *directDownloadCookies;
char remotePerm[REMOTE_PERM_BUF_SIZE+1];
CSYNC_STATUS error_status;
enum csync_instructions_e instruction; /* u32 */
+2
Ver Arquivo
@@ -184,6 +184,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
csync_vio_set_file_id( other->file_id, cur->file_id );
}
other->inode = cur->inode;
other->should_update_etag = true;
cur->instruction = CSYNC_INSTRUCTION_NONE;
} else if (other->instruction == CSYNC_INSTRUCTION_REMOVE) {
other->instruction = CSYNC_INSTRUCTION_RENAME;
@@ -193,6 +194,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
csync_vio_set_file_id( other->file_id, cur->file_id );
}
other->inode = cur->inode;
other->should_update_etag = true;
cur->instruction = CSYNC_INSTRUCTION_NONE;
} else if (other->instruction == CSYNC_INSTRUCTION_NEW) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "OOOO=> NEW detected in other tree!");
+7 -26
Ver Arquivo
@@ -58,28 +58,6 @@ int csync_get_statedb_exists(CSYNC *ctx) {
return ctx->statedb.exists;
}
/* Set the hide attribute in win32. That makes it invisible in normal explorers */
static void _csync_win32_hide_file( const char *file ) {
#ifdef _WIN32
mbchar_t *fileName;
DWORD dwAttrs;
if( !file ) return;
fileName = c_utf8_to_locale( file );
dwAttrs = GetFileAttributesW(fileName);
if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
if (!(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
SetFileAttributesW(fileName, dwAttrs | FILE_ATTRIBUTE_HIDDEN );
}
}
c_free_locale_string(fileName);
#else
(void) file;
#endif
}
static int _csync_check_db_integrity(sqlite3 *db) {
c_strlist_t *result = NULL;
int rc = -1;
@@ -168,7 +146,7 @@ static int _csync_statedb_check(const char *statedb) {
rc = sqlite3_open(statedb, &db);
if (rc == SQLITE_OK) {
sqlite3_close(db);
_csync_win32_hide_file(statedb);
csync_win32_set_file_hidden(statedb, true);
return 1;
}
sqlite3_close(db);
@@ -322,8 +300,6 @@ static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3
name = (const char*) sqlite3_column_text(stmt, 2);
memcpy((*st)->path, (len ? name : ""), len + 1);
(*st)->inode = sqlite3_column_int64(stmt,3);
(*st)->uid = sqlite3_column_int(stmt, 4);
(*st)->gid = sqlite3_column_int(stmt, 5);
(*st)->mode = sqlite3_column_int(stmt, 6);
(*st)->modtime = strtoul((char*)sqlite3_column_text(stmt, 7), NULL, 10);
@@ -337,6 +313,11 @@ static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3
if(column_count > 10 && sqlite3_column_text(stmt,10)) {
csync_vio_set_file_id((*st)->file_id, (char*) sqlite3_column_text(stmt, 10));
}
if(column_count > 11 && sqlite3_column_text(stmt,11)) {
strncpy((*st)->remotePerm,
(char*) sqlite3_column_text(stmt, 11),
REMOTE_PERM_BUF_SIZE);
}
}
}
return rc;
@@ -476,7 +457,7 @@ char *csync_statedb_get_etag( CSYNC *ctx, uint64_t jHash ) {
return ret;
}
#define BELOW_PATH_QUERY "SELECT phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid FROM metadata WHERE path LIKE(?)"
#define BELOW_PATH_QUERY "SELECT phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm FROM metadata WHERE path LIKE(?)"
int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
int rc;
+41 -15
Ver Arquivo
@@ -140,6 +140,14 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
len = strlen(path);
/* This code should probably be in csync_exclude, but it does not have the fs parameter.
Keep it here for now and TODO also find out if we want this for Windows
https://github.com/owncloud/mirall/issues/2086 */
if (fs->flags & CSYNC_VIO_FILE_FLAGS_HIDDEN) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file excluded because it is a hidden file: %s", path);
return 0;
}
/* Check if file is excluded */
excluded = csync_excluded(ctx, path,type);
@@ -254,20 +262,22 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
st->instruction = CSYNC_INSTRUCTION_EVAL;
goto out;
}
bool metadata_differ = (ctx->current == REMOTE_REPLICA && (!c_streq(fs->file_id, tmp->file_id)
|| !c_streq(fs->remotePerm, tmp->remotePerm)))
|| (ctx->current == LOCAL_REPLICA && fs->inode != tmp->inode);
if (type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA
&& c_streq(fs->file_id, tmp->file_id) && !ctx->read_from_db_disabled) {
&& !metadata_differ && !ctx->read_from_db_disabled) {
/* If both etag and file id are equal for a directory, read all contents from
* the database.
* The comparison of file id ensure that we fetch all the file id when upgrading from
* owncloud 5 to owncloud 6.
* The metadata comparison ensure that we fetch all the file id or permission when
* upgrading owncloud
*/
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Reading from database: %s", path);
ctx->remote.read_from_db = true;
}
if (!c_streq(fs->file_id, tmp->file_id) && ctx->current == REMOTE_REPLICA) {
/* file id has changed. Which means we need to update the DB.
* (upgrade from owncloud 5 to owncloud 6 for instence) */
if (metadata_differ) {
/* file id or permissions has changed. Which means we need to update them in the DB. */
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Need to update metadata for: %s", path);
st->should_update_etag = true;
}
st->instruction = CSYNC_INSTRUCTION_NONE;
@@ -364,8 +374,6 @@ out:
st->mode = fs->mode;
st->size = fs->size;
st->modtime = fs->mtime;
st->uid = fs->uid;
st->gid = fs->gid;
st->nlink = fs->nlink;
st->type = type;
st->etag = NULL;
@@ -374,6 +382,17 @@ out:
st->etag = c_strdup(fs->etag);
}
csync_vio_set_file_id(st->file_id, fs->file_id);
if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL) {
SAFE_FREE(st->directDownloadUrl);
st->directDownloadUrl = c_strdup(fs->directDownloadUrl);
}
if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES) {
SAFE_FREE(st->directDownloadCookies);
st->directDownloadCookies = c_strdup(fs->directDownloadCookies);
}
if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_PERM) {
strncpy(st->remotePerm, fs->remotePerm, REMOTE_PERM_BUF_SIZE);
}
fastout: /* target if the file information is read from database into st */
st->phash = h;
@@ -589,9 +608,14 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
continue;
}
/* == see if really stat has to be called. */
fs = csync_vio_file_stat_new();
res = csync_vio_stat(ctx, filename, fs);
/* Only for the local replica we have to stat(), for the remote one we have all data already */
if (ctx->replica == LOCAL_REPLICA) {
fs = csync_vio_file_stat_new();
res = csync_vio_stat(ctx, filename, fs);
} else {
fs = dirent;
res = 0;
}
if( res == 0) {
switch (fs->type) {
@@ -646,7 +670,10 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
previous_fs->child_modified = ctx->current_fs->child_modified;
}
csync_vio_file_stat_destroy(fs);
/* Only for the local replica we have to destroy stat(), for the remote one it is a pointer to dirent */
if (ctx->replica == LOCAL_REPLICA) {
csync_vio_file_stat_destroy(fs);
}
if (rc < 0) {
if (CSYNC_STATUS_IS_OK(ctx->status_code)) {
@@ -674,8 +701,7 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
if (flag == CSYNC_FTW_FLAG_DIR && ctx->current_fs
&& (ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL ||
ctx->current_fs->instruction == CSYNC_INSTRUCTION_NEW ||
ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL_RENAME)) {
ctx->current_fs->instruction == CSYNC_INSTRUCTION_NEW)) {
ctx->current_fs->should_update_etag = true;
}
-53
Ver Arquivo
@@ -128,59 +128,6 @@ void csync_win32_set_file_hidden( const char *file, bool h ) {
#endif
}
csync_vio_file_stat_t *csync_vio_convert_file_stat(csync_file_stat_t *st) {
csync_vio_file_stat_t *vfs = NULL;
if (st == NULL) {
return NULL;
}
vfs = csync_vio_file_stat_new();
if (vfs == NULL) {
return NULL;
}
vfs->acl = NULL;
if (st->pathlen > 0) {
vfs->name = c_strdup(st->path);
}
vfs->uid = st->uid;
vfs->gid = st->gid;
vfs->atime = 0;
vfs->mtime = st->modtime;
vfs->ctime = 0;
vfs->size = st->size;
vfs->blksize = 0; /* Depricated. */
vfs->blkcount = 0;
vfs->mode = st->mode;
vfs->device = 0;
vfs->inode = st->inode;
vfs->nlink = st->nlink;
/* fields. */
vfs->fields = CSYNC_VIO_FILE_STAT_FIELDS_TYPE
+ CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS
+ CSYNC_VIO_FILE_STAT_FIELDS_INODE
+ CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT
+ CSYNC_VIO_FILE_STAT_FIELDS_SIZE
+ CSYNC_VIO_FILE_STAT_FIELDS_MTIME
+ CSYNC_VIO_FILE_STAT_FIELDS_UID
+ CSYNC_VIO_FILE_STAT_FIELDS_GID;
if (st->type == CSYNC_FTW_TYPE_DIR)
vfs->type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
else if (st->type == CSYNC_FTW_TYPE_FILE)
vfs->type = CSYNC_VIO_FILE_TYPE_REGULAR;
else if (st->type == CSYNC_FTW_TYPE_SLINK)
vfs->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
else
vfs->type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
return vfs;
}
bool (*csync_file_locked_or_open_ext) (const char*) = 0; // filled in by library user
void set_csync_file_locked_or_open_ext(bool (*f) (const char*));
void set_csync_file_locked_or_open_ext(bool (*f) (const char*)) {
-3
Ver Arquivo
@@ -32,8 +32,5 @@ void csync_memstat_check(void);
void csync_win32_set_file_hidden( const char *file, bool hidden );
/* Convert a csync_file_stat_t to csync_vio_file_stat_t */
csync_vio_file_stat_t *csync_vio_convert_file_stat(csync_file_stat_t *st);
bool csync_file_locked_or_open( const char *dir, const char *fname);
#endif /* _CSYNC_UTIL_H */
-2
Ver Arquivo
@@ -20,8 +20,6 @@ set(CSTDLIB_LINK_LIBRARIES
set(cstdlib_SRCS
c_alloc.c
c_dir.c
c_file.c
c_list.c
c_path.c
c_rbtree.c
-189
Ver Arquivo
@@ -1,189 +0,0 @@
/*
* cynapses libc functions
*
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "c_private.h"
#include "c_macro.h"
#include "c_alloc.h"
#include "c_dir.h"
#include "c_string.h"
int c_mkdirs(const char *path, mode_t mode) {
int tmp;
csync_stat_t sb;
mbchar_t *wpath = c_utf8_to_locale(path);
mbchar_t *swpath = NULL;
if (path == NULL) {
errno = EINVAL;
return -1;
}
if (_tstat(wpath, &sb) == 0) {
if (! S_ISDIR(sb.st_mode)) {
errno = ENOTDIR;
c_free_locale_string(wpath);
return -1;
}
}
tmp = strlen(path);
while(tmp > 0 && path[tmp - 1] == '/') --tmp;
while(tmp > 0 && path[tmp - 1] != '/') --tmp;
while(tmp > 0 && path[tmp - 1] == '/') --tmp;
if (tmp > 0) {
char subpath[tmp + 1];
memcpy(subpath, path, tmp);
subpath[tmp] = '\0';
swpath = c_utf8_to_locale(subpath);
if (_tstat(swpath, &sb) == 0) {
if (! S_ISDIR(sb.st_mode)) {
c_free_locale_string(swpath);
c_free_locale_string(wpath);
errno = ENOTDIR;
return -1;
}
} else if (errno != ENOENT) {
c_free_locale_string(wpath);
c_free_locale_string(swpath);
return -1;
} else if (c_mkdirs(subpath, mode) < 0) {
c_free_locale_string(swpath);
c_free_locale_string(wpath);
return -1;
}
}
tmp = _tmkdir(wpath, mode);
c_free_locale_string(swpath);
c_free_locale_string(wpath);
if ((tmp < 0) && (errno == EEXIST)) {
return 0;
}
return tmp;
}
int c_rmdirs(const char *path) {
_TDIR *d;
struct _tdirent *dp;
csync_stat_t sb;
char *fname = NULL;
mbchar_t *wfname = NULL;
mbchar_t *wpath = c_utf8_to_locale(path);
char *rd_name = NULL;
if ((d = _topendir(wpath)) != NULL) {
while( _tstat(wpath, &sb) == 0) {
/* if we can remove the directory we're done */
if (_trmdir(wpath) == 0) {
break;
}
switch (errno) {
case ENOTEMPTY:
case EEXIST:
case EBADF:
break; /* continue */
default:
_tclosedir(d);
c_free_locale_string(wpath);
return 0;
}
while ((dp = _treaddir(d)) != NULL) {
size_t len;
rd_name = c_utf8_from_locale(dp->d_name);
/* skip '.' and '..' */
if( c_streq( rd_name, "." ) || c_streq( rd_name, ".." ) ) {
c_free_locale_string(rd_name);
continue;
}
len = strlen(path) + strlen(rd_name) + 2;
fname = c_malloc(len);
if (fname == NULL) {
_tclosedir(d);
c_free_locale_string(rd_name);
c_free_locale_string(wpath);
return -1;
}
snprintf(fname, len, "%s/%s", path, rd_name);
wfname = c_utf8_to_locale(fname);
/* stat the file */
if (_tstat(wfname, &sb) != -1) {
#ifdef __unix__
if (S_ISDIR(sb.st_mode) && !S_ISLNK(sb.st_mode)) {
#else
if (S_ISDIR(sb.st_mode)) {
#endif
if (_trmdir(wfname) < 0) { /* can't be deleted */
if (errno == EACCES) {
_tclosedir(d);
SAFE_FREE(fname);
c_free_locale_string(wfname);
c_free_locale_string(rd_name);
c_free_locale_string(wpath);
return -1;
}
c_rmdirs(fname);
}
} else {
_tunlink(wfname);
}
} /* lstat */
SAFE_FREE(fname);
c_free_locale_string(wfname);
c_free_locale_string(rd_name);
} /* readdir */
_trewinddir(d);
}
} else {
c_free_locale_string(wpath);
return -1;
}
c_free_locale_string(wpath);
_tclosedir(d);
return 0;
}
int c_isdir(const char *path) {
csync_stat_t sb;
mbchar_t *wpath = c_utf8_to_locale(path);
int re = 0;
if (path != NULL) {
if (_tstat (wpath, &sb) == 0 && S_ISDIR(sb.st_mode)) {
re = 1;
}
}
c_free_locale_string(wpath);
return re;
}
-86
Ver Arquivo
@@ -1,86 +0,0 @@
/*
* cynapses libc functions
*
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file c_dir.h
*
* @brief Interface of the cynapses libc directory function
*
* @defgroup cynDirInternals cynapses libc directory functions
* @ingroup cynLibraryAPI
*
* @{
*/
#ifndef _C_DIR_H
#define _C_DIR_H
#include <sys/types.h>
/**
* @brief Create parent directories as needed.
*
* The newly created directory will be owned by the effective user ID of the
* process.
*
* @param path The path to the directory to create.
*
* @param mode Specifies the permissions to use. It is modified
* by the process's umask in the usual way: the
* permissions of the created file are (mode & ~umask).
*
* @return 0 on success, < 0 on error with errno set:
* - EACCES The parent directory does not allow write
* permission to the process, or one of the directories
* - ENOTDIR if durl is not a directory
* - EINVAL NULL durl passed or smbc_init not called.
* - ENOMEM Insufficient memory was available.
*
* @see mkdir()
*/
int c_mkdirs(const char *path, mode_t mode);
/**
* @brief Remove the directory and subdirectories including the content.
*
* This removes all directories and files recursivly.
*
* @param dir The directory to remove recusively.
*
* @return 0 on success, < 0 on error with errno set.
*/
int c_rmdirs(const char *dir);
/**
* @brief Check if a path is a directory.
*
* @param path The path to check.
*
* @return 1 if the path is a directory, 0 if the path doesn't exist, is a
* file or can't be accessed.
*/
int c_isdir(const char *path);
/**
* }@
*/
#endif /* _CDIR_H */
-346
Ver Arquivo
@@ -1,346 +0,0 @@
/*
* cynapses libc functions
*
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef _WIN32
#include <windef.h>
#include <winbase.h>
#endif
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include "c_file.h"
#include "c_string.h"
#include "c_private.h"
#ifdef _WIN32
/* check if path is a symlink */
int c_islink(const char *path) {
int re = 0;
mbchar_t *wpath = 0;
DWORD dwAttrs;
WIN32_FIND_DATAW FindFileData;
HANDLE hFind;
wpath = c_utf8_to_locale(path);
dwAttrs = GetFileAttributesW(wpath);
if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
if ((dwAttrs & FILE_ATTRIBUTE_REPARSE_POINT)) {
hFind = FindFirstFileW(wpath, &FindFileData );
if (hFind != INVALID_HANDLE_VALUE) {
if( (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
(FindFileData.dwReserved0 & IO_REPARSE_TAG_SYMLINK) ) {
re = 1;
}
}
FindClose(hFind);
}
}
c_free_locale_string(wpath);
return re;
}
#endif
/* check if path is a file */
int c_isfile(const char *path) {
csync_stat_t sb;
mbchar_t *wpath = c_utf8_to_locale(path);
int re = _tstat(wpath, &sb);
c_free_locale_string(wpath);
if (re< 0) {
return 0;
}
#ifdef __unix__
if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) {
#else
if (S_ISREG(sb.st_mode)) {
#endif
return 1;
}
return 0;
}
/* copy file from src to dst, overwrites dst */
#ifdef _WIN32
int c_copy(const char* src, const char *dst, mode_t mode) {
int rc = -1;
mbchar_t *wsrc = 0;
mbchar_t *wdst = 0;
(void) mode; /* unused on win32 */
if(src && dst) {
wsrc = c_utf8_to_locale(src);
wdst = c_utf8_to_locale(dst);
if (CopyFileW(wsrc, wdst, FALSE)) {
rc = 0;
}
c_free_locale_string(wsrc);
c_free_locale_string(wdst);
if( rc < 0 ) {
errno = GetLastError();
}
}
return rc;
}
#else
int c_copy(const char* src, const char *dst, mode_t mode) {
int srcfd = -1;
int dstfd = -1;
int rc = -1;
ssize_t bread, bwritten;
csync_stat_t sb;
char buf[4096];
if (c_streq(src, dst)) {
return -1;
}
srcfd = open(src, O_RDONLY, 0);
if (srcfd < 0) {
goto out;
}
rc = _tfstat(srcfd, &sb);
if (rc < 0) {
goto out;
}
if (S_ISDIR(sb.st_mode)) {
errno = EISDIR;
rc = -1;
goto out;
}
if (mode == 0) {
mode = sb.st_mode;
}
dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
if (dstfd < 0) {
rc = -1;
goto out;
}
rc = _tfstat(dstfd, &sb);
if (rc == 0) {
if (S_ISDIR(sb.st_mode)) {
errno = EISDIR;
rc = -1;
goto out;
}
}
for (;;) {
bread = read(srcfd, buf, sizeof(buf));
if (bread == 0) {
/* done */
break;
} else if (bread < 0) {
errno = ENODATA;
rc = -1;
goto out;
}
bwritten = write(dstfd, buf, bread);
if (bwritten < 0) {
errno = ENODATA;
rc = -1;
goto out;
}
if (bread != bwritten) {
errno = EFAULT;
rc = -1;
goto out;
}
}
#ifdef __unix__
fsync(dstfd);
#endif
rc = 0;
out:
if (srcfd >= 0) {
close(srcfd);
}
if (dstfd >= 0) {
close(dstfd);
}
if (rc < 0 && c_isfile(dst)) {
unlink(dst);
}
return rc;
}
#endif
int c_rename( const char *src, const char *dst ) {
mbchar_t *nuri = NULL;
mbchar_t *ouri = NULL;
int rc = 0;
nuri = c_utf8_to_locale(dst);
if (nuri == NULL) {
return -1;
}
ouri = c_utf8_to_locale(src);
if (ouri == NULL) {
c_free_locale_string(nuri);
return -1;
}
#ifdef _WIN32
{
#define MAX_TRIES_RENAME 3
int err = 0;
int cnt = 0;
do {
BOOL ok;
ok = MoveFileExW(ouri,
nuri,
MOVEFILE_COPY_ALLOWED +
MOVEFILE_REPLACE_EXISTING +
MOVEFILE_WRITE_THROUGH);
if (!ok) {
/* error */
err = GetLastError();
if( (err == ERROR_ACCESS_DENIED ||
err == ERROR_LOCK_VIOLATION ||
err == ERROR_SHARING_VIOLATION) && cnt < MAX_TRIES_RENAME ) {
cnt++;
Sleep(cnt*100);
continue;
}
}
break;
} while( 1 );
if( err != 0 ) {
errno = err;
rc = -1;
}
}
#else
rc = rename(ouri, nuri);
#endif
c_free_locale_string(nuri);
c_free_locale_string(ouri);
return rc;
}
int c_compare_file( const char *f1, const char *f2 ) {
mbchar_t *wf1, *wf2;
int fd1 = -1, fd2 = -1;
size_t size1, size2;
char buffer1[BUFFER_SIZE];
char buffer2[BUFFER_SIZE];
csync_stat_t stat1;
csync_stat_t stat2;
int rc = -1;
if(f1 == NULL || f2 == NULL) return -1;
wf1 = c_utf8_to_locale(f1);
if(wf1 == NULL) {
return -1;
}
wf2 = c_utf8_to_locale(f2);
if(wf2 == NULL) {
c_free_locale_string(wf1);
return -1;
}
#ifdef _WIN32
_fmode = _O_BINARY;
#endif
fd1 = _topen(wf1, O_RDONLY);
if(fd1 < 0) {
rc = -1;
goto out;
}
fd2 = _topen(wf2, O_RDONLY);
if(fd2 < 0) {
rc = -1;
goto out;
}
/* compare size first. */
rc = _tfstat(fd1, &stat1);
if (rc < 0) {
goto out;
}
rc = _tfstat(fd2, &stat2);
if (rc < 0) {
goto out;
}
/* if sizes are different, the files can not be equal. */
if (stat1.st_size != stat2.st_size) {
rc = 0;
goto out;
}
while( (size1 = read(fd1, buffer1, BUFFER_SIZE)) > 0 ) {
size2 = read( fd2, buffer2, BUFFER_SIZE );
if( size1 != size2 ) {
rc = 0;
goto out;
}
if(memcmp(buffer1, buffer2, size1) != 0) {
/* buffers are different */
rc = 0;
goto out;
}
}
rc = 1;
out:
if(fd1 > -1) close(fd1);
if(fd2 > -1) close(fd2);
c_free_locale_string( wf1 );
c_free_locale_string( wf2 );
return rc;
}
-102
Ver Arquivo
@@ -1,102 +0,0 @@
/*
* cynapses libc functions
*
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file c_file.h
*
* @brief Interface of the cynapses libc file function
*
* @defgroup cynFileInternals cynapses libc file functions
* @ingroup cynLibraryAPI
*
* @{
*/
#ifndef _C_FILE_H
#define _C_FILE_H
#include <sys/types.h>
#include <stdio.h>
#ifndef BUFFER_SIZE
#define BUFFER_SIZE (16 * 1024)
#endif
#ifdef _WIN32
/**
* @brief Check if a path is a link.
*
* @param path The path to check.
*
* @return 1 if the path is a symbolic link, 0 if the path doesn't
* exist or is something else.
*/
int c_islink(const char *path);
#endif
/**
* @brief Check if a path is a regular file or a link.
*
* @param path The path to check.
*
* @return 1 if the path is a file, 0 if the path doesn't exist, is
* something else or can't be accessed.
*/
int c_isfile(const char *path);
/**
* @brief copy a file from source to destination.
*
* @param src Path to the source file
* @param dst Path to the destination file
* @param mode File creation mode of the destination. If mode is 0 then the
* mode from the source will be used.
*
* @return 0 on success, less than 0 on error with errno set.
* EISDIR if src or dst is a file.
*/
int c_copy(const char *src, const char *dst, mode_t mode);
/**
* @brief Compare the content of two files byte by byte.
* @param f1 Path of file 1
* @param f2 Path of file 2
*
* @return 0 if the files differ, 1 if the files are equal or -1 on
* error with errno set.
*/
int c_compare_file( const char *f1, const char *f2 );
/**
* @brief move a file from source to destination.
*
* @param src Path to the source file
* @param dst Path to the destination file
*
* @return 0 on success, less than 0 on error with errno set.
*/
int c_rename( const char *src, const char *dst );
/**
* }@
*/
#endif /* _C_FILE_H */
-36
Ver Arquivo
@@ -23,45 +23,9 @@
#include "c_macro.h"
#include "c_alloc.h"
#include "c_dir.h"
#include "c_file.h"
#include "c_list.h"
#include "c_path.h"
#include "c_rbtree.h"
#include "c_string.h"
#include "c_time.h"
#include "c_private.h"
#ifndef UNIT_TESTING
#ifdef malloc
#undef malloc
#endif
#define malloc(x) DO_NOT_CALL_MALLOC__USE_C_MALLOC_INSTEAD
#ifdef calloc
#undef calloc
#endif
#define calloc(x,y) DO_NOT_CALL_CALLOC__USE_C_CALLOC_INSTEAD
#endif
#ifdef realloc
#undef realloc
#endif
#define realloc(x,y) DO_NOT_CALL_REALLOC__USE_C_REALLOC_INSTEAD
#ifdef dirname
#undef dirname
#endif
#define dirname(x) DO_NOT_CALL_MALLOC__USE_C_DIRNAME_INSTEAD
#ifdef basename
#undef basename
#endif
#define basename(x) DO_NOT_CALL_MALLOC__USE_C_BASENAME_INSTEAD
#ifdef strdup
#undef strdup
#endif
#define strdup(x) DO_NOT_CALL_STRDUP__USE_C_STRDUP_INSTEAD
-156
Ver Arquivo
@@ -117,81 +117,6 @@ char *c_basename (const char *path) {
return newbuf;
}
char *c_tmpname(const char *templ) {
char *tmp = NULL;
char *target = NULL;
int rc;
int i = 0;
if (!templ) {
goto err;
}
/* If the template does not contain the XXXXXX it will be appended. */
if( !strstr( templ, "XXXXXX" )) {
/* split up the path */
char *path = c_dirname(templ);
char *base = c_basename(templ);
if (!base) {
if (path) {
SAFE_FREE(path);
}
goto err;
}
/* Create real hidden files for unixoide. */
if( path ) {
#ifdef _WIN32
rc = asprintf(&target, "%s/%s.~XXXXXX", path, base);
#else
rc = asprintf(&target, "%s/.%s.~XXXXXX", path, base);
#endif
} else {
#ifdef _WIN32
rc = asprintf(&target, "%s.~XXXXXX", base);
#else
rc = asprintf(&target, ".%s.~XXXXXX", base);
#endif
}
SAFE_FREE(path);
SAFE_FREE(base);
if (rc < 0) {
goto err;
}
} else {
target = c_strdup(templ);
}
if (!target) {
goto err;
}
tmp = strstr( target, "XXXXXX" );
if (!tmp) {
goto err;
}
for (i = 0; i < 6; ++i) {
#ifdef _WIN32
/* in win32 MAX_RAND is 32767, thus we can not shift that far,
* otherwise the last three chars are 0
*/
int hexdigit = (rand() >> (i * 2)) & 0x1f;
#else
int hexdigit = (rand() >> (i * 5)) & 0x1f;
#endif
tmp[i] = hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
}
return target;
err:
errno = EINVAL;
return NULL;
}
int c_parse_uri(const char *uri,
char **scheme,
char **user, char **passwd,
@@ -470,84 +395,3 @@ int c_parse_uri(const char *uri,
return -1;
}
/*
* http://refactormycode.com/codes/1345-extracting-directory-filename-and-extension-from-a-path
* Allocate a block of memory that holds the PATHINFO at the beginning
* followed by the actual path. Two extra bytes are allocated (+3 instead
* of just +1) to deal with shifting the filename and extension to protect the trailing '/'
* and the leading '.'. These extra bytes also double as the empty string, as
* well as a pad to keep from reading past the memory block.
*
*/
C_PATHINFO * c_split_path(const char* pathSrc)
{
size_t length = strlen(pathSrc);
size_t len=0;
C_PATHINFO * pathinfo = (C_PATHINFO *) c_malloc(sizeof(C_PATHINFO) + length + 3);
if (pathinfo)
{
char * path = (char *) &pathinfo[1]; // copy of the path
char * theEnd = &path[length + 1]; // second null terminator
char * extension;
char * lastSep;
// Copy the original string and double null terminate it.
strcpy(path, pathSrc);
*theEnd = '\0';
pathinfo->directory = theEnd; // Assume no path
pathinfo->extension = theEnd; // Assume no extension
pathinfo->filename = path; // Assume filename only
lastSep = strrchr(path, '/');
if (lastSep)
{
pathinfo->directory = path; // Pick up the path
memmove(lastSep + 1, lastSep, strlen(lastSep));
*lastSep++ ='/';
*lastSep++ ='\0'; // Truncate directory
pathinfo->filename = lastSep; // Pick up name after path
}
// Start at the second character of the filename to handle
// filenames that start with '.' like ".login".
// We don't overrun the buffer in the cases of an empty path
// or a path that looks like "/usr/bin/" because of the extra
// byte.
extension = strrchr(&pathinfo->filename[1], '.');
if (extension)
{
// Shift the extension over to protect the leading '.' since
// we need to truncate the filename.
memmove(extension + 1, extension, strlen(extension));
pathinfo->extension = extension + 1;
*extension = '\0'; // Truncate filename
}
else
{
len=strlen(pathinfo->filename);
if(len>1)
{
//tmp files from kate/kwrite "somefile~": '~' should be the extension
if(pathinfo->filename[len-1]=='~')
{
extension = &pathinfo->filename[len-1];
memmove(extension + 1, extension, strlen(extension));
pathinfo->extension = extension + 1;
*extension = '\0'; // Truncate filename
}
}
}
}
return pathinfo;
}
-22
Ver Arquivo
@@ -66,19 +66,6 @@ char *c_dirname(const char *path);
*/
char *c_basename (const char *path);
/**
* @brief Make a temporary filename.
*
* @param templ The template to replace. If the template contains six X like
* 'XXXXXX', these are replaced by a random string. If not, the
* templ is interpreted as a path, and a name to a hidden file
* with six random is returned.
* The caller has to free the memory.
*
* @return a poitner to the random hidden filename or NULL.
*/
char *c_tmpname(const char *templ);
/**
* @brief parse a uri and split it into components.
*
@@ -120,15 +107,6 @@ typedef struct
char * extension;
} C_PATHINFO;
/**
* @brief Extracting directory, filename and extension from a path.
*
* @param pathSrc The path to parse.
*
* @return Returns a C_PATHINFO structure that should be freed using SAFE_FREE().
*/
C_PATHINFO * c_split_path(const char* pathSrc);
/**
* }@
-63
Ver Arquivo
@@ -239,69 +239,6 @@ void c_strlist_destroy(c_strlist_t *strlist) {
SAFE_FREE(strlist);
}
char *c_strreplace(char *src, const char *pattern, const char *repl) {
char *p = NULL;
while ((p = strstr(src, pattern)) != NULL) {
size_t of = p - src;
size_t l = strlen(src);
size_t pl = strlen(pattern);
size_t rl = strlen(repl);
if (rl > pl) {
src = (char *) c_realloc(src, strlen(src) + rl - pl + 1);
}
if (rl != pl) {
memmove(src + of + rl, src + of + pl, l - of - pl + 1);
}
strncpy(src + of, repl, rl);
}
return src;
}
char *c_uppercase(const char* str) {
char *new;
char *p;
if (str == NULL) {
return NULL;
}
new = c_strdup(str);
if (new == NULL) {
return NULL;
}
for (p = new; *p; p++) {
*p = toupper(*p);
}
return new;
}
char *c_lowercase(const char* str) {
char *new;
char *p;
if (str == NULL) {
return NULL;
}
new = c_strdup(str);
if (new == NULL) {
return NULL;
}
for (p = new; *p; p++) {
*p = tolower(*p);
}
return new;
}
/* Convert a wide multibyte String to UTF8 */
char* c_utf8_from_locale(const mbchar_t *wstr)
{
-31
Ver Arquivo
@@ -119,37 +119,6 @@ void c_strlist_clear(c_strlist_t *strlist);
*/
void c_strlist_destroy(c_strlist_t *strlist);
/**
* @breif Replace a string with another string in a source string.
*
* @param src String to search for pattern.
*
* @param pattern Pattern to search for in the source string.
*
* @param repl The string which which should replace pattern if found.
*
* @return Return a pointer to the source string.
*/
char *c_strreplace(char *src, const char *pattern, const char *repl);
/**
* @brief Uppercase a string.
*
* @param str The String to uppercase.
*
* @return The malloced uppered string or NULL on error.
*/
char *c_uppercase(const char* str);
/**
* @brief Lowercase a string.
*
* @param str The String to lowercase.
*
* @return The malloced lowered string or NULL on error.
*/
char *c_lowercase(const char* str);
/**
* @brief Convert a platform locale string to utf8.
*
+7 -17
Ver Arquivo
@@ -24,6 +24,7 @@
#include <errno.h>
#include <stdio.h>
#include <assert.h>
#include "csync_private.h"
#include "csync_util.h"
@@ -44,7 +45,7 @@ csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name) {
if(ctx->remote.read_from_db) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Read from db flag is true, should not!" );
}
return owncloud_opendir(name);
return owncloud_opendir(ctx, name);
break;
case LOCAL_REPLICA:
return csync_vio_local_opendir(name);
@@ -69,7 +70,7 @@ int csync_vio_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
if( ctx->remote.read_from_db ) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote ReadFromDb is true, should not!");
}
rc = owncloud_closedir(dhandle);
rc = owncloud_closedir(ctx, dhandle);
break;
case LOCAL_REPLICA:
rc = csync_vio_local_closedir(dhandle);
@@ -87,7 +88,7 @@ csync_vio_file_stat_t *csync_vio_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle
if( ctx->remote.read_from_db ) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote readfromdb is true, should not!");
}
return owncloud_readdir(dhandle);
return owncloud_readdir(ctx, dhandle);
break;
case LOCAL_REPLICA:
return csync_vio_local_readdir(dhandle);
@@ -106,7 +107,8 @@ int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) {
switch(ctx->replica) {
case REMOTE_REPLICA:
rc = owncloud_stat(uri, buf);
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "ERROR: Cannot call remote stat, not implemented");
assert(ctx->replica != REMOTE_REPLICA);
break;
case LOCAL_REPLICA:
rc = csync_vio_local_stat(uri, buf);
@@ -121,21 +123,9 @@ int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) {
return rc;
}
char *csync_vio_get_status_string(CSYNC *ctx) {
if(ctx->error_string) {
return ctx->error_string;
}
return owncloud_error_string();
}
int csync_vio_set_property(CSYNC* ctx, const char* key, void* data) {
(void) ctx;
return owncloud_set_property(key, data);
}
int csync_vio_commit(CSYNC *ctx) {
(void) ctx;
return owncloud_commit();
return owncloud_error_string(ctx);
}
-3
Ver Arquivo
@@ -39,10 +39,7 @@ csync_vio_file_stat_t *csync_vio_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle
int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf);
int csync_vio_set_property(CSYNC *ctx, const char *key, void *data);
char *csync_vio_get_status_string(CSYNC *ctx);
int csync_vio_commit(CSYNC *ctx);
#endif /* _CSYNC_VIO_H */
+4 -14
Ver Arquivo
@@ -22,14 +22,8 @@
#include "vio/csync_vio_file_stat.h"
csync_vio_file_stat_t *csync_vio_file_stat_new(void) {
csync_vio_file_stat_t *file_stat = NULL;
file_stat = (csync_vio_file_stat_t *) c_malloc(sizeof(csync_vio_file_stat_t));
if (file_stat == NULL) {
return NULL;
}
file_stat->etag = NULL;
memset(file_stat->file_id, 0, FILE_ID_BUF_SIZE+1);
csync_vio_file_stat_t *file_stat = (csync_vio_file_stat_t *) c_malloc(sizeof(csync_vio_file_stat_t));
ZERO_STRUCTP(file_stat);
return file_stat;
}
@@ -39,15 +33,11 @@ void csync_vio_file_stat_destroy(csync_vio_file_stat_t *file_stat) {
return;
}
if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_SYMLINK_NAME) {
SAFE_FREE(file_stat->u.symlink_name);
}
if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_CHECKSUM) {
SAFE_FREE(file_stat->u.checksum);
}
if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) {
SAFE_FREE(file_stat->etag);
}
SAFE_FREE(file_stat->directDownloadUrl);
SAFE_FREE(file_stat->directDownloadCookies);
SAFE_FREE(file_stat->name);
SAFE_FREE(file_stat);
}
+21 -26
Ver Arquivo
@@ -34,12 +34,15 @@
#define FILE_ID_BUF_SIZE 21
// currently specified at https://github.com/owncloud/core/issues/8322 are 9 to 10
#define REMOTE_PERM_BUF_SIZE 15
typedef struct csync_vio_file_stat_s csync_vio_file_stat_t;
enum csync_vio_file_flags_e {
CSYNC_VIO_FILE_FLAGS_NONE = 0,
CSYNC_VIO_FILE_FLAGS_SYMLINK = 1 << 0,
CSYNC_VIO_FILE_FLAGS_LOCAL = 1 << 1
CSYNC_VIO_FILE_FLAGS_HIDDEN = 1 << 1
};
enum csync_vio_file_type_e {
@@ -56,48 +59,44 @@ enum csync_vio_file_type_e {
enum csync_vio_file_stat_fields_e {
CSYNC_VIO_FILE_STAT_FIELDS_NONE = 0,
CSYNC_VIO_FILE_STAT_FIELDS_TYPE = 1 << 0,
CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS = 1 << 1,
CSYNC_VIO_FILE_STAT_FIELDS_MODE = 1 << 1, // local POSIX mode
CSYNC_VIO_FILE_STAT_FIELDS_FLAGS = 1 << 2,
CSYNC_VIO_FILE_STAT_FIELDS_DEVICE = 1 << 3,
CSYNC_VIO_FILE_STAT_FIELDS_INODE = 1 << 4,
CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT = 1 << 5,
CSYNC_VIO_FILE_STAT_FIELDS_SIZE = 1 << 6,
CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_COUNT = 1 << 7, /* will be removed */
CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_SIZE = 1 << 8, /* will be removed */
// CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_COUNT = 1 << 7, /* will be removed */
// CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_SIZE = 1 << 8, /* will be removed */
CSYNC_VIO_FILE_STAT_FIELDS_ATIME = 1 << 9,
CSYNC_VIO_FILE_STAT_FIELDS_MTIME = 1 << 10,
CSYNC_VIO_FILE_STAT_FIELDS_CTIME = 1 << 11,
CSYNC_VIO_FILE_STAT_FIELDS_SYMLINK_NAME = 1 << 12,
CSYNC_VIO_FILE_STAT_FIELDS_CHECKSUM = 1 << 13,
CSYNC_VIO_FILE_STAT_FIELDS_ACL = 1 << 14,
CSYNC_VIO_FILE_STAT_FIELDS_UID = 1 << 15,
CSYNC_VIO_FILE_STAT_FIELDS_GID = 1 << 16,
// CSYNC_VIO_FILE_STAT_FIELDS_SYMLINK_NAME = 1 << 12,
// CSYNC_VIO_FILE_STAT_FIELDS_CHECKSUM = 1 << 13,
// CSYNC_VIO_FILE_STAT_FIELDS_ACL = 1 << 14,
// CSYNC_VIO_FILE_STAT_FIELDS_UID = 1 << 15,
// CSYNC_VIO_FILE_STAT_FIELDS_GID = 1 << 16,
CSYNC_VIO_FILE_STAT_FIELDS_ETAG = 1 << 17,
CSYNC_VIO_FILE_STAT_FIELDS_FILE_ID = 1 << 18
CSYNC_VIO_FILE_STAT_FIELDS_FILE_ID = 1 << 18,
CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL = 1 << 19,
CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES = 1 << 20,
CSYNC_VIO_FILE_STAT_FIELDS_PERM = 1 << 21 // remote oC perm
};
struct csync_vio_file_stat_s {
union {
char *symlink_name;
char *checksum;
} u;
void *acl;
char *name;
char *etag;
char *etag; // FIXME: Should this be inlined like file_id and perm?
char file_id[FILE_ID_BUF_SIZE+1];
uid_t uid;
gid_t gid;
char *directDownloadUrl;
char *directDownloadCookies;
char remotePerm[REMOTE_PERM_BUF_SIZE+1];
time_t atime;
time_t mtime;
time_t ctime;
int64_t size;
int64_t blksize; /* will be removed in future, not used in csync */
unsigned long blkcount; /* will be removed in future, not used in csync */
mode_t mode;
@@ -109,10 +108,6 @@ struct csync_vio_file_stat_s {
enum csync_vio_file_type_e type;
enum csync_vio_file_flags_e flags;
void *reserved1;
void *reserved2;
void *reserved3;
};
csync_vio_file_stat_t *csync_vio_file_stat_new(void);
+8 -16
Ver Arquivo
@@ -224,12 +224,10 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
buf->type = CSYNC_VIO_FILE_TYPE_REGULAR;
break;
} while (0);
/* TODO Do we want to parse for CSYNC_VIO_FILE_FLAGS_HIDDEN ? */
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
buf->mode = 666;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
buf->device = fileInfo.dwVolumeSerialNumber;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DEVICE;
@@ -240,7 +238,7 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
/* printf("Index: %I64i\n", FileIndex.QuadPart); */
buf->inode = FileIndex.QuadPart;
buf->size = (fileInfo.nFileSizeHigh * (int64_t)(MAXDWORD+1)) + fileInfo.nFileSizeLow;
buf->size = (fileInfo.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + fileInfo.nFileSizeLow;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
/* Get the file time with a win32 call rather than through stat. See
@@ -316,7 +314,7 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
buf->mode = sb.st_mode;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MODE;
if (buf->type == CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK) {
/* FIXME: handle symlink */
@@ -324,6 +322,11 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
} else {
buf->flags = CSYNC_VIO_FILE_FLAGS_NONE;
}
#ifdef __APPLE__
if (sb.st_flags & UF_HIDDEN) {
buf->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
}
#endif
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS;
buf->device = sb.st_dev;
@@ -332,11 +335,6 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
buf->inode = sb.st_ino;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE;
/* Both values are only initialized to zero as they are not used in csync */
/* They are deprecated and will be rmemoved later. */
buf->blksize = 0;
buf->blkcount = 0;
buf->atime = sb.st_atime;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME;
@@ -349,12 +347,6 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
buf->nlink = sb.st_nlink;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT;
buf->uid = sb.st_uid;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_UID;
buf->gid = sb.st_gid;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_GID;
buf->size = sb.st_size;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
-2
Ver Arquivo
@@ -21,8 +21,6 @@ set(TEST_TARGET_LIBRARIES ${TORTURE_LIBRARY})
# std
add_cmocka_test(check_std_c_alloc std_tests/check_std_c_alloc.c ${TEST_TARGET_LIBRARIES})
add_cmocka_test(check_std_c_dir std_tests/check_std_c_dir.c ${TEST_TARGET_LIBRARIES})
add_cmocka_test(check_std_c_file std_tests/check_std_c_file.c ${TEST_TARGET_LIBRARIES})
add_cmocka_test(check_std_c_jhash std_tests/check_std_c_jhash.c ${TEST_TARGET_LIBRARIES})
add_cmocka_test(check_std_c_list std_tests/check_std_c_list.c ${TEST_TARGET_LIBRARIES})
add_cmocka_test(check_std_c_path std_tests/check_std_c_path.c ${TEST_TARGET_LIBRARIES})
@@ -36,9 +36,6 @@ static void setup(void **state) {
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync");
assert_int_equal(rc, 0);
*state = csync;
}
@@ -55,9 +52,6 @@ static void setup_module(void **state) {
rc = csync_create(&csync, "/tmp/check_csync1", "dummy://foo/bar");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync");
assert_int_equal(rc, 0);
rc = csync_init(csync);
*state = csync;
}
@@ -38,7 +38,6 @@ static void check_csync_destroy_null(void **state)
static void check_csync_create(void **state)
{
CSYNC *csync;
char confdir[1024] = {0};
int rc;
(void) state; /* unused */
@@ -46,9 +45,6 @@ static void check_csync_create(void **state)
rc = csync_create(&csync, "/tmp/csync1", "/tmp/csync2");
assert_int_equal(rc, 0);
snprintf(confdir, sizeof(confdir), "%s/%s", getenv("HOME"), CSYNC_CONF_DIR);
assert_string_equal(csync->options.config_dir, confdir);
rc = csync_destroy(csync);
assert_int_equal(rc, 0);
}
@@ -32,10 +32,6 @@ static void setup(void **state) {
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
free(csync->options.config_dir);
csync->options.config_dir = c_strdup("/tmp/check_csync1/");
assert_non_null(csync->options.config_dir);
*state = csync;
}
@@ -46,10 +42,6 @@ static void setup_init(void **state) {
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
free(csync->options.config_dir);
csync->options.config_dir = c_strdup("/tmp/check_csync1/");
assert_non_null(csync->options.config_dir);
rc = csync_exclude_load(csync, SOURCEDIR "/../sync-exclude.lst");
assert_int_equal(rc, 0);
-6
Ver Arquivo
@@ -36,9 +36,6 @@ static void setup(void **state) {
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync");
assert_int_equal(rc, 0);
*state = csync;
}
@@ -55,9 +52,6 @@ static void setup_module(void **state) {
rc = csync_create(&csync, "/tmp/check_csync1", "dummy://foo/bar");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync");
assert_int_equal(rc, 0);
*state = csync;
}
-3
Ver Arquivo
@@ -40,9 +40,6 @@ static void setup(void **state) {
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync");
assert_int_equal(rc, 0);
*state = csync;
}
@@ -40,8 +40,6 @@ static void setup(void **state) {
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
csync_set_config_dir(csync, "/tmp/check_csync1/");
csync->statedb.file = c_strdup( TESTDB );
*state = csync;
}
@@ -44,8 +44,6 @@ static void setup(void **state)
assert_int_equal(rc, 0);
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync/");
assert_int_equal(rc, 0);
rc = csync_init(csync);
assert_int_equal(rc, 0);
-17
Ver Arquivo
@@ -36,8 +36,6 @@ static void setup(void **state)
assert_int_equal(rc, 0);
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync");
assert_int_equal(rc, 0);
rc = csync_init(csync);
assert_int_equal(rc, 0);
rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
@@ -60,8 +58,6 @@ static void setup_ftw(void **state)
assert_int_equal(rc, 0);
rc = csync_create(&csync, "/tmp", "/tmp");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync");
assert_int_equal(rc, 0);
rc = csync_init(csync);
assert_int_equal(rc, 0);
rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
@@ -124,8 +120,6 @@ static csync_vio_file_stat_t* create_fstat(const char *name,
fs->type = CSYNC_VIO_FILE_TYPE_REGULAR;
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
fs->mode = 0644;
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS;
if (inode == 0) {
fs->inode = 619070;
@@ -146,17 +140,6 @@ static csync_vio_file_stat_t* create_fstat(const char *name,
}
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT;
fs->uid = 1000;
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_UID;
fs->gid = 1000;
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_GID;
fs->blkcount = 312;
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_COUNT;
fs->blksize = 4096;
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_SIZE;
if (mtime == 0) {
fs->atime = fs->ctime = fs->mtime = time(&t);
+2 -4
Ver Arquivo
@@ -34,7 +34,6 @@ use LWP::UserAgent;
use LWP::Protocol::https;
use HTTP::Request::Common qw( POST GET DELETE );
use File::Basename;
use POSIX qw/strftime/;
use Encode qw(from_to);
use utf8;
@@ -129,9 +128,8 @@ sub initTesting(;$)
# $d->DebugLevel(3);
$prefix = "t1" unless( defined $prefix );
my $dirId = sprintf("%02d", rand(100));
my $dateTime = strftime('%Y%m%d%H%M%S',localtime);
my $dir = sprintf( "%s-%s-%s/", $prefix, $dateTime, $dirId );
my $dirId = sprintf("%#.3o", rand(1000));
my $dir = sprintf( "%s-%s/", $prefix, $dirId );
$localDir = $dir;
$localDir .= "/" unless( $localDir =~ /\/$/ );
+11
Ver Arquivo
@@ -46,6 +46,7 @@ glob_put( 'toremote1/rtl1/rtl11/*', "remoteToLocal1/rtl1/rtl11/" );
glob_put( 'toremote1/rtl2/*', "remoteToLocal1/rtl2/" );
glob_put( 'toremote1/rtl4/*', "remoteToLocal1/rtl4/" );
# call csync, sync local t1 to remote t1
csync();
@@ -74,9 +75,19 @@ foreach my $file ( <./tolocal1/*> ) {
print "Copying $file to $locDir\n";
copy( $file, $locDir );
}
# Also add a file with symbols
my $symbolName = "a\%b#c\$d-e";
system( "echo \"my symbols\" >> $locDir/$symbolName" );
#Also on the server
put_to_dir( "$locDir/$symbolName", 'remoteToLocal1' );
csync( );
print "\nAssert local and remote dirs.\n";
assertLocalAndRemoteDir( '', 0);
assert( ! -e localDir().$symbolName );
# move a local file
printInfo( "Move a file locally." );
+23 -1
Ver Arquivo
@@ -185,12 +185,34 @@ assertLocalAndRemoteDir( 'remoteToLocal1', 1);
printInfo("Move a file from the server");
$inode = getInode('remoteToLocal1/rtl2/kb1_local_gone.jpg');
moveRemoteFile( 'remoteToLocal1/rtl2/kb1_local_gone.jpg', 'remoteToLocal1/rtl2/kb1_local_gone2.jpg');
#also create a new directory localy for the next test
mkdir( localDir().'superNewDir' );
createLocalFile(localDir(). 'superNewDir/f1', 1234 );
createLocalFile(localDir(). 'superNewDir/f2', 1324 );
my $superNewDirInode = getInode('superNewDir');
csync();
assertLocalAndRemoteDir( 'remoteToLocal1', 1);
assertLocalAndRemoteDir( '', 1);
$inode2 = getInode('remoteToLocal1/rtl2/kb1_local_gone2.jpg');
assert( $inode == $inode2, "Inode has changed 3!");
printInfo("Move a newly created directory");
moveRemoteFile('superNewDir', 'superNewDirRenamed');
#also add new files in new directory
createLocalFile(localDir(). 'superNewDir/f3' , 2456 );
$inode = getInode('superNewDir/f3');
csync();
assertLocalAndRemoteDir( '', 1);
assert( ! -e localDir().'superNewDir' );
$inode2 = getInode('superNewDir/f3');
assert( $inode == $inode2, "Inode of f3 changed");
$inode2 = getInode('superNewDir');
assert( $superNewDirInode == $inode2, "Inode of superNewDir changed");
cleanup();
+10
Ver Arquivo
@@ -67,6 +67,13 @@ system( "rm -rf " . localDir() . 'remoteToLocal1' );
system( "echo \"my file\" >> /tmp/myfile.txt" );
put_to_dir( '/tmp/myfile.txt', 'remoteToLocal1/rtl1/rtl11' );
# Also add a file with symbols
my $symbolName = "a\%b#c\$d-e";
system( "echo \"my symbols\" >> /tmp/$symbolName" );
put_to_dir( "/tmp/$symbolName", 'remoteToLocal1/rtl1/rtl11' );
my $fileid = remoteFileId( 'remoteToLocal1/rtl1/', 'rtl11' );
my $fid2 = remoteFileId( 'remoteToLocal1/rtl1/', 'La ced' );
assert($fid2 eq "" or $fileid ne $fid2, "File IDs are equal" );
@@ -90,6 +97,9 @@ printInfo("Move file and create another one with the same name.");
move( localDir() . 'newdir/myfile.txt', localDir() . 'newdir/oldfile.txt' );
system( "echo \"super new\" >> " . localDir() . 'newdir/myfile.txt' );
#Move a file with symbols as well
move( localDir() . "newdir/$symbolName", localDir() . "newdir/$symbolName.new" );
#Add some files for the next test.
system( "echo \"un\" > " . localDir() . '1.txt' );
system( "echo \"deux\" > " . localDir() . '2.txt' );
-1
Ver Arquivo
@@ -30,7 +30,6 @@ use ownCloud::Test;
use strict;
print "Hello, this is t5, a tester for syncing of files in Shares\n";
# stat error occours on windsows when the file is busy for example
initTesting();
Arquivo executável
+256
Ver Arquivo
@@ -0,0 +1,256 @@
#!/usr/bin/perl
#
# Test script for the ownCloud module of csync.
# This script requires a running ownCloud instance accessible via HTTP.
# It does quite some fancy tests and asserts the results.
#
# Copyright (C) by Klaas Freitag <freitag@owncloud.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
use lib ".";
use Carp::Assert;
use File::Copy;
use ownCloud::Test;
use strict;
print "Hello, this is t7, a tester for syncing of files in read only directory\n";
# Check if the expected rows in the DB are non-empty. Note that in some cases they might be, then we cannot use this function
# https://github.com/owncloud/mirall/issues/2038
sub assertCsyncJournalOk {
my $path = $_[0];
# FIXME: should test also remoteperm but it's not working with owncloud6
# my $cmd = 'sqlite3 ' . $path . '.csync_journal.db "SELECT count(*) from metadata where length(remotePerm) == 0 or length(fileId) == 0"';
my $cmd = 'sqlite3 ' . $path . '.csync_journal.db "SELECT count(*) from metadata where length(fileId) == 0"';
my $result = `$cmd`;
assert($result == "0");
}
# IMPORTANT NOTE :
print "This test use the OWNCLOUD_TEST_PERMISSIONS environement variable and _PERM_xxx_ on filenames to set the permission. ";
print "It does not rely on real permission set on the server. This test is just for testing the propagation choices\n";
# "It would be nice" to have a test that test with real permissions on the server
$ENV{OWNCLOUD_TEST_PERMISSIONS} = "1";
initTesting();
printInfo( "Init" );
#create some files localy
my $tmpdir = "/tmp/t7/";
mkdir($tmpdir);
createLocalFile( $tmpdir . "normalFile_PERM_WVND_.data", 100 );
createLocalFile( $tmpdir . "cannotBeRemoved_PERM_WVN_.data", 101 );
createLocalFile( $tmpdir . "canBeRemoved_PERM_D_.data", 102 );
my $md5CanotBeModified = createLocalFile( $tmpdir . "canotBeModified_PERM_DVN_.data", 103 );
createLocalFile( $tmpdir . "canBeModified_PERM_W_.data", 104 );
#put them in some directories
createRemoteDir( "normalDirectory_PERM_CKDNV_" );
glob_put( "$tmpdir/*", "normalDirectory_PERM_CKDNV_" );
createRemoteDir( "readonlyDirectory_PERM_M_" );
glob_put( "$tmpdir/*", "readonlyDirectory_PERM_M_" );
createRemoteDir( "readonlyDirectory_PERM_M_/subdir_PERM_CK_" );
createRemoteDir( "readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_" );
glob_put( "$tmpdir/normalFile_PERM_WVND_.data", "readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_" );
csync();
assertCsyncJournalOk(localDir());
assertLocalAndRemoteDir( '', 0);
system("sleep 1"); #make sure changes have different mtime
printInfo( "Do some changes and see how they propagate" );
#1. remove the file than cannot be removed
# (they should be recovered)
unlink( localDir() . 'normalDirectory_PERM_CKDNV_/cannotBeRemoved_PERM_WVN_.data' );
unlink( localDir() . 'readonlyDirectory_PERM_M_/cannotBeRemoved_PERM_WVN_.data' );
#2. remove the file that can be removed
# (they should properly be gone)
unlink( localDir() . 'normalDirectory_PERM_CKDNV_/canBeRemoved_PERM_D_.data' );
unlink( localDir() . 'readonlyDirectory_PERM_M_/canBeRemoved_PERM_D_.data' );
#3. Edit the files that cannot be modified
# (they should be recovered, and a conflict shall be created)
system("echo 'modified' > ". localDir() . "normalDirectory_PERM_CKDNV_/canotBeModified_PERM_DVN_.data");
system("echo 'modified_' > ". localDir() . "readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN_.data");
#4. Edit other files
# (they should be uploaded)
system("echo '__modified' > ". localDir() . "normalDirectory_PERM_CKDNV_/canBeModified_PERM_W_.data");
system("echo '__modified_' > ". localDir() . "readonlyDirectory_PERM_M_/canBeModified_PERM_W_.data");
#5. Create a new file in a read only folder
# (they should not be uploaded)
createLocalFile( localDir() . "readonlyDirectory_PERM_M_/newFile_PERM_WDNV_.data", 105 );
#6. Create a new file in a read only folder
# (should be uploaded)
createLocalFile( localDir() . "normalDirectory_PERM_CKDNV_/newFile_PERM_WDNV_.data", 106 );
#do the sync
csync();
assertCsyncJournalOk(localDir());
#1.
# File should be recovered
assert( -e localDir(). 'normalDirectory_PERM_CKDNV_/cannotBeRemoved_PERM_WVN_.data' );
assert( -e localDir(). 'readonlyDirectory_PERM_M_/cannotBeRemoved_PERM_WVN_.data' );
#2.
# File should be deleted
assert( !-e localDir() . 'normalDirectory_PERM_CKDNV_/canBeRemoved_PERM_D_.data' );
assert( !-e localDir() . 'readonlyDirectory_PERM_M_/canBeRemoved_PERM_D_.data' );
#3.
# File should be recovered
assert($md5CanotBeModified eq md5OfFile( localDir().'normalDirectory_PERM_CKDNV_/canotBeModified_PERM_DVN_.data' ));
assert($md5CanotBeModified eq md5OfFile( localDir().'readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN_.data' ));
# and conflict created
# TODO check that the conflict file has the right content
assert( -e glob(localDir().'normalDirectory_PERM_CKDNV_/canotBeModified_PERM_DVN__conflict-*.data' ) );
assert( -e glob(localDir().'readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN__conflict-*.data' ) );
# remove the conflicts for the next assertLocalAndRemoteDir
system("rm " . localDir().'normalDirectory_PERM_CKDNV_/canotBeModified_PERM_DVN__conflict-*.data' );
system("rm " . localDir().'readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN__conflict-*.data' );
#4. File should be updated, that's tested by assertLocalAndRemoteDir
#5.
# The file should not exist on the remote
# TODO: test that the file is NOT on the server
# but still be there
assert( -e localDir() . "readonlyDirectory_PERM_M_/newFile_PERM_WDNV_.data" );
# remove it so assertLocalAndRemoteDir succeed.
unlink(localDir() . "readonlyDirectory_PERM_M_/newFile_PERM_WDNV_.data");
#6.
# the file should be in the server and local
assert( -e localDir() . "normalDirectory_PERM_CKDNV_/newFile_PERM_WDNV_.data" );
### Both side should still be the same
assertLocalAndRemoteDir( '', 0);
#######################################################################
printInfo( "remove the read only directory" );
# -> It must be recovered
system("rm -r " . localDir().'readonlyDirectory_PERM_M_' );
csync();
assertCsyncJournalOk(localDir());
assert( -e localDir(). 'readonlyDirectory_PERM_M_/cannotBeRemoved_PERM_WVN_.data' );
assert( -e localDir(). 'readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
assertLocalAndRemoteDir( '', 0);
#######################################################################
printInfo( "move a directory in a outside read only folder" );
system("sqlite3 " . localDir().'.csync_journal.db .dump');
#Missing directory should be restored
#new directory should be uploaded
system("mv " . localDir().'readonlyDirectory_PERM_M_/subdir_PERM_CK_ ' . localDir().'normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_' );
# two syncs may be necessary for now: https://github.com/owncloud/mirall/issues/2038
csync();
csync();
system("sqlite3 " . localDir().'.csync_journal.db .dump');
assertCsyncJournalOk(localDir());
# old name restored
assert( -e localDir(). 'readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/' );
assert( -e localDir(). 'readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
# new still exist
assert( -e localDir(). 'normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
assertLocalAndRemoteDir( '', 0);
#######################################################################
printInfo( "rename a directory in a read only folder and move a directory to a read-only" );
# do a sync to update the database
csync();
#1. rename a directory in a read only folder
#Missing directory should be restored
#new directory should stay but not be uploaded
system("mv " . localDir().'readonlyDirectory_PERM_M_/subdir_PERM_CK_ ' . localDir().'readonlyDirectory_PERM_M_/newname_PERM_CK_' );
#2. move a directory from read to read only (move the directory from previous step)
system("mv " . localDir().'normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_ ' . localDir().'readonlyDirectory_PERM_M_/moved_PERM_CK_' );
# two syncs may be necessary for now: https://github.com/owncloud/mirall/issues/2038
csync();
csync();
assertCsyncJournalOk(localDir());
#1.
# old name restored
assert( -e localDir(). 'readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
# new still exist
assert( -e localDir(). 'readonlyDirectory_PERM_M_/newname_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
# but is not on server: so remove for assertLocalAndRemoteDir
system("rm -r " . localDir(). "readonlyDirectory_PERM_M_/newname_PERM_CK_");
#2.
# old removed
assert( ! -e localDir(). 'normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_/' );
# new still there
assert( -e localDir(). 'readonlyDirectory_PERM_M_/moved_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data' );
#but not on server
system("rm -r " . localDir(). "readonlyDirectory_PERM_M_/moved_PERM_CK_");
assertLocalAndRemoteDir( '', 0);
system("sqlite3 " . localDir().'.csync_journal.db .dump');
cleanup();
-176
Ver Arquivo
@@ -1,176 +0,0 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "torture.h"
#include "std/c_private.h"
#include "std/c_dir.h"
#include "std/c_string.h"
const char *check_dir = "/tmp/check/c_mkdirs//with/check//";
const char *check_file = "/tmp/check/c_mkdirs/with/check/foobar.txt";
static void setup(void **state) {
int rc;
(void) state; /* unused */
rc = c_mkdirs(check_dir, 0755);
assert_int_equal(rc, 0);
rc = system("touch /tmp/check/c_mkdirs/with/check/foobar.txt");
assert_int_equal(rc, 0);
}
static void teardown(void **state) {
int rc;
(void) state; /* unused */
rc = c_rmdirs(check_dir);
assert_int_equal(rc, 0);
}
static int test_dir(const char *path, mode_t mode) {
csync_stat_t sb;
if (lstat(path, &sb) < 0) {
return -1;
}
if (! S_ISDIR(sb.st_mode)) {
return -1;
}
/* FIXME */
if ((sb.st_mode & mode) == mode) {
return 0;
}
return -1;
}
static void check_c_mkdirs_rmdirs(void **state)
{
csync_stat_t sb;
int rc;
mbchar_t *wcheck_dir;
(void) state; /* unused */
rc = c_mkdirs(check_dir, 0755);
assert_int_equal(rc, 0);
rc = test_dir(check_dir, 0755);
assert_int_equal(rc, 0);
rc = c_rmdirs(check_dir);
assert_int_equal(rc, 0);
wcheck_dir = c_utf8_to_locale(check_dir);
rc = _tstat(wcheck_dir, &sb);
c_free_locale_string(wcheck_dir);
assert_int_equal(rc, -1);
}
static void check_c_mkdirs_mode(void **state)
{
csync_stat_t sb;
int rc;
mbchar_t *wcheck_dir;
(void) state; /* unused */
rc = c_mkdirs(check_dir, 0700);
assert_int_equal(rc, 0);
rc = test_dir(check_dir, 0700);
assert_int_equal(rc, 0);
rc = c_rmdirs(check_dir);
assert_int_equal(rc, 0);
wcheck_dir = c_utf8_to_locale(check_dir);
rc = _tstat(wcheck_dir, &sb);
assert_int_equal(rc, -1);
c_free_locale_string(wcheck_dir);
}
static void check_c_mkdirs_existing_path(void **state)
{
int rc;
(void) state; /* unused */
rc = c_mkdirs(check_dir, 0755);
assert_int_equal(rc, 0);
}
static void check_c_mkdirs_file(void **state)
{
int rc;
(void) state; /* unused */
rc = c_mkdirs(check_file, 0755);
assert_int_equal(rc, -1);
assert_int_equal(errno, ENOTDIR);
}
static void check_c_mkdirs_null(void **state)
{
(void) state; /* unused */
assert_int_equal(c_mkdirs(NULL, 0755), -1);
}
static void check_c_isdir(void **state)
{
(void) state; /* unused */
assert_int_equal(c_isdir(check_dir), 1);
}
static void check_c_isdir_on_file(void **state)
{
(void) state; /* unused */
assert_int_equal(c_isdir(check_file), 0);
}
static void check_c_isdir_null(void **state)
{
(void) state; /* unused */
assert_int_equal(c_isdir(NULL), 0);
}
int torture_run_tests(void)
{
const UnitTest tests[] = {
unit_test(check_c_mkdirs_rmdirs),
unit_test(check_c_mkdirs_mode),
unit_test_setup_teardown(check_c_mkdirs_existing_path, setup, teardown),
unit_test_setup_teardown(check_c_mkdirs_file, setup, teardown),
unit_test(check_c_mkdirs_null),
unit_test_setup_teardown(check_c_isdir, setup, teardown),
unit_test_setup_teardown(check_c_isdir_on_file, setup, teardown),
unit_test(check_c_isdir_null),
};
return run_tests(tests);
}
-180
Ver Arquivo
@@ -1,180 +0,0 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "torture.h"
#include "std/c_private.h"
#include "std/c_file.h"
#include "std/c_string.h"
const char *check_dir = "/tmp/check";
const char *check_src_file = "/tmp/check/foo.txt";
const char *check_dst_file = "/tmp/check/bar.txt";
static int test_file(const char *path, mode_t mode) {
csync_stat_t sb;
mbchar_t *mbpath = c_utf8_to_locale(path);
int rc = _tstat(mbpath, &sb);
c_free_locale_string(mbpath);
if (rc < 0) {
return -1;
}
if (! S_ISREG(sb.st_mode)) {
return -1;
}
if ((sb.st_mode & mode) == mode) {
return 0;
}
return -1;
}
static void setup(void **state) {
int rc;
(void) state; /* unused */
rc = system("mkdir -p /tmp/check");
assert_int_equal(rc, 0);
rc = system("echo 42 > /tmp/check/foo.txt");
assert_int_equal(rc, 0);
}
static void teardown(void **state) {
int rc;
(void) state; /* unused */
rc = system("rm -rf /tmp/check");
assert_int_equal(rc, 0);
}
static void check_c_copy(void **state)
{
int rc;
(void) state; /* unused */
rc = c_copy(check_src_file, check_dst_file, 0644);
assert_int_equal(rc, 0);
rc = test_file(check_dst_file, 0644);
assert_int_equal(rc, 0);
}
static void check_c_copy_same_file(void **state)
{
int rc;
(void) state; /* unused */
rc = c_copy(check_src_file, check_src_file, 0644);
assert_int_equal(rc, -1);
}
static void check_c_copy_isdir(void **state)
{
int rc;
(void) state; /* unused */
rc = c_copy(check_src_file, check_dir, 0644);
assert_int_equal(rc, -1);
assert_int_equal(errno, EISDIR);
rc = c_copy(check_dir, check_dst_file, 0644);
assert_int_equal(rc, -1);
assert_int_equal(errno, ENOENT);
}
static void check_c_compare_file(void **state)
{
int rc;
(void) state;
rc = c_copy(check_src_file, check_dst_file, 0644);
assert_int_equal(rc, 0);
rc = c_compare_file( check_src_file, check_dst_file );
assert_int_equal(rc, 1);
/* Check error conditions */
rc = c_compare_file( NULL, check_dst_file );
assert_int_equal(rc, -1);
rc = c_compare_file( check_dst_file, NULL );
assert_int_equal(rc, -1);
rc = c_compare_file( NULL, NULL );
assert_int_equal(rc, -1);
rc = c_compare_file( check_src_file, "/I_do_not_exist_in_the_filesystem.dummy");
assert_int_equal(rc, -1);
rc = c_compare_file( "/I_do_not_exist_in_the_filesystem.dummy", check_dst_file);
assert_int_equal(rc, -1);
rc = system("echo \"hallo42\" > /tmp/check/foo.txt");
assert_int_equal(rc, 0);
rc = system("echo \"hallo52\" > /tmp/check/bar.txt");
assert_int_equal(rc, 0);
rc = c_compare_file( check_src_file, check_dst_file );
assert_int_equal(rc, 0);
/* Create two 1MB random files */
rc = system("dd if=/dev/urandom of=/tmp/check/foo.txt bs=1024 count=1024");
assert_int_equal(rc, 0);
rc = system("dd if=/dev/urandom of=/tmp/check/bar.txt bs=1024 count=1024");
assert_int_equal(rc, 0);
rc = c_compare_file( check_src_file, check_dst_file );
assert_int_equal(rc, 0);
/* Create two 1MB random files with different size */
rc = system("dd if=/dev/urandom of=/tmp/check/foo.txt bs=1024 count=1024");
assert_int_equal(rc, 0);
rc = system("dd if=/dev/urandom of=/tmp/check/bar.txt bs=1024 count=1020");
assert_int_equal(rc, 0);
rc = c_compare_file( check_src_file, check_dst_file );
assert_int_equal(rc, 0);
/* compare two big files which are equal */
rc = c_copy(check_src_file, check_dst_file, 0644);
assert_int_equal(rc, 0);
rc = c_compare_file( check_src_file, check_dst_file );
assert_int_equal(rc, 1);
}
int torture_run_tests(void)
{
const UnitTest tests[] = {
unit_test_setup_teardown(check_c_copy, setup, teardown),
unit_test(check_c_copy_same_file),
unit_test_setup_teardown(check_c_copy_isdir, setup, teardown),
unit_test_setup_teardown(check_c_compare_file, setup, teardown),
};
return run_tests(tests);
}
-27
Ver Arquivo
@@ -130,32 +130,6 @@ static void check_c_dirname_uri(void **state)
free(dname);
}
static void check_c_tmpname(void **state)
{
char tmpl[22]={0};
char prev[22]={0};
char *tmp;
int i = 0;
(void) state; /* unused */
srand((unsigned)time(NULL));
/* remember the last random value and compare the new one against.
* They may never be the same. */
for(i = 0; i < 100; i++){
strcpy(tmpl, "check_tmpname.XXXXXX");
tmp = c_tmpname(tmpl);
assert_non_null(tmp);
if (strlen(prev)) {
assert_string_not_equal(tmp, prev);
}
strcpy(prev, tmp);
SAFE_FREE(tmp);
}
}
static void check_c_parse_uri(void **state)
{
const char *test_scheme = "git+ssh";
@@ -204,7 +178,6 @@ int torture_run_tests(void)
unit_test(check_c_dirname),
unit_test(check_c_dirname_uri),
unit_test(check_c_parse_uri),
unit_test(check_c_tmpname),
};
return run_tests(tests);
-86
Ver Arquivo
@@ -113,85 +113,6 @@ static void check_c_strlist_expand(void **state)
c_strlist_destroy(strlist);
}
static void check_c_strreplace(void **state)
{
char *str = strdup("/home/%(USER)");
(void) state; /* unused */
str = c_strreplace(str, "%(USER)", "csync");
assert_string_equal(str, "/home/csync");
free(str);
}
static void check_c_lowercase(void **state)
{
char *str;
(void) state; /* unused */
str = c_lowercase("LoWeRcASE");
assert_string_equal(str, "lowercase");
free(str);
}
static void check_c_lowercase_empty(void **state)
{
char *str;
(void) state; /* unused */
str = c_lowercase("");
assert_string_equal(str, "");
free(str);
}
static void check_c_lowercase_null(void **state)
{
char *str;
(void) state; /* unused */
str = c_lowercase(NULL);
assert_null(str);
}
static void check_c_uppercase(void **state)
{
char *str;
(void) state; /* unused */
str = c_uppercase("upperCASE");
assert_string_equal(str, "UPPERCASE");
free(str);
}
static void check_c_uppercase_empty(void **state)
{
char *str;
(void) state; /* unused */
str = c_uppercase("");
assert_string_equal(str, "");
free(str);
}
static void check_c_uppercase_null(void **state)
{
char *str;
(void) state; /* unused */
str = c_uppercase(NULL);
assert_null(str);
}
int torture_run_tests(void)
@@ -203,13 +124,6 @@ int torture_run_tests(void)
unit_test(check_c_strlist_new),
unit_test(check_c_strlist_add),
unit_test(check_c_strlist_expand),
unit_test(check_c_strreplace),
unit_test(check_c_lowercase),
unit_test(check_c_lowercase_empty),
unit_test(check_c_lowercase_null),
unit_test(check_c_uppercase),
unit_test(check_c_uppercase_empty),
unit_test(check_c_uppercase_null),
};
return run_tests(tests);
+5 -4
Ver Arquivo
@@ -45,7 +45,6 @@ if (APPLE)
list(APPEND 3rdparty_SRC
3rdparty/qtmacgoodies/src/macpreferenceswindow.mm
3rdparty/qtmacgoodies/src/macstandardicon.mm
3rdparty/qtmacgoodies/src/macwindow.mm
)
endif()
@@ -83,11 +82,11 @@ set(libsync_SRCS
mirall/folderman.cpp
mirall/folder.cpp
mirall/folderwatcher.cpp
mirall/authenticationdialog.cpp
mirall/syncresult.cpp
mirall/mirallconfigfile.cpp
mirall/syncengine.cpp
mirall/owncloudpropagator.cpp
mirall/bandwidthmanager.cpp
mirall/propagatorjobs.cpp
mirall/propagator_qnam.cpp
mirall/propagator_legacy.cpp
@@ -107,7 +106,6 @@ set(libsync_SRCS
mirall/clientproxy.cpp
mirall/syncrunfilelog.cpp
mirall/cookiejar.cpp
mirall/accountmigrator.cpp
creds/dummycredentials.cpp
creds/abstractcredentials.cpp
creds/credentialsfactory.cpp
@@ -127,6 +125,7 @@ else()
creds/shibbolethcredentials.cpp
creds/shibboleth/shibbolethwebview.cpp
creds/shibboleth/shibbolethrefresher.cpp
creds/shibboleth/authenticationdialog.cpp
creds/shibboleth/shibbolethuserjob.cpp
)
endif()
@@ -248,7 +247,7 @@ else()
install(TARGETS ${synclib_NAME} DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/MacOS)
if (SPARKLE_FOUND)
install(DIRECTORY "${SPARKLE_LIBRARY}"
DESTINATION "${OWNCLOUD_OSX_BUNDLE}/Contents/Frameworks" USE_SOURCE_PERMISSIONS)
DESTINATION "${OWNCLOUD_OSX_BUNDLE}/Contents/Frameworks")
endif (SPARKLE_FOUND)
endif()
@@ -357,7 +356,9 @@ ENDIF()
include_directories(../csync/src ../csync/src/httpbf/src ${CMAKE_CURRENT_BINARY_DIR}/../csync ${CMAKE_CURRENT_BINARY_DIR}/../csync/src )
include_directories(${3rdparty_INC})
if(NOT TOKEN_AUTH_ONLY)
qt_add_translation(mirall_I18N ${TRANSLATIONS})
endif()
set( final_src
${mirall_HEADERS}
+3 -4
Ver Arquivo
@@ -48,8 +48,9 @@ int getauth(const char *prompt,
void *userdata)
{
int re = 0;
QMutex mutex;
// ### safe?
// ### safe? Not really. If the wizard is run in the main thread, the caccount could change during the sync.
// Ideally, http_credentials could be use userdata, but userdata is the SyncEngine.
HttpCredentials* http_credentials = qobject_cast<HttpCredentials*>(AccountManager::instance()->account()->credentials());
if (!http_credentials) {
@@ -63,10 +64,8 @@ int getauth(const char *prompt,
if( qPrompt == QLatin1String("Enter your username:") ) {
// qDebug() << "OOO Username requested!";
QMutexLocker locker( &mutex );
qstrncpy( buf, user.toUtf8().constData(), len );
} else if( qPrompt == QLatin1String("Enter your password:") ) {
QMutexLocker locker( &mutex );
// qDebug() << "OOO Password requested!";
qstrncpy( buf, pwd.toUtf8().constData(), len );
} else {
+21 -1
Ver Arquivo
@@ -20,6 +20,7 @@
#include <QDebug>
#include "creds/shibbolethcredentials.h"
#include "creds/shibboleth/authenticationdialog.h"
#include "creds/shibboleth/shibbolethwebview.h"
#include "creds/shibboleth/shibbolethrefresher.h"
#include "creds/shibbolethcredentials.h"
@@ -172,6 +173,8 @@ QNetworkAccessManager* ShibbolethCredentials::getQNAM() const
QNetworkAccessManager* qnam(new MirallAccessManager);
connect(qnam, SIGNAL(finished(QNetworkReply*)),
this, SLOT(slotReplyFinished(QNetworkReply*)));
connect(qnam, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
SLOT(slotHandleAuthentication(QNetworkReply*,QAuthenticator*)));
return qnam;
}
@@ -316,6 +319,23 @@ void ShibbolethCredentials::invalidateAndFetch(Account* account)
job->start();
}
void ShibbolethCredentials::slotHandleAuthentication(QNetworkReply *reply, QAuthenticator *authenticator)
{
Q_UNUSED(reply)
QUrl url = reply->url();
// show only scheme, host and port
QUrl reducedUrl;
reducedUrl.setScheme(url.scheme());
reducedUrl.setHost(url.host());
reducedUrl.setPort(url.port());
AuthenticationDialog dialog(authenticator->realm(), reducedUrl.toString());
if (dialog.exec() == QDialog::Accepted) {
authenticator->setUser(dialog.user());
authenticator->setPassword(dialog.password());
}
}
void ShibbolethCredentials::slotInvalidateAndFetchInvalidateDone(QKeychain::Job* job)
{
Account *account = qvariant_cast<Account*>(job->property("account"));
@@ -385,7 +405,7 @@ void ShibbolethCredentials::showLoginWindow(Account* account)
QList<QNetworkCookie> ShibbolethCredentials::accountCookies(Account *account)
{
return account->networkAccessManager()->cookieJar()->cookiesForUrl(account->davUrl());
return account->networkAccessManager()->cookieJar()->cookiesForUrl(account->url());
}
QNetworkCookie ShibbolethCredentials::findShibCookie(Account *account, QList<QNetworkCookie> cookies)
+1
Ver Arquivo
@@ -63,6 +63,7 @@ public:
public Q_SLOTS:
void invalidateAndFetch(Account *account);
void slotHandleAuthentication(QNetworkReply*,QAuthenticator*);
private Q_SLOTS:
void onShibbolethCookieReceived(const QNetworkCookie&, Account*);
+19 -22
Ver Arquivo
@@ -17,6 +17,7 @@
#include <QDebug>
#include <QNetworkReply>
#include <QSettings>
#include <QNetworkCookieJar>
#include "mirall/account.h"
#include "mirall/mirallaccessmanager.h"
@@ -79,11 +80,19 @@ public:
: MirallAccessManager(parent), _cred(cred) {}
protected:
QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData) {
QByteArray credHash = QByteArray(_cred->user().toUtf8()+":"+_cred->password().toUtf8()).toBase64();
if (_cred->user().isEmpty() || _cred->password().isEmpty() || _cred->_token.isEmpty()) {
qWarning() << Q_FUNC_INFO << "Empty user/password/token provided!";
}
QNetworkRequest req(request);
QByteArray credHash = QByteArray(_cred->user().toUtf8()+":"+_cred->password().toUtf8()).toBase64();
req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash);
//qDebug() << "Request for " << req.url() << "with authorization" << QByteArray::fromBase64(credHash);
req.setRawHeader(QByteArray("Cookie"), _cred->_token.toLocal8Bit());
// A pre-authenticated cookie
QByteArray token = _cred->_token.toUtf8();
setRawCookie(token, request.url());
return MirallAccessManager::createRequest(op, req, outgoingData);
}
private:
@@ -112,7 +121,7 @@ void TokenCredentials::syncContextPreInit (CSYNC* ctx)
void TokenCredentials::syncContextPreStart (CSYNC* ctx)
{
csync_set_module_property(ctx, "session_key", _token.toLocal8Bit().data());
csync_set_module_property(ctx, "session_key", _token.toUtf8().data());
}
bool TokenCredentials::changed(AbstractCredentials* credentials) const
@@ -156,12 +165,6 @@ bool TokenCredentials::ready() const
return _ready;
}
QString TokenCredentials::fetchUser(Account* account)
{
_user = account->credentialSetting(QLatin1String(userC)).toString();
return _user;
}
void TokenCredentials::fetch(Account *account)
{
if( !account ) {
@@ -169,10 +172,11 @@ void TokenCredentials::fetch(Account *account)
}
Q_EMIT fetched();
}
bool TokenCredentials::stillValid(QNetworkReply *reply)
{
return ((reply->error() != QNetworkReply::AuthenticationRequiredError)
// returned if user or password is incorrect
// returned if user/password or token are incorrect
&& (reply->error() != QNetworkReply::OperationCanceledError
|| !reply->property(authenticationFailedC).toBool()));
}
@@ -184,19 +188,12 @@ QString TokenCredentials::queryPassword(bool *ok)
void TokenCredentials::invalidateToken(Account *account)
{
_password = QString();
qDebug() << Q_FUNC_INFO;
_ready = false;
// User must be fetched from config file to generate a valid key
fetchUser(account);
const QString kck = keychainKey(account->url().toString(), _user);
if( kck.isEmpty() ) {
qDebug() << "InvalidateToken: User is empty, bailing out!";
return;
}
account->clearCookieJar();
_token = QString();
_user = QString();
_password = QString();
}
void TokenCredentials::persist(Account *account)
+1 -2
Ver Arquivo
@@ -53,7 +53,6 @@ public:
QString password() const;
QString queryPassword(bool *ok);
void invalidateToken(Account *account);
QString fetchUser(Account *account);
private Q_SLOTS:
void slotAuthentication(QNetworkReply*, QAuthenticator*);
@@ -61,7 +60,7 @@ private Q_SLOTS:
private:
QString _user;
QString _password;
QString _token;
QString _token; // the cookies
bool _ready;
};
+6 -67
Ver Arquivo
@@ -18,7 +18,6 @@
#include "mirall/mirallconfigfile.h"
#include "mirall/mirallaccessmanager.h"
#include "mirall/quotainfo.h"
#include "mirall/owncloudtheme.h"
#include "creds/abstractcredentials.h"
#include "creds/credentialsfactory.h"
@@ -28,8 +27,6 @@
#include <QNetworkAccessManager>
#include <QSslSocket>
#include <QNetworkCookieJar>
#include <QFileInfo>
#include <QDir>
#include <QDebug>
@@ -39,7 +36,6 @@ static const char urlC[] = "url";
static const char authTypeC[] = "authType";
static const char userC[] = "user";
static const char httpUserC[] = "http_user";
static const char caCertsKeyC[] = "CaCertificates";
AccountManager *AccountManager::_instance = 0;
@@ -75,7 +71,6 @@ Account::Account(AbstractSslErrorHandler *sslErrorHandler, QObject *parent)
, _treatSslErrorsAsFailure(false)
, _state(Account::Disconnected)
, _davPath("remote.php/webdav/")
, _wasMigrated(false)
{
qRegisterMetaType<Account*>("Account*");
}
@@ -103,66 +98,25 @@ void Account::save()
}
settings->sync();
// Save accepted certificates.
settings->beginGroup(QLatin1String("General"));
// ### TODO port away from MirallConfigFile
MirallConfigFile cfg;
qDebug() << "Saving " << approvedCerts().count() << " unknown certs.";
QByteArray certs;
Q_FOREACH( const QSslCertificate& cert, approvedCerts() ) {
certs += cert.toPem() + '\n';
}
if (!certs.isEmpty()) {
settings->setValue( QLatin1String(caCertsKeyC), certs );
cfg.setCaCerts( certs );
}
}
Account* Account::restore()
{
// try to open the correctly themed settings
QScopedPointer<QSettings> settings(settingsWithGroup(Theme::instance()->appName()));
Account *acc = 0;
bool migratedCreds = false;
// if the settings file could not be opened, the childKeys list is empty
if( settings->childKeys().isEmpty() ) {
// Now try to open the original ownCloud settings to see if they exist.
QString oCCfgFile = QDir::fromNativeSeparators( settings->fileName() );
// replace the last two segments with ownCloud/owncloud.cfg
oCCfgFile = oCCfgFile.left( oCCfgFile.lastIndexOf('/'));
oCCfgFile = oCCfgFile.left( oCCfgFile.lastIndexOf('/'));
oCCfgFile += QLatin1String("/ownCloud/owncloud.cfg");
qDebug() << "Migrate: checking old config " << oCCfgFile;
QFileInfo fi( oCCfgFile );
if( fi.isReadable() ) {
QSettings *oCSettings = new QSettings(oCCfgFile, QSettings::IniFormat);
oCSettings->beginGroup(QLatin1String("ownCloud"));
// Check the theme url to see if it is the same url that the oC config was for
QString overrideUrl = Theme::instance()->overrideServerUrl();
if( !overrideUrl.isEmpty() ) {
if (overrideUrl.endsWith('/')) { overrideUrl.chop(1); }
QString oCUrl = oCSettings->value(QLatin1String(urlC)).toString();
if (oCUrl.endsWith('/')) { oCUrl.chop(1); }
// in case the urls are equal reset the settings object to read from
// the ownCloud settings object
qDebug() << "Migrate oC config if " << oCUrl << " == " << overrideUrl << ":"
<< (oCUrl == overrideUrl ? "Yes" : "No");
if( oCUrl == overrideUrl ) {
migratedCreds = true;
settings.reset( oCSettings );
} else {
delete oCSettings;
}
}
}
}
if (!settings->childKeys().isEmpty()) {
acc = new Account;
Account *acc = new Account;
MirallConfigFile cfg;
acc->setApprovedCerts(QSslCertificate::fromData(cfg.caCerts()));
acc->setUrl(settings->value(QLatin1String(urlC)).toUrl());
acc->setCredentials(CredentialsFactory::create(settings->value(QLatin1String(authTypeC)).toString()));
@@ -174,11 +128,6 @@ Account* Account::restore()
continue;
acc->_settingsMap.insert(key, settings->value(key));
}
// now the cert, it is in the general group
settings->beginGroup(QLatin1String("General"));
acc->setApprovedCerts(QSslCertificate::fromData(settings->value(caCertsKeyC).toByteArray()));
acc->setMigrated(migratedCreds);
return acc;
}
return 0;
@@ -415,14 +364,4 @@ void Account::slotHandleErrors(QNetworkReply *reply , QList<QSslError> errors)
}
}
bool Account::wasMigrated()
{
return _wasMigrated;
}
void Account::setMigrated(bool mig)
{
_wasMigrated = mig;
}
} // namespace Mirall
-8
Ver Arquivo
@@ -108,13 +108,6 @@ public:
/** Returns webdav entry URL, based on url() */
QUrl davUrl() const;
/** set and retrieve the migration flag: if an account of a branded
* client was migrated from a former ownCloud Account, this is true
*/
void setMigrated(bool mig);
bool wasMigrated();
QList<QNetworkCookie> lastAuthCookies() const;
QNetworkReply* headRequest(const QString &relPath);
@@ -173,7 +166,6 @@ private:
int _state;
static QString _configFileName;
QString _davPath; // default "remote.php/webdav/";
bool _wasMigrated;
};
}
-89
Ver Arquivo
@@ -1,89 +0,0 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "mirall/accountmigrator.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/folderman.h"
#include "mirall/theme.h"
#include <QSettings>
#include <QStringList>
#include <QDir>
#include <QFileInfo>
#include <QDebug>
namespace Mirall {
// The purpose of this class is to migrate an existing account that
// was set up with an unbranded client to an branded one.
// The usecase is: Usually people try first with the community client,
// later they maybe switch to a branded client. When they install the
// branded client first, it should automatically pick the information
// from the already configured account.
AccountMigrator::AccountMigrator()
{
}
// the list of folder definitions which are files in the directory "folders"
// underneath the ownCloud configPath (with ownCloud as a last segment)
// need to be copied to the themed path and adjusted.
QStringList AccountMigrator::migrateFolderDefinitons()
{
MirallConfigFile cfg;
QStringList re;
QString themePath = cfg.configPath();
// create the original ownCloud config path out of the theme path
// by removing the theme folder and append ownCloud.
QString oCPath = themePath;
if( oCPath.endsWith(QLatin1Char('/')) ) {
oCPath.truncate( oCPath.length()-1 );
}
oCPath = oCPath.left( oCPath.lastIndexOf('/'));
themePath += QLatin1String( "folders");
oCPath += QLatin1String( "/ownCloud/folders" );
qDebug() << "Migrator: theme-path: " << themePath;
qDebug() << "Migrator: ownCloud path: " << oCPath;
// get a dir listing of the ownCloud folder definitions and copy
// them over to the theme dir
QDir oCDir(oCPath);
oCDir.setFilter( QDir::Files );
QStringList files = oCDir.entryList();
foreach( const QString& file, files ) {
QString escapedAlias = FolderMan::instance()->escapeAlias(file);
QString themeFile = themePath + QDir::separator() + file;
QString oCFile = oCPath+QDir::separator()+file;
if( QFile::copy( oCFile, themeFile ) ) {
re.append(file);
qDebug() << "Migrator: Folder definition migrated: " << file;
// fix the connection entry of the folder definition
QSettings settings(themeFile, QSettings::IniFormat);
settings.beginGroup( escapedAlias );
settings.setValue(QLatin1String("connection"), Theme::instance()->appName());
settings.sync();
}
}
return re;
}
}
-38
Ver Arquivo
@@ -1,38 +0,0 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef ACCOUNTMIGRATOR_H
#define ACCOUNTMIGRATOR_H
#include <QStringList>
namespace Mirall {
class AccountMigrator {
public:
explicit AccountMigrator();
/**
* @brief migrateFolderDefinitons - migrate the folder definition files
* @return the list of migrated folder definitions
*/
QStringList migrateFolderDefinitons();
signals:
public slots:
};
}
#endif // ACCOUNTMIGRATOR_H
+1 -1
Ver Arquivo
@@ -713,7 +713,7 @@ void AccountSettings::slotIgnoreFilesEditor()
_ignoreEditor->setAttribute( Qt::WA_DeleteOnClose, true );
_ignoreEditor->open();
} else {
ownCloudGui::raiseDialog(_ignoreEditor);
Utility::raiseDialog(_ignoreEditor);
}
}
+1 -1
Ver Arquivo
@@ -71,7 +71,7 @@ QString applicationTrPath()
#elif defined(Q_OS_MAC)
return QApplication::applicationDirPath()+QLatin1String("/../Resources/Translations"); // path defaults to app dir.
#elif defined(Q_OS_UNIX)
return QString::fromLatin1(DATADIR"/"APPLICATION_EXECUTABLE"/i18n/");
return QString::fromLatin1(DATADIR "/" APPLICATION_EXECUTABLE "/i18n/");
#endif
}
}
+408
Ver Arquivo
@@ -0,0 +1,408 @@
/*
* Copyright (C) by Markus Goetz <markus@woboq.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "owncloudpropagator.h"
#include "propagator_qnam.h"
#include "propagatorjobs.h"
#include "propagator_legacy.h"
#include "mirall/utility.h"
#ifdef Q_OS_WIN
#include <windef.h>
#include <winbase.h>
#endif
#include <QTimer>
#include <QObject>
namespace Mirall {
// Because of the many layers of buffering inside Qt (and probably the OS and the network)
// we cannot lower this value much more. If we do, the estimated bw will be very high
// because the buffers fill fast while the actual network algorithms are not relevant yet.
static qint64 relativeLimitMeasuringTimerIntervalMsec = 1000*2;
// See also WritingState in http://code.woboq.org/qt5/qtbase/src/network/access/qhttpprotocolhandler.cpp.html#_ZN20QHttpProtocolHandler11sendRequestEv
// FIXME At some point:
// * Register device only after the QNR received its metaDataChanged() signal
// * Incorporate Qt buffer fill state (it's a negative absolute delta).
// * Incorporate SSL overhead (percentage)
// * For relative limiting, do less measuring and more delaying+giving quota
// * For relative limiting, smoothen measurements
BandwidthManager::BandwidthManager(OwncloudPropagator *p) : QObject(),
_propagator(p),
_relativeLimitCurrentMeasuredDevice(0),
_relativeUploadLimitProgressAtMeasuringRestart(0),
_currentUploadLimit(0),
_relativeLimitCurrentMeasuredJob(0),
_currentDownloadLimit(0)
{
_currentUploadLimit = _propagator->_uploadLimit.fetchAndAddAcquire(0);
_currentDownloadLimit = _propagator->_downloadLimit.fetchAndAddAcquire(0);
QObject::connect(&_switchingTimer, SIGNAL(timeout()), this, SLOT(switchingTimerExpired()));
_switchingTimer.setInterval(10*1000);
_switchingTimer.start();
QMetaObject::invokeMethod(this, "switchingTimerExpired", Qt::QueuedConnection);
// absolute uploads/downloads
QObject::connect(&_absoluteLimitTimer, SIGNAL(timeout()), this, SLOT(absoluteLimitTimerExpired()));
_absoluteLimitTimer.setInterval(1000);
_absoluteLimitTimer.start();
// Relative uploads
QObject::connect(&_relativeUploadMeasuringTimer,SIGNAL(timeout()),
this, SLOT(relativeUploadMeasuringTimerExpired()));
_relativeUploadMeasuringTimer.setInterval(relativeLimitMeasuringTimerIntervalMsec);
_relativeUploadMeasuringTimer.start();
_relativeUploadMeasuringTimer.setSingleShot(true); // will be restarted from the delay timer
QObject::connect(&_relativeUploadDelayTimer, SIGNAL(timeout()),
this, SLOT(relativeUploadDelayTimerExpired()));
_relativeUploadDelayTimer.setSingleShot(true); // will be restarted from the measuring timer
// Relative downloads
QObject::connect(&_relativeDownloadMeasuringTimer,SIGNAL(timeout()),
this, SLOT(relativeDownloadMeasuringTimerExpired()));
_relativeDownloadMeasuringTimer.setInterval(relativeLimitMeasuringTimerIntervalMsec);
_relativeDownloadMeasuringTimer.start();
_relativeDownloadMeasuringTimer.setSingleShot(true); // will be restarted from the delay timer
QObject::connect(&_relativeDownloadDelayTimer, SIGNAL(timeout()),
this, SLOT(relativeDownloadDelayTimerExpired()));
_relativeDownloadDelayTimer.setSingleShot(true); // will be restarted from the measuring timer
}
void BandwidthManager::registerUploadDevice(UploadDevice *p)
{
qDebug() << Q_FUNC_INFO << p;
_absoluteUploadDeviceList.append(p);
_relativeUploadDeviceList.append(p);
QObject::connect(p, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterUploadDevice(QObject*)));
if (usingAbsoluteUploadLimit()) {
p->setBandwidthLimited(true);
p->setChoked(false);
} else if (usingRelativeUploadLimit()) {
p->setBandwidthLimited(true);
p->setChoked(true);
} else {
p->setBandwidthLimited(false);
p->setChoked(false);
}
}
void BandwidthManager::unregisterUploadDevice(QObject *o)
{
UploadDevice *p = qobject_cast<UploadDevice*>(o);
if (p) {
unregisterUploadDevice(p);
}
}
void BandwidthManager::unregisterUploadDevice(UploadDevice* p)
{
qDebug() << Q_FUNC_INFO << p;
_absoluteUploadDeviceList.removeAll(p);
_relativeUploadDeviceList.removeAll(p);
if (p == _relativeLimitCurrentMeasuredDevice) {
_relativeLimitCurrentMeasuredDevice = 0;
_relativeUploadLimitProgressAtMeasuringRestart = 0;
}
}
void BandwidthManager::registerDownloadJob(GETFileJob* j)
{
qDebug() << Q_FUNC_INFO << j;
_downloadJobList.append(j);
QObject::connect(j, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterDownloadJob(QObject*)));
if (usingAbsoluteDownloadLimit()) {
j->setBandwidthLimited(true);
j->setChoked(false);
} else if (usingRelativeDownloadLimit()) {
j->setBandwidthLimited(true);
j->setChoked(true);
} else {
j->setBandwidthLimited(false);
j->setChoked(false);
}
}
void BandwidthManager::unregisterDownloadJob(GETFileJob* j)
{
_downloadJobList.removeAll(j);
if (_relativeLimitCurrentMeasuredJob == j) {
_relativeLimitCurrentMeasuredJob = 0;
_relativeDownloadLimitProgressAtMeasuringRestart = 0;
}
}
void BandwidthManager::unregisterDownloadJob(QObject* o)
{
GETFileJob *p = qobject_cast<GETFileJob*>(o);
if (p) {
unregisterDownloadJob(p);
}
}
void BandwidthManager::relativeUploadMeasuringTimerExpired()
{
if (!usingRelativeUploadLimit() || _relativeUploadDeviceList.count() == 0) {
// Not in this limiting mode, just wait 1 sec to continue the cycle
_relativeUploadDelayTimer.setInterval(1000);
_relativeUploadDelayTimer.start();
return;
}
if (_relativeLimitCurrentMeasuredDevice == 0) {
qDebug() << Q_FUNC_INFO << "No device set, just waiting 1 sec";
_relativeUploadDelayTimer.setInterval(1000);
_relativeUploadDelayTimer.start();
return;
}
qDebug() << Q_FUNC_INFO << _relativeUploadDeviceList.count() << "Starting Delay";
qint64 relativeLimitProgressMeasured = (_relativeLimitCurrentMeasuredDevice->_readWithProgress
+ _relativeLimitCurrentMeasuredDevice->_read) / 2;
qint64 relativeLimitProgressDifference = relativeLimitProgressMeasured - _relativeUploadLimitProgressAtMeasuringRestart;
qDebug() << Q_FUNC_INFO << _relativeUploadLimitProgressAtMeasuringRestart
<< relativeLimitProgressMeasured << relativeLimitProgressDifference;
qint64 speedkBPerSec = (relativeLimitProgressDifference / relativeLimitMeasuringTimerIntervalMsec*1000.0) / 1024.0;
qDebug() << Q_FUNC_INFO << relativeLimitProgressDifference/1024 <<"kB =>" << speedkBPerSec << "kB/sec on full speed ("
<< _relativeLimitCurrentMeasuredDevice->_readWithProgress << _relativeLimitCurrentMeasuredDevice->_read
<< qAbs(_relativeLimitCurrentMeasuredDevice->_readWithProgress
- _relativeLimitCurrentMeasuredDevice->_read) << ")";
qint64 uploadLimitPercent = -_currentUploadLimit;
// don't use too extreme values
uploadLimitPercent = qMin(uploadLimitPercent, qint64(90));
uploadLimitPercent = qMax(qint64(10), uploadLimitPercent);
qint64 wholeTimeMsec = (100.0 / uploadLimitPercent) * relativeLimitMeasuringTimerIntervalMsec;
qint64 waitTimeMsec = wholeTimeMsec - relativeLimitMeasuringTimerIntervalMsec;
qint64 realWaitTimeMsec = waitTimeMsec + wholeTimeMsec;
qDebug() << Q_FUNC_INFO << waitTimeMsec << " - "<< realWaitTimeMsec <<
" msec for " << uploadLimitPercent << "%";
qDebug() << Q_FUNC_INFO << "XXXX" << uploadLimitPercent << relativeLimitMeasuringTimerIntervalMsec;
// We want to wait twice as long since we want to give all
// devices the same quota we used now since we don't want
// any upload to timeout
_relativeUploadDelayTimer.setInterval(realWaitTimeMsec);
_relativeUploadDelayTimer.start();
int deviceCount = _relativeUploadDeviceList.count();
qint64 quotaPerDevice = relativeLimitProgressDifference * (uploadLimitPercent / 100.0) / deviceCount + 1.0;
qDebug() << Q_FUNC_INFO << "YYYY" << relativeLimitProgressDifference << uploadLimitPercent << deviceCount;
Q_FOREACH(UploadDevice *ud, _relativeUploadDeviceList) {
ud->setBandwidthLimited(true);
ud->setChoked(false);
ud->giveBandwidthQuota(quotaPerDevice);
qDebug() << Q_FUNC_INFO << "Gave" << quotaPerDevice/1024.0 << "kB to" << ud;
}
_relativeLimitCurrentMeasuredDevice = 0;
}
void BandwidthManager::relativeUploadDelayTimerExpired()
{
// Switch to measuring state
_relativeUploadMeasuringTimer.start(); // always start to continue the cycle
if (!usingRelativeUploadLimit()) {
return; // oh, not actually needed
}
if (_relativeUploadDeviceList.isEmpty()) {
return;
}
qDebug() << Q_FUNC_INFO << _relativeUploadDeviceList.count() << "Starting measuring";
// Take first device and then append it again (= we round robin all devices)
_relativeLimitCurrentMeasuredDevice = _relativeUploadDeviceList.takeFirst();
_relativeUploadDeviceList.append(_relativeLimitCurrentMeasuredDevice);
_relativeUploadLimitProgressAtMeasuringRestart = (_relativeLimitCurrentMeasuredDevice->_readWithProgress
+ _relativeLimitCurrentMeasuredDevice->_read) / 2;
_relativeLimitCurrentMeasuredDevice->setBandwidthLimited(false);
_relativeLimitCurrentMeasuredDevice->setChoked(false);
// choke all other UploadDevices
Q_FOREACH(UploadDevice *ud, _relativeUploadDeviceList) {
if (ud != _relativeLimitCurrentMeasuredDevice) {
ud->setBandwidthLimited(true);
ud->setChoked(true);
}
}
// now we're in measuring state
}
// for downloads:
void BandwidthManager::relativeDownloadMeasuringTimerExpired()
{
if (!usingRelativeDownloadLimit() || _downloadJobList.count() == 0) {
// Not in this limiting mode, just wait 1 sec to continue the cycle
_relativeDownloadDelayTimer.setInterval(1000);
_relativeDownloadDelayTimer.start();
return;
}
if (_relativeLimitCurrentMeasuredJob == 0) {
qDebug() << Q_FUNC_INFO << "No job set, just waiting 1 sec";
_relativeDownloadDelayTimer.setInterval(1000);
_relativeDownloadDelayTimer.start();
return;
}
qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "Starting Delay";
qint64 relativeLimitProgressMeasured = _relativeLimitCurrentMeasuredJob->currentDownloadPosition();
qint64 relativeLimitProgressDifference = relativeLimitProgressMeasured - _relativeDownloadLimitProgressAtMeasuringRestart;
qDebug() << Q_FUNC_INFO << _relativeDownloadLimitProgressAtMeasuringRestart
<< relativeLimitProgressMeasured << relativeLimitProgressDifference;
qint64 speedkBPerSec = (relativeLimitProgressDifference / relativeLimitMeasuringTimerIntervalMsec*1000.0) / 1024.0;
qDebug() << Q_FUNC_INFO << relativeLimitProgressDifference/1024 <<"kB =>" << speedkBPerSec << "kB/sec on full speed ("
<< _relativeLimitCurrentMeasuredJob->currentDownloadPosition() ;
qint64 downloadLimitPercent = -_currentDownloadLimit;
// don't use too extreme values
downloadLimitPercent = qMin(downloadLimitPercent, qint64(90));
downloadLimitPercent = qMax(qint64(10), downloadLimitPercent);
qint64 wholeTimeMsec = (100.0 / downloadLimitPercent) * relativeLimitMeasuringTimerIntervalMsec;
qint64 waitTimeMsec = wholeTimeMsec - relativeLimitMeasuringTimerIntervalMsec;
qint64 realWaitTimeMsec = waitTimeMsec + wholeTimeMsec;
qDebug() << Q_FUNC_INFO << waitTimeMsec << " - "<< realWaitTimeMsec <<
" msec for " << downloadLimitPercent << "%";
qDebug() << Q_FUNC_INFO << "XXXX" << downloadLimitPercent << relativeLimitMeasuringTimerIntervalMsec;
// We want to wait twice as long since we want to give all
// devices the same quota we used now since we don't want
// any upload to timeout
_relativeDownloadDelayTimer.setInterval(realWaitTimeMsec);
_relativeDownloadDelayTimer.start();
int jobCount = _downloadJobList.count();
qint64 quota = relativeLimitProgressDifference * (downloadLimitPercent / 100.0);
// if (quota > 20*1024) {
// qDebug() << "======== ADJUSTING QUOTA FROM " << quota << " TO " << quota - 20*1024;
// quota -= 20*1024;
// }
qint64 quotaPerJob = quota / jobCount + 1.0;
qDebug() << Q_FUNC_INFO << "YYYY" << relativeLimitProgressDifference << downloadLimitPercent << jobCount;
Q_FOREACH(GETFileJob *gfj, _downloadJobList) {
gfj->setBandwidthLimited(true);
gfj->setChoked(false);
gfj->giveBandwidthQuota(quotaPerJob);
qDebug() << Q_FUNC_INFO << "Gave" << quotaPerJob/1024.0 << "kB to" << gfj;
}
_relativeLimitCurrentMeasuredDevice = 0;
}
void BandwidthManager::relativeDownloadDelayTimerExpired()
{
// Switch to measuring state
_relativeDownloadMeasuringTimer.start(); // always start to continue the cycle
if (!usingRelativeDownloadLimit()) {
return; // oh, not actually needed
}
if (_downloadJobList.isEmpty()) {
//qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "No jobs?";
return;
}
qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "Starting measuring";
// Take first device and then append it again (= we round robin all devices)
_relativeLimitCurrentMeasuredJob = _downloadJobList.takeFirst();
_downloadJobList.append(_relativeLimitCurrentMeasuredJob);
_relativeDownloadLimitProgressAtMeasuringRestart = _relativeLimitCurrentMeasuredJob->currentDownloadPosition();
_relativeLimitCurrentMeasuredJob->setBandwidthLimited(false);
_relativeLimitCurrentMeasuredJob->setChoked(false);
// choke all other UploadDevices
Q_FOREACH(GETFileJob *gfj, _downloadJobList) {
if (gfj != _relativeLimitCurrentMeasuredJob) {
gfj->setBandwidthLimited(true);
gfj->setChoked(true);
}
}
// now we're in measuring state
}
// end downloads
void BandwidthManager::switchingTimerExpired() {
qint64 newUploadLimit = _propagator->_uploadLimit.fetchAndAddAcquire(0);
if (newUploadLimit != _currentUploadLimit) {
qDebug() << Q_FUNC_INFO << "Upload Bandwidth limit changed" << _currentUploadLimit << newUploadLimit;
_currentUploadLimit = newUploadLimit;
Q_FOREACH(UploadDevice *ud, _relativeUploadDeviceList) {
if (newUploadLimit == 0) {
ud->setBandwidthLimited(false);
ud->setChoked(false);
} else if (newUploadLimit > 0) {
ud->setBandwidthLimited(true);
ud->setChoked(false);
} else if (newUploadLimit < 0) {
ud->setBandwidthLimited(true);
ud->setChoked(true);
}
}
}
qint64 newDownloadLimit = _propagator->_downloadLimit.fetchAndAddAcquire(0);
if (newDownloadLimit != _currentDownloadLimit) {
qDebug() << Q_FUNC_INFO << "Download Bandwidth limit changed" << _currentDownloadLimit << newDownloadLimit;
_currentDownloadLimit = newDownloadLimit;
Q_FOREACH(GETFileJob *j, _downloadJobList) {
if (usingAbsoluteDownloadLimit()) {
j->setBandwidthLimited(true);
j->setChoked(false);
} else if (usingRelativeDownloadLimit()) {
j->setBandwidthLimited(true);
j->setChoked(true);
} else {
j->setBandwidthLimited(false);
j->setChoked(false);
}
}
}
}
void BandwidthManager::absoluteLimitTimerExpired()
{
if (usingAbsoluteUploadLimit() && _absoluteUploadDeviceList.count() > 0) {
qint64 quotaPerDevice = _currentUploadLimit / qMax(1, _absoluteUploadDeviceList.count());
qDebug() << Q_FUNC_INFO << quotaPerDevice << _absoluteUploadDeviceList.count() << _currentUploadLimit;
Q_FOREACH(UploadDevice *device, _absoluteUploadDeviceList) {
device->giveBandwidthQuota(quotaPerDevice);
qDebug() << Q_FUNC_INFO << "Gave " << quotaPerDevice/1024.0 << " kB to" << device;
}
}
if (usingAbsoluteDownloadLimit() && _downloadJobList.count() > 0) {
qint64 quotaPerJob = _currentDownloadLimit / qMax(1, _downloadJobList.count());
qDebug() << Q_FUNC_INFO << quotaPerJob << _downloadJobList.count() << _currentDownloadLimit;
Q_FOREACH(GETFileJob *j, _downloadJobList) {
j->giveBandwidthQuota(quotaPerJob);
qDebug() << Q_FUNC_INFO << "Gave " << quotaPerJob/1024.0 << " kB to" << j;
}
}
}
}
+83
Ver Arquivo
@@ -0,0 +1,83 @@
/*
* Copyright (C) by Markus Goetz <markus@woboq.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef BANDWIDTHMANAGER_H
#define BANDWIDTHMANAGER_H
#include <QObject>
#include <QLinkedList>
#include <QTimer>
#include <QIODevice>
namespace Mirall {
class UploadDevice;
class GETFileJob;
class OwncloudPropagator;
class BandwidthManager : public QObject {
Q_OBJECT
public:
BandwidthManager(OwncloudPropagator *p);
bool usingAbsoluteUploadLimit() { return _currentUploadLimit > 0; }
bool usingRelativeUploadLimit() { return _currentUploadLimit < 0; }
bool usingAbsoluteDownloadLimit() { return _currentDownloadLimit > 0; }
bool usingRelativeDownloadLimit() { return _currentDownloadLimit < 0; }
public slots:
void registerUploadDevice(UploadDevice*);
void unregisterUploadDevice(UploadDevice*);
void unregisterUploadDevice(QObject*);
void registerDownloadJob(GETFileJob*);
void unregisterDownloadJob(GETFileJob*);
void unregisterDownloadJob(QObject*);
void absoluteLimitTimerExpired();
void switchingTimerExpired();
void relativeUploadMeasuringTimerExpired();
void relativeUploadDelayTimerExpired();
void relativeDownloadMeasuringTimerExpired();
void relativeDownloadDelayTimerExpired();
private:
QTimer _switchingTimer; // for switching between absolute and relative bw limiting
OwncloudPropagator *_propagator; // FIXME this timer and this variable should be replaced
// by the propagator emitting the changed limit values to us as signal
QTimer _absoluteLimitTimer; // for absolute up/down bw limiting
QLinkedList<UploadDevice*> _absoluteUploadDeviceList;
QLinkedList<UploadDevice*> _relativeUploadDeviceList; // FIXME merge with list above ^^
QTimer _relativeUploadMeasuringTimer;
QTimer _relativeUploadDelayTimer; // for relative bw limiting, we need to wait this amount before measuring again
UploadDevice *_relativeLimitCurrentMeasuredDevice; // the device measured
qint64 _relativeUploadLimitProgressAtMeasuringRestart; // for measuring how much progress we made at start
qint64 _currentUploadLimit;
QLinkedList<GETFileJob*> _downloadJobList;
QTimer _relativeDownloadMeasuringTimer;
QTimer _relativeDownloadDelayTimer; // for relative bw limiting, we need to wait this amount before measuring again
GETFileJob *_relativeLimitCurrentMeasuredJob; // the device measured
qint64 _relativeDownloadLimitProgressAtMeasuringRestart; // for measuring how much progress we made at start
qint64 _currentDownloadLimit;
};
}
#endif
+88 -19
Ver Arquivo
@@ -122,9 +122,7 @@ bool Folder::init()
csync_set_log_level( 11 );
MirallConfigFile cfgFile;
csync_set_config_dir( _csync_ctx, cfgFile.configPath().toUtf8() );
setIgnoredFiles();
if (Account *account = AccountManager::instance()->account()) {
account->credentials()->syncContextPreInit(_csync_ctx);
} else {
@@ -268,6 +266,7 @@ void Folder::slotPollTimerTimeout()
qDebug() << "* Polling" << alias() << "for changes. (time since last sync:" << (_timeSinceLastSync.elapsed() / 1000) << "s)";
if (quint64(_timeSinceLastSync.elapsed()) > MirallConfigFile().forceSyncInterval() ||
_lastEtag.isNull() ||
!(_syncResult.status() == SyncResult::Success ||_syncResult.status() == SyncResult::Problem)) {
qDebug() << "** Force Sync now, state is " << _syncResult.statusString();
emit scheduleToSync(alias());
@@ -606,6 +605,8 @@ void Folder::startSync(const QStringList &pathList)
SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*)));
connect(_engine.data(), SIGNAL(transmissionProgress(Progress::Info)), this, SLOT(slotTransmissionProgress(Progress::Info)));
setDirtyNetworkLimits();
QMetaObject::invokeMethod(_engine.data(), "startSync", Qt::QueuedConnection);
// disable events until syncing is done
@@ -617,7 +618,21 @@ void Folder::startSync(const QStringList &pathList)
void Folder::setDirtyNetworkLimits()
{
if (_engine) {
_engine->setNetworkLimits();
MirallConfigFile cfg;
int downloadLimit = 0;
if (cfg.useDownloadLimit()) {
downloadLimit = cfg.downloadLimit() * 1000;
}
int uploadLimit = -75; // 75%
int useUpLimit = cfg.useUploadLimit();
if ( useUpLimit >= 1) {
uploadLimit = cfg.uploadLimit() * 1000;
} else if (useUpLimit == 0) {
uploadLimit = 0;
}
_engine->setNetworkLimits(uploadLimit, downloadLimit);
}
}
@@ -645,10 +660,13 @@ void Folder::slotSyncFinished()
bubbleUpSyncResult();
_engine.reset(0);
bool anotherSyncNeeded = false;
if (_engine) {
anotherSyncNeeded = _engine->isAnotherSyncNeeded();
_engine.reset(0);
}
// _watcher->setEventsEnabledDelayed(2000);
_pollTimer.start();
_timeSinceLastSync.restart();
if (_csyncError) {
@@ -675,6 +693,16 @@ void Folder::slotSyncFinished()
// all come in.
QTimer::singleShot(200, this, SLOT(slotEmitFinishedDelayed() ));
if (!anotherSyncNeeded) {
_pollTimer.start();
_timeSinceLastSync.restart();
} else {
// Another sync is required. We will make sure that the poll timer occurs soon enough
// and we clear the etag to force a sync
_lastEtag.clear();
QTimer::singleShot(1000, this, SLOT(slotPollTimerTimeout() ));
}
}
void Folder::slotEmitFinishedDelayed()
@@ -727,6 +755,38 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *
#endif
}
// compute the file status of a directory recursively. It returns either
// "all in sync" or "needs update" or "error", no more details.
SyncFileStatus Folder::recursiveFolderStatus( const QString& fileName )
{
QDir dir(path() + fileName);
const QStringList dirEntries = dir.entryList( QDir::AllEntries | QDir::NoDotAndDotDot );
foreach( const QString entry, dirEntries ) {
QFileInfo fi(entry);
SyncFileStatus sfs;
if( fi.isDir() ) {
sfs = recursiveFolderStatus( fileName + QLatin1Char('/') + entry );
} else {
QString fs( fileName + QLatin1Char('/') + entry );
if( fileName.isEmpty() ) {
// toplevel, no slash etc. needed.
fs = entry;
}
sfs = fileStatus( fs );
}
if( sfs == FILE_STATUS_STAT_ERROR || sfs == FILE_STATUS_ERROR ) {
return FILE_STATUS_ERROR;
}
if( sfs != FILE_STATUS_SYNC) {
return FILE_STATUS_EVAL;
}
}
return FILE_STATUS_SYNC;
}
SyncFileStatus Folder::fileStatus( const QString& fileName )
{
/*
@@ -746,7 +806,11 @@ SyncFileStatus Folder::fileStatus( const QString& fileName )
// FIXME: Find a way for STATUS_ERROR
SyncFileStatus stat = FILE_STATUS_NONE;
QString file = path() + fileName;
QString file = fileName;
if( path() != QLatin1String("/") ) {
file = path() + fileName;
}
QFileInfo fi(file);
if( !fi.exists() ) {
@@ -770,20 +834,25 @@ SyncFileStatus Folder::fileStatus( const QString& fileName )
}
}
SyncJournalFileRecord rec = _journal.getFileRecord(fileName);
if( stat == FILE_STATUS_NONE && !rec.isValid() ) {
stat = FILE_STATUS_NEW;
}
if( type == CSYNC_FTW_TYPE_DIR ) {
// compute recursive status of the directory
stat = recursiveFolderStatus( fileName );
} else {
if( stat == FILE_STATUS_NONE ) {
SyncJournalFileRecord rec = _journal.getFileRecord(fileName);
if( !rec.isValid() ) {
stat = FILE_STATUS_NEW;
}
// file was locally modified.
if( stat == FILE_STATUS_NONE && fi.lastModified() != rec._modtime ) {
stat = FILE_STATUS_EVAL;
// file was locally modified.
if( stat == FILE_STATUS_NONE && fi.lastModified() != rec._modtime ) {
stat = FILE_STATUS_EVAL;
}
}
if( stat == FILE_STATUS_NONE ) {
stat = FILE_STATUS_SYNC;
}
}
if( stat == FILE_STATUS_NONE ) {
stat = FILE_STATUS_SYNC;
}
return stat;
}
+11 -1
Ver Arquivo
@@ -76,6 +76,17 @@ public:
*/
SyncFileStatus fileStatus( const QString& );
/**
* @brief recursiveFolderStatus
* @param fileName - the relative file name to examine
* @return the resulting status
*
* The resulting status can only be either SYNC which means all files
* are in sync, ERROR if an error occured, or EVAL if something needs
* to be synced underneath this dir.
*/
SyncFileStatus recursiveFolderStatus( const QString& fileName );
/**
* alias or nickname
*/
@@ -186,7 +197,6 @@ private slots:
private:
bool init();
void setIgnoredFiles();
void bubbleUpSyncResult();
-12
Ver Arquivo
@@ -13,13 +13,10 @@
*/
#include "mirall/folderman.h"
#include "mirall/account.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/folder.h"
#include "mirall/syncresult.h"
#include "mirall/theme.h"
#include "mirall/accountmigrator.h"
#include <neon/ne_socket.h>
@@ -150,15 +147,6 @@ int FolderMan::setupFolders()
dir.setFilter(QDir::Files | QDir::Hidden);
QStringList list = dir.entryList();
if( list.count() == 0 ) {
// maybe the account was just migrated.
Account *acc = AccountManager::instance()->account();
if ( acc && acc->wasMigrated() ) {
AccountMigrator accMig;
list = accMig.migrateFolderDefinitons();
}
}
foreach ( const QString& alias, list ) {
Folder *f = setupFolderFromConfigFile( alias );
if( f ) {
+1 -2
Ver Arquivo
@@ -83,8 +83,6 @@ public:
void removeMonitorPath( const QString& alias, const QString& path );
void addMonitorPath( const QString& alias, const QString& path );
QString escapeAlias( const QString& ) const;
signals:
/**
* signal to indicate a folder named by alias has changed its sync state.
@@ -132,6 +130,7 @@ private:
// Escaping of the alias which is used in QSettings AND the file
// system, thus need to be escaped.
QString escapeAlias( const QString& ) const;
QString unescapeAlias( const QString& ) const;
void removeFolder( const QString& );
+21 -29
Ver Arquivo
@@ -12,16 +12,15 @@
*/
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkProxy>
#include <QAuthenticator>
#include <QSslConfiguration>
#include <QNetworkCookie>
#include <QNetworkCookieJar>
#include "mirall/cookiejar.h"
#include "mirall/mirallaccessmanager.h"
#include "mirall/utility.h"
#include "mirall/authenticationdialog.h"
namespace Mirall
{
@@ -36,16 +35,31 @@ MirallAccessManager::MirallAccessManager(QObject* parent)
setProxy(proxy);
#endif
setCookieJar(new CookieJar);
connect(this, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
this, SLOT(slotProxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
connect(this, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
this, SLOT(slotAuthenticationRequired(QNetworkReply*,QAuthenticator*)));
QObject::connect(this, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
this, SLOT(slotProxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
}
void MirallAccessManager::setRawCookie(const QByteArray &rawCookie, const QUrl &url)
{
QNetworkCookie cookie(rawCookie.left(rawCookie.indexOf('=')),
rawCookie.mid(rawCookie.indexOf('=')+1));
qDebug() << Q_FUNC_INFO << cookie.name() << cookie.value();
QList<QNetworkCookie> cookieList;
cookieList.append(cookie);
QNetworkCookieJar *jar = cookieJar();
jar->setCookiesFromUrl(cookieList, url);
}
QNetworkReply* MirallAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
{
QNetworkRequest newRequest(request);
if (newRequest.hasRawHeader("cookie")) {
// This will set the cookie into the QNetworkCookieJar which will then override the cookie header
setRawCookie(request.rawHeader("cookie"), request.url());
}
newRequest.setRawHeader(QByteArray("User-Agent"), Utility::userAgentString());
QByteArray verb = newRequest.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray();
// For PROPFIND (assumed to be a WebDAV op), set xml/utf8 as content type/encoding
@@ -66,27 +80,5 @@ void MirallAccessManager::slotProxyAuthenticationRequired(const QNetworkProxy &p
authenticator->setPassword(proxy.password());
}
}
void MirallAccessManager::slotAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)
{
// do not handle 401 created by the networkjobs. We may want
// to eventually exempt some, but for now we need
// it only for other things, e.g. the browser. Would we handle
// network jobs, this would break the wizard logic
if (reply->property("doNotHandleAuth").toBool()) {
return;
}
QUrl url = reply->url();
// show only scheme, host and port
QUrl reducedUrl;
reducedUrl.setScheme(url.scheme());
reducedUrl.setHost(url.host());
reducedUrl.setPort(url.port());
AuthenticationDialog dialog(authenticator->realm(), reducedUrl.toString());
if (dialog.exec() == QDialog::Accepted) {
authenticator->setUser(dialog.user());
authenticator->setPassword(dialog.password());
}
}
} // ns Mirall
+4 -2
Ver Arquivo
@@ -17,6 +17,8 @@
#include "owncloudlib.h"
#include <QNetworkAccessManager>
class QByteArray;
class QUrl;
namespace Mirall
{
@@ -27,12 +29,12 @@ class OWNCLOUDSYNC_EXPORT MirallAccessManager : public QNetworkAccessManager
public:
MirallAccessManager(QObject* parent = 0);
void setRawCookie(const QByteArray &rawCookie, const QUrl &url);
protected:
QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData = 0);
protected slots:
void slotProxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator);
void slotAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator);
};
} // ns Mirall
+2 -2
Ver Arquivo
@@ -31,6 +31,7 @@
#include "mirall/networkjobs.h"
#include "mirall/account.h"
#include "mirall/owncloudpropagator.h"
#include "creds/credentialsfactory.h"
#include "creds/abstractcredentials.h"
@@ -48,7 +49,7 @@ AbstractNetworkJob::AbstractNetworkJob(Account *account, const QString &path, QO
, _path(path)
{
_timer.setSingleShot(true);
_timer.setInterval(10*1000); // default to 10 seconds.
_timer.setInterval(OwncloudPropagator::httpTimeout() * 1000); // default to 5 minutes.
connect(&_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
}
@@ -57,7 +58,6 @@ void AbstractNetworkJob::setReply(QNetworkReply *reply)
if (_reply) {
_reply->deleteLater();
}
reply->setProperty("doNotHandleAuth", true);
_reply = reply;
}
+2 -45
Ver Arquivo
@@ -21,7 +21,6 @@
#include "mirall/owncloudsetupwizard.h"
#if defined(Q_OS_MAC)
# include "mirall/settingsdialogmac.h"
# include "macwindow.h" // qtmacgoodies
#else
# include "mirall/settingsdialog.h"
#endif
@@ -34,10 +33,6 @@
#include <QMessageBox>
#include <QSignalMapper>
#if defined(Q_OS_X11)
#include <QX11Info>
#endif
namespace Mirall {
ownCloudGui::ownCloudGui(Application *parent) :
@@ -116,14 +111,6 @@ void ownCloudGui::slotTrayClicked( QSystemTrayIcon::ActivationReason reason )
if( reason == QSystemTrayIcon::Trigger ) {
slotOpenSettingsDialog(true); // start settings if config is existing.
}
#else
// On Mac, if the settings dialog is already visible but hidden
// by other applications, this will bring it to the front.
if( reason == QSystemTrayIcon::Trigger ) {
if (!_settingsDialog.isNull() && _settingsDialog->isVisible()) {
slotShowSettings();
}
}
#endif
}
@@ -488,7 +475,7 @@ void ownCloudGui::slotShowSettings()
_settingsDialog->show();
}
_settingsDialog->setGeneralErrors( _startupFails );
ownCloudGui::raiseDialog(_settingsDialog.data());
Utility::raiseDialog(_settingsDialog.data());
}
void ownCloudGui::slotShowSyncProtocol()
@@ -516,7 +503,7 @@ void ownCloudGui::slotToggleLogBrowser()
if (_logBrowser->isVisible() ) {
_logBrowser->hide();
} else {
ownCloudGui::raiseDialog(_logBrowser);
Utility::raiseDialog(_logBrowser);
}
}
@@ -532,35 +519,5 @@ void ownCloudGui::slotHelp()
QDesktopServices::openUrl(QUrl(Theme::instance()->helpUrl()));
}
void ownCloudGui::raiseDialog( QWidget *raiseWidget )
{
if( raiseWidget && raiseWidget->parentWidget() == 0) {
// Qt has a bug which causes parent-less dialogs to pop-under.
raiseWidget->showNormal();
raiseWidget->raise();
raiseWidget->activateWindow();
}
#if defined(Q_OS_MAC)
// viel hilft viel ;-)
MacWindow::bringToFront(raiseWidget);
#endif
#if defined(Q_OS_X11)
WId wid = widget->winId();
NETWM::init();
XEvent e;
e.xclient.type = ClientMessage;
e.xclient.message_type = NETWM::NET_ACTIVE_WINDOW;
e.xclient.display = QX11Info::display();
e.xclient.window = wid;
e.xclient.format = 32;
e.xclient.data.l[0] = 2;
e.xclient.data.l[1] = QX11Info::appTime();
e.xclient.data.l[2] = 0;
e.xclient.data.l[3] = 0l;
e.xclient.data.l[4] = 0l;
#endif
}
} // end namespace
-2
Ver Arquivo
@@ -43,8 +43,6 @@ public:
bool checkAccountExists(bool openSettings);
static void raiseDialog( QWidget *raiseWidget );
signals:
void setupProxy();
+89 -15
Ver Arquivo
@@ -21,6 +21,7 @@
#include "propagator_legacy.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/utility.h"
#include <json.h>
#ifdef Q_OS_WIN
#include <windef.h>
@@ -29,11 +30,15 @@
#include <QStack>
#include <QFileInfo>
#include <QTimer>
#include <QObject>
#include <QTimerEvent>
namespace Mirall {
/* The maximum number of active job in parallel */
static int maximumActiveJob() {
int OwncloudPropagator::maximumActiveJob()
{
static int max = qgetenv("OWNCLOUD_MAX_PARALLEL").toUInt();
if (!max) {
max = 3; //default
@@ -41,9 +46,18 @@ static int maximumActiveJob() {
return max;
}
void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorString)
{
_item._errorString = errorString;
if (_item._isRestoration) {
if( status == SyncFileItem::Success || status == SyncFileItem::Conflict) {
status = SyncFileItem::Restoration;
} else {
_item._errorString += tr("; Restoration Failed: ") + errorString;
}
} else {
_item._errorString = errorString;
}
_item._status = status;
// Blacklisting
@@ -77,6 +91,7 @@ void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorStr
_propagator->_journal->updateBlacklistEntry( record );
break;
case SyncFileItem::Success:
case SyncFileItem::Restoration:
if( _item._blacklistedInDb ) {
// wipe blacklist entry.
_propagator->_journal->wipeBlacklistEntry(_item._file);
@@ -132,6 +147,7 @@ bool PropagateItemJob::checkForProblemsWithShared(int httpStatusCode, const QStr
// Also remove the inodes and fileid from the db so no further renames are tried for
// this item.
_propagator->_journal->avoidRenamesOnNextSync(_item._file);
_propagator->_anotherSyncNeeded = true;
}
if( newJob ) {
newJob->setRestoreJobMsg(msg);
@@ -153,7 +169,8 @@ void PropagateItemJob::slotRestoreJobCompleted(const SyncFileItem& item )
_restoreJob->setRestoreJobMsg();
}
if( item._status == SyncFileItem::Success || item._status == SyncFileItem::Conflict) {
if( item._status == SyncFileItem::Success || item._status == SyncFileItem::Conflict
|| item._status == SyncFileItem::Restoration) {
done( SyncFileItem::SoftError, msg);
} else {
done( item._status, tr("A file or directory was removed from a read only share, but restoring failed: %1").arg(item._errorString) );
@@ -198,6 +215,7 @@ PropagateItemJob* OwncloudPropagator::createJob(const SyncFileItem& item) {
return new PropagateLocalRename(this, item);
}
case CSYNC_INSTRUCTION_IGNORE:
case CSYNC_INSTRUCTION_ERROR:
return new PropagateIgnoreJob(this, item);
default:
return 0;
@@ -205,14 +223,13 @@ PropagateItemJob* OwncloudPropagator::createJob(const SyncFileItem& item) {
return 0;
}
void OwncloudPropagator::start(const SyncFileItemVector& _syncedItems)
void OwncloudPropagator::start(const SyncFileItemVector& items)
{
/* This builds all the job needed for the propagation.
* Each directories is a PropagateDirectory job, which contains the files in it.
* In order to do that we sort the items by destination. and loop over it. When we enter a
* directory, we can create the directory job and push it on the stack. */
SyncFileItemVector items = _syncedItems;
std::sort(items.begin(), items.end());
* In order to do that we loop over the items. (which are sorted by destination)
* When we enter adirectory, we can create the directory job and push it on the stack. */
_rootJob.reset(new PropagateDirectory(this));
QStack<QPair<QString /* directory name */, PropagateDirectory* /* job */> > directories;
directories.push(qMakePair(QString(), _rootJob.data()));
@@ -303,14 +320,31 @@ bool OwncloudPropagator::isInSharedDirectory(const QString& file)
*/
bool OwncloudPropagator::useLegacyJobs()
{
if (_downloadLimit.fetchAndAddAcquire(0) != 0 || _uploadLimit.fetchAndAddAcquire(0) != 0) {
// QNAM does not support bandwith limiting
// Allow an environement variable for debugging
QByteArray env = qgetenv("OWNCLOUD_USE_LEGACY_JOBS");
if (env=="true" || env =="1") {
qDebug() << "Force Legacy Propagator ACTIVATED";
return true;
}
// Allow an environement variable for debugging
QByteArray env = qgetenv("OWNCLOUD_USE_LEGACY_JOBS");
return env=="true" || env =="1";
env = qgetenv("OWNCLOUD_NEW_BANDWIDTH_LIMITING");
if (env=="true" || env =="1") {
qDebug() << "New Bandwidth Limiting Code ACTIVATED";
// Only certain Qt versions support this at the moment.
// They need those Change-Ids: Idb1c2d5a382a704d8cc08fe03c55c883bfc95aa7 Iefbcb1a21d8aedef1eb11761232dd16a049018dc
// FIXME We need to check the Qt version and then also return false here as soon
// as mirall ships with those Qt versions on Windows and OS X
return false;
}
if (_downloadLimit.fetchAndAddAcquire(0) != 0 || _uploadLimit.fetchAndAddAcquire(0) != 0) {
qDebug() << "Switching To Legacy Propagator Because Of Bandwidth Limit ACTIVATED";
// QNAM does not support bandwith limiting
// in most Qt versions.
return true;
}
return false;
}
int OwncloudPropagator::httpTimeout()
@@ -386,7 +420,8 @@ void PropagateDirectory::start()
void PropagateDirectory::slotSubJobFinished(SyncFileItem::Status status)
{
if (status == SyncFileItem::FatalError || (_current == -1 && status != SyncFileItem::Success)) {
if (status == SyncFileItem::FatalError ||
(_current == -1 && status != SyncFileItem::Success && status != SyncFileItem::Restoration)) {
abort();
emit finished(status);
return;
@@ -403,7 +438,7 @@ void PropagateDirectory::slotSubJobReady()
return; // Ignore the case when the _fistJob is ready and not yet finished
if (_runningNow && _current >= 0 && _current < _subJobs.count()) {
// there is a job running and the current one is not ready yet, we can't start new job
if (!_subJobs[_current]->_readySent || _propagator->_activeJobs >= maximumActiveJob())
if (!_subJobs[_current]->_readySent || _propagator->_activeJobs >= _propagator->maximumActiveJob())
return;
}
@@ -422,6 +457,12 @@ void PropagateDirectory::slotSubJobReady()
}
if (_item._should_update_etag && _item._instruction != CSYNC_INSTRUCTION_REMOVE) {
if (PropagateRemoteMkdir* mkdir = qobject_cast<PropagateRemoteMkdir*>(_firstJob.data())) {
// special case from MKDIR, get the fileId from the job there
if (_item._fileId.isEmpty() && !mkdir->_item._fileId.isEmpty()) {
_item._fileId = mkdir->_item._fileId;
}
}
SyncJournalFileRecord record(_item, _propagator->_localDir + _item._file);
_propagator->_journal->setFileRecord(record);
}
@@ -430,4 +471,37 @@ void PropagateDirectory::slotSubJobReady()
}
}
void CleanupPollsJob::start()
{
if (_pollInfos.empty()) {
emit finished();
deleteLater();
return;
}
auto info = _pollInfos.takeFirst();
SyncFileItem item;
item._file = info._file;
item._modtime = info._modtime;
PollJob *job = new PollJob(_account, info._url, item, _journal, _localPath, this);
connect(job, SIGNAL(finishedSignal()), SLOT(slotPollFinished()));
job->start();
}
void CleanupPollsJob::slotPollFinished()
{
PollJob *job = qobject_cast<PollJob *>(sender());
Q_ASSERT(job);
if (job->_item._status == SyncFileItem::FatalError) {
emit aborted(job->_item._errorString);
return;
} else if (job->_item._status != SyncFileItem::Success) {
qDebug() << "There was an error with file " << job->_item._file << job->_item._errorString;
} else {
_journal->setFileRecord(SyncJournalFileRecord(job->_item, _localPath + job->_item._file));
}
// Continue with the next entry, or finish
start();
}
}
+88 -8
Ver Arquivo
@@ -18,16 +18,26 @@
#include <neon/ne_request.h>
#include <QHash>
#include <QObject>
#include <qelapsedtimer.h>
#include <QMap>
#include <QLinkedList>
#include <QElapsedTimer>
#include <QTimer>
#include <QPointer>
#include <QIODevice>
#include "syncfileitem.h"
#include "syncjournaldb.h"
#include "bandwidthmanager.h"
struct hbf_transfer_s;
struct ne_session_s;
struct ne_decompress_s;
typedef struct ne_prop_result_set_s ne_prop_result_set;
namespace Mirall {
class Account;
class SyncJournalDb;
class OwncloudPropagator;
@@ -36,10 +46,8 @@ class PropagatorJob : public QObject {
protected:
OwncloudPropagator *_propagator;
void emitReady() {
bool wasReady = _readySent;
_readySent = true;
if (!wasReady)
emit ready();
emit ready();
};
public:
bool _readySent;
@@ -139,11 +147,15 @@ protected:
* set a custom restore job message that is used if the restore job succeeded.
* It is displayed in the activity view.
*/
QString restoreJobMsg() const { return _restoreJobMsg; }
void setRestoreJobMsg( const QString& msg = QString() ) { _restoreJobMsg = msg; }
QString restoreJobMsg() const {
return _item._isRestoration ? _item._errorString : QString();
}
void setRestoreJobMsg( const QString& msg = QString() ) {
_item._isRestoration = true;
_item._errorString = msg;
}
SyncFileItem _item;
QString _restoreJobMsg;
protected slots:
void slotRestoreJobCompleted(const SyncFileItem& );
@@ -164,10 +176,48 @@ public:
PropagateIgnoreJob(OwncloudPropagator* propagator,const SyncFileItem& item)
: PropagateItemJob(propagator, item) {}
void start() {
done(SyncFileItem::FileIgnored, _item._errorString);
SyncFileItem::Status status = _item._status;
done(status == SyncFileItem::NoStatus ? SyncFileItem::FileIgnored : status, _item._errorString);
}
};
class BandwidthManager; // fwd
class UploadDevice : public QIODevice {
Q_OBJECT
public:
QPointer<QIODevice> _file;
qint64 _read;
qint64 _size;
qint64 _start;
QPointer<BandwidthManager> _bandwidthManager;
qint64 _bandwidthQuota;
qint64 _readWithProgress;
UploadDevice(QIODevice *file, qint64 start, qint64 size, BandwidthManager *bwm);
~UploadDevice();
virtual qint64 writeData(const char* , qint64 );
virtual qint64 readData(char* data, qint64 maxlen);
virtual bool atEnd() const;
virtual qint64 size() const;
qint64 bytesAvailable() const;
virtual bool isSequential() const;
virtual bool seek ( qint64 pos );
void setBandwidthLimited(bool);
bool isBandwidthLimited() { return _bandwidthLimited; }
void setChoked(bool);
bool isChoked() { return _choked; }
void giveBandwidthQuota(qint64 bwq);
private:
bool _bandwidthLimited; // if _bandwidthQuota will be used
bool _choked; // if upload is paused (readData() will return 0)
protected slots:
void slotJobUploadProgress(qint64 sent, qint64 t);
};
//Q_DECLARE_METATYPE(UploadDevice);
//Q_DECLARE_METATYPE(QPointer<UploadDevice>);
class OwncloudPropagator : public QObject {
Q_OBJECT
@@ -189,6 +239,8 @@ public:
SyncJournalDb * const _journal;
bool _finishedEmited; // used to ensure that finished is only emit once
BandwidthManager _bandwidthManager;
public:
OwncloudPropagator(ne_session_s *session, const QString &localDir, const QString &remoteDir, const QString &remoteFolder,
SyncJournalDb *progressDb, QThread *neonThread)
@@ -199,7 +251,9 @@ public:
, _remoteFolder((remoteFolder.endsWith(QChar('/'))) ? remoteFolder : remoteFolder+'/' )
, _journal(progressDb)
, _finishedEmited(false)
, _bandwidthManager(this)
, _activeJobs(0)
, _anotherSyncNeeded(false)
{ }
void start(const SyncFileItemVector &_syncedItems);
@@ -212,6 +266,12 @@ public:
/* The number of currently active jobs */
int _activeJobs;
/** We detected that another sync is required after this one */
bool _anotherSyncNeeded;
/* The maximum number of active job in parallel */
int maximumActiveJob();
bool isInSharedDirectory(const QString& file);
bool localFileNameClash(const QString& relfile);
@@ -247,6 +307,26 @@ signals:
};
// Job that wait for all the poll jobs to be completed
class CleanupPollsJob : public QObject {
Q_OBJECT
QVector< SyncJournalDb::PollInfo > _pollInfos;
Account *_account;
SyncJournalDb *_journal;
QString _localPath;
public:
explicit CleanupPollsJob(const QVector< SyncJournalDb::PollInfo > &pollInfos, Account *account,
SyncJournalDb *journal, const QString &localPath, QObject* parent = 0)
: QObject(parent), _pollInfos(pollInfos), _account(account), _journal(journal), _localPath(localPath) {}
void start();
signals:
void finished();
void aborted(const QString &error);
private slots:
void slotPollFinished();
};
}
#endif
-10
Ver Arquivo
@@ -124,16 +124,6 @@ QPixmap ownCloudTheme::wizardHeaderLogo() const
}
#endif
QString ownCloudTheme::appName() const
{
return QLatin1String("ownCloud");
}
QString ownCloudTheme::appNameGUI() const
{
return QLatin1String("ownCloud");
}
}
-3
Ver Arquivo
@@ -33,9 +33,6 @@ public:
QIcon trayFolderIcon( const QString& ) const;
QIcon folderDisabledIcon() const;
QIcon applicationIcon() const;
QString appName() const;
QString appNameGUI() const;
QVariant customMedia(CustomMediaType type);
QString helpUrl() const;
+1 -1
Ver Arquivo
@@ -84,7 +84,7 @@ bool Progress::isWarningKind( SyncFileItem::Status kind)
{
return kind == SyncFileItem::SoftError || kind == SyncFileItem::NormalError
|| kind == SyncFileItem::FatalError || kind == SyncFileItem::FileIgnored
|| kind == SyncFileItem::Conflict;
|| kind == SyncFileItem::Conflict || kind == SyncFileItem::Restoration;
}
+4
Ver Arquivo
@@ -523,6 +523,10 @@ void PropagateDownloadFileLegacy::start()
_propagator->_journal->commit("download file start");
}
if (!_item._directDownloadUrl.isEmpty()) {
qDebug() << Q_FUNC_INFO << "Direct download URL" << _item._directDownloadUrl << "not supported with legacy propagator, will go via ownCloud server";
}
/* actually do the request */
int retry = 0;
+465 -102
Ver Arquivo
@@ -20,6 +20,7 @@
#include "utility.h"
#include "filesystem.h"
#include "propagatorjobs.h"
#include <json.h>
#include <QNetworkAccessManager>
#include <QFileInfo>
#include <QDir>
@@ -55,6 +56,11 @@ static SyncFileItem::Status classifyError(QNetworkReply::NetworkError nerror, in
return SyncFileItem::SoftError;
}
if (httpCode == 423) {
// Locked
return SyncFileItem::SoftError;
}
return SyncFileItem::NormalError;
}
@@ -64,8 +70,7 @@ void PUTFileJob::start() {
req.setRawHeader(it.key(), it.value());
}
setReply(davRequest("PUT", path(), req, _device));
_device->setParent(reply());
setReply(davRequest("PUT", path(), req, _device.data()));
setupConnections(reply());
if( reply()->error() != QNetworkReply::NoError ) {
@@ -83,6 +88,75 @@ void PUTFileJob::slotTimeout() {
reply()->abort();
}
void PollJob::start()
{
setTimeout(120 * 1000);
QUrl accountUrl = account()->url();
QUrl finalUrl = QUrl::fromUserInput(accountUrl.scheme() + QLatin1String("://") + accountUrl.authority()
+ (path().startsWith('/') ? QLatin1String("") : QLatin1Literal("/")) + path());
setReply(getRequest(finalUrl));
setupConnections(reply());
connect(reply(), SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(resetTimeout()));
AbstractNetworkJob::start();
}
bool PollJob::finished()
{
QNetworkReply::NetworkError err = reply()->error();
if (err != QNetworkReply::NoError) {
_item._httpErrorCode = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
_item._status = classifyError(err, _item._httpErrorCode);
_item._errorString = reply()->errorString();
if (_item._status == SyncFileItem::FatalError || _item._httpErrorCode >= 400) {
if (_item._status != SyncFileItem::FatalError
&& _item._httpErrorCode != 503) {
SyncJournalDb::PollInfo info;
info._file = _item._file;
// no info._url removes it from the database
_journal->setPollInfo(info);
_journal->commit("remove poll info");
}
emit finishedSignal();
return true;
}
start();
return false;
}
bool ok = false;
QByteArray jsonData = reply()->readAll().trimmed();
qDebug() << Q_FUNC_INFO << ">" << jsonData << "<" << reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QVariantMap status = QtJson::parse(QString::fromUtf8(jsonData), ok).toMap();
if (!ok || status.isEmpty()) {
_item._errorString = tr("Invalid json reply from the poll URL");
_item._status = SyncFileItem::NormalError;
emit finishedSignal();
return true;
}
if (status["unfinished"].isValid()) {
start();
return false;
}
_item._errorString = status["error"].toString();
_item._status = _item._errorString.isEmpty() ? SyncFileItem::Success : SyncFileItem::NormalError;
_item._fileId = status["fileid"].toByteArray();
_item._etag = status["etag"].toByteArray();
_item._responseTimeStamp = responseTimestamp();
SyncJournalDb::PollInfo info;
info._file = _item._file;
// no info._url removes it from the database
_journal->setPollInfo(info);
_journal->commit("remove poll info");
emit finishedSignal();
return true;
}
void PropagateUploadFileQNAM::start()
{
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
@@ -111,84 +185,159 @@ void PropagateUploadFileQNAM::start()
_currentChunk = 0;
_duration.start();
_propagator->_activeJobs++;
emit progress(_item, 0);
emitReady();
this->startNextChunk();
}
struct ChunkDevice : QIODevice {
public:
QPointer<QIODevice> _file;
qint64 _read;
qint64 _size;
qint64 _start;
UploadDevice::UploadDevice(QIODevice *file, qint64 start, qint64 size, BandwidthManager *bwm)
: QIODevice(file), _file(file), _read(0), _size(size), _start(start),
_bandwidthManager(bwm),
_bandwidthQuota(0),
_readWithProgress(0),
_bandwidthLimited(false), _choked(false)
{
qDebug() << Q_FUNC_INFO << start << size << chunkSize();
_bandwidthManager->registerUploadDevice(this);
_file = QPointer<QIODevice>(file);
}
ChunkDevice(QIODevice *file, qint64 start, qint64 size)
: QIODevice(file), _file(file), _read(0), _size(size), _start(start) {
_file = QPointer<QIODevice>(file);
_file.data()->seek(start);
UploadDevice::~UploadDevice() {
if (_bandwidthManager) {
_bandwidthManager->unregisterUploadDevice(this);
}
}
virtual qint64 writeData(const char* , qint64 ) {
Q_ASSERT(!"write to read only device");
qint64 UploadDevice::writeData(const char* , qint64 ) {
Q_ASSERT(!"write to read only device");
return 0;
}
qint64 UploadDevice::readData(char* data, qint64 maxlen) {
if (_file.isNull()) {
qDebug() << Q_FUNC_INFO << "Upload file object deleted during upload";
close();
return -1;
}
_file.data()->seek(_start + _read);
//qDebug() << Q_FUNC_INFO << maxlen << _read << _size << _bandwidthQuota;
if (_size - _read <= 0) {
// at end
qDebug() << Q_FUNC_INFO << _read << _size << _bandwidthQuota << "at end";
_bandwidthManager->unregisterUploadDevice(this);
return -1;
}
maxlen = qMin(maxlen, _size - _read);
if (maxlen == 0) {
return 0;
}
virtual qint64 readData(char* data, qint64 maxlen) {
if (_file.isNull()) {
qDebug() << Q_FUNC_INFO << "Upload file object deleted during upload";
close();
return -1;
}
maxlen = qMin(maxlen, chunkSize() - _read);
if (maxlen == 0)
if (isChoked()) {
qDebug() << Q_FUNC_INFO << this << "Upload Choked";
return 0;
}
if (isBandwidthLimited()) {
qDebug() << Q_FUNC_INFO << "BW LIMITED" << maxlen << _bandwidthQuota
<< qMin(maxlen, _bandwidthQuota);
maxlen = qMin(maxlen, _bandwidthQuota);
if (maxlen <= 0) { // no quota
qDebug() << Q_FUNC_INFO << "no quota";
return 0;
qint64 ret = _file.data()->read(data, maxlen);
if (ret < 0)
return -1;
_read += ret;
return ret;
}
virtual bool atEnd() const {
if (_file.isNull()) {
qDebug() << Q_FUNC_INFO << "Upload file object deleted during upload";
return true;
}
return _read >= chunkSize() || _file.data()->atEnd();
_bandwidthQuota -= maxlen;
}
qDebug() << Q_FUNC_INFO << "reading limited=" << isBandwidthLimited()
<< "maxlen=" << maxlen << "quota=" << _bandwidthQuota;
qint64 ret = _file.data()->read(data, maxlen);
//qDebug() << Q_FUNC_INFO << "returning " << ret;
virtual qint64 size() const{
return _size;
if (ret < 0)
return -1;
_read += ret;
//qDebug() << Q_FUNC_INFO << "returning2 " << ret << _read;
return ret;
}
void UploadDevice::slotJobUploadProgress(qint64 sent, qint64 t)
{
//qDebug() << Q_FUNC_INFO << sent << _read << t << _size << _bandwidthQuota;
if (sent == 0 || t == 0) {
return;
}
_readWithProgress = sent;
}
qint64 bytesAvailable() const
{
return _size - _read + QIODevice::bytesAvailable();
bool UploadDevice::atEnd() const {
if (_file.isNull()) {
qDebug() << Q_FUNC_INFO << "Upload file object deleted during upload";
return true;
}
// qDebug() << this << Q_FUNC_INFO << _read << chunkSize()
// << (_read >= chunkSize() || _file.data()->atEnd())
// << (_read >= _size);
return _file.data()->atEnd() || (_read >= _size);
}
// random access, we can seek
virtual bool isSequential() const{
qint64 UploadDevice::size() const{
// qDebug() << this << Q_FUNC_INFO << _size;
return _size;
}
qint64 UploadDevice::bytesAvailable() const
{
// qDebug() << this << Q_FUNC_INFO << _size << _read << QIODevice::bytesAvailable()
// << _size - _read + QIODevice::bytesAvailable();
return _size - _read + QIODevice::bytesAvailable();
}
// random access, we can seek
bool UploadDevice::isSequential() const{
return false;
}
bool UploadDevice::seek ( qint64 pos ) {
if (_file.isNull()) {
qDebug() << Q_FUNC_INFO << "Upload file object deleted during upload";
close();
return false;
}
qDebug() << this << Q_FUNC_INFO << pos << _read;
_read = pos;
return _file.data()->seek(pos + _start);
}
virtual bool seek ( qint64 pos ) {
if (_file.isNull()) {
qDebug() << Q_FUNC_INFO << "Upload file object deleted during upload";
close();
return false;
}
_read = pos;
return _file.data()->seek(pos + _start);
void UploadDevice::giveBandwidthQuota(qint64 bwq) {
// qDebug() << Q_FUNC_INFO << bwq;
if (!atEnd()) {
_bandwidthQuota = bwq;
// qDebug() << Q_FUNC_INFO << bwq << "emitting readyRead()" << _read << _readWithProgress;
QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection); // tell QNAM that we have quota
}
};
}
void UploadDevice::setBandwidthLimited(bool b) {
_bandwidthLimited = b;
QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
}
void UploadDevice::setChoked(bool b) {
_choked = b;
if (!_choked) {
QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
}
}
void PropagateUploadFileQNAM::startNextChunk()
{
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
return;
if (! _jobs.isEmpty() && _currentChunk + _startChunk >= _chunkCount - 1) {
// Don't do parallel upload of chunk if this might be the last chunk because the server cannot handle that
// https://github.com/owncloud/core/issues/11106
// We return now and when the _jobs will be finished we will proceed the last chunk
return;
}
/*
* // If the source file has changed during upload, it is detected and the
@@ -206,6 +355,7 @@ void PropagateUploadFileQNAM::startNextChunk()
quint64 fileSize = _item._size;
QMap<QByteArray, QByteArray> headers;
headers["OC-Total-Length"] = QByteArray::number(fileSize);
headers["OC-Async"] = "1";
headers["Content-Type"] = "application/octet-stream";
headers["X-OC-Mtime"] = QByteArray::number(qint64(_item._modtime));
if (!_item._etag.isEmpty() && _item._etag != "empty_etag") {
@@ -215,7 +365,7 @@ void PropagateUploadFileQNAM::startNextChunk()
}
QString path = _item._file;
QIODevice *device = 0;
UploadDevice *device = 0;
if (_chunkCount > 1) {
int sendingChunk = (_currentChunk + _startChunk) % _chunkCount;
// XOR with chunk size to make sure everything goes well if chunk size change between runs
@@ -229,9 +379,9 @@ void PropagateUploadFileQNAM::startNextChunk()
currentChunkSize = chunkSize();
}
}
device = new ChunkDevice(_file, chunkSize() * quint64(sendingChunk), currentChunkSize);
device = new UploadDevice(_file, chunkSize() * quint64(sendingChunk), currentChunkSize, &_propagator->_bandwidthManager);
} else {
device = _file;
device = new UploadDevice(_file, 0, fileSize, &_propagator->_bandwidthManager);
}
bool isOpen = true;
@@ -240,11 +390,31 @@ void PropagateUploadFileQNAM::startNextChunk()
}
if( isOpen ) {
_job = new PUTFileJob(AccountManager::instance()->account(), _propagator->_remoteFolder + path, device, headers);
_job->setTimeout(_propagator->httpTimeout() * 1000);
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
connect(_job, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(slotUploadProgress(qint64,qint64)));
_job->start();
PUTFileJob* job = new PUTFileJob(AccountManager::instance()->account(), _propagator->_remoteFolder + path, device, headers, _currentChunk);
_jobs.append(job);
_currentChunk++;
connect(job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
connect(job, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(slotUploadProgress(qint64,qint64)));
connect(job, SIGNAL(uploadProgress(qint64,qint64)), device, SLOT(slotJobUploadProgress(qint64,qint64)));
connect(job, SIGNAL(destroyed(QObject*)), this, SLOT(slotJobDestroyed(QObject*)));
job->start();
_propagator->_activeJobs++;
QByteArray env = qgetenv("OWNCLOUD_PARALLEL_CHUNK");
bool parallelChunkUpload = env=="true" || env =="1";;
if (_currentChunk + _startChunk >= _chunkCount - 1) {
// Don't do parallel upload of chunk if this might be the last chunk because the server cannot handle that
// https://github.com/owncloud/core/issues/11106
parallelChunkUpload = false;
}
if (parallelChunkUpload && (_propagator->_activeJobs < _propagator->maximumActiveJob())
&& _currentChunk < _chunkCount ) {
startNextChunk();
}
if (!parallelChunkUpload || _chunkCount - _currentChunk <= 0) {
emitReady();
}
} else {
qDebug() << "ERR: Could not open upload file: " << device->errorString();
done( SyncFileItem::NormalError, device->errorString() );
@@ -257,6 +427,7 @@ void PropagateUploadFileQNAM::slotPutFinished()
{
PUTFileJob *job = qobject_cast<PUTFileJob *>(sender());
Q_ASSERT(job);
slotJobDestroyed(job); // remove it from the _jobs list
qDebug() << Q_FUNC_INFO << job->reply()->request().url() << "FINISHED WITH STATUS"
<< job->reply()->error()
@@ -264,10 +435,16 @@ void PropagateUploadFileQNAM::slotPutFinished()
<< job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute)
<< job->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute);
_propagator->_activeJobs--;
if (_finished) {
// We have send the finished signal already. We don't need to handle any remaining jobs
return;
}
QNetworkReply::NetworkError err = job->reply()->error();
if (err != QNetworkReply::NoError) {
_item._httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
_propagator->_activeJobs--;
if(checkForProblemsWithShared(_item._httpErrorCode,
tr("The file was edited locally but is part of a read only share. "
"It is restored and your edit is in the conflict file."))) {
@@ -279,7 +456,11 @@ void PropagateUploadFileQNAM::slotPutFinished()
qDebug() << replyContent; // display the XML error in the debug
QRegExp rx("<s:message>(.*)</s:message>"); // Issue #1366: display server exception
if (rx.indexIn(QString::fromUtf8(replyContent)) != -1) {
errorString += QLatin1String(" (") + rx.cap(1) + QLatin1Char(')');
if (_item._httpErrorCode == 423) {
errorString = rx.cap(1); // For "Locked", the library user doesn't want all the stuff except the <s:message> contents
} else {
errorString += QLatin1String(" (") + rx.cap(1) + QLatin1Char(')');
}
}
if (_item._httpErrorCode == 412) {
@@ -292,19 +473,33 @@ void PropagateUploadFileQNAM::slotPutFinished()
return;
}
_item._httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
// The server needs some time to process the request and provide with a poll URL
if (_item._httpErrorCode == 202) {
_finished = true;
QString path = QString::fromUtf8(job->reply()->rawHeader("OC-Finish-Poll"));
if (path.isEmpty()) {
done(SyncFileItem::NormalError, tr("Poll URL missing"));
return;
}
startPollJob(path);
return;
}
bool finished = job->reply()->hasRawHeader("ETag");
if (!finished) {
QFileInfo fi(_propagator->_localDir + _item._file);
if( !fi.exists() ) {
_propagator->_activeJobs--;
_finished = true;
done(SyncFileItem::SoftError, tr("The local file was removed during sync."));
return;
}
if (Utility::qDateTimeToTime_t(fi.lastModified()) != _item._modtime) {
qDebug() << "The local file has changed during upload:" << _item._modtime << "!=" << Utility::qDateTimeToTime_t(fi.lastModified()) << fi.lastModified();
_propagator->_activeJobs--;
_finished = true;
_propagator->_anotherSyncNeeded = true;
done(SyncFileItem::SoftError, tr("Local file changed during sync."));
// FIXME: the legacy code was retrying for a few seconds.
// and also checking that after the last chunk, and removed the file in case of INSTRUCTION_NEW
@@ -312,16 +507,24 @@ void PropagateUploadFileQNAM::slotPutFinished()
}
// Proceed to next chunk.
_currentChunk++;
if (_currentChunk >= _chunkCount) {
_propagator->_activeJobs--;
if (!_jobs.empty()) {
// just wait for the other job to finish.
return;
}
_finished = true;
done(SyncFileItem::NormalError, tr("The server did not acknowledge the last chunk. (No e-tag were present)"));
return;
}
SyncJournalDb::UploadInfo pi;
pi._valid = true;
pi._chunk = (_currentChunk + _startChunk) % _chunkCount; // next chunk to start with
auto currentChunk = job->_chunk;
foreach (auto *job, _jobs) {
// Take the minimum finished one
currentChunk = qMin(currentChunk, job->_chunk - 1);
}
pi._chunk = (currentChunk + _startChunk + 1) % _chunkCount ; // next chunk to start with
pi._transferid = _transferId;
pi._modtime = Utility::qDateTimeFromTime_t(_item._modtime);
_propagator->_journal->setUploadInfo(_item._file, pi);
@@ -331,7 +534,7 @@ void PropagateUploadFileQNAM::slotPutFinished()
}
// the following code only happens after all chunks were uploaded.
//
_finished = true;
// the file id should only be empty for new files up- or downloaded
QByteArray fid = job->reply()->rawHeader("OC-FileID");
if( !fid.isEmpty() ) {
@@ -363,8 +566,6 @@ void PropagateUploadFileQNAM::finalize(const SyncFileItem &copy)
_item._etag = copy._etag;
_item._fileId = copy._fileId;
_propagator->_activeJobs--;
_item._requestDuration = _duration.elapsed();
_propagator->_journal->setFileRecord(SyncJournalFileRecord(_item, _propagator->_localDir + _item._file));
@@ -372,37 +573,115 @@ void PropagateUploadFileQNAM::finalize(const SyncFileItem &copy)
_propagator->_journal->setUploadInfo(_item._file, SyncJournalDb::UploadInfo());
_propagator->_journal->commit("upload file start");
qDebug() << Q_FUNC_INFO << "msec=" <<_duration.elapsed();
done(SyncFileItem::Success);
}
void PropagateUploadFileQNAM::slotUploadProgress(qint64 sent, qint64)
void PropagateUploadFileQNAM::slotUploadProgress(qint64 sent, qint64 t)
{
int progressChunk = _currentChunk + _startChunk;
int progressChunk = _currentChunk + _startChunk - 1;
if (progressChunk >= _chunkCount)
progressChunk = _currentChunk;
emit progress(_item, sent + _currentChunk * chunkSize());
progressChunk = _currentChunk - 1;
quint64 amount = progressChunk * chunkSize();
sender()->setProperty("byteWritten", sent);
if (_jobs.count() > 1) {
amount -= (_jobs.count() -1) * chunkSize();
foreach (QObject *j, _jobs) {
amount += j->property("byteWritten").toULongLong();
}
} else {
amount += sent;
}
emit progress(_item, amount);
}
void PropagateUploadFileQNAM::startPollJob(const QString& path)
{
PollJob* job = new PollJob(AccountManager::instance()->account(), path, _item,
_propagator->_journal, _propagator->_localDir, this);
connect(job, SIGNAL(finishedSignal()), SLOT(slotPollFinished()));
SyncJournalDb::PollInfo info;
info._file = _item._file;
info._url = path;
info._modtime = _item._modtime;
_propagator->_journal->setPollInfo(info);
_propagator->_journal->commit("add poll info");
job->start();
}
void PropagateUploadFileQNAM::slotPollFinished()
{
PollJob *job = qobject_cast<PollJob *>(sender());
Q_ASSERT(job);
if (job->_item._status != SyncFileItem::Success) {
done(job->_item._status, job->_item._errorString);
return;
}
finalize(job->_item);
}
void PropagateUploadFileQNAM::slotJobDestroyed(QObject* job)
{
_jobs.erase(std::remove(_jobs.begin(), _jobs.end(), job) , _jobs.end());
}
void PropagateUploadFileQNAM::abort()
{
if (_job && _job->reply()) {
qDebug() << Q_FUNC_INFO << this->_item._file;
_job->reply()->abort();
foreach(auto *job, _jobs) {
if (job->reply()) {
qDebug() << Q_FUNC_INFO << job << this->_item._file;
job->reply()->abort();
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// DOES NOT take owncership of the device.
GETFileJob::GETFileJob(Account* account, const QString& path, QFile *device,
const QMap<QByteArray, QByteArray> &headers, const QByteArray &expectedEtagForResume,
quint64 _resumeStart, QObject* parent)
: AbstractNetworkJob(account, path, parent),
_device(device), _headers(headers), _expectedEtagForResume(expectedEtagForResume),
_resumeStart(_resumeStart) , _errorStatus(SyncFileItem::NoStatus)
, _bandwidthLimited(false), _bandwidthChoked(false), _bandwidthQuota(0), _bandwidthManager(0)
, _hasEmittedFinishedSignal(false)
{
}
GETFileJob::GETFileJob(Account* account, const QUrl& url, QFile *device,
const QMap<QByteArray, QByteArray> &headers, const QByteArray &expectedEtagForResume,
quint64 resumeStart, QObject* parent)
: AbstractNetworkJob(account, url.toEncoded(), parent),
_device(device), _headers(headers), _expectedEtagForResume(expectedEtagForResume), _resumeStart(resumeStart),
_errorStatus(SyncFileItem::NoStatus), _directDownloadUrl(url)
, _bandwidthLimited(false), _bandwidthChoked(false), _bandwidthQuota(0), _bandwidthManager(0)
, _hasEmittedFinishedSignal(false)
{
}
void GETFileJob::start() {
QNetworkRequest req;
for(QMap<QByteArray, QByteArray>::const_iterator it = _headers.begin(); it != _headers.end(); ++it) {
req.setRawHeader(it.key(), it.value());
}
setReply(davRequest("GET", path(), req));
if (_directDownloadUrl.isEmpty()) {
setReply(davRequest("GET", path(), req));
} else {
// Use direct URL
setReply(davRequest("GET", _directDownloadUrl, req));
}
setupConnections(reply());
reply()->setReadBufferSize(128 * 1024);
reply()->setReadBufferSize(16 * 1024); // keep low so we can easier limit the bandwidth
qDebug() << Q_FUNC_INFO << _bandwidthManager << _bandwidthChoked << _bandwidthLimited;
if (_bandwidthManager) {
_bandwidthManager->registerDownloadJob(this);
}
if( reply()->error() != QNetworkReply::NoError ) {
qWarning() << Q_FUNC_INFO << " Network error: " << reply()->errorString();
@@ -417,23 +696,31 @@ void GETFileJob::start() {
void GETFileJob::slotMetaDataChanged()
{
// For some reason setting the read buffer in GETFileJob::start doesn't seem to go
// through the HTTP layer thread(?)
reply()->setReadBufferSize(16 * 1024);
if (reply()->error() != QNetworkReply::NoError
|| reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() / 100 != 2) {
// We will handle the error when the job is finished.
return;
}
QByteArray etag = parseEtag(reply()->rawHeader("Etag"));
if (etag.isEmpty()) {
_etag = parseEtag(reply()->rawHeader("Etag"));
if (!_directDownloadUrl.isEmpty() && !_etag.isEmpty()) {
qDebug() << Q_FUNC_INFO << "Direct download used, ignoring server ETag" << _etag;
_etag = QByteArray(); // reset received ETag
} else if (!_directDownloadUrl.isEmpty()) {
// All fine, ETag empty and directDownloadUrl used
} else if (_etag.isEmpty()) {
qDebug() << Q_FUNC_INFO << "No E-Tag reply by server, considering it invalid";
_errorString = tr("No E-Tag received from server, check Proxy/Gateway");
_errorStatus = SyncFileItem::NormalError;
reply()->abort();
return;
} else if (!_expectedEtagForResume.isEmpty() && _expectedEtagForResume != etag) {
} else if (!_expectedEtagForResume.isEmpty() && _expectedEtagForResume != _etag) {
qDebug() << Q_FUNC_INFO << "We received a different E-Tag for resuming!"
<< _expectedEtagForResume << "vs" << etag;
<< _expectedEtagForResume << "vs" << _etag;
_errorString = tr("We received a different E-Tag for resuming. Retrying next time.");
_errorStatus = SyncFileItem::NormalError;
reply()->abort();
@@ -469,13 +756,62 @@ void GETFileJob::slotMetaDataChanged()
}
void GETFileJob::setBandwidthManager(BandwidthManager *bwm)
{
_bandwidthManager = bwm;
}
void GETFileJob::setChoked(bool c)
{
_bandwidthChoked = c;
QMetaObject::invokeMethod(this, "slotReadyRead", Qt::QueuedConnection);
}
void GETFileJob::setBandwidthLimited(bool b)
{
_bandwidthLimited = b;
QMetaObject::invokeMethod(this, "slotReadyRead", Qt::QueuedConnection);
}
void GETFileJob::giveBandwidthQuota(qint64 q)
{
_bandwidthQuota = q;
qDebug() << Q_FUNC_INFO << "Got" << q << "bytes";
QMetaObject::invokeMethod(this, "slotReadyRead", Qt::QueuedConnection);
}
qint64 GETFileJob::currentDownloadPosition()
{
if (_device && _device->pos() > 0 && _device->pos() > _resumeStart) {
return _device->pos();
}
return _resumeStart;
}
void GETFileJob::slotReadyRead()
{
int bufferSize = qMin(1024*8ll , reply()->bytesAvailable());
QByteArray buffer(bufferSize, Qt::Uninitialized);
//qDebug() << Q_FUNC_INFO << reply()->bytesAvailable() << reply()->isOpen() << reply()->isFinished();
while(reply()->bytesAvailable() > 0) {
qint64 r = reply()->read(buffer.data(), bufferSize);
if (_bandwidthChoked) {
qDebug() << Q_FUNC_INFO << "Download choked";
break;
}
qint64 toRead = bufferSize;
if (_bandwidthLimited) {
toRead = qMin(qint64(bufferSize), _bandwidthQuota);
if (toRead == 0) {
qDebug() << Q_FUNC_INFO << "Out of quota";
break;
}
_bandwidthQuota -= toRead;
//qDebug() << Q_FUNC_INFO << "Reading" << toRead << "remaining" << _bandwidthQuota;
}
qint64 r = reply()->read(buffer.data(), toRead);
if (r < 0) {
_errorString = reply()->errorString();
_errorStatus = SyncFileItem::NormalError;
@@ -494,6 +830,26 @@ void GETFileJob::slotReadyRead()
}
}
resetTimeout();
//qDebug() << Q_FUNC_INFO << "END" << reply()->isFinished() << reply()->bytesAvailable() << _hasEmittedFinishedSignal;
if (reply()->isFinished() && reply()->bytesAvailable() == 0) {
qDebug() << Q_FUNC_INFO << "Actually finished!";
if (_bandwidthManager) {
_bandwidthManager->unregisterDownloadJob(this);
}
if (!_hasEmittedFinishedSignal) {
emit finishedSignal();
}
_hasEmittedFinishedSignal = true;
deleteLater();
}
}
void GETFileJob::slotTimeout()
{
_errorString = tr("Connection Timeout");
_errorStatus = SyncFileItem::FatalError;
reply()->abort();
}
void PropagateDownloadFileQNAM::start()
@@ -503,7 +859,7 @@ void PropagateDownloadFileQNAM::start()
qDebug() << Q_FUNC_INFO << _item._file << _propagator->_activeJobs;
// do a case clash check.
// do a klaas' case clash check.
if( _propagator->localFileNameClash(_item._file) ) {
done( SyncFileItem::NormalError, tr("File %1 can not be downloaded because of a local file name clash!")
.arg(QDir::toNativeSeparators(_item._file)) );
@@ -555,8 +911,6 @@ void PropagateDownloadFileQNAM::start()
QMap<QByteArray, QByteArray> headers;
/* Allow compressed content by setting the header */
//headers["Accept-Encoding"] = "gzip";
if (_tmpFile.size() > 0) {
quint64 done = _tmpFile.size();
@@ -571,10 +925,23 @@ void PropagateDownloadFileQNAM::start()
_startSize = done;
}
_job = new GETFileJob(AccountManager::instance()->account(),
_propagator->_remoteFolder + _item._file,
&_tmpFile, headers, expectedEtagForResume, _startSize);
_job->setTimeout(_propagator->httpTimeout() * 1000);
if (_item._directDownloadUrl.isEmpty()) {
// Normal job, download from oC instance
_job = new GETFileJob(AccountManager::instance()->account(),
_propagator->_remoteFolder + _item._file,
&_tmpFile, headers, expectedEtagForResume, _startSize);
} else {
// We were provided a direct URL, use that one
if (!_item._directDownloadCookies.isEmpty()) {
headers["Cookie"] = _item._directDownloadCookies.toUtf8();
}
QUrl url = QUrl::fromUserInput(_item._directDownloadUrl);
_job = new GETFileJob(AccountManager::instance()->account(),
url,
&_tmpFile, headers, expectedEtagForResume, _startSize);
qDebug() << Q_FUNC_INFO << "directDownloadUrl given for " << _item._file << _item._directDownloadUrl << headers["Cookie"];
}
_job->setBandwidthManager(&_propagator->_bandwidthManager);
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
connect(_job, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slotDownloadProgress(qint64,qint64)));
_propagator->_activeJobs ++;
@@ -611,7 +978,11 @@ void PropagateDownloadFileQNAM::slotGetFinished()
return;
}
_item._etag = parseEtag(job->reply()->rawHeader("Etag"));
if (!job->etag().isEmpty()) {
// The etag will be empty if we used a direct download URL.
// (If it was really empty by the server, the GETFileJob will have errored
_item._etag = parseEtag(job->etag());
}
_item._requestDuration = job->duration();
_item._responseTimeStamp = job->responseTimestamp();
@@ -693,13 +1064,5 @@ void PropagateDownloadFileQNAM::abort()
_job->reply()->abort();
}
void GETFileJob::slotTimeout()
{
_errorString = tr("Connection Timeout");
_errorStatus = SyncFileItem::FatalError;
reply()->abort();
}
}
+77 -17
Ver Arquivo
@@ -51,15 +51,17 @@ public:
class PUTFileJob : public AbstractNetworkJob {
Q_OBJECT
QIODevice* _device;
QSharedPointer<QIODevice> _device;
QMap<QByteArray, QByteArray> _headers;
QString _errorString;
public:
// Takes ownership of the device
explicit PUTFileJob(Account* account, const QString& path, QIODevice *device,
const QMap<QByteArray, QByteArray> &headers, QObject* parent = 0)
: AbstractNetworkJob(account, path, parent), _device(device), _headers(headers) {}
const QMap<QByteArray, QByteArray> &headers, int chunk, QObject* parent = 0)
: AbstractNetworkJob(account, path, parent), _device(device), _headers(headers), _chunk(chunk) {}
int _chunk;
virtual void start();
@@ -80,26 +82,55 @@ signals:
void uploadProgress(qint64,qint64);
};
class PollJob : public AbstractNetworkJob {
Q_OBJECT
SyncJournalDb *_journal;
QString _localPath;
public:
SyncFileItem _item;
// Takes ownership of the device
explicit PollJob(Account* account, const QString &path, const SyncFileItem &item,
SyncJournalDb *journal, const QString &localPath, QObject *parent)
: AbstractNetworkJob(account, path, parent), _journal(journal), _localPath(localPath), _item(item) {}
void start() Q_DECL_OVERRIDE;
bool finished() Q_DECL_OVERRIDE;
void slotTimeout() Q_DECL_OVERRIDE {
// emit finishedSignal(false);
// deleteLater();
qDebug() << Q_FUNC_INFO;
reply()->abort();
}
signals:
void finishedSignal();
};
class PropagateUploadFileQNAM : public PropagateItemJob {
Q_OBJECT
QPointer<PUTFileJob> _job;
QFile *_file;
int _startChunk;
int _currentChunk;
int _chunkCount;
int _transferId;
QElapsedTimer _duration;
QVector<PUTFileJob*> _jobs;
bool _finished;
public:
PropagateUploadFileQNAM(OwncloudPropagator* propagator,const SyncFileItem& item)
: PropagateItemJob(propagator, item), _startChunk(0), _currentChunk(0), _chunkCount(0), _transferId(0) {}
: PropagateItemJob(propagator, item), _startChunk(0), _currentChunk(0), _chunkCount(0), _transferId(0), _finished(false) {}
void start();
private slots:
void slotPutFinished();
void slotPollFinished();
void slotUploadProgress(qint64,qint64);
void abort();
void startNextChunk();
void finalize(const SyncFileItem&);
void slotJobDestroyed(QObject *job);
private:
void startPollJob(const QString& path);
};
@@ -111,22 +142,53 @@ class GETFileJob : public AbstractNetworkJob {
QByteArray _expectedEtagForResume;
quint64 _resumeStart;
SyncFileItem::Status _errorStatus;
QUrl _directDownloadUrl;
QByteArray _etag;
bool _bandwidthLimited; // if _bandwidthQuota will be used
bool _bandwidthChoked; // if download is paused (won't read on readyRead())
qint64 _bandwidthQuota;
QPointer<BandwidthManager> _bandwidthManager;
bool _hasEmittedFinishedSignal;
public:
// DOES NOT take owncership of the device.
explicit GETFileJob(Account* account, const QString& path, QFile *device,
const QMap<QByteArray, QByteArray> &headers, QByteArray expectedEtagForResume,
quint64 resumeStart, QObject* parent = 0)
: AbstractNetworkJob(account, path, parent),
_device(device), _headers(headers), _expectedEtagForResume(expectedEtagForResume),
_resumeStart(resumeStart), _errorStatus(SyncFileItem::NoStatus) {}
explicit GETFileJob(Mirall::Account* account, const QString& path, QFile* device,
const QMap<QByteArray, QByteArray> &headers, const QByteArray& expectedEtagForResume,
quint64 _resumeStart, QObject* parent = 0);
// For directDownloadUrl:
explicit GETFileJob(Mirall::Account* account, const QUrl& url, QFile* device,
const QMap<QByteArray, QByteArray> &headers, const QByteArray& expectedEtagForResume,
quint64 resumeStart, QObject* parent = 0);
virtual ~GETFileJob() {
if (_bandwidthManager) {
_bandwidthManager->unregisterDownloadJob(this);
}
}
virtual void start();
virtual bool finished() {
emit finishedSignal();
return true;
qDebug() << Q_FUNC_INFO << reply()->bytesAvailable() << _hasEmittedFinishedSignal;
if (reply()->bytesAvailable()) {
qDebug() << Q_FUNC_INFO << "Not all read yet because of bandwidth limits";
return false;
} else {
if (_bandwidthManager) {
_bandwidthManager->unregisterDownloadJob(this);
}
if (!_hasEmittedFinishedSignal) {
emit finishedSignal();
}
_hasEmittedFinishedSignal = true;
return true; // discard
}
}
void setBandwidthManager(BandwidthManager *bwm);
void setChoked(bool c);
void setBandwidthLimited(bool b);
void giveBandwidthQuota(qint64 q);
qint64 currentDownloadPosition();
QString errorString() {
return _errorString.isEmpty() ? reply()->errorString() : _errorString;
};
@@ -135,6 +197,8 @@ public:
virtual void slotTimeout();
QByteArray &etag() { return _etag; }
signals:
void finishedSignal();
@@ -161,10 +225,6 @@ private slots:
void abort();
void downloadFinished();
void slotDownloadProgress(qint64,qint64);
};
}
+41 -14
Ver Arquivo
@@ -154,6 +154,35 @@ void PropagateRemoteRemove::start()
done(SyncFileItem::Success);
}
/* The list of properties that is fetched in PropFind after a MKCOL */
static const ne_propname ls_props[] = {
{ "DAV:", "getetag"},
{ "http://owncloud.org/ns", "id"},
{ NULL, NULL }
};
/*
* Parse the PROPFIND result after a MKCOL
*/
void PropagateRemoteMkdir::propfind_results(void *userdata,
const ne_uri *uri,
const ne_prop_result_set *set)
{
PropagateRemoteMkdir *job = static_cast<PropagateRemoteMkdir *>(userdata);
job->_item._etag = parseEtag(ne_propset_value( set, &ls_props[0] ));
const char* fileId = ne_propset_value( set, &ls_props[1] );
if (fileId) {
job->_item._fileId = fileId;
qDebug() << "MKCOL: " << uri << " FileID set it to " << fileId;
// save the file id already so we can detect rename
SyncJournalFileRecord record(job->_item, job->_propagator->_localDir + job->_item._renameTarget);
job->_propagator->_journal->setFileRecord(record);
}
}
void PropagateRemoteMkdir::start()
{
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
@@ -174,6 +203,16 @@ void PropagateRemoteMkdir::start()
return;
}
// Get the fileid
// This is required so that wa can detect moves even if the folder is renamed on the server
// while files are still uploading
// TODO: Now we have to do a propfind because the server does not give the file id in the request
// https://github.com/owncloud/core/issues/9000
ne_propfind_handler *hdl = ne_propfind_create(_propagator->_session, uri.data(), 0);
ne_propfind_named(hdl, ls_props, propfind_results, this);
ne_propfind_destroy(hdl);
done(SyncFileItem::Success);
}
@@ -226,16 +265,7 @@ void PropagateRemoteRename::start()
return;
if (_item._file == _item._renameTarget) {
if (!_item._isDirectory) {
// The parents has been renamed already so there is nothing more to do.
// But we still need to fetch the new ETAG
// FIXME maybe do a recusrsive propfind after having moved the parent.
// Note: we also update the mtime because the server do not keep the mtime when moving files
QScopedPointer<char, QScopedPointerPodDeleter> uri2(
ne_path_escape((_propagator->_remoteDir + _item._renameTarget).toUtf8()));
if (!updateMTimeAndETag(uri2.data(), _item._modtime))
return;
}
// The parents has been renamed already so there is nothing more to do.
} else if (_item._file == QLatin1String("Shared") ) {
// Check if it is the toplevel Shared folder and do not propagate it.
if( QFile::rename( _propagator->_localDir + _item._renameTarget, _propagator->_localDir + QLatin1String("Shared")) ) {
@@ -263,9 +293,6 @@ void PropagateRemoteRename::start()
if (updateErrorFromSession(rc)) {
return;
}
if (!updateMTimeAndETag(uri2.data(), _item._modtime))
return;
}
// Wed, 15 Nov 1995 06:25:24 GMT
QDateTime dt = QDateTime::currentDateTimeUtc();
@@ -325,7 +352,7 @@ bool PropagateNeonJob::updateErrorFromSession(int neon_code, ne_request* req, in
if (ignoreHttpCode && httpStatusCode == ignoreHttpCode)
return false;
done(SyncFileItem::NormalError, errorString);
done((httpStatusCode != 423) ? SyncFileItem::NormalError : SyncFileItem::SoftError, errorString);
return true;
case NE_LOOKUP: /* Server or proxy hostname lookup failed */
case NE_AUTH: /* User authentication failed on server */
+3
Ver Arquivo
@@ -94,6 +94,9 @@ class PropagateRemoteMkdir : public PropagateNeonJob {
public:
PropagateRemoteMkdir (OwncloudPropagator* propagator,const SyncFileItem& item) : PropagateNeonJob(propagator, item) {}
void start();
private:
static void propfind_results(void *userdata, const ne_uri *uri, const ne_prop_result_set *set);
friend class PropagateDirectory; // So it can access the _item;
};
class PropagateLocalRename : public PropagateItemJob {
Q_OBJECT
-7
Ver Arquivo
@@ -46,13 +46,6 @@ SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent) :
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
_ui->setupUi(this);
// People perceive this as a Window, so also make Ctrl+W work
QAction *closeWindowAction = new QAction(this);
closeWindowAction->setShortcut(QKeySequence("Ctrl+W"));
connect(closeWindowAction, SIGNAL(triggered()), SLOT(accept()));
addAction(closeWindowAction);
setObjectName("Settings"); // required as group for saveGeometry call
setWindowTitle(tr("%1").arg(Theme::instance()->appNameGUI()));
+1 -6
Ver Arquivo
@@ -30,13 +30,8 @@ SettingsDialogMac::SettingsDialogMac(ownCloudGui *gui, QWidget *parent)
// Emulate dialog behavior: Escape means close
QAction *closeDialogAction = new QAction(this);
closeDialogAction->setShortcut(QKeySequence(Qt::Key_Escape));
connect(closeDialogAction, SIGNAL(triggered()), SLOT(close()));
addAction(closeDialogAction);
// People perceive this as a Window, so also make Ctrl+W work
QAction *closeWindowAction = new QAction(this);
closeWindowAction->setShortcut(QKeySequence("Ctrl+W"));
closeWindowAction->setShortcut(QKeySequence(Qt::Key_Escape));
connect(closeWindowAction, SIGNAL(triggered()), SLOT(close()));
addAction(closeWindowAction);
+71 -42
Ver Arquivo
@@ -19,6 +19,7 @@
#include "mirall/folderman.h"
#include "mirall/folder.h"
#include "mirall/utility.h"
#include "mirall/theme.h"
#include <QDebug>
#include <QUrl>
@@ -26,12 +27,11 @@
#include <QLocalServer>
#include <QMetaObject>
#include <QStringList>
#include <QScopedPointer>
#include <QFile>
#include <QDir>
#include <QApplication>
#include "mirall/utility.h"
namespace Mirall {
#define DEBUG qDebug() << "SocketApi: "
@@ -42,7 +42,8 @@ SocketApi::SocketApi(QObject* parent, const QUrl& localFile)
{
QString socketPath;
if (Utility::isWindows()) {
socketPath = QLatin1String("\\\\.\\pipe\\");
socketPath = QLatin1String("\\\\.\\pipe\\")
+ Theme::instance()->appName();
} else {
socketPath = localFile.toLocalFile();
@@ -51,14 +52,15 @@ SocketApi::SocketApi(QObject* parent, const QUrl& localFile)
// setup socket
_localServer = new QLocalServer(this);
QLocalServer::removeServer(socketPath);
if(!_localServer->listen(socketPath))
if(!_localServer->listen(socketPath)) {
DEBUG << "can't start server" << socketPath;
else
DEBUG << "server started" << socketPath;
connect(_localServer, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
} else {
DEBUG << "server started, listening at " << socketPath;
}
connect(_localServer, SIGNAL(newConnection()), this, SLOT(slotNewConnection()));
// folder watcher
connect(FolderMan::instance(), SIGNAL(folderSyncStateChange(QString)), SLOT(onSyncStateChanged(QString)));
connect(FolderMan::instance(), SIGNAL(folderSyncStateChange(QString)), SLOT(slotSyncStateChanged(QString)));
}
SocketApi::~SocketApi()
@@ -67,11 +69,14 @@ SocketApi::~SocketApi()
_localServer->close();
}
void SocketApi::onNewConnection()
void SocketApi::slotNewConnection()
{
QLocalSocket* socket = _localServer->nextPendingConnection();
if( ! socket ) {
return;
}
DEBUG << "New connection " << socket;
connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadSocket()));
connect(socket, SIGNAL(disconnected()), this, SLOT(onLostConnection()));
Q_ASSERT(socket->readAll().isEmpty());
@@ -87,13 +92,12 @@ void SocketApi::onLostConnection()
}
void SocketApi::onReadyRead()
void SocketApi::slotReadSocket()
{
QLocalSocket* socket = qobject_cast<QLocalSocket*>(sender());
Q_ASSERT(socket);
while(socket->canReadLine())
{
while(socket->canReadLine()) {
QString line = QString::fromUtf8(socket->readLine()).trimmed();
QString command = line.split(":").first();
QString function = QString(QLatin1String("command_")).append(command);
@@ -102,18 +106,15 @@ void SocketApi::onReadyRead()
int indexOfMethod = this->metaObject()->indexOfMethod(functionWithArguments.toAscii());
QString argument = line.remove(0, command.length()+1).trimmed();
if(indexOfMethod != -1)
{
if(indexOfMethod != -1) {
QMetaObject::invokeMethod(this, function.toAscii(), Q_ARG(QString, argument), Q_ARG(QLocalSocket*, socket));
}
else
{
} else {
DEBUG << "The command is not supported by this version of the client:" << command << "with argument:" << argument;
}
}
}
void SocketApi::onSyncStateChanged(const QString&)
void SocketApi::slotSyncStateChanged(const QString&)
{
broadcastMessage("UPDATE_VIEW");
}
@@ -137,66 +138,94 @@ void SocketApi::broadcastMessage(const QString& message)
void SocketApi::command_RETRIEVE_FOLDER_STATUS(const QString& argument, QLocalSocket* socket)
{
bool checkForSyncDirsOnly = false;
qDebug() << Q_FUNC_INFO << argument;
//TODO: do security checks?!
Folder* folder = FolderMan::instance()->folderForPath( argument );
// this can happen in offline mode e.g.: nothing to worry about
if(!folder)
{
if (!folder) {
DEBUG << "folder offline or not watched:" << argument;
return;
checkForSyncDirsOnly = true;
}
QDir dir(argument);
foreach(QString entry, dir.entryList(QDir::AllEntries|QDir::NoDotAndDotDot))
{
QStringList dirEntries;
if( checkForSyncDirsOnly ) {
dirEntries = dir.entryList(QDir::Dirs);
} else {
dirEntries = dir.entryList( QDir::AllEntries | QDir::NoDotAndDotDot );
}
foreach(const QString entry, dirEntries) {
QString absoluteFilePath = dir.absoluteFilePath(entry);
QString statusString;
SyncFileStatus fileStatus = folder->fileStatus(absoluteFilePath.mid(folder->path().length()));
switch(fileStatus)
{
if( checkForSyncDirsOnly ) {
Folder *f = FolderMan::instance()->folderForPath(absoluteFilePath);
if( f ) {
statusString = QLatin1String("SYNCDIR");
SyncFileStatus sfs = f->recursiveFolderStatus("");
if (sfs == FILE_STATUS_ERROR) {
statusString.append(QLatin1String("_ERR"));
} else if( sfs == FILE_STATUS_EVAL ) {
statusString.append(QLatin1String("_EVAL"));
} else if( sfs == FILE_STATUS_SYNC ) {
// all cool.
} else {
qDebug() << "Unexpected directory status!";
}
}
} else {
SyncFileStatus fileStatus = folder->fileStatus(absoluteFilePath.mid(folder->path().length()));
switch(fileStatus)
{
case FILE_STATUS_NONE:
statusString = QLatin1String("STATUS_NONE");
statusString = QLatin1String("NONE");
break;
case FILE_STATUS_EVAL:
statusString = QLatin1String("STATUS_EVAL");
statusString = QLatin1String("EVAL");
break;
case FILE_STATUS_REMOVE:
statusString = QLatin1String("STATUS_REMOVE");
statusString = QLatin1String("REMOVE");
break;
case FILE_STATUS_RENAME:
statusString = QLatin1String("STATUS_RENAME");
statusString = QLatin1String("RENAME");
break;
case FILE_STATUS_NEW:
statusString = QLatin1String("STATUS_NEW");
statusString = QLatin1String("NEW");
break;
case FILE_STATUS_CONFLICT:
statusString = QLatin1String("STATUS_CONFLICT");
statusString = QLatin1String("CONFLICT");
break;
case FILE_STATUS_IGNORE:
statusString = QLatin1String("STATUS_IGNORE");
statusString = QLatin1String("IGNORE");
break;
case FILE_STATUS_SYNC:
statusString = QLatin1String("STATUS_SYNC");
statusString = QLatin1String("SYNC");
break;
case FILE_STATUS_STAT_ERROR:
statusString = QLatin1String("STATUS_STAT_ERROR");
statusString = QLatin1String("STAT_ERROR");
break;
case FILE_STATUS_ERROR:
statusString = QLatin1String("STATUS_ERROR");
statusString = QLatin1String("ERROR");
break;
case FILE_STATUS_UPDATED:
statusString = QLatin1String("STATUS_UPDATED");
statusString = QLatin1String("UPDATED");
break;
default:
qWarning() << "not all SyncFileStatus items checked!";
Q_ASSERT(false);
statusString = QLatin1String("STATUS_NONE");
statusString = QLatin1String("NONE");
}
}
if( ! statusString.isEmpty() ) {
QString message("%1:%2:%3");
message = message.arg("STATUS").arg(statusString).arg(absoluteFilePath);
sendMessage(socket, message);
}
QString message("%1:%2:%3");
message = message.arg("STATUS").arg(statusString).arg(absoluteFilePath);
sendMessage(socket, message);
}
}
+3 -3
Ver Arquivo
@@ -34,10 +34,10 @@ public:
virtual ~SocketApi();
private slots:
void onNewConnection();
void slotNewConnection();
void onLostConnection();
void onReadyRead();
void onSyncStateChanged(const QString&);
void slotReadSocket();
void slotSyncStateChanged(const QString&);
private:
void sendMessage(QLocalSocket* socket, const QString& message);
+1 -5
Ver Arquivo
@@ -176,11 +176,6 @@ void SslButton::updateAccountInfo(Account *account)
} else {
setVisible(true);
}
if(QMenu *oldMenu = menu()) {
oldMenu->hide(); // Need to be hidden because the QToolButton would be left in invalid state if the menu is deleted while it is visible
setMenu(0);
oldMenu->deleteLater(); // setMenu do not delete the previous menu.
}
if (account->url().scheme() == QLatin1String("https")) {
setIcon(QIcon(QPixmap(":/mirall/resources/lock-https.png")));
QSslCipher cipher = account->sslConfiguration().sessionCipher();
@@ -217,6 +212,7 @@ void SslButton::updateAccountInfo(Account *account)
} else {
setIcon(QIcon(QPixmap(":/mirall/resources/lock-http.png")));
setToolTip(tr("This connection is NOT secure as it is not encrypted.\n"));
setMenu(0);
}
}

Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais