From: Jocelyn Turcotte Date: Mon, 14 Aug 2017 17:19:52 +0000 (+0200) Subject: Move csync to src/csync X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~701^2~145 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=f897a91354810232d590d322b2afde6344e45e93;p=nextcloud-desktop.git Move csync to src/csync --- diff --git a/CMakeLists.txt b/CMakeLists.txt index d4b2a52ca..976f19aec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -219,7 +219,6 @@ if(UNIT_TESTING) add_subdirectory(test) endif(UNIT_TESTING) -add_subdirectory(csync) add_subdirectory(src) if(NOT BUILD_LIBRARIES_ONLY) add_subdirectory(shell_integration) diff --git a/csync/AUTHORS b/csync/AUTHORS deleted file mode 100644 index 5fd81c08e..000000000 --- a/csync/AUTHORS +++ /dev/null @@ -1,3 +0,0 @@ -Andreas Schneider -Klaas Freitag -Olivier Goffart diff --git a/csync/CMakeLists.txt b/csync/CMakeLists.txt deleted file mode 100644 index 8b36dde86..000000000 --- a/csync/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ - - -# global needed variables -set(APPLICATION_NAME "ocsync") - -set(LIBRARY_VERSION ${MIRALL_VERSION}) -set(LIBRARY_SOVERSION "0") - -# add definitions -include(DefineCMakeDefaults) -include(DefinePlatformDefaults) -include(DefineCompilerFlags) -include(DefineOptions.cmake) - -include(DefineInstallationPaths) - -# add macros -include(MacroAddPlugin) -include(MacroCopyFile) - -find_package(SQLite3 3.8.0 REQUIRED) - -include(ConfigureChecks.cmake) - -include_directories(${CMAKE_CURRENT_BINARY_DIR}) - -if (MEM_NULL_TESTS) - add_definitions(-DCSYNC_MEM_NULL_TESTS) -endif (MEM_NULL_TESTS) - -add_subdirectory(src) - -configure_file(config_csync.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_csync.h) diff --git a/csync/COPYING b/csync/COPYING deleted file mode 100644 index 4362b4915..000000000 --- a/csync/COPYING +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/csync/ChangeLog b/csync/ChangeLog deleted file mode 100644 index a95a07589..000000000 --- a/csync/ChangeLog +++ /dev/null @@ -1,355 +0,0 @@ -ChangeLog -========== -version 0.91.4 (released 2013-12-12, ownCloud Cleint 1.5.0) - * changelog added, version bumped. - -version 0.91.3 (released 2013-12-11, ownCloud Client 1.5.0rc1) - * Fix progress bar on win32 - * Fix network rate limiting on win32 - * Do not check for etag during failing requests - * Start quota timer only after the predecessor returned - * Remove tmp files in case of certain download problems - * Some valgrind fixes - * Theming fix: button behaviour - * Fix a case where a sync loop could happen. - * Multi-linguar installer - * Fix handling of quotes in etags written by older ownClouds - * Fix errno handling in update phase - * Make csync compile on FreeBSD - * Minor cleanups. - -version 0.91.2 (released 2013-12-10, ownCloud Client 1.5.0beta3) - * have translatable error message for indiv. file errors. - * Use uint64_t for inode on win32 to fix a type glitch. - * Add test that directories are properly moved. - * Handle symlinks correctly. - * No longer recurse into ignored directories in update - phase. - * Added proper symlink detection for win32 platform. - -version 0.91.1 (released 2013-12-03, ownCloud Client 1.5.0beta2) - * Close database correctly to fix a potential crash (mirall#1229) - * Handle invalid inodes correctly. - * Use lstat rather than stat to detect symlinks correctly. - (core#6146) - -version 0.91.0 (released 2013-11-28, ownCloud Client 1.5.0beta1) - * fix ascii to int conversion for large numbers. - * add support for file ids, needed to detect server side moves. - * removed unused code, ie. database writing code that went to - mirall. - * add functions to query the database by fileid. - * add functions to read fileids from PUT replies. - * add server side move detection. - * enhanced test scripts - * Remove ne_sock_init and ne_sock_exit from owncloud module - (mirall#1115) - * Renamed 'md5' to 'etag' in code identifiers to avoid confusion. - * add new state EVAL_RENAME - * link the owncloud module directly rather than dl-loading it. - * add a content type header 'application/octet-stream' to PUTs. - * remove -gzip from etag header if its there. (mirall#1195) - * Many minor fixes, refactorings and improvements. - -version 0.90.4 (released 2013-10-18, ownCloud Client 1.4.2) - - * Count renamed and deleted files for progress information. - * Do not reset csync internal error state in helper funcs - and do not overwrite error messages. - That fixes error reporting to the client. - * Disable check on inodes on all platforms as inodes are not - reliable. - * Fix resuming after user aborting the sync process. - * enabled HBF debugging permanently. - -version 0.90.1 (released 2013-09-24, ownCloud Client 1.4.1) - * no more check on the local inode in updater for win32 (bug #779) - * detect if server does not send an etag after an upload - completed. - * fix crash in case of network timeout, reported as - https://github.comowncloud/client/issues/1010 - * compile and cmake fixes for win32 - * fixed behaviour of csync_exclude - * documentation and spelling fixes. - -version 0.90.0 (released 2013-09-04, ownCloud Client 1.4.0) - * Added API to get progress information from csync. - * Added c_rename function to csync std. - * Fix: Do renames of files before any puts. - * Improved database integrity checks. - * Improvements of database writing efficiency. - * Fix: stat file on win32 even if its opened by application. - * httpbf: configurable block size and threshold. - * Many fixes found by a Coverity check. - * Fix: use correct stat struct on all platforms - * Fix: download resuming. - * ownCloud module: Bandwith limitation added. - * Added ability to remove ignored files automatically. - * Fix: Use int64_t and friends - * Fix: Removed all compile warnings. - * Left excluded files and links in csync's tree to be able to show. - them to the user. - * Add OC-Total-Length header for better quota handling. - * Report inbetween progress - -version 0.80.0 (released 2013-06-25) - * Big file chunking (e.g. up/download of big files should now be no - problem anymore) - * Resuming (download of big files will resume) - * Fix false conflicts when database is corrupt/missing - * Fix false conflicts when file is locked - * Put legitimate conflict files only on client side - * Fix unreliable sync after push_file failed - * Fix rename due to inode cast error - * Make chunking work on nginx setups or through nginx proxies - * Improve error reporting in csync_update - * Clean progress database on csync_commit - * Fix issues detected by Coverity - * Fix conflict file appearing when a file cannot be stated - * Do not shadow server errors by not downloading files that have - failed to download in the past - -version 0.70.6 (released 2013-04-11) - * [Fixes] Try to avoid to upload incomplete files - * [Fixes] Increase read timeout to 300 seconds - * [Fixes] Handle IGNORE status correctly - * [Fixes] Set path and phash for ignored files - * [Fixes] Fix some issues discovered by Coverity - * [Fixes] Make sure to never allow empty pathes in rmdir - * [Fixes] Fix a crash caused by superfluous free() calls - -version 0.70.5 (released 2013-04-02) - * detect 'wrong' conflict files on client side. - * [Fixes] Give context to module to enable logging (cmd client). - * [Fixes] Fix version table contents. - * [Fixes] Fix handling of non statable files on Win32. - * [Fixes] Fix renames on clientside on read only shares. - * [Fixes] Various small fixes and improvements. - -version 0.70.4 (released 2013-02-26) - * [Win32] Ship with upto-date openssl version to fix SSL problems we saw. - * [Fixes] Fix crash during mkdir. - * [Fixes] Added workaround for problem that server sometimes does - not respond properly to PROPFIND (mirall#285) - * [Fixes] Fix handling of deletion of non empty or locked - directories. - * [Fixes] Fixed some potential memory leaks. - * [Fixes] Files with filenames with unix extensions - are ignored now. - -version 0.70.3 (released 2013-01-24) - * [Platform] Fix session cookie extraction (mirall bug #260). - -version 0.70.2 (released 2013-01-23) - * [Platform] Improved module parameter system. - * [Platform] New logging framework. Dropped log4c dependency. - * [Platform] New API to provide sync progress information. - * [Fixes] More efficiency for the ownCloud plugin through less HTTP requests to - the server. - * [Fixes] ownCloud plugin: Improved upload performance. - * [Fixes] Improved error reporting to mirall. - * [Fixes] ownCloud plugin: Improved interpretation of HTTP error codes. - * [Fixes] ownCloud plugin: Do not abort on errors with individual files any - more. - * [Fixes] Lots of other minor fixes. - * [MacOSX] Use libneon with proper big file support. - * [Win32] Use libneon with openSSL support now. - -version 0.70.0 and 0.70.1 were beta versions. - -version 0.60.2 (released 2012-11-26) - * Migration to cross platform testing system cmocka. - * Fixed various minor things incl. potential mem leaks. - * Clang fixes. - * Moved journal database to sync directory. - * Fixed more csync->ocsync renaming issues. - * Fixed statedb query below path. - * Fixed win32 Daylight Saving Time issues. - * Allow static linking with iniparser and sqlite. - * Win32: Fix CreateHandle function in local stat. - * Win32: More wide char fixes. - * Added version table to journal database. - * Fixes for HTTP reply computation. - * Stricter error checks on PROPFIND results. - * Workaround for DST influenced times from previous versions. - * Detect looping in mkdirs to fix sharing. - -version 0.60.1 (released 2012-10-18) - * Fix improper memory cleanup which could - cause memory leaks and crashes - * Fix memory leak - * Allow single quote (') in file names - * Remove stray temporary files - -version 0.60.0 (released 2012-10-10) - * simplification of pac based proxy support. - * syncing algorithm based on ids rather than on timestamps - * make it possible to relocate database - -version 0.50.11 (third beta version, released 2012-10-05) - * Renamed ownCloud version of csync to ocsync for ownCloud. - * Migration paths for csync database and config. - * Fixed that exclude patterns are also tested on files basenames. - * Fixed return type for query function if no database exists. - * minor code fixes - -version 0.50.10 (second beta version, released 2012-09-20) - * Fixed crash by removing a bogus free. - * More useful logging. - * ownCloud: Maintain the http session by handling the HTTP Cookie. - -version 0.50.9 (first beta version, released 2012-08-30) - * Fixed strncpy handling (mkdir on windows problem). - * extend database with columns uniq id and type. - * Use server maintained uniq IDs for update detection instead of - mtimes. - * Maintain uniq IDs in local database - * Handle change propagation through the file tree locally and remote. - * Added module to build a file tree from the local database (dbtree.c) - * Added methods to query IDs from the server and maintain it locally. - -version 0.50.8 (released 2012-08-10) - * Inode equivalent support for Win32 platforms to support rename - * ownCloud supports propagates renames from local to webdav MOVE - * ownCloud module works with proxy, settings from mirall. - * improved CMake modules (openSSL) - * Fixed namespace for lastmodified propset. - * Added cmocka based tests for ownCloud module. - * Added a config_test.h config_csync.header file. - * Fix link handling: Ignore symlinks. - * Modules can now report their capabilities to csync core. - * A lot of minor fixes and improvements. - -version 0.50.7 (released 2012-06-19) - * Added ability to log to a callback, ie. let the app - catch the log output - * Added push to remote without pushing to temp file first. - * Fixed file copy function to use wide character (win32). - * Fixed loading of statedb if user has special char (win32). - -version 0.50.6 (released 2012-05-18) - * Directories with 'strange' characters broke sync. (oC bug #613) - * Special characters in Windows did not sync correctly. (oC bug #478) - * Make neon redirecting - * Switch logging off on Apple to not fill the syslog. (oC bug #622) - -version 0.50.5 (released 2012-04-18) - * removed argp lib dependency - * simplified and fixed CMake files - * MacOS porting efforts - * more granular error reports, thread save - -version 0.50.0 (released 2013-08-01) - * Added owncloud module. - * Added support for more platforms: FreeBSD, Windows and MacOSX - * Added support for more compilers: CLang, MinGW and latest GCC - * Added a backup mode to the reconciler. - * Added new logging framework (removed log4c dependency). - * Added new config parser (removed iniparser dependency). - * Added cmocka tests. - * Added a way to export file_tree_walk functions. - * Added capabilities for modules. - * Added possiblity to push information to the modules. - * Added iconv support to support various char sets. - * Added csync_commit() to rerun on the same context. - * Added content checking in conflict case. - * Added callbacks for progress information. - * Added get() and put() functions for modules. - * Improved database: more performance, more integrity checks - * Improved error reporting: status codes, custom errnos - * Fixed serveral bugs. - * Relicensed libcsync to LGPLv2.1+. - -version 0.44.0 (released 2010-02-15) - * Migrated sftp module to libssh 0.4. - * Added more cache entries to the default config. - * Added missing requirements. - * Fixed build warnings. - * Fixed some memory leaks using sftp attributes. - * Some code cleanups. - -version 0.43.0 (released 2009-05-25) - * Added SFTP support with libssh 0.3. - * Added possibility to pass userdata to the auth function. - * Added a better version function. - * Fixed CMake build. - * Fixed CMake find modules. - * Fixed some flaws in cstd functions. - * Documented all public functions. - -version 0.42.0 (released 2009-02-10) - * Small fix in the userguide. - -version 0.42.0 rc3 (released 2009-01-23) - libcsync: - * Added checks for unix extensions. - * Added more documentation to the userguide. - * Fixed loading of plugins. - * Fixed call for deletion functions. - * Normalize the path to / for the statedb filename. - * More change name of client options to be more descriptive. - -version 0.42.0 rc2 (released 2009-01-07) - libcsync: - * Fixed a bug in the creation of the statedb - * Completed userguide - -version 0.42.0 rc1 (released 2008-12-04) - libcsync: - * Reduced calls of syscall functions. - * Added own function to create a temporary filename. - * Fixed libsmbclient 3.0.x support. - -version 0.42.0 beta1 (released 2008-09-10) - - libcsync: - * Added a sftp module using libssh - * Added user guide (just a start) - * Added testcase for update detection - * Added a function to parse an uri to cstdlib - * Updated the manpage - * Fixed some segfaults in cstdlib - * Fixed some memory leaks - - csync: - * Improved the auth callback - -version 0.42.0 alpha4 (released 2008-07-02) - - libcsync: - * Added the possibility to run csync completely without a journal - * Improved chmod calls during propagation. Most of the time we use the - default mode and don't need to call chmod. - * Improved the exclude list handling in the file tree walker. This - increased the speed of the update detection. - * Fixed csync on PPC - * Fixed serveral small bugs - - csync: - * Added commandline option to run csync completely without a journal - * Added a manpage - -version 0.42.0 alpha3 (released 2008-06-25) - - libcsync: - * Added a tree merger to write a complete journal - * Added support to run csync without a journal - * Fixed kerberos support in csync_smb module - * Fixed closing of files after the copy - * Fixed update detection to detect special files (fifo, pipes, - char devices, ..) - * Fixed O_NOATIME flag on open() if we don't have the permission - - csync: - * Add a variable to run csync completely without a journal - -version 0.42.0 alpha2 (released 2008-06-16) - - libcsync: - * Peformance improvements - * Add more directories to the standard exclude file - * Bugfixes - -version 0.42.0 alpha1 (released 2008-06-02) - - * Initial release diff --git a/csync/ConfigureChecks.cmake b/csync/ConfigureChecks.cmake deleted file mode 100644 index 6d64d5a63..000000000 --- a/csync/ConfigureChecks.cmake +++ /dev/null @@ -1,65 +0,0 @@ -include(CheckIncludeFile) -include(CheckSymbolExists) -include(CheckFunctionExists) -include(CheckLibraryExists) -include(CheckTypeSize) -include(CheckCXXSourceCompiles) - -set(PACKAGE ${APPLICATION_NAME}) -set(VERSION ${APPLICATION_VERSION}) -set(DATADIR ${DATA_INSTALL_DIR}) -set(LIBDIR ${LIB_INSTALL_DIR}) -set(SYSCONFDIR ${SYSCONF_INSTALL_DIR}) - -set(BINARYDIR ${CMAKE_CURRENT_BINARY_DIR}) -set(SOURCEDIR ${CMAKE_CURRENT_SOURCE_DIR}) - -# HEADER FILES -check_include_file(argp.h HAVE_ARGP_H) - -# FUNCTIONS -if (NOT LINUX) - # librt - check_library_exists(rt nanosleep "" HAVE_LIBRT) - - set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ) -endif (NOT LINUX) - -check_library_exists(rt clock_gettime "" HAVE_CLOCK_GETTIME) -if (HAVE_LIBRT OR HAVE_CLOCK_GETTIME) - set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} rt) -endif (HAVE_LIBRT OR HAVE_CLOCK_GETTIME) - -check_library_exists(dl dlopen "" HAVE_LIBDL) -if (HAVE_LIBDL) - set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} dl) -endif (HAVE_LIBDL) - -check_function_exists(asprintf HAVE_ASPRINTF) - -check_function_exists(fnmatch HAVE_FNMATCH) -if(NOT HAVE_FNMATCH AND WIN32) - find_library(SHLWAPI_LIBRARY shlwapi) - set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} shlwapi) -endif() - -if(WIN32) - set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} psapi kernel32) -endif() - -check_function_exists(timegm HAVE_TIMEGM) -check_function_exists(strerror_r HAVE_STRERROR_R) -check_function_exists(utimes HAVE_UTIMES) -check_function_exists(lstat HAVE_LSTAT) -check_function_exists(asprintf HAVE_ASPRINTF) -if (WIN32) - check_function_exists(__mingw_asprintf HAVE___MINGW_ASPRINTF) -endif(WIN32) -if (UNIX AND HAVE_ASPRINTF) - add_definitions(-D_GNU_SOURCE) -endif (UNIX AND HAVE_ASPRINTF) -if (WIN32) - check_function_exists(__mingw_asprintf HAVE___MINGW_ASPRINTF) -endif(WIN32) - -set(CSYNC_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "csync required system libraries") diff --git a/csync/DefineOptions.cmake b/csync/DefineOptions.cmake deleted file mode 100644 index 485e18322..000000000 --- a/csync/DefineOptions.cmake +++ /dev/null @@ -1,2 +0,0 @@ -option(UNIT_TESTING "Build with unit tests" OFF) -option(MEM_NULL_TESTS "Enable NULL memory testing" OFF) diff --git a/csync/INSTALL b/csync/INSTALL deleted file mode 100644 index caf65c2bd..000000000 --- a/csync/INSTALL +++ /dev/null @@ -1,84 +0,0 @@ -# How to build from source - -## Requirements - -### Common requirements - -In order to build csync, you need to install several components: - -- A C compiler -- [CMake](http://www.cmake.org) >= 2.6.0. -- [check](http://check.sourceforge.net) >= 0.9.5 -- [sqlite3](http://www.sqlite.org) >= 3.4 -- [libneon](http://www.webdav.org/neon/) >= 0.29.0 - -optional: -- [libsmbclient](http://www.samba.org) >= 3.5 -- [libssh](http://www.libssh.org) >= 0.5 - -sqlite3 is a runtime requirement. libsmbclient is needed for -the smb plugin, libssh for the sftp plugin. libneon is required for the -ownCloud plugin. - -Note that these version numbers are versions we know work correctly. If you -build and run csync successfully with an older version, please let us know. - - -## Building -First, you need to configure the compilation, using CMake. Go inside the -`build` dir. Create it if it doesn't exist. - -GNU/Linux and MacOS X: - - cmake -DCMAKE_BUILD_TYPE=Debug .. - make - -### CMake standard options -Here is a list of the most interesting options provided out of the box by CMake. - -- CMAKE_BUILD_TYPE: The type of build (can be Debug Release MinSizeRel RelWithDebInfo) -- CMAKE_INSTALL_PREFIX: The prefix to use when running make install (Default to - /usr/local on GNU/Linux and MacOS X) -- CMAKE_C_COMPILER: The path to the C compiler -- CMAKE_CXX_COMPILER: The path to the C++ compiler - -### CMake options defined for csync - -Options are defined in the following files: - -- DefineOptions.cmake - -They can be changed with the -D option: - -`cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_LOG4C=OFF ..` - -### Browsing/editing CMake options - -In addition to passing options on the command line, you can browse and edit -CMake options using `cmakesetup` (Windows) or `ccmake` (GNU/Linux and MacOS X). - -- Go to the build dir -- On Windows: run `cmakesetup` -- On GNU/Linux and MacOS X: run `ccmake ..` - -## Installing - -Before installing you can run the tests if everything is working: - - make test - -If you want to install csync after compilation run: - - make install - -## Running - -The csync binary can be found in the `build/client` directory. - -## About this document - -This document is written using [Markdown][] syntax, making it possible to -provide usable information in both plain text and HTML format. Whenever -modifying this document please use [Markdown][] syntax. - -[markdown]: http://www.daringfireball.net/projects/markdown diff --git a/csync/README b/csync/README deleted file mode 100644 index 2487e2415..000000000 --- a/csync/README +++ /dev/null @@ -1,34 +0,0 @@ -WHAT IS CSYNC? -============== - -csync is a lightweight utility to synchronize files between two directories on -a system or between multiple systems. - -It synchronizes bidirectionally and allows the user to keep two copies of files -and directories in sync. csync uses widely adopted protocols, such as smb or -sftp, so that there is no need for a server component. It is a user-level -program which means you don’t need to be a superuser or administrator. - -CONTRIBUTIONS -============= - -If you want to contribute to the development of the software then please join -the mailing list. Patches are accepted preferably created with git and we are -always glad to receive feedback or suggestions to the address -csync-devel@csync.org. -More information on the various mailing lists can be found at -http://www.csync.org/communication/. - -You can also get the sourcecode straight from the git repository - see -http://git.csync.org/ - -DOCUMENTATION -============= - -As a user you can find a userguide which is shipped with this package or is -available at the website. For developers there is doxygen documentation and -comments in the source code itself. See - -http://www.csync.org/userguide/ -and -http://www.csync.org/api/ diff --git a/csync/config_csync.h.cmake b/csync/config_csync.h.cmake deleted file mode 100644 index f5c9f09b2..000000000 --- a/csync/config_csync.h.cmake +++ /dev/null @@ -1,24 +0,0 @@ -#cmakedefine PACKAGE "${APPLICATION_NAME}" -#cmakedefine VERSION "${APPLICATION_VERSION}" -#cmakedefine LOCALEDIR "${LOCALE_INSTALL_DIR}" -#cmakedefine LIBDIR "${LIBDIR}" -#cmakedefine SYSCONFDIR "${SYSCONFDIR}" -#cmakedefine BINARYDIR "${BINARYDIR}" -#cmakedefine SOURCEDIR "${SOURCEDIR}" - -#cmakedefine HAVE_CLOCK_GETTIME - -#cmakedefine WITH_LOG4C 1 - -#cmakedefine HAVE_ARGP_H 1 - -#cmakedefine HAVE_TIMEGM 1 -#cmakedefine HAVE_STRERROR_R 1 -#cmakedefine HAVE_UTIMES 1 -#cmakedefine HAVE_LSTAT 1 -#cmakedefine HAVE_FNMATCH 1 - -#cmakedefine HAVE___MINGW_ASPRINTF 1 -#cmakedefine HAVE_ASPRINTF 1 - -#cmakedefine WITH_TESTING 1 diff --git a/csync/src/CMakeLists.txt b/csync/src/CMakeLists.txt deleted file mode 100644 index 8bce5f418..000000000 --- a/csync/src/CMakeLists.txt +++ /dev/null @@ -1,139 +0,0 @@ -project(libcsync) - -add_subdirectory(std) - -# Statically include sqlite - -set(CSYNC_PUBLIC_INCLUDE_DIRS - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_SOURCE_DIR} - CACHE INTERNAL "csync public include directories" -) - -set(CSYNC_PRIVATE_INCLUDE_DIRS - ${SQLITE3_INCLUDE_DIRS} - ${CSTDLIB_PUBLIC_INCLUDE_DIRS} - ${CMAKE_BINARY_DIR} -) - -set(CSYNC_LIBRARY - ocsync - CACHE INTERNAL "ocsync library" -) - -set(CSYNC_LINK_LIBRARIES - ${CSTDLIB_LIBRARY} - ${CSYNC_REQUIRED_LIBRARIES} - ${SQLITE3_LIBRARIES} -) - -# Specific option for builds tied to servers that do not support renaming extensions -set(NO_RENAME_EXTENSION 0 CACHE BOOL "Do not issue rename if the extension changes") -if(NO_RENAME_EXTENSION) - add_definitions(-DNO_RENAME_EXTENSION) -endif() - -set(csync_SRCS - csync.c - csync_exclude.c - csync_log.c - csync_statedb.c - csync_time.c - csync_util.c - csync_misc.c - - csync_update.c - csync_reconcile.c - - csync_rename.cc - - vio/csync_vio.c - vio/csync_vio_file_stat.c -) - -if (WIN32) - list(APPEND csync_SRCS - vio/csync_vio_local_win.c - ) -else() - list(APPEND csync_SRCS - vio/csync_vio_local_unix.c - ) -endif() - - -configure_file(csync_version.h.in ${CMAKE_CURRENT_BINARY_DIR}/csync_version.h) - -set(csync_HDRS - ${CMAKE_CURRENT_BINARY_DIR}/csync_version.h - csync.h - vio/csync_vio.h - vio/csync_vio_method.h - vio/csync_vio_module.h -) - -# Statically include sqlite -if (USE_OUR_OWN_SQLITE3) - list(APPEND csync_SRCS ${SQLITE3_SOURCE}) - if (WIN32) - # We want to export sqlite symbols from the ocsync DLL without - # having to patch both sqlite3.h and the amalgation sqlite3.c, - # so do the import/export magic manually through the build system. - remove_definitions(-DSQLITE_API=__declspec\(dllimport\)) - add_definitions(-DSQLITE_API=__declspec\(dllexport\)) - endif() -endif() - -include_directories( - ${CSYNC_PUBLIC_INCLUDE_DIRS} - ${CSYNC_PRIVATE_INCLUDE_DIRS} -) - -add_library(${CSYNC_LIBRARY} SHARED ${csync_SRCS}) -#add_library(${CSYNC_LIBRARY}_static STATIC ${csync_SRCS}) - -generate_export_header( ${CSYNC_LIBRARY} - BASE_NAME ${CSYNC_LIBRARY} - EXPORT_MACRO_NAME OCSYNC_EXPORT - EXPORT_FILE_NAME ocsynclib.h -) - -target_link_libraries(${CSYNC_LIBRARY} ${CSYNC_LINK_LIBRARIES}) -#target_link_libraries(${CSYNC_LIBRARY}_static ${CSYNC_LINK_LIBRARIES}) - -set_target_properties( - ${CSYNC_LIBRARY} - PROPERTIES - VERSION - ${LIBRARY_VERSION} - SOVERSION - ${LIBRARY_SOVERSION} - RUNTIME_OUTPUT_DIRECTORY - ${BIN_OUTPUT_DIRECTORY} -) -if(BUILD_OWNCLOUD_OSX_BUNDLE) - INSTALL( - TARGETS - ${CSYNC_LIBRARY} - LIBRARY DESTINATION - ${LIB_INSTALL_DIR} - ARCHIVE DESTINATION - ${LIB_INSTALL_DIR} - RUNTIME DESTINATION - ${BIN_INSTALL_DIR} - ) -else() - INSTALL( - TARGETS - ${CSYNC_LIBRARY} - LIBRARY DESTINATION - ${LIB_INSTALL_DIR}/${APPLICATION_EXECUTABLE} - ARCHIVE DESTINATION - ${LIB_INSTALL_DIR}/${APPLICATION_EXECUTABLE} - RUNTIME DESTINATION - ${BIN_INSTALL_DIR}/${APPLICATION_EXECUTABLE} - ) -endif() - - diff --git a/csync/src/csync.c b/csync/src/csync.c deleted file mode 100644 index 1f75ac3bd..000000000 --- a/csync/src/csync.c +++ /dev/null @@ -1,651 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * 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 "config_csync.h" - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "c_lib.h" -#include "csync_private.h" -#include "csync_exclude.h" -#include "csync_statedb.h" -#include "csync_time.h" -#include "csync_util.h" -#include "csync_misc.h" -#include "std/c_private.h" - -#include "csync_update.h" -#include "csync_reconcile.h" - -#include "vio/csync_vio.h" - -#include "csync_log.h" -#include "csync_rename.h" -#include "c_jhash.h" - -static int _key_cmp(const void *key, const void *data) { - uint64_t a; - csync_file_stat_t *b; - - a = *(uint64_t *) (key); - b = (csync_file_stat_t *) data; - - if (a < b->phash) { - return -1; - } else if (a > b->phash) { - return 1; - } - - return 0; -} - -static int _data_cmp(const void *key, const void *data) { - csync_file_stat_t *a, *b; - - a = (csync_file_stat_t *) key; - b = (csync_file_stat_t *) data; - - if (a->phash < b->phash) { - return -1; - } else if (a->phash > b->phash) { - return 1; - } - - return 0; -} - -void csync_create(CSYNC **csync, const char *local) { - CSYNC *ctx; - size_t len = 0; - - ctx = c_malloc(sizeof(CSYNC)); - - ctx->status_code = CSYNC_STATUS_OK; - - /* remove trailing slashes */ - len = strlen(local); - while(len > 0 && local[len - 1] == '/') --len; - - ctx->local.uri = c_strndup(local, len); - - ctx->status_code = CSYNC_STATUS_OK; - - ctx->current_fs = NULL; - - ctx->abort = false; - - ctx->ignore_hidden_files = true; - - *csync = ctx; -} - -void csync_init(CSYNC *ctx, const char *db_file) { - assert(ctx); - /* Do not initialize twice */ - - assert(!(ctx->status & CSYNC_STATUS_INIT)); - ctx->status_code = CSYNC_STATUS_OK; - - ctx->local.type = LOCAL_REPLICA; - - ctx->remote.type = REMOTE_REPLICA; - - SAFE_FREE(ctx->statedb.file); - ctx->statedb.file = c_strdup(db_file); - - c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp); - c_rbtree_create(&ctx->remote.tree, _key_cmp, _data_cmp); - - ctx->remote.root_perms = 0; - - ctx->status = CSYNC_STATUS_INIT; - - /* initialize random generator */ - srand(time(NULL)); -} - -int csync_update(CSYNC *ctx) { - int rc = -1; - struct timespec start, finish; - - if (ctx == NULL) { - errno = EBADF; - return -1; - } - ctx->status_code = CSYNC_STATUS_OK; - - /* Path of database file is set in csync_init */ - if (csync_statedb_load(ctx, ctx->statedb.file, &ctx->statedb.db) < 0) { - rc = -1; - return rc; - } - - ctx->status_code = CSYNC_STATUS_OK; - - csync_memstat_check(); - - if (!ctx->excludes) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "No exclude file loaded or defined!"); - } - - /* update detection for local replica */ - csync_gettime(&start); - ctx->current = LOCAL_REPLICA; - ctx->replica = ctx->local.type; - - rc = csync_ftw(ctx, ctx->local.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); - } - goto out; - } - - csync_gettime(&finish); - - CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, - "Update detection for local replica took %.2f seconds walking %zu files.", - c_secdiff(finish, start), c_rbtree_size(ctx->local.tree)); - csync_memstat_check(); - - /* update detection for remote replica */ - csync_gettime(&start); - ctx->current = REMOTE_REPLICA; - ctx->replica = ctx->remote.type; - - rc = csync_ftw(ctx, "", 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); - } - goto out; - } - - 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; - - rc = 0; - -out: - csync_statedb_close(ctx); - return rc; -} - -int csync_reconcile(CSYNC *ctx) { - int rc = -1; - struct timespec start, finish; - - if (ctx == NULL) { - errno = EBADF; - return -1; - } - ctx->status_code = CSYNC_STATUS_OK; - - /* Reconciliation for local replica */ - csync_gettime(&start); - - if (csync_statedb_load(ctx, ctx->statedb.file, &ctx->statedb.db) < 0) { - rc = -1; - return rc; - } - - ctx->current = LOCAL_REPLICA; - ctx->replica = ctx->local.type; - - rc = csync_reconcile_updates(ctx); - - csync_gettime(&finish); - - CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, - "Reconciliation for local replica took %.2f seconds visiting %zu files.", - c_secdiff(finish, start), c_rbtree_size(ctx->local.tree)); - - if (rc < 0) { - if (!CSYNC_STATUS_IS_OK(ctx->status_code)) { - ctx->status_code = csync_errno_to_status( errno, CSYNC_STATUS_RECONCILE_ERROR ); - } - goto out; - } - - /* Reconciliation for remote replica */ - csync_gettime(&start); - - ctx->current = REMOTE_REPLICA; - ctx->replica = ctx->remote.type; - - rc = csync_reconcile_updates(ctx); - - csync_gettime(&finish); - - CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, - "Reconciliation for remote replica took %.2f seconds visiting %zu files.", - c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree)); - - if (rc < 0) { - if (!CSYNC_STATUS_IS_OK(ctx->status_code)) { - ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_RECONCILE_ERROR ); - } - goto out; - } - - ctx->status |= CSYNC_STATUS_RECONCILE; - - rc = 0; - -out: - csync_statedb_close(ctx); - return 0; -} - -/* - * local visitor which calls the user visitor with repacked stat info. - */ -static int _csync_treewalk_visitor(void *obj, void *data) { - int rc = 0; - csync_file_stat_t *cur = NULL; - CSYNC *ctx = NULL; - c_rbtree_visit_func *visitor = NULL; - _csync_treewalk_context *twctx = NULL; - TREE_WALK_FILE trav; - c_rbtree_t *other_tree = NULL; - c_rbnode_t *other_node = NULL; - - cur = (csync_file_stat_t *) obj; - ctx = (CSYNC *) data; - - if (ctx == NULL) { - return -1; - } - - /* we need the opposite tree! */ - switch (ctx->current) { - case LOCAL_REPLICA: - other_tree = ctx->remote.tree; - break; - case REMOTE_REPLICA: - other_tree = ctx->local.tree; - break; - default: - break; - } - - other_node = c_rbtree_find(other_tree, &cur->phash); - - if (!other_node) { - /* Check the renamed path as well. */ - int len; - uint64_t h = 0; - char *renamed_path = csync_rename_adjust_path(ctx, cur->path); - - if (!c_streq(renamed_path, cur->path)) { - len = strlen( renamed_path ); - h = c_jhash64((uint8_t *) renamed_path, len, 0); - other_node = c_rbtree_find(other_tree, &h); - } - SAFE_FREE(renamed_path); - } - - if (!other_node) { - /* Check the source path as well. */ - int len; - uint64_t h = 0; - char *renamed_path = csync_rename_adjust_path_source(ctx, cur->path); - - if (!c_streq(renamed_path, cur->path)) { - len = strlen( renamed_path ); - h = c_jhash64((uint8_t *) renamed_path, len, 0); - other_node = c_rbtree_find(other_tree, &h); - } - SAFE_FREE(renamed_path); - } - - if (obj == NULL || data == NULL) { - ctx->status_code = CSYNC_STATUS_PARAM_ERROR; - return -1; - } - ctx->status_code = CSYNC_STATUS_OK; - - twctx = (_csync_treewalk_context*) ctx->callbacks.userdata; - if (twctx == NULL) { - ctx->status_code = CSYNC_STATUS_PARAM_ERROR; - return -1; - } - - if (twctx->instruction_filter > 0 && - !(twctx->instruction_filter & cur->instruction) ) { - return 0; - } - - visitor = (c_rbtree_visit_func*)(twctx->user_visitor); - if (visitor != NULL) { - trav.path = cur->path; - trav.size = cur->size; - trav.modtime = cur->modtime; - 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; - trav.has_ignored_files = cur->has_ignored_files; - trav.checksumHeader = cur->checksumHeader; - - if( other_node ) { - csync_file_stat_t *other_stat = (csync_file_stat_t*)other_node->data; - trav.other.etag = other_stat->etag; - trav.other.file_id = other_stat->file_id; - trav.other.instruction = other_stat->instruction; - trav.other.modtime = other_stat->modtime; - trav.other.size = other_stat->size; - } else { - trav.other.etag = 0; - trav.other.file_id = 0; - trav.other.instruction = CSYNC_INSTRUCTION_NONE; - trav.other.modtime = 0; - trav.other.size = 0; - } - - rc = (*visitor)(&trav, twctx->userdata); - cur->instruction = trav.instruction; - if (trav.etag != cur->etag) { // FIXME It would be nice to have this documented - SAFE_FREE(cur->etag); - cur->etag = c_strdup(trav.etag); - } - - return rc; - } - ctx->status_code = CSYNC_STATUS_PARAM_ERROR; - return -1; -} - -/* - * treewalk function, called from its wrappers below. - * - * it encapsulates the user visitor function, the filter and the userdata - * into a treewalk_context structure and calls the rb treewalk function, - * which calls the local _csync_treewalk_visitor in this module. - * The user visitor is called from there. - */ -static int _csync_walk_tree(CSYNC *ctx, c_rbtree_t *tree, csync_treewalk_visit_func *visitor, int filter) -{ - _csync_treewalk_context tw_ctx; - int rc = -1; - - if (ctx == NULL) { - errno = EBADF; - return rc; - } - - if (visitor == NULL || tree == NULL) { - ctx->status_code = CSYNC_STATUS_PARAM_ERROR; - return rc; - } - - tw_ctx.userdata = ctx->callbacks.userdata; - tw_ctx.user_visitor = visitor; - tw_ctx.instruction_filter = filter; - - ctx->callbacks.userdata = &tw_ctx; - - rc = c_rbtree_walk(tree, (void*) ctx, _csync_treewalk_visitor); - if( rc < 0 ) { - if( ctx->status_code == CSYNC_STATUS_OK ) - ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_TREE_ERROR); - } - ctx->callbacks.userdata = tw_ctx.userdata; - - return rc; -} - -/* - * wrapper function for treewalk on the remote tree - */ -int csync_walk_remote_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter) -{ - c_rbtree_t *tree = NULL; - int rc = -1; - - if(ctx != NULL) { - ctx->status_code = CSYNC_STATUS_OK; - ctx->current = REMOTE_REPLICA; - tree = ctx->remote.tree; - } - - /* all error handling in the called function */ - rc = _csync_walk_tree(ctx, tree, visitor, filter); - return rc; -} - -/* - * wrapper function for treewalk on the local tree - */ -int csync_walk_local_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter) -{ - c_rbtree_t *tree = NULL; - int rc = -1; - - if (ctx != NULL) { - ctx->status_code = CSYNC_STATUS_OK; - ctx->current = LOCAL_REPLICA; - tree = ctx->local.tree; - } - - /* all error handling in the called function */ - rc = _csync_walk_tree(ctx, tree, visitor, filter); - return rc; -} - -static void _tree_destructor(void *data) { - csync_file_stat_t *freedata = NULL; - - freedata = (csync_file_stat_t *) data; - csync_file_stat_free(freedata); -} - -/* reset all the list to empty. - * used by csync_commit and csync_destroy */ -static void _csync_clean_ctx(CSYNC *ctx) -{ - /* destroy the rbtrees */ - if (c_rbtree_size(ctx->local.tree) > 0) { - c_rbtree_destroy(ctx->local.tree, _tree_destructor); - } - - if (c_rbtree_size(ctx->remote.tree) > 0) { - c_rbtree_destroy(ctx->remote.tree, _tree_destructor); - } - - csync_rename_destroy(ctx); - - /* free memory */ - c_rbtree_free(ctx->local.tree); - c_rbtree_free(ctx->remote.tree); - - SAFE_FREE(ctx->remote.root_perms); -} - -int csync_commit(CSYNC *ctx) { - int rc = 0; - - if (ctx == NULL) { - return -1; - } - - ctx->status_code = CSYNC_STATUS_OK; - - if (ctx->statedb.db != NULL - && csync_statedb_close(ctx) < 0) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "ERR: closing of statedb failed."); - rc = -1; - } - ctx->statedb.db = NULL; - - _csync_clean_ctx(ctx); - - ctx->remote.read_from_db = 0; - ctx->read_remote_from_db = true; - ctx->db_is_empty = false; - - - /* Create new trees */ - c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp); - c_rbtree_create(&ctx->remote.tree, _key_cmp, _data_cmp); - - - ctx->status = CSYNC_STATUS_INIT; - SAFE_FREE(ctx->error_string); - - rc = 0; - return rc; -} - -int csync_destroy(CSYNC *ctx) { - int rc = 0; - - if (ctx == NULL) { - errno = EBADF; - return -1; - } - ctx->status_code = CSYNC_STATUS_OK; - - if (ctx->statedb.db != NULL - && csync_statedb_close(ctx) < 0) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "ERR: closing of statedb failed."); - rc = -1; - } - ctx->statedb.db = NULL; - - _csync_clean_ctx(ctx); - - SAFE_FREE(ctx->statedb.file); - SAFE_FREE(ctx->local.uri); - SAFE_FREE(ctx->error_string); - - SAFE_FREE(ctx); - - return rc; -} - -void *csync_get_userdata(CSYNC *ctx) { - if (ctx == NULL) { - return NULL; - } - return ctx->callbacks.userdata; -} - -int csync_set_userdata(CSYNC *ctx, void *userdata) { - if (ctx == NULL) { - return -1; - } - - ctx->callbacks.userdata = userdata; - - return 0; -} - -csync_auth_callback csync_get_auth_callback(CSYNC *ctx) { - if (ctx == NULL) { - return NULL; - } - - return ctx->callbacks.auth_function; -} - -int csync_set_status(CSYNC *ctx, int status) { - if (ctx == NULL || status < 0) { - return -1; - } - - ctx->status = status; - - return 0; -} - -CSYNC_STATUS csync_get_status(CSYNC *ctx) { - if (ctx == NULL) { - return -1; - } - - return ctx->status_code; -} - -const char *csync_get_status_string(CSYNC *ctx) -{ - return csync_vio_get_status_string(ctx); -} - -void csync_request_abort(CSYNC *ctx) -{ - if (ctx != NULL) { - ctx->abort = true; - } -} - -void csync_resume(CSYNC *ctx) -{ - if (ctx != NULL) { - ctx->abort = false; - } -} - -int csync_abort_requested(CSYNC *ctx) -{ - if (ctx != NULL) { - return ctx->abort; - } else { - return (1 == 0); - } -} - -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->checksumHeader); - SAFE_FREE(st); - } -} diff --git a/csync/src/csync.h b/csync/src/csync.h deleted file mode 100644 index daf778c24..000000000 --- a/csync/src/csync.h +++ /dev/null @@ -1,515 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * 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 csync.h - * - * @brief Application developer interface for csync. - * - * @defgroup csyncPublicAPI csync public API - * - * @{ - */ - -#ifndef _CSYNC_H -#define _CSYNC_H - -#include "std/c_private.h" -#include "ocsynclib.h" -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -enum csync_status_codes_e { - CSYNC_STATUS_OK = 0, - - CSYNC_STATUS_ERROR = 1024, /* don't use this code, - */ - CSYNC_STATUS_UNSUCCESSFUL, /* Unspecific problem happend */ - CSYNC_STATUS_NO_LOCK, /* OBSOLETE does not happen anymore */ - CSYNC_STATUS_STATEDB_LOAD_ERROR, /* Statedb can not be loaded. */ - CSYNC_STATUS_STATEDB_CORRUPTED, /* Statedb is corrupted */ - CSYNC_STATUS_NO_MODULE, /* URL passed to csync does not start with owncloud:// or ownclouds:// */ - CSYNC_STATUS_TIMESKEW, /* OBSOLETE */ - CSYNC_STATUS_FILESYSTEM_UNKNOWN, /* UNUSED */ - CSYNC_STATUS_TREE_ERROR, /* csync trees could not be created */ - CSYNC_STATUS_MEMORY_ERROR, /* not enough memory problem */ - CSYNC_STATUS_PARAM_ERROR, /* parameter is zero where not expected */ - CSYNC_STATUS_UPDATE_ERROR, /* general update or discovery error */ - CSYNC_STATUS_RECONCILE_ERROR, /* general reconcile error */ - CSYNC_STATUS_PROPAGATE_ERROR, /* OBSOLETE */ - CSYNC_STATUS_REMOTE_ACCESS_ERROR, /* UNUSED */ - CSYNC_STATUS_REMOTE_CREATE_ERROR, /* UNUSED */ - CSYNC_STATUS_REMOTE_STAT_ERROR, /* UNUSED */ - CSYNC_STATUS_LOCAL_CREATE_ERROR, /* UNUSED */ - CSYNC_STATUS_LOCAL_STAT_ERROR, /* UNUSED */ - CSYNC_STATUS_PROXY_ERROR, /* UNUSED */ - CSYNC_STATUS_LOOKUP_ERROR, /* Neon fails to find proxy. Almost OBSOLETE */ - CSYNC_STATUS_SERVER_AUTH_ERROR, /* UNUSED */ - CSYNC_STATUS_PROXY_AUTH_ERROR, /* UNUSED */ - CSYNC_STATUS_CONNECT_ERROR, /* neon driven connection failed */ - CSYNC_STATUS_TIMEOUT, /* UNUSED */ - CSYNC_STATUS_HTTP_ERROR, /* UNUSED */ - CSYNC_STATUS_PERMISSION_DENIED, /* */ - CSYNC_STATUS_NOT_FOUND, - CSYNC_STATUS_FILE_EXISTS, - CSYNC_STATUS_OUT_OF_SPACE, - CSYNC_STATUS_QUOTA_EXCEEDED, /* UNUSED */ - CSYNC_STATUS_SERVICE_UNAVAILABLE, - CSYNC_STATUS_STORAGE_UNAVAILABLE, - CSYNC_STATUS_FILE_SIZE_ERROR, - CSYNC_STATUS_CONTEXT_LOST, - CSYNC_STATUS_MERGE_FILETREE_ERROR, - CSYNC_STATUS_CSYNC_STATUS_ERROR, - CSYNC_STATUS_OPENDIR_ERROR, - CSYNC_STATUS_READDIR_ERROR, - CSYNC_STATUS_OPEN_ERROR, - CSYNC_STATUS_ABORTED, - /* Codes for file individual status: */ - CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK, - CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST, - CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS, - CSYNC_STATUS_INDIVIDUAL_TRAILING_SPACE, - CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME, - CYSNC_STATUS_FILE_LOCKED_OR_OPEN, - CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN, - CSYNC_STATUS_INVALID_CHARACTERS, - CSYNC_STATUS_INDIVIDUAL_STAT_FAILED, - CSYNC_STATUS_FORBIDDEN, - CSYNC_STATUS_INDIVIDUAL_TOO_DEEP, - CSYNC_STATUS_INDIVIDUAL_IS_CONFLICT_FILE -}; - -typedef enum csync_status_codes_e CSYNC_STATUS; - -#ifndef likely -# define likely(x) (x) -#endif -#ifndef unlikely -# define unlikely(x) (x) -#endif - -#define CSYNC_STATUS_IS_OK(x) (likely((x) == CSYNC_STATUS_OK)) -#define CSYNC_STATUS_IS_ERR(x) (unlikely((x) >= CSYNC_STATUS_ERROR)) -#define CSYNC_STATUS_IS_EQUAL(x, y) ((x) == (y)) - -/** - * Instruction enum. In the file traversal structure, it describes - * the csync state of a file. - */ -enum csync_instructions_e { - CSYNC_INSTRUCTION_NONE = 0x00000000, /* Nothing to do (UPDATE|RECONCILE) */ - CSYNC_INSTRUCTION_EVAL = 0x00000001, /* There was changed compared to the DB (UPDATE) */ - CSYNC_INSTRUCTION_REMOVE = 0x00000002, /* The file need to be removed (RECONCILE) */ - CSYNC_INSTRUCTION_RENAME = 0x00000004, /* The file need to be renamed (RECONCILE) */ - CSYNC_INSTRUCTION_EVAL_RENAME = 0x00000800, /* The file is new, it is the destination of a rename (UPDATE) */ - CSYNC_INSTRUCTION_NEW = 0x00000008, /* The file is new compared to the db (UPDATE) */ - CSYNC_INSTRUCTION_CONFLICT = 0x00000010, /* The file need to be downloaded because it is a conflict (RECONCILE) */ - CSYNC_INSTRUCTION_IGNORE = 0x00000020, /* The file is ignored (UPDATE|RECONCILE) */ - CSYNC_INSTRUCTION_SYNC = 0x00000040, /* The file need to be pushed to the other remote (RECONCILE) */ - CSYNC_INSTRUCTION_STAT_ERROR = 0x00000080, - CSYNC_INSTRUCTION_ERROR = 0x00000100, - CSYNC_INSTRUCTION_TYPE_CHANGE = 0x00000200, /* Like NEW, but deletes the old entity first (RECONCILE) - Used when the type of something changes from directory to file - or back. */ - CSYNC_INSTRUCTION_UPDATE_METADATA = 0x00000400, /* If the etag has been updated and need to be writen to the db, - but without any propagation (UPDATE|RECONCILE) */ -}; - -enum csync_ftw_type_e { - CSYNC_FTW_TYPE_FILE, - CSYNC_FTW_TYPE_SLINK, - CSYNC_FTW_TYPE_DIR, - CSYNC_FTW_TYPE_SKIP -}; - - -#define FILE_ID_BUF_SIZE 36 - -// 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_HIDDEN = 1 << 1 -}; - -enum csync_vio_file_type_e { - CSYNC_VIO_FILE_TYPE_UNKNOWN, - CSYNC_VIO_FILE_TYPE_REGULAR, - CSYNC_VIO_FILE_TYPE_DIRECTORY, - CSYNC_VIO_FILE_TYPE_FIFO, - CSYNC_VIO_FILE_TYPE_SOCKET, - CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE, - CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE, - CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK -}; - -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_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_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_ETAG = 1 << 17, - 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 { - char *name; - char *etag; // FIXME: Should this be inlined like file_id and perm? - char file_id[FILE_ID_BUF_SIZE+1]; - char *directDownloadUrl; - char *directDownloadCookies; - char remotePerm[REMOTE_PERM_BUF_SIZE+1]; - - time_t atime; - time_t mtime; - time_t ctime; - - int64_t size; - - mode_t mode; - - uint64_t inode; - - int fields; // actually enum csync_vio_file_stat_fields_e fields; - enum csync_vio_file_type_e type; - - enum csync_vio_file_flags_e flags; - - char *original_name; // only set if locale conversion fails - - // For remote file stats: the highest quality checksum the server provided - // in the "SHA1:324315da2143" form. - char *checksumHeader; -}; - -csync_vio_file_stat_t OCSYNC_EXPORT *csync_vio_file_stat_new(void); -csync_vio_file_stat_t OCSYNC_EXPORT *csync_vio_file_stat_copy(csync_vio_file_stat_t *file_stat); - -void OCSYNC_EXPORT csync_vio_file_stat_destroy(csync_vio_file_stat_t *fstat); - -void OCSYNC_EXPORT csync_vio_file_stat_set_file_id( csync_vio_file_stat_t* dst, const char* src ); - -void OCSYNC_EXPORT csync_vio_set_file_id(char* dst, const char *src ); - - -/** - * CSync File Traversal structure. - * - * This structure is passed to the visitor function for every file - * which is seen. - * - */ - -struct csync_tree_walk_file_s { - const char *path; - int64_t size; - int64_t inode; - time_t modtime; - mode_t mode; - enum csync_ftw_type_e type; - enum csync_instructions_e instruction; - - /* For directories: Does it have children that were ignored (hidden or ignore pattern) */ - int has_ignored_files; - - const char *rename_path; - const char *etag; - const char *file_id; - const char *remotePerm; - char *directDownloadUrl; - char *directDownloadCookies; - - const char *checksumHeader; - - struct { - int64_t size; - time_t modtime; - const char *etag; - const char *file_id; - enum csync_instructions_e instruction; - } other; - - CSYNC_STATUS error_status; -}; -typedef struct csync_tree_walk_file_s TREE_WALK_FILE; - -/** - * csync handle - */ -typedef struct csync_s CSYNC; - -typedef int (*csync_auth_callback) (const char *prompt, char *buf, size_t len, - int echo, int verify, void *userdata); - -typedef void (*csync_log_callback) (int verbosity, - const char *function, - const char *buffer); - -typedef void (*csync_update_callback) (bool local, - const char *dirUrl, - void *userdata); - -typedef void csync_vio_handle_t; -typedef csync_vio_handle_t* (*csync_vio_opendir_hook) (const char *url, - void *userdata); -typedef csync_vio_file_stat_t* (*csync_vio_readdir_hook) (csync_vio_handle_t *dhhandle, - void *userdata); -typedef void (*csync_vio_closedir_hook) (csync_vio_handle_t *dhhandle, - void *userdata); -typedef int (*csync_vio_stat_hook) (csync_vio_handle_t *dhhandle, - void *userdata); - -/* Compute the checksum of the given \a checksumTypeId for \a path. */ -typedef const char *(*csync_checksum_hook)( - const char *path, const char *otherChecksumHeader, void *userdata); - -/** - * @brief Allocate a csync context. - * - * @param csync The context variable to allocate. - */ -void OCSYNC_EXPORT csync_create(CSYNC **csync, const char *local); - -/** - * @brief Initialize the file synchronizer. - * - * This function loads the configuration - * - * @param ctx The context to initialize. - */ -void OCSYNC_EXPORT csync_init(CSYNC *ctx, const char *db_file); - -/** - * @brief Update detection - * - * @param ctx The context to run the update detection on. - * - * @return 0 on success, less than 0 if an error occurred. - */ -int OCSYNC_EXPORT csync_update(CSYNC *ctx); - -/** - * @brief Reconciliation - * - * @param ctx The context to run the reconciliation on. - * - * @return 0 on success, less than 0 if an error occurred. - */ -int OCSYNC_EXPORT csync_reconcile(CSYNC *ctx); - -/** - * @brief Re-initializes the csync context - * - * @param ctx The context to commit. - * - * @return 0 on success, less than 0 if an error occurred. - */ -int OCSYNC_EXPORT csync_commit(CSYNC *ctx); - -/** - * @brief Destroy the csync context - * - * frees the memory. - * - * @param ctx The context to destroy. - * - * @return 0 on success, less than 0 if an error occurred. - */ -int OCSYNC_EXPORT csync_destroy(CSYNC *ctx); - -/** - * @brief Get the userdata saved in the context. - * - * @param ctx The csync context. - * - * @return The userdata saved in the context, NULL if an error - * occurred. - */ -void *csync_get_userdata(CSYNC *ctx); - -/** - * @brief Save userdata to the context which is passed to the auth - * callback function. - * - * @param ctx The csync context. - * - * @param userdata The userdata to be stored in the context. - * - * @return 0 on success, less than 0 if an error occurred. - */ -int OCSYNC_EXPORT csync_set_userdata(CSYNC *ctx, void *userdata); - -/** - * @brief Get the authentication callback set. - * - * @param ctx The csync context. - * - * @return The authentication callback set or NULL if an error - * occurred. - */ -csync_auth_callback OCSYNC_EXPORT csync_get_auth_callback(CSYNC *ctx); - -/** - * @brief Set the authentication callback. - * - * @param ctx The csync context. - * - * @param cb The authentication callback. - * - * @return 0 on success, less than 0 if an error occurred. - */ -int OCSYNC_EXPORT csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb); - -/** - * @brief Set the log level. - * - * @param[in] level The log verbosity. - * - * @return 0 on success, < 0 if an error occurred. - */ -int OCSYNC_EXPORT csync_set_log_level(int level); - -/** - * @brief Get the log verbosity - * - * @return The log verbosity, -1 on error. - */ -int OCSYNC_EXPORT csync_get_log_level(void); - -/** - * @brief Get the logging callback set. - * - * @return The logging callback set or NULL if an error - * occurred. - */ -csync_log_callback OCSYNC_EXPORT csync_get_log_callback(void); - -/** - * @brief Set the logging callback. - * - * @param cb The logging callback. - * - * @return 0 on success, less than 0 if an error occurred. - */ -int OCSYNC_EXPORT csync_set_log_callback(csync_log_callback cb); - -/* Used for special modes or debugging */ -CSYNC_STATUS OCSYNC_EXPORT csync_get_status(CSYNC *ctx); - -/* Used for special modes or debugging */ -int OCSYNC_EXPORT csync_set_status(CSYNC *ctx, int status); - -typedef int csync_treewalk_visit_func(TREE_WALK_FILE* ,void*); - -/** - * @brief Walk the local file tree and call a visitor function for each file. - * - * @param ctx The csync context. - * @param visitor A callback function to handle the file info. - * @param filter A filter, built from or'ed csync_instructions_e - * - * @return 0 on success, less than 0 if an error occurred. - */ -int OCSYNC_EXPORT csync_walk_local_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter); - -/** - * @brief Walk the remote file tree and call a visitor function for each file. - * - * @param ctx The csync context. - * @param visitor A callback function to handle the file info. - * @param filter A filter, built from and'ed csync_instructions_e - * - * @return 0 on success, less than 0 if an error occurred. - */ -int OCSYNC_EXPORT csync_walk_remote_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter); - -/** - * @brief Get the csync status string. - * - * @param ctx The csync context. - * - * @return A const pointer to a string with more precise status info. - */ -const char OCSYNC_EXPORT *csync_get_status_string(CSYNC *ctx); - -/** - * @brief Aborts the current sync run as soon as possible. Can be called from another thread. - * - * @param ctx The csync context. - */ -void OCSYNC_EXPORT csync_request_abort(CSYNC *ctx); - -/** - * @brief Clears the abort flag. Can be called from another thread. - * - * @param ctx The csync context. - */ -void OCSYNC_EXPORT csync_resume(CSYNC *ctx); - -/** - * @brief Checks for the abort flag, to be used from the modules. - * - * @param ctx The csync context. - */ -int OCSYNC_EXPORT csync_abort_requested(CSYNC *ctx); - -char OCSYNC_EXPORT *csync_normalize_etag(const char *); -time_t OCSYNC_EXPORT oc_httpdate_parse( const char *date ); - -#ifdef __cplusplus -} -#endif - -/** - * }@ - */ -#endif /* _CSYNC_H */ -/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/csync/src/csync_exclude.c b/csync/src/csync_exclude.c deleted file mode 100644 index fea662504..000000000 --- a/csync/src/csync_exclude.c +++ /dev/null @@ -1,437 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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 "config_csync.h" - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include - -#include -#include -#include - -#include "c_lib.h" -#include "c_private.h" - -#include "csync_private.h" -#include "csync_exclude.h" -#include "csync_misc.h" - -#ifdef _WIN32 -#include -#else -#include -#endif - -#define CSYNC_LOG_CATEGORY_NAME "csync.exclude" -#include "csync_log.h" - -#ifndef WITH_TESTING -static -#endif -int _csync_exclude_add(c_strlist_t **inList, const char *string) { - size_t i = 0; - - // We never want duplicates, so check whether the string is already - // in the list first. - if (*inList) { - for (i = 0; i < (*inList)->count; ++i) { - char *pattern = (*inList)->vector[i]; - if (c_streq(pattern, string)) { - return 1; - } - } - } - return c_strlist_add_grow(inList, string); -} - -/** Expands C-like escape sequences. - * - * The returned string is heap-allocated and owned by the caller. - */ -static const char *csync_exclude_expand_escapes(const char * input) -{ - size_t i_len = strlen(input) + 1; - char *out = c_malloc(i_len); // out can only be shorter - - size_t i = 0; - size_t o = 0; - for (; i < i_len; ++i) { - if (input[i] == '\\') { - // at worst input[i+1] is \0 - switch (input[i+1]) { - case '\'': out[o++] = '\''; break; - case '"': out[o++] = '"'; break; - case '?': out[o++] = '?'; break; - case '\\': out[o++] = '\\'; break; - case 'a': out[o++] = '\a'; break; - case 'b': out[o++] = '\b'; break; - case 'f': out[o++] = '\f'; break; - case 'n': out[o++] = '\n'; break; - case 'r': out[o++] = '\r'; break; - case 't': out[o++] = '\t'; break; - case 'v': out[o++] = '\v'; break; - default: - out[o++] = input[i]; - out[o++] = input[i+1]; - break; - } - ++i; - } else { - out[o++] = input[i]; - } - } - return out; -} - -int csync_exclude_load(const char *fname, c_strlist_t **list) { - int fd = -1; - int i = 0; - int rc = -1; - int64_t size; - char *buf = NULL; - char *entry = NULL; - mbchar_t *w_fname; - - if (fname == NULL) { - return -1; - } - -#ifdef _WIN32 - _fmode = _O_BINARY; -#endif - - w_fname = c_utf8_path_to_locale(fname); - if (w_fname == NULL) { - return -1; - } - - fd = _topen(w_fname, O_RDONLY); - c_free_locale_string(w_fname); - if (fd < 0) { - return -1; - } - - size = lseek(fd, 0, SEEK_END); - if (size < 0) { - rc = -1; - goto out; - } - lseek(fd, 0, SEEK_SET); - if (size == 0) { - rc = 0; - goto out; - } - buf = c_malloc(size + 1); - if (read(fd, buf, size) != size) { - rc = -1; - goto out; - } - buf[size] = '\0'; - - /* FIXME: Use fgets and don't add duplicates */ - entry = buf; - for (i = 0; i < size; i++) { - if (buf[i] == '\n' || buf[i] == '\r') { - if (entry != buf + i) { - buf[i] = '\0'; - if (*entry != '#') { - const char *unescaped = csync_exclude_expand_escapes(entry); - rc = _csync_exclude_add(list, unescaped); - if( rc == 0 ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Adding entry: %s", unescaped); - } - SAFE_FREE(unescaped); - if (rc < 0) { - goto out; - } - } - } - entry = buf + i + 1; - } - } - - rc = 0; -out: - SAFE_FREE(buf); - close(fd); - return rc; -} - -// See http://support.microsoft.com/kb/74496 and -// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx -// Additionally, we ignore '$Recycle.Bin', see https://github.com/owncloud/client/issues/2955 -static const char* win_reserved_words[] = {"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", - "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", - "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", "CLOCK$", "$Recycle.Bin" }; - -bool csync_is_windows_reserved_word(const char* filename) { - - size_t win_reserve_words_len = sizeof(win_reserved_words) / sizeof(char*); - size_t j; - - for (j = 0; j < win_reserve_words_len; j++) { - int len_reserved_word = strlen(win_reserved_words[j]); - int len_filename = strlen(filename); - if (len_filename == 2 && filename[1] == ':') { - if (filename[0] >= 'a' && filename[0] <= 'z') { - return true; - } - if (filename[0] >= 'A' && filename[0] <= 'Z') { - return true; - } - } - if (c_strncasecmp(filename, win_reserved_words[j], len_reserved_word) == 0) { - if (len_filename == len_reserved_word) { - return true; - } - if ((len_filename > len_reserved_word) && (filename[len_reserved_word] == '.')) { - return true; - } - } - } - return false; -} - -static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const char *path, int filetype, bool check_leading_dirs) { - size_t i = 0; - const char *bname = NULL; - size_t blen = 0; - char *conflict = NULL; - int rc = -1; - CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED; - CSYNC_EXCLUDE_TYPE type = CSYNC_NOT_EXCLUDED; - - /* split up the path */ - bname = strrchr(path, '/'); - if (bname) { - bname += 1; // don't include the / - } else { - bname = path; - } - blen = strlen(bname); - - rc = csync_fnmatch("._sync_*.db*", bname, 0); - if (rc == 0) { - match = CSYNC_FILE_SILENTLY_EXCLUDED; - goto out; - } - rc = csync_fnmatch(".sync_*.db*", bname, 0); - if (rc == 0) { - match = CSYNC_FILE_SILENTLY_EXCLUDED; - goto out; - } - rc = csync_fnmatch(".csync_journal.db*", bname, 0); - if (rc == 0) { - match = CSYNC_FILE_SILENTLY_EXCLUDED; - goto out; - } - - // check the strlen and ignore the file if its name is longer than 254 chars. - // whenever changing this also check createDownloadTmpFileName - if (blen > 254) { - match = CSYNC_FILE_EXCLUDE_LONG_FILENAME; - goto out; - } - -#ifdef _WIN32 - // Windows cannot sync files ending in spaces (#2176). It also cannot - // distinguish files ending in '.' from files without an ending, - // as '.' is a separator that is not stored internally, so let's - // not allow to sync those to avoid file loss/ambiguities (#416) - if (blen > 1) { - if (bname[blen-1]== ' ') { - match = CSYNC_FILE_EXCLUDE_TRAILING_SPACE; - goto out; - } else if (bname[blen-1]== '.' ) { - match = CSYNC_FILE_EXCLUDE_INVALID_CHAR; - goto out; - } - } - - if (csync_is_windows_reserved_word(bname)) { - match = CSYNC_FILE_EXCLUDE_INVALID_CHAR; - goto out; - } - - // Filter out characters not allowed in a filename on windows - const char *p = NULL; - for (p = path; *p; p++) { - switch (*p) { - case '\\': - case ':': - case '?': - case '*': - case '"': - case '>': - case '<': - case '|': - match = CSYNC_FILE_EXCLUDE_INVALID_CHAR; - goto out; - default: - break; - } - } -#endif - - /* We create a desktop.ini on Windows for the sidebar icon, make sure we don't sync them. */ - rc = csync_fnmatch("Desktop.ini", bname, 0); - if (rc == 0) { - match = CSYNC_FILE_SILENTLY_EXCLUDED; - goto out; - } - - rc = csync_fnmatch(".owncloudsync.log*", bname, 0); - if (rc == 0) { - match = CSYNC_FILE_SILENTLY_EXCLUDED; - goto out; - } - - /* Always ignore conflict files, not only via the exclude list */ - rc = csync_fnmatch("*_conflict-*", bname, 0); - if (rc == 0) { - match = CSYNC_FILE_EXCLUDE_CONFLICT; - goto out; - } - - if (getenv("CSYNC_CONFLICT_FILE_USERNAME")) { - rc = asprintf(&conflict, "*_conflict_%s-*", getenv("CSYNC_CONFLICT_FILE_USERNAME")); - if (rc < 0) { - goto out; - } - rc = csync_fnmatch(conflict, path, 0); - if (rc == 0) { - match = CSYNC_FILE_EXCLUDE_CONFLICT; - SAFE_FREE(conflict); - goto out; - } - SAFE_FREE(conflict); - } - - if( ! excludes ) { - goto out; - } - - c_strlist_t *path_components = NULL; - if (check_leading_dirs) { - /* Build a list of path components to check. */ - path_components = c_strlist_new(32); - char *path_split = strdup(path); - size_t len = strlen(path_split); - for (i = len; ; --i) { - // read backwards until a path separator is found - if (i != 0 && path_split[i-1] != '/') { - continue; - } - - // check 'basename', i.e. for "/foo/bar/fi" we'd check 'fi', 'bar', 'foo' - if (path_split[i] != 0) { - c_strlist_add_grow(&path_components, path_split + i); - } - - if (i == 0) { - break; - } - - // check 'dirname', i.e. for "/foo/bar/fi" we'd check '/foo/bar', '/foo' - path_split[i-1] = '\0'; - c_strlist_add_grow(&path_components, path_split); - } - SAFE_FREE(path_split); - } - - /* Loop over all exclude patterns and evaluate the given path */ - for (i = 0; match == CSYNC_NOT_EXCLUDED && i < excludes->count; i++) { - bool match_dirs_only = false; - char *pattern = excludes->vector[i]; - - type = CSYNC_FILE_EXCLUDE_LIST; - if (!pattern[0]) { /* empty pattern */ - continue; - } - /* Excludes starting with ']' means it can be cleanup */ - if (pattern[0] == ']') { - ++pattern; - if (filetype == CSYNC_FTW_TYPE_FILE) { - type = CSYNC_FILE_EXCLUDE_AND_REMOVE; - } - } - /* Check if the pattern applies to pathes only. */ - if (pattern[strlen(pattern)-1] == '/') { - if (!check_leading_dirs && filetype == CSYNC_FTW_TYPE_FILE) { - continue; - } - match_dirs_only = true; - pattern[strlen(pattern)-1] = '\0'; /* Cut off the slash */ - } - - /* check if the pattern contains a / and if, compare to the whole path */ - if (strchr(pattern, '/')) { - rc = csync_fnmatch(pattern, path, FNM_PATHNAME); - if( rc == 0 ) { - match = type; - } - /* if the pattern requires a dir, but path is not, its still not excluded. */ - if (match_dirs_only && filetype != CSYNC_FTW_TYPE_DIR) { - match = CSYNC_NOT_EXCLUDED; - } - } - - /* if still not excluded, check each component and leading directory of the path */ - if (match == CSYNC_NOT_EXCLUDED && check_leading_dirs) { - size_t j = 0; - if (match_dirs_only && filetype == CSYNC_FTW_TYPE_FILE) { - j = 1; // skip the first entry, which is bname - } - for (; j < path_components->count; ++j) { - rc = csync_fnmatch(pattern, path_components->vector[j], 0); - if (rc == 0) { - match = type; - break; - } - } - } else if (match == CSYNC_NOT_EXCLUDED && !check_leading_dirs) { - rc = csync_fnmatch(pattern, bname, 0); - if (rc == 0) { - match = type; - } - } - if (match_dirs_only) { - /* restore the '/' */ - pattern[strlen(pattern)] = '/'; - } - } - c_strlist_destroy(path_components); - - out: - - return match; -} - -CSYNC_EXCLUDE_TYPE csync_excluded_traversal(c_strlist_t *excludes, const char *path, int filetype) { - return _csync_excluded_common(excludes, path, filetype, false); -} - -CSYNC_EXCLUDE_TYPE csync_excluded_no_ctx(c_strlist_t *excludes, const char *path, int filetype) { - return _csync_excluded_common(excludes, path, filetype, true); -} - diff --git a/csync/src/csync_exclude.h b/csync/src/csync_exclude.h deleted file mode 100644 index 722d27cac..000000000 --- a/csync/src/csync_exclude.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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_EXCLUDE_H -#define _CSYNC_EXCLUDE_H - -#include "ocsynclib.h" - -enum csync_exclude_type_e { - CSYNC_NOT_EXCLUDED = 0, - CSYNC_FILE_SILENTLY_EXCLUDED, - CSYNC_FILE_EXCLUDE_AND_REMOVE, - CSYNC_FILE_EXCLUDE_LIST, - CSYNC_FILE_EXCLUDE_INVALID_CHAR, - CSYNC_FILE_EXCLUDE_TRAILING_SPACE, - CSYNC_FILE_EXCLUDE_LONG_FILENAME, - CSYNC_FILE_EXCLUDE_HIDDEN, - CSYNC_FILE_EXCLUDE_STAT_FAILED, - CSYNC_FILE_EXCLUDE_CONFLICT -}; -typedef enum csync_exclude_type_e CSYNC_EXCLUDE_TYPE; - -#ifdef WITH_TESTING -int OCSYNC_EXPORT _csync_exclude_add(c_strlist_t **inList, const char *string); -#endif - -/** - * @brief Load exclude list - * - * @param ctx The context of the synchronizer. - * @param fname The filename to load. - * - * @return 0 on success, -1 if an error occurred with errno set. - */ -int OCSYNC_EXPORT csync_exclude_load(const char *fname, c_strlist_t **list); - -/** - * @brief Check if the given path should be excluded in a traversal situation. - * - * It does only part of the work that csync_excluded does because it's assumed - * that all leading directories have been run through csync_excluded_traversal() - * before. This can be significantly faster. - * - * That means for '/foo/bar/file' only ('/foo/bar/file', 'file') is checked - * against the exclude patterns. - * - * @param ctx The synchronizer context. - * @param path The patch to check. - * - * @return 2 if excluded and needs cleanup, 1 if excluded, 0 if not. - */ -CSYNC_EXCLUDE_TYPE csync_excluded_traversal(c_strlist_t *excludes, const char *path, int filetype); - -/** - * @brief csync_excluded_no_ctx - * @param excludes - * @param path - * @param filetype - * @return - */ -CSYNC_EXCLUDE_TYPE OCSYNC_EXPORT csync_excluded_no_ctx(c_strlist_t *excludes, const char *path, int filetype); -#endif /* _CSYNC_EXCLUDE_H */ - -/** - * @brief Checks if filename is considered reserved by Windows - * @param file_name filename - * @return true if file is reserved, false otherwise - */ -bool csync_is_windows_reserved_word(const char *file_name); - - -/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/csync/src/csync_log.c b/csync/src/csync_log.c deleted file mode 100644 index 4a2e24a32..000000000 --- a/csync/src/csync_log.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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 "config_csync.h" - -#include -#include -#include - -#include "csync_private.h" -#include "csync_log.h" - -CSYNC_THREAD int csync_log_level; -CSYNC_THREAD csync_log_callback csync_log_cb; - -void csync_log(int verbosity, - const char *function, - const char *format, ...) -{ - csync_log_callback log_fn = csync_get_log_callback(); - if (log_fn && verbosity <= csync_get_log_level()) { - char buffer[1024]; - va_list va; - - va_start(va, format); - vsnprintf(buffer, sizeof(buffer), format, va); - va_end(va); - - log_fn(verbosity, function, buffer); - return; - } -} - -int csync_set_log_level(int level) { - if (level < 0) { - return -1; - } - - csync_log_level = level; - - return 0; -} - -int csync_get_log_level(void) { - return csync_log_level; -} - -int csync_set_log_callback(csync_log_callback cb) { - if (cb == NULL) { - return -1; - } - - csync_log_cb = cb; - - return 0; -} - -csync_log_callback csync_get_log_callback(void) { - return csync_log_cb; -} diff --git a/csync/src/csync_log.h b/csync/src/csync_log.h deleted file mode 100644 index 0cd0d01fc..000000000 --- a/csync/src/csync_log.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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 csync_log.h - * - * @brief Logging interface of csync - * - * @defgroup csyncLogInternals csync logging internals - * @ingroup csyncInternalAPI - * - * @{ - */ - -#ifndef _CSYNC_LOG_H -#define _CSYNC_LOG_H - -/* GCC have printf type attribute check. */ -#ifndef PRINTF_ATTRIBUTE -#ifdef __GNUC__ -#ifdef _WIN32 -#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__gnu_printf__, a, b))) -#else -#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b))) -#endif -#else -#define PRINTF_ATTRIBUTE(a,b) -#endif /* __GNUC__ */ -#endif /* ndef PRINTF_ATTRIBUTE */ - -enum csync_log_priority_e { - CSYNC_LOG_PRIORITY_NOLOG = 0, - CSYNC_LOG_PRIORITY_FATAL, - CSYNC_LOG_PRIORITY_ALERT, - CSYNC_LOG_PRIORITY_CRIT, - CSYNC_LOG_PRIORITY_ERROR, - CSYNC_LOG_PRIORITY_WARN, - CSYNC_LOG_PRIORITY_NOTICE, - CSYNC_LOG_PRIORITY_INFO, - CSYNC_LOG_PRIORITY_DEBUG, - CSYNC_LOG_PRIORITY_TRACE, - CSYNC_LOG_PRIORITY_NOTSET, - CSYNC_LOG_PRIORITY_UNKNOWN, -}; - -#define CSYNC_LOG(priority, ...) \ - csync_log(priority, __func__, __VA_ARGS__) - -void csync_log(int verbosity, - const char *function, - const char *format, ...) PRINTF_ATTRIBUTE(3, 4); - -/** - * }@ - */ -#endif /* _CSYNC_LOG_H */ - -/* vim: set ft=c.doxygen ts=4 sw=4 et cindent: */ diff --git a/csync/src/csync_macros.h b/csync/src/csync_macros.h deleted file mode 100644 index f128b434d..000000000 --- a/csync/src/csync_macros.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * cynapses libc functions - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * 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_MACROS_H -#define _CSYNC_MACROS_H - -#include -#include - -/* How many elements there are in a static array */ -#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) - -/* Some special custom errno values to report bugs properly. The BASE value - * should always be larger than the highest system errno. */ -#define CSYNC_CUSTOM_ERRNO_BASE 10000 - -#define ERRNO_GENERAL_ERROR CSYNC_CUSTOM_ERRNO_BASE+2 -#define ERRNO_LOOKUP_ERROR CSYNC_CUSTOM_ERRNO_BASE+3 -#define ERRNO_USER_UNKNOWN_ON_SERVER CSYNC_CUSTOM_ERRNO_BASE+4 -#define ERRNO_PROXY_AUTH CSYNC_CUSTOM_ERRNO_BASE+5 -#define ERRNO_CONNECT CSYNC_CUSTOM_ERRNO_BASE+6 -#define ERRNO_TIMEOUT CSYNC_CUSTOM_ERRNO_BASE+7 -#define ERRNO_PRECONDITION CSYNC_CUSTOM_ERRNO_BASE+8 -#define ERRNO_RETRY CSYNC_CUSTOM_ERRNO_BASE+9 -#define ERRNO_REDIRECT CSYNC_CUSTOM_ERRNO_BASE+10 -#define ERRNO_WRONG_CONTENT CSYNC_CUSTOM_ERRNO_BASE+11 -#define ERRNO_ERROR_STRING CSYNC_CUSTOM_ERRNO_BASE+13 -#define ERRNO_SERVICE_UNAVAILABLE CSYNC_CUSTOM_ERRNO_BASE+14 -#define ERRNO_USER_ABORT CSYNC_CUSTOM_ERRNO_BASE+16 -#define ERRNO_STORAGE_UNAVAILABLE CSYNC_CUSTOM_ERRNO_BASE+17 -#define ERRNO_FORBIDDEN CSYNC_CUSTOM_ERRNO_BASE+18 - -#endif /* _CSYNC_MACROS_H */ -/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/csync/src/csync_misc.c b/csync/src/csync_misc.c deleted file mode 100644 index d23236113..000000000 --- a/csync/src/csync_misc.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * 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 "config_csync.h" - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include -#include - -#if _WIN32 -# ifndef _WIN32_IE -# define _WIN32_IE 0x0501 // SHGetSpecialFolderPath -# endif -# include -#else /* _WIN32 */ -# include -#endif /* _WIN32 */ - -#include "c_lib.h" -#include "csync_misc.h" -#include "csync_macros.h" -#include "csync_log.h" - -#ifdef HAVE_FNMATCH -#include - -int csync_fnmatch(__const char *__pattern, __const char *__name, int __flags) { - return fnmatch(__pattern, __name, __flags); -} - -#else /* HAVE_FNMATCH */ - -#include -int csync_fnmatch(const char *pattern, const char *name, int flags) { - BOOL match; - - (void) flags; - - match = PathMatchSpecA(name, pattern); - - if(match) - return 0; - else - return 1; -} -#endif /* HAVE_FNMATCH */ - -CSYNC_STATUS csync_errno_to_status(int error, CSYNC_STATUS default_status) -{ - CSYNC_STATUS status = CSYNC_STATUS_OK; - - switch (error) { - case 0: - status = CSYNC_STATUS_OK; - break; - /* The custom errnos first. */ - case ERRNO_GENERAL_ERROR: - status = CSYNC_STATUS_UNSUCCESSFUL; - break; - case ERRNO_LOOKUP_ERROR: /* In Neon: Server or proxy hostname lookup failed */ - status = CSYNC_STATUS_LOOKUP_ERROR; - break; - case ERRNO_USER_UNKNOWN_ON_SERVER: /* Neon: User authentication on server failed. */ - status = CSYNC_STATUS_SERVER_AUTH_ERROR; - break; - case ERRNO_PROXY_AUTH: - status = CSYNC_STATUS_PROXY_AUTH_ERROR; /* Neon: User authentication on proxy failed */ - break; - case ERRNO_CONNECT: - status = CSYNC_STATUS_CONNECT_ERROR; /* Network: Connection error */ - break; - case ERRNO_TIMEOUT: - status = CSYNC_STATUS_TIMEOUT; /* Network: Timeout error */ - break; - case ERRNO_SERVICE_UNAVAILABLE: - status = CSYNC_STATUS_SERVICE_UNAVAILABLE; /* Service temporarily down */ - break; - case ERRNO_STORAGE_UNAVAILABLE: - status = CSYNC_STATUS_STORAGE_UNAVAILABLE; /* Storage temporarily unavailable */ - break; - case EFBIG: - status = CSYNC_STATUS_FILE_SIZE_ERROR; /* File larger than 2MB */ - break; - case ERRNO_PRECONDITION: - case ERRNO_RETRY: - case ERRNO_REDIRECT: - case ERRNO_WRONG_CONTENT: - status = CSYNC_STATUS_HTTP_ERROR; - break; - - case EPERM: /* Operation not permitted */ - case EACCES: /* Permission denied */ - status = CSYNC_STATUS_PERMISSION_DENIED; - break; - case ENOENT: /* No such file or directory */ - status = CSYNC_STATUS_NOT_FOUND; - break; - case EAGAIN: /* Try again */ - status = CSYNC_STATUS_TIMEOUT; - break; - case EEXIST: /* File exists */ - status = CSYNC_STATUS_FILE_EXISTS; - break; - case EINVAL: - status = CSYNC_STATUS_PARAM_ERROR; - break; - case ENOSPC: - status = CSYNC_STATUS_OUT_OF_SPACE; - break; - - /* All the remaining basic errnos: */ - case EIO: /* I/O error */ - case ESRCH: /* No such process */ - case EINTR: /* Interrupted system call */ - case ENXIO: /* No such device or address */ - case E2BIG: /* Argument list too long */ - case ENOEXEC: /* Exec format error */ - case EBADF: /* Bad file number */ - case ECHILD: /* No child processes */ - case ENOMEM: /* Out of memory */ - case EFAULT: /* Bad address */ -#ifndef _WIN32 - case ENOTBLK: /* Block device required */ -#endif - case EBUSY: /* Device or resource busy */ - case EXDEV: /* Cross-device link */ - case ENODEV: /* No such device */ - case ENOTDIR: /* Not a directory */ - case EISDIR: /* Is a directory */ - case ENFILE: /* File table overflow */ - case EMFILE: /* Too many open files */ - case ENOTTY: /* Not a typewriter */ -#ifndef _WIN32 - case ETXTBSY: /* Text file busy */ -#endif - case ESPIPE: /* Illegal seek */ - case EROFS: /* Read-only file system */ - case EMLINK: /* Too many links */ - case EPIPE: /* Broken pipe */ - - case ERRNO_ERROR_STRING: - default: - status = default_status; - } - - return status; -} - -/* Remove possible quotes, and also the -gzip at the end - * Remove "-gzip" at the end (cf. https://github.comowncloud/client/issues/1195) - * The caller must take ownership of the resulting string. - */ -char *csync_normalize_etag(const char *etag) -{ - int len = 0; - char *buf = NULL; - if (!etag) - return NULL; - - len = strlen(etag); - /* strip "XXXX-gzip" */ - if(len >= 7 && etag[0] == '"' && c_streq(etag + len - 6, "-gzip\"")) { - etag++; - len -= 7; - } - /* strip leading -gzip */ - if(len >= 5 && c_streq(etag + len - 5, "-gzip")) { - len -= 5; - } - /* strip normal quotes */ - if (etag[0] == '"' && etag[len-1] == '"') { - etag++; - len -= 2; - } - - buf = c_malloc( len+1 ); - strncpy( buf, etag, len ); - buf[len] = '\0'; - return buf; -} - diff --git a/csync/src/csync_misc.h b/csync/src/csync_misc.h deleted file mode 100644 index 6b9f98418..000000000 --- a/csync/src/csync_misc.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * 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_MISC_H -#define _CSYNC_MISC_H - -#include -#include - -#ifdef HAVE_FNMATCH -#include -#else -/* Steal this define to make csync_exclude compile. Note that if fnmatch - * is not defined it's probably Win32 which uses a different implementation - * than fmmatch anyway, which does not care for flags. - **/ -#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ -#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ -#endif - -int csync_fnmatch(const char *pattern, const char *name, int flags); - -/** - * @brief csync_errno_to_status - errno to csync status code - * - * This function tries to convert the value of the current set errno - * to a csync status code. - * - * @return the corresponding csync error code. - */ -CSYNC_STATUS csync_errno_to_status(int error, CSYNC_STATUS default_status); - -#endif /* _CSYNC_MISC_H */ diff --git a/csync/src/csync_private.h b/csync/src/csync_private.h deleted file mode 100644 index 2edc26019..000000000 --- a/csync/src/csync_private.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * cynapses libc functions - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * 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 csync_private.h - * - * @brief Private interface of csync - * - * @defgroup csyncInternalAPI csync internal API - * - * @{ - */ - -#ifndef _CSYNC_PRIVATE_H -#define _CSYNC_PRIVATE_H - -#include -#include -#include - -#include "config_csync.h" -#include "std/c_lib.h" -#include "std/c_private.h" -#include "csync.h" -#include "csync_misc.h" - -#include "csync_macros.h" - -/** - * How deep to scan directories. - */ -#define MAX_DEPTH 100 - -#define CSYNC_STATUS_INIT 1 << 0 -#define CSYNC_STATUS_UPDATE 1 << 1 -#define CSYNC_STATUS_RECONCILE 1 << 2 -#define CSYNC_STATUS_PROPAGATE 1 << 3 - -#define CSYNC_STATUS_DONE (CSYNC_STATUS_INIT | \ - CSYNC_STATUS_UPDATE | \ - CSYNC_STATUS_RECONCILE | \ - CSYNC_STATUS_PROPAGATE) - -enum csync_replica_e { - LOCAL_REPLICA, - REMOTE_REPLICA -}; - -typedef struct csync_file_stat_s csync_file_stat_t; - -/** - * @brief csync public structure - */ -struct csync_s { - struct { - csync_auth_callback auth_function; - void *userdata; - csync_update_callback update_callback; - void *update_callback_userdata; - - /* hooks for checking the white list (uses the update_callback_userdata) */ - int (*checkSelectiveSyncBlackListHook)(void*, const char*); - int (*checkSelectiveSyncNewFolderHook)(void*, const char* /* path */, const char* /* remotePerm */); - - - csync_vio_opendir_hook remote_opendir_hook; - csync_vio_readdir_hook remote_readdir_hook; - csync_vio_closedir_hook remote_closedir_hook; - void *vio_userdata; - - /* hook for comparing checksums of files during discovery */ - csync_checksum_hook checksum_hook; - void *checksum_userdata; - - } callbacks; - c_strlist_t *excludes; - - struct { - char *file; - sqlite3 *db; - int exists; - - sqlite3_stmt* by_hash_stmt; - sqlite3_stmt* by_fileid_stmt; - sqlite3_stmt* by_inode_stmt; - - int lastReturnValue; - } statedb; - - struct { - char *uri; - c_rbtree_t *tree; - enum csync_replica_e type; - } local; - - struct { - c_rbtree_t *tree; - enum csync_replica_e type; - int read_from_db; - 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; - - - /* replica we are currently walking */ - enum csync_replica_e current; - - /* replica we want to work on */ - enum csync_replica_e replica; - - /* Used in the update phase so changes in the sub directories can be notified to - parent directories */ - csync_file_stat_t *current_fs; - - /* csync error code */ - enum csync_status_codes_e status_code; - - char *error_string; - - int status; - volatile int abort; - void *rename_info; - - /** - * Specify if it is allowed to read the remote tree from the DB (default to enabled) - */ - bool read_remote_from_db; - - /** - * If true, the DB is considered empty and all reads are skipped. (default is false) - * This is useful during the initial local discovery as it speeds it up significantly. - */ - bool db_is_empty; - - bool ignore_hidden_files; -}; - - -#ifdef _MSC_VER -#pragma pack(1) -#endif -struct csync_file_stat_s { - uint64_t phash; /* u64 */ - time_t modtime; /* u64 */ - int64_t size; /* u64 */ - size_t pathlen; /* u64 */ - uint64_t inode; /* u64 */ - mode_t mode; /* u32 */ - unsigned int type : 4; - unsigned int child_modified : 1; - unsigned int has_ignored_files : 1; /* specify that a directory, or child directory contains ignored files */ - - char *destpath; /* for renames */ - const char *etag; - char file_id[FILE_ID_BUF_SIZE+1]; /* the ownCloud file id is fixed width in ownCloud. */ - char *directDownloadUrl; - char *directDownloadCookies; - char remotePerm[REMOTE_PERM_BUF_SIZE+1]; - - // In the local tree, this can hold a checksum and its type if it is - // computed during discovery for some reason. - // In the remote tree, this will have the server checksum, if available. - // In both cases, the format is "SHA1:baff". - const char *checksumHeader; - - CSYNC_STATUS error_status; - - enum csync_instructions_e instruction; /* u32 */ - char path[1]; /* u8 */ -} -#if !defined(__SUNPRO_C) && !defined(_MSC_VER) -__attribute__ ((packed)) -#endif -#ifdef _MSC_VER -#pragma pack() -#endif -; - -OCSYNC_EXPORT void csync_file_stat_free(csync_file_stat_t *st); - -/* - * context for the treewalk function - */ -struct _csync_treewalk_context_s -{ - csync_treewalk_visit_func *user_visitor; - int instruction_filter; - void *userdata; -}; -typedef struct _csync_treewalk_context_s _csync_treewalk_context; - -void set_errno_from_http_errcode( int err ); - -/** - * }@ - */ -#endif /* _CSYNC_PRIVATE_H */ -/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/csync/src/csync_reconcile.c b/csync/src/csync_reconcile.c deleted file mode 100644 index 59156e800..000000000 --- a/csync/src/csync_reconcile.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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 "config_csync.h" - -#include -#include "csync_private.h" -#include "csync_reconcile.h" -#include "csync_util.h" -#include "csync_statedb.h" -#include "csync_rename.h" -#include "c_jhash.h" - -#define CSYNC_LOG_CATEGORY_NAME "csync.reconciler" -#include "csync_log.h" - -#include "inttypes.h" - -/* Check if a file is ignored because one parent is ignored. - * return the node of the ignored directoy if it's the case, or NULL if it is not ignored */ -static c_rbnode_t *_csync_check_ignored(c_rbtree_t *tree, const char *path, int pathlen) { - uint64_t h = 0; - c_rbnode_t *node = NULL; - - /* compute the size of the parent directory */ - int parentlen = pathlen - 1; - while (parentlen > 0 && path[parentlen] != '/') { - parentlen--; - } - if (parentlen <= 0) { - return NULL; - } - - h = c_jhash64((uint8_t *) path, parentlen, 0); - node = c_rbtree_find(tree, &h); - if (node) { - csync_file_stat_t *n = (csync_file_stat_t*)node->data; - if (n->instruction == CSYNC_INSTRUCTION_IGNORE) { - /* Yes, we are ignored */ - return node; - } else { - /* Not ignored */ - return NULL; - } - } else { - /* Try if the parent itself is ignored */ - return _csync_check_ignored(tree, path, parentlen); - } -} - -/* Returns true if we're reasonably certain that hash equality - * for the header means content equality. - * - * Cryptographic safety is not required - this is mainly - * intended to rule out checksums like Adler32 that are not intended for - * hashing and have high likelihood of collision with particular inputs. - */ -static bool _csync_is_collision_safe_hash(const char *checksum_header) -{ - return strncmp(checksum_header, "SHA1:", 5) == 0 - || strncmp(checksum_header, "MD5:", 4) == 0; -} - -/** - * The main function in the reconcile pass. - * - * It's called for each entry in the local and remote rbtrees by - * csync_reconcile() - * - * Before the reconcile phase the trees already know about changes - * relative to the sync journal. This function's job is to spot conflicts - * between local and remote changes and adjust the nodes accordingly. - * - * See doc/dev/sync-algorithm.md for an overview. - * - * - * Older detail comment: - * - * We merge replicas at the file level. The merged replica contains the - * superset of files that are on the local machine and server copies of - * the replica. In the case where the same file is in both the local - * and server copy, the file that was modified most recently is used. - * This means that new files are not deleted, and updated versions of - * existing files are not overwritten. - * - * When a file is updated, the merge algorithm compares the destination - * file with the the source file. If the destination file is newer - * (timestamp is newer), it is not overwritten. If both files, on the - * source and the destination, have been changed, the newer file wins. - */ -static int _csync_merge_algorithm_visitor(void *obj, void *data) { - csync_file_stat_t *cur = NULL; - csync_file_stat_t *other = NULL; - csync_file_stat_t *tmp = NULL; - uint64_t h = 0; - int len = 0; - - CSYNC *ctx = NULL; - c_rbtree_t *tree = NULL; - c_rbnode_t *node = NULL; - - cur = (csync_file_stat_t *) obj; - ctx = (CSYNC *) data; - - /* we need the opposite tree! */ - switch (ctx->current) { - case LOCAL_REPLICA: - tree = ctx->remote.tree; - break; - case REMOTE_REPLICA: - tree = ctx->local.tree; - break; - default: - break; - } - - node = c_rbtree_find(tree, &cur->phash); - - if (!node) { - /* Check the renamed path as well. */ - char *renamed_path = csync_rename_adjust_path(ctx, cur->path); - if (!c_streq(renamed_path, cur->path)) { - len = strlen( renamed_path ); - h = c_jhash64((uint8_t *) renamed_path, len, 0); - node = c_rbtree_find(tree, &h); - } - SAFE_FREE(renamed_path); - } - if (!node) { - /* Check if it is ignored */ - node = _csync_check_ignored(tree, cur->path, cur->pathlen); - /* If it is ignored, other->instruction will be IGNORE so this one will also be ignored */ - } - - /* file only found on current replica */ - if (node == NULL) { - switch(cur->instruction) { - /* file has been modified */ - case CSYNC_INSTRUCTION_EVAL: - cur->instruction = CSYNC_INSTRUCTION_NEW; - break; - /* file has been removed on the opposite replica */ - case CSYNC_INSTRUCTION_NONE: - case CSYNC_INSTRUCTION_UPDATE_METADATA: - if (cur->has_ignored_files) { - /* Do not remove a directory that has ignored files */ - break; - } - if (cur->child_modified) { - /* re-create directory that has modified contents */ - cur->instruction = CSYNC_INSTRUCTION_NEW; - break; - } - cur->instruction = CSYNC_INSTRUCTION_REMOVE; - break; - case CSYNC_INSTRUCTION_EVAL_RENAME: - if(ctx->current == LOCAL_REPLICA ) { - /* use the old name to find the "other" node */ - tmp = csync_statedb_get_stat_by_inode(ctx, cur->inode); - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Finding opposite temp through inode %" PRIu64 ": %s", - cur->inode, tmp ? "true":"false"); - } else if( ctx->current == REMOTE_REPLICA ) { - tmp = csync_statedb_get_stat_by_file_id(ctx, cur->file_id); - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Finding opposite temp through file ID %s: %s", - cur->file_id, tmp ? "true":"false"); - } else { - CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Unknown replica..."); - } - - if( tmp ) { - len = strlen( tmp->path ); - if( len > 0 ) { - h = c_jhash64((uint8_t *) tmp->path, len, 0); - /* First, check that the file is NOT in our tree (another file with the same name was added) */ - node = c_rbtree_find(ctx->current == REMOTE_REPLICA ? ctx->remote.tree : ctx->local.tree, &h); - if (node) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Origin found in our tree : %s", tmp->path); - } else { - /* Find the temporar file in the other tree. */ - node = c_rbtree_find(tree, &h); - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "PHash of temporary opposite (%s): %" PRIu64 " %s", - tmp->path , h, node ? "found": "not found" ); - if (node) { - other = (csync_file_stat_t*)node->data; - } else { - /* the renamed file could not be found in the opposite tree. That is because it - * is not longer existing there, maybe because it was renamed or deleted. - * The journal is cleaned up later after propagation. - */ - } - } - } - - if(!other) { - cur->instruction = CSYNC_INSTRUCTION_NEW; - } else if (other->instruction == CSYNC_INSTRUCTION_NONE - || other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA - || cur->type == CSYNC_FTW_TYPE_DIR) { - other->instruction = CSYNC_INSTRUCTION_RENAME; - other->destpath = c_strdup( cur->path ); - if( !c_streq(cur->file_id, "") ) { - csync_vio_set_file_id( other->file_id, cur->file_id ); - } - other->inode = cur->inode; - cur->instruction = CSYNC_INSTRUCTION_NONE; - } else if (other->instruction == CSYNC_INSTRUCTION_REMOVE) { - other->instruction = CSYNC_INSTRUCTION_RENAME; - other->destpath = c_strdup( cur->path ); - - if( !c_streq(cur->file_id, "") ) { - csync_vio_set_file_id( other->file_id, cur->file_id ); - } - other->inode = cur->inode; - cur->instruction = CSYNC_INSTRUCTION_NONE; - } else if (other->instruction == CSYNC_INSTRUCTION_NEW) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "OOOO=> NEW detected in other tree!"); - cur->instruction = CSYNC_INSTRUCTION_CONFLICT; - } else { - assert(other->type != CSYNC_FTW_TYPE_DIR); - cur->instruction = CSYNC_INSTRUCTION_NONE; - other->instruction = CSYNC_INSTRUCTION_SYNC; - } - csync_file_stat_free(tmp); - } - - break; - default: - break; - } - } else { - bool is_conflict = true; - /* - * file found on the other replica - */ - other = (csync_file_stat_t *) node->data; - - switch (cur->instruction) { - case CSYNC_INSTRUCTION_UPDATE_METADATA: - if (other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA && ctx->current == LOCAL_REPLICA) { - // Remote wins, the SyncEngine will pick relevant local metadata since the remote tree is walked last. - cur->instruction = CSYNC_INSTRUCTION_NONE; - } - break; - case CSYNC_INSTRUCTION_EVAL_RENAME: - /* If the file already exist on the other side, we have a conflict. - Abort the rename and consider it is a new file. */ - cur->instruction = CSYNC_INSTRUCTION_NEW; - /* fall trough */ - /* file on current replica is changed or new */ - case CSYNC_INSTRUCTION_EVAL: - case CSYNC_INSTRUCTION_NEW: - // This operation is usually a no-op and will by default return false - if (csync_file_locked_or_open(ctx->local.uri, cur->path)) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "[Reconciler] IGNORING file %s/%s since it is locked / open", ctx->local.uri, cur->path); - cur->instruction = CSYNC_INSTRUCTION_ERROR; - if (cur->error_status == CSYNC_STATUS_OK) // don't overwrite error - cur->error_status = CYSNC_STATUS_FILE_LOCKED_OR_OPEN; - break; - } else { - //CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "[Reconciler] not ignoring file %s/%s", ctx->local.uri, cur->path); - } - switch (other->instruction) { - /* file on other replica is changed or new */ - case CSYNC_INSTRUCTION_NEW: - case CSYNC_INSTRUCTION_EVAL: - if (other->type == CSYNC_FTW_TYPE_DIR && - cur->type == CSYNC_FTW_TYPE_DIR) { - // Folders of the same path are always considered equals - is_conflict = false; - } else { - // If the size or mtime is different, it's definitely a conflict. - is_conflict = ((other->size != cur->size) || (other->modtime != cur->modtime)); - - // It could be a conflict even if size and mtime match! - // - // In older client versions we always treated these cases as a - // non-conflict. This behavior is preserved in case the server - // doesn't provide a suitable content hash. - // - // When it does have one, however, we do create a job, but the job - // will compare hashes and avoid the download if they are equal. - const char *remoteChecksumHeader = - (ctx->current == REMOTE_REPLICA ? cur->checksumHeader : other->checksumHeader); - if (remoteChecksumHeader) { - is_conflict |= _csync_is_collision_safe_hash(remoteChecksumHeader); - } - - // SO: If there is no checksum, we can have !is_conflict here - // even though the files have different content! This is an - // intentional tradeoff. Downloading and comparing files would - // be technically correct in this situation but leads to too - // much waste. - // In particular this kind of NEW/NEW situation with identical - // sizes and mtimes pops up when the local database is lost for - // whatever reason. - } - if (ctx->current == REMOTE_REPLICA) { - // If the files are considered equal, only update the DB with the etag from remote - cur->instruction = is_conflict ? CSYNC_INSTRUCTION_CONFLICT : CSYNC_INSTRUCTION_UPDATE_METADATA; - other->instruction = CSYNC_INSTRUCTION_NONE; - } else { - cur->instruction = CSYNC_INSTRUCTION_NONE; - other->instruction = is_conflict ? CSYNC_INSTRUCTION_CONFLICT : CSYNC_INSTRUCTION_UPDATE_METADATA; - } - - break; - /* file on the other replica has not been modified */ - case CSYNC_INSTRUCTION_NONE: - case CSYNC_INSTRUCTION_UPDATE_METADATA: - if (cur->type != other->type) { - // If the type of the entity changed, it's like NEW, but - // needs to delete the other entity first. - cur->instruction = CSYNC_INSTRUCTION_TYPE_CHANGE; - other->instruction = CSYNC_INSTRUCTION_NONE; - } else if (cur->type == CSYNC_FTW_TYPE_DIR) { - cur->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; - other->instruction = CSYNC_INSTRUCTION_NONE; - } else { - cur->instruction = CSYNC_INSTRUCTION_SYNC; - other->instruction = CSYNC_INSTRUCTION_NONE; - } - break; - case CSYNC_INSTRUCTION_IGNORE: - cur->instruction = CSYNC_INSTRUCTION_IGNORE; - break; - default: - break; - } - default: - break; - } - } - - //hide instruction NONE messages when log level is set to debug, - //only show these messages on log level trace - const char *repo = ctx->current == REMOTE_REPLICA ? "server" : "client"; - if(cur->instruction ==CSYNC_INSTRUCTION_NONE) - { - if(cur->type == CSYNC_FTW_TYPE_DIR) - { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, - "%-30s %s dir: %s", - csync_instruction_str(cur->instruction), - repo, - cur->path); - } - else - { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, - "%-30s %s file: %s", - csync_instruction_str(cur->instruction), - repo, - cur->path); - } - } - else - { - if(cur->type == CSYNC_FTW_TYPE_DIR) - { - CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, - "%-30s %s dir: %s", - csync_instruction_str(cur->instruction), - repo, - cur->path); - } - else - { - CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, - "%-30s %s file: %s", - csync_instruction_str(cur->instruction), - repo, - cur->path); - } - } - - return 0; -} - -int csync_reconcile_updates(CSYNC *ctx) { - int rc; - c_rbtree_t *tree = NULL; - - switch (ctx->current) { - case LOCAL_REPLICA: - tree = ctx->local.tree; - break; - case REMOTE_REPLICA: - tree = ctx->remote.tree; - break; - default: - break; - } - - rc = c_rbtree_walk(tree, (void *) ctx, _csync_merge_algorithm_visitor); - if( rc < 0 ) { - ctx->status_code = CSYNC_STATUS_RECONCILE_ERROR; - } - return rc; -} - -/* vim: set ts=8 sw=2 et cindent: */ diff --git a/csync/src/csync_reconcile.h b/csync/src/csync_reconcile.h deleted file mode 100644 index f333adba6..000000000 --- a/csync/src/csync_reconcile.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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_RECONCILE_H -#define _CSYNC_RECONCILE_H - -/** - * @file csync_reconcile.h - * - * @brief Reconciliation - * - * The most important component is the update detector, because the reconciler - * depends on it. The correctness of reconciler is mandatory because it can - * damage a filesystem. It decides which file: - * - * - stays untouched - * - has a conflict - * - gets synchronized - * - or is deleted. - * - * @defgroup csyncReconcilationInternals csync reconciliation internals - * @ingroup csyncInternalAPI - * - * @{ - */ - -/** - * @brief Reconcile the files. - * - * @param ctx The csync context to use. - * - * @return 0 on success, < 0 on error. - * - * @todo Add an argument to set the algorithm to use. - */ -int OCSYNC_EXPORT csync_reconcile_updates(CSYNC *ctx); - -/** - * }@ - */ -#endif /* _CSYNC_RECONCILE_H */ - -/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/csync/src/csync_rename.cc b/csync/src/csync_rename.cc deleted file mode 100644 index 5cc43ce22..000000000 --- a/csync/src/csync_rename.cc +++ /dev/null @@ -1,102 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2012 by Olivier Goffart - * - * 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 - */ - -extern "C" { -#include "csync_private.h" -#include "csync_rename.h" -} - -#include -#include -#include -#include - -static std::string _parentDir(const std::string &path) { - int len = path.length(); - while(len > 0 && path[len-1]!='/') len--; - while(len > 0 && path[len-1]=='/') len--; - return path.substr(0, len); -} - -struct csync_rename_s { - static csync_rename_s *get(CSYNC *ctx) { - if (!ctx->rename_info) { - ctx->rename_info = new csync_rename_s; - } - return reinterpret_cast(ctx->rename_info); - } - - std::map folder_renamed_to; // map from->to - std::map folder_renamed_from; // map to->from - - struct renameop { - csync_file_stat_t *st; - bool operator<(const renameop &other) const { - return strlen(st->destpath) < strlen(other.st->destpath); - } - }; - std::vector todo; -}; - -extern "C" { -void csync_rename_destroy(CSYNC* ctx) -{ - delete reinterpret_cast(ctx->rename_info); - ctx->rename_info = 0; -} - -void csync_rename_record(CSYNC* ctx, const char* from, const char* to) -{ - csync_rename_s::get(ctx)->folder_renamed_to[from] = to; - csync_rename_s::get(ctx)->folder_renamed_from[to] = from; -} - -char* csync_rename_adjust_path(CSYNC* ctx, const char* path) -{ - csync_rename_s* d = csync_rename_s::get(ctx); - for (std::string p = _parentDir(path); !p.empty(); p = _parentDir(p)) { - std::map< std::string, std::string >::iterator it = d->folder_renamed_to.find(p); - if (it != d->folder_renamed_to.end()) { - std::string rep = it->second + (path + p.length()); - return c_strdup(rep.c_str()); - } - } - return c_strdup(path); -} - -char* csync_rename_adjust_path_source(CSYNC* ctx, const char* path) -{ - csync_rename_s* d = csync_rename_s::get(ctx); - for (std::string p = _parentDir(path); !p.empty(); p = _parentDir(p)) { - std::map< std::string, std::string >::iterator it = d->folder_renamed_from.find(p); - if (it != d->folder_renamed_from.end()) { - std::string rep = it->second + (path + p.length()); - return c_strdup(rep.c_str()); - } - } - return c_strdup(path); -} - -bool csync_rename_count(CSYNC *ctx) { - csync_rename_s* d = csync_rename_s::get(ctx); - return d->folder_renamed_from.size(); -} - -} diff --git a/csync/src/csync_rename.h b/csync/src/csync_rename.h deleted file mode 100644 index 53968324c..000000000 --- a/csync/src/csync_rename.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2012 by Olivier Goffart - * - * 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 - */ - -#pragma once - -#include "csync.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Return the final destination path of a given patch in case of renames */ -char OCSYNC_EXPORT *csync_rename_adjust_path(CSYNC *ctx, const char *path); -/* Return the source of a given path in case of renames */ -char OCSYNC_EXPORT *csync_rename_adjust_path_source(CSYNC *ctx, const char *path); -void OCSYNC_EXPORT csync_rename_destroy(CSYNC *ctx); -void OCSYNC_EXPORT csync_rename_record(CSYNC *ctx, const char *from, const char *to); -/* Return the amount of renamed item recorded */ -bool OCSYNC_EXPORT csync_rename_count(CSYNC *ctx); - -#ifdef __cplusplus -} -#endif diff --git a/csync/src/csync_statedb.c b/csync/src/csync_statedb.c deleted file mode 100644 index 056ca48dd..000000000 --- a/csync/src/csync_statedb.c +++ /dev/null @@ -1,656 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * 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 "config_csync.h" - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "c_lib.h" -#include "csync_private.h" -#include "csync_statedb.h" -#include "csync_util.h" -#include "csync_misc.h" -#include "csync_exclude.h" - -#include "c_string.h" -#include "c_jhash.h" -#include "csync_time.h" - -#define CSYNC_LOG_CATEGORY_NAME "csync.statedb" -#include "csync_log.h" -#include "csync_rename.h" - -#define BUF_SIZE 16 - -#define sqlite_open(A, B) sqlite3_open_v2(A,B, SQLITE_OPEN_READONLY+SQLITE_OPEN_NOMUTEX, NULL) - -#define SQLTM_TIME 150 -#define SQLTM_COUNT 10 - -#define SQLITE_BUSY_HANDLED(F) if(1) { \ - int n = 0; \ - do { rc = F ; \ - if( (rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED) ) { \ - n++; \ - csync_sleep(SQLTM_TIME); \ - } \ - }while( (n < SQLTM_COUNT) && ((rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED))); \ - } - - -void csync_set_statedb_exists(CSYNC *ctx, int val) { - ctx->statedb.exists = val; -} - -int csync_get_statedb_exists(CSYNC *ctx) { - return ctx->statedb.exists; -} - -static int _csync_check_db_integrity(sqlite3 *db) { - c_strlist_t *result = NULL; - int rc = -1; - - result = csync_statedb_query(db, "PRAGMA quick_check;"); - if (result != NULL) { - /* There is a result */ - if (result->count > 0) { - if (c_streq(result->vector[0], "ok")) { - rc = 0; - } - } - c_strlist_destroy(result); - } - - if( sqlite3_threadsafe() == 0 ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "* WARNING: SQLite module is not threadsafe!"); - rc = -1; - } - - return rc; -} - -static int _csync_statedb_is_empty(sqlite3 *db) { - c_strlist_t *result = NULL; - int rc = 0; - - result = csync_statedb_query(db, "SELECT COUNT(phash) FROM metadata LIMIT 1 OFFSET 0;"); - if (result == NULL) { - rc = 1; - } - c_strlist_destroy(result); - - return rc; -} - -#ifndef NDEBUG -static void sqlite_profile( void *x, const char* sql, sqlite3_uint64 time) -{ - (void)x; - CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, - "_SQL_ %s: %llu", sql, time); - -} -#endif - -int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb) { - int rc = -1; - c_strlist_t *result = NULL; - sqlite3 *db = NULL; - - if( !ctx ) { - return -1; - } - - if (ctx->statedb.db) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: DB already open"); - ctx->status_code = CSYNC_STATUS_PARAM_ERROR; - return -1; - } - - ctx->statedb.lastReturnValue = SQLITE_OK; - - /* Openthe database */ - if (sqlite_open(statedb, &db) != SQLITE_OK) { - const char *errmsg= sqlite3_errmsg(ctx->statedb.db); - CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: Failed to sqlite3 open statedb - bail out: %s.", - errmsg ? errmsg : ""); - - rc = -1; - ctx->status_code = CSYNC_STATUS_STATEDB_LOAD_ERROR; - goto out; - } - - if (_csync_check_db_integrity(db) != 0) { - const char *errmsg= sqlite3_errmsg(db); - CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: sqlite3 integrity check failed - bail out: %s.", - errmsg ? errmsg : ""); - rc = -1; - ctx->status_code = CSYNC_STATUS_STATEDB_CORRUPTED; - goto out; - } - - if (_csync_statedb_is_empty(db)) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "statedb contents doesn't exist"); - csync_set_statedb_exists(ctx, 0); - } else { - csync_set_statedb_exists(ctx, 1); - } - - /* Print out the version */ - // - result = csync_statedb_query(db, "SELECT sqlite_version();"); - if (result && result->count >= 1) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3 version \"%s\"", *result->vector); - } - c_strlist_destroy(result); - - /* optimization for speeding up SQLite */ - result = csync_statedb_query(db, "PRAGMA synchronous = NORMAL;"); - c_strlist_destroy(result); - result = csync_statedb_query(db, "PRAGMA case_sensitive_like = ON;"); - c_strlist_destroy(result); - - /* set a busy handler with 5 seconds timeout */ - sqlite3_busy_timeout(db, 5000); - -#ifndef NDEBUG - sqlite3_profile(db, sqlite_profile, 0 ); -#endif - *pdb = db; - - CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Success"); - - return 0; -out: - sqlite3_close(db); - return rc; -} - -int csync_statedb_close(CSYNC *ctx) { - int rc = 0; - - if (!ctx) { - return -1; - } - - /* deallocate query resources */ - if( ctx->statedb.by_fileid_stmt ) { - sqlite3_finalize(ctx->statedb.by_fileid_stmt); - ctx->statedb.by_fileid_stmt = NULL; - } - if( ctx->statedb.by_hash_stmt ) { - sqlite3_finalize(ctx->statedb.by_hash_stmt); - ctx->statedb.by_hash_stmt = NULL; - } - if( ctx->statedb.by_inode_stmt) { - sqlite3_finalize(ctx->statedb.by_inode_stmt); - ctx->statedb.by_inode_stmt = NULL; - } - - ctx->statedb.lastReturnValue = SQLITE_OK; - - int sr = sqlite3_close(ctx->statedb.db); - CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3_close=%d", sr); - - ctx->statedb.db = 0; - - return rc; -} - -#define METADATA_QUERY \ - "phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, " \ - "filesize, ignoredChildrenRemote, " \ - "contentchecksumtype.name || ':' || contentChecksum " \ - "FROM metadata " \ - "LEFT JOIN checksumtype as contentchecksumtype ON metadata.contentChecksumTypeId == contentchecksumtype.id" - -// This funciton parses a line from the metadata table into the given csync_file_stat -// structure which it is also allocating. -// Note that this function calls laso sqlite3_step to actually get the info from db and -// returns the sqlite return type. -static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3_stmt *stmt ) -{ - int rc = SQLITE_ERROR; - int column_count; - int len; - - if( ! stmt ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Fatal: Statement is NULL."); - return SQLITE_ERROR; - } - - column_count = sqlite3_column_count(stmt); - - SQLITE_BUSY_HANDLED( sqlite3_step(stmt) ); - - if( rc == SQLITE_ROW ) { - if(column_count > 7) { - const char *name; - - /* phash, pathlen, path, inode, uid, gid, mode, modtime */ - len = sqlite3_column_int(stmt, 1); - *st = c_malloc(sizeof(csync_file_stat_t) + len + 1); - /* clear the whole structure */ - ZERO_STRUCTP(*st); - - /* The query suceeded so use the phash we pass to the function. */ - (*st)->phash = sqlite3_column_int64(stmt, 0); - - (*st)->pathlen = sqlite3_column_int(stmt, 1); - name = (const char*) sqlite3_column_text(stmt, 2); - memcpy((*st)->path, (len ? name : ""), len + 1); - (*st)->inode = sqlite3_column_int64(stmt,3); - (*st)->mode = sqlite3_column_int(stmt, 6); - (*st)->modtime = strtoul((char*)sqlite3_column_text(stmt, 7), NULL, 10); - - if(*st && column_count > 8 ) { - (*st)->type = sqlite3_column_int(stmt, 8); - } - - if(column_count > 9 && sqlite3_column_text(stmt, 9)) { - (*st)->etag = c_strdup( (char*) sqlite3_column_text(stmt, 9) ); - } - 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); - } - if(column_count > 12 && sqlite3_column_int64(stmt,12)) { - (*st)->size = sqlite3_column_int64(stmt, 12); - } - if(column_count > 13) { - (*st)->has_ignored_files = sqlite3_column_int(stmt, 13); - } - if (column_count > 14 && sqlite3_column_text(stmt, 14)) { - (*st)->checksumHeader = c_strdup((char *)sqlite3_column_text(stmt, 14)); - } - - } - } else { - if( rc != SQLITE_DONE ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Query results in %d", rc); - } - } - return rc; -} - -/* caller must free the memory */ -csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx, - uint64_t phash) -{ - csync_file_stat_t *st = NULL; - int rc; - - if( !ctx || ctx->db_is_empty ) { - return NULL; - } - - if( ctx->statedb.by_hash_stmt == NULL ) { - const char *hash_query = "SELECT " METADATA_QUERY " WHERE phash=?1"; - - SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, hash_query, strlen(hash_query), &ctx->statedb.by_hash_stmt, NULL)); - ctx->statedb.lastReturnValue = rc; - if( rc != SQLITE_OK ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for hash query."); - return NULL; - } - } - - if( ctx->statedb.by_hash_stmt == NULL ) { - return NULL; - } - - sqlite3_bind_int64(ctx->statedb.by_hash_stmt, 1, (long long signed int)phash); - - rc = _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_hash_stmt); - ctx->statedb.lastReturnValue = rc; - if( !(rc == SQLITE_ROW || rc == SQLITE_DONE) ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata: %d!", rc); - } - sqlite3_reset(ctx->statedb.by_hash_stmt); - - return st; -} - -csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx, - const char *file_id ) { - csync_file_stat_t *st = NULL; - int rc = 0; - - if (!file_id) { - return 0; - } - if (c_streq(file_id, "")) { - return 0; - } - - if( !ctx || ctx->db_is_empty ) { - return NULL; - } - - if( ctx->statedb.by_fileid_stmt == NULL ) { - const char *query = "SELECT " METADATA_QUERY " WHERE fileid=?1"; - - SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, query, strlen(query), &ctx->statedb.by_fileid_stmt, NULL)); - ctx->statedb.lastReturnValue = rc; - if( rc != SQLITE_OK ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for file id query."); - return NULL; - } - } - - /* bind the query value */ - sqlite3_bind_text(ctx->statedb.by_fileid_stmt, 1, file_id, -1, SQLITE_STATIC); - - rc = _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_fileid_stmt); - ctx->statedb.lastReturnValue = rc; - if( !(rc == SQLITE_ROW || rc == SQLITE_DONE) ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata: %d!", rc); - } - // clear the resources used by the statement. - sqlite3_reset(ctx->statedb.by_fileid_stmt); - - return st; -} - -/* caller must free the memory */ -csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx, - uint64_t inode) -{ - csync_file_stat_t *st = NULL; - int rc; - - if (!inode) { - return NULL; - } - - if( !ctx || ctx->db_is_empty ) { - return NULL; - } - - if( ctx->statedb.by_inode_stmt == NULL ) { - const char *inode_query = "SELECT " METADATA_QUERY " WHERE inode=?1"; - - SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, inode_query, strlen(inode_query), &ctx->statedb.by_inode_stmt, NULL)); - ctx->statedb.lastReturnValue = rc; - if( rc != SQLITE_OK ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for inode query."); - return NULL; - } - } - - if( ctx->statedb.by_inode_stmt == NULL ) { - return NULL; - } - - sqlite3_bind_int64(ctx->statedb.by_inode_stmt, 1, (long long signed int)inode); - - rc = _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_inode_stmt); - ctx->statedb.lastReturnValue = rc; - if( !(rc == SQLITE_ROW || rc == SQLITE_DONE) ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata by inode: %d!", rc); - } - sqlite3_reset(ctx->statedb.by_inode_stmt); - - return st; -} - -int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) { - int rc; - sqlite3_stmt *stmt = NULL; - int64_t cnt = 0; - - if( !path ) { - return -1; - } - - if( !ctx || ctx->db_is_empty ) { - return -1; - } - - /* Select the entries for anything that starts with (path+'/') - * In other words, anything that is between path+'/' and path+'0', - * (because '0' follows '/' in ascii) - */ - const char *below_path_query = "SELECT " METADATA_QUERY " WHERE path > (?||'/') AND path < (?||'0') ORDER BY path||'/' ASC"; - SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, below_path_query, -1, &stmt, NULL)); - ctx->statedb.lastReturnValue = rc; - if( rc != SQLITE_OK ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for below path query."); - return -1; - } - - if (stmt == NULL) { - return -1; - } - - sqlite3_bind_text(stmt, 1, path, -1, SQLITE_STATIC); - sqlite3_bind_text(stmt, 2, path, -1, SQLITE_STATIC); - - cnt = 0; - - ctx->statedb.lastReturnValue = rc; - do { - csync_file_stat_t *st = NULL; - - rc = _csync_file_stat_from_metadata_table( &st, stmt); - if( st ) { - /* When selective sync is used, the database may have subtrees with a parent - * whose etag (md5) is _invalid_. These are ignored and shall not appear in the - * remote tree. - * Sometimes folders that are not ignored by selective sync get marked as - * _invalid_, but that is not a problem as the next discovery will retrieve - * their correct etags again and we don't run into this case. - */ - if( c_streq(st->etag, "_invalid_") ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s selective sync excluded", st->path); - char *skipbase = c_strdup(st->path); - skipbase[st->pathlen] = '/'; - int skiplen = st->pathlen + 1; - - /* Skip over all entries with the same base path. Note that this depends - * strongly on the ordering of the retrieved items. */ - do { - csync_file_stat_free(st); - rc = _csync_file_stat_from_metadata_table( &st, stmt); - if( st && strncmp(st->path, skipbase, skiplen) != 0 ) { - break; - } - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s selective sync excluded because the parent is", st->path); - } while( rc == SQLITE_ROW ); - - /* End of data? */ - if( rc != SQLITE_ROW || !st ) { - continue; - } - } - - /* Check for exclusion from the tree. - * Note that this is only a safety net in case the ignore list changes - * without a full remote discovery being triggered. */ - CSYNC_EXCLUDE_TYPE excluded = csync_excluded_traversal(ctx->excludes, st->path, st->type); - if (excluded != CSYNC_NOT_EXCLUDED) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded (%d)", st->path, excluded); - - if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE - || excluded == CSYNC_FILE_SILENTLY_EXCLUDED) { - csync_file_stat_free(st); - continue; - } - - st->instruction = CSYNC_INSTRUCTION_IGNORE; - } - - /* store into result list. */ - if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) { - csync_file_stat_free(st); - ctx->status_code = CSYNC_STATUS_TREE_ERROR; - break; - } - cnt++; - } - } while( rc == SQLITE_ROW ); - - ctx->statedb.lastReturnValue = rc; - if( rc != SQLITE_DONE ) { - ctx->status_code = CSYNC_STATUS_TREE_ERROR; - } else { - CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "%" PRId64 " entries read below path %s from db.", cnt, path); - } - sqlite3_finalize(stmt); - - return 0; -} - -/* query the statedb, caller must free the memory */ -c_strlist_t *csync_statedb_query(sqlite3 *db, - const char *statement) { - int err = SQLITE_OK; - int rc = SQLITE_OK; - size_t i = 0; - size_t busy_count = 0; - size_t retry_count = 0; - size_t column_count = 0; - sqlite3_stmt *stmt; - const char *tail = NULL; - const char *field = NULL; - c_strlist_t *result = NULL; - int row = 0; - - do { - /* compile SQL program into a virtual machine, reattempteing if busy */ - do { - if (busy_count) { - csync_sleep(100); - CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3_prepare: BUSY counter: %zu", busy_count); - } - err = sqlite3_prepare(db, statement, -1, &stmt, &tail); - } while (err == SQLITE_BUSY && busy_count ++ < 120); - - if (err != SQLITE_OK) { - if (err == SQLITE_BUSY) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Gave up waiting for lock to clear"); - } - CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, - "sqlite3_compile error: %s - on query %s", - sqlite3_errmsg(db), statement); - break; - } else { - busy_count = 0; - column_count = sqlite3_column_count(stmt); - - /* execute virtual machine by iterating over rows */ - for(;;) { - err = sqlite3_step(stmt); - - if (err == SQLITE_BUSY) { - if (busy_count++ > 120) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Busy counter has reached its maximum. Aborting this sql statement"); - break; - } - csync_sleep(100); - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "sqlite3_step: BUSY counter: %zu", busy_count); - continue; - } - - if (err == SQLITE_MISUSE) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite3_step: MISUSE!!"); - } - - if (err == SQLITE_DONE) { - if (result == NULL) { - result = c_strlist_new(1); - } - break; - } - - if (err == SQLITE_ERROR) { - break; - } - - row++; - if( result ) { - result = c_strlist_expand(result, row*column_count); - } else { - result = c_strlist_new(column_count); - } - - if (result == NULL) { - return NULL; - } - - /* iterate over columns */ - for (i = 0; i < column_count; i++) { - field = (const char *) sqlite3_column_text(stmt, i); - if (!field) - field = ""; - // CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "sqlite3_column_text: %s", field); - if (c_strlist_add(result, field) < 0) { - c_strlist_destroy(result); - return NULL; - } - } - } /* end infinite for loop */ - - /* deallocate vm resources */ - rc = sqlite3_finalize(stmt); - - if (err != SQLITE_DONE && rc != SQLITE_SCHEMA) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite_step error: %s - on query: %s", sqlite3_errmsg(db), statement); - if (result != NULL) { - c_strlist_destroy(result); - } - return NULL; - } - - if (rc == SQLITE_SCHEMA) { - retry_count ++; - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "SQLITE_SCHEMA error occurred on query: %s", statement); - if (retry_count < 10) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Retrying now."); - } else { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "RETRY count has reached its maximum. Aborting statement: %s", statement); - if (result != NULL) { - c_strlist_destroy(result); - } - result = c_strlist_new(1); - } - } - } - } while (rc == SQLITE_SCHEMA && retry_count < 10); - - return result; -} - -/* vim: set ts=8 sw=2 et cindent: */ diff --git a/csync/src/csync_statedb.h b/csync/src/csync_statedb.h deleted file mode 100644 index 601e34a1b..000000000 --- a/csync/src/csync_statedb.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * 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 csync_private.h - * - * @brief Private interface of csync - * - * @defgroup csyncstatedbInternals csync statedb internals - * @ingroup csyncInternalAPI - * - * @{ - */ - -#ifndef _CSYNC_STATEDB_H -#define _CSYNC_STATEDB_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "c_lib.h" -#include "csync_private.h" - -void csync_set_statedb_exists(CSYNC *ctx, int val); - -int csync_get_statedb_exists(CSYNC *ctx); - -/** - * @brief Load the statedb. - * - * This function tries to load the statedb. If it doesn't exists it creates - * the sqlite3 database, but doesn't create the tables. This will be done when - * csync gets destroyed. - * - * @param ctx The csync context. - * @param statedb Path to the statedb file (sqlite3 db). - * - * @return 0 on success, less than 0 if an error occurred with errno set. - */ -OCSYNC_EXPORT int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb); - -OCSYNC_EXPORT int csync_statedb_close(CSYNC *ctx); - -OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx, uint64_t phash); - -OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx, uint64_t inode); - -OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx, const char *file_id); - -/** - * @brief Query all files metadata inside and below a path. - * @param ctx The csync context. - * @param path The path. - * - * This function queries all metadata of all files inside or below the - * given path. The result is a linear string list with a multiple of 9 - * entries. For each result file there are 9 strings which are phash, - * path, inode, uid, gid, mode, modtime, type and md5 (unique id). - * - * Note that not only the files in the given path are part of the result - * but also the files in directories below the given path. Ie. if the - * parameter path is /home/kf/test, we have /home/kf/test/file.txt in - * the result but also /home/kf/test/homework/another_file.txt - * - * @return A stringlist containing a multiple of 9 entries. - */ -int csync_statedb_get_below_path(CSYNC *ctx, const char *path); - -/** - * @brief A generic statedb query. - * - * @param ctx The csync context. - * @param statement The SQL statement to execute - * - * @return A stringlist of the entries of a column. An emtpy stringlist if - * nothing has been found. NULL on error. - */ -c_strlist_t *csync_statedb_query(sqlite3 *db, const char *statement); - -#ifdef __cplusplus -} -#endif - -/** - * }@ - */ -#endif /* _CSYNC_STATEDB_H */ -/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/csync/src/csync_time.c b/csync/src/csync_time.c deleted file mode 100644 index 85bdd5ff4..000000000 --- a/csync/src/csync_time.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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 "config_csync.h" - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include - -#include "csync_time.h" -#include "vio/csync_vio.h" - -#ifndef _WIN32 -#include -#include -#endif - -#define CSYNC_LOG_CATEGORY_NAME "csync.time" -#include "csync_log.h" - -#ifdef HAVE_CLOCK_GETTIME -# ifdef _POSIX_MONOTONIC_CLOCK -# define CSYNC_CLOCK CLOCK_MONOTONIC -# else -# define CSYNC_CLOCK CLOCK_REALTIME -# endif -#endif - - -int csync_gettime(struct timespec *tp) -{ -#if defined(_WIN32) - __int64 wintime; - GetSystemTimeAsFileTime((FILETIME*)&wintime); - wintime -= 116444736000000000ll; //1jan1601 to 1jan1970 - tp->tv_sec = wintime / 10000000ll; //seconds - tp->tv_nsec = wintime % 10000000ll * 100; //nano-seconds -#elif defined(HAVE_CLOCK_GETTIME) - return clock_gettime(CSYNC_CLOCK, tp); -#else - struct timeval tv; - - if (gettimeofday(&tv, NULL) < 0) { - return -1; - } - - tp->tv_sec = tv.tv_sec; - tp->tv_nsec = tv.tv_usec * 1000; -#endif - return 0; -} - -#undef CSYNC_CLOCK - -void csync_sleep(unsigned int msecs) -{ -#if defined(_WIN32) - Sleep(msecs); -#else - usleep(msecs * 1000); -#endif -} diff --git a/csync/src/csync_time.h b/csync/src/csync_time.h deleted file mode 100644 index 1492bef8d..000000000 --- a/csync/src/csync_time.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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_TIME_H -#define _CSYNC_TIME_H - -#include - -#include "csync_private.h" - -int csync_gettime(struct timespec *tp); -void csync_sleep(unsigned int msecs); - -#endif /* _CSYNC_TIME_H */ diff --git a/csync/src/csync_update.c b/csync/src/csync_update.c deleted file mode 100644 index 1a069442e..000000000 --- a/csync/src/csync_update.c +++ /dev/null @@ -1,862 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * 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 "config_csync.h" - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include -#include - -#include "c_lib.h" -#include "c_jhash.h" - -#include "csync_private.h" -#include "csync_exclude.h" -#include "csync_statedb.h" -#include "csync_update.h" -#include "csync_util.h" -#include "csync_misc.h" - -#include "vio/csync_vio.h" - -#define CSYNC_LOG_CATEGORY_NAME "csync.updater" -#include "csync_log.h" -#include "csync_rename.h" - -/* calculate the hash of a given uri */ -static uint64_t _hash_of_file(CSYNC *ctx, const char *file) { - const char *path; - int len; - uint64_t h = 0; - - if( ctx && file ) { - path = file; - if (ctx->current == LOCAL_REPLICA) { - if (strlen(path) <= strlen(ctx->local.uri)) { - return 0; - } - path += strlen(ctx->local.uri) + 1; - } - len = strlen(path); - h = c_jhash64((uint8_t *) path, len, 0); - } - return h; -} - -#ifdef NO_RENAME_EXTENSION -/* Return true if the two path have the same extension. false otherwise. */ -static bool _csync_sameextension(const char *p1, const char *p2) { - /* Find pointer to the extensions */ - const char *e1 = strrchr(p1, '.'); - const char *e2 = strrchr(p2, '.'); - - /* If the found extension contains a '/', it is because the . was in the folder name - * => no extensions */ - if (e1 && strchr(e1, '/')) e1 = NULL; - if (e2 && strchr(e2, '/')) e2 = NULL; - - /* If none have extension, it is the same extension */ - if (!e1 && !e2) - return true; - - /* c_streq takes care of the rest */ - return c_streq(e1, e2); -} -#endif - -static bool _last_db_return_error(CSYNC* ctx) { - return ctx->statedb.lastReturnValue != SQLITE_OK && ctx->statedb.lastReturnValue != SQLITE_DONE && ctx->statedb.lastReturnValue != SQLITE_ROW; -} - -/* - * This static method is needed because the type members of the two structs use - * different enum values. A direct comparion is not neccessarily correct. - * - * tmp is csync_file_stat_t - * fs is csync_vio_file_stat_t with this vio type: - * enum csync_vio_file_type_e { - * CSYNC_VIO_FILE_TYPE_UNKNOWN, - * CSYNC_VIO_FILE_TYPE_REGULAR, - * CSYNC_VIO_FILE_TYPE_DIRECTORY, - * CSYNC_VIO_FILE_TYPE_FIFO, - * CSYNC_VIO_FILE_TYPE_SOCKET, - * CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE, - * CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE, - * CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK - * }; - * - * csync_file_stat_t can be: - * CSYNC_FTW_TYPE_SKIP, CSYNC_FTW_TYPE_FILE - * CSYNC_FTW_TYPE_DIR, CSYNC_FTW_TYPE_SLINK - */ -static bool _csync_filetype_different( const csync_file_stat_t *tmp, const csync_vio_file_stat_t *fs) -{ - if( !(tmp && fs)) return false; - - if( tmp->type == CSYNC_FTW_TYPE_SKIP ) return true; - - if( tmp->type == CSYNC_FTW_TYPE_DIR && fs->type != CSYNC_VIO_FILE_TYPE_DIRECTORY ) - return true; - if( tmp->type == CSYNC_FTW_TYPE_FILE && fs->type != CSYNC_VIO_FILE_TYPE_REGULAR ) - return true; - if( tmp->type == CSYNC_FTW_TYPE_SLINK && fs->type != CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK ) - return true; - - return false; // both are NOT different. -} - -/* Return true if two mtime are considered equal - * We consider mtime that are one hour difference to be equal if they are one hour appart - * because on some system (FAT) the date is changing when the daylight saving is changing */ -static bool _csync_mtime_equal(time_t a, time_t b) -{ - if (a == b) - return true; - - /* 1h of difference +- 1 second because the accuracy of FAT is 2 seconds (#2438) */ - if (fabs(3600 - fabs(difftime(a, b))) < 2) - return true; - - return false; -} - -/** - * The main function of the discovery/update pass. - * - * It's called (indirectly) by csync_update(), once for each entity in the - * local filesystem and once for each entity in the server data. - * - * It has two main jobs: - * - figure out whether anything happened compared to the sync journal - * and set (primarily) the instruction flag accordingly - * - build the ctx->local.tree / ctx->remote.tree - * - * See doc/dev/sync-algorithm.md for an overview. - */ -static int _csync_detect_update(CSYNC *ctx, const char *file, - const csync_vio_file_stat_t *fs, const int type) { - uint64_t h = 0; - size_t len = 0; - size_t size = 0; - const char *path = NULL; - csync_file_stat_t *st = NULL; - csync_file_stat_t *tmp = NULL; - CSYNC_EXCLUDE_TYPE excluded; - - if ((file == NULL) || (fs == NULL)) { - errno = EINVAL; - ctx->status_code = CSYNC_STATUS_PARAM_ERROR; - return -1; - } - - path = file; - if (ctx->current == LOCAL_REPLICA) { - if (strlen(path) <= strlen(ctx->local.uri)) { - ctx->status_code = CSYNC_STATUS_PARAM_ERROR; - return -1; - } - path += strlen(ctx->local.uri) + 1; - } - - len = strlen(path); - - if (type == CSYNC_FTW_TYPE_SKIP) { - excluded =CSYNC_FILE_EXCLUDE_STAT_FAILED; - } else { - /* Check if file is excluded */ - excluded = csync_excluded_traversal(ctx->excludes, path, type); - } - - if( excluded == CSYNC_NOT_EXCLUDED ) { - /* Even if it is not excluded by a pattern, maybe it is to be ignored - * because it's a hidden file that should not be synced. - * This code should probably be in csync_exclude, but it does not have the fs parameter. - * Keep it here for now */ - if (ctx->ignore_hidden_files && (fs->flags & CSYNC_VIO_FILE_FLAGS_HIDDEN)) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file excluded because it is a hidden file: %s", path); - excluded = CSYNC_FILE_EXCLUDE_HIDDEN; - } - } else { - /* File is ignored because it's matched by a user- or system exclude pattern. */ - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded (%d)", path, excluded); - if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE) { - return 1; - } - if (excluded == CSYNC_FILE_SILENTLY_EXCLUDED) { - return 1; - } - } - - if (ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncBlackListHook) { - if (ctx->callbacks.checkSelectiveSyncBlackListHook(ctx->callbacks.update_callback_userdata, path)) { - return 1; - } - } - - h = _hash_of_file(ctx, file ); - if( h == 0 ) { - return -1; - } - size = sizeof(csync_file_stat_t) + len + 1; - - st = c_malloc(size); - - /* Set instruction by default to none */ - st->instruction = CSYNC_INSTRUCTION_NONE; - st->etag = NULL; - st->child_modified = 0; - st->has_ignored_files = 0; - if (type == CSYNC_FTW_TYPE_FILE ) { - if (fs->mtime == 0) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - mtime is zero!", path); - } - } - - if (excluded > CSYNC_NOT_EXCLUDED || type == CSYNC_FTW_TYPE_SLINK) { - st->instruction = CSYNC_INSTRUCTION_IGNORE; - if (ctx->current_fs) { - ctx->current_fs->has_ignored_files = true; - } - - goto out; - } - - /* Update detection: Check if a database entry exists. - * If not, the file is either new or has been renamed. To see if it is - * renamed, the db gets queried by the inode of the file as that one - * does not change on rename. - */ - if (csync_get_statedb_exists(ctx)) { - tmp = csync_statedb_get_stat_by_hash(ctx, h); - - if(_last_db_return_error(ctx)) { - csync_file_stat_free(st); - csync_file_stat_free(tmp); - ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL; - return -1; - } - - if(tmp && tmp->phash == h ) { /* there is an entry in the database */ - /* we have an update! */ - CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Database entry found, compare: %" PRId64 " <-> %" PRId64 - ", etag: %s <-> %s, inode: %" PRId64 " <-> %" PRId64 - ", size: %" PRId64 " <-> %" PRId64 ", perms: %s <-> %s, ignore: %d", - ((int64_t) fs->mtime), ((int64_t) tmp->modtime), - fs->etag, tmp->etag, (uint64_t) fs->inode, (uint64_t) tmp->inode, - (uint64_t) fs->size, (uint64_t) tmp->size, fs->remotePerm, tmp->remotePerm, tmp->has_ignored_files ); - if (ctx->current == REMOTE_REPLICA && !c_streq(fs->etag, tmp->etag)) { - st->instruction = CSYNC_INSTRUCTION_EVAL; - - // Preserve the EVAL flag later on if the type has changed. - if (_csync_filetype_different(tmp, fs)) { - st->child_modified = 1; - } - - goto out; - } - if (ctx->current == LOCAL_REPLICA && - (!_csync_mtime_equal(fs->mtime, tmp->modtime) - // zero size in statedb can happen during migration - || (tmp->size != 0 && fs->size != tmp->size))) { - - // Checksum comparison at this stage is only enabled for .eml files, - // check #4754 #4755 - bool isEmlFile = csync_fnmatch("*.eml", file, FNM_CASEFOLD) == 0; - if (isEmlFile && fs->size == tmp->size && tmp->checksumHeader) { - if (ctx->callbacks.checksum_hook) { - st->checksumHeader = ctx->callbacks.checksum_hook( - file, tmp->checksumHeader, - ctx->callbacks.checksum_userdata); - } - bool checksumIdentical = false; - if (st->checksumHeader) { - checksumIdentical = strncmp(st->checksumHeader, tmp->checksumHeader, 1000) == 0; - } - if (checksumIdentical) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "NOTE: Checksums are identical, file did not actually change: %s", path); - st->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; - goto out; - } - } - - // Preserve the EVAL flag later on if the type has changed. - if (_csync_filetype_different(tmp, fs)) { - st->child_modified = 1; - } - - 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 - && !metadata_differ && ctx->read_remote_from_db) { - /* If both etag and file id are equal for a directory, read all contents from - * the database. - * 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 it was remembered in the db that the remote dir has ignored files, store - * that so that the reconciler can make advantage of. - */ - if( ctx->current == REMOTE_REPLICA ) { - st->has_ignored_files = tmp->has_ignored_files; - } - 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->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; - } else { - st->instruction = CSYNC_INSTRUCTION_NONE; - } - } else { - enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN; - - /* tmp might point to malloc mem, so free it here before reusing tmp */ - csync_file_stat_free(tmp); - - /* check if it's a file and has been renamed */ - if (ctx->current == LOCAL_REPLICA) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Checking for rename based on inode # %" PRId64 "", (uint64_t) fs->inode); - - tmp = csync_statedb_get_stat_by_inode(ctx, fs->inode); - - if(_last_db_return_error(ctx)) { - csync_file_stat_free(st); - ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL; - return -1; - } - - /* translate the file type between the two stat types csync has. */ - if( tmp && tmp->type == CSYNC_FTW_TYPE_FILE ) { - tmp_vio_type = CSYNC_VIO_FILE_TYPE_REGULAR; - } else if( tmp && tmp->type == CSYNC_FTW_TYPE_DIR) { - tmp_vio_type = CSYNC_VIO_FILE_TYPE_DIRECTORY; - } else if( tmp && tmp->type == CSYNC_FTW_TYPE_SLINK ) { - tmp_vio_type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; - } else { - tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN; - } - - // Default to NEW unless we're sure it's a rename. - st->instruction = CSYNC_INSTRUCTION_NEW; - - bool isRename = - tmp && tmp->inode == fs->inode && tmp_vio_type == fs->type - && (tmp->modtime == fs->mtime || fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) -#ifdef NO_RENAME_EXTENSION - && _csync_sameextension(tmp->path, path) -#endif - ; - - - // Verify the checksum where possible - if (isRename && tmp->checksumHeader && ctx->callbacks.checksum_hook - && fs->type == CSYNC_VIO_FILE_TYPE_REGULAR) { - st->checksumHeader = ctx->callbacks.checksum_hook( - file, tmp->checksumHeader, - ctx->callbacks.checksum_userdata); - if (st->checksumHeader) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "checking checksum of potential rename %s %s <-> %s", path, st->checksumHeader, tmp->checksumHeader); - isRename = strncmp(st->checksumHeader, tmp->checksumHeader, 1000) == 0; - } - } - - if (isRename) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "pot rename detected based on inode # %" PRId64 "", (uint64_t) fs->inode); - /* inode found so the file has been renamed */ - st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME; - if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) { - csync_rename_record(ctx, tmp->path, path); - } - } - goto out; - - } else { - /* Remote Replica Rename check */ - tmp = csync_statedb_get_stat_by_file_id(ctx, fs->file_id); - - if(_last_db_return_error(ctx)) { - csync_file_stat_free(st); - ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL; - return -1; - } - if(tmp ) { /* tmp existing at all */ - if ( _csync_filetype_different(tmp, fs)) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "file types different is not!"); - st->instruction = CSYNC_INSTRUCTION_NEW; - goto out; - } - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "remote rename detected based on fileid %s %s", tmp->path, file); - st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME; - if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) { - csync_rename_record(ctx, tmp->path, path); - } else { - if( !c_streq(tmp->etag, fs->etag) ) { - /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "ETags are different!"); */ - /* File with different etag, don't do a rename, but download the file again */ - st->instruction = CSYNC_INSTRUCTION_NEW; - } - } - goto out; - - } else { - /* file not found in statedb */ - st->instruction = CSYNC_INSTRUCTION_NEW; - - if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY && ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncNewFolderHook) { - if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path, fs->remotePerm)) { - csync_file_stat_free(st); - return 1; - } - } - goto out; - } - } - } - } else { - CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Unable to open statedb" ); - csync_file_stat_free(st); - ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL; - return -1; - } - -out: - - /* Set the ignored error string. */ - if (st->instruction == CSYNC_INSTRUCTION_IGNORE) { - if( type == CSYNC_FTW_TYPE_SLINK ) { - st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK; /* Symbolic links are ignored. */ - } else { - if (excluded == CSYNC_FILE_EXCLUDE_LIST) { - st->error_status = CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST; /* File listed on ignore list. */ - } else if (excluded == CSYNC_FILE_EXCLUDE_INVALID_CHAR) { - st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS; /* File contains invalid characters. */ - } else if (excluded == CSYNC_FILE_EXCLUDE_TRAILING_SPACE) { - st->error_status = CSYNC_STATUS_INDIVIDUAL_TRAILING_SPACE; /* File ends with a trailing space. */ - } else if (excluded == CSYNC_FILE_EXCLUDE_LONG_FILENAME) { - st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME; /* File name is too long. */ - } else if (excluded == CSYNC_FILE_EXCLUDE_HIDDEN ) { - st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN; - } else if (excluded == CSYNC_FILE_EXCLUDE_STAT_FAILED) { - st->error_status = CSYNC_STATUS_INDIVIDUAL_STAT_FAILED; - } else if (excluded == CSYNC_FILE_EXCLUDE_CONFLICT) { - st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_CONFLICT_FILE; - } - } - } - if (st->instruction != CSYNC_INSTRUCTION_NONE - && st->instruction != CSYNC_INSTRUCTION_IGNORE - && st->instruction != CSYNC_INSTRUCTION_UPDATE_METADATA - && type != CSYNC_FTW_TYPE_DIR) { - st->child_modified = 1; - } - ctx->current_fs = st; - - csync_file_stat_free(tmp); - st->inode = fs->inode; - st->mode = fs->mode; - st->size = fs->size; - st->modtime = fs->mtime; - st->type = type; - st->etag = NULL; - if( fs->etag ) { - SAFE_FREE(st->etag); - 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); - } - - // For the remote: propagate the discovered checksum - if (fs->checksumHeader && ctx->current == REMOTE_REPLICA) { - st->checksumHeader = c_strdup(fs->checksumHeader); - } - - st->phash = h; - st->pathlen = len; - memcpy(st->path, (len ? path : ""), len + 1); - - switch (ctx->current) { - case LOCAL_REPLICA: - if (c_rbtree_insert(ctx->local.tree, (void *) st) < 0) { - csync_file_stat_free(st); - ctx->status_code = CSYNC_STATUS_TREE_ERROR; - return -1; - } - break; - case REMOTE_REPLICA: - if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) { - csync_file_stat_free(st); - ctx->status_code = CSYNC_STATUS_TREE_ERROR; - return -1; - } - break; - default: - break; - } - CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "file: %s, instruction: %s <<=", st->path, - csync_instruction_str(st->instruction)); - - return 0; -} - -int csync_walker(CSYNC *ctx, const char *file, const csync_vio_file_stat_t *fs, - enum csync_ftw_flags_e flag) { - int rc = -1; - int type = CSYNC_FTW_TYPE_SKIP; - csync_file_stat_t *st = NULL; - uint64_t h; - - if (ctx->abort) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!"); - ctx->status_code = CSYNC_STATUS_ABORTED; - return -1; - } - - switch (flag) { - case CSYNC_FTW_FLAG_FILE: - if (ctx->current == REMOTE_REPLICA) { - if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_SIZE) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=%" PRIu64 "]", file, fs->file_id, fs->size); - } else { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=UNKNOWN]", file, fs->file_id); - } - } else { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [inode=%" PRIu64 " size=%" PRIu64 "]", file, fs->inode, fs->size); - } - type = CSYNC_FTW_TYPE_FILE; - break; - case CSYNC_FTW_FLAG_DIR: /* enter directory */ - if (ctx->current == REMOTE_REPLICA) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [file_id=%s]", file, fs->file_id); - } else { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [inode=%" PRIu64 "]", file, fs->inode); - } - type = CSYNC_FTW_TYPE_DIR; - break; - case CSYNC_FTW_FLAG_NSTAT: /* not statable file */ - /* if file was here before and now is not longer stat-able, still - * add it to the db, otherwise not. */ - h = _hash_of_file( ctx, file ); - if( h == 0 ) { - return 0; - } - st = csync_statedb_get_stat_by_hash(ctx, h); - if( !st ) { - return 0; - } - csync_file_stat_free(st); - st = NULL; - - type = CSYNC_FTW_TYPE_SKIP; - break; - case CSYNC_FTW_FLAG_SLINK: - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "symlink: %s - not supported", file); - type = CSYNC_FTW_TYPE_SLINK; - break; - case CSYNC_FTW_FLAG_DNR: - case CSYNC_FTW_FLAG_DP: - case CSYNC_FTW_FLAG_SLN: - default: - return 0; - break; - } - - rc = _csync_detect_update(ctx, file, fs, type ); - - return rc; -} - -static bool fill_tree_from_db(CSYNC *ctx, const char *uri) -{ - if( csync_statedb_get_below_path(ctx, uri) < 0 ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "StateDB could not be read!"); - return false; - } - - return true; -} - -/* set the current item to an ignored state. - * If the item is set to ignored, the update phase continues, ie. its not a hard error */ -static bool mark_current_item_ignored( CSYNC *ctx, csync_file_stat_t *previous_fs, CSYNC_STATUS status ) -{ - if(!ctx) { - return false; - } - - if (ctx->current_fs) { - ctx->current_fs->instruction = CSYNC_INSTRUCTION_IGNORE; - ctx->current_fs->error_status = status; - /* If a directory has ignored files, put the flag on the parent directory as well */ - if( previous_fs ) { - previous_fs->has_ignored_files = true; - } - return true; - } - return false; -} - -/* File tree walker */ -int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, - unsigned int depth) { - char *filename = NULL; - char *d_name = NULL; - csync_vio_handle_t *dh = NULL; - csync_vio_file_stat_t *dirent = NULL; - csync_file_stat_t *previous_fs = NULL; - int read_from_db = 0; - int rc = 0; - int res = 0; - - if (!depth) { - mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_INDIVIDUAL_TOO_DEEP); - goto done; - } - - bool do_read_from_db = (ctx->current == REMOTE_REPLICA && ctx->remote.read_from_db); - - read_from_db = ctx->remote.read_from_db; - - // if the etag of this dir is still the same, its content is restored from the - // database. - if( do_read_from_db ) { - if( ! fill_tree_from_db(ctx, uri) ) { - errno = ENOENT; - ctx->status_code = CSYNC_STATUS_OPENDIR_ERROR; - goto error; - } - goto done; - } - - if ((dh = csync_vio_opendir(ctx, uri)) == NULL) { - if (ctx->abort) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!"); - ctx->status_code = CSYNC_STATUS_ABORTED; - goto error; - } - int asp = 0; - /* permission denied */ - ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_OPENDIR_ERROR); - if (errno == EACCES) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Permission denied."); - if (mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_PERMISSION_DENIED)) { - goto done; - } - } else if(errno == ENOENT) { - asp = asprintf( &ctx->error_string, "%s", uri); - if (asp < 0) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!"); - } - } - // 403 Forbidden can be sent by the server if the file firewall is active. - // A file or directory should be ignored and sync must continue. See #3490 - else if(errno == ERRNO_FORBIDDEN) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Directory access Forbidden (File Firewall?)"); - if( mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_FORBIDDEN) ) { - goto done; - } - /* if current_fs is not defined here, better throw an error */ - } - // The server usually replies with the custom "503 Storage not available" - // if some path is temporarily unavailable. But in some cases a standard 503 - // is returned too. Thus we can't distinguish the two and will treat any - // 503 as request to ignore the folder. See #3113 #2884. - else if(errno == ERRNO_STORAGE_UNAVAILABLE || errno == ERRNO_SERVICE_UNAVAILABLE) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Storage was not available!"); - if( mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_STORAGE_UNAVAILABLE ) ) { - goto done; - } - /* if current_fs is not defined here, better throw an error */ - } else { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "opendir failed for %s - errno %d", uri, errno); - } - goto error; - } - - while ((dirent = csync_vio_readdir(ctx, dh))) { - int flen; - int flag; - - /* Conversion error */ - if (dirent->name == NULL && dirent->original_name) { - ctx->status_code = CSYNC_STATUS_INVALID_CHARACTERS; - ctx->error_string = dirent->original_name; // take ownership - dirent->original_name = NULL; - goto error; - } - - d_name = dirent->name; - if (d_name == NULL) { - ctx->status_code = CSYNC_STATUS_READDIR_ERROR; - goto error; - } - - /* skip "." and ".." */ - if ( (d_name[0] == '.' && d_name[1] == '\0') - || (d_name[0] == '.' && d_name[1] == '.' && d_name[2] == '\0')) { - csync_vio_file_stat_destroy(dirent); - dirent = NULL; - continue; - } - - if (uri[0] == '\0') { - filename = c_strdup(d_name); - flen = strlen(d_name); - } else { - flen = asprintf(&filename, "%s/%s", uri, d_name); - } - if (flen < 0 || !filename) { - csync_vio_file_stat_destroy(dirent); - dirent = NULL; - ctx->status_code = CSYNC_STATUS_MEMORY_ERROR; - goto error; - } - - /* Only for the local replica we have to stat(), for the remote one we have all data already */ - if (ctx->replica == LOCAL_REPLICA) { - res = csync_vio_stat(ctx, filename, dirent); - } else { - res = 0; - } - - /* if the filename starts with a . we consider it a hidden file - * For windows, the hidden state is also discovered within the vio - * local stat function. - */ - if( d_name[0] == '.' ) { - if (strcmp(".sys.admin#recall#", d_name) != 0) { /* recall file shall not be ignored (#4420) */ - dirent->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN; - } - } - - if( res == 0) { - switch (dirent->type) { - case CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK: - flag = CSYNC_FTW_FLAG_SLINK; - break; - case CSYNC_VIO_FILE_TYPE_DIRECTORY: - flag = CSYNC_FTW_FLAG_DIR; - break; - case CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE: - case CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE: - case CSYNC_VIO_FILE_TYPE_SOCKET: - flag = CSYNC_FTW_FLAG_SPEC; - break; - case CSYNC_VIO_FILE_TYPE_FIFO: - flag = CSYNC_FTW_FLAG_SPEC; - break; - default: - flag = CSYNC_FTW_FLAG_FILE; - break; - }; - } else { - flag = CSYNC_FTW_FLAG_NSTAT; - } - - previous_fs = ctx->current_fs; - - /* Call walker function for each file */ - rc = fn(ctx, filename, dirent, flag); - /* this function may update ctx->current and ctx->read_from_db */ - - if (rc < 0) { - if (CSYNC_STATUS_IS_OK(ctx->status_code)) { - ctx->status_code = CSYNC_STATUS_UPDATE_ERROR; - } - - ctx->current_fs = previous_fs; - goto error; - } - - if (flag == CSYNC_FTW_FLAG_DIR && rc == 0 - && (!ctx->current_fs || ctx->current_fs->instruction != CSYNC_INSTRUCTION_IGNORE)) { - rc = csync_ftw(ctx, filename, fn, depth - 1); - if (rc < 0) { - ctx->current_fs = previous_fs; - goto error; - } - - if (ctx->current_fs && !ctx->current_fs->child_modified - && ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL) { - if (ctx->current == REMOTE_REPLICA) { - ctx->current_fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; - } else { - ctx->current_fs->instruction = CSYNC_INSTRUCTION_NONE; - } - } - - if (ctx->current_fs && previous_fs && ctx->current_fs->has_ignored_files) { - /* If a directory has ignored files, put the flag on the parent directory as well */ - previous_fs->has_ignored_files = ctx->current_fs->has_ignored_files; - } - } - - if (ctx->current_fs && previous_fs && ctx->current_fs->child_modified) { - /* If a directory has modified files, put the flag on the parent directory as well */ - previous_fs->child_modified = ctx->current_fs->child_modified; - } - - ctx->current_fs = previous_fs; - ctx->remote.read_from_db = read_from_db; - SAFE_FREE(filename); - csync_vio_file_stat_destroy(dirent); - dirent = NULL; - } - - csync_vio_closedir(ctx, dh); - CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, " <= Closing walk for %s with read_from_db %d", uri, read_from_db); - -done: - csync_vio_file_stat_destroy(dirent); - SAFE_FREE(filename); - return rc; -error: - ctx->remote.read_from_db = read_from_db; - if (dh != NULL) { - csync_vio_closedir(ctx, dh); - } - SAFE_FREE(filename); - return -1; -} - -/* vim: set ts=8 sw=2 et cindent: */ diff --git a/csync/src/csync_update.h b/csync/src/csync_update.h deleted file mode 100644 index 4a7495e3a..000000000 --- a/csync/src/csync_update.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * 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_UPDATE_H -#define _CSYNC_UPDATE_H - -#include "csync.h" - -/** - * @file csync_update.h - * - * @brief Update Detection - * - * TODO - * - * @defgroup csyncUpdateDetectionInternals csync update detection internals - * @ingroup csyncInternalAPI - * - * @{ - */ - -/** - * Types for files - */ -enum csync_ftw_flags_e { - CSYNC_FTW_FLAG_FILE, /* Regular file. */ - CSYNC_FTW_FLAG_DIR, /* Directory. */ - CSYNC_FTW_FLAG_DNR, /* Unreadable directory. */ - CSYNC_FTW_FLAG_NSTAT, /* Unstatable file. */ - CSYNC_FTW_FLAG_SLINK, /* Symbolic link. */ - CSYNC_FTW_FLAG_SPEC, /* Special file (fifo, ...). */ - /* These flags are only passed from the `nftw' function. */ - CSYNC_FTW_FLAG_DP, /* Directory, all subdirs have been visited. */ - CSYNC_FTW_FLAG_SLN /* Symbolic link naming non-existing file. */ -}; - -typedef int (*csync_walker_fn) (CSYNC *ctx, const char *file, - const csync_vio_file_stat_t *fs, enum csync_ftw_flags_e flag); - -/** - * @brief The walker function to use in the file tree walker. - * - * @param ctx The used csync context. - * - * @param file The file we are researching. - * - * @param fs The stat information we got. - * - * @param flag The flag describing the type of the file. - * - * @return 0 on success, < 0 on error. - */ -int csync_walker(CSYNC *ctx, const char *file, const csync_vio_file_stat_t *fs, - enum csync_ftw_flags_e flag); - -/** - * @brief The file tree walker. - * - * This function walks through the directory tree that is located under the uri - * specified. It calls a walker function which is provided as a function pointer - * once for each entry in the tree. By default, directories are handled before - * the files and subdirectories they contain (pre-order traversal). - * - * @param ctx The csync context to use. - * - * @param uri The uri/path to the directory tree to walk. - * - * @param fn The walker function to call once for each entry. - * - * @param depth The max depth to walk down the tree. - * - * @return 0 on success, < 0 on error. If fn() returns non-zero, then the tree - * walk is terminated and the value returned by fn() is returned as the - * result. - */ -int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, - unsigned int depth); - -#endif /* _CSYNC_UPDATE_H */ - -/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/csync/src/csync_util.c b/csync/src/csync_util.c deleted file mode 100644 index 1bc09c35c..000000000 --- a/csync/src/csync_util.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * 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 "config_csync.h" - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include - -#include "c_jhash.h" -#include "csync_util.h" -#include "vio/csync_vio.h" - -#define CSYNC_LOG_CATEGORY_NAME "csync.util" -#include "csync_log.h" -#include "csync_statedb.h" - -typedef struct { - const char *instr_str; - enum csync_instructions_e instr_code; -} _instr_code_struct; - -static const _instr_code_struct _instr[] = -{ - { "INSTRUCTION_NONE", CSYNC_INSTRUCTION_NONE }, - { "INSTRUCTION_EVAL", CSYNC_INSTRUCTION_EVAL }, - { "INSTRUCTION_REMOVE", CSYNC_INSTRUCTION_REMOVE }, - { "INSTRUCTION_RENAME", CSYNC_INSTRUCTION_RENAME }, - { "INSTRUCTION_EVAL_RENAME", CSYNC_INSTRUCTION_EVAL_RENAME }, - { "INSTRUCTION_NEW", CSYNC_INSTRUCTION_NEW }, - { "INSTRUCTION_CONFLICT", CSYNC_INSTRUCTION_CONFLICT }, - { "INSTRUCTION_IGNORE", CSYNC_INSTRUCTION_IGNORE }, - { "INSTRUCTION_SYNC", CSYNC_INSTRUCTION_SYNC }, - { "INSTRUCTION_STAT_ERR", CSYNC_INSTRUCTION_STAT_ERROR }, - { "INSTRUCTION_ERROR", CSYNC_INSTRUCTION_ERROR }, - { "INSTRUCTION_TYPE_CHANGE", CSYNC_INSTRUCTION_TYPE_CHANGE }, - { "INSTRUCTION_UPDATE_METADATA", CSYNC_INSTRUCTION_UPDATE_METADATA }, - { NULL, CSYNC_INSTRUCTION_ERROR } -}; - -struct csync_memstat_s { - int size; - int resident; - int shared; - int trs; - int drs; - int lrs; - int dt; -}; - -const char *csync_instruction_str(enum csync_instructions_e instr) -{ - int idx = 0; - - while (_instr[idx].instr_str != NULL) { - if (_instr[idx].instr_code == instr) { - return _instr[idx].instr_str; - } - idx++; - } - - return "ERROR!"; -} - - -void csync_memstat_check(void) { - int s = 0; - struct csync_memstat_s m; - FILE* fp; - - /* get process memory stats */ - fp = fopen("/proc/self/statm","r"); - if (fp == NULL) { - return; - } - s = fscanf(fp, "%d%d%d%d%d%d%d", &m.size, &m.resident, &m.shared, &m.trs, - &m.drs, &m.lrs, &m.dt); - fclose(fp); - if (s == EOF) { - return; - } - - CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Memory: %dK total size, %dK resident, %dK shared", - m.size * 4, m.resident * 4, m.shared * 4); -} - -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*)) { - csync_file_locked_or_open_ext = f; -} - -bool csync_file_locked_or_open( const char *dir, const char *fname) { - char *tmp_uri = NULL; - bool ret; - if (!csync_file_locked_or_open_ext) { - return false; - } - if (asprintf(&tmp_uri, "%s/%s", dir, fname) < 0) { - return -1; - } - CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "csync_file_locked_or_open %s", tmp_uri); - ret = csync_file_locked_or_open_ext(tmp_uri); - SAFE_FREE(tmp_uri); - return ret; -} - -#ifndef HAVE_TIMEGM -#ifdef _WIN32 -static int is_leap(unsigned y) { - y += 1900; - return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0); -} - -static time_t timegm(struct tm *tm) { - static const unsigned ndays[2][12] = { - {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, - {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; - - time_t res = 0; - int i; - - for (i = 70; i < tm->tm_year; ++i) - res += is_leap(i) ? 366 : 365; - - for (i = 0; i < tm->tm_mon; ++i) - res += ndays[is_leap(tm->tm_year)][i]; - res += tm->tm_mday - 1; - res *= 24; - res += tm->tm_hour; - res *= 60; - res += tm->tm_min; - res *= 60; - res += tm->tm_sec; - return res; -} -#else -/* A hopefully portable version of timegm */ -static time_t timegm(struct tm *tm ) { - time_t ret; - char *tz; - - tz = getenv("TZ"); - setenv("TZ", "", 1); - tzset(); - ret = mktime(tm); - if (tz) - setenv("TZ", tz, 1); - else - unsetenv("TZ"); - tzset(); - return ret; -} -#endif /* Platform switch */ -#endif /* HAVE_TIMEGM */ - -#define RFC1123_FORMAT "%3s, %02d %3s %4d %02d:%02d:%02d GMT" -static const char short_months[12][4] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" -}; -/* - * This function is borrowed from libneon's ne_httpdate_parse. - * Unfortunately that one converts to local time but here UTC is - * needed. - * This one uses timegm instead, which returns UTC. - */ -time_t oc_httpdate_parse( const char *date ) { - struct tm gmt; - char wkday[4], mon[4]; - int n; - time_t result = 0; - - memset(&gmt, 0, sizeof(struct tm)); - - /* it goes: Sun, 06 Nov 1994 08:49:37 GMT */ - n = sscanf(date, RFC1123_FORMAT, - wkday, &gmt.tm_mday, mon, &gmt.tm_year, &gmt.tm_hour, - &gmt.tm_min, &gmt.tm_sec); - /* Is it portable to check n==7 here? */ - gmt.tm_year -= 1900; - for (n=0; n<12; n++) - if (strcmp(mon, short_months[n]) == 0) - break; - /* tm_mon comes out as 12 if the month is corrupt, which is desired, - * since the mktime will then fail */ - gmt.tm_mon = n; - gmt.tm_isdst = -1; - result = timegm(&gmt); - return result; -} diff --git a/csync/src/csync_util.h b/csync/src/csync_util.h deleted file mode 100644 index f65ada592..000000000 --- a/csync/src/csync_util.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * 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_UTIL_H -#define _CSYNC_UTIL_H - -#include - -#include "csync_private.h" - -const char OCSYNC_EXPORT *csync_instruction_str(enum csync_instructions_e instr); - -void OCSYNC_EXPORT csync_memstat_check(void); - -bool OCSYNC_EXPORT csync_file_locked_or_open( const char *dir, const char *fname); -#endif /* _CSYNC_UTIL_H */ diff --git a/csync/src/csync_version.h.in b/csync/src/csync_version.h.in deleted file mode 100644 index 9471734b8..000000000 --- a/csync/src/csync_version.h.in +++ /dev/null @@ -1,37 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2006-2012 by Andreas Schneider - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _CSYNC_VERSION_H -#define _CSYNC_VERSION_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define CSYNC_STRINGIFY(s) CSYNC_TOSTRING(s) -#define CSYNC_TOSTRING(s) #s - -#define MIRALL_VERSION @MIRALL_VERSION@ - -#ifdef __cplusplus -} -#endif - -#endif // _CSYNC_VERSION_H diff --git a/csync/src/std/CMakeLists.txt b/csync/src/std/CMakeLists.txt deleted file mode 100644 index 519cada86..000000000 --- a/csync/src/std/CMakeLists.txt +++ /dev/null @@ -1,44 +0,0 @@ -project(cstdlib) - -set(CSTDLIB_PUBLIC_INCLUDE_DIRS - ${CMAKE_CURRENT_SOURCE_DIR} - CACHE INTERNAL "cstdlib public include directories" -) - -set(CSTDLIB_LIBRARY - cstdlib - CACHE INTERNAL "cstdlib library" -) - -set(CSTDLIB_LINK_LIBRARIES - ${CSTDLIB_LIBRARY} -) - -set(cstdlib_SRCS - c_alloc.c - c_path.c - c_rbtree.c - c_string.c - c_time.c - c_utf8.cc -) - -if(NOT HAVE_ASPRINTF AND NOT HAVE___MINGW_ASPRINTF) - list(APPEND cstdlib_SRCS - asprintf.c - ) -endif() - -include_directories( - ${CSTDLIB_PUBLIC_INCLUDE_DIRS} -) - -add_library(${CSTDLIB_LIBRARY} STATIC ${cstdlib_SRCS}) -if(NOT WIN32) - add_definitions( -fPIC ) - qt5_use_modules(${CSTDLIB_LIBRARY} Core) -endif() -if(NOT HAVE_FNMATCH AND WIN32) - # needed for PathMatchSpec for our fnmatch replacement - target_link_libraries(${CSTDLIB_LIBRARY} ${SHLWAPI_LIBRARY}) -endif() diff --git a/csync/src/std/asprintf.c b/csync/src/std/asprintf.c deleted file mode 100644 index 8738df973..000000000 --- a/csync/src/std/asprintf.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - https://raw.githubusercontent.com/littlstar/asprintf.c/20ce5207a4ecb24017b5a17e6cd7d006e3047146/asprintf.c - - The MIT License (MIT) - - Copyright (c) 2014 Little Star Media, Inc. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -/** - * `asprintf.c' - asprintf - * - * copyright (c) 2014 joseph werle - */ - -#ifndef HAVE_ASPRINTF - -#include -#include -#include - -#include "asprintf.h" - -int -asprintf (char **str, const char *fmt, ...) { - int size = 0; - va_list args; - - // init variadic argumens - va_start(args, fmt); - - // format and get size - size = vasprintf(str, fmt, args); - - // toss args - va_end(args); - - return size; -} - -int -vasprintf (char **str, const char *fmt, va_list args) { - int size = 0; - va_list tmpa; - - // copy - va_copy(tmpa, args); - - // apply variadic arguments to - // sprintf with format to get size - size = vsnprintf(NULL, size, fmt, tmpa); - - // toss args - va_end(tmpa); - - // return -1 to be compliant if - // size is less than 0 - if (size < 0) { return -1; } - - // alloc with size plus 1 for `\0' - *str = (char *) malloc(size + 1); - - // return -1 to be compliant - // if pointer is `NULL' - if (NULL == *str) { return -1; } - - // format string with original - // variadic arguments and set new size - size = vsprintf(*str, fmt, args); - return size; -} - -#endif diff --git a/csync/src/std/asprintf.h b/csync/src/std/asprintf.h deleted file mode 100644 index d6dd2e859..000000000 --- a/csync/src/std/asprintf.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - https://raw.githubusercontent.com/littlstar/asprintf.c/20ce5207a4ecb24017b5a17e6cd7d006e3047146/asprintf.h - - The MIT License (MIT) - - Copyright (c) 2014 Little Star Media, Inc. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -/** - * `asprintf.h' - asprintf.c - * - * copyright (c) 2014 joseph werle - */ - -#ifndef HAVE_ASPRINTF -#ifndef ASPRINTF_H -#define ASPRINTF_H 1 - -#include - -/** - * Sets `char **' pointer to be a buffer - * large enough to hold the formatted string - * accepting a `va_list' args of variadic - * arguments. - */ - -int -vasprintf (char **, const char *, va_list); - -/** - * Sets `char **' pointer to be a buffer - * large enough to hold the formatted - * string accepting `n' arguments of - * variadic arguments. - */ - -int -asprintf (char **, const char *, ...); - -#endif -#endif diff --git a/csync/src/std/c_alloc.c b/csync/src/std/c_alloc.c deleted file mode 100644 index b87a3836f..000000000 --- a/csync/src/std/c_alloc.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * cynapses libc functions - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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 - -#include "c_macro.h" -#include "c_alloc.h" - -void *c_calloc(size_t count, size_t size) { - if (size == 0 || count == 0) { - return NULL; - } - -#ifdef CSYNC_MEM_NULL_TESTS - if (getenv("CSYNC_NOMEMORY")) { - return NULL; - } -#endif /* CSYNC_MEM_NULL_TESTS */ - -#undef calloc - return calloc(count, size); -#define calloc(x,y) DO_NOT_CALL_CALLOC__USE_XCALLOC_INSTEAD -} - -void *c_malloc(size_t size) { - if (size == 0) { - return NULL; - } -#undef malloc - return c_calloc(1, size); -#define malloc(x) DO_NOT_CALL_MALLOC__USE_XMALLOC_INSTEAD -} - -void *c_realloc(void *ptr, size_t size) { - -#ifdef CSYNC_MEM_NULL_TESTS - if (getenv("CSYNC_NOMEMORY")) { - return NULL; - } -#endif /* CSYNC_MEM_NULL_TESTS */ - -#undef realloc - return realloc(ptr, size); -#define realloc(x,y) DO_NOT_CALL_REALLOC__USE_XREALLOC_INSTEAD -} - -char *c_strdup(const char *str) { - char *ret; - ret = (char *) c_malloc(strlen(str) + 1); - if (ret == NULL) { - return NULL; - } - strcpy(ret, str); - return ret; -} - -char *c_strndup(const char *str, size_t size) { - char *ret; - size_t len; - len = strlen(str); - if (len > size) { - len = size; - } - ret = (char *) c_malloc(len + 1); - if (ret == NULL) { - return NULL; - } - strncpy(ret, str, len); - ret[size] = '\0'; - return ret; -} - diff --git a/csync/src/std/c_alloc.h b/csync/src/std/c_alloc.h deleted file mode 100644 index 6eeccd69d..000000000 --- a/csync/src/std/c_alloc.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * cynapses libc functions - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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_alloc.h - * - * @brief Interface of the cynapses libc alloc function - * - * @defgroup cynLibraryAPI cynapses libc API (internal) - * - * @defgroup cynAllocInternals cynapses libc alloc functions - * @ingroup cynLibraryAPI - * - * @{ - */ - -#ifndef _C_ALLOC_H -#define _C_ALLOC_H - -#include - -#include "c_macro.h" - -/** - * @brief Allocates memory for an array. - * - * Allocates memory for an array of elements of bytes each and - * returns a pointer to the allocated memory. The memory is set to zero. - * - * @param count Amount of elements to allocate - * @param size Size in bytes of each element to allocate. - * - * @return A unique pointer value that can later be successfully passed to - * free(). If size or count is 0, NULL will be returned. - */ -void *c_calloc(size_t count, size_t size); - -/** - * @brief Allocates memory for an array. - * - * Allocates bytes of memory. The memory is set to zero. - * - * @param size Size in bytes to allocate. - * - * @return A unique pointer value that can later be successfully passed to - * free(). If size or count is 0, NULL will be returned. - */ -void *c_malloc(size_t size); - -/** - * @brief Changes the size of the memory block pointed to. - * - * Newly allocated memory will be uninitialized. - * - * @param ptr Pointer to the memory which should be resized. - * @param size Value to resize. - * - * @return If ptr is NULL, the call is equivalent to c_malloc(size); if size - * is equal to zero, the call is equivalent to free(ptr). Unless ptr - * is NULL, it must have been returned by an earlier call to - * c_malloc(), c_calloc() or c_realloc(). If the area pointed to was - * moved, a free(ptr) is done. - */ -void *c_realloc(void *ptr, size_t size); - -/** - * @brief Duplicate a string. - * - * The function returns a pointer to a newly allocated string which is a - * duplicate of the string str. - * - * @param str String to duplicate. - * - * @return Returns a pointer to the duplicated string, or NULL if insufficient - * memory was available. - * - */ -char *c_strdup(const char *str); - -/** - * @brief Duplicate a string. - * - * The function returns a pointer to a newly allocated string which is a - * duplicate of the string str of size bytes. - * - * @param str String to duplicate. - * - * @param size Size of the string to duplicate. - * - * @return Returns a pointer to the duplicated string, or NULL if insufficient - * memory was available. A terminating null byte '\0' is added. - * - */ -char *c_strndup(const char *str, size_t size); - -/** - * }@ - */ -#endif /* _C_ALLOC_H */ diff --git a/csync/src/std/c_jhash.h b/csync/src/std/c_jhash.h deleted file mode 100644 index 261a0a4a4..000000000 --- a/csync/src/std/c_jhash.h +++ /dev/null @@ -1,245 +0,0 @@ -/* - * c_jhash.c Jenkins Hash - * - * Copyright (c) 1997 Bob Jenkins - * - * lookup8.c, by Bob Jenkins, January 4 1997, Public Domain. - * hash(), hash2(), hash3, and _c_mix() are externally useful functions. - * Routines to test the hash are included if SELF_TEST is defined. - * You can use this free for any purpose. It has no warranty. - * - * See http://burtleburtle.net/bob/hash/evahash.html - */ - -/** - * @file c_jhash.h - * - * @brief Interface of the cynapses jhash implementation - * - * @defgroup cynJHashInternals cynapses libc jhash function - * @ingroup cynLibraryAPI - * - * @{ - */ -#ifndef _C_JHASH_H -#define _C_JHASH_H - -#include - -#define c_hashsize(n) ((uint8_t) 1 << (n)) -#define c_hashmask(n) (xhashsize(n) - 1) - -/** - * _c_mix -- Mix 3 32-bit values reversibly. - * - * For every delta with one or two bit set, and the deltas of all three - * high bits or all three low bits, whether the original value of a,b,c - * is almost all zero or is uniformly distributed, - * If _c_mix() is run forward or backward, at least 32 bits in a,b,c - * have at least 1/4 probability of changing. - * If _c_mix() is run forward, every bit of c will change between 1/3 and - * 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) - * _c_mix() was built out of 36 single-cycle latency instructions in a - * structure that could supported 2x parallelism, like so: - * a -= b; - * a -= c; x = (c>>13); - * b -= c; a ^= x; - * b -= a; x = (a<<8); - * c -= a; b ^= x; - * c -= b; x = (b>>13); - * ... - * - * Unfortunately, superscalar Pentiums and Sparcs can't take advantage - * of that parallelism. They've also turned some of those single-cycle - * latency instructions into multi-cycle latency instructions. Still, - * this is the fastest good hash I could find. There were about 2^^68 - * to choose from. I only looked at a billion or so. - */ -#define _c_mix(a,b,c) \ -{ \ - a -= b; a -= c; a ^= (c>>13); \ - b -= c; b -= a; b ^= (a<<8); \ - c -= a; c -= b; c ^= (b>>13); \ - a -= b; a -= c; a ^= (c>>12); \ - b -= c; b -= a; b ^= (a<<16); \ - c -= a; c -= b; c ^= (b>>5); \ - a -= b; a -= c; a ^= (c>>3); \ - b -= c; b -= a; b ^= (a<<10); \ - c -= a; c -= b; c ^= (b>>15); \ -} - -/** - * _c_mix64 -- Mix 3 64-bit values reversibly. - * - * _c_mix64() takes 48 machine instructions, but only 24 cycles on a superscalar - * machine (like Intel's new MMX architecture). It requires 4 64-bit - * registers for 4::2 parallelism. - * All 1-bit deltas, all 2-bit deltas, all deltas composed of top bits of - * (a,b,c), and all deltas of bottom bits were tested. All deltas were - * tested both on random keys and on keys that were nearly all zero. - * These deltas all cause every bit of c to change between 1/3 and 2/3 - * of the time (well, only 113/400 to 287/400 of the time for some - * 2-bit delta). These deltas all cause at least 80 bits to change - * among (a,b,c) when the _c_mix is run either forward or backward (yes it - * is reversible). - * This implies that a hash using _c_mix64 has no funnels. There may be - * characteristics with 3-bit deltas or bigger, I didn't test for - * those. - */ -#define _c_mix64(a,b,c) \ -{ \ - a -= b; a -= c; a ^= (c>>43); \ - b -= c; b -= a; b ^= (a<<9); \ - c -= a; c -= b; c ^= (b>>8); \ - a -= b; a -= c; a ^= (c>>38); \ - b -= c; b -= a; b ^= (a<<23); \ - c -= a; c -= b; c ^= (b>>5); \ - a -= b; a -= c; a ^= (c>>35); \ - b -= c; b -= a; b ^= (a<<49); \ - c -= a; c -= b; c ^= (b>>11); \ - a -= b; a -= c; a ^= (c>>12); \ - b -= c; b -= a; b ^= (a<<18); \ - c -= a; c -= b; c ^= (b>>22); \ -} - -/** - * @brief hash a variable-length key into a 32-bit value - * - * The best hash table sizes are powers of 2. There is no need to do - * mod a prime (mod is sooo slow!). If you need less than 32 bits, - * use a bitmask. For example, if you need only 10 bits, do - * h = (h & hashmask(10)); - * In which case, the hash table should have hashsize(10) elements. - * - * Use for hash table lookup, or anything where one collision in 2^32 is - * acceptable. Do NOT use for cryptographic purposes. - * - * @param k The key (the unaligned variable-length array of bytes). - * - * @param length The length of the key, counting by bytes. - * - * @param initval Initial value, can be any 4-byte value. - * - * @return Returns a 32-bit value. Every bit of the key affects every bit - * of the return value. Every 1-bit and 2-bit delta achieves - * avalanche. About 36+6len instructions. - */ -static inline uint32_t c_jhash(const uint8_t *k, uint32_t length, uint32_t initval) { - uint32_t a,b,c,len; - - /* Set up the internal state */ - len = length; - a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ - c = initval; /* the previous hash value */ - - while (len >= 12) { - a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24)); - b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24)); - c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24)); - _c_mix(a,b,c); - k += 12; len -= 12; - } - - /* handle the last 11 bytes */ - c += length; - /* all the case statements fall through */ - switch(len) { - case 11: c+=((uint32_t)k[10]<<24); - case 10: c+=((uint32_t)k[9]<<16); - case 9 : c+=((uint32_t)k[8]<<8); - /* the first byte of c is reserved for the length */ - case 8 : b+=((uint32_t)k[7]<<24); - case 7 : b+=((uint32_t)k[6]<<16); - case 6 : b+=((uint32_t)k[5]<<8); - case 5 : b+=k[4]; - case 4 : a+=((uint32_t)k[3]<<24); - case 3 : a+=((uint32_t)k[2]<<16); - case 2 : a+=((uint32_t)k[1]<<8); - case 1 : a+=k[0]; - /* case 0: nothing left to add */ - } - _c_mix(a,b,c); - - return c; -} - -/** - * @brief hash a variable-length key into a 64-bit value - * - * The best hash table sizes are powers of 2. There is no need to do - * mod a prime (mod is sooo slow!). If you need less than 64 bits, - * use a bitmask. For example, if you need only 10 bits, do - * h = (h & hashmask(10)); - * In which case, the hash table should have hashsize(10) elements. - * - * Use for hash table lookup, or anything where one collision in 2^^64 - * is acceptable. Do NOT use for cryptographic purposes. - * - * @param k The key (the unaligned variable-length array of bytes). - * @param length The length of the key, counting by bytes. - * @param intval Initial value, can be any 8-byte value. - * - * @return A 64-bit value. Every bit of the key affects every bit of - * the return value. No funnels. Every 1-bit and 2-bit delta - * achieves avalanche. About 41+5len instructions. - */ -static inline uint64_t c_jhash64(const uint8_t *k, uint64_t length, uint64_t intval) { - uint64_t a,b,c,len; - - /* Set up the internal state */ - len = length; - a = b = intval; /* the previous hash value */ - c = 0x9e3779b97f4a7c13LL; /* the golden ratio; an arbitrary value */ - - /* handle most of the key */ - while (len >= 24) - { - a += (k[0] +((uint64_t)k[ 1]<< 8)+((uint64_t)k[ 2]<<16)+((uint64_t)k[ 3]<<24) - +((uint64_t)k[4 ]<<32)+((uint64_t)k[ 5]<<40)+((uint64_t)k[ 6]<<48)+((uint64_t)k[ 7]<<56)); - b += (k[8] +((uint64_t)k[ 9]<< 8)+((uint64_t)k[10]<<16)+((uint64_t)k[11]<<24) - +((uint64_t)k[12]<<32)+((uint64_t)k[13]<<40)+((uint64_t)k[14]<<48)+((uint64_t)k[15]<<56)); - c += (k[16] +((uint64_t)k[17]<< 8)+((uint64_t)k[18]<<16)+((uint64_t)k[19]<<24) - +((uint64_t)k[20]<<32)+((uint64_t)k[21]<<40)+((uint64_t)k[22]<<48)+((uint64_t)k[23]<<56)); - _c_mix64(a,b,c); - k += 24; len -= 24; - } - - /* handle the last 23 bytes */ - c += length; - switch(len) { - case 23: c+=((uint64_t)k[22]<<56); - case 22: c+=((uint64_t)k[21]<<48); - case 21: c+=((uint64_t)k[20]<<40); - case 20: c+=((uint64_t)k[19]<<32); - case 19: c+=((uint64_t)k[18]<<24); - case 18: c+=((uint64_t)k[17]<<16); - case 17: c+=((uint64_t)k[16]<<8); - /* the first byte of c is reserved for the length */ - case 16: b+=((uint64_t)k[15]<<56); - case 15: b+=((uint64_t)k[14]<<48); - case 14: b+=((uint64_t)k[13]<<40); - case 13: b+=((uint64_t)k[12]<<32); - case 12: b+=((uint64_t)k[11]<<24); - case 11: b+=((uint64_t)k[10]<<16); - case 10: b+=((uint64_t)k[ 9]<<8); - case 9: b+=((uint64_t)k[ 8]); - case 8: a+=((uint64_t)k[ 7]<<56); - case 7: a+=((uint64_t)k[ 6]<<48); - case 6: a+=((uint64_t)k[ 5]<<40); - case 5: a+=((uint64_t)k[ 4]<<32); - case 4: a+=((uint64_t)k[ 3]<<24); - case 3: a+=((uint64_t)k[ 2]<<16); - case 2: a+=((uint64_t)k[ 1]<<8); - case 1: a+=((uint64_t)k[ 0]); - /* case 0: nothing left to add */ - } - _c_mix64(a,b,c); - - return c; -} - -/** - * }@ - */ -#endif /* _C_JHASH_H */ - diff --git a/csync/src/std/c_lib.h b/csync/src/std/c_lib.h deleted file mode 100644 index b9c1ea8d3..000000000 --- a/csync/src/std/c_lib.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * cynapses libc functions - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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 -#include - -#include "c_macro.h" -#include "c_alloc.h" -#include "c_path.h" -#include "c_rbtree.h" -#include "c_string.h" -#include "c_time.h" -#include "c_private.h" diff --git a/csync/src/std/c_macro.h b/csync/src/std/c_macro.h deleted file mode 100644 index a4a0e1c1c..000000000 --- a/csync/src/std/c_macro.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * cynapses libc functions - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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_macro.h - * - * @brief cynapses libc macro definitions - * - * @defgroup cynMacroInternals cynapses libc macro definitions - * @ingroup cynLibraryAPI - * - * @{ - */ -#ifndef _C_MACRO_H -#define _C_MACRO_H - -#include -#include - -#define INT_TO_POINTER(i) (void *) i -#define POINTER_TO_INT(p) *((int *) (p)) - -/** Zero a structure */ -#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) - -/** Zero a structure given a pointer to the structure */ -#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0) - -/** Free memory and zero the pointer */ -#define SAFE_FREE(x) do { if ((x) != NULL) {free((void*)x); x=NULL;} } while(0) - -/** Get the smaller value */ -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - -/** Get the bigger value */ -#define MAX(a,b) ((a) < (b) ? (b) : (a)) - -/** Get the size of an array */ -#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) - -/** - * This is a hack to fix warnings. The idea is to use this everywhere that we - * get the "discarding const" warning by the compiler. That doesn't actually - * fix the real issue, but marks the place and you can search the code for - * discard_const. - * - * Please use this macro only when there is no other way to fix the warning. - * We should use this function in only in a very few places. - * - * Also, please call this via the discard_const_p() macro interface, as that - * makes the return type safe. - */ -#define discard_const(ptr) ((void *)((uintptr_t)(ptr))) - -/** - * Type-safe version of discard_const - */ -#define discard_const_p(type, ptr) ((type *)discard_const(ptr)) - -#if (__GNUC__ >= 3) -# ifndef likely -# define likely(x) __builtin_expect(!!(x), 1) -# endif -# ifndef unlikely -# define unlikely(x) __builtin_expect(!!(x), 0) -# endif -#else /* __GNUC__ */ -# ifndef likely -# define likely(x) (x) -# endif -# ifndef unlikely -# define unlikely(x) (x) -# endif -#endif /* __GNUC__ */ - -/** - * }@ - */ - -#ifdef _WIN32 -/* missing errno codes on mingw */ -#ifndef ENOTBLK -#define ENOTBLK 15 -#endif -#ifndef ETXTBSY -#define ETXTBSY 26 -#endif -#ifndef ENOBUFS -#define ENOBUFS WSAENOBUFS -#endif -#endif /* _WIN32 */ - -#endif /* _C_MACRO_H */ - diff --git a/csync/src/std/c_path.c b/csync/src/std/c_path.c deleted file mode 100644 index 1094a1c67..000000000 --- a/csync/src/std/c_path.c +++ /dev/null @@ -1,451 +0,0 @@ -/* - * cynapses libc functions - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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 _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include -#include - -#include "c_private.h" -#include "c_alloc.h" -#include "c_path.h" -#include "c_string.h" - -/* - * dirname - parse directory component. - */ -char *c_dirname (const char *path) { - char *newbuf = NULL; - unsigned int len; - - if (path == NULL || *path == '\0') { - return c_strdup("."); - } - - len = strlen(path); - - /* Remove trailing slashes */ - while(len > 0 && path[len - 1] == '/') --len; - - /* We have only slashes */ - if (len == 0) { - return c_strdup("/"); - } - - /* goto next slash */ - while(len > 0 && path[len - 1] != '/') --len; - - if (len == 0) { - return c_strdup("."); - } else if (len == 1) { - return c_strdup("/"); - } - - /* Remove slashes again */ - while(len > 0 && path[len - 1] == '/') --len; - - newbuf = c_malloc(len + 1); - - strncpy(newbuf, path, len); - newbuf[len] = '\0'; - - return newbuf; -} - -char *c_basename (const char *path) { - char *newbuf = NULL; - const char *s; - unsigned int len; - - if (path == NULL || *path == '\0') { - return c_strdup("."); - } - - len = strlen(path); - /* Remove trailing slashes */ - while(len > 0 && path[len - 1] == '/') --len; - - /* We have only slashes */ - if (len == 0) { - return c_strdup("/"); - } - - while(len > 0 && path[len - 1] != '/') --len; - - if (len > 0) { - s = path + len; - len = strlen(s); - - while(len > 0 && s[len - 1] == '/') --len; - } else { - return c_strdup(path); - } - - newbuf = c_malloc(len + 1); - - strncpy(newbuf, s, len); - newbuf[len] = '\0'; - - return newbuf; -} - -int c_parse_uri(const char *uri, - char **scheme, - char **user, char **passwd, - char **host, unsigned int *port, - char **path) { - const char *p, *z; - - if (uri == NULL || *uri == '\0') { - return -1; - } - - /* - * uri = scheme://user:password@host:port/path - * p = ^ - * z = ^ - */ - p = z = uri; - - /* check for valid scheme; git+ssh, pop3 */ - while (isalpha((int) *p) || isdigit((int) *p) || - *p == '+' || *p == '-') { - /* - * uri = scheme://user:password@host:port/path - * p = ^ - * z = ^ - */ - p++; - } - - /* get scheme */ - if (*p == ':') { - if (scheme != NULL) { - *scheme = c_strndup(z, p - z); - - if (*scheme == NULL) { - errno = ENOMEM; - return -1; - } - } - p++; - z = p; - } - - /* - * uri = scheme://user:password@host:port/path - * p = ^ - * z = ^ - */ - p = z; - - /* do we have a hostname */ - if (p[0] == '/' && p[1] == '/') { - /* - * uri = scheme://user:password@host:port/path - * p = ^ - * z = ^ - */ - z += 2; - p = z; - - /* check for user and passwd */ - while (*p && *p != '@' && *p != '/') { - /* - * uri = scheme://user:password@host:port/path - * p = ^ or ^ - * z = ^ - */ - p++; - } - - /* check for user and password */ - if (*p == '@') { - const char *q; - - q = p; - - /* check if we have a password */ - while (q > z && *q != ':') { - /* - * uri = scheme://user:password@host:port/path - * p = ^ - * z = ^ - * q = ^ - */ - q--; - } - - /* password found */ - if (*q == ':') { - if (user != NULL) { - *user = c_strndup(z, q - z); - if (*user == NULL) { - errno = ENOMEM; - if (scheme != NULL) SAFE_FREE(*scheme); - return -1; - } - } - - if (passwd != NULL) { - *passwd = c_strndup(q + 1, p - (q + 1)); - if (*passwd == NULL) { - if (scheme != NULL) SAFE_FREE(*scheme); - if (user != NULL) SAFE_FREE(*user); - errno = ENOMEM; - return -1; - } - } - } else { - /* user only */ - if (user != NULL) { - *user = c_strndup(z, p - z); - if( *user == NULL) { - if (scheme != NULL) SAFE_FREE(*scheme); - errno = ENOMEM; - return -1; - } - } - } - - p++; - z = p; - } - - /* - * uri = scheme://user:password@host:port/path - * p = ^ - * z = ^ - */ - p = z; - - /* check for IPv6 address */ - if (*p == '[') { - /* - * uri = scheme://user:password@[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:port/path - * p = ^ - * z = ^ - */ - p++; - - /* check if we have a valid IPv6 address */ - while (*p && (isxdigit((int) *p) || *p == '.' || *p == ':')) { - /* - * uri = scheme://user:password@[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:port/path - * p = ^ - * z = ^ - */ - p++; - } - - /* valid IPv6 address found */ - if (*p == ']') { - /* - * uri = scheme://user:password@[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:port/path - * p = ^ - * z = ^ - */ - z++; - - if (host != NULL) { - *host = c_strndup(z, p - z); - if (*host == NULL) { - if (scheme != NULL) SAFE_FREE(*scheme); - if (user != NULL) SAFE_FREE(*user); - if (passwd != NULL) SAFE_FREE(*passwd); - errno = ENOMEM; - return -1; - } - } - - /* - * uri = scheme://user:password@[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:port/path - * p = ^ - * z = ^ - */ - p++; - } else { - /* invalid IPv6 address, assume a hostname */ - p = z; - - while (*p && *p != ':' && *p != '/') { - p++; - /* - * uri = scheme://user:password@host:port/path - * p = ^ or ^ - * z = ^ - */ - } - - if (host != NULL) { - *host = c_strndup(z, p - z); - if (*host == NULL) { - if (scheme != NULL) SAFE_FREE(*scheme); - if (user != NULL) SAFE_FREE(*user); - if (passwd != NULL) SAFE_FREE(*passwd); - errno = ENOMEM; - return -1; - } - } - } - } else { - /* check for hostname */ - while (*p && *p != ':' && *p != '/') { - /* - * uri = scheme://user:password@host:port/path - * p = ^ ^ - * z = ^ - */ - p++; - } - - if (host != NULL) { - *host = c_strndup(z, p - z); - if (*host == NULL) { - if (scheme != NULL) SAFE_FREE(*scheme); - if (user != NULL) SAFE_FREE(*user); - if (passwd != NULL) SAFE_FREE(*passwd); - errno = ENOMEM; - return -1; - } - } - } - - /* check for port */ - if (*p == ':') { - char **e = NULL; - /* - * uri = scheme://user:password@host:port/path - * p = ^ - * z = ^ - */ - z = ++p; - - /* get only the digits */ - while (isdigit((int) *p)) { - /* - * uri = scheme://user:password@host:port/path - * p = ^ - * z = ^ - */ - e = (char **) &p; - p++; - } - - if (port != NULL) { - *port = strtoul(z, e, 0); - } - - /* - * uri = scheme://user:password@host:port/path - * p = ^ - */ - } - } - - if (*p == '\0') { - return 0; - } - - /* get the path with the leading slash */ - if (*p == '/') { - if (path != NULL) { - *path = c_strdup(p); - if (*path == NULL) { - if (scheme != NULL) SAFE_FREE(*scheme); - if (user != NULL) SAFE_FREE(*user); - if (passwd != NULL) SAFE_FREE(*passwd); - if (host != NULL) SAFE_FREE(*host); - errno = ENOMEM; - return -1; - } - } - - return 0; - } - - return -1; -} - - -/* - * This function takes a path and converts it to a UNC representation of the - * string. That means that it prepends a \\?\ (unless already UNC) and converts - * all slashes to backslashes. - * - * Note the following: - * - The string must be absolute. - * - it needs to contain a drive character to be a valid UNC - * - A conversion is only done if the path len is larger than 245. Otherwise - * the windows API functions work with the normal "unixoid" representation too. - * - * This function allocates memory that must be freed by the caller. - */ - const char *c_path_to_UNC(const char *str) - { - int len = 0; - char *longStr = NULL; - - len = strlen(str); - longStr = c_malloc(len+5); - *longStr = '\0'; - - // prepend \\?\ and convert '/' => '\' to support long names - if( str[0] == '/' || str[0] == '\\' ) { - // Don't prepend if already UNC - if( !(len > 1 && (str[1] == '/' || str[1] == '\\')) ) { - strcpy( longStr, "\\\\?"); - } - } else { - strcpy( longStr, "\\\\?\\"); // prepend string by this four magic chars. - } - strncat( longStr, str, len ); - - /* replace all occurences of / with the windows native \ */ - char *c = longStr; - for (; *c; ++c) { - if(*c == '/') { - *c = '\\'; - } - } - return longStr; - } - - mbchar_t* c_utf8_path_to_locale(const char *str) - { - if( str == NULL ) { - return NULL; - } else { - #ifdef _WIN32 - const char *unc_str = c_path_to_UNC(str); - mbchar_t *dst = c_utf8_string_to_locale(unc_str); - SAFE_FREE(unc_str); - return dst; - #else - return c_utf8_string_to_locale(str); - #endif - } - } diff --git a/csync/src/std/c_path.h b/csync/src/std/c_path.h deleted file mode 100644 index 291b1b8d3..000000000 --- a/csync/src/std/c_path.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * cynapses libc functions - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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_path.h - * - * @brief Interface of the cynapses libc path functions - * - * @defgroup cynPathInternals cynapses libc path functions - * @ingroup cynLibraryAPI - * - * @{ - */ - -#ifndef _C_PATH_H -#define _C_PATH_H - -#include "c_macro.h" -#include "c_private.h" - -/** - * @brief Parse directory component. - * - * dirname breaks a null-terminated pathname string into a directory component. - * In the usual case, c_dirname() returns the string up to, but not including, - * the final '/'. Trailing '/' characters are not counted as part of the - * pathname. The caller must free the memory. - * - * @param path The path to parse. - * - * @return The dirname of path or NULL if we can't allocate memory. If path - * does not contain a slash, c_dirname() returns the string ".". If - * path is the string "/", it returns the string "/". If path is - * NULL or an empty string, "." is returned. - */ -char *c_dirname(const char *path); - -/** - * @brief basename - parse filename component. - * - * basename breaks a null-terminated pathname string into a filename component. - * c_basename() returns the component following the final '/'. Trailing '/' - * characters are not counted as part of the pathname. - * - * @param path The path to parse. - * - * @return The filename of path or NULL if we can't allocate memory. If path - * is a the string "/", basename returns the string "/". If path is - * NULL or an empty string, "." is returned. - */ -char *c_basename (const char *path); - -/** - * @brief parse a uri and split it into components. - * - * parse_uri parses an uri in the format - * - * [:][//[[:]@][:]]/[] - * - * into its compoments. If you only want a special component, - * pass NULL for all other components. All components will be allocated if they have - * been found. - * - * @param uri The uri to parse. - * @param scheme String for the scheme component - * @param user String for the username component - * @param passwd String for the password component - * @param host String for the password component - * @param port Integer for the port - * @param path String for the path component with a leading slash. - * - * @return 0 on success, < 0 on error. - */ -int c_parse_uri(const char *uri, char **scheme, char **user, char **passwd, - char **host, unsigned int *port, char **path); - -/** - * @brief Parts of a path. - * - * @param directory '\0' terminated path including the final '/' - * - * @param filename '\0' terminated string - * - * @param extension '\0' terminated string - * - */ -typedef struct -{ - char * directory; - char * filename; - char * extension; -} C_PATHINFO; - -/** - * @brief c_path_to_UNC converts a unixoid path to UNC format. - * - * It converts the '/' to '\' and prepends \\?\ to the path. - * - * A proper windows path has to have a drive letter, otherwise it is not - * valid UNC. - * - * @param str The path to convert - * - * @return a pointer to the converted string. Caller has to free it. - */ -const char *c_path_to_UNC(const char *str); - -/** - * @brief c_utf8_path_to_locale converts a unixoid path to the locale aware format - * - * On windows, it converts to UNC and multibyte. - * On Mac, it converts to the correct utf8 using iconv. - * On Linux, it returns utf8 - * - * @param str The path to convert - * - * @return a pointer to the converted string. Caller has to free it using the - * function c_free_locale_string. - */ -mbchar_t* c_utf8_path_to_locale(const char *str); - -/** - * }@ - */ -#endif /* _C_PATH_H */ diff --git a/csync/src/std/c_private.h b/csync/src/std/c_private.h deleted file mode 100644 index 26bba70db..000000000 --- a/csync/src/std/c_private.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * cynapses libc functions - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Dominik Schmidt - * Copyright (c) 2012-2013 by Klaas Freitag - * - * 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 _C_PRIVATE_H -#define _C_PRIVATE_H - -#include "config_csync.h" - -/* cross platform defines */ -#include "config_csync.h" -#include -#include - -#ifdef _WIN32 -#include -#include -#include -#include -#else -#include -#endif - -#include - -#ifdef __MINGW32__ -#define EDQUOT 0 -#define ENODATA 0 -#ifndef S_IRGRP -#define S_IRGRP 0 -#endif -#ifndef S_IROTH -#define S_IROTH 0 -#endif -#ifndef S_IXGRP -#define S_IXGRP 0 -#endif -#ifndef S_IXOTH -#define S_IXOTH 0 -#endif - -#define S_IFSOCK 10000 /* dummy val on Win32 */ -#define S_IFLNK 10001 /* dummy val on Win32 */ - -#define O_NOFOLLOW 0 -#define O_NOCTTY 0 - -#define uid_t int -#define gid_t int -#define nlink_t int -#define getuid() 0 -#define geteuid() 0 -#elif defined(_WIN32) -#define mode_t int -#else -#include -#endif - -#ifndef ENODATA -#define ENODATA EPIPE -#endif - - -#ifdef _WIN32 -typedef struct stat64 csync_stat_t; -#define _FILE_OFFSET_BITS 64 -#else -typedef struct stat csync_stat_t; -#endif - -#ifndef O_NOATIME -#define O_NOATIME 0 -#endif - -#ifndef ENODATA -#define ENODATA EBADF -#endif - -#if !defined(HAVE_ASPRINTF) -#if defined(HAVE___MINGW_ASPRINTF) -#define asprintf __mingw_asprintf -#else -#include "asprintf.h" -#endif -#endif - -#ifndef HAVE_STRERROR_R -#define strerror_r(errnum, buf, buflen) snprintf(buf, buflen, "%s", strerror(errnum)) -#endif - -#ifndef HAVE_LSTAT -#define lstat _stat -#endif - -/* tchar definitions for clean win32 filenames */ -#ifndef _UNICODE -#define _UNICODE -#endif - -#if defined _WIN32 && defined _UNICODE -typedef wchar_t mbchar_t; -#define _topen _wopen -#define _tdirent _wdirent -#define _topendir _wopendir -#define _tclosedir _wclosedir -#define _treaddir _wreaddir -#define _trewinddir _wrewinddir -#define _ttelldir _wtelldir -#define _tseekdir _wseekdir -#define _tcreat _wcreat -#define _tstat _wstat64 -#define _tfstat _fstat64 -#define _tunlink _wunlink -#define _tmkdir(X,Y) _wmkdir(X) -#define _trmdir _wrmdir -#define _tchmod _wchmod -#define _trewinddir _wrewinddir -#define _tchown(X, Y, Z) 0 /* no chown on Win32 */ -#define _tchdir _wchdir -#define _tgetcwd _wgetcwd -#else -typedef char mbchar_t; -#define _tdirent dirent -#define _topen open -#define _topendir opendir -#define _tclosedir closedir -#define _treaddir readdir -#define _trewinddir rewinddir -#define _ttelldir telldir -#define _tseekdir seekdir -#define _tcreat creat -#define _tstat lstat -#define _tfstat fstat -#define _tunlink unlink -#define _tmkdir(X,Y) mkdir(X,Y) -#define _trmdir rmdir -#define _tchmod chmod -#define _trewinddir rewinddir -#define _tchown(X,Y,Z) chown(X,Y,Z) -#define _tchdir chdir -#define _tgetcwd getcwd -#endif - -/* FIXME: Implement TLS for OS X */ -#if defined(__GNUC__) && !defined(__APPLE__) -# define CSYNC_THREAD __thread -#elif defined(_MSC_VER) -# define CSYNC_THREAD __declspec(thread) -#else -# define CSYNC_THREAD -#endif - -#endif //_C_PRIVATE_H - -/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/csync/src/std/c_rbtree.c b/csync/src/std/c_rbtree.c deleted file mode 100644 index 9a38fd0a6..000000000 --- a/csync/src/std/c_rbtree.c +++ /dev/null @@ -1,743 +0,0 @@ -/* - * cynapses libc functions - * - * Copyright (c) 2003-2004 by Andrew Suffield - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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 - */ - -/* - * This code was originally released under GPL but Andrew Suffield agreed to - * change it to LGPL. - */ - -/* - * static function don't have NULL pointer checks, segfaults are intended. - */ - -#include -#include -#include - -#include "c_alloc.h" -#include "c_rbtree.h" - -#define NIL &_sentinel /* all leafs are sentinels */ -static c_rbnode_t _sentinel = {NULL, NIL, NIL, NULL, NULL, BLACK}; - -void c_rbtree_create(c_rbtree_t **rbtree, c_rbtree_compare_func *key_compare, c_rbtree_compare_func *data_compare) { - assert(rbtree); - assert(key_compare); - assert(data_compare); - - c_rbtree_t *tree = NULL; - - tree = c_malloc(sizeof(*tree)); - tree->root = NIL; - tree->key_compare = key_compare; - tree->data_compare = data_compare; - tree->size = 0; - - *rbtree = tree; -} - -static c_rbnode_t *_rbtree_subtree_dup(const c_rbnode_t *node, c_rbtree_t *new_tree, c_rbnode_t *new_parent) { - c_rbnode_t *new_node = NULL; - - new_node = (c_rbnode_t*) c_malloc(sizeof(c_rbnode_t)); - - new_node->tree = new_tree; - new_node->data = node->data; - new_node->color = node->color; - new_node->parent = new_parent; - - if (node->left == NIL) { - new_node->left = NIL; - } else { - new_node->left = _rbtree_subtree_dup(node->left, new_tree, new_node); - } - - if (node->right == NIL) { - new_node->right = NIL; - } else { - new_node->right = _rbtree_subtree_dup(node->right, new_tree, new_node); - } - - return new_node; -} - -c_rbtree_t *c_rbtree_dup(const c_rbtree_t *tree) { - c_rbtree_t *new_tree = NULL; - - new_tree = (c_rbtree_t*) c_malloc(sizeof(c_rbtree_t)); - - new_tree->key_compare = tree->key_compare; - new_tree->data_compare = tree->data_compare; - new_tree->size = tree->size; - new_tree->root = _rbtree_subtree_dup(tree->root, new_tree, NULL); - - return new_tree; -} - -static int _rbtree_subtree_free(c_rbnode_t *node) { - assert(node); - - if (node->left != NIL) { - if (_rbtree_subtree_free(node->left) < 0) { - /* TODO: set errno? ECANCELED? */ - return -1; - } - } - - if (node->right != NIL) { - if (_rbtree_subtree_free(node->right) < 0) { - /* TODO: set errno? ECANCELED? */ - return -1; - } - } - - SAFE_FREE(node); - - return 0; -} - -int c_rbtree_free(c_rbtree_t *tree) { - if (tree == NULL) { - errno = EINVAL; - return -1; - } - - if (tree->root != NIL) { - _rbtree_subtree_free(tree->root); - } - - SAFE_FREE(tree); - - return 0; -} - -static int _rbtree_subtree_walk(c_rbnode_t *node, void *data, c_rbtree_visit_func *visitor) { - assert(node); - assert(data); - assert(visitor); - - if (node == NIL) { - return 0; - } - - if (_rbtree_subtree_walk(node->left, data, visitor) < 0) { - return -1; - } - - if ((*visitor)(node->data, data) < 0) { - return -1; - } - - if (_rbtree_subtree_walk(node->right, data, visitor) < 0) { - return -1; - } - - return 0; -} - -int c_rbtree_walk(c_rbtree_t *tree, void *data, c_rbtree_visit_func *visitor) { - if (tree == NULL || data == NULL || visitor == NULL) { - errno = EINVAL; - return -1; - } - - if (_rbtree_subtree_walk(tree->root, data, visitor) < 0) { - return -1; - } - - return 0; -} - -static c_rbnode_t *_rbtree_subtree_head(c_rbnode_t *node) { - assert(node); - - if (node == NIL) { - return node; - } - - while (node->left != NIL) { - node = node->left; - } - - return node; -} - -static c_rbnode_t *_rbtree_subtree_tail(c_rbnode_t *node) { - assert(node); - - if (node == NIL) { - return node; - } - - while (node->right != NIL) { - node = node->right; - } - - return node; -} - -c_rbnode_t *c_rbtree_head(c_rbtree_t *tree) { - c_rbnode_t *node = NULL; - - if (tree == NULL) { - errno = EINVAL; - return NULL; - } - - node = _rbtree_subtree_head(tree->root); - - return node != NIL ? node : NULL; -} - -c_rbnode_t *c_rbtree_tail(c_rbtree_t *tree) { - c_rbnode_t *node = NULL; - - if (tree == NULL) { - errno = EINVAL; - return NULL; - } - - node = _rbtree_subtree_tail(tree->root); - - return node != NIL ? node : NULL; -} - -c_rbnode_t *c_rbtree_node_next(c_rbnode_t *node) { - c_rbnode_t *parent = NULL; - - if (node == NULL) { - errno = EINVAL; - return NULL; - } - - if (node->right != NIL) { - c_rbnode_t *next = NULL; - next = _rbtree_subtree_head(node->right); - - return next != NIL ? next : NULL; - } - - parent = node->parent; - while (parent && node == parent->right) { - node = parent; - parent = node->parent; - } - - return parent != NULL ? parent : NULL; -} - -c_rbnode_t *c_rbtree_node_prev(c_rbnode_t *node) { - c_rbnode_t *parent = NULL; - - if (node == NULL) { - return NULL; - } - - if (node->left != NIL) { - c_rbnode_t *prev = NULL; - prev = _rbtree_subtree_tail(node->left); - return prev != NIL ? prev : NULL; - } - - parent = node->parent; - while (parent && node == parent->left) { - node = parent; - parent = node->parent; - } - - return parent != NULL ? parent : NULL; -} - -c_rbnode_t *c_rbtree_find(c_rbtree_t *tree, const void *key) { - int cmp = 0; - c_rbnode_t *node = NULL; - - if (tree == NULL) { - errno = EINVAL; - return NULL; - } - node = tree->root; - - while (node != NIL) { - cmp = tree->key_compare(key, node->data); - if (cmp == 0) { - return node; - } - - if (cmp < 0) { - node = node->left; - } else { - node = node->right; - } - } - - return NULL; -} - -static void _rbtree_subtree_left_rotate(c_rbnode_t *x) { - c_rbnode_t *y = NULL; - - assert(x); - - y = x->right; - - /* establish x-right link */ - x->right = y->left; - - if (y->left != NIL) { - y->left->parent = x; - } - - /* establish y->parent link */ - if (y != NIL) { - y->parent = x->parent; - } - - if (x->parent) { - if (x == x->parent->left) { - x->parent->left = y; - } else { - x->parent->right = y; - } - } else { - x->tree->root = y; - } - - /* link x and y */ - y->left = x; - if (x != NIL) { - x->parent = y; - } -} - -/* rotat node x to the right */ -static void _rbtree_subtree_right_rotate(c_rbnode_t *x) { - c_rbnode_t *y = NULL; - - assert(x); - - y = x->left; - - /* establish x->left link */ - x->left = y->right; - - if (y->right != NIL) { - y->right->parent = x; - } - - /* establish y->parent link */ - if (y != NIL) { - y->parent = x->parent; - } - - if (x->parent) { - if (x == x->parent->right) { - x->parent->right = y; - } else { - x->parent->left = y; - } - } else { - x->tree->root = y; - } - - /* link x and y */ - y->right = x; - if (x != NIL) { - x->parent = y; - } -} - -int c_rbtree_insert(c_rbtree_t *tree, void *data) { - int cmp = 0; - c_rbnode_t *current = NULL; - c_rbnode_t *parent = NULL; - c_rbnode_t *x = NULL; - - if (tree == NULL) { - errno = EINVAL; - return -1; - } - - /* First we do a classic binary tree insert */ - current = tree->root; - parent = NULL; - - while (current != NIL) { - cmp = tree->data_compare(data, current->data); - parent = current; - if (cmp == 0) { - return 1; - } else if (cmp < 0) { - current = current->left; - } else { - current = current->right; - } - } - - x = (c_rbnode_t *) c_malloc(sizeof(c_rbnode_t)); - - x->tree = tree; - x->data = data; - x->parent = parent; - x->left = NIL; - x->right = NIL; - x->color = RED; - - if (parent) { - /* Note that cmp still contains the comparison of data with - * parent->data, from the last pass through the loop above - */ - if (cmp < 0) { - parent->left = x; - } else { - parent->right = x; - } - } else { - tree->root = x; - } - - /* Insert fixup - check red-black properties */ - while (x != tree->root && x->parent->color == RED) { - /* we have a violation */ - if (x->parent == x->parent->parent->left) { - c_rbnode_t *y = NULL; - - y = x->parent->parent->right; - if (y->color == RED) { - x->parent->color = BLACK; - y->color = BLACK; - x->parent->parent->color = RED; - x = x->parent->parent; - } else { - /* uncle is back */ - if (x == x->parent->right) { - /* make x a left child */ - x = x->parent; - _rbtree_subtree_left_rotate(x); - } - x->parent->color = BLACK; - x->parent->parent->color = RED; - _rbtree_subtree_right_rotate(x->parent->parent); - } - } else { - c_rbnode_t *y = NULL; - - y = x->parent->parent->left; - if (y->color == RED) { - x->parent->color = BLACK; - y->color = BLACK; - x->parent->parent->color = RED; - x = x->parent->parent; - } else { - /* uncle is back */ - if (x == x->parent->left) { - x = x->parent; - _rbtree_subtree_right_rotate(x); - } - x->parent->color = BLACK; - x->parent->parent->color = RED; - _rbtree_subtree_left_rotate(x->parent->parent); - } - } - } /* end while */ - tree->root->color = BLACK; - - tree->size++; - - return 0; -} - -int c_rbtree_node_delete(c_rbnode_t *node) { - c_rbtree_t *tree; - c_rbnode_t *y; - c_rbnode_t *x; - - if (node == NULL || node == NIL) { - errno = EINVAL; - return -1; - } - - tree = node->tree; - - if (node->left == NIL || node->right == NIL) { - /* y has a NIL node as a child */ - y = node; - } else { - /* find tree successor with a NIL node as a child */ - y = node; - while(y->left != NIL) { - y = y->left; - } - } - - /* x is y's only child */ - if (y->left != NIL) { - x = y->left; - } else { - x = y->right; - } - - /* remove y from the parent chain */ - x->parent = y->parent; - - if (y->parent) { - if (y == y->parent->left) { - y->parent->left = x; - } else { - y->parent->right = x; - } - } else { - y->tree->root = x; - } - - /* If y is not the node we're deleting, splice it in place of that - * node - * - * The traditional code would call for us to simply copy y->data, but - * that would invalidate the wrong pointer - there might be external - * references to this node, and we must preserve its address. - */ - if (y != node) { - /* Update y */ - y->parent = node->parent; - y->left = node->left; - y->right = node->right; - - /* Update the children and the parent */ - if (y->left != NIL) { - y->left->parent = y; - } - if (y->right != NIL) { - y->right->parent = y; - } - if (y->parent != NULL) { - if (node == y->parent->left) { - y->parent->left = y; - } else { - y->parent->right = y; - } - } else { - y->tree->root = y; - } - } - - if (y->color == BLACK) { - while (x != y->tree->root && x->color == BLACK) { - if (x == x->parent->left) { - c_rbnode_t *w = NULL; - - w = x->parent->right; - - if (w->color == RED) { - w->color = BLACK; - x->parent->color = RED; - _rbtree_subtree_left_rotate(x->parent); - w = x->parent->right; - } - - if (w->left->color == BLACK && w->right->color == BLACK) { - w->color = RED; - x = x->parent; - } else { - if (w->right->color == BLACK) { - w->left->color = BLACK; - w->color = RED; - _rbtree_subtree_right_rotate(w); - w = x->parent->right; - } - w->color = x->parent->color; - x->parent->color = BLACK; - w->right->color = BLACK; - _rbtree_subtree_left_rotate(x->parent); - x = y->tree->root; - } - } else { - c_rbnode_t *w = NULL; - - w = x->parent->left; - if (w->color == RED) { - w->color = BLACK; - x->parent->color = RED; - _rbtree_subtree_right_rotate(x->parent); - w = x->parent->left; - } - - if (w->right->color == BLACK && w->left->color == BLACK) { - w->color = RED; - x = x->parent; - } else { - if (w->left->color == BLACK) { - w->right->color = BLACK; - w->color = RED; - _rbtree_subtree_left_rotate(w); - w = x->parent->left; - } - w->color = x->parent->color; - x->parent->color = BLACK; - w->left->color = BLACK; - _rbtree_subtree_right_rotate(x->parent); - x = y->tree->root; - } - } - } - x->color = BLACK; - } /* end if: y->color == BLACK */ - - /* node has now been spliced out of the tree */ - SAFE_FREE(y); - tree->size--; - - return 0; -} - -static int _rbtree_subtree_check_black_height(c_rbnode_t *node) { - int left = 0; - int right = 0; - - assert(node); - - if (node == NIL) { - return 0; - } - - left = _rbtree_subtree_check_black_height(node->left); - right = _rbtree_subtree_check_black_height(node->right); - if (left != right) { - return -1; - } - - return left + (node->color == BLACK); -} - -int c_rbtree_check_sanity(c_rbtree_t *tree) { - c_rbnode_t *node = NULL; - c_rbnode_t *prev = NULL; - c_rbnode_t *next = NULL; - c_rbnode_t *tail = NULL; - size_t size = 0; - - if (tree == NULL) { - errno = EINVAL; - return -1; - } - - if (! tree->key_compare || ! tree->data_compare) { - errno = EINVAL; - return -2; - } - - /* Iterate the tree */ - tail = c_rbtree_tail(tree); - for (node = c_rbtree_head(tree); node; node = next) { - if (node->tree != tree) { - return -4; - } - - /* We should never see a nil while iterating */ - if (node == NIL) { - return -5; - } - - /* node == tree-root iff node->parent == NIL */ - if (node == tree->root) { - if (node->parent != NULL) { - return -6; - } - } else { - if (node->parent == NULL) { - return -7; - } - } - - /* Invertability of the iterate functions */ - if (prev != c_rbtree_node_prev(node)) { - return -8; - } - - /* Check the iteration sequence */ - if (prev) { - if (tree->data_compare(prev->data, node->data) > 0) { - return -9; - } - - /* And the other way around, to make sure data_compare is stable */ - if (tree->data_compare(node->data, prev->data) < 0) { - return -10; - } - } - - /* The binary tree property */ - if (node->left != NIL) { - if (tree->data_compare(node->left->data, node->data) > 0) { - return -11; - } - - if (tree->data_compare(node->data, node->left->data) < 0) { - return -11; - } - } - - if (node->right != NIL) { - if (tree->data_compare(node->data, node->right->data) > 0) { - return -12; - } - - if (tree->data_compare(node->right->data, node->data) < 0) { - return -13; - } - } - - /* Red-black tree property 3: red nodes have black children */ - if (node->color == RED) { - if (node->left->color == RED) { - return -14; - } - if (node->right->color == RED) { - return -15; - } - } - - /* next == NULL if node == tail */ - next = c_rbtree_node_next(node); - if (next) { - if (node == tail) { - return -16; - } - } else { - if (node != tail) { - return -17; - } - } - - prev = node; - size++; - } /* end for loop */ - - if (size != tree->size) { - return -18; - } - - if (_rbtree_subtree_check_black_height(tree->root) < 0) { - return -19; - } - - return 0; -} diff --git a/csync/src/std/c_rbtree.h b/csync/src/std/c_rbtree.h deleted file mode 100644 index 635458fd2..000000000 --- a/csync/src/std/c_rbtree.h +++ /dev/null @@ -1,309 +0,0 @@ -/* - * cynapses libc functions - * - * Copyright (c) 2003-2004 by Andrew Suffield - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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_rbtree.h - * - * @brief Interface of the cynapses libc red-black tree implementation - * - * A red-black tree is a type of self-balancing binary search tree. It is - * complex, but has good worst-case running time for its operations and is - * efficient in practice: it can search, insert, and delete in O(log n) - * time, where n is the number of elements in the tree. - * - * In red-black trees, the leaf nodes are not relevant and do not contain - * data. Therefore we use a sentinal node to save memory. All references - * from internal nodes to leaf nodes instead point to the sentinel node. - * - * In a red-black tree each node has a color attribute, the value of which - * is either red or black. In addition to the ordinary requirements imposed - * on binary search trees, the following additional requirements of any - * valid red-black tree apply: - * - * 1. A node is either red or black. - * 2. The root is black. - * 3. All leaves are black, even when the parent is black - * (The leaves are the null children.) - * 4. Both children of every red node are black. - * 5. Every simple path from a node to a descendant leaf contains the same - * number of black nodes, either counting or not counting the null black - * nodes. (Counting or not counting the null black nodes does not affect - * the structure as long as the choice is used consistently.). - * - * These constraints enforce a critical property of red-black trees: that the - * longest path from the root to a leaf is no more than twice as long as the - * shortest path from the root to a leaf in that tree. The result is that the - * tree is roughly balanced. Since operations such as inserting, deleting, and - * finding values requires worst-case time proportional to the height of the - * tree, this theoretical upper bound on the height allows red-black trees to - * be efficient in the worst-case, unlike ordinary binary search trees. - * - * http://en.wikipedia.org/wiki/Red-black_tree - * - * @defgroup cynRBTreeInternals cynapses libc red-black tree functions - * @ingroup cynLibraryAPI - * - * @{ - */ -#ifndef _C_RBTREE_H -#define _C_RBTREE_H - -/* Forward declarations */ -struct c_rbtree_s; typedef struct c_rbtree_s c_rbtree_t; -struct c_rbnode_s; typedef struct c_rbnode_s c_rbnode_t; - -/** - * Define the two colors for the red-black tree - */ -enum xrbcolor_e { BLACK = 0, RED }; typedef enum xrbcolor_e xrbcolor_t; - -/** - * @brief Callback function to compare a key with the data from a - * red-black tree node. - * - * @param key key as a generic pointer - * @param data data as a generic pointer - * - * @return It returns an integer less than, equal to, or greater than zero - * depending on the key or data you use. The function is similar - * to strcmp(). - */ -typedef int c_rbtree_compare_func(const void *key, const void *data); - -/** - * @brief Visit function for the c_rbtree_walk() function. - * - * This function will be called by c_rbtree_walk() for every node. It is up to - * the developer what the function does. The fist parameter is a node object - * the second can be of any kind. - * - * @param obj The node data that will be passed by c_rbtree_walk(). - * @param data Generic data pointer. - * - * @return 0 on success, < 0 on error. You should set errno. - * - */ -typedef int c_rbtree_visit_func(void *, void *); - -/** - * Structure that represents a red-black tree - */ -struct c_rbtree_s { - c_rbnode_t *root; - c_rbtree_compare_func *key_compare; - c_rbtree_compare_func *data_compare; - size_t size; -}; - -/** - * Structure that represents a node of a red-black tree - */ -struct c_rbnode_s { - c_rbtree_t *tree; - c_rbnode_t *left; - c_rbnode_t *right; - c_rbnode_t *parent; - void *data; - xrbcolor_t color; -}; - -/** - * @brief Create the red-black tree - * - * @param rbtree The pointer to assign the allocated memory. - * - * @param key_compare Callback function to compare a key with the data - * inside a reb-black tree node. - * - * @param data_compare Callback function to compare a key as data with thee - * data inside a red-black tree node. - */ -void c_rbtree_create(c_rbtree_t **rbtree, c_rbtree_compare_func *key_compare, c_rbtree_compare_func *data_compare); - -/** - * @brief Duplicate a red-black tree. - * - * @param tree Tree to duplicate. - * - * @return Pointer to a new allocated duplicated rbtree. NULL if an error - * occurred. - */ -c_rbtree_t *c_rbtree_dup(const c_rbtree_t *tree); - -/** - * @brief Free the structure of a red-black tree. - * - * You should call c_rbtree_destroy() before you call this function. - * - * @param tree The tree to free. - * - * @return 0 on success, less than 0 if an error occurred. - */ -int c_rbtree_free(c_rbtree_t *tree); - -/** - * @brief Destroy the content and the nodes of an red-black tree. - * - * This is far from the most efficient way to walk a tree, but it is - * the *safest* way to destroy a tree - the destructor can do almost - * anything (as long as it does not create an infinite loop) to the - * tree structure without risk. - * - * If for some strange reason you need a faster destructor (think - * twice - speed and memory deallocation don't mix well) then consider - * stashing an llist of dataects and destroying that instead, and just - * using c_rbtree_free() on your tree. - * - * @param T The tree to destroy. - * @param DESTRUCTOR The destructor to call on a node to destroy. - */ -#define c_rbtree_destroy(T, DESTRUCTOR) \ - do { \ - if (T) { \ - c_rbnode_t *_c_rbtree_temp; \ - while ((_c_rbtree_temp = c_rbtree_head(T))) { \ - (DESTRUCTOR)(_c_rbtree_temp->data); \ - if (_c_rbtree_temp == c_rbtree_head(T)) { \ - c_rbtree_node_delete(_c_rbtree_temp); \ - } \ - } \ - } \ - SAFE_FREE(T); \ - } while (0); - -/** - * @brief Inserts a node into a red black tree. - * - * @param tree The red black tree to insert the node. - * @param data The data to insert into the tree. - * - * @return 0 on success, 1 if a duplicate has been found and < 0 if an error - * occurred with errno set. - * EINVAL if a null pointer has been passed as the tree. - * ENOMEM if there is no memory left. - */ -int c_rbtree_insert(c_rbtree_t *tree, void *data); - -/** - * @brief Find a node in a red-black tree. - * - * c_rbtree_find() is searching for the given key in a red-black tree and - * returns the node if the key has been found. - * - * @param tree The tree to search. - * @param key The key to search for. - * - * @return If the key was found the node will be returned. On error NULL - * will be returned. - */ -c_rbnode_t *c_rbtree_find(c_rbtree_t *tree, const void *key); - -/** - * @brief Get the head of the red-black tree. - * - * @param tree The tree to get the head for. - * - * @return The head node. NULL if an error occurred. - */ -c_rbnode_t *c_rbtree_head(c_rbtree_t *tree); - -/** - * @brief Get the tail of the red-black tree. - * - * @param tree The tree to get the tail for. - * - * @return The tail node. NULL if an error occurred. - */ -c_rbnode_t *c_rbtree_tail(c_rbtree_t *tree); - -/** - * @brief Get the size of the red-black tree. - * - * @param T The tree to get the size from. - * - * @return The size of the red-black tree. - */ -#define c_rbtree_size(T) (T) == NULL ? 0 : ((T)->size) - -/** - * @brief Walk over a red-black tree. - * - * Walk over a red-black tree calling a visitor function for each node found. - * - * @param tree Tree to walk. - * @param data Data which should be passed to the visitor function. - * @param visitor Visitor function. This will be called for each node passed. - * - * @return 0 on sucess, less than 0 if an error occurred. - */ -int c_rbtree_walk(c_rbtree_t *tree, void *data, c_rbtree_visit_func *visitor); - -/** - * @brief Delete a node in a red-black tree. - * - * @param node Node which should be deleted. - * - * @return 0 on success, -1 if an error occurred. - */ -int c_rbtree_node_delete(c_rbnode_t *node); - -/** - * @brief Get the next node. - * - * @param node The node of which you want the next node. - * - * @return The next node, NULL if an error occurred. - */ -c_rbnode_t *c_rbtree_node_next(c_rbnode_t *node); - -/** - * @brief Get the previous node. - * - * @param node The node of which you want the previous node. - * - * @return The previous node, NULL if an error occurred. - */ -c_rbnode_t *c_rbtree_node_prev(c_rbnode_t *node); - -/** - * @brief Get the data of a node. - * - * @param N The node to get the data from. - * - * @return The data, NULL if an error occurred. - */ -#define c_rbtree_node_data(N) ((N) ? ((N)->data) : NULL) - -/** - * @brief Perform a sanity check for a red-black tree. - * - * This is mostly for testing purposes. - * - * @param tree The tree to check. - * - * @return 0 on success, less than 0 if an error occurred. - */ -int c_rbtree_check_sanity(c_rbtree_t *tree); - -/** - * }@ - */ -#endif /* _C_RBTREE_H */ diff --git a/csync/src/std/c_string.c b/csync/src/std/c_string.c deleted file mode 100644 index 8929f2458..000000000 --- a/csync/src/std/c_string.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * cynapses libc functions - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * 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 "config_csync.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "c_string.h" -#include "c_path.h" -#include "c_alloc.h" -#include "c_macro.h" - -#ifdef _WIN32 -#include -#endif - -int c_strncasecmp(const char *a, const char *b, size_t n) { -#ifdef _WIN32 - return _strnicmp(a, b, n); -#else - return strncasecmp(a, b, n); -#endif -} - -int c_streq(const char *a, const char *b) { - register const char *s1 = a; - register const char *s2 = b; - - if (s1 == NULL || s2 == NULL) { - return 0; - } - - while (*s1 == *s2++) { - if (*s1++ == '\0') { - return 1; - } - } - - return 0; -} - -c_strlist_t *c_strlist_new(size_t size) { - c_strlist_t *strlist = NULL; - - if (size == 0) { - errno = EINVAL; - return NULL; - } - - strlist = c_malloc(sizeof(c_strlist_t)); - if (strlist == NULL) { - return NULL; - } - - strlist->vector = (char **) c_malloc(size * sizeof(char *)); - strlist->count = 0; - strlist->size = size; - - return strlist; -} - -c_strlist_t *c_strlist_expand(c_strlist_t *strlist, size_t size) { - if (strlist == NULL || size == 0) { - errno = EINVAL; - return NULL; - } - - if (strlist->size >= size) { - return strlist; - } - - strlist->vector = (char **) c_realloc(strlist->vector, size * sizeof(char *)); - if (strlist->vector == NULL) { - return NULL; - } - - strlist->size = size; - - return strlist; -} - -int c_strlist_add(c_strlist_t *strlist, const char *string) { - if (strlist == NULL || string == NULL) { - return -1; - } - - if (strlist->count < strlist->size) { - strlist->vector[strlist->count] = c_strdup(string); - if (strlist->vector[strlist->count] == NULL) { - return -1; - } - strlist->count++; - } else { - errno = ENOBUFS; - return -1; - } - - return 0; -} - -int c_strlist_add_grow(c_strlist_t **strlist, const char *string) { - if (*strlist == NULL) { - *strlist = c_strlist_new(32); - if (*strlist == NULL) { - return -1; - } - } - - if ((*strlist)->count == (*strlist)->size) { - c_strlist_t *list = c_strlist_expand(*strlist, 2 * (*strlist)->size); - if (list == NULL) { - return -1; - } - *strlist = list; - } - - return c_strlist_add(*strlist, string); -} - -void c_strlist_clear(c_strlist_t *strlist) { - size_t i = 0; - - if (strlist == NULL) { - return; - } - - for (i = 0; i < strlist->count; i++) { - SAFE_FREE(strlist->vector[i]); - } - - strlist->count = 0; -} - -void c_strlist_destroy(c_strlist_t *strlist) { - - if (strlist == NULL) { - return; - } - - c_strlist_clear(strlist); - SAFE_FREE(strlist->vector); - SAFE_FREE(strlist); -} diff --git a/csync/src/std/c_string.h b/csync/src/std/c_string.h deleted file mode 100644 index 304c598a2..000000000 --- a/csync/src/std/c_string.h +++ /dev/null @@ -1,221 +0,0 @@ -/* - * cynapses libc functions - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * 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_string.h - * - * @brief Interface of the cynapses string implementations - * - * @defgroup cynStringInternals cynapses libc string functions - * @ingroup cynLibraryAPI - * - * @{ - */ -#ifndef _C_STR_H -#define _C_STR_H - -#include "c_private.h" -#include "c_macro.h" - -#include - -struct c_strlist_s; typedef struct c_strlist_s c_strlist_t; - -/** - * @brief Structure for a stringlist - * - * Using a for loop you can access the strings saved in the vector. - * - * c_strlist_t strlist; - * int i; - * for (i = 0; i < strlist->count; i++) { - * printf("value: %s", strlist->vector[i]; - * } - */ -struct c_strlist_s { - /** The string vector */ - char **vector; - /** The count of the strings saved in the vector */ - size_t count; - /** Size of strings allocated */ - size_t size; -}; - -/** - * @brief Compare to strings case insensitively. - * - * @param a First string to compare. - * @param b Second string to compare. - * @param n Max comparison length. - * - * @return see strncasecmp - */ -int c_strncasecmp(const char *a, const char *b, size_t n); - -/** - * @brief Compare to strings if they are equal. - * - * @param a First string to compare. - * @param b Second string to compare. - * - * @return 1 if they are equal, 0 if not. - */ -int c_streq(const char *a, const char *b); - -/** - * @brief Create a new stringlist. - * - * @param size Size to allocate. - * - * @return Pointer to the newly allocated stringlist. NULL if an error occured. - */ -c_strlist_t *c_strlist_new(size_t size); - -/** - * @brief Expand the stringlist - * - * @param strlist Stringlist to expand - * @param size New size of the strlinglist to expand - * - * @return Pointer to the expanded stringlist. NULL if an error occured. - */ -c_strlist_t *c_strlist_expand(c_strlist_t *strlist, size_t size); - -/** - * @brief Add a string to the stringlist. - * - * Duplicates the string and stores it in the stringlist. - * - * @param strlist Stringlist to add the string. - * @param string String to add. - * - * @return 0 on success, less than 0 and errno set if an error occured. - * ENOBUFS if the list is full. - */ -int c_strlist_add(c_strlist_t *strlist, const char *string); - -/** - * @brief Add a string to the stringlist, growing it if necessary - * - * Duplicates the string and stores it in the stringlist. - * It also initializes the stringlist if it starts out as null. - * - * @param strlist Stringlist to add the string. - * @param string String to add. - * - * @return 0 on success, less than 0 and errno set if an error occured. - */ -int c_strlist_add_grow(c_strlist_t **strlist, const char *string); - -/** - * @brief Removes all strings from the list. - * - * Frees the strings. - * - * @param strlist Stringlist to clear - */ -void c_strlist_clear(c_strlist_t *strlist); - -/** - * @brief Destroy the memory of the stringlist. - * - * Frees the strings and the stringlist. - * - * @param strlist Stringlist to destroy - */ -void c_strlist_destroy(c_strlist_t *strlist); - -/** - * @brief Convert a platform locale string to utf8. - * - * This function is part of the multi platform abstraction of basic file - * operations to handle various platform encoding correctly. - * - * Instead of using the standard file operations the multi platform aliases - * defined in c_private.h have to be used instead. - * - * To convert path names returned by these functions to the internally used - * utf8 format this function has to be used. The returned string has to - * be freed by c_free_locale_string(). On some platforms this method allocates - * memory and on others not but it has never to be cared about. - * - * @param str The multibyte encoded string to convert - * - * @return The malloced converted string or NULL on error. - * - * @see c_free_locale_string() - * @see c_utf8_to_locale() - * - */ - char* c_utf8_from_locale(const mbchar_t *str); - -/** - * @brief Convert a utf8 encoded string to platform specific locale. - * - * This function is part of the multi platform abstraction of basic file - * operations to handle various platform encoding correctly. - * - * Instead of using the standard file operations the multi platform aliases - * defined in c_private.h have to be used instead. - * - * To convert strings as input for the cross platform functions from the - * internally used utf8 format, this function has to be used. - * The returned string has to be freed by c_free_locale_string(). On some - * platforms this method allocates memory and on others not but it has never - * sto be cared about. - * - * If the string to convert is a path, consider using c_utf8_path_to_locale(). - * - * @param str The utf8 string to convert. - * - * @return The malloced converted multibyte string or NULL on error. - * - * @see c_free_locale_string() - * @see c_utf8_from_locale() - * - */ -mbchar_t* c_utf8_string_to_locale(const char *wstr); - -/** - * @brief Free buffer malloced by c_utf8_from_locale or c_utf8_to_locale(). - * - * This function is part of the multi platform abstraction of basic file - * operations to handle various platform encoding correctly. - * - * Instead of using the standard file operations the multi platform aliases - * defined in c_private.h have to be used instead. - * - * This function frees the memory that was allocated by a previous call to - * c_utf8_to_locale() or c_utf8_from_locale(). - * - * @param buf The buffer to free. - * - * @see c_utf8_from_locale(), c_utf8_to_locale() - * - */ -#define c_free_locale_string(x) SAFE_FREE(x) - - -/** - * }@ - */ -#endif /* _C_STR_H */ - diff --git a/csync/src/std/c_time.c b/csync/src/std/c_time.c deleted file mode 100644 index ad43fed02..000000000 --- a/csync/src/std/c_time.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * c_time - time functions - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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 "config_csync.h" -#include "c_private.h" -#include "c_string.h" - -#include "c_path.h" -#include "c_time.h" - -#ifndef _WIN32 -#include -#endif - -struct timespec c_tspecdiff(struct timespec time1, struct timespec time0) { - struct timespec ret; - int xsec = 0; - int sign = 1; - - if (time0.tv_nsec > time1.tv_nsec) { - xsec = (int) ((time0.tv_nsec - time1.tv_nsec) / (1E9 + 1)); - time0.tv_nsec -= (long int) (1E9 * xsec); - time0.tv_sec += xsec; - } - - if ((time1.tv_nsec - time0.tv_nsec) > 1E9) { - xsec = (int) ((time1.tv_nsec - time0.tv_nsec) / 1E9); - time0.tv_nsec += (long int) (1E9 * xsec); - time0.tv_sec -= xsec; - } - - ret.tv_sec = time1.tv_sec - time0.tv_sec; - ret.tv_nsec = time1.tv_nsec - time0.tv_nsec; - - if (time1.tv_sec < time0.tv_sec) { - sign = -1; - } - - ret.tv_sec = ret.tv_sec * sign; - - return ret; -} - -double c_secdiff(struct timespec clock1, struct timespec clock0) { - double ret; - struct timespec diff; - - diff = c_tspecdiff(clock1, clock0); - - ret = diff.tv_sec; - ret += (double) diff.tv_nsec / (double) 1E9; - - return ret; -} - - -#ifdef HAVE_UTIMES -int c_utimes(const char *uri, const struct timeval *times) { - mbchar_t *wuri = c_utf8_path_to_locale(uri); - int ret = utimes(wuri, times); - c_free_locale_string(wuri); - return ret; -} -#else // HAVE_UTIMES - -#ifdef _WIN32 -// implementation for utimes taken from KDE mingw headers - -#include -#include -#define CSYNC_SECONDS_SINCE_1601 11644473600LL -#define CSYNC_USEC_IN_SEC 1000000LL -//after Microsoft KB167296 -static void UnixTimevalToFileTime(struct timeval t, LPFILETIME pft) -{ - LONGLONG ll; - ll = Int32x32To64(t.tv_sec, CSYNC_USEC_IN_SEC*10) + t.tv_usec*10 + CSYNC_SECONDS_SINCE_1601*CSYNC_USEC_IN_SEC*10; - pft->dwLowDateTime = (DWORD)ll; - pft->dwHighDateTime = ll >> 32; -} - -int c_utimes(const char *uri, const struct timeval *times) { - FILETIME LastAccessTime; - FILETIME LastModificationTime; - HANDLE hFile; - - mbchar_t *wuri = c_utf8_path_to_locale( uri ); - - if(times) { - UnixTimevalToFileTime(times[0], &LastAccessTime); - UnixTimevalToFileTime(times[1], &LastModificationTime); - } - else { - GetSystemTimeAsFileTime(&LastAccessTime); - GetSystemTimeAsFileTime(&LastModificationTime); - } - - hFile=CreateFileW(wuri, FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL+FILE_FLAG_BACKUP_SEMANTICS, NULL); - if(hFile==INVALID_HANDLE_VALUE) { - switch(GetLastError()) { - case ERROR_FILE_NOT_FOUND: - errno=ENOENT; - break; - case ERROR_PATH_NOT_FOUND: - case ERROR_INVALID_DRIVE: - errno=ENOTDIR; - break; - /*case ERROR_WRITE_PROTECT: //CreateFile sets ERROR_ACCESS_DENIED on read-only devices - * errno=EROFS; - * break;*/ - case ERROR_ACCESS_DENIED: - errno=EACCES; - break; - default: - errno=ENOENT; //what other errors can occur? - } - - return -1; - } - - if(!SetFileTime(hFile, NULL, &LastAccessTime, &LastModificationTime)) { - //can this happen? - errno=ENOENT; - CloseHandle(hFile); - c_free_locale_string(wuri); - return -1; - } - - CloseHandle(hFile); - c_free_locale_string(wuri); - - return 0; -} - -#endif // _WIN32 -#endif // HAVE_UTIMES diff --git a/csync/src/std/c_time.h b/csync/src/std/c_time.h deleted file mode 100644 index aa8ef2f16..000000000 --- a/csync/src/std/c_time.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * c_time - time functions - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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 _C_TIME_H -#define _C_TIME_H - -#include - -/** - * @brief Calculate time difference - * - * The c_tspecdiff function returns the time elapsed between time time1 and time - * time0 represented as timespec. - * - * @param time1 The time. - * @param time0 The time. - * - * @return time elapsed between time1 and time0. - */ -struct timespec c_tspecdiff(struct timespec time1, struct timespec time0); - -/** - * @brief Calculate time difference. - * - * The function returns the time elapsed between time clock1 and time - * clock0 represented as double (in seconds and milliseconds). - * - * @param clock1 The time. - * @param clock0 The time. - * - * @return time elapsed between clock1 and clock0 in seconds and - * milliseconds. - */ -double c_secdiff(struct timespec clock1, struct timespec clock0); - -int c_utimes(const char *uri, const struct timeval *times); - -#endif /* _C_TIME_H */ diff --git a/csync/src/std/c_utf8.cc b/csync/src/std/c_utf8.cc deleted file mode 100644 index 4bd5d75ac..000000000 --- a/csync/src/std/c_utf8.cc +++ /dev/null @@ -1,104 +0,0 @@ -/* - * cynapses libc functions - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2012-2013 by Klaas Freitag - * - * 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 "config_csync.h" - -#ifdef _WIN32 -#include -#include -#include -#include -#include -#include -#include -#else -#include -#include -#endif - -extern "C" { -#include "c_alloc.h" -#include "c_string.h" - -/* Convert a locale String to UTF8 */ -char* c_utf8_from_locale(const mbchar_t *wstr) -{ - if (wstr == NULL) { - return NULL; - } - -#ifdef _WIN32 - char *dst = NULL; - char *mdst = NULL; - int size_needed; - size_t len; - len = wcslen(wstr); - /* Call once to get the required size. */ - size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, len, NULL, 0, NULL, NULL); - if (size_needed > 0) { - mdst = (char*)c_malloc(size_needed + 1); - - memset(mdst, 0, size_needed + 1); - WideCharToMultiByte(CP_UTF8, 0, wstr, len, mdst, size_needed, NULL, NULL); - dst = mdst; - } - return dst; -#else - QTextDecoder dec(QTextCodec::codecForLocale()); - QString s = dec.toUnicode(wstr, qstrlen(wstr)); - if (s.isEmpty() || dec.hasFailure()) { - /* Conversion error: since we can't report error from this function, just return the original - string. We take care of invalid utf-8 in SyncEngine::treewalkFile */ - return c_strdup(wstr); - } -#ifdef __APPLE__ - s = s.normalized(QString::NormalizationForm_C); -#endif - return c_strdup(std::move(s).toUtf8().constData()); -#endif -} - -/* Convert a an UTF8 string to locale */ -mbchar_t* c_utf8_string_to_locale(const char *str) -{ - if (str == NULL ) { - return NULL; - } -#ifdef _WIN32 - mbchar_t *dst = NULL; - size_t len; - int size_needed; - - len = strlen(str); - size_needed = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); - if (size_needed > 0) { - int size_char = (size_needed + 1) * sizeof(mbchar_t); - dst = (mbchar_t*)c_malloc(size_char); - memset((void*)dst, 0, size_char); - MultiByteToWideChar(CP_UTF8, 0, str, -1, dst, size_needed); - } - return dst; -#else - return c_strdup(QFile::encodeName(QString::fromUtf8(str))); -#endif -} - -} diff --git a/csync/src/vio/csync_vio.c b/csync/src/vio/csync_vio.c deleted file mode 100644 index 909117836..000000000 --- a/csync/src/vio/csync_vio.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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 _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include - -#include "csync_private.h" -#include "csync_util.h" -#include "vio/csync_vio.h" -#include "vio/csync_vio_local.h" -#include "csync_statedb.h" -#include "std/c_jhash.h" - -#define CSYNC_LOG_CATEGORY_NAME "csync.vio.main" - -#include "csync_log.h" - -csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name) { - switch(ctx->replica) { - case REMOTE_REPLICA: - if(ctx->remote.read_from_db) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Read from db flag is true, should not!" ); - } - return ctx->callbacks.remote_opendir_hook(name, ctx->callbacks.vio_userdata); - break; - case LOCAL_REPLICA: - if( ctx->callbacks.update_callback ) { - ctx->callbacks.update_callback(ctx->replica, name, ctx->callbacks.update_callback_userdata); - } - return csync_vio_local_opendir(name); - break; - default: - CSYNC_LOG(CSYNC_LOG_PRIORITY_ALERT, "Invalid replica (%d)", (int)ctx->replica); - break; - } - return NULL; -} - -int csync_vio_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle) { - int rc = -1; - - if (dhandle == NULL) { - errno = EBADF; - return -1; - } - - switch(ctx->replica) { - case REMOTE_REPLICA: - if( ctx->remote.read_from_db ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote ReadFromDb is true, should not!"); - } - ctx->callbacks.remote_closedir_hook(dhandle, ctx->callbacks.vio_userdata); - rc = 0; - break; - case LOCAL_REPLICA: - rc = csync_vio_local_closedir(dhandle); - break; - default: - CSYNC_LOG(CSYNC_LOG_PRIORITY_ALERT, "Invalid replica (%d)", (int)ctx->replica); - break; - } - return rc; -} - -csync_vio_file_stat_t *csync_vio_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle) { - switch(ctx->replica) { - case REMOTE_REPLICA: - if( ctx->remote.read_from_db ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote readfromdb is true, should not!"); - } - return ctx->callbacks.remote_readdir_hook(dhandle, ctx->callbacks.vio_userdata); - break; - case LOCAL_REPLICA: - return csync_vio_local_readdir(dhandle); - break; - default: - CSYNC_LOG(CSYNC_LOG_PRIORITY_ALERT, "Invalid replica (%d)", (int)ctx->replica); - break; - } - - return NULL; -} - - -int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) { - int rc = -1; - - switch(ctx->replica) { - case REMOTE_REPLICA: - 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); - if (rc < 0) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Local stat failed, errno %d for %s", errno, uri); - } - break; - default: - break; - } - - return rc; -} - -char *csync_vio_get_status_string(CSYNC *ctx) { - if(ctx->error_string) { - return ctx->error_string; - } - return 0; -} diff --git a/csync/src/vio/csync_vio.h b/csync/src/vio/csync_vio.h deleted file mode 100644 index 715b18542..000000000 --- a/csync/src/vio/csync_vio.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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_VIO_H -#define _CSYNC_VIO_H - -#include -#include -#include -#include "c_private.h" -#include "csync.h" -#include "csync_private.h" - -typedef struct fhandle_s { - int fd; -} fhandle_t; - -csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name); -int csync_vio_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle); -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); - -char *csync_vio_get_status_string(CSYNC *ctx); - - -#endif /* _CSYNC_VIO_H */ diff --git a/csync/src/vio/csync_vio_file_stat.c b/csync/src/vio/csync_vio_file_stat.c deleted file mode 100644 index 8ebb64f33..000000000 --- a/csync/src/vio/csync_vio_file_stat.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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 "c_lib.h" -#include "csync.h" -#include "csync_log.h" - -csync_vio_file_stat_t *csync_vio_file_stat_new(void) { - 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; -} - -csync_vio_file_stat_t* csync_vio_file_stat_copy(csync_vio_file_stat_t *file_stat) { - csync_vio_file_stat_t *file_stat_cpy = csync_vio_file_stat_new(); - memcpy(file_stat_cpy, file_stat, sizeof(csync_vio_file_stat_t)); - if (file_stat_cpy->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) { - file_stat_cpy->etag = c_strdup(file_stat_cpy->etag); - } - if (file_stat_cpy->directDownloadCookies) { - file_stat_cpy->directDownloadCookies = c_strdup(file_stat_cpy->directDownloadCookies); - } - if (file_stat_cpy->directDownloadUrl) { - file_stat_cpy->directDownloadUrl = c_strdup(file_stat_cpy->directDownloadUrl); - } - if (file_stat_cpy->checksumHeader) { - file_stat_cpy->checksumHeader = c_strdup(file_stat_cpy->checksumHeader); - } - file_stat_cpy->name = c_strdup(file_stat_cpy->name); - return file_stat_cpy; -} - -void csync_vio_file_stat_destroy(csync_vio_file_stat_t *file_stat) { - /* FIXME: free rest */ - if (file_stat == NULL) { - return; - } - - 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->original_name); - SAFE_FREE(file_stat->checksumHeader); - SAFE_FREE(file_stat); -} - -void csync_vio_file_stat_set_file_id( csync_vio_file_stat_t *dst, const char* src ) { - - csync_vio_set_file_id( dst->file_id, src ); - if( c_streq( dst->file_id, "" )) { - return; - } - dst->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FILE_ID; -} - -void csync_vio_set_file_id( char* dst, const char *src ) { - if( src && dst ) { - if( strlen(src) > FILE_ID_BUF_SIZE ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Ignoring file_id because it is too long: %s", src); - strcpy(dst, ""); - } else { - strcpy(dst, src); - } - } -} diff --git a/csync/src/vio/csync_vio_local.h b/csync/src/vio/csync_vio_local.h deleted file mode 100644 index 294383121..000000000 --- a/csync/src/vio/csync_vio_local.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * - * 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_VIO_LOCAL_H -#define _CSYNC_VIO_LOCAL_H - -csync_vio_handle_t OCSYNC_EXPORT *csync_vio_local_opendir(const char *name); -int OCSYNC_EXPORT csync_vio_local_closedir(csync_vio_handle_t *dhandle); -csync_vio_file_stat_t OCSYNC_EXPORT *csync_vio_local_readdir(csync_vio_handle_t *dhandle); - -int OCSYNC_EXPORT csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf); - -#endif /* _CSYNC_VIO_LOCAL_H */ diff --git a/csync/src/vio/csync_vio_local_unix.c b/csync/src/vio/csync_vio_local_unix.c deleted file mode 100644 index 5d5666688..000000000 --- a/csync/src/vio/csync_vio_local_unix.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2013- by Klaas Freitag - * - * 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 -#include -#include -#include -#include -#include - -#include "c_private.h" -#include "c_lib.h" -#include "c_string.h" -#include "csync_util.h" -#include "csync_log.h" -#include "csync_vio.h" - -#include "vio/csync_vio_local.h" - -/* - * directory functions - */ - -typedef struct dhandle_s { - DIR *dh; - char *path; -} dhandle_t; - -csync_vio_handle_t *csync_vio_local_opendir(const char *name) { - dhandle_t *handle = NULL; - mbchar_t *dirname = NULL; - - handle = c_malloc(sizeof(dhandle_t)); - - dirname = c_utf8_path_to_locale(name); - - handle->dh = _topendir( dirname ); - if (handle->dh == NULL) { - c_free_locale_string(dirname); - SAFE_FREE(handle); - return NULL; - } - - handle->path = c_strdup(name); - c_free_locale_string(dirname); - - return (csync_vio_handle_t *) handle; -} - -int csync_vio_local_closedir(csync_vio_handle_t *dhandle) { - dhandle_t *handle = NULL; - int rc = -1; - - if (dhandle == NULL) { - errno = EBADF; - return -1; - } - - handle = (dhandle_t *) dhandle; - rc = _tclosedir(handle->dh); - - SAFE_FREE(handle->path); - SAFE_FREE(handle); - - return rc; -} - -csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) { - - dhandle_t *handle = NULL; - csync_vio_file_stat_t *file_stat = NULL; - - handle = (dhandle_t *) dhandle; - - errno = 0; - file_stat = csync_vio_file_stat_new(); - if (file_stat == NULL) { - goto err; - } - file_stat->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE; - - struct _tdirent *dirent = NULL; - - dirent = _treaddir(handle->dh); - if (dirent == NULL) { - goto err; - } - file_stat->name = c_utf8_from_locale(dirent->d_name); - if (file_stat->name == NULL) { - //file_stat->original_name = c_strdup(dirent->d_name); - if (asprintf(&file_stat->original_name, "%s/%s", handle->path, dirent->d_name) < 0) { - goto err; - } - CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Invalid characters in file/directory name, please rename: \"%s\" (%s)", - dirent->d_name, handle->path); - } - - /* Check for availability of d_type, see manpage. */ -#if defined(_DIRENT_HAVE_D_TYPE) || defined(__APPLE__) - switch (dirent->d_type) { - case DT_FIFO: - case DT_SOCK: - case DT_CHR: - case DT_BLK: - break; - case DT_DIR: - case DT_REG: - file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; - if (dirent->d_type == DT_DIR) { - file_stat->type = CSYNC_VIO_FILE_TYPE_DIRECTORY; - } else { - file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR; - } - break; - case DT_UNKNOWN: - file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; - file_stat->type = CSYNC_VIO_FILE_TYPE_UNKNOWN; - default: - break; - } -#endif - - return file_stat; - -err: - csync_vio_file_stat_destroy(file_stat); - - return NULL; -} - - -int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) { - csync_stat_t sb; - - mbchar_t *wuri = c_utf8_path_to_locale( uri ); - - if( _tstat(wuri, &sb) < 0) { - c_free_locale_string(wuri); - return -1; - } - - buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE; - - switch(sb.st_mode & S_IFMT) { - case S_IFBLK: - buf->type = CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE; - break; - case S_IFCHR: - buf->type = CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE; - break; - case S_IFDIR: - buf->type = CSYNC_VIO_FILE_TYPE_DIRECTORY; - break; - case S_IFIFO: - buf->type = CSYNC_VIO_FILE_TYPE_FIFO; - break; - case S_IFREG: - buf->type = CSYNC_VIO_FILE_TYPE_REGULAR; - break; - case S_IFLNK: - buf->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; - break; - case S_IFSOCK: - buf->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; - break; - default: - buf->type = CSYNC_VIO_FILE_TYPE_UNKNOWN; - break; - } - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; - - buf->mode = sb.st_mode; - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MODE; - - if (buf->type == CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK) { - /* FIXME: handle symlink */ - buf->flags = CSYNC_VIO_FILE_FLAGS_SYMLINK; - } 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->inode = sb.st_ino; - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE; - - buf->atime = sb.st_atime; - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME; - - buf->mtime = sb.st_mtime; - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME; - - buf->ctime = sb.st_ctime; - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME; - - buf->size = sb.st_size; - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE; - - c_free_locale_string(wuri); - return 0; -} diff --git a/csync/src/vio/csync_vio_local_win.c b/csync/src/vio/csync_vio_local_win.c deleted file mode 100644 index fc4eea512..000000000 --- a/csync/src/vio/csync_vio_local_win.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * libcsync -- a library to sync a directory with another - * - * Copyright (c) 2008-2013 by Andreas Schneider - * Copyright (c) 2013- by Klaas Freitag - * - * 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 -#include -#include -#include -#include - -#include "windows.h" - -#include "c_private.h" -#include "c_lib.h" -#include "c_string.h" -#include "csync_util.h" -#include "csync_log.h" -#include "csync_vio.h" - -#include "vio/csync_vio_local.h" - - -/* - * directory functions - */ - -typedef struct dhandle_s { - WIN32_FIND_DATA ffd; - HANDLE hFind; - int firstFind; - char *path; -} dhandle_t; - -csync_vio_handle_t *csync_vio_local_opendir(const char *name) { - dhandle_t *handle = NULL; - mbchar_t *dirname = NULL; - - handle = c_malloc(sizeof(dhandle_t)); - - // the file wildcard has to be attached - int len_name = strlen(name); - if( len_name ) { - char *h = NULL; - - // alloc an enough large buffer to take the name + '/*' + the closing zero. - h = c_malloc(len_name+3); - strncpy( h, name, 1+len_name); - strncat(h, "/*", 2); - - dirname = c_utf8_path_to_locale(h); - SAFE_FREE(h); - } - - if( dirname ) { - handle->hFind = FindFirstFile(dirname, &(handle->ffd)); - } - - if (!dirname || handle->hFind == INVALID_HANDLE_VALUE) { - int retcode = GetLastError(); - if( retcode == ERROR_FILE_NOT_FOUND ) { - errno = ENOENT; - } else { - errno = EACCES; - } - SAFE_FREE(handle); - return NULL; - } - - handle->firstFind = 1; // Set a flag that there first fileinfo is available. - - handle->path = c_strdup(name); - c_free_locale_string(dirname); - - return (csync_vio_handle_t *) handle; -} - -int csync_vio_local_closedir(csync_vio_handle_t *dhandle) { - dhandle_t *handle = NULL; - int rc = -1; - - if (dhandle == NULL) { - errno = EBADF; - return -1; - } - - handle = (dhandle_t *) dhandle; - // FindClose returns non-zero on success - if( FindClose(handle->hFind) != 0 ) { - rc = 0; - } else { - // error case, set errno - errno = EBADF; - } - - SAFE_FREE(handle->path); - SAFE_FREE(handle); - - return rc; -} - - -static time_t FileTimeToUnixTime(FILETIME *filetime, DWORD *remainder) -{ - long long int t = filetime->dwHighDateTime; - t <<= 32; - t += (UINT32)filetime->dwLowDateTime; - t -= 116444736000000000LL; - if (t < 0) - { - if (remainder) *remainder = 9999999 - (-t - 1) % 10000000; - return -1 - ((-t - 1) / 10000000); - } - else - { - if (remainder) *remainder = t % 10000000; - return t / 10000000; - } -} - -csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) { - - dhandle_t *handle = NULL; - csync_vio_file_stat_t *file_stat = NULL; - DWORD rem; - - handle = (dhandle_t *) dhandle; - - errno = 0; - file_stat = csync_vio_file_stat_new(); - if (file_stat == NULL) { - errno = ENOMEM; - goto err; - } - file_stat->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE; - - // the win32 functions get the first valid entry with the opendir - // thus we must not jump to next entry if it was the first find. - if( handle->firstFind ) { - handle->firstFind = 0; - } else { - if( FindNextFile(handle->hFind, &(handle->ffd)) == 0 ) { - // might be error, check! - int dwError = GetLastError(); - if (dwError != ERROR_NO_MORE_FILES) { - errno = EACCES; // no more files is fine. Otherwise EACCESS - } - goto err; - } - } - file_stat->name = c_utf8_from_locale(handle->ffd.cFileName); - - file_stat->flags = CSYNC_VIO_FILE_FLAGS_NONE; - file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; - if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - // Detect symlinks, and treat junctions as symlinks too. - if (handle->ffd.dwReserved0 == IO_REPARSE_TAG_SYMLINK - || handle->ffd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT) { - file_stat->flags |= CSYNC_VIO_FILE_FLAGS_SYMLINK; - file_stat->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; - } else { - // The SIS and DEDUP reparse points should be treated as - // regular files. We don't know about the other ones yet, - // but will also treat them normally for now. - file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR; - } - } else if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE - || handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE - || handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) { - file_stat->type = CSYNC_VIO_FILE_TYPE_UNKNOWN; - } else if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - file_stat->type = CSYNC_VIO_FILE_TYPE_DIRECTORY; - } else { - file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR; - } - - /* Check for the hidden flag */ - if( handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) { - file_stat->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN; - } - - file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS; - file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; - - file_stat->size = (handle->ffd.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + handle->ffd.nFileSizeLow; - file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE; - - file_stat->atime = FileTimeToUnixTime(&handle->ffd.ftLastAccessTime, &rem); - file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME; - - file_stat->mtime = FileTimeToUnixTime(&handle->ffd.ftLastWriteTime, &rem); - /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Local File MTime: %llu", (unsigned long long) buf->mtime ); */ - file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME; - - file_stat->ctime = FileTimeToUnixTime(&handle->ffd.ftCreationTime, &rem); - file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME; - - return file_stat; - -err: - SAFE_FREE(file_stat); - - return NULL; -} - - - -int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) { - /* Almost nothing to do since csync_vio_local_readdir already filled up most of the information - But we still need to fetch the file ID. - Possible optimisation: only fetch the file id when we need it (for new files) - */ - - HANDLE h; - BY_HANDLE_FILE_INFORMATION fileInfo; - ULARGE_INTEGER FileIndex; - mbchar_t *wuri = c_utf8_path_to_locale( uri ); - - h = CreateFileW( wuri, 0, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, - NULL ); - if( h == INVALID_HANDLE_VALUE ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "CreateFileW failed on %s", uri ); - errno = GetLastError(); - c_free_locale_string(wuri); - return -1; - } - - if(!GetFileInformationByHandle( h, &fileInfo ) ) { - CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "GetFileInformationByHandle failed on %s", uri ); - errno = GetLastError(); - c_free_locale_string(wuri); - CloseHandle(h); - return -1; - } - - /* Get the Windows file id as an inode replacement. */ - FileIndex.HighPart = fileInfo.nFileIndexHigh; - FileIndex.LowPart = fileInfo.nFileIndexLow; - FileIndex.QuadPart &= 0x0000FFFFFFFFFFFF; - /* printf("Index: %I64i\n", FileIndex.QuadPart); */ - buf->inode = FileIndex.QuadPart; - - if (!(buf->fields & CSYNC_VIO_FILE_STAT_FIELDS_SIZE)) { - buf->size = (fileInfo.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + fileInfo.nFileSizeLow; - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE; - } - if (!(buf->fields & CSYNC_VIO_FILE_STAT_FIELDS_MTIME)) { - DWORD rem; - buf->mtime = FileTimeToUnixTime(&fileInfo.ftLastWriteTime, &rem); - /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Local File MTime: %llu", (unsigned long long) buf->mtime ); */ - buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME; - } - - c_free_locale_string(wuri); - CloseHandle(h); - return 0; -} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3cbacd537..f871836cf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,7 @@ if(NOT TOKEN_AUTH_ONLY) find_package(Qt5Keychain REQUIRED) endif() +add_subdirectory(csync) add_subdirectory(libsync) if (NOT BUILD_LIBRARIES_ONLY) add_subdirectory(gui) diff --git a/src/cmd/CMakeLists.txt b/src/cmd/CMakeLists.txt index 4a0d76d71..26b641f21 100644 --- a/src/cmd/CMakeLists.txt +++ b/src/cmd/CMakeLists.txt @@ -12,9 +12,8 @@ include_directories(${CMAKE_SOURCE_DIR}/src/libsync ) # csync is required. -include_directories(${CMAKE_SOURCE_DIR}/csync/src - ${CMAKE_BINARY_DIR}/csync - ${CMAKE_BINARY_DIR}/csync/src +include_directories(${CMAKE_SOURCE_DIR}/src/csync + ${CMAKE_BINARY_DIR}/src/csync ) # Need tokenizer for netrc parser diff --git a/src/csync/AUTHORS b/src/csync/AUTHORS new file mode 100644 index 000000000..5fd81c08e --- /dev/null +++ b/src/csync/AUTHORS @@ -0,0 +1,3 @@ +Andreas Schneider +Klaas Freitag +Olivier Goffart diff --git a/src/csync/CMakeLists.txt b/src/csync/CMakeLists.txt new file mode 100644 index 000000000..db99a88d0 --- /dev/null +++ b/src/csync/CMakeLists.txt @@ -0,0 +1,166 @@ +project(libcsync) +# global needed variables +set(APPLICATION_NAME "ocsync") + +set(LIBRARY_VERSION ${MIRALL_VERSION}) +set(LIBRARY_SOVERSION "0") + +# add definitions +include(DefineCMakeDefaults) +include(DefinePlatformDefaults) +include(DefineCompilerFlags) +include(DefineOptions.cmake) + +include(DefineInstallationPaths) + +# add macros +include(MacroAddPlugin) +include(MacroCopyFile) + +find_package(SQLite3 3.8.0 REQUIRED) + +include(ConfigureChecks.cmake) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +if (MEM_NULL_TESTS) + add_definitions(-DCSYNC_MEM_NULL_TESTS) +endif (MEM_NULL_TESTS) + +add_subdirectory(std) + +# Statically include sqlite + +set(CSYNC_PUBLIC_INCLUDE_DIRS + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR} + CACHE INTERNAL "csync public include directories" +) + +set(CSYNC_PRIVATE_INCLUDE_DIRS + ${SQLITE3_INCLUDE_DIRS} + ${CSTDLIB_PUBLIC_INCLUDE_DIRS} + ${CMAKE_BINARY_DIR} +) + +set(CSYNC_LIBRARY + ocsync + CACHE INTERNAL "ocsync library" +) + +set(CSYNC_LINK_LIBRARIES + ${CSTDLIB_LIBRARY} + ${CSYNC_REQUIRED_LIBRARIES} + ${SQLITE3_LIBRARIES} +) + +# Specific option for builds tied to servers that do not support renaming extensions +set(NO_RENAME_EXTENSION 0 CACHE BOOL "Do not issue rename if the extension changes") +if(NO_RENAME_EXTENSION) + add_definitions(-DNO_RENAME_EXTENSION) +endif() + +set(csync_SRCS + csync.c + csync_exclude.c + csync_log.c + csync_statedb.c + csync_time.c + csync_util.c + csync_misc.c + + csync_update.c + csync_reconcile.c + + csync_rename.cc + + vio/csync_vio.c + vio/csync_vio_file_stat.c +) + +if (WIN32) + list(APPEND csync_SRCS + vio/csync_vio_local_win.c + ) +else() + list(APPEND csync_SRCS + vio/csync_vio_local_unix.c + ) +endif() + + +configure_file(csync_version.h.in ${CMAKE_CURRENT_BINARY_DIR}/csync_version.h) + +set(csync_HDRS + ${CMAKE_CURRENT_BINARY_DIR}/csync_version.h + csync.h + vio/csync_vio.h + vio/csync_vio_method.h + vio/csync_vio_module.h +) + +# Statically include sqlite +if (USE_OUR_OWN_SQLITE3) + list(APPEND csync_SRCS ${SQLITE3_SOURCE}) + if (WIN32) + # We want to export sqlite symbols from the ocsync DLL without + # having to patch both sqlite3.h and the amalgation sqlite3.c, + # so do the import/export magic manually through the build system. + remove_definitions(-DSQLITE_API=__declspec\(dllimport\)) + add_definitions(-DSQLITE_API=__declspec\(dllexport\)) + endif() +endif() + +include_directories( + ${CSYNC_PUBLIC_INCLUDE_DIRS} + ${CSYNC_PRIVATE_INCLUDE_DIRS} +) + +add_library(${CSYNC_LIBRARY} SHARED ${csync_SRCS}) +#add_library(${CSYNC_LIBRARY}_static STATIC ${csync_SRCS}) + +generate_export_header( ${CSYNC_LIBRARY} + BASE_NAME ${CSYNC_LIBRARY} + EXPORT_MACRO_NAME OCSYNC_EXPORT + EXPORT_FILE_NAME ocsynclib.h +) + +target_link_libraries(${CSYNC_LIBRARY} ${CSYNC_LINK_LIBRARIES}) +#target_link_libraries(${CSYNC_LIBRARY}_static ${CSYNC_LINK_LIBRARIES}) + +set_target_properties( + ${CSYNC_LIBRARY} + PROPERTIES + VERSION + ${LIBRARY_VERSION} + SOVERSION + ${LIBRARY_SOVERSION} + RUNTIME_OUTPUT_DIRECTORY + ${BIN_OUTPUT_DIRECTORY} +) +if(BUILD_OWNCLOUD_OSX_BUNDLE) + INSTALL( + TARGETS + ${CSYNC_LIBRARY} + LIBRARY DESTINATION + ${LIB_INSTALL_DIR} + ARCHIVE DESTINATION + ${LIB_INSTALL_DIR} + RUNTIME DESTINATION + ${BIN_INSTALL_DIR} + ) +else() + INSTALL( + TARGETS + ${CSYNC_LIBRARY} + LIBRARY DESTINATION + ${LIB_INSTALL_DIR}/${APPLICATION_EXECUTABLE} + ARCHIVE DESTINATION + ${LIB_INSTALL_DIR}/${APPLICATION_EXECUTABLE} + RUNTIME DESTINATION + ${BIN_INSTALL_DIR}/${APPLICATION_EXECUTABLE} + ) +endif() + +configure_file(config_csync.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_csync.h) diff --git a/src/csync/COPYING b/src/csync/COPYING new file mode 100644 index 000000000..4362b4915 --- /dev/null +++ b/src/csync/COPYING @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/src/csync/ChangeLog b/src/csync/ChangeLog new file mode 100644 index 000000000..a95a07589 --- /dev/null +++ b/src/csync/ChangeLog @@ -0,0 +1,355 @@ +ChangeLog +========== +version 0.91.4 (released 2013-12-12, ownCloud Cleint 1.5.0) + * changelog added, version bumped. + +version 0.91.3 (released 2013-12-11, ownCloud Client 1.5.0rc1) + * Fix progress bar on win32 + * Fix network rate limiting on win32 + * Do not check for etag during failing requests + * Start quota timer only after the predecessor returned + * Remove tmp files in case of certain download problems + * Some valgrind fixes + * Theming fix: button behaviour + * Fix a case where a sync loop could happen. + * Multi-linguar installer + * Fix handling of quotes in etags written by older ownClouds + * Fix errno handling in update phase + * Make csync compile on FreeBSD + * Minor cleanups. + +version 0.91.2 (released 2013-12-10, ownCloud Client 1.5.0beta3) + * have translatable error message for indiv. file errors. + * Use uint64_t for inode on win32 to fix a type glitch. + * Add test that directories are properly moved. + * Handle symlinks correctly. + * No longer recurse into ignored directories in update + phase. + * Added proper symlink detection for win32 platform. + +version 0.91.1 (released 2013-12-03, ownCloud Client 1.5.0beta2) + * Close database correctly to fix a potential crash (mirall#1229) + * Handle invalid inodes correctly. + * Use lstat rather than stat to detect symlinks correctly. + (core#6146) + +version 0.91.0 (released 2013-11-28, ownCloud Client 1.5.0beta1) + * fix ascii to int conversion for large numbers. + * add support for file ids, needed to detect server side moves. + * removed unused code, ie. database writing code that went to + mirall. + * add functions to query the database by fileid. + * add functions to read fileids from PUT replies. + * add server side move detection. + * enhanced test scripts + * Remove ne_sock_init and ne_sock_exit from owncloud module + (mirall#1115) + * Renamed 'md5' to 'etag' in code identifiers to avoid confusion. + * add new state EVAL_RENAME + * link the owncloud module directly rather than dl-loading it. + * add a content type header 'application/octet-stream' to PUTs. + * remove -gzip from etag header if its there. (mirall#1195) + * Many minor fixes, refactorings and improvements. + +version 0.90.4 (released 2013-10-18, ownCloud Client 1.4.2) + + * Count renamed and deleted files for progress information. + * Do not reset csync internal error state in helper funcs + and do not overwrite error messages. + That fixes error reporting to the client. + * Disable check on inodes on all platforms as inodes are not + reliable. + * Fix resuming after user aborting the sync process. + * enabled HBF debugging permanently. + +version 0.90.1 (released 2013-09-24, ownCloud Client 1.4.1) + * no more check on the local inode in updater for win32 (bug #779) + * detect if server does not send an etag after an upload + completed. + * fix crash in case of network timeout, reported as + https://github.comowncloud/client/issues/1010 + * compile and cmake fixes for win32 + * fixed behaviour of csync_exclude + * documentation and spelling fixes. + +version 0.90.0 (released 2013-09-04, ownCloud Client 1.4.0) + * Added API to get progress information from csync. + * Added c_rename function to csync std. + * Fix: Do renames of files before any puts. + * Improved database integrity checks. + * Improvements of database writing efficiency. + * Fix: stat file on win32 even if its opened by application. + * httpbf: configurable block size and threshold. + * Many fixes found by a Coverity check. + * Fix: use correct stat struct on all platforms + * Fix: download resuming. + * ownCloud module: Bandwith limitation added. + * Added ability to remove ignored files automatically. + * Fix: Use int64_t and friends + * Fix: Removed all compile warnings. + * Left excluded files and links in csync's tree to be able to show. + them to the user. + * Add OC-Total-Length header for better quota handling. + * Report inbetween progress + +version 0.80.0 (released 2013-06-25) + * Big file chunking (e.g. up/download of big files should now be no + problem anymore) + * Resuming (download of big files will resume) + * Fix false conflicts when database is corrupt/missing + * Fix false conflicts when file is locked + * Put legitimate conflict files only on client side + * Fix unreliable sync after push_file failed + * Fix rename due to inode cast error + * Make chunking work on nginx setups or through nginx proxies + * Improve error reporting in csync_update + * Clean progress database on csync_commit + * Fix issues detected by Coverity + * Fix conflict file appearing when a file cannot be stated + * Do not shadow server errors by not downloading files that have + failed to download in the past + +version 0.70.6 (released 2013-04-11) + * [Fixes] Try to avoid to upload incomplete files + * [Fixes] Increase read timeout to 300 seconds + * [Fixes] Handle IGNORE status correctly + * [Fixes] Set path and phash for ignored files + * [Fixes] Fix some issues discovered by Coverity + * [Fixes] Make sure to never allow empty pathes in rmdir + * [Fixes] Fix a crash caused by superfluous free() calls + +version 0.70.5 (released 2013-04-02) + * detect 'wrong' conflict files on client side. + * [Fixes] Give context to module to enable logging (cmd client). + * [Fixes] Fix version table contents. + * [Fixes] Fix handling of non statable files on Win32. + * [Fixes] Fix renames on clientside on read only shares. + * [Fixes] Various small fixes and improvements. + +version 0.70.4 (released 2013-02-26) + * [Win32] Ship with upto-date openssl version to fix SSL problems we saw. + * [Fixes] Fix crash during mkdir. + * [Fixes] Added workaround for problem that server sometimes does + not respond properly to PROPFIND (mirall#285) + * [Fixes] Fix handling of deletion of non empty or locked + directories. + * [Fixes] Fixed some potential memory leaks. + * [Fixes] Files with filenames with unix extensions + are ignored now. + +version 0.70.3 (released 2013-01-24) + * [Platform] Fix session cookie extraction (mirall bug #260). + +version 0.70.2 (released 2013-01-23) + * [Platform] Improved module parameter system. + * [Platform] New logging framework. Dropped log4c dependency. + * [Platform] New API to provide sync progress information. + * [Fixes] More efficiency for the ownCloud plugin through less HTTP requests to + the server. + * [Fixes] ownCloud plugin: Improved upload performance. + * [Fixes] Improved error reporting to mirall. + * [Fixes] ownCloud plugin: Improved interpretation of HTTP error codes. + * [Fixes] ownCloud plugin: Do not abort on errors with individual files any + more. + * [Fixes] Lots of other minor fixes. + * [MacOSX] Use libneon with proper big file support. + * [Win32] Use libneon with openSSL support now. + +version 0.70.0 and 0.70.1 were beta versions. + +version 0.60.2 (released 2012-11-26) + * Migration to cross platform testing system cmocka. + * Fixed various minor things incl. potential mem leaks. + * Clang fixes. + * Moved journal database to sync directory. + * Fixed more csync->ocsync renaming issues. + * Fixed statedb query below path. + * Fixed win32 Daylight Saving Time issues. + * Allow static linking with iniparser and sqlite. + * Win32: Fix CreateHandle function in local stat. + * Win32: More wide char fixes. + * Added version table to journal database. + * Fixes for HTTP reply computation. + * Stricter error checks on PROPFIND results. + * Workaround for DST influenced times from previous versions. + * Detect looping in mkdirs to fix sharing. + +version 0.60.1 (released 2012-10-18) + * Fix improper memory cleanup which could + cause memory leaks and crashes + * Fix memory leak + * Allow single quote (') in file names + * Remove stray temporary files + +version 0.60.0 (released 2012-10-10) + * simplification of pac based proxy support. + * syncing algorithm based on ids rather than on timestamps + * make it possible to relocate database + +version 0.50.11 (third beta version, released 2012-10-05) + * Renamed ownCloud version of csync to ocsync for ownCloud. + * Migration paths for csync database and config. + * Fixed that exclude patterns are also tested on files basenames. + * Fixed return type for query function if no database exists. + * minor code fixes + +version 0.50.10 (second beta version, released 2012-09-20) + * Fixed crash by removing a bogus free. + * More useful logging. + * ownCloud: Maintain the http session by handling the HTTP Cookie. + +version 0.50.9 (first beta version, released 2012-08-30) + * Fixed strncpy handling (mkdir on windows problem). + * extend database with columns uniq id and type. + * Use server maintained uniq IDs for update detection instead of + mtimes. + * Maintain uniq IDs in local database + * Handle change propagation through the file tree locally and remote. + * Added module to build a file tree from the local database (dbtree.c) + * Added methods to query IDs from the server and maintain it locally. + +version 0.50.8 (released 2012-08-10) + * Inode equivalent support for Win32 platforms to support rename + * ownCloud supports propagates renames from local to webdav MOVE + * ownCloud module works with proxy, settings from mirall. + * improved CMake modules (openSSL) + * Fixed namespace for lastmodified propset. + * Added cmocka based tests for ownCloud module. + * Added a config_test.h config_csync.header file. + * Fix link handling: Ignore symlinks. + * Modules can now report their capabilities to csync core. + * A lot of minor fixes and improvements. + +version 0.50.7 (released 2012-06-19) + * Added ability to log to a callback, ie. let the app + catch the log output + * Added push to remote without pushing to temp file first. + * Fixed file copy function to use wide character (win32). + * Fixed loading of statedb if user has special char (win32). + +version 0.50.6 (released 2012-05-18) + * Directories with 'strange' characters broke sync. (oC bug #613) + * Special characters in Windows did not sync correctly. (oC bug #478) + * Make neon redirecting + * Switch logging off on Apple to not fill the syslog. (oC bug #622) + +version 0.50.5 (released 2012-04-18) + * removed argp lib dependency + * simplified and fixed CMake files + * MacOS porting efforts + * more granular error reports, thread save + +version 0.50.0 (released 2013-08-01) + * Added owncloud module. + * Added support for more platforms: FreeBSD, Windows and MacOSX + * Added support for more compilers: CLang, MinGW and latest GCC + * Added a backup mode to the reconciler. + * Added new logging framework (removed log4c dependency). + * Added new config parser (removed iniparser dependency). + * Added cmocka tests. + * Added a way to export file_tree_walk functions. + * Added capabilities for modules. + * Added possiblity to push information to the modules. + * Added iconv support to support various char sets. + * Added csync_commit() to rerun on the same context. + * Added content checking in conflict case. + * Added callbacks for progress information. + * Added get() and put() functions for modules. + * Improved database: more performance, more integrity checks + * Improved error reporting: status codes, custom errnos + * Fixed serveral bugs. + * Relicensed libcsync to LGPLv2.1+. + +version 0.44.0 (released 2010-02-15) + * Migrated sftp module to libssh 0.4. + * Added more cache entries to the default config. + * Added missing requirements. + * Fixed build warnings. + * Fixed some memory leaks using sftp attributes. + * Some code cleanups. + +version 0.43.0 (released 2009-05-25) + * Added SFTP support with libssh 0.3. + * Added possibility to pass userdata to the auth function. + * Added a better version function. + * Fixed CMake build. + * Fixed CMake find modules. + * Fixed some flaws in cstd functions. + * Documented all public functions. + +version 0.42.0 (released 2009-02-10) + * Small fix in the userguide. + +version 0.42.0 rc3 (released 2009-01-23) + libcsync: + * Added checks for unix extensions. + * Added more documentation to the userguide. + * Fixed loading of plugins. + * Fixed call for deletion functions. + * Normalize the path to / for the statedb filename. + * More change name of client options to be more descriptive. + +version 0.42.0 rc2 (released 2009-01-07) + libcsync: + * Fixed a bug in the creation of the statedb + * Completed userguide + +version 0.42.0 rc1 (released 2008-12-04) + libcsync: + * Reduced calls of syscall functions. + * Added own function to create a temporary filename. + * Fixed libsmbclient 3.0.x support. + +version 0.42.0 beta1 (released 2008-09-10) + + libcsync: + * Added a sftp module using libssh + * Added user guide (just a start) + * Added testcase for update detection + * Added a function to parse an uri to cstdlib + * Updated the manpage + * Fixed some segfaults in cstdlib + * Fixed some memory leaks + + csync: + * Improved the auth callback + +version 0.42.0 alpha4 (released 2008-07-02) + + libcsync: + * Added the possibility to run csync completely without a journal + * Improved chmod calls during propagation. Most of the time we use the + default mode and don't need to call chmod. + * Improved the exclude list handling in the file tree walker. This + increased the speed of the update detection. + * Fixed csync on PPC + * Fixed serveral small bugs + + csync: + * Added commandline option to run csync completely without a journal + * Added a manpage + +version 0.42.0 alpha3 (released 2008-06-25) + + libcsync: + * Added a tree merger to write a complete journal + * Added support to run csync without a journal + * Fixed kerberos support in csync_smb module + * Fixed closing of files after the copy + * Fixed update detection to detect special files (fifo, pipes, + char devices, ..) + * Fixed O_NOATIME flag on open() if we don't have the permission + + csync: + * Add a variable to run csync completely without a journal + +version 0.42.0 alpha2 (released 2008-06-16) + + libcsync: + * Peformance improvements + * Add more directories to the standard exclude file + * Bugfixes + +version 0.42.0 alpha1 (released 2008-06-02) + + * Initial release diff --git a/src/csync/ConfigureChecks.cmake b/src/csync/ConfigureChecks.cmake new file mode 100644 index 000000000..6d64d5a63 --- /dev/null +++ b/src/csync/ConfigureChecks.cmake @@ -0,0 +1,65 @@ +include(CheckIncludeFile) +include(CheckSymbolExists) +include(CheckFunctionExists) +include(CheckLibraryExists) +include(CheckTypeSize) +include(CheckCXXSourceCompiles) + +set(PACKAGE ${APPLICATION_NAME}) +set(VERSION ${APPLICATION_VERSION}) +set(DATADIR ${DATA_INSTALL_DIR}) +set(LIBDIR ${LIB_INSTALL_DIR}) +set(SYSCONFDIR ${SYSCONF_INSTALL_DIR}) + +set(BINARYDIR ${CMAKE_CURRENT_BINARY_DIR}) +set(SOURCEDIR ${CMAKE_CURRENT_SOURCE_DIR}) + +# HEADER FILES +check_include_file(argp.h HAVE_ARGP_H) + +# FUNCTIONS +if (NOT LINUX) + # librt + check_library_exists(rt nanosleep "" HAVE_LIBRT) + + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ) +endif (NOT LINUX) + +check_library_exists(rt clock_gettime "" HAVE_CLOCK_GETTIME) +if (HAVE_LIBRT OR HAVE_CLOCK_GETTIME) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} rt) +endif (HAVE_LIBRT OR HAVE_CLOCK_GETTIME) + +check_library_exists(dl dlopen "" HAVE_LIBDL) +if (HAVE_LIBDL) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} dl) +endif (HAVE_LIBDL) + +check_function_exists(asprintf HAVE_ASPRINTF) + +check_function_exists(fnmatch HAVE_FNMATCH) +if(NOT HAVE_FNMATCH AND WIN32) + find_library(SHLWAPI_LIBRARY shlwapi) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} shlwapi) +endif() + +if(WIN32) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} psapi kernel32) +endif() + +check_function_exists(timegm HAVE_TIMEGM) +check_function_exists(strerror_r HAVE_STRERROR_R) +check_function_exists(utimes HAVE_UTIMES) +check_function_exists(lstat HAVE_LSTAT) +check_function_exists(asprintf HAVE_ASPRINTF) +if (WIN32) + check_function_exists(__mingw_asprintf HAVE___MINGW_ASPRINTF) +endif(WIN32) +if (UNIX AND HAVE_ASPRINTF) + add_definitions(-D_GNU_SOURCE) +endif (UNIX AND HAVE_ASPRINTF) +if (WIN32) + check_function_exists(__mingw_asprintf HAVE___MINGW_ASPRINTF) +endif(WIN32) + +set(CSYNC_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "csync required system libraries") diff --git a/src/csync/DefineOptions.cmake b/src/csync/DefineOptions.cmake new file mode 100644 index 000000000..485e18322 --- /dev/null +++ b/src/csync/DefineOptions.cmake @@ -0,0 +1,2 @@ +option(UNIT_TESTING "Build with unit tests" OFF) +option(MEM_NULL_TESTS "Enable NULL memory testing" OFF) diff --git a/src/csync/INSTALL b/src/csync/INSTALL new file mode 100644 index 000000000..caf65c2bd --- /dev/null +++ b/src/csync/INSTALL @@ -0,0 +1,84 @@ +# How to build from source + +## Requirements + +### Common requirements + +In order to build csync, you need to install several components: + +- A C compiler +- [CMake](http://www.cmake.org) >= 2.6.0. +- [check](http://check.sourceforge.net) >= 0.9.5 +- [sqlite3](http://www.sqlite.org) >= 3.4 +- [libneon](http://www.webdav.org/neon/) >= 0.29.0 + +optional: +- [libsmbclient](http://www.samba.org) >= 3.5 +- [libssh](http://www.libssh.org) >= 0.5 + +sqlite3 is a runtime requirement. libsmbclient is needed for +the smb plugin, libssh for the sftp plugin. libneon is required for the +ownCloud plugin. + +Note that these version numbers are versions we know work correctly. If you +build and run csync successfully with an older version, please let us know. + + +## Building +First, you need to configure the compilation, using CMake. Go inside the +`build` dir. Create it if it doesn't exist. + +GNU/Linux and MacOS X: + + cmake -DCMAKE_BUILD_TYPE=Debug .. + make + +### CMake standard options +Here is a list of the most interesting options provided out of the box by CMake. + +- CMAKE_BUILD_TYPE: The type of build (can be Debug Release MinSizeRel RelWithDebInfo) +- CMAKE_INSTALL_PREFIX: The prefix to use when running make install (Default to + /usr/local on GNU/Linux and MacOS X) +- CMAKE_C_COMPILER: The path to the C compiler +- CMAKE_CXX_COMPILER: The path to the C++ compiler + +### CMake options defined for csync + +Options are defined in the following files: + +- DefineOptions.cmake + +They can be changed with the -D option: + +`cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_LOG4C=OFF ..` + +### Browsing/editing CMake options + +In addition to passing options on the command line, you can browse and edit +CMake options using `cmakesetup` (Windows) or `ccmake` (GNU/Linux and MacOS X). + +- Go to the build dir +- On Windows: run `cmakesetup` +- On GNU/Linux and MacOS X: run `ccmake ..` + +## Installing + +Before installing you can run the tests if everything is working: + + make test + +If you want to install csync after compilation run: + + make install + +## Running + +The csync binary can be found in the `build/client` directory. + +## About this document + +This document is written using [Markdown][] syntax, making it possible to +provide usable information in both plain text and HTML format. Whenever +modifying this document please use [Markdown][] syntax. + +[markdown]: http://www.daringfireball.net/projects/markdown diff --git a/src/csync/README b/src/csync/README new file mode 100644 index 000000000..2487e2415 --- /dev/null +++ b/src/csync/README @@ -0,0 +1,34 @@ +WHAT IS CSYNC? +============== + +csync is a lightweight utility to synchronize files between two directories on +a system or between multiple systems. + +It synchronizes bidirectionally and allows the user to keep two copies of files +and directories in sync. csync uses widely adopted protocols, such as smb or +sftp, so that there is no need for a server component. It is a user-level +program which means you don’t need to be a superuser or administrator. + +CONTRIBUTIONS +============= + +If you want to contribute to the development of the software then please join +the mailing list. Patches are accepted preferably created with git and we are +always glad to receive feedback or suggestions to the address +csync-devel@csync.org. +More information on the various mailing lists can be found at +http://www.csync.org/communication/. + +You can also get the sourcecode straight from the git repository - see +http://git.csync.org/ + +DOCUMENTATION +============= + +As a user you can find a userguide which is shipped with this package or is +available at the website. For developers there is doxygen documentation and +comments in the source code itself. See + +http://www.csync.org/userguide/ +and +http://www.csync.org/api/ diff --git a/src/csync/config_csync.h.cmake b/src/csync/config_csync.h.cmake new file mode 100644 index 000000000..f5c9f09b2 --- /dev/null +++ b/src/csync/config_csync.h.cmake @@ -0,0 +1,24 @@ +#cmakedefine PACKAGE "${APPLICATION_NAME}" +#cmakedefine VERSION "${APPLICATION_VERSION}" +#cmakedefine LOCALEDIR "${LOCALE_INSTALL_DIR}" +#cmakedefine LIBDIR "${LIBDIR}" +#cmakedefine SYSCONFDIR "${SYSCONFDIR}" +#cmakedefine BINARYDIR "${BINARYDIR}" +#cmakedefine SOURCEDIR "${SOURCEDIR}" + +#cmakedefine HAVE_CLOCK_GETTIME + +#cmakedefine WITH_LOG4C 1 + +#cmakedefine HAVE_ARGP_H 1 + +#cmakedefine HAVE_TIMEGM 1 +#cmakedefine HAVE_STRERROR_R 1 +#cmakedefine HAVE_UTIMES 1 +#cmakedefine HAVE_LSTAT 1 +#cmakedefine HAVE_FNMATCH 1 + +#cmakedefine HAVE___MINGW_ASPRINTF 1 +#cmakedefine HAVE_ASPRINTF 1 + +#cmakedefine WITH_TESTING 1 diff --git a/src/csync/csync.c b/src/csync/csync.c new file mode 100644 index 000000000..1f75ac3bd --- /dev/null +++ b/src/csync/csync.c @@ -0,0 +1,651 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2012-2013 by Klaas Freitag + * + * 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 "config_csync.h" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "c_lib.h" +#include "csync_private.h" +#include "csync_exclude.h" +#include "csync_statedb.h" +#include "csync_time.h" +#include "csync_util.h" +#include "csync_misc.h" +#include "std/c_private.h" + +#include "csync_update.h" +#include "csync_reconcile.h" + +#include "vio/csync_vio.h" + +#include "csync_log.h" +#include "csync_rename.h" +#include "c_jhash.h" + +static int _key_cmp(const void *key, const void *data) { + uint64_t a; + csync_file_stat_t *b; + + a = *(uint64_t *) (key); + b = (csync_file_stat_t *) data; + + if (a < b->phash) { + return -1; + } else if (a > b->phash) { + return 1; + } + + return 0; +} + +static int _data_cmp(const void *key, const void *data) { + csync_file_stat_t *a, *b; + + a = (csync_file_stat_t *) key; + b = (csync_file_stat_t *) data; + + if (a->phash < b->phash) { + return -1; + } else if (a->phash > b->phash) { + return 1; + } + + return 0; +} + +void csync_create(CSYNC **csync, const char *local) { + CSYNC *ctx; + size_t len = 0; + + ctx = c_malloc(sizeof(CSYNC)); + + ctx->status_code = CSYNC_STATUS_OK; + + /* remove trailing slashes */ + len = strlen(local); + while(len > 0 && local[len - 1] == '/') --len; + + ctx->local.uri = c_strndup(local, len); + + ctx->status_code = CSYNC_STATUS_OK; + + ctx->current_fs = NULL; + + ctx->abort = false; + + ctx->ignore_hidden_files = true; + + *csync = ctx; +} + +void csync_init(CSYNC *ctx, const char *db_file) { + assert(ctx); + /* Do not initialize twice */ + + assert(!(ctx->status & CSYNC_STATUS_INIT)); + ctx->status_code = CSYNC_STATUS_OK; + + ctx->local.type = LOCAL_REPLICA; + + ctx->remote.type = REMOTE_REPLICA; + + SAFE_FREE(ctx->statedb.file); + ctx->statedb.file = c_strdup(db_file); + + c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp); + c_rbtree_create(&ctx->remote.tree, _key_cmp, _data_cmp); + + ctx->remote.root_perms = 0; + + ctx->status = CSYNC_STATUS_INIT; + + /* initialize random generator */ + srand(time(NULL)); +} + +int csync_update(CSYNC *ctx) { + int rc = -1; + struct timespec start, finish; + + if (ctx == NULL) { + errno = EBADF; + return -1; + } + ctx->status_code = CSYNC_STATUS_OK; + + /* Path of database file is set in csync_init */ + if (csync_statedb_load(ctx, ctx->statedb.file, &ctx->statedb.db) < 0) { + rc = -1; + return rc; + } + + ctx->status_code = CSYNC_STATUS_OK; + + csync_memstat_check(); + + if (!ctx->excludes) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "No exclude file loaded or defined!"); + } + + /* update detection for local replica */ + csync_gettime(&start); + ctx->current = LOCAL_REPLICA; + ctx->replica = ctx->local.type; + + rc = csync_ftw(ctx, ctx->local.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); + } + goto out; + } + + csync_gettime(&finish); + + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, + "Update detection for local replica took %.2f seconds walking %zu files.", + c_secdiff(finish, start), c_rbtree_size(ctx->local.tree)); + csync_memstat_check(); + + /* update detection for remote replica */ + csync_gettime(&start); + ctx->current = REMOTE_REPLICA; + ctx->replica = ctx->remote.type; + + rc = csync_ftw(ctx, "", 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); + } + goto out; + } + + 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; + + rc = 0; + +out: + csync_statedb_close(ctx); + return rc; +} + +int csync_reconcile(CSYNC *ctx) { + int rc = -1; + struct timespec start, finish; + + if (ctx == NULL) { + errno = EBADF; + return -1; + } + ctx->status_code = CSYNC_STATUS_OK; + + /* Reconciliation for local replica */ + csync_gettime(&start); + + if (csync_statedb_load(ctx, ctx->statedb.file, &ctx->statedb.db) < 0) { + rc = -1; + return rc; + } + + ctx->current = LOCAL_REPLICA; + ctx->replica = ctx->local.type; + + rc = csync_reconcile_updates(ctx); + + csync_gettime(&finish); + + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, + "Reconciliation for local replica took %.2f seconds visiting %zu files.", + c_secdiff(finish, start), c_rbtree_size(ctx->local.tree)); + + if (rc < 0) { + if (!CSYNC_STATUS_IS_OK(ctx->status_code)) { + ctx->status_code = csync_errno_to_status( errno, CSYNC_STATUS_RECONCILE_ERROR ); + } + goto out; + } + + /* Reconciliation for remote replica */ + csync_gettime(&start); + + ctx->current = REMOTE_REPLICA; + ctx->replica = ctx->remote.type; + + rc = csync_reconcile_updates(ctx); + + csync_gettime(&finish); + + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, + "Reconciliation for remote replica took %.2f seconds visiting %zu files.", + c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree)); + + if (rc < 0) { + if (!CSYNC_STATUS_IS_OK(ctx->status_code)) { + ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_RECONCILE_ERROR ); + } + goto out; + } + + ctx->status |= CSYNC_STATUS_RECONCILE; + + rc = 0; + +out: + csync_statedb_close(ctx); + return 0; +} + +/* + * local visitor which calls the user visitor with repacked stat info. + */ +static int _csync_treewalk_visitor(void *obj, void *data) { + int rc = 0; + csync_file_stat_t *cur = NULL; + CSYNC *ctx = NULL; + c_rbtree_visit_func *visitor = NULL; + _csync_treewalk_context *twctx = NULL; + TREE_WALK_FILE trav; + c_rbtree_t *other_tree = NULL; + c_rbnode_t *other_node = NULL; + + cur = (csync_file_stat_t *) obj; + ctx = (CSYNC *) data; + + if (ctx == NULL) { + return -1; + } + + /* we need the opposite tree! */ + switch (ctx->current) { + case LOCAL_REPLICA: + other_tree = ctx->remote.tree; + break; + case REMOTE_REPLICA: + other_tree = ctx->local.tree; + break; + default: + break; + } + + other_node = c_rbtree_find(other_tree, &cur->phash); + + if (!other_node) { + /* Check the renamed path as well. */ + int len; + uint64_t h = 0; + char *renamed_path = csync_rename_adjust_path(ctx, cur->path); + + if (!c_streq(renamed_path, cur->path)) { + len = strlen( renamed_path ); + h = c_jhash64((uint8_t *) renamed_path, len, 0); + other_node = c_rbtree_find(other_tree, &h); + } + SAFE_FREE(renamed_path); + } + + if (!other_node) { + /* Check the source path as well. */ + int len; + uint64_t h = 0; + char *renamed_path = csync_rename_adjust_path_source(ctx, cur->path); + + if (!c_streq(renamed_path, cur->path)) { + len = strlen( renamed_path ); + h = c_jhash64((uint8_t *) renamed_path, len, 0); + other_node = c_rbtree_find(other_tree, &h); + } + SAFE_FREE(renamed_path); + } + + if (obj == NULL || data == NULL) { + ctx->status_code = CSYNC_STATUS_PARAM_ERROR; + return -1; + } + ctx->status_code = CSYNC_STATUS_OK; + + twctx = (_csync_treewalk_context*) ctx->callbacks.userdata; + if (twctx == NULL) { + ctx->status_code = CSYNC_STATUS_PARAM_ERROR; + return -1; + } + + if (twctx->instruction_filter > 0 && + !(twctx->instruction_filter & cur->instruction) ) { + return 0; + } + + visitor = (c_rbtree_visit_func*)(twctx->user_visitor); + if (visitor != NULL) { + trav.path = cur->path; + trav.size = cur->size; + trav.modtime = cur->modtime; + 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; + trav.has_ignored_files = cur->has_ignored_files; + trav.checksumHeader = cur->checksumHeader; + + if( other_node ) { + csync_file_stat_t *other_stat = (csync_file_stat_t*)other_node->data; + trav.other.etag = other_stat->etag; + trav.other.file_id = other_stat->file_id; + trav.other.instruction = other_stat->instruction; + trav.other.modtime = other_stat->modtime; + trav.other.size = other_stat->size; + } else { + trav.other.etag = 0; + trav.other.file_id = 0; + trav.other.instruction = CSYNC_INSTRUCTION_NONE; + trav.other.modtime = 0; + trav.other.size = 0; + } + + rc = (*visitor)(&trav, twctx->userdata); + cur->instruction = trav.instruction; + if (trav.etag != cur->etag) { // FIXME It would be nice to have this documented + SAFE_FREE(cur->etag); + cur->etag = c_strdup(trav.etag); + } + + return rc; + } + ctx->status_code = CSYNC_STATUS_PARAM_ERROR; + return -1; +} + +/* + * treewalk function, called from its wrappers below. + * + * it encapsulates the user visitor function, the filter and the userdata + * into a treewalk_context structure and calls the rb treewalk function, + * which calls the local _csync_treewalk_visitor in this module. + * The user visitor is called from there. + */ +static int _csync_walk_tree(CSYNC *ctx, c_rbtree_t *tree, csync_treewalk_visit_func *visitor, int filter) +{ + _csync_treewalk_context tw_ctx; + int rc = -1; + + if (ctx == NULL) { + errno = EBADF; + return rc; + } + + if (visitor == NULL || tree == NULL) { + ctx->status_code = CSYNC_STATUS_PARAM_ERROR; + return rc; + } + + tw_ctx.userdata = ctx->callbacks.userdata; + tw_ctx.user_visitor = visitor; + tw_ctx.instruction_filter = filter; + + ctx->callbacks.userdata = &tw_ctx; + + rc = c_rbtree_walk(tree, (void*) ctx, _csync_treewalk_visitor); + if( rc < 0 ) { + if( ctx->status_code == CSYNC_STATUS_OK ) + ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_TREE_ERROR); + } + ctx->callbacks.userdata = tw_ctx.userdata; + + return rc; +} + +/* + * wrapper function for treewalk on the remote tree + */ +int csync_walk_remote_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter) +{ + c_rbtree_t *tree = NULL; + int rc = -1; + + if(ctx != NULL) { + ctx->status_code = CSYNC_STATUS_OK; + ctx->current = REMOTE_REPLICA; + tree = ctx->remote.tree; + } + + /* all error handling in the called function */ + rc = _csync_walk_tree(ctx, tree, visitor, filter); + return rc; +} + +/* + * wrapper function for treewalk on the local tree + */ +int csync_walk_local_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter) +{ + c_rbtree_t *tree = NULL; + int rc = -1; + + if (ctx != NULL) { + ctx->status_code = CSYNC_STATUS_OK; + ctx->current = LOCAL_REPLICA; + tree = ctx->local.tree; + } + + /* all error handling in the called function */ + rc = _csync_walk_tree(ctx, tree, visitor, filter); + return rc; +} + +static void _tree_destructor(void *data) { + csync_file_stat_t *freedata = NULL; + + freedata = (csync_file_stat_t *) data; + csync_file_stat_free(freedata); +} + +/* reset all the list to empty. + * used by csync_commit and csync_destroy */ +static void _csync_clean_ctx(CSYNC *ctx) +{ + /* destroy the rbtrees */ + if (c_rbtree_size(ctx->local.tree) > 0) { + c_rbtree_destroy(ctx->local.tree, _tree_destructor); + } + + if (c_rbtree_size(ctx->remote.tree) > 0) { + c_rbtree_destroy(ctx->remote.tree, _tree_destructor); + } + + csync_rename_destroy(ctx); + + /* free memory */ + c_rbtree_free(ctx->local.tree); + c_rbtree_free(ctx->remote.tree); + + SAFE_FREE(ctx->remote.root_perms); +} + +int csync_commit(CSYNC *ctx) { + int rc = 0; + + if (ctx == NULL) { + return -1; + } + + ctx->status_code = CSYNC_STATUS_OK; + + if (ctx->statedb.db != NULL + && csync_statedb_close(ctx) < 0) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "ERR: closing of statedb failed."); + rc = -1; + } + ctx->statedb.db = NULL; + + _csync_clean_ctx(ctx); + + ctx->remote.read_from_db = 0; + ctx->read_remote_from_db = true; + ctx->db_is_empty = false; + + + /* Create new trees */ + c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp); + c_rbtree_create(&ctx->remote.tree, _key_cmp, _data_cmp); + + + ctx->status = CSYNC_STATUS_INIT; + SAFE_FREE(ctx->error_string); + + rc = 0; + return rc; +} + +int csync_destroy(CSYNC *ctx) { + int rc = 0; + + if (ctx == NULL) { + errno = EBADF; + return -1; + } + ctx->status_code = CSYNC_STATUS_OK; + + if (ctx->statedb.db != NULL + && csync_statedb_close(ctx) < 0) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "ERR: closing of statedb failed."); + rc = -1; + } + ctx->statedb.db = NULL; + + _csync_clean_ctx(ctx); + + SAFE_FREE(ctx->statedb.file); + SAFE_FREE(ctx->local.uri); + SAFE_FREE(ctx->error_string); + + SAFE_FREE(ctx); + + return rc; +} + +void *csync_get_userdata(CSYNC *ctx) { + if (ctx == NULL) { + return NULL; + } + return ctx->callbacks.userdata; +} + +int csync_set_userdata(CSYNC *ctx, void *userdata) { + if (ctx == NULL) { + return -1; + } + + ctx->callbacks.userdata = userdata; + + return 0; +} + +csync_auth_callback csync_get_auth_callback(CSYNC *ctx) { + if (ctx == NULL) { + return NULL; + } + + return ctx->callbacks.auth_function; +} + +int csync_set_status(CSYNC *ctx, int status) { + if (ctx == NULL || status < 0) { + return -1; + } + + ctx->status = status; + + return 0; +} + +CSYNC_STATUS csync_get_status(CSYNC *ctx) { + if (ctx == NULL) { + return -1; + } + + return ctx->status_code; +} + +const char *csync_get_status_string(CSYNC *ctx) +{ + return csync_vio_get_status_string(ctx); +} + +void csync_request_abort(CSYNC *ctx) +{ + if (ctx != NULL) { + ctx->abort = true; + } +} + +void csync_resume(CSYNC *ctx) +{ + if (ctx != NULL) { + ctx->abort = false; + } +} + +int csync_abort_requested(CSYNC *ctx) +{ + if (ctx != NULL) { + return ctx->abort; + } else { + return (1 == 0); + } +} + +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->checksumHeader); + SAFE_FREE(st); + } +} diff --git a/src/csync/csync.h b/src/csync/csync.h new file mode 100644 index 000000000..daf778c24 --- /dev/null +++ b/src/csync/csync.h @@ -0,0 +1,515 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2012-2013 by Klaas Freitag + * + * 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 csync.h + * + * @brief Application developer interface for csync. + * + * @defgroup csyncPublicAPI csync public API + * + * @{ + */ + +#ifndef _CSYNC_H +#define _CSYNC_H + +#include "std/c_private.h" +#include "ocsynclib.h" +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum csync_status_codes_e { + CSYNC_STATUS_OK = 0, + + CSYNC_STATUS_ERROR = 1024, /* don't use this code, + */ + CSYNC_STATUS_UNSUCCESSFUL, /* Unspecific problem happend */ + CSYNC_STATUS_NO_LOCK, /* OBSOLETE does not happen anymore */ + CSYNC_STATUS_STATEDB_LOAD_ERROR, /* Statedb can not be loaded. */ + CSYNC_STATUS_STATEDB_CORRUPTED, /* Statedb is corrupted */ + CSYNC_STATUS_NO_MODULE, /* URL passed to csync does not start with owncloud:// or ownclouds:// */ + CSYNC_STATUS_TIMESKEW, /* OBSOLETE */ + CSYNC_STATUS_FILESYSTEM_UNKNOWN, /* UNUSED */ + CSYNC_STATUS_TREE_ERROR, /* csync trees could not be created */ + CSYNC_STATUS_MEMORY_ERROR, /* not enough memory problem */ + CSYNC_STATUS_PARAM_ERROR, /* parameter is zero where not expected */ + CSYNC_STATUS_UPDATE_ERROR, /* general update or discovery error */ + CSYNC_STATUS_RECONCILE_ERROR, /* general reconcile error */ + CSYNC_STATUS_PROPAGATE_ERROR, /* OBSOLETE */ + CSYNC_STATUS_REMOTE_ACCESS_ERROR, /* UNUSED */ + CSYNC_STATUS_REMOTE_CREATE_ERROR, /* UNUSED */ + CSYNC_STATUS_REMOTE_STAT_ERROR, /* UNUSED */ + CSYNC_STATUS_LOCAL_CREATE_ERROR, /* UNUSED */ + CSYNC_STATUS_LOCAL_STAT_ERROR, /* UNUSED */ + CSYNC_STATUS_PROXY_ERROR, /* UNUSED */ + CSYNC_STATUS_LOOKUP_ERROR, /* Neon fails to find proxy. Almost OBSOLETE */ + CSYNC_STATUS_SERVER_AUTH_ERROR, /* UNUSED */ + CSYNC_STATUS_PROXY_AUTH_ERROR, /* UNUSED */ + CSYNC_STATUS_CONNECT_ERROR, /* neon driven connection failed */ + CSYNC_STATUS_TIMEOUT, /* UNUSED */ + CSYNC_STATUS_HTTP_ERROR, /* UNUSED */ + CSYNC_STATUS_PERMISSION_DENIED, /* */ + CSYNC_STATUS_NOT_FOUND, + CSYNC_STATUS_FILE_EXISTS, + CSYNC_STATUS_OUT_OF_SPACE, + CSYNC_STATUS_QUOTA_EXCEEDED, /* UNUSED */ + CSYNC_STATUS_SERVICE_UNAVAILABLE, + CSYNC_STATUS_STORAGE_UNAVAILABLE, + CSYNC_STATUS_FILE_SIZE_ERROR, + CSYNC_STATUS_CONTEXT_LOST, + CSYNC_STATUS_MERGE_FILETREE_ERROR, + CSYNC_STATUS_CSYNC_STATUS_ERROR, + CSYNC_STATUS_OPENDIR_ERROR, + CSYNC_STATUS_READDIR_ERROR, + CSYNC_STATUS_OPEN_ERROR, + CSYNC_STATUS_ABORTED, + /* Codes for file individual status: */ + CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK, + CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST, + CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS, + CSYNC_STATUS_INDIVIDUAL_TRAILING_SPACE, + CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME, + CYSNC_STATUS_FILE_LOCKED_OR_OPEN, + CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN, + CSYNC_STATUS_INVALID_CHARACTERS, + CSYNC_STATUS_INDIVIDUAL_STAT_FAILED, + CSYNC_STATUS_FORBIDDEN, + CSYNC_STATUS_INDIVIDUAL_TOO_DEEP, + CSYNC_STATUS_INDIVIDUAL_IS_CONFLICT_FILE +}; + +typedef enum csync_status_codes_e CSYNC_STATUS; + +#ifndef likely +# define likely(x) (x) +#endif +#ifndef unlikely +# define unlikely(x) (x) +#endif + +#define CSYNC_STATUS_IS_OK(x) (likely((x) == CSYNC_STATUS_OK)) +#define CSYNC_STATUS_IS_ERR(x) (unlikely((x) >= CSYNC_STATUS_ERROR)) +#define CSYNC_STATUS_IS_EQUAL(x, y) ((x) == (y)) + +/** + * Instruction enum. In the file traversal structure, it describes + * the csync state of a file. + */ +enum csync_instructions_e { + CSYNC_INSTRUCTION_NONE = 0x00000000, /* Nothing to do (UPDATE|RECONCILE) */ + CSYNC_INSTRUCTION_EVAL = 0x00000001, /* There was changed compared to the DB (UPDATE) */ + CSYNC_INSTRUCTION_REMOVE = 0x00000002, /* The file need to be removed (RECONCILE) */ + CSYNC_INSTRUCTION_RENAME = 0x00000004, /* The file need to be renamed (RECONCILE) */ + CSYNC_INSTRUCTION_EVAL_RENAME = 0x00000800, /* The file is new, it is the destination of a rename (UPDATE) */ + CSYNC_INSTRUCTION_NEW = 0x00000008, /* The file is new compared to the db (UPDATE) */ + CSYNC_INSTRUCTION_CONFLICT = 0x00000010, /* The file need to be downloaded because it is a conflict (RECONCILE) */ + CSYNC_INSTRUCTION_IGNORE = 0x00000020, /* The file is ignored (UPDATE|RECONCILE) */ + CSYNC_INSTRUCTION_SYNC = 0x00000040, /* The file need to be pushed to the other remote (RECONCILE) */ + CSYNC_INSTRUCTION_STAT_ERROR = 0x00000080, + CSYNC_INSTRUCTION_ERROR = 0x00000100, + CSYNC_INSTRUCTION_TYPE_CHANGE = 0x00000200, /* Like NEW, but deletes the old entity first (RECONCILE) + Used when the type of something changes from directory to file + or back. */ + CSYNC_INSTRUCTION_UPDATE_METADATA = 0x00000400, /* If the etag has been updated and need to be writen to the db, + but without any propagation (UPDATE|RECONCILE) */ +}; + +enum csync_ftw_type_e { + CSYNC_FTW_TYPE_FILE, + CSYNC_FTW_TYPE_SLINK, + CSYNC_FTW_TYPE_DIR, + CSYNC_FTW_TYPE_SKIP +}; + + +#define FILE_ID_BUF_SIZE 36 + +// 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_HIDDEN = 1 << 1 +}; + +enum csync_vio_file_type_e { + CSYNC_VIO_FILE_TYPE_UNKNOWN, + CSYNC_VIO_FILE_TYPE_REGULAR, + CSYNC_VIO_FILE_TYPE_DIRECTORY, + CSYNC_VIO_FILE_TYPE_FIFO, + CSYNC_VIO_FILE_TYPE_SOCKET, + CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE, + CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE, + CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK +}; + +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_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_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_ETAG = 1 << 17, + 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 { + char *name; + char *etag; // FIXME: Should this be inlined like file_id and perm? + char file_id[FILE_ID_BUF_SIZE+1]; + char *directDownloadUrl; + char *directDownloadCookies; + char remotePerm[REMOTE_PERM_BUF_SIZE+1]; + + time_t atime; + time_t mtime; + time_t ctime; + + int64_t size; + + mode_t mode; + + uint64_t inode; + + int fields; // actually enum csync_vio_file_stat_fields_e fields; + enum csync_vio_file_type_e type; + + enum csync_vio_file_flags_e flags; + + char *original_name; // only set if locale conversion fails + + // For remote file stats: the highest quality checksum the server provided + // in the "SHA1:324315da2143" form. + char *checksumHeader; +}; + +csync_vio_file_stat_t OCSYNC_EXPORT *csync_vio_file_stat_new(void); +csync_vio_file_stat_t OCSYNC_EXPORT *csync_vio_file_stat_copy(csync_vio_file_stat_t *file_stat); + +void OCSYNC_EXPORT csync_vio_file_stat_destroy(csync_vio_file_stat_t *fstat); + +void OCSYNC_EXPORT csync_vio_file_stat_set_file_id( csync_vio_file_stat_t* dst, const char* src ); + +void OCSYNC_EXPORT csync_vio_set_file_id(char* dst, const char *src ); + + +/** + * CSync File Traversal structure. + * + * This structure is passed to the visitor function for every file + * which is seen. + * + */ + +struct csync_tree_walk_file_s { + const char *path; + int64_t size; + int64_t inode; + time_t modtime; + mode_t mode; + enum csync_ftw_type_e type; + enum csync_instructions_e instruction; + + /* For directories: Does it have children that were ignored (hidden or ignore pattern) */ + int has_ignored_files; + + const char *rename_path; + const char *etag; + const char *file_id; + const char *remotePerm; + char *directDownloadUrl; + char *directDownloadCookies; + + const char *checksumHeader; + + struct { + int64_t size; + time_t modtime; + const char *etag; + const char *file_id; + enum csync_instructions_e instruction; + } other; + + CSYNC_STATUS error_status; +}; +typedef struct csync_tree_walk_file_s TREE_WALK_FILE; + +/** + * csync handle + */ +typedef struct csync_s CSYNC; + +typedef int (*csync_auth_callback) (const char *prompt, char *buf, size_t len, + int echo, int verify, void *userdata); + +typedef void (*csync_log_callback) (int verbosity, + const char *function, + const char *buffer); + +typedef void (*csync_update_callback) (bool local, + const char *dirUrl, + void *userdata); + +typedef void csync_vio_handle_t; +typedef csync_vio_handle_t* (*csync_vio_opendir_hook) (const char *url, + void *userdata); +typedef csync_vio_file_stat_t* (*csync_vio_readdir_hook) (csync_vio_handle_t *dhhandle, + void *userdata); +typedef void (*csync_vio_closedir_hook) (csync_vio_handle_t *dhhandle, + void *userdata); +typedef int (*csync_vio_stat_hook) (csync_vio_handle_t *dhhandle, + void *userdata); + +/* Compute the checksum of the given \a checksumTypeId for \a path. */ +typedef const char *(*csync_checksum_hook)( + const char *path, const char *otherChecksumHeader, void *userdata); + +/** + * @brief Allocate a csync context. + * + * @param csync The context variable to allocate. + */ +void OCSYNC_EXPORT csync_create(CSYNC **csync, const char *local); + +/** + * @brief Initialize the file synchronizer. + * + * This function loads the configuration + * + * @param ctx The context to initialize. + */ +void OCSYNC_EXPORT csync_init(CSYNC *ctx, const char *db_file); + +/** + * @brief Update detection + * + * @param ctx The context to run the update detection on. + * + * @return 0 on success, less than 0 if an error occurred. + */ +int OCSYNC_EXPORT csync_update(CSYNC *ctx); + +/** + * @brief Reconciliation + * + * @param ctx The context to run the reconciliation on. + * + * @return 0 on success, less than 0 if an error occurred. + */ +int OCSYNC_EXPORT csync_reconcile(CSYNC *ctx); + +/** + * @brief Re-initializes the csync context + * + * @param ctx The context to commit. + * + * @return 0 on success, less than 0 if an error occurred. + */ +int OCSYNC_EXPORT csync_commit(CSYNC *ctx); + +/** + * @brief Destroy the csync context + * + * frees the memory. + * + * @param ctx The context to destroy. + * + * @return 0 on success, less than 0 if an error occurred. + */ +int OCSYNC_EXPORT csync_destroy(CSYNC *ctx); + +/** + * @brief Get the userdata saved in the context. + * + * @param ctx The csync context. + * + * @return The userdata saved in the context, NULL if an error + * occurred. + */ +void *csync_get_userdata(CSYNC *ctx); + +/** + * @brief Save userdata to the context which is passed to the auth + * callback function. + * + * @param ctx The csync context. + * + * @param userdata The userdata to be stored in the context. + * + * @return 0 on success, less than 0 if an error occurred. + */ +int OCSYNC_EXPORT csync_set_userdata(CSYNC *ctx, void *userdata); + +/** + * @brief Get the authentication callback set. + * + * @param ctx The csync context. + * + * @return The authentication callback set or NULL if an error + * occurred. + */ +csync_auth_callback OCSYNC_EXPORT csync_get_auth_callback(CSYNC *ctx); + +/** + * @brief Set the authentication callback. + * + * @param ctx The csync context. + * + * @param cb The authentication callback. + * + * @return 0 on success, less than 0 if an error occurred. + */ +int OCSYNC_EXPORT csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb); + +/** + * @brief Set the log level. + * + * @param[in] level The log verbosity. + * + * @return 0 on success, < 0 if an error occurred. + */ +int OCSYNC_EXPORT csync_set_log_level(int level); + +/** + * @brief Get the log verbosity + * + * @return The log verbosity, -1 on error. + */ +int OCSYNC_EXPORT csync_get_log_level(void); + +/** + * @brief Get the logging callback set. + * + * @return The logging callback set or NULL if an error + * occurred. + */ +csync_log_callback OCSYNC_EXPORT csync_get_log_callback(void); + +/** + * @brief Set the logging callback. + * + * @param cb The logging callback. + * + * @return 0 on success, less than 0 if an error occurred. + */ +int OCSYNC_EXPORT csync_set_log_callback(csync_log_callback cb); + +/* Used for special modes or debugging */ +CSYNC_STATUS OCSYNC_EXPORT csync_get_status(CSYNC *ctx); + +/* Used for special modes or debugging */ +int OCSYNC_EXPORT csync_set_status(CSYNC *ctx, int status); + +typedef int csync_treewalk_visit_func(TREE_WALK_FILE* ,void*); + +/** + * @brief Walk the local file tree and call a visitor function for each file. + * + * @param ctx The csync context. + * @param visitor A callback function to handle the file info. + * @param filter A filter, built from or'ed csync_instructions_e + * + * @return 0 on success, less than 0 if an error occurred. + */ +int OCSYNC_EXPORT csync_walk_local_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter); + +/** + * @brief Walk the remote file tree and call a visitor function for each file. + * + * @param ctx The csync context. + * @param visitor A callback function to handle the file info. + * @param filter A filter, built from and'ed csync_instructions_e + * + * @return 0 on success, less than 0 if an error occurred. + */ +int OCSYNC_EXPORT csync_walk_remote_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter); + +/** + * @brief Get the csync status string. + * + * @param ctx The csync context. + * + * @return A const pointer to a string with more precise status info. + */ +const char OCSYNC_EXPORT *csync_get_status_string(CSYNC *ctx); + +/** + * @brief Aborts the current sync run as soon as possible. Can be called from another thread. + * + * @param ctx The csync context. + */ +void OCSYNC_EXPORT csync_request_abort(CSYNC *ctx); + +/** + * @brief Clears the abort flag. Can be called from another thread. + * + * @param ctx The csync context. + */ +void OCSYNC_EXPORT csync_resume(CSYNC *ctx); + +/** + * @brief Checks for the abort flag, to be used from the modules. + * + * @param ctx The csync context. + */ +int OCSYNC_EXPORT csync_abort_requested(CSYNC *ctx); + +char OCSYNC_EXPORT *csync_normalize_etag(const char *); +time_t OCSYNC_EXPORT oc_httpdate_parse( const char *date ); + +#ifdef __cplusplus +} +#endif + +/** + * }@ + */ +#endif /* _CSYNC_H */ +/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/src/csync/csync_exclude.c b/src/csync/csync_exclude.c new file mode 100644 index 000000000..fea662504 --- /dev/null +++ b/src/csync/csync_exclude.c @@ -0,0 +1,437 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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 "config_csync.h" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include + +#include +#include +#include + +#include "c_lib.h" +#include "c_private.h" + +#include "csync_private.h" +#include "csync_exclude.h" +#include "csync_misc.h" + +#ifdef _WIN32 +#include +#else +#include +#endif + +#define CSYNC_LOG_CATEGORY_NAME "csync.exclude" +#include "csync_log.h" + +#ifndef WITH_TESTING +static +#endif +int _csync_exclude_add(c_strlist_t **inList, const char *string) { + size_t i = 0; + + // We never want duplicates, so check whether the string is already + // in the list first. + if (*inList) { + for (i = 0; i < (*inList)->count; ++i) { + char *pattern = (*inList)->vector[i]; + if (c_streq(pattern, string)) { + return 1; + } + } + } + return c_strlist_add_grow(inList, string); +} + +/** Expands C-like escape sequences. + * + * The returned string is heap-allocated and owned by the caller. + */ +static const char *csync_exclude_expand_escapes(const char * input) +{ + size_t i_len = strlen(input) + 1; + char *out = c_malloc(i_len); // out can only be shorter + + size_t i = 0; + size_t o = 0; + for (; i < i_len; ++i) { + if (input[i] == '\\') { + // at worst input[i+1] is \0 + switch (input[i+1]) { + case '\'': out[o++] = '\''; break; + case '"': out[o++] = '"'; break; + case '?': out[o++] = '?'; break; + case '\\': out[o++] = '\\'; break; + case 'a': out[o++] = '\a'; break; + case 'b': out[o++] = '\b'; break; + case 'f': out[o++] = '\f'; break; + case 'n': out[o++] = '\n'; break; + case 'r': out[o++] = '\r'; break; + case 't': out[o++] = '\t'; break; + case 'v': out[o++] = '\v'; break; + default: + out[o++] = input[i]; + out[o++] = input[i+1]; + break; + } + ++i; + } else { + out[o++] = input[i]; + } + } + return out; +} + +int csync_exclude_load(const char *fname, c_strlist_t **list) { + int fd = -1; + int i = 0; + int rc = -1; + int64_t size; + char *buf = NULL; + char *entry = NULL; + mbchar_t *w_fname; + + if (fname == NULL) { + return -1; + } + +#ifdef _WIN32 + _fmode = _O_BINARY; +#endif + + w_fname = c_utf8_path_to_locale(fname); + if (w_fname == NULL) { + return -1; + } + + fd = _topen(w_fname, O_RDONLY); + c_free_locale_string(w_fname); + if (fd < 0) { + return -1; + } + + size = lseek(fd, 0, SEEK_END); + if (size < 0) { + rc = -1; + goto out; + } + lseek(fd, 0, SEEK_SET); + if (size == 0) { + rc = 0; + goto out; + } + buf = c_malloc(size + 1); + if (read(fd, buf, size) != size) { + rc = -1; + goto out; + } + buf[size] = '\0'; + + /* FIXME: Use fgets and don't add duplicates */ + entry = buf; + for (i = 0; i < size; i++) { + if (buf[i] == '\n' || buf[i] == '\r') { + if (entry != buf + i) { + buf[i] = '\0'; + if (*entry != '#') { + const char *unescaped = csync_exclude_expand_escapes(entry); + rc = _csync_exclude_add(list, unescaped); + if( rc == 0 ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Adding entry: %s", unescaped); + } + SAFE_FREE(unescaped); + if (rc < 0) { + goto out; + } + } + } + entry = buf + i + 1; + } + } + + rc = 0; +out: + SAFE_FREE(buf); + close(fd); + return rc; +} + +// See http://support.microsoft.com/kb/74496 and +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx +// Additionally, we ignore '$Recycle.Bin', see https://github.com/owncloud/client/issues/2955 +static const char* win_reserved_words[] = {"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", + "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", + "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", "CLOCK$", "$Recycle.Bin" }; + +bool csync_is_windows_reserved_word(const char* filename) { + + size_t win_reserve_words_len = sizeof(win_reserved_words) / sizeof(char*); + size_t j; + + for (j = 0; j < win_reserve_words_len; j++) { + int len_reserved_word = strlen(win_reserved_words[j]); + int len_filename = strlen(filename); + if (len_filename == 2 && filename[1] == ':') { + if (filename[0] >= 'a' && filename[0] <= 'z') { + return true; + } + if (filename[0] >= 'A' && filename[0] <= 'Z') { + return true; + } + } + if (c_strncasecmp(filename, win_reserved_words[j], len_reserved_word) == 0) { + if (len_filename == len_reserved_word) { + return true; + } + if ((len_filename > len_reserved_word) && (filename[len_reserved_word] == '.')) { + return true; + } + } + } + return false; +} + +static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const char *path, int filetype, bool check_leading_dirs) { + size_t i = 0; + const char *bname = NULL; + size_t blen = 0; + char *conflict = NULL; + int rc = -1; + CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED; + CSYNC_EXCLUDE_TYPE type = CSYNC_NOT_EXCLUDED; + + /* split up the path */ + bname = strrchr(path, '/'); + if (bname) { + bname += 1; // don't include the / + } else { + bname = path; + } + blen = strlen(bname); + + rc = csync_fnmatch("._sync_*.db*", bname, 0); + if (rc == 0) { + match = CSYNC_FILE_SILENTLY_EXCLUDED; + goto out; + } + rc = csync_fnmatch(".sync_*.db*", bname, 0); + if (rc == 0) { + match = CSYNC_FILE_SILENTLY_EXCLUDED; + goto out; + } + rc = csync_fnmatch(".csync_journal.db*", bname, 0); + if (rc == 0) { + match = CSYNC_FILE_SILENTLY_EXCLUDED; + goto out; + } + + // check the strlen and ignore the file if its name is longer than 254 chars. + // whenever changing this also check createDownloadTmpFileName + if (blen > 254) { + match = CSYNC_FILE_EXCLUDE_LONG_FILENAME; + goto out; + } + +#ifdef _WIN32 + // Windows cannot sync files ending in spaces (#2176). It also cannot + // distinguish files ending in '.' from files without an ending, + // as '.' is a separator that is not stored internally, so let's + // not allow to sync those to avoid file loss/ambiguities (#416) + if (blen > 1) { + if (bname[blen-1]== ' ') { + match = CSYNC_FILE_EXCLUDE_TRAILING_SPACE; + goto out; + } else if (bname[blen-1]== '.' ) { + match = CSYNC_FILE_EXCLUDE_INVALID_CHAR; + goto out; + } + } + + if (csync_is_windows_reserved_word(bname)) { + match = CSYNC_FILE_EXCLUDE_INVALID_CHAR; + goto out; + } + + // Filter out characters not allowed in a filename on windows + const char *p = NULL; + for (p = path; *p; p++) { + switch (*p) { + case '\\': + case ':': + case '?': + case '*': + case '"': + case '>': + case '<': + case '|': + match = CSYNC_FILE_EXCLUDE_INVALID_CHAR; + goto out; + default: + break; + } + } +#endif + + /* We create a desktop.ini on Windows for the sidebar icon, make sure we don't sync them. */ + rc = csync_fnmatch("Desktop.ini", bname, 0); + if (rc == 0) { + match = CSYNC_FILE_SILENTLY_EXCLUDED; + goto out; + } + + rc = csync_fnmatch(".owncloudsync.log*", bname, 0); + if (rc == 0) { + match = CSYNC_FILE_SILENTLY_EXCLUDED; + goto out; + } + + /* Always ignore conflict files, not only via the exclude list */ + rc = csync_fnmatch("*_conflict-*", bname, 0); + if (rc == 0) { + match = CSYNC_FILE_EXCLUDE_CONFLICT; + goto out; + } + + if (getenv("CSYNC_CONFLICT_FILE_USERNAME")) { + rc = asprintf(&conflict, "*_conflict_%s-*", getenv("CSYNC_CONFLICT_FILE_USERNAME")); + if (rc < 0) { + goto out; + } + rc = csync_fnmatch(conflict, path, 0); + if (rc == 0) { + match = CSYNC_FILE_EXCLUDE_CONFLICT; + SAFE_FREE(conflict); + goto out; + } + SAFE_FREE(conflict); + } + + if( ! excludes ) { + goto out; + } + + c_strlist_t *path_components = NULL; + if (check_leading_dirs) { + /* Build a list of path components to check. */ + path_components = c_strlist_new(32); + char *path_split = strdup(path); + size_t len = strlen(path_split); + for (i = len; ; --i) { + // read backwards until a path separator is found + if (i != 0 && path_split[i-1] != '/') { + continue; + } + + // check 'basename', i.e. for "/foo/bar/fi" we'd check 'fi', 'bar', 'foo' + if (path_split[i] != 0) { + c_strlist_add_grow(&path_components, path_split + i); + } + + if (i == 0) { + break; + } + + // check 'dirname', i.e. for "/foo/bar/fi" we'd check '/foo/bar', '/foo' + path_split[i-1] = '\0'; + c_strlist_add_grow(&path_components, path_split); + } + SAFE_FREE(path_split); + } + + /* Loop over all exclude patterns and evaluate the given path */ + for (i = 0; match == CSYNC_NOT_EXCLUDED && i < excludes->count; i++) { + bool match_dirs_only = false; + char *pattern = excludes->vector[i]; + + type = CSYNC_FILE_EXCLUDE_LIST; + if (!pattern[0]) { /* empty pattern */ + continue; + } + /* Excludes starting with ']' means it can be cleanup */ + if (pattern[0] == ']') { + ++pattern; + if (filetype == CSYNC_FTW_TYPE_FILE) { + type = CSYNC_FILE_EXCLUDE_AND_REMOVE; + } + } + /* Check if the pattern applies to pathes only. */ + if (pattern[strlen(pattern)-1] == '/') { + if (!check_leading_dirs && filetype == CSYNC_FTW_TYPE_FILE) { + continue; + } + match_dirs_only = true; + pattern[strlen(pattern)-1] = '\0'; /* Cut off the slash */ + } + + /* check if the pattern contains a / and if, compare to the whole path */ + if (strchr(pattern, '/')) { + rc = csync_fnmatch(pattern, path, FNM_PATHNAME); + if( rc == 0 ) { + match = type; + } + /* if the pattern requires a dir, but path is not, its still not excluded. */ + if (match_dirs_only && filetype != CSYNC_FTW_TYPE_DIR) { + match = CSYNC_NOT_EXCLUDED; + } + } + + /* if still not excluded, check each component and leading directory of the path */ + if (match == CSYNC_NOT_EXCLUDED && check_leading_dirs) { + size_t j = 0; + if (match_dirs_only && filetype == CSYNC_FTW_TYPE_FILE) { + j = 1; // skip the first entry, which is bname + } + for (; j < path_components->count; ++j) { + rc = csync_fnmatch(pattern, path_components->vector[j], 0); + if (rc == 0) { + match = type; + break; + } + } + } else if (match == CSYNC_NOT_EXCLUDED && !check_leading_dirs) { + rc = csync_fnmatch(pattern, bname, 0); + if (rc == 0) { + match = type; + } + } + if (match_dirs_only) { + /* restore the '/' */ + pattern[strlen(pattern)] = '/'; + } + } + c_strlist_destroy(path_components); + + out: + + return match; +} + +CSYNC_EXCLUDE_TYPE csync_excluded_traversal(c_strlist_t *excludes, const char *path, int filetype) { + return _csync_excluded_common(excludes, path, filetype, false); +} + +CSYNC_EXCLUDE_TYPE csync_excluded_no_ctx(c_strlist_t *excludes, const char *path, int filetype) { + return _csync_excluded_common(excludes, path, filetype, true); +} + diff --git a/src/csync/csync_exclude.h b/src/csync/csync_exclude.h new file mode 100644 index 000000000..722d27cac --- /dev/null +++ b/src/csync/csync_exclude.h @@ -0,0 +1,89 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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_EXCLUDE_H +#define _CSYNC_EXCLUDE_H + +#include "ocsynclib.h" + +enum csync_exclude_type_e { + CSYNC_NOT_EXCLUDED = 0, + CSYNC_FILE_SILENTLY_EXCLUDED, + CSYNC_FILE_EXCLUDE_AND_REMOVE, + CSYNC_FILE_EXCLUDE_LIST, + CSYNC_FILE_EXCLUDE_INVALID_CHAR, + CSYNC_FILE_EXCLUDE_TRAILING_SPACE, + CSYNC_FILE_EXCLUDE_LONG_FILENAME, + CSYNC_FILE_EXCLUDE_HIDDEN, + CSYNC_FILE_EXCLUDE_STAT_FAILED, + CSYNC_FILE_EXCLUDE_CONFLICT +}; +typedef enum csync_exclude_type_e CSYNC_EXCLUDE_TYPE; + +#ifdef WITH_TESTING +int OCSYNC_EXPORT _csync_exclude_add(c_strlist_t **inList, const char *string); +#endif + +/** + * @brief Load exclude list + * + * @param ctx The context of the synchronizer. + * @param fname The filename to load. + * + * @return 0 on success, -1 if an error occurred with errno set. + */ +int OCSYNC_EXPORT csync_exclude_load(const char *fname, c_strlist_t **list); + +/** + * @brief Check if the given path should be excluded in a traversal situation. + * + * It does only part of the work that csync_excluded does because it's assumed + * that all leading directories have been run through csync_excluded_traversal() + * before. This can be significantly faster. + * + * That means for '/foo/bar/file' only ('/foo/bar/file', 'file') is checked + * against the exclude patterns. + * + * @param ctx The synchronizer context. + * @param path The patch to check. + * + * @return 2 if excluded and needs cleanup, 1 if excluded, 0 if not. + */ +CSYNC_EXCLUDE_TYPE csync_excluded_traversal(c_strlist_t *excludes, const char *path, int filetype); + +/** + * @brief csync_excluded_no_ctx + * @param excludes + * @param path + * @param filetype + * @return + */ +CSYNC_EXCLUDE_TYPE OCSYNC_EXPORT csync_excluded_no_ctx(c_strlist_t *excludes, const char *path, int filetype); +#endif /* _CSYNC_EXCLUDE_H */ + +/** + * @brief Checks if filename is considered reserved by Windows + * @param file_name filename + * @return true if file is reserved, false otherwise + */ +bool csync_is_windows_reserved_word(const char *file_name); + + +/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/src/csync/csync_log.c b/src/csync/csync_log.c new file mode 100644 index 000000000..4a2e24a32 --- /dev/null +++ b/src/csync/csync_log.c @@ -0,0 +1,77 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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 "config_csync.h" + +#include +#include +#include + +#include "csync_private.h" +#include "csync_log.h" + +CSYNC_THREAD int csync_log_level; +CSYNC_THREAD csync_log_callback csync_log_cb; + +void csync_log(int verbosity, + const char *function, + const char *format, ...) +{ + csync_log_callback log_fn = csync_get_log_callback(); + if (log_fn && verbosity <= csync_get_log_level()) { + char buffer[1024]; + va_list va; + + va_start(va, format); + vsnprintf(buffer, sizeof(buffer), format, va); + va_end(va); + + log_fn(verbosity, function, buffer); + return; + } +} + +int csync_set_log_level(int level) { + if (level < 0) { + return -1; + } + + csync_log_level = level; + + return 0; +} + +int csync_get_log_level(void) { + return csync_log_level; +} + +int csync_set_log_callback(csync_log_callback cb) { + if (cb == NULL) { + return -1; + } + + csync_log_cb = cb; + + return 0; +} + +csync_log_callback csync_get_log_callback(void) { + return csync_log_cb; +} diff --git a/src/csync/csync_log.h b/src/csync/csync_log.h new file mode 100644 index 000000000..0cd0d01fc --- /dev/null +++ b/src/csync/csync_log.h @@ -0,0 +1,75 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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 csync_log.h + * + * @brief Logging interface of csync + * + * @defgroup csyncLogInternals csync logging internals + * @ingroup csyncInternalAPI + * + * @{ + */ + +#ifndef _CSYNC_LOG_H +#define _CSYNC_LOG_H + +/* GCC have printf type attribute check. */ +#ifndef PRINTF_ATTRIBUTE +#ifdef __GNUC__ +#ifdef _WIN32 +#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__gnu_printf__, a, b))) +#else +#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b))) +#endif +#else +#define PRINTF_ATTRIBUTE(a,b) +#endif /* __GNUC__ */ +#endif /* ndef PRINTF_ATTRIBUTE */ + +enum csync_log_priority_e { + CSYNC_LOG_PRIORITY_NOLOG = 0, + CSYNC_LOG_PRIORITY_FATAL, + CSYNC_LOG_PRIORITY_ALERT, + CSYNC_LOG_PRIORITY_CRIT, + CSYNC_LOG_PRIORITY_ERROR, + CSYNC_LOG_PRIORITY_WARN, + CSYNC_LOG_PRIORITY_NOTICE, + CSYNC_LOG_PRIORITY_INFO, + CSYNC_LOG_PRIORITY_DEBUG, + CSYNC_LOG_PRIORITY_TRACE, + CSYNC_LOG_PRIORITY_NOTSET, + CSYNC_LOG_PRIORITY_UNKNOWN, +}; + +#define CSYNC_LOG(priority, ...) \ + csync_log(priority, __func__, __VA_ARGS__) + +void csync_log(int verbosity, + const char *function, + const char *format, ...) PRINTF_ATTRIBUTE(3, 4); + +/** + * }@ + */ +#endif /* _CSYNC_LOG_H */ + +/* vim: set ft=c.doxygen ts=4 sw=4 et cindent: */ diff --git a/src/csync/csync_macros.h b/src/csync/csync_macros.h new file mode 100644 index 000000000..f128b434d --- /dev/null +++ b/src/csync/csync_macros.h @@ -0,0 +1,52 @@ +/* + * cynapses libc functions + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2012-2013 by Klaas Freitag + * + * 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_MACROS_H +#define _CSYNC_MACROS_H + +#include +#include + +/* How many elements there are in a static array */ +#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) + +/* Some special custom errno values to report bugs properly. The BASE value + * should always be larger than the highest system errno. */ +#define CSYNC_CUSTOM_ERRNO_BASE 10000 + +#define ERRNO_GENERAL_ERROR CSYNC_CUSTOM_ERRNO_BASE+2 +#define ERRNO_LOOKUP_ERROR CSYNC_CUSTOM_ERRNO_BASE+3 +#define ERRNO_USER_UNKNOWN_ON_SERVER CSYNC_CUSTOM_ERRNO_BASE+4 +#define ERRNO_PROXY_AUTH CSYNC_CUSTOM_ERRNO_BASE+5 +#define ERRNO_CONNECT CSYNC_CUSTOM_ERRNO_BASE+6 +#define ERRNO_TIMEOUT CSYNC_CUSTOM_ERRNO_BASE+7 +#define ERRNO_PRECONDITION CSYNC_CUSTOM_ERRNO_BASE+8 +#define ERRNO_RETRY CSYNC_CUSTOM_ERRNO_BASE+9 +#define ERRNO_REDIRECT CSYNC_CUSTOM_ERRNO_BASE+10 +#define ERRNO_WRONG_CONTENT CSYNC_CUSTOM_ERRNO_BASE+11 +#define ERRNO_ERROR_STRING CSYNC_CUSTOM_ERRNO_BASE+13 +#define ERRNO_SERVICE_UNAVAILABLE CSYNC_CUSTOM_ERRNO_BASE+14 +#define ERRNO_USER_ABORT CSYNC_CUSTOM_ERRNO_BASE+16 +#define ERRNO_STORAGE_UNAVAILABLE CSYNC_CUSTOM_ERRNO_BASE+17 +#define ERRNO_FORBIDDEN CSYNC_CUSTOM_ERRNO_BASE+18 + +#endif /* _CSYNC_MACROS_H */ +/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/src/csync/csync_misc.c b/src/csync/csync_misc.c new file mode 100644 index 000000000..d23236113 --- /dev/null +++ b/src/csync/csync_misc.c @@ -0,0 +1,206 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2012-2013 by Klaas Freitag + * + * 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 "config_csync.h" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +#if _WIN32 +# ifndef _WIN32_IE +# define _WIN32_IE 0x0501 // SHGetSpecialFolderPath +# endif +# include +#else /* _WIN32 */ +# include +#endif /* _WIN32 */ + +#include "c_lib.h" +#include "csync_misc.h" +#include "csync_macros.h" +#include "csync_log.h" + +#ifdef HAVE_FNMATCH +#include + +int csync_fnmatch(__const char *__pattern, __const char *__name, int __flags) { + return fnmatch(__pattern, __name, __flags); +} + +#else /* HAVE_FNMATCH */ + +#include +int csync_fnmatch(const char *pattern, const char *name, int flags) { + BOOL match; + + (void) flags; + + match = PathMatchSpecA(name, pattern); + + if(match) + return 0; + else + return 1; +} +#endif /* HAVE_FNMATCH */ + +CSYNC_STATUS csync_errno_to_status(int error, CSYNC_STATUS default_status) +{ + CSYNC_STATUS status = CSYNC_STATUS_OK; + + switch (error) { + case 0: + status = CSYNC_STATUS_OK; + break; + /* The custom errnos first. */ + case ERRNO_GENERAL_ERROR: + status = CSYNC_STATUS_UNSUCCESSFUL; + break; + case ERRNO_LOOKUP_ERROR: /* In Neon: Server or proxy hostname lookup failed */ + status = CSYNC_STATUS_LOOKUP_ERROR; + break; + case ERRNO_USER_UNKNOWN_ON_SERVER: /* Neon: User authentication on server failed. */ + status = CSYNC_STATUS_SERVER_AUTH_ERROR; + break; + case ERRNO_PROXY_AUTH: + status = CSYNC_STATUS_PROXY_AUTH_ERROR; /* Neon: User authentication on proxy failed */ + break; + case ERRNO_CONNECT: + status = CSYNC_STATUS_CONNECT_ERROR; /* Network: Connection error */ + break; + case ERRNO_TIMEOUT: + status = CSYNC_STATUS_TIMEOUT; /* Network: Timeout error */ + break; + case ERRNO_SERVICE_UNAVAILABLE: + status = CSYNC_STATUS_SERVICE_UNAVAILABLE; /* Service temporarily down */ + break; + case ERRNO_STORAGE_UNAVAILABLE: + status = CSYNC_STATUS_STORAGE_UNAVAILABLE; /* Storage temporarily unavailable */ + break; + case EFBIG: + status = CSYNC_STATUS_FILE_SIZE_ERROR; /* File larger than 2MB */ + break; + case ERRNO_PRECONDITION: + case ERRNO_RETRY: + case ERRNO_REDIRECT: + case ERRNO_WRONG_CONTENT: + status = CSYNC_STATUS_HTTP_ERROR; + break; + + case EPERM: /* Operation not permitted */ + case EACCES: /* Permission denied */ + status = CSYNC_STATUS_PERMISSION_DENIED; + break; + case ENOENT: /* No such file or directory */ + status = CSYNC_STATUS_NOT_FOUND; + break; + case EAGAIN: /* Try again */ + status = CSYNC_STATUS_TIMEOUT; + break; + case EEXIST: /* File exists */ + status = CSYNC_STATUS_FILE_EXISTS; + break; + case EINVAL: + status = CSYNC_STATUS_PARAM_ERROR; + break; + case ENOSPC: + status = CSYNC_STATUS_OUT_OF_SPACE; + break; + + /* All the remaining basic errnos: */ + case EIO: /* I/O error */ + case ESRCH: /* No such process */ + case EINTR: /* Interrupted system call */ + case ENXIO: /* No such device or address */ + case E2BIG: /* Argument list too long */ + case ENOEXEC: /* Exec format error */ + case EBADF: /* Bad file number */ + case ECHILD: /* No child processes */ + case ENOMEM: /* Out of memory */ + case EFAULT: /* Bad address */ +#ifndef _WIN32 + case ENOTBLK: /* Block device required */ +#endif + case EBUSY: /* Device or resource busy */ + case EXDEV: /* Cross-device link */ + case ENODEV: /* No such device */ + case ENOTDIR: /* Not a directory */ + case EISDIR: /* Is a directory */ + case ENFILE: /* File table overflow */ + case EMFILE: /* Too many open files */ + case ENOTTY: /* Not a typewriter */ +#ifndef _WIN32 + case ETXTBSY: /* Text file busy */ +#endif + case ESPIPE: /* Illegal seek */ + case EROFS: /* Read-only file system */ + case EMLINK: /* Too many links */ + case EPIPE: /* Broken pipe */ + + case ERRNO_ERROR_STRING: + default: + status = default_status; + } + + return status; +} + +/* Remove possible quotes, and also the -gzip at the end + * Remove "-gzip" at the end (cf. https://github.comowncloud/client/issues/1195) + * The caller must take ownership of the resulting string. + */ +char *csync_normalize_etag(const char *etag) +{ + int len = 0; + char *buf = NULL; + if (!etag) + return NULL; + + len = strlen(etag); + /* strip "XXXX-gzip" */ + if(len >= 7 && etag[0] == '"' && c_streq(etag + len - 6, "-gzip\"")) { + etag++; + len -= 7; + } + /* strip leading -gzip */ + if(len >= 5 && c_streq(etag + len - 5, "-gzip")) { + len -= 5; + } + /* strip normal quotes */ + if (etag[0] == '"' && etag[len-1] == '"') { + etag++; + len -= 2; + } + + buf = c_malloc( len+1 ); + strncpy( buf, etag, len ); + buf[len] = '\0'; + return buf; +} + diff --git a/src/csync/csync_misc.h b/src/csync/csync_misc.h new file mode 100644 index 000000000..6b9f98418 --- /dev/null +++ b/src/csync/csync_misc.h @@ -0,0 +1,51 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2012-2013 by Klaas Freitag + * + * 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_MISC_H +#define _CSYNC_MISC_H + +#include +#include + +#ifdef HAVE_FNMATCH +#include +#else +/* Steal this define to make csync_exclude compile. Note that if fnmatch + * is not defined it's probably Win32 which uses a different implementation + * than fmmatch anyway, which does not care for flags. + **/ +#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ +#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#endif + +int csync_fnmatch(const char *pattern, const char *name, int flags); + +/** + * @brief csync_errno_to_status - errno to csync status code + * + * This function tries to convert the value of the current set errno + * to a csync status code. + * + * @return the corresponding csync error code. + */ +CSYNC_STATUS csync_errno_to_status(int error, CSYNC_STATUS default_status); + +#endif /* _CSYNC_MISC_H */ diff --git a/src/csync/csync_private.h b/src/csync/csync_private.h new file mode 100644 index 000000000..2edc26019 --- /dev/null +++ b/src/csync/csync_private.h @@ -0,0 +1,215 @@ +/* + * cynapses libc functions + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2012-2013 by Klaas Freitag + * + * 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 csync_private.h + * + * @brief Private interface of csync + * + * @defgroup csyncInternalAPI csync internal API + * + * @{ + */ + +#ifndef _CSYNC_PRIVATE_H +#define _CSYNC_PRIVATE_H + +#include +#include +#include + +#include "config_csync.h" +#include "std/c_lib.h" +#include "std/c_private.h" +#include "csync.h" +#include "csync_misc.h" + +#include "csync_macros.h" + +/** + * How deep to scan directories. + */ +#define MAX_DEPTH 100 + +#define CSYNC_STATUS_INIT 1 << 0 +#define CSYNC_STATUS_UPDATE 1 << 1 +#define CSYNC_STATUS_RECONCILE 1 << 2 +#define CSYNC_STATUS_PROPAGATE 1 << 3 + +#define CSYNC_STATUS_DONE (CSYNC_STATUS_INIT | \ + CSYNC_STATUS_UPDATE | \ + CSYNC_STATUS_RECONCILE | \ + CSYNC_STATUS_PROPAGATE) + +enum csync_replica_e { + LOCAL_REPLICA, + REMOTE_REPLICA +}; + +typedef struct csync_file_stat_s csync_file_stat_t; + +/** + * @brief csync public structure + */ +struct csync_s { + struct { + csync_auth_callback auth_function; + void *userdata; + csync_update_callback update_callback; + void *update_callback_userdata; + + /* hooks for checking the white list (uses the update_callback_userdata) */ + int (*checkSelectiveSyncBlackListHook)(void*, const char*); + int (*checkSelectiveSyncNewFolderHook)(void*, const char* /* path */, const char* /* remotePerm */); + + + csync_vio_opendir_hook remote_opendir_hook; + csync_vio_readdir_hook remote_readdir_hook; + csync_vio_closedir_hook remote_closedir_hook; + void *vio_userdata; + + /* hook for comparing checksums of files during discovery */ + csync_checksum_hook checksum_hook; + void *checksum_userdata; + + } callbacks; + c_strlist_t *excludes; + + struct { + char *file; + sqlite3 *db; + int exists; + + sqlite3_stmt* by_hash_stmt; + sqlite3_stmt* by_fileid_stmt; + sqlite3_stmt* by_inode_stmt; + + int lastReturnValue; + } statedb; + + struct { + char *uri; + c_rbtree_t *tree; + enum csync_replica_e type; + } local; + + struct { + c_rbtree_t *tree; + enum csync_replica_e type; + int read_from_db; + 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; + + + /* replica we are currently walking */ + enum csync_replica_e current; + + /* replica we want to work on */ + enum csync_replica_e replica; + + /* Used in the update phase so changes in the sub directories can be notified to + parent directories */ + csync_file_stat_t *current_fs; + + /* csync error code */ + enum csync_status_codes_e status_code; + + char *error_string; + + int status; + volatile int abort; + void *rename_info; + + /** + * Specify if it is allowed to read the remote tree from the DB (default to enabled) + */ + bool read_remote_from_db; + + /** + * If true, the DB is considered empty and all reads are skipped. (default is false) + * This is useful during the initial local discovery as it speeds it up significantly. + */ + bool db_is_empty; + + bool ignore_hidden_files; +}; + + +#ifdef _MSC_VER +#pragma pack(1) +#endif +struct csync_file_stat_s { + uint64_t phash; /* u64 */ + time_t modtime; /* u64 */ + int64_t size; /* u64 */ + size_t pathlen; /* u64 */ + uint64_t inode; /* u64 */ + mode_t mode; /* u32 */ + unsigned int type : 4; + unsigned int child_modified : 1; + unsigned int has_ignored_files : 1; /* specify that a directory, or child directory contains ignored files */ + + char *destpath; /* for renames */ + const char *etag; + char file_id[FILE_ID_BUF_SIZE+1]; /* the ownCloud file id is fixed width in ownCloud. */ + char *directDownloadUrl; + char *directDownloadCookies; + char remotePerm[REMOTE_PERM_BUF_SIZE+1]; + + // In the local tree, this can hold a checksum and its type if it is + // computed during discovery for some reason. + // In the remote tree, this will have the server checksum, if available. + // In both cases, the format is "SHA1:baff". + const char *checksumHeader; + + CSYNC_STATUS error_status; + + enum csync_instructions_e instruction; /* u32 */ + char path[1]; /* u8 */ +} +#if !defined(__SUNPRO_C) && !defined(_MSC_VER) +__attribute__ ((packed)) +#endif +#ifdef _MSC_VER +#pragma pack() +#endif +; + +OCSYNC_EXPORT void csync_file_stat_free(csync_file_stat_t *st); + +/* + * context for the treewalk function + */ +struct _csync_treewalk_context_s +{ + csync_treewalk_visit_func *user_visitor; + int instruction_filter; + void *userdata; +}; +typedef struct _csync_treewalk_context_s _csync_treewalk_context; + +void set_errno_from_http_errcode( int err ); + +/** + * }@ + */ +#endif /* _CSYNC_PRIVATE_H */ +/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/src/csync/csync_reconcile.c b/src/csync/csync_reconcile.c new file mode 100644 index 000000000..59156e800 --- /dev/null +++ b/src/csync/csync_reconcile.c @@ -0,0 +1,418 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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 "config_csync.h" + +#include +#include "csync_private.h" +#include "csync_reconcile.h" +#include "csync_util.h" +#include "csync_statedb.h" +#include "csync_rename.h" +#include "c_jhash.h" + +#define CSYNC_LOG_CATEGORY_NAME "csync.reconciler" +#include "csync_log.h" + +#include "inttypes.h" + +/* Check if a file is ignored because one parent is ignored. + * return the node of the ignored directoy if it's the case, or NULL if it is not ignored */ +static c_rbnode_t *_csync_check_ignored(c_rbtree_t *tree, const char *path, int pathlen) { + uint64_t h = 0; + c_rbnode_t *node = NULL; + + /* compute the size of the parent directory */ + int parentlen = pathlen - 1; + while (parentlen > 0 && path[parentlen] != '/') { + parentlen--; + } + if (parentlen <= 0) { + return NULL; + } + + h = c_jhash64((uint8_t *) path, parentlen, 0); + node = c_rbtree_find(tree, &h); + if (node) { + csync_file_stat_t *n = (csync_file_stat_t*)node->data; + if (n->instruction == CSYNC_INSTRUCTION_IGNORE) { + /* Yes, we are ignored */ + return node; + } else { + /* Not ignored */ + return NULL; + } + } else { + /* Try if the parent itself is ignored */ + return _csync_check_ignored(tree, path, parentlen); + } +} + +/* Returns true if we're reasonably certain that hash equality + * for the header means content equality. + * + * Cryptographic safety is not required - this is mainly + * intended to rule out checksums like Adler32 that are not intended for + * hashing and have high likelihood of collision with particular inputs. + */ +static bool _csync_is_collision_safe_hash(const char *checksum_header) +{ + return strncmp(checksum_header, "SHA1:", 5) == 0 + || strncmp(checksum_header, "MD5:", 4) == 0; +} + +/** + * The main function in the reconcile pass. + * + * It's called for each entry in the local and remote rbtrees by + * csync_reconcile() + * + * Before the reconcile phase the trees already know about changes + * relative to the sync journal. This function's job is to spot conflicts + * between local and remote changes and adjust the nodes accordingly. + * + * See doc/dev/sync-algorithm.md for an overview. + * + * + * Older detail comment: + * + * We merge replicas at the file level. The merged replica contains the + * superset of files that are on the local machine and server copies of + * the replica. In the case where the same file is in both the local + * and server copy, the file that was modified most recently is used. + * This means that new files are not deleted, and updated versions of + * existing files are not overwritten. + * + * When a file is updated, the merge algorithm compares the destination + * file with the the source file. If the destination file is newer + * (timestamp is newer), it is not overwritten. If both files, on the + * source and the destination, have been changed, the newer file wins. + */ +static int _csync_merge_algorithm_visitor(void *obj, void *data) { + csync_file_stat_t *cur = NULL; + csync_file_stat_t *other = NULL; + csync_file_stat_t *tmp = NULL; + uint64_t h = 0; + int len = 0; + + CSYNC *ctx = NULL; + c_rbtree_t *tree = NULL; + c_rbnode_t *node = NULL; + + cur = (csync_file_stat_t *) obj; + ctx = (CSYNC *) data; + + /* we need the opposite tree! */ + switch (ctx->current) { + case LOCAL_REPLICA: + tree = ctx->remote.tree; + break; + case REMOTE_REPLICA: + tree = ctx->local.tree; + break; + default: + break; + } + + node = c_rbtree_find(tree, &cur->phash); + + if (!node) { + /* Check the renamed path as well. */ + char *renamed_path = csync_rename_adjust_path(ctx, cur->path); + if (!c_streq(renamed_path, cur->path)) { + len = strlen( renamed_path ); + h = c_jhash64((uint8_t *) renamed_path, len, 0); + node = c_rbtree_find(tree, &h); + } + SAFE_FREE(renamed_path); + } + if (!node) { + /* Check if it is ignored */ + node = _csync_check_ignored(tree, cur->path, cur->pathlen); + /* If it is ignored, other->instruction will be IGNORE so this one will also be ignored */ + } + + /* file only found on current replica */ + if (node == NULL) { + switch(cur->instruction) { + /* file has been modified */ + case CSYNC_INSTRUCTION_EVAL: + cur->instruction = CSYNC_INSTRUCTION_NEW; + break; + /* file has been removed on the opposite replica */ + case CSYNC_INSTRUCTION_NONE: + case CSYNC_INSTRUCTION_UPDATE_METADATA: + if (cur->has_ignored_files) { + /* Do not remove a directory that has ignored files */ + break; + } + if (cur->child_modified) { + /* re-create directory that has modified contents */ + cur->instruction = CSYNC_INSTRUCTION_NEW; + break; + } + cur->instruction = CSYNC_INSTRUCTION_REMOVE; + break; + case CSYNC_INSTRUCTION_EVAL_RENAME: + if(ctx->current == LOCAL_REPLICA ) { + /* use the old name to find the "other" node */ + tmp = csync_statedb_get_stat_by_inode(ctx, cur->inode); + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Finding opposite temp through inode %" PRIu64 ": %s", + cur->inode, tmp ? "true":"false"); + } else if( ctx->current == REMOTE_REPLICA ) { + tmp = csync_statedb_get_stat_by_file_id(ctx, cur->file_id); + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Finding opposite temp through file ID %s: %s", + cur->file_id, tmp ? "true":"false"); + } else { + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Unknown replica..."); + } + + if( tmp ) { + len = strlen( tmp->path ); + if( len > 0 ) { + h = c_jhash64((uint8_t *) tmp->path, len, 0); + /* First, check that the file is NOT in our tree (another file with the same name was added) */ + node = c_rbtree_find(ctx->current == REMOTE_REPLICA ? ctx->remote.tree : ctx->local.tree, &h); + if (node) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Origin found in our tree : %s", tmp->path); + } else { + /* Find the temporar file in the other tree. */ + node = c_rbtree_find(tree, &h); + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "PHash of temporary opposite (%s): %" PRIu64 " %s", + tmp->path , h, node ? "found": "not found" ); + if (node) { + other = (csync_file_stat_t*)node->data; + } else { + /* the renamed file could not be found in the opposite tree. That is because it + * is not longer existing there, maybe because it was renamed or deleted. + * The journal is cleaned up later after propagation. + */ + } + } + } + + if(!other) { + cur->instruction = CSYNC_INSTRUCTION_NEW; + } else if (other->instruction == CSYNC_INSTRUCTION_NONE + || other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA + || cur->type == CSYNC_FTW_TYPE_DIR) { + other->instruction = CSYNC_INSTRUCTION_RENAME; + other->destpath = c_strdup( cur->path ); + if( !c_streq(cur->file_id, "") ) { + csync_vio_set_file_id( other->file_id, cur->file_id ); + } + other->inode = cur->inode; + cur->instruction = CSYNC_INSTRUCTION_NONE; + } else if (other->instruction == CSYNC_INSTRUCTION_REMOVE) { + other->instruction = CSYNC_INSTRUCTION_RENAME; + other->destpath = c_strdup( cur->path ); + + if( !c_streq(cur->file_id, "") ) { + csync_vio_set_file_id( other->file_id, cur->file_id ); + } + other->inode = cur->inode; + cur->instruction = CSYNC_INSTRUCTION_NONE; + } else if (other->instruction == CSYNC_INSTRUCTION_NEW) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "OOOO=> NEW detected in other tree!"); + cur->instruction = CSYNC_INSTRUCTION_CONFLICT; + } else { + assert(other->type != CSYNC_FTW_TYPE_DIR); + cur->instruction = CSYNC_INSTRUCTION_NONE; + other->instruction = CSYNC_INSTRUCTION_SYNC; + } + csync_file_stat_free(tmp); + } + + break; + default: + break; + } + } else { + bool is_conflict = true; + /* + * file found on the other replica + */ + other = (csync_file_stat_t *) node->data; + + switch (cur->instruction) { + case CSYNC_INSTRUCTION_UPDATE_METADATA: + if (other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA && ctx->current == LOCAL_REPLICA) { + // Remote wins, the SyncEngine will pick relevant local metadata since the remote tree is walked last. + cur->instruction = CSYNC_INSTRUCTION_NONE; + } + break; + case CSYNC_INSTRUCTION_EVAL_RENAME: + /* If the file already exist on the other side, we have a conflict. + Abort the rename and consider it is a new file. */ + cur->instruction = CSYNC_INSTRUCTION_NEW; + /* fall trough */ + /* file on current replica is changed or new */ + case CSYNC_INSTRUCTION_EVAL: + case CSYNC_INSTRUCTION_NEW: + // This operation is usually a no-op and will by default return false + if (csync_file_locked_or_open(ctx->local.uri, cur->path)) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "[Reconciler] IGNORING file %s/%s since it is locked / open", ctx->local.uri, cur->path); + cur->instruction = CSYNC_INSTRUCTION_ERROR; + if (cur->error_status == CSYNC_STATUS_OK) // don't overwrite error + cur->error_status = CYSNC_STATUS_FILE_LOCKED_OR_OPEN; + break; + } else { + //CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "[Reconciler] not ignoring file %s/%s", ctx->local.uri, cur->path); + } + switch (other->instruction) { + /* file on other replica is changed or new */ + case CSYNC_INSTRUCTION_NEW: + case CSYNC_INSTRUCTION_EVAL: + if (other->type == CSYNC_FTW_TYPE_DIR && + cur->type == CSYNC_FTW_TYPE_DIR) { + // Folders of the same path are always considered equals + is_conflict = false; + } else { + // If the size or mtime is different, it's definitely a conflict. + is_conflict = ((other->size != cur->size) || (other->modtime != cur->modtime)); + + // It could be a conflict even if size and mtime match! + // + // In older client versions we always treated these cases as a + // non-conflict. This behavior is preserved in case the server + // doesn't provide a suitable content hash. + // + // When it does have one, however, we do create a job, but the job + // will compare hashes and avoid the download if they are equal. + const char *remoteChecksumHeader = + (ctx->current == REMOTE_REPLICA ? cur->checksumHeader : other->checksumHeader); + if (remoteChecksumHeader) { + is_conflict |= _csync_is_collision_safe_hash(remoteChecksumHeader); + } + + // SO: If there is no checksum, we can have !is_conflict here + // even though the files have different content! This is an + // intentional tradeoff. Downloading and comparing files would + // be technically correct in this situation but leads to too + // much waste. + // In particular this kind of NEW/NEW situation with identical + // sizes and mtimes pops up when the local database is lost for + // whatever reason. + } + if (ctx->current == REMOTE_REPLICA) { + // If the files are considered equal, only update the DB with the etag from remote + cur->instruction = is_conflict ? CSYNC_INSTRUCTION_CONFLICT : CSYNC_INSTRUCTION_UPDATE_METADATA; + other->instruction = CSYNC_INSTRUCTION_NONE; + } else { + cur->instruction = CSYNC_INSTRUCTION_NONE; + other->instruction = is_conflict ? CSYNC_INSTRUCTION_CONFLICT : CSYNC_INSTRUCTION_UPDATE_METADATA; + } + + break; + /* file on the other replica has not been modified */ + case CSYNC_INSTRUCTION_NONE: + case CSYNC_INSTRUCTION_UPDATE_METADATA: + if (cur->type != other->type) { + // If the type of the entity changed, it's like NEW, but + // needs to delete the other entity first. + cur->instruction = CSYNC_INSTRUCTION_TYPE_CHANGE; + other->instruction = CSYNC_INSTRUCTION_NONE; + } else if (cur->type == CSYNC_FTW_TYPE_DIR) { + cur->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; + other->instruction = CSYNC_INSTRUCTION_NONE; + } else { + cur->instruction = CSYNC_INSTRUCTION_SYNC; + other->instruction = CSYNC_INSTRUCTION_NONE; + } + break; + case CSYNC_INSTRUCTION_IGNORE: + cur->instruction = CSYNC_INSTRUCTION_IGNORE; + break; + default: + break; + } + default: + break; + } + } + + //hide instruction NONE messages when log level is set to debug, + //only show these messages on log level trace + const char *repo = ctx->current == REMOTE_REPLICA ? "server" : "client"; + if(cur->instruction ==CSYNC_INSTRUCTION_NONE) + { + if(cur->type == CSYNC_FTW_TYPE_DIR) + { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, + "%-30s %s dir: %s", + csync_instruction_str(cur->instruction), + repo, + cur->path); + } + else + { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, + "%-30s %s file: %s", + csync_instruction_str(cur->instruction), + repo, + cur->path); + } + } + else + { + if(cur->type == CSYNC_FTW_TYPE_DIR) + { + CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, + "%-30s %s dir: %s", + csync_instruction_str(cur->instruction), + repo, + cur->path); + } + else + { + CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, + "%-30s %s file: %s", + csync_instruction_str(cur->instruction), + repo, + cur->path); + } + } + + return 0; +} + +int csync_reconcile_updates(CSYNC *ctx) { + int rc; + c_rbtree_t *tree = NULL; + + switch (ctx->current) { + case LOCAL_REPLICA: + tree = ctx->local.tree; + break; + case REMOTE_REPLICA: + tree = ctx->remote.tree; + break; + default: + break; + } + + rc = c_rbtree_walk(tree, (void *) ctx, _csync_merge_algorithm_visitor); + if( rc < 0 ) { + ctx->status_code = CSYNC_STATUS_RECONCILE_ERROR; + } + return rc; +} + +/* vim: set ts=8 sw=2 et cindent: */ diff --git a/src/csync/csync_reconcile.h b/src/csync/csync_reconcile.h new file mode 100644 index 000000000..f333adba6 --- /dev/null +++ b/src/csync/csync_reconcile.h @@ -0,0 +1,60 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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_RECONCILE_H +#define _CSYNC_RECONCILE_H + +/** + * @file csync_reconcile.h + * + * @brief Reconciliation + * + * The most important component is the update detector, because the reconciler + * depends on it. The correctness of reconciler is mandatory because it can + * damage a filesystem. It decides which file: + * + * - stays untouched + * - has a conflict + * - gets synchronized + * - or is deleted. + * + * @defgroup csyncReconcilationInternals csync reconciliation internals + * @ingroup csyncInternalAPI + * + * @{ + */ + +/** + * @brief Reconcile the files. + * + * @param ctx The csync context to use. + * + * @return 0 on success, < 0 on error. + * + * @todo Add an argument to set the algorithm to use. + */ +int OCSYNC_EXPORT csync_reconcile_updates(CSYNC *ctx); + +/** + * }@ + */ +#endif /* _CSYNC_RECONCILE_H */ + +/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/src/csync/csync_rename.cc b/src/csync/csync_rename.cc new file mode 100644 index 000000000..5cc43ce22 --- /dev/null +++ b/src/csync/csync_rename.cc @@ -0,0 +1,102 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2012 by Olivier Goffart + * + * 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 + */ + +extern "C" { +#include "csync_private.h" +#include "csync_rename.h" +} + +#include +#include +#include +#include + +static std::string _parentDir(const std::string &path) { + int len = path.length(); + while(len > 0 && path[len-1]!='/') len--; + while(len > 0 && path[len-1]=='/') len--; + return path.substr(0, len); +} + +struct csync_rename_s { + static csync_rename_s *get(CSYNC *ctx) { + if (!ctx->rename_info) { + ctx->rename_info = new csync_rename_s; + } + return reinterpret_cast(ctx->rename_info); + } + + std::map folder_renamed_to; // map from->to + std::map folder_renamed_from; // map to->from + + struct renameop { + csync_file_stat_t *st; + bool operator<(const renameop &other) const { + return strlen(st->destpath) < strlen(other.st->destpath); + } + }; + std::vector todo; +}; + +extern "C" { +void csync_rename_destroy(CSYNC* ctx) +{ + delete reinterpret_cast(ctx->rename_info); + ctx->rename_info = 0; +} + +void csync_rename_record(CSYNC* ctx, const char* from, const char* to) +{ + csync_rename_s::get(ctx)->folder_renamed_to[from] = to; + csync_rename_s::get(ctx)->folder_renamed_from[to] = from; +} + +char* csync_rename_adjust_path(CSYNC* ctx, const char* path) +{ + csync_rename_s* d = csync_rename_s::get(ctx); + for (std::string p = _parentDir(path); !p.empty(); p = _parentDir(p)) { + std::map< std::string, std::string >::iterator it = d->folder_renamed_to.find(p); + if (it != d->folder_renamed_to.end()) { + std::string rep = it->second + (path + p.length()); + return c_strdup(rep.c_str()); + } + } + return c_strdup(path); +} + +char* csync_rename_adjust_path_source(CSYNC* ctx, const char* path) +{ + csync_rename_s* d = csync_rename_s::get(ctx); + for (std::string p = _parentDir(path); !p.empty(); p = _parentDir(p)) { + std::map< std::string, std::string >::iterator it = d->folder_renamed_from.find(p); + if (it != d->folder_renamed_from.end()) { + std::string rep = it->second + (path + p.length()); + return c_strdup(rep.c_str()); + } + } + return c_strdup(path); +} + +bool csync_rename_count(CSYNC *ctx) { + csync_rename_s* d = csync_rename_s::get(ctx); + return d->folder_renamed_from.size(); +} + +} diff --git a/src/csync/csync_rename.h b/src/csync/csync_rename.h new file mode 100644 index 000000000..53968324c --- /dev/null +++ b/src/csync/csync_rename.h @@ -0,0 +1,40 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2012 by Olivier Goffart + * + * 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 + */ + +#pragma once + +#include "csync.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Return the final destination path of a given patch in case of renames */ +char OCSYNC_EXPORT *csync_rename_adjust_path(CSYNC *ctx, const char *path); +/* Return the source of a given path in case of renames */ +char OCSYNC_EXPORT *csync_rename_adjust_path_source(CSYNC *ctx, const char *path); +void OCSYNC_EXPORT csync_rename_destroy(CSYNC *ctx); +void OCSYNC_EXPORT csync_rename_record(CSYNC *ctx, const char *from, const char *to); +/* Return the amount of renamed item recorded */ +bool OCSYNC_EXPORT csync_rename_count(CSYNC *ctx); + +#ifdef __cplusplus +} +#endif diff --git a/src/csync/csync_statedb.c b/src/csync/csync_statedb.c new file mode 100644 index 000000000..056ca48dd --- /dev/null +++ b/src/csync/csync_statedb.c @@ -0,0 +1,656 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2012-2013 by Klaas Freitag + * + * 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 "config_csync.h" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "c_lib.h" +#include "csync_private.h" +#include "csync_statedb.h" +#include "csync_util.h" +#include "csync_misc.h" +#include "csync_exclude.h" + +#include "c_string.h" +#include "c_jhash.h" +#include "csync_time.h" + +#define CSYNC_LOG_CATEGORY_NAME "csync.statedb" +#include "csync_log.h" +#include "csync_rename.h" + +#define BUF_SIZE 16 + +#define sqlite_open(A, B) sqlite3_open_v2(A,B, SQLITE_OPEN_READONLY+SQLITE_OPEN_NOMUTEX, NULL) + +#define SQLTM_TIME 150 +#define SQLTM_COUNT 10 + +#define SQLITE_BUSY_HANDLED(F) if(1) { \ + int n = 0; \ + do { rc = F ; \ + if( (rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED) ) { \ + n++; \ + csync_sleep(SQLTM_TIME); \ + } \ + }while( (n < SQLTM_COUNT) && ((rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED))); \ + } + + +void csync_set_statedb_exists(CSYNC *ctx, int val) { + ctx->statedb.exists = val; +} + +int csync_get_statedb_exists(CSYNC *ctx) { + return ctx->statedb.exists; +} + +static int _csync_check_db_integrity(sqlite3 *db) { + c_strlist_t *result = NULL; + int rc = -1; + + result = csync_statedb_query(db, "PRAGMA quick_check;"); + if (result != NULL) { + /* There is a result */ + if (result->count > 0) { + if (c_streq(result->vector[0], "ok")) { + rc = 0; + } + } + c_strlist_destroy(result); + } + + if( sqlite3_threadsafe() == 0 ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "* WARNING: SQLite module is not threadsafe!"); + rc = -1; + } + + return rc; +} + +static int _csync_statedb_is_empty(sqlite3 *db) { + c_strlist_t *result = NULL; + int rc = 0; + + result = csync_statedb_query(db, "SELECT COUNT(phash) FROM metadata LIMIT 1 OFFSET 0;"); + if (result == NULL) { + rc = 1; + } + c_strlist_destroy(result); + + return rc; +} + +#ifndef NDEBUG +static void sqlite_profile( void *x, const char* sql, sqlite3_uint64 time) +{ + (void)x; + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, + "_SQL_ %s: %llu", sql, time); + +} +#endif + +int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb) { + int rc = -1; + c_strlist_t *result = NULL; + sqlite3 *db = NULL; + + if( !ctx ) { + return -1; + } + + if (ctx->statedb.db) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: DB already open"); + ctx->status_code = CSYNC_STATUS_PARAM_ERROR; + return -1; + } + + ctx->statedb.lastReturnValue = SQLITE_OK; + + /* Openthe database */ + if (sqlite_open(statedb, &db) != SQLITE_OK) { + const char *errmsg= sqlite3_errmsg(ctx->statedb.db); + CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: Failed to sqlite3 open statedb - bail out: %s.", + errmsg ? errmsg : ""); + + rc = -1; + ctx->status_code = CSYNC_STATUS_STATEDB_LOAD_ERROR; + goto out; + } + + if (_csync_check_db_integrity(db) != 0) { + const char *errmsg= sqlite3_errmsg(db); + CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: sqlite3 integrity check failed - bail out: %s.", + errmsg ? errmsg : ""); + rc = -1; + ctx->status_code = CSYNC_STATUS_STATEDB_CORRUPTED; + goto out; + } + + if (_csync_statedb_is_empty(db)) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "statedb contents doesn't exist"); + csync_set_statedb_exists(ctx, 0); + } else { + csync_set_statedb_exists(ctx, 1); + } + + /* Print out the version */ + // + result = csync_statedb_query(db, "SELECT sqlite_version();"); + if (result && result->count >= 1) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3 version \"%s\"", *result->vector); + } + c_strlist_destroy(result); + + /* optimization for speeding up SQLite */ + result = csync_statedb_query(db, "PRAGMA synchronous = NORMAL;"); + c_strlist_destroy(result); + result = csync_statedb_query(db, "PRAGMA case_sensitive_like = ON;"); + c_strlist_destroy(result); + + /* set a busy handler with 5 seconds timeout */ + sqlite3_busy_timeout(db, 5000); + +#ifndef NDEBUG + sqlite3_profile(db, sqlite_profile, 0 ); +#endif + *pdb = db; + + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Success"); + + return 0; +out: + sqlite3_close(db); + return rc; +} + +int csync_statedb_close(CSYNC *ctx) { + int rc = 0; + + if (!ctx) { + return -1; + } + + /* deallocate query resources */ + if( ctx->statedb.by_fileid_stmt ) { + sqlite3_finalize(ctx->statedb.by_fileid_stmt); + ctx->statedb.by_fileid_stmt = NULL; + } + if( ctx->statedb.by_hash_stmt ) { + sqlite3_finalize(ctx->statedb.by_hash_stmt); + ctx->statedb.by_hash_stmt = NULL; + } + if( ctx->statedb.by_inode_stmt) { + sqlite3_finalize(ctx->statedb.by_inode_stmt); + ctx->statedb.by_inode_stmt = NULL; + } + + ctx->statedb.lastReturnValue = SQLITE_OK; + + int sr = sqlite3_close(ctx->statedb.db); + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3_close=%d", sr); + + ctx->statedb.db = 0; + + return rc; +} + +#define METADATA_QUERY \ + "phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, " \ + "filesize, ignoredChildrenRemote, " \ + "contentchecksumtype.name || ':' || contentChecksum " \ + "FROM metadata " \ + "LEFT JOIN checksumtype as contentchecksumtype ON metadata.contentChecksumTypeId == contentchecksumtype.id" + +// This funciton parses a line from the metadata table into the given csync_file_stat +// structure which it is also allocating. +// Note that this function calls laso sqlite3_step to actually get the info from db and +// returns the sqlite return type. +static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3_stmt *stmt ) +{ + int rc = SQLITE_ERROR; + int column_count; + int len; + + if( ! stmt ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Fatal: Statement is NULL."); + return SQLITE_ERROR; + } + + column_count = sqlite3_column_count(stmt); + + SQLITE_BUSY_HANDLED( sqlite3_step(stmt) ); + + if( rc == SQLITE_ROW ) { + if(column_count > 7) { + const char *name; + + /* phash, pathlen, path, inode, uid, gid, mode, modtime */ + len = sqlite3_column_int(stmt, 1); + *st = c_malloc(sizeof(csync_file_stat_t) + len + 1); + /* clear the whole structure */ + ZERO_STRUCTP(*st); + + /* The query suceeded so use the phash we pass to the function. */ + (*st)->phash = sqlite3_column_int64(stmt, 0); + + (*st)->pathlen = sqlite3_column_int(stmt, 1); + name = (const char*) sqlite3_column_text(stmt, 2); + memcpy((*st)->path, (len ? name : ""), len + 1); + (*st)->inode = sqlite3_column_int64(stmt,3); + (*st)->mode = sqlite3_column_int(stmt, 6); + (*st)->modtime = strtoul((char*)sqlite3_column_text(stmt, 7), NULL, 10); + + if(*st && column_count > 8 ) { + (*st)->type = sqlite3_column_int(stmt, 8); + } + + if(column_count > 9 && sqlite3_column_text(stmt, 9)) { + (*st)->etag = c_strdup( (char*) sqlite3_column_text(stmt, 9) ); + } + 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); + } + if(column_count > 12 && sqlite3_column_int64(stmt,12)) { + (*st)->size = sqlite3_column_int64(stmt, 12); + } + if(column_count > 13) { + (*st)->has_ignored_files = sqlite3_column_int(stmt, 13); + } + if (column_count > 14 && sqlite3_column_text(stmt, 14)) { + (*st)->checksumHeader = c_strdup((char *)sqlite3_column_text(stmt, 14)); + } + + } + } else { + if( rc != SQLITE_DONE ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Query results in %d", rc); + } + } + return rc; +} + +/* caller must free the memory */ +csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx, + uint64_t phash) +{ + csync_file_stat_t *st = NULL; + int rc; + + if( !ctx || ctx->db_is_empty ) { + return NULL; + } + + if( ctx->statedb.by_hash_stmt == NULL ) { + const char *hash_query = "SELECT " METADATA_QUERY " WHERE phash=?1"; + + SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, hash_query, strlen(hash_query), &ctx->statedb.by_hash_stmt, NULL)); + ctx->statedb.lastReturnValue = rc; + if( rc != SQLITE_OK ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for hash query."); + return NULL; + } + } + + if( ctx->statedb.by_hash_stmt == NULL ) { + return NULL; + } + + sqlite3_bind_int64(ctx->statedb.by_hash_stmt, 1, (long long signed int)phash); + + rc = _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_hash_stmt); + ctx->statedb.lastReturnValue = rc; + if( !(rc == SQLITE_ROW || rc == SQLITE_DONE) ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata: %d!", rc); + } + sqlite3_reset(ctx->statedb.by_hash_stmt); + + return st; +} + +csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx, + const char *file_id ) { + csync_file_stat_t *st = NULL; + int rc = 0; + + if (!file_id) { + return 0; + } + if (c_streq(file_id, "")) { + return 0; + } + + if( !ctx || ctx->db_is_empty ) { + return NULL; + } + + if( ctx->statedb.by_fileid_stmt == NULL ) { + const char *query = "SELECT " METADATA_QUERY " WHERE fileid=?1"; + + SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, query, strlen(query), &ctx->statedb.by_fileid_stmt, NULL)); + ctx->statedb.lastReturnValue = rc; + if( rc != SQLITE_OK ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for file id query."); + return NULL; + } + } + + /* bind the query value */ + sqlite3_bind_text(ctx->statedb.by_fileid_stmt, 1, file_id, -1, SQLITE_STATIC); + + rc = _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_fileid_stmt); + ctx->statedb.lastReturnValue = rc; + if( !(rc == SQLITE_ROW || rc == SQLITE_DONE) ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata: %d!", rc); + } + // clear the resources used by the statement. + sqlite3_reset(ctx->statedb.by_fileid_stmt); + + return st; +} + +/* caller must free the memory */ +csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx, + uint64_t inode) +{ + csync_file_stat_t *st = NULL; + int rc; + + if (!inode) { + return NULL; + } + + if( !ctx || ctx->db_is_empty ) { + return NULL; + } + + if( ctx->statedb.by_inode_stmt == NULL ) { + const char *inode_query = "SELECT " METADATA_QUERY " WHERE inode=?1"; + + SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, inode_query, strlen(inode_query), &ctx->statedb.by_inode_stmt, NULL)); + ctx->statedb.lastReturnValue = rc; + if( rc != SQLITE_OK ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for inode query."); + return NULL; + } + } + + if( ctx->statedb.by_inode_stmt == NULL ) { + return NULL; + } + + sqlite3_bind_int64(ctx->statedb.by_inode_stmt, 1, (long long signed int)inode); + + rc = _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_inode_stmt); + ctx->statedb.lastReturnValue = rc; + if( !(rc == SQLITE_ROW || rc == SQLITE_DONE) ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata by inode: %d!", rc); + } + sqlite3_reset(ctx->statedb.by_inode_stmt); + + return st; +} + +int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) { + int rc; + sqlite3_stmt *stmt = NULL; + int64_t cnt = 0; + + if( !path ) { + return -1; + } + + if( !ctx || ctx->db_is_empty ) { + return -1; + } + + /* Select the entries for anything that starts with (path+'/') + * In other words, anything that is between path+'/' and path+'0', + * (because '0' follows '/' in ascii) + */ + const char *below_path_query = "SELECT " METADATA_QUERY " WHERE path > (?||'/') AND path < (?||'0') ORDER BY path||'/' ASC"; + SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, below_path_query, -1, &stmt, NULL)); + ctx->statedb.lastReturnValue = rc; + if( rc != SQLITE_OK ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for below path query."); + return -1; + } + + if (stmt == NULL) { + return -1; + } + + sqlite3_bind_text(stmt, 1, path, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, path, -1, SQLITE_STATIC); + + cnt = 0; + + ctx->statedb.lastReturnValue = rc; + do { + csync_file_stat_t *st = NULL; + + rc = _csync_file_stat_from_metadata_table( &st, stmt); + if( st ) { + /* When selective sync is used, the database may have subtrees with a parent + * whose etag (md5) is _invalid_. These are ignored and shall not appear in the + * remote tree. + * Sometimes folders that are not ignored by selective sync get marked as + * _invalid_, but that is not a problem as the next discovery will retrieve + * their correct etags again and we don't run into this case. + */ + if( c_streq(st->etag, "_invalid_") ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s selective sync excluded", st->path); + char *skipbase = c_strdup(st->path); + skipbase[st->pathlen] = '/'; + int skiplen = st->pathlen + 1; + + /* Skip over all entries with the same base path. Note that this depends + * strongly on the ordering of the retrieved items. */ + do { + csync_file_stat_free(st); + rc = _csync_file_stat_from_metadata_table( &st, stmt); + if( st && strncmp(st->path, skipbase, skiplen) != 0 ) { + break; + } + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s selective sync excluded because the parent is", st->path); + } while( rc == SQLITE_ROW ); + + /* End of data? */ + if( rc != SQLITE_ROW || !st ) { + continue; + } + } + + /* Check for exclusion from the tree. + * Note that this is only a safety net in case the ignore list changes + * without a full remote discovery being triggered. */ + CSYNC_EXCLUDE_TYPE excluded = csync_excluded_traversal(ctx->excludes, st->path, st->type); + if (excluded != CSYNC_NOT_EXCLUDED) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded (%d)", st->path, excluded); + + if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE + || excluded == CSYNC_FILE_SILENTLY_EXCLUDED) { + csync_file_stat_free(st); + continue; + } + + st->instruction = CSYNC_INSTRUCTION_IGNORE; + } + + /* store into result list. */ + if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) { + csync_file_stat_free(st); + ctx->status_code = CSYNC_STATUS_TREE_ERROR; + break; + } + cnt++; + } + } while( rc == SQLITE_ROW ); + + ctx->statedb.lastReturnValue = rc; + if( rc != SQLITE_DONE ) { + ctx->status_code = CSYNC_STATUS_TREE_ERROR; + } else { + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "%" PRId64 " entries read below path %s from db.", cnt, path); + } + sqlite3_finalize(stmt); + + return 0; +} + +/* query the statedb, caller must free the memory */ +c_strlist_t *csync_statedb_query(sqlite3 *db, + const char *statement) { + int err = SQLITE_OK; + int rc = SQLITE_OK; + size_t i = 0; + size_t busy_count = 0; + size_t retry_count = 0; + size_t column_count = 0; + sqlite3_stmt *stmt; + const char *tail = NULL; + const char *field = NULL; + c_strlist_t *result = NULL; + int row = 0; + + do { + /* compile SQL program into a virtual machine, reattempteing if busy */ + do { + if (busy_count) { + csync_sleep(100); + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3_prepare: BUSY counter: %zu", busy_count); + } + err = sqlite3_prepare(db, statement, -1, &stmt, &tail); + } while (err == SQLITE_BUSY && busy_count ++ < 120); + + if (err != SQLITE_OK) { + if (err == SQLITE_BUSY) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Gave up waiting for lock to clear"); + } + CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, + "sqlite3_compile error: %s - on query %s", + sqlite3_errmsg(db), statement); + break; + } else { + busy_count = 0; + column_count = sqlite3_column_count(stmt); + + /* execute virtual machine by iterating over rows */ + for(;;) { + err = sqlite3_step(stmt); + + if (err == SQLITE_BUSY) { + if (busy_count++ > 120) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Busy counter has reached its maximum. Aborting this sql statement"); + break; + } + csync_sleep(100); + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "sqlite3_step: BUSY counter: %zu", busy_count); + continue; + } + + if (err == SQLITE_MISUSE) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite3_step: MISUSE!!"); + } + + if (err == SQLITE_DONE) { + if (result == NULL) { + result = c_strlist_new(1); + } + break; + } + + if (err == SQLITE_ERROR) { + break; + } + + row++; + if( result ) { + result = c_strlist_expand(result, row*column_count); + } else { + result = c_strlist_new(column_count); + } + + if (result == NULL) { + return NULL; + } + + /* iterate over columns */ + for (i = 0; i < column_count; i++) { + field = (const char *) sqlite3_column_text(stmt, i); + if (!field) + field = ""; + // CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "sqlite3_column_text: %s", field); + if (c_strlist_add(result, field) < 0) { + c_strlist_destroy(result); + return NULL; + } + } + } /* end infinite for loop */ + + /* deallocate vm resources */ + rc = sqlite3_finalize(stmt); + + if (err != SQLITE_DONE && rc != SQLITE_SCHEMA) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite_step error: %s - on query: %s", sqlite3_errmsg(db), statement); + if (result != NULL) { + c_strlist_destroy(result); + } + return NULL; + } + + if (rc == SQLITE_SCHEMA) { + retry_count ++; + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "SQLITE_SCHEMA error occurred on query: %s", statement); + if (retry_count < 10) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Retrying now."); + } else { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "RETRY count has reached its maximum. Aborting statement: %s", statement); + if (result != NULL) { + c_strlist_destroy(result); + } + result = c_strlist_new(1); + } + } + } + } while (rc == SQLITE_SCHEMA && retry_count < 10); + + return result; +} + +/* vim: set ts=8 sw=2 et cindent: */ diff --git a/src/csync/csync_statedb.h b/src/csync/csync_statedb.h new file mode 100644 index 000000000..601e34a1b --- /dev/null +++ b/src/csync/csync_statedb.h @@ -0,0 +1,107 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2012-2013 by Klaas Freitag + * + * 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 csync_private.h + * + * @brief Private interface of csync + * + * @defgroup csyncstatedbInternals csync statedb internals + * @ingroup csyncInternalAPI + * + * @{ + */ + +#ifndef _CSYNC_STATEDB_H +#define _CSYNC_STATEDB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "c_lib.h" +#include "csync_private.h" + +void csync_set_statedb_exists(CSYNC *ctx, int val); + +int csync_get_statedb_exists(CSYNC *ctx); + +/** + * @brief Load the statedb. + * + * This function tries to load the statedb. If it doesn't exists it creates + * the sqlite3 database, but doesn't create the tables. This will be done when + * csync gets destroyed. + * + * @param ctx The csync context. + * @param statedb Path to the statedb file (sqlite3 db). + * + * @return 0 on success, less than 0 if an error occurred with errno set. + */ +OCSYNC_EXPORT int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb); + +OCSYNC_EXPORT int csync_statedb_close(CSYNC *ctx); + +OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx, uint64_t phash); + +OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx, uint64_t inode); + +OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx, const char *file_id); + +/** + * @brief Query all files metadata inside and below a path. + * @param ctx The csync context. + * @param path The path. + * + * This function queries all metadata of all files inside or below the + * given path. The result is a linear string list with a multiple of 9 + * entries. For each result file there are 9 strings which are phash, + * path, inode, uid, gid, mode, modtime, type and md5 (unique id). + * + * Note that not only the files in the given path are part of the result + * but also the files in directories below the given path. Ie. if the + * parameter path is /home/kf/test, we have /home/kf/test/file.txt in + * the result but also /home/kf/test/homework/another_file.txt + * + * @return A stringlist containing a multiple of 9 entries. + */ +int csync_statedb_get_below_path(CSYNC *ctx, const char *path); + +/** + * @brief A generic statedb query. + * + * @param ctx The csync context. + * @param statement The SQL statement to execute + * + * @return A stringlist of the entries of a column. An emtpy stringlist if + * nothing has been found. NULL on error. + */ +c_strlist_t *csync_statedb_query(sqlite3 *db, const char *statement); + +#ifdef __cplusplus +} +#endif + +/** + * }@ + */ +#endif /* _CSYNC_STATEDB_H */ +/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/src/csync/csync_time.c b/src/csync/csync_time.c new file mode 100644 index 000000000..85bdd5ff4 --- /dev/null +++ b/src/csync/csync_time.c @@ -0,0 +1,83 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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 "config_csync.h" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include + +#include "csync_time.h" +#include "vio/csync_vio.h" + +#ifndef _WIN32 +#include +#include +#endif + +#define CSYNC_LOG_CATEGORY_NAME "csync.time" +#include "csync_log.h" + +#ifdef HAVE_CLOCK_GETTIME +# ifdef _POSIX_MONOTONIC_CLOCK +# define CSYNC_CLOCK CLOCK_MONOTONIC +# else +# define CSYNC_CLOCK CLOCK_REALTIME +# endif +#endif + + +int csync_gettime(struct timespec *tp) +{ +#if defined(_WIN32) + __int64 wintime; + GetSystemTimeAsFileTime((FILETIME*)&wintime); + wintime -= 116444736000000000ll; //1jan1601 to 1jan1970 + tp->tv_sec = wintime / 10000000ll; //seconds + tp->tv_nsec = wintime % 10000000ll * 100; //nano-seconds +#elif defined(HAVE_CLOCK_GETTIME) + return clock_gettime(CSYNC_CLOCK, tp); +#else + struct timeval tv; + + if (gettimeofday(&tv, NULL) < 0) { + return -1; + } + + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = tv.tv_usec * 1000; +#endif + return 0; +} + +#undef CSYNC_CLOCK + +void csync_sleep(unsigned int msecs) +{ +#if defined(_WIN32) + Sleep(msecs); +#else + usleep(msecs * 1000); +#endif +} diff --git a/src/csync/csync_time.h b/src/csync/csync_time.h new file mode 100644 index 000000000..1492bef8d --- /dev/null +++ b/src/csync/csync_time.h @@ -0,0 +1,31 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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_TIME_H +#define _CSYNC_TIME_H + +#include + +#include "csync_private.h" + +int csync_gettime(struct timespec *tp); +void csync_sleep(unsigned int msecs); + +#endif /* _CSYNC_TIME_H */ diff --git a/src/csync/csync_update.c b/src/csync/csync_update.c new file mode 100644 index 000000000..1a069442e --- /dev/null +++ b/src/csync/csync_update.c @@ -0,0 +1,862 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2012-2013 by Klaas Freitag + * + * 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 "config_csync.h" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +#include "c_lib.h" +#include "c_jhash.h" + +#include "csync_private.h" +#include "csync_exclude.h" +#include "csync_statedb.h" +#include "csync_update.h" +#include "csync_util.h" +#include "csync_misc.h" + +#include "vio/csync_vio.h" + +#define CSYNC_LOG_CATEGORY_NAME "csync.updater" +#include "csync_log.h" +#include "csync_rename.h" + +/* calculate the hash of a given uri */ +static uint64_t _hash_of_file(CSYNC *ctx, const char *file) { + const char *path; + int len; + uint64_t h = 0; + + if( ctx && file ) { + path = file; + if (ctx->current == LOCAL_REPLICA) { + if (strlen(path) <= strlen(ctx->local.uri)) { + return 0; + } + path += strlen(ctx->local.uri) + 1; + } + len = strlen(path); + h = c_jhash64((uint8_t *) path, len, 0); + } + return h; +} + +#ifdef NO_RENAME_EXTENSION +/* Return true if the two path have the same extension. false otherwise. */ +static bool _csync_sameextension(const char *p1, const char *p2) { + /* Find pointer to the extensions */ + const char *e1 = strrchr(p1, '.'); + const char *e2 = strrchr(p2, '.'); + + /* If the found extension contains a '/', it is because the . was in the folder name + * => no extensions */ + if (e1 && strchr(e1, '/')) e1 = NULL; + if (e2 && strchr(e2, '/')) e2 = NULL; + + /* If none have extension, it is the same extension */ + if (!e1 && !e2) + return true; + + /* c_streq takes care of the rest */ + return c_streq(e1, e2); +} +#endif + +static bool _last_db_return_error(CSYNC* ctx) { + return ctx->statedb.lastReturnValue != SQLITE_OK && ctx->statedb.lastReturnValue != SQLITE_DONE && ctx->statedb.lastReturnValue != SQLITE_ROW; +} + +/* + * This static method is needed because the type members of the two structs use + * different enum values. A direct comparion is not neccessarily correct. + * + * tmp is csync_file_stat_t + * fs is csync_vio_file_stat_t with this vio type: + * enum csync_vio_file_type_e { + * CSYNC_VIO_FILE_TYPE_UNKNOWN, + * CSYNC_VIO_FILE_TYPE_REGULAR, + * CSYNC_VIO_FILE_TYPE_DIRECTORY, + * CSYNC_VIO_FILE_TYPE_FIFO, + * CSYNC_VIO_FILE_TYPE_SOCKET, + * CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE, + * CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE, + * CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK + * }; + * + * csync_file_stat_t can be: + * CSYNC_FTW_TYPE_SKIP, CSYNC_FTW_TYPE_FILE + * CSYNC_FTW_TYPE_DIR, CSYNC_FTW_TYPE_SLINK + */ +static bool _csync_filetype_different( const csync_file_stat_t *tmp, const csync_vio_file_stat_t *fs) +{ + if( !(tmp && fs)) return false; + + if( tmp->type == CSYNC_FTW_TYPE_SKIP ) return true; + + if( tmp->type == CSYNC_FTW_TYPE_DIR && fs->type != CSYNC_VIO_FILE_TYPE_DIRECTORY ) + return true; + if( tmp->type == CSYNC_FTW_TYPE_FILE && fs->type != CSYNC_VIO_FILE_TYPE_REGULAR ) + return true; + if( tmp->type == CSYNC_FTW_TYPE_SLINK && fs->type != CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK ) + return true; + + return false; // both are NOT different. +} + +/* Return true if two mtime are considered equal + * We consider mtime that are one hour difference to be equal if they are one hour appart + * because on some system (FAT) the date is changing when the daylight saving is changing */ +static bool _csync_mtime_equal(time_t a, time_t b) +{ + if (a == b) + return true; + + /* 1h of difference +- 1 second because the accuracy of FAT is 2 seconds (#2438) */ + if (fabs(3600 - fabs(difftime(a, b))) < 2) + return true; + + return false; +} + +/** + * The main function of the discovery/update pass. + * + * It's called (indirectly) by csync_update(), once for each entity in the + * local filesystem and once for each entity in the server data. + * + * It has two main jobs: + * - figure out whether anything happened compared to the sync journal + * and set (primarily) the instruction flag accordingly + * - build the ctx->local.tree / ctx->remote.tree + * + * See doc/dev/sync-algorithm.md for an overview. + */ +static int _csync_detect_update(CSYNC *ctx, const char *file, + const csync_vio_file_stat_t *fs, const int type) { + uint64_t h = 0; + size_t len = 0; + size_t size = 0; + const char *path = NULL; + csync_file_stat_t *st = NULL; + csync_file_stat_t *tmp = NULL; + CSYNC_EXCLUDE_TYPE excluded; + + if ((file == NULL) || (fs == NULL)) { + errno = EINVAL; + ctx->status_code = CSYNC_STATUS_PARAM_ERROR; + return -1; + } + + path = file; + if (ctx->current == LOCAL_REPLICA) { + if (strlen(path) <= strlen(ctx->local.uri)) { + ctx->status_code = CSYNC_STATUS_PARAM_ERROR; + return -1; + } + path += strlen(ctx->local.uri) + 1; + } + + len = strlen(path); + + if (type == CSYNC_FTW_TYPE_SKIP) { + excluded =CSYNC_FILE_EXCLUDE_STAT_FAILED; + } else { + /* Check if file is excluded */ + excluded = csync_excluded_traversal(ctx->excludes, path, type); + } + + if( excluded == CSYNC_NOT_EXCLUDED ) { + /* Even if it is not excluded by a pattern, maybe it is to be ignored + * because it's a hidden file that should not be synced. + * This code should probably be in csync_exclude, but it does not have the fs parameter. + * Keep it here for now */ + if (ctx->ignore_hidden_files && (fs->flags & CSYNC_VIO_FILE_FLAGS_HIDDEN)) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file excluded because it is a hidden file: %s", path); + excluded = CSYNC_FILE_EXCLUDE_HIDDEN; + } + } else { + /* File is ignored because it's matched by a user- or system exclude pattern. */ + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded (%d)", path, excluded); + if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE) { + return 1; + } + if (excluded == CSYNC_FILE_SILENTLY_EXCLUDED) { + return 1; + } + } + + if (ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncBlackListHook) { + if (ctx->callbacks.checkSelectiveSyncBlackListHook(ctx->callbacks.update_callback_userdata, path)) { + return 1; + } + } + + h = _hash_of_file(ctx, file ); + if( h == 0 ) { + return -1; + } + size = sizeof(csync_file_stat_t) + len + 1; + + st = c_malloc(size); + + /* Set instruction by default to none */ + st->instruction = CSYNC_INSTRUCTION_NONE; + st->etag = NULL; + st->child_modified = 0; + st->has_ignored_files = 0; + if (type == CSYNC_FTW_TYPE_FILE ) { + if (fs->mtime == 0) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - mtime is zero!", path); + } + } + + if (excluded > CSYNC_NOT_EXCLUDED || type == CSYNC_FTW_TYPE_SLINK) { + st->instruction = CSYNC_INSTRUCTION_IGNORE; + if (ctx->current_fs) { + ctx->current_fs->has_ignored_files = true; + } + + goto out; + } + + /* Update detection: Check if a database entry exists. + * If not, the file is either new or has been renamed. To see if it is + * renamed, the db gets queried by the inode of the file as that one + * does not change on rename. + */ + if (csync_get_statedb_exists(ctx)) { + tmp = csync_statedb_get_stat_by_hash(ctx, h); + + if(_last_db_return_error(ctx)) { + csync_file_stat_free(st); + csync_file_stat_free(tmp); + ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL; + return -1; + } + + if(tmp && tmp->phash == h ) { /* there is an entry in the database */ + /* we have an update! */ + CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Database entry found, compare: %" PRId64 " <-> %" PRId64 + ", etag: %s <-> %s, inode: %" PRId64 " <-> %" PRId64 + ", size: %" PRId64 " <-> %" PRId64 ", perms: %s <-> %s, ignore: %d", + ((int64_t) fs->mtime), ((int64_t) tmp->modtime), + fs->etag, tmp->etag, (uint64_t) fs->inode, (uint64_t) tmp->inode, + (uint64_t) fs->size, (uint64_t) tmp->size, fs->remotePerm, tmp->remotePerm, tmp->has_ignored_files ); + if (ctx->current == REMOTE_REPLICA && !c_streq(fs->etag, tmp->etag)) { + st->instruction = CSYNC_INSTRUCTION_EVAL; + + // Preserve the EVAL flag later on if the type has changed. + if (_csync_filetype_different(tmp, fs)) { + st->child_modified = 1; + } + + goto out; + } + if (ctx->current == LOCAL_REPLICA && + (!_csync_mtime_equal(fs->mtime, tmp->modtime) + // zero size in statedb can happen during migration + || (tmp->size != 0 && fs->size != tmp->size))) { + + // Checksum comparison at this stage is only enabled for .eml files, + // check #4754 #4755 + bool isEmlFile = csync_fnmatch("*.eml", file, FNM_CASEFOLD) == 0; + if (isEmlFile && fs->size == tmp->size && tmp->checksumHeader) { + if (ctx->callbacks.checksum_hook) { + st->checksumHeader = ctx->callbacks.checksum_hook( + file, tmp->checksumHeader, + ctx->callbacks.checksum_userdata); + } + bool checksumIdentical = false; + if (st->checksumHeader) { + checksumIdentical = strncmp(st->checksumHeader, tmp->checksumHeader, 1000) == 0; + } + if (checksumIdentical) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "NOTE: Checksums are identical, file did not actually change: %s", path); + st->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; + goto out; + } + } + + // Preserve the EVAL flag later on if the type has changed. + if (_csync_filetype_different(tmp, fs)) { + st->child_modified = 1; + } + + 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 + && !metadata_differ && ctx->read_remote_from_db) { + /* If both etag and file id are equal for a directory, read all contents from + * the database. + * 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 it was remembered in the db that the remote dir has ignored files, store + * that so that the reconciler can make advantage of. + */ + if( ctx->current == REMOTE_REPLICA ) { + st->has_ignored_files = tmp->has_ignored_files; + } + 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->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; + } else { + st->instruction = CSYNC_INSTRUCTION_NONE; + } + } else { + enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN; + + /* tmp might point to malloc mem, so free it here before reusing tmp */ + csync_file_stat_free(tmp); + + /* check if it's a file and has been renamed */ + if (ctx->current == LOCAL_REPLICA) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Checking for rename based on inode # %" PRId64 "", (uint64_t) fs->inode); + + tmp = csync_statedb_get_stat_by_inode(ctx, fs->inode); + + if(_last_db_return_error(ctx)) { + csync_file_stat_free(st); + ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL; + return -1; + } + + /* translate the file type between the two stat types csync has. */ + if( tmp && tmp->type == CSYNC_FTW_TYPE_FILE ) { + tmp_vio_type = CSYNC_VIO_FILE_TYPE_REGULAR; + } else if( tmp && tmp->type == CSYNC_FTW_TYPE_DIR) { + tmp_vio_type = CSYNC_VIO_FILE_TYPE_DIRECTORY; + } else if( tmp && tmp->type == CSYNC_FTW_TYPE_SLINK ) { + tmp_vio_type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; + } else { + tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN; + } + + // Default to NEW unless we're sure it's a rename. + st->instruction = CSYNC_INSTRUCTION_NEW; + + bool isRename = + tmp && tmp->inode == fs->inode && tmp_vio_type == fs->type + && (tmp->modtime == fs->mtime || fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) +#ifdef NO_RENAME_EXTENSION + && _csync_sameextension(tmp->path, path) +#endif + ; + + + // Verify the checksum where possible + if (isRename && tmp->checksumHeader && ctx->callbacks.checksum_hook + && fs->type == CSYNC_VIO_FILE_TYPE_REGULAR) { + st->checksumHeader = ctx->callbacks.checksum_hook( + file, tmp->checksumHeader, + ctx->callbacks.checksum_userdata); + if (st->checksumHeader) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "checking checksum of potential rename %s %s <-> %s", path, st->checksumHeader, tmp->checksumHeader); + isRename = strncmp(st->checksumHeader, tmp->checksumHeader, 1000) == 0; + } + } + + if (isRename) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "pot rename detected based on inode # %" PRId64 "", (uint64_t) fs->inode); + /* inode found so the file has been renamed */ + st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME; + if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) { + csync_rename_record(ctx, tmp->path, path); + } + } + goto out; + + } else { + /* Remote Replica Rename check */ + tmp = csync_statedb_get_stat_by_file_id(ctx, fs->file_id); + + if(_last_db_return_error(ctx)) { + csync_file_stat_free(st); + ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL; + return -1; + } + if(tmp ) { /* tmp existing at all */ + if ( _csync_filetype_different(tmp, fs)) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "file types different is not!"); + st->instruction = CSYNC_INSTRUCTION_NEW; + goto out; + } + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "remote rename detected based on fileid %s %s", tmp->path, file); + st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME; + if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) { + csync_rename_record(ctx, tmp->path, path); + } else { + if( !c_streq(tmp->etag, fs->etag) ) { + /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "ETags are different!"); */ + /* File with different etag, don't do a rename, but download the file again */ + st->instruction = CSYNC_INSTRUCTION_NEW; + } + } + goto out; + + } else { + /* file not found in statedb */ + st->instruction = CSYNC_INSTRUCTION_NEW; + + if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY && ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncNewFolderHook) { + if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path, fs->remotePerm)) { + csync_file_stat_free(st); + return 1; + } + } + goto out; + } + } + } + } else { + CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Unable to open statedb" ); + csync_file_stat_free(st); + ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL; + return -1; + } + +out: + + /* Set the ignored error string. */ + if (st->instruction == CSYNC_INSTRUCTION_IGNORE) { + if( type == CSYNC_FTW_TYPE_SLINK ) { + st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK; /* Symbolic links are ignored. */ + } else { + if (excluded == CSYNC_FILE_EXCLUDE_LIST) { + st->error_status = CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST; /* File listed on ignore list. */ + } else if (excluded == CSYNC_FILE_EXCLUDE_INVALID_CHAR) { + st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS; /* File contains invalid characters. */ + } else if (excluded == CSYNC_FILE_EXCLUDE_TRAILING_SPACE) { + st->error_status = CSYNC_STATUS_INDIVIDUAL_TRAILING_SPACE; /* File ends with a trailing space. */ + } else if (excluded == CSYNC_FILE_EXCLUDE_LONG_FILENAME) { + st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME; /* File name is too long. */ + } else if (excluded == CSYNC_FILE_EXCLUDE_HIDDEN ) { + st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN; + } else if (excluded == CSYNC_FILE_EXCLUDE_STAT_FAILED) { + st->error_status = CSYNC_STATUS_INDIVIDUAL_STAT_FAILED; + } else if (excluded == CSYNC_FILE_EXCLUDE_CONFLICT) { + st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_CONFLICT_FILE; + } + } + } + if (st->instruction != CSYNC_INSTRUCTION_NONE + && st->instruction != CSYNC_INSTRUCTION_IGNORE + && st->instruction != CSYNC_INSTRUCTION_UPDATE_METADATA + && type != CSYNC_FTW_TYPE_DIR) { + st->child_modified = 1; + } + ctx->current_fs = st; + + csync_file_stat_free(tmp); + st->inode = fs->inode; + st->mode = fs->mode; + st->size = fs->size; + st->modtime = fs->mtime; + st->type = type; + st->etag = NULL; + if( fs->etag ) { + SAFE_FREE(st->etag); + 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); + } + + // For the remote: propagate the discovered checksum + if (fs->checksumHeader && ctx->current == REMOTE_REPLICA) { + st->checksumHeader = c_strdup(fs->checksumHeader); + } + + st->phash = h; + st->pathlen = len; + memcpy(st->path, (len ? path : ""), len + 1); + + switch (ctx->current) { + case LOCAL_REPLICA: + if (c_rbtree_insert(ctx->local.tree, (void *) st) < 0) { + csync_file_stat_free(st); + ctx->status_code = CSYNC_STATUS_TREE_ERROR; + return -1; + } + break; + case REMOTE_REPLICA: + if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) { + csync_file_stat_free(st); + ctx->status_code = CSYNC_STATUS_TREE_ERROR; + return -1; + } + break; + default: + break; + } + CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "file: %s, instruction: %s <<=", st->path, + csync_instruction_str(st->instruction)); + + return 0; +} + +int csync_walker(CSYNC *ctx, const char *file, const csync_vio_file_stat_t *fs, + enum csync_ftw_flags_e flag) { + int rc = -1; + int type = CSYNC_FTW_TYPE_SKIP; + csync_file_stat_t *st = NULL; + uint64_t h; + + if (ctx->abort) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!"); + ctx->status_code = CSYNC_STATUS_ABORTED; + return -1; + } + + switch (flag) { + case CSYNC_FTW_FLAG_FILE: + if (ctx->current == REMOTE_REPLICA) { + if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_SIZE) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=%" PRIu64 "]", file, fs->file_id, fs->size); + } else { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=UNKNOWN]", file, fs->file_id); + } + } else { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [inode=%" PRIu64 " size=%" PRIu64 "]", file, fs->inode, fs->size); + } + type = CSYNC_FTW_TYPE_FILE; + break; + case CSYNC_FTW_FLAG_DIR: /* enter directory */ + if (ctx->current == REMOTE_REPLICA) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [file_id=%s]", file, fs->file_id); + } else { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [inode=%" PRIu64 "]", file, fs->inode); + } + type = CSYNC_FTW_TYPE_DIR; + break; + case CSYNC_FTW_FLAG_NSTAT: /* not statable file */ + /* if file was here before and now is not longer stat-able, still + * add it to the db, otherwise not. */ + h = _hash_of_file( ctx, file ); + if( h == 0 ) { + return 0; + } + st = csync_statedb_get_stat_by_hash(ctx, h); + if( !st ) { + return 0; + } + csync_file_stat_free(st); + st = NULL; + + type = CSYNC_FTW_TYPE_SKIP; + break; + case CSYNC_FTW_FLAG_SLINK: + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "symlink: %s - not supported", file); + type = CSYNC_FTW_TYPE_SLINK; + break; + case CSYNC_FTW_FLAG_DNR: + case CSYNC_FTW_FLAG_DP: + case CSYNC_FTW_FLAG_SLN: + default: + return 0; + break; + } + + rc = _csync_detect_update(ctx, file, fs, type ); + + return rc; +} + +static bool fill_tree_from_db(CSYNC *ctx, const char *uri) +{ + if( csync_statedb_get_below_path(ctx, uri) < 0 ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "StateDB could not be read!"); + return false; + } + + return true; +} + +/* set the current item to an ignored state. + * If the item is set to ignored, the update phase continues, ie. its not a hard error */ +static bool mark_current_item_ignored( CSYNC *ctx, csync_file_stat_t *previous_fs, CSYNC_STATUS status ) +{ + if(!ctx) { + return false; + } + + if (ctx->current_fs) { + ctx->current_fs->instruction = CSYNC_INSTRUCTION_IGNORE; + ctx->current_fs->error_status = status; + /* If a directory has ignored files, put the flag on the parent directory as well */ + if( previous_fs ) { + previous_fs->has_ignored_files = true; + } + return true; + } + return false; +} + +/* File tree walker */ +int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, + unsigned int depth) { + char *filename = NULL; + char *d_name = NULL; + csync_vio_handle_t *dh = NULL; + csync_vio_file_stat_t *dirent = NULL; + csync_file_stat_t *previous_fs = NULL; + int read_from_db = 0; + int rc = 0; + int res = 0; + + if (!depth) { + mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_INDIVIDUAL_TOO_DEEP); + goto done; + } + + bool do_read_from_db = (ctx->current == REMOTE_REPLICA && ctx->remote.read_from_db); + + read_from_db = ctx->remote.read_from_db; + + // if the etag of this dir is still the same, its content is restored from the + // database. + if( do_read_from_db ) { + if( ! fill_tree_from_db(ctx, uri) ) { + errno = ENOENT; + ctx->status_code = CSYNC_STATUS_OPENDIR_ERROR; + goto error; + } + goto done; + } + + if ((dh = csync_vio_opendir(ctx, uri)) == NULL) { + if (ctx->abort) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!"); + ctx->status_code = CSYNC_STATUS_ABORTED; + goto error; + } + int asp = 0; + /* permission denied */ + ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_OPENDIR_ERROR); + if (errno == EACCES) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Permission denied."); + if (mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_PERMISSION_DENIED)) { + goto done; + } + } else if(errno == ENOENT) { + asp = asprintf( &ctx->error_string, "%s", uri); + if (asp < 0) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!"); + } + } + // 403 Forbidden can be sent by the server if the file firewall is active. + // A file or directory should be ignored and sync must continue. See #3490 + else if(errno == ERRNO_FORBIDDEN) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Directory access Forbidden (File Firewall?)"); + if( mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_FORBIDDEN) ) { + goto done; + } + /* if current_fs is not defined here, better throw an error */ + } + // The server usually replies with the custom "503 Storage not available" + // if some path is temporarily unavailable. But in some cases a standard 503 + // is returned too. Thus we can't distinguish the two and will treat any + // 503 as request to ignore the folder. See #3113 #2884. + else if(errno == ERRNO_STORAGE_UNAVAILABLE || errno == ERRNO_SERVICE_UNAVAILABLE) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Storage was not available!"); + if( mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_STORAGE_UNAVAILABLE ) ) { + goto done; + } + /* if current_fs is not defined here, better throw an error */ + } else { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "opendir failed for %s - errno %d", uri, errno); + } + goto error; + } + + while ((dirent = csync_vio_readdir(ctx, dh))) { + int flen; + int flag; + + /* Conversion error */ + if (dirent->name == NULL && dirent->original_name) { + ctx->status_code = CSYNC_STATUS_INVALID_CHARACTERS; + ctx->error_string = dirent->original_name; // take ownership + dirent->original_name = NULL; + goto error; + } + + d_name = dirent->name; + if (d_name == NULL) { + ctx->status_code = CSYNC_STATUS_READDIR_ERROR; + goto error; + } + + /* skip "." and ".." */ + if ( (d_name[0] == '.' && d_name[1] == '\0') + || (d_name[0] == '.' && d_name[1] == '.' && d_name[2] == '\0')) { + csync_vio_file_stat_destroy(dirent); + dirent = NULL; + continue; + } + + if (uri[0] == '\0') { + filename = c_strdup(d_name); + flen = strlen(d_name); + } else { + flen = asprintf(&filename, "%s/%s", uri, d_name); + } + if (flen < 0 || !filename) { + csync_vio_file_stat_destroy(dirent); + dirent = NULL; + ctx->status_code = CSYNC_STATUS_MEMORY_ERROR; + goto error; + } + + /* Only for the local replica we have to stat(), for the remote one we have all data already */ + if (ctx->replica == LOCAL_REPLICA) { + res = csync_vio_stat(ctx, filename, dirent); + } else { + res = 0; + } + + /* if the filename starts with a . we consider it a hidden file + * For windows, the hidden state is also discovered within the vio + * local stat function. + */ + if( d_name[0] == '.' ) { + if (strcmp(".sys.admin#recall#", d_name) != 0) { /* recall file shall not be ignored (#4420) */ + dirent->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN; + } + } + + if( res == 0) { + switch (dirent->type) { + case CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK: + flag = CSYNC_FTW_FLAG_SLINK; + break; + case CSYNC_VIO_FILE_TYPE_DIRECTORY: + flag = CSYNC_FTW_FLAG_DIR; + break; + case CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE: + case CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE: + case CSYNC_VIO_FILE_TYPE_SOCKET: + flag = CSYNC_FTW_FLAG_SPEC; + break; + case CSYNC_VIO_FILE_TYPE_FIFO: + flag = CSYNC_FTW_FLAG_SPEC; + break; + default: + flag = CSYNC_FTW_FLAG_FILE; + break; + }; + } else { + flag = CSYNC_FTW_FLAG_NSTAT; + } + + previous_fs = ctx->current_fs; + + /* Call walker function for each file */ + rc = fn(ctx, filename, dirent, flag); + /* this function may update ctx->current and ctx->read_from_db */ + + if (rc < 0) { + if (CSYNC_STATUS_IS_OK(ctx->status_code)) { + ctx->status_code = CSYNC_STATUS_UPDATE_ERROR; + } + + ctx->current_fs = previous_fs; + goto error; + } + + if (flag == CSYNC_FTW_FLAG_DIR && rc == 0 + && (!ctx->current_fs || ctx->current_fs->instruction != CSYNC_INSTRUCTION_IGNORE)) { + rc = csync_ftw(ctx, filename, fn, depth - 1); + if (rc < 0) { + ctx->current_fs = previous_fs; + goto error; + } + + if (ctx->current_fs && !ctx->current_fs->child_modified + && ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL) { + if (ctx->current == REMOTE_REPLICA) { + ctx->current_fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; + } else { + ctx->current_fs->instruction = CSYNC_INSTRUCTION_NONE; + } + } + + if (ctx->current_fs && previous_fs && ctx->current_fs->has_ignored_files) { + /* If a directory has ignored files, put the flag on the parent directory as well */ + previous_fs->has_ignored_files = ctx->current_fs->has_ignored_files; + } + } + + if (ctx->current_fs && previous_fs && ctx->current_fs->child_modified) { + /* If a directory has modified files, put the flag on the parent directory as well */ + previous_fs->child_modified = ctx->current_fs->child_modified; + } + + ctx->current_fs = previous_fs; + ctx->remote.read_from_db = read_from_db; + SAFE_FREE(filename); + csync_vio_file_stat_destroy(dirent); + dirent = NULL; + } + + csync_vio_closedir(ctx, dh); + CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, " <= Closing walk for %s with read_from_db %d", uri, read_from_db); + +done: + csync_vio_file_stat_destroy(dirent); + SAFE_FREE(filename); + return rc; +error: + ctx->remote.read_from_db = read_from_db; + if (dh != NULL) { + csync_vio_closedir(ctx, dh); + } + SAFE_FREE(filename); + return -1; +} + +/* vim: set ts=8 sw=2 et cindent: */ diff --git a/src/csync/csync_update.h b/src/csync/csync_update.h new file mode 100644 index 000000000..4a7495e3a --- /dev/null +++ b/src/csync/csync_update.h @@ -0,0 +1,99 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2012-2013 by Klaas Freitag + * + * 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_UPDATE_H +#define _CSYNC_UPDATE_H + +#include "csync.h" + +/** + * @file csync_update.h + * + * @brief Update Detection + * + * TODO + * + * @defgroup csyncUpdateDetectionInternals csync update detection internals + * @ingroup csyncInternalAPI + * + * @{ + */ + +/** + * Types for files + */ +enum csync_ftw_flags_e { + CSYNC_FTW_FLAG_FILE, /* Regular file. */ + CSYNC_FTW_FLAG_DIR, /* Directory. */ + CSYNC_FTW_FLAG_DNR, /* Unreadable directory. */ + CSYNC_FTW_FLAG_NSTAT, /* Unstatable file. */ + CSYNC_FTW_FLAG_SLINK, /* Symbolic link. */ + CSYNC_FTW_FLAG_SPEC, /* Special file (fifo, ...). */ + /* These flags are only passed from the `nftw' function. */ + CSYNC_FTW_FLAG_DP, /* Directory, all subdirs have been visited. */ + CSYNC_FTW_FLAG_SLN /* Symbolic link naming non-existing file. */ +}; + +typedef int (*csync_walker_fn) (CSYNC *ctx, const char *file, + const csync_vio_file_stat_t *fs, enum csync_ftw_flags_e flag); + +/** + * @brief The walker function to use in the file tree walker. + * + * @param ctx The used csync context. + * + * @param file The file we are researching. + * + * @param fs The stat information we got. + * + * @param flag The flag describing the type of the file. + * + * @return 0 on success, < 0 on error. + */ +int csync_walker(CSYNC *ctx, const char *file, const csync_vio_file_stat_t *fs, + enum csync_ftw_flags_e flag); + +/** + * @brief The file tree walker. + * + * This function walks through the directory tree that is located under the uri + * specified. It calls a walker function which is provided as a function pointer + * once for each entry in the tree. By default, directories are handled before + * the files and subdirectories they contain (pre-order traversal). + * + * @param ctx The csync context to use. + * + * @param uri The uri/path to the directory tree to walk. + * + * @param fn The walker function to call once for each entry. + * + * @param depth The max depth to walk down the tree. + * + * @return 0 on success, < 0 on error. If fn() returns non-zero, then the tree + * walk is terminated and the value returned by fn() is returned as the + * result. + */ +int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, + unsigned int depth); + +#endif /* _CSYNC_UPDATE_H */ + +/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/src/csync/csync_util.c b/src/csync/csync_util.c new file mode 100644 index 000000000..1bc09c35c --- /dev/null +++ b/src/csync/csync_util.c @@ -0,0 +1,213 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2012-2013 by Klaas Freitag + * + * 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 "config_csync.h" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include + +#include "c_jhash.h" +#include "csync_util.h" +#include "vio/csync_vio.h" + +#define CSYNC_LOG_CATEGORY_NAME "csync.util" +#include "csync_log.h" +#include "csync_statedb.h" + +typedef struct { + const char *instr_str; + enum csync_instructions_e instr_code; +} _instr_code_struct; + +static const _instr_code_struct _instr[] = +{ + { "INSTRUCTION_NONE", CSYNC_INSTRUCTION_NONE }, + { "INSTRUCTION_EVAL", CSYNC_INSTRUCTION_EVAL }, + { "INSTRUCTION_REMOVE", CSYNC_INSTRUCTION_REMOVE }, + { "INSTRUCTION_RENAME", CSYNC_INSTRUCTION_RENAME }, + { "INSTRUCTION_EVAL_RENAME", CSYNC_INSTRUCTION_EVAL_RENAME }, + { "INSTRUCTION_NEW", CSYNC_INSTRUCTION_NEW }, + { "INSTRUCTION_CONFLICT", CSYNC_INSTRUCTION_CONFLICT }, + { "INSTRUCTION_IGNORE", CSYNC_INSTRUCTION_IGNORE }, + { "INSTRUCTION_SYNC", CSYNC_INSTRUCTION_SYNC }, + { "INSTRUCTION_STAT_ERR", CSYNC_INSTRUCTION_STAT_ERROR }, + { "INSTRUCTION_ERROR", CSYNC_INSTRUCTION_ERROR }, + { "INSTRUCTION_TYPE_CHANGE", CSYNC_INSTRUCTION_TYPE_CHANGE }, + { "INSTRUCTION_UPDATE_METADATA", CSYNC_INSTRUCTION_UPDATE_METADATA }, + { NULL, CSYNC_INSTRUCTION_ERROR } +}; + +struct csync_memstat_s { + int size; + int resident; + int shared; + int trs; + int drs; + int lrs; + int dt; +}; + +const char *csync_instruction_str(enum csync_instructions_e instr) +{ + int idx = 0; + + while (_instr[idx].instr_str != NULL) { + if (_instr[idx].instr_code == instr) { + return _instr[idx].instr_str; + } + idx++; + } + + return "ERROR!"; +} + + +void csync_memstat_check(void) { + int s = 0; + struct csync_memstat_s m; + FILE* fp; + + /* get process memory stats */ + fp = fopen("/proc/self/statm","r"); + if (fp == NULL) { + return; + } + s = fscanf(fp, "%d%d%d%d%d%d%d", &m.size, &m.resident, &m.shared, &m.trs, + &m.drs, &m.lrs, &m.dt); + fclose(fp); + if (s == EOF) { + return; + } + + CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Memory: %dK total size, %dK resident, %dK shared", + m.size * 4, m.resident * 4, m.shared * 4); +} + +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*)) { + csync_file_locked_or_open_ext = f; +} + +bool csync_file_locked_or_open( const char *dir, const char *fname) { + char *tmp_uri = NULL; + bool ret; + if (!csync_file_locked_or_open_ext) { + return false; + } + if (asprintf(&tmp_uri, "%s/%s", dir, fname) < 0) { + return -1; + } + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "csync_file_locked_or_open %s", tmp_uri); + ret = csync_file_locked_or_open_ext(tmp_uri); + SAFE_FREE(tmp_uri); + return ret; +} + +#ifndef HAVE_TIMEGM +#ifdef _WIN32 +static int is_leap(unsigned y) { + y += 1900; + return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0); +} + +static time_t timegm(struct tm *tm) { + static const unsigned ndays[2][12] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; + + time_t res = 0; + int i; + + for (i = 70; i < tm->tm_year; ++i) + res += is_leap(i) ? 366 : 365; + + for (i = 0; i < tm->tm_mon; ++i) + res += ndays[is_leap(tm->tm_year)][i]; + res += tm->tm_mday - 1; + res *= 24; + res += tm->tm_hour; + res *= 60; + res += tm->tm_min; + res *= 60; + res += tm->tm_sec; + return res; +} +#else +/* A hopefully portable version of timegm */ +static time_t timegm(struct tm *tm ) { + time_t ret; + char *tz; + + tz = getenv("TZ"); + setenv("TZ", "", 1); + tzset(); + ret = mktime(tm); + if (tz) + setenv("TZ", tz, 1); + else + unsetenv("TZ"); + tzset(); + return ret; +} +#endif /* Platform switch */ +#endif /* HAVE_TIMEGM */ + +#define RFC1123_FORMAT "%3s, %02d %3s %4d %02d:%02d:%02d GMT" +static const char short_months[12][4] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; +/* + * This function is borrowed from libneon's ne_httpdate_parse. + * Unfortunately that one converts to local time but here UTC is + * needed. + * This one uses timegm instead, which returns UTC. + */ +time_t oc_httpdate_parse( const char *date ) { + struct tm gmt; + char wkday[4], mon[4]; + int n; + time_t result = 0; + + memset(&gmt, 0, sizeof(struct tm)); + + /* it goes: Sun, 06 Nov 1994 08:49:37 GMT */ + n = sscanf(date, RFC1123_FORMAT, + wkday, &gmt.tm_mday, mon, &gmt.tm_year, &gmt.tm_hour, + &gmt.tm_min, &gmt.tm_sec); + /* Is it portable to check n==7 here? */ + gmt.tm_year -= 1900; + for (n=0; n<12; n++) + if (strcmp(mon, short_months[n]) == 0) + break; + /* tm_mon comes out as 12 if the month is corrupt, which is desired, + * since the mktime will then fail */ + gmt.tm_mon = n; + gmt.tm_isdst = -1; + result = timegm(&gmt); + return result; +} diff --git a/src/csync/csync_util.h b/src/csync/csync_util.h new file mode 100644 index 000000000..f65ada592 --- /dev/null +++ b/src/csync/csync_util.h @@ -0,0 +1,34 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2012-2013 by Klaas Freitag + * + * 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_UTIL_H +#define _CSYNC_UTIL_H + +#include + +#include "csync_private.h" + +const char OCSYNC_EXPORT *csync_instruction_str(enum csync_instructions_e instr); + +void OCSYNC_EXPORT csync_memstat_check(void); + +bool OCSYNC_EXPORT csync_file_locked_or_open( const char *dir, const char *fname); +#endif /* _CSYNC_UTIL_H */ diff --git a/src/csync/csync_version.h.in b/src/csync/csync_version.h.in new file mode 100644 index 000000000..9471734b8 --- /dev/null +++ b/src/csync/csync_version.h.in @@ -0,0 +1,37 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2006-2012 by Andreas Schneider + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CSYNC_VERSION_H +#define _CSYNC_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define CSYNC_STRINGIFY(s) CSYNC_TOSTRING(s) +#define CSYNC_TOSTRING(s) #s + +#define MIRALL_VERSION @MIRALL_VERSION@ + +#ifdef __cplusplus +} +#endif + +#endif // _CSYNC_VERSION_H diff --git a/src/csync/std/CMakeLists.txt b/src/csync/std/CMakeLists.txt new file mode 100644 index 000000000..519cada86 --- /dev/null +++ b/src/csync/std/CMakeLists.txt @@ -0,0 +1,44 @@ +project(cstdlib) + +set(CSTDLIB_PUBLIC_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR} + CACHE INTERNAL "cstdlib public include directories" +) + +set(CSTDLIB_LIBRARY + cstdlib + CACHE INTERNAL "cstdlib library" +) + +set(CSTDLIB_LINK_LIBRARIES + ${CSTDLIB_LIBRARY} +) + +set(cstdlib_SRCS + c_alloc.c + c_path.c + c_rbtree.c + c_string.c + c_time.c + c_utf8.cc +) + +if(NOT HAVE_ASPRINTF AND NOT HAVE___MINGW_ASPRINTF) + list(APPEND cstdlib_SRCS + asprintf.c + ) +endif() + +include_directories( + ${CSTDLIB_PUBLIC_INCLUDE_DIRS} +) + +add_library(${CSTDLIB_LIBRARY} STATIC ${cstdlib_SRCS}) +if(NOT WIN32) + add_definitions( -fPIC ) + qt5_use_modules(${CSTDLIB_LIBRARY} Core) +endif() +if(NOT HAVE_FNMATCH AND WIN32) + # needed for PathMatchSpec for our fnmatch replacement + target_link_libraries(${CSTDLIB_LIBRARY} ${SHLWAPI_LIBRARY}) +endif() diff --git a/src/csync/std/asprintf.c b/src/csync/std/asprintf.c new file mode 100644 index 000000000..8738df973 --- /dev/null +++ b/src/csync/std/asprintf.c @@ -0,0 +1,90 @@ +/* + https://raw.githubusercontent.com/littlstar/asprintf.c/20ce5207a4ecb24017b5a17e6cd7d006e3047146/asprintf.c + + The MIT License (MIT) + + Copyright (c) 2014 Little Star Media, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +/** + * `asprintf.c' - asprintf + * + * copyright (c) 2014 joseph werle + */ + +#ifndef HAVE_ASPRINTF + +#include +#include +#include + +#include "asprintf.h" + +int +asprintf (char **str, const char *fmt, ...) { + int size = 0; + va_list args; + + // init variadic argumens + va_start(args, fmt); + + // format and get size + size = vasprintf(str, fmt, args); + + // toss args + va_end(args); + + return size; +} + +int +vasprintf (char **str, const char *fmt, va_list args) { + int size = 0; + va_list tmpa; + + // copy + va_copy(tmpa, args); + + // apply variadic arguments to + // sprintf with format to get size + size = vsnprintf(NULL, size, fmt, tmpa); + + // toss args + va_end(tmpa); + + // return -1 to be compliant if + // size is less than 0 + if (size < 0) { return -1; } + + // alloc with size plus 1 for `\0' + *str = (char *) malloc(size + 1); + + // return -1 to be compliant + // if pointer is `NULL' + if (NULL == *str) { return -1; } + + // format string with original + // variadic arguments and set new size + size = vsprintf(*str, fmt, args); + return size; +} + +#endif diff --git a/src/csync/std/asprintf.h b/src/csync/std/asprintf.h new file mode 100644 index 000000000..d6dd2e859 --- /dev/null +++ b/src/csync/std/asprintf.h @@ -0,0 +1,60 @@ +/* + https://raw.githubusercontent.com/littlstar/asprintf.c/20ce5207a4ecb24017b5a17e6cd7d006e3047146/asprintf.h + + The MIT License (MIT) + + Copyright (c) 2014 Little Star Media, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +/** + * `asprintf.h' - asprintf.c + * + * copyright (c) 2014 joseph werle + */ + +#ifndef HAVE_ASPRINTF +#ifndef ASPRINTF_H +#define ASPRINTF_H 1 + +#include + +/** + * Sets `char **' pointer to be a buffer + * large enough to hold the formatted string + * accepting a `va_list' args of variadic + * arguments. + */ + +int +vasprintf (char **, const char *, va_list); + +/** + * Sets `char **' pointer to be a buffer + * large enough to hold the formatted + * string accepting `n' arguments of + * variadic arguments. + */ + +int +asprintf (char **, const char *, ...); + +#endif +#endif diff --git a/src/csync/std/c_alloc.c b/src/csync/std/c_alloc.c new file mode 100644 index 000000000..b87a3836f --- /dev/null +++ b/src/csync/std/c_alloc.c @@ -0,0 +1,89 @@ +/* + * cynapses libc functions + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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 + +#include "c_macro.h" +#include "c_alloc.h" + +void *c_calloc(size_t count, size_t size) { + if (size == 0 || count == 0) { + return NULL; + } + +#ifdef CSYNC_MEM_NULL_TESTS + if (getenv("CSYNC_NOMEMORY")) { + return NULL; + } +#endif /* CSYNC_MEM_NULL_TESTS */ + +#undef calloc + return calloc(count, size); +#define calloc(x,y) DO_NOT_CALL_CALLOC__USE_XCALLOC_INSTEAD +} + +void *c_malloc(size_t size) { + if (size == 0) { + return NULL; + } +#undef malloc + return c_calloc(1, size); +#define malloc(x) DO_NOT_CALL_MALLOC__USE_XMALLOC_INSTEAD +} + +void *c_realloc(void *ptr, size_t size) { + +#ifdef CSYNC_MEM_NULL_TESTS + if (getenv("CSYNC_NOMEMORY")) { + return NULL; + } +#endif /* CSYNC_MEM_NULL_TESTS */ + +#undef realloc + return realloc(ptr, size); +#define realloc(x,y) DO_NOT_CALL_REALLOC__USE_XREALLOC_INSTEAD +} + +char *c_strdup(const char *str) { + char *ret; + ret = (char *) c_malloc(strlen(str) + 1); + if (ret == NULL) { + return NULL; + } + strcpy(ret, str); + return ret; +} + +char *c_strndup(const char *str, size_t size) { + char *ret; + size_t len; + len = strlen(str); + if (len > size) { + len = size; + } + ret = (char *) c_malloc(len + 1); + if (ret == NULL) { + return NULL; + } + strncpy(ret, str, len); + ret[size] = '\0'; + return ret; +} + diff --git a/src/csync/std/c_alloc.h b/src/csync/std/c_alloc.h new file mode 100644 index 000000000..6eeccd69d --- /dev/null +++ b/src/csync/std/c_alloc.h @@ -0,0 +1,116 @@ +/* + * cynapses libc functions + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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_alloc.h + * + * @brief Interface of the cynapses libc alloc function + * + * @defgroup cynLibraryAPI cynapses libc API (internal) + * + * @defgroup cynAllocInternals cynapses libc alloc functions + * @ingroup cynLibraryAPI + * + * @{ + */ + +#ifndef _C_ALLOC_H +#define _C_ALLOC_H + +#include + +#include "c_macro.h" + +/** + * @brief Allocates memory for an array. + * + * Allocates memory for an array of elements of bytes each and + * returns a pointer to the allocated memory. The memory is set to zero. + * + * @param count Amount of elements to allocate + * @param size Size in bytes of each element to allocate. + * + * @return A unique pointer value that can later be successfully passed to + * free(). If size or count is 0, NULL will be returned. + */ +void *c_calloc(size_t count, size_t size); + +/** + * @brief Allocates memory for an array. + * + * Allocates bytes of memory. The memory is set to zero. + * + * @param size Size in bytes to allocate. + * + * @return A unique pointer value that can later be successfully passed to + * free(). If size or count is 0, NULL will be returned. + */ +void *c_malloc(size_t size); + +/** + * @brief Changes the size of the memory block pointed to. + * + * Newly allocated memory will be uninitialized. + * + * @param ptr Pointer to the memory which should be resized. + * @param size Value to resize. + * + * @return If ptr is NULL, the call is equivalent to c_malloc(size); if size + * is equal to zero, the call is equivalent to free(ptr). Unless ptr + * is NULL, it must have been returned by an earlier call to + * c_malloc(), c_calloc() or c_realloc(). If the area pointed to was + * moved, a free(ptr) is done. + */ +void *c_realloc(void *ptr, size_t size); + +/** + * @brief Duplicate a string. + * + * The function returns a pointer to a newly allocated string which is a + * duplicate of the string str. + * + * @param str String to duplicate. + * + * @return Returns a pointer to the duplicated string, or NULL if insufficient + * memory was available. + * + */ +char *c_strdup(const char *str); + +/** + * @brief Duplicate a string. + * + * The function returns a pointer to a newly allocated string which is a + * duplicate of the string str of size bytes. + * + * @param str String to duplicate. + * + * @param size Size of the string to duplicate. + * + * @return Returns a pointer to the duplicated string, or NULL if insufficient + * memory was available. A terminating null byte '\0' is added. + * + */ +char *c_strndup(const char *str, size_t size); + +/** + * }@ + */ +#endif /* _C_ALLOC_H */ diff --git a/src/csync/std/c_jhash.h b/src/csync/std/c_jhash.h new file mode 100644 index 000000000..261a0a4a4 --- /dev/null +++ b/src/csync/std/c_jhash.h @@ -0,0 +1,245 @@ +/* + * c_jhash.c Jenkins Hash + * + * Copyright (c) 1997 Bob Jenkins + * + * lookup8.c, by Bob Jenkins, January 4 1997, Public Domain. + * hash(), hash2(), hash3, and _c_mix() are externally useful functions. + * Routines to test the hash are included if SELF_TEST is defined. + * You can use this free for any purpose. It has no warranty. + * + * See http://burtleburtle.net/bob/hash/evahash.html + */ + +/** + * @file c_jhash.h + * + * @brief Interface of the cynapses jhash implementation + * + * @defgroup cynJHashInternals cynapses libc jhash function + * @ingroup cynLibraryAPI + * + * @{ + */ +#ifndef _C_JHASH_H +#define _C_JHASH_H + +#include + +#define c_hashsize(n) ((uint8_t) 1 << (n)) +#define c_hashmask(n) (xhashsize(n) - 1) + +/** + * _c_mix -- Mix 3 32-bit values reversibly. + * + * For every delta with one or two bit set, and the deltas of all three + * high bits or all three low bits, whether the original value of a,b,c + * is almost all zero or is uniformly distributed, + * If _c_mix() is run forward or backward, at least 32 bits in a,b,c + * have at least 1/4 probability of changing. + * If _c_mix() is run forward, every bit of c will change between 1/3 and + * 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) + * _c_mix() was built out of 36 single-cycle latency instructions in a + * structure that could supported 2x parallelism, like so: + * a -= b; + * a -= c; x = (c>>13); + * b -= c; a ^= x; + * b -= a; x = (a<<8); + * c -= a; b ^= x; + * c -= b; x = (b>>13); + * ... + * + * Unfortunately, superscalar Pentiums and Sparcs can't take advantage + * of that parallelism. They've also turned some of those single-cycle + * latency instructions into multi-cycle latency instructions. Still, + * this is the fastest good hash I could find. There were about 2^^68 + * to choose from. I only looked at a billion or so. + */ +#define _c_mix(a,b,c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<<8); \ + c -= a; c -= b; c ^= (b>>13); \ + a -= b; a -= c; a ^= (c>>12); \ + b -= c; b -= a; b ^= (a<<16); \ + c -= a; c -= b; c ^= (b>>5); \ + a -= b; a -= c; a ^= (c>>3); \ + b -= c; b -= a; b ^= (a<<10); \ + c -= a; c -= b; c ^= (b>>15); \ +} + +/** + * _c_mix64 -- Mix 3 64-bit values reversibly. + * + * _c_mix64() takes 48 machine instructions, but only 24 cycles on a superscalar + * machine (like Intel's new MMX architecture). It requires 4 64-bit + * registers for 4::2 parallelism. + * All 1-bit deltas, all 2-bit deltas, all deltas composed of top bits of + * (a,b,c), and all deltas of bottom bits were tested. All deltas were + * tested both on random keys and on keys that were nearly all zero. + * These deltas all cause every bit of c to change between 1/3 and 2/3 + * of the time (well, only 113/400 to 287/400 of the time for some + * 2-bit delta). These deltas all cause at least 80 bits to change + * among (a,b,c) when the _c_mix is run either forward or backward (yes it + * is reversible). + * This implies that a hash using _c_mix64 has no funnels. There may be + * characteristics with 3-bit deltas or bigger, I didn't test for + * those. + */ +#define _c_mix64(a,b,c) \ +{ \ + a -= b; a -= c; a ^= (c>>43); \ + b -= c; b -= a; b ^= (a<<9); \ + c -= a; c -= b; c ^= (b>>8); \ + a -= b; a -= c; a ^= (c>>38); \ + b -= c; b -= a; b ^= (a<<23); \ + c -= a; c -= b; c ^= (b>>5); \ + a -= b; a -= c; a ^= (c>>35); \ + b -= c; b -= a; b ^= (a<<49); \ + c -= a; c -= b; c ^= (b>>11); \ + a -= b; a -= c; a ^= (c>>12); \ + b -= c; b -= a; b ^= (a<<18); \ + c -= a; c -= b; c ^= (b>>22); \ +} + +/** + * @brief hash a variable-length key into a 32-bit value + * + * The best hash table sizes are powers of 2. There is no need to do + * mod a prime (mod is sooo slow!). If you need less than 32 bits, + * use a bitmask. For example, if you need only 10 bits, do + * h = (h & hashmask(10)); + * In which case, the hash table should have hashsize(10) elements. + * + * Use for hash table lookup, or anything where one collision in 2^32 is + * acceptable. Do NOT use for cryptographic purposes. + * + * @param k The key (the unaligned variable-length array of bytes). + * + * @param length The length of the key, counting by bytes. + * + * @param initval Initial value, can be any 4-byte value. + * + * @return Returns a 32-bit value. Every bit of the key affects every bit + * of the return value. Every 1-bit and 2-bit delta achieves + * avalanche. About 36+6len instructions. + */ +static inline uint32_t c_jhash(const uint8_t *k, uint32_t length, uint32_t initval) { + uint32_t a,b,c,len; + + /* Set up the internal state */ + len = length; + a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ + c = initval; /* the previous hash value */ + + while (len >= 12) { + a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24)); + b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24)); + c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24)); + _c_mix(a,b,c); + k += 12; len -= 12; + } + + /* handle the last 11 bytes */ + c += length; + /* all the case statements fall through */ + switch(len) { + case 11: c+=((uint32_t)k[10]<<24); + case 10: c+=((uint32_t)k[9]<<16); + case 9 : c+=((uint32_t)k[8]<<8); + /* the first byte of c is reserved for the length */ + case 8 : b+=((uint32_t)k[7]<<24); + case 7 : b+=((uint32_t)k[6]<<16); + case 6 : b+=((uint32_t)k[5]<<8); + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)k[3]<<24); + case 3 : a+=((uint32_t)k[2]<<16); + case 2 : a+=((uint32_t)k[1]<<8); + case 1 : a+=k[0]; + /* case 0: nothing left to add */ + } + _c_mix(a,b,c); + + return c; +} + +/** + * @brief hash a variable-length key into a 64-bit value + * + * The best hash table sizes are powers of 2. There is no need to do + * mod a prime (mod is sooo slow!). If you need less than 64 bits, + * use a bitmask. For example, if you need only 10 bits, do + * h = (h & hashmask(10)); + * In which case, the hash table should have hashsize(10) elements. + * + * Use for hash table lookup, or anything where one collision in 2^^64 + * is acceptable. Do NOT use for cryptographic purposes. + * + * @param k The key (the unaligned variable-length array of bytes). + * @param length The length of the key, counting by bytes. + * @param intval Initial value, can be any 8-byte value. + * + * @return A 64-bit value. Every bit of the key affects every bit of + * the return value. No funnels. Every 1-bit and 2-bit delta + * achieves avalanche. About 41+5len instructions. + */ +static inline uint64_t c_jhash64(const uint8_t *k, uint64_t length, uint64_t intval) { + uint64_t a,b,c,len; + + /* Set up the internal state */ + len = length; + a = b = intval; /* the previous hash value */ + c = 0x9e3779b97f4a7c13LL; /* the golden ratio; an arbitrary value */ + + /* handle most of the key */ + while (len >= 24) + { + a += (k[0] +((uint64_t)k[ 1]<< 8)+((uint64_t)k[ 2]<<16)+((uint64_t)k[ 3]<<24) + +((uint64_t)k[4 ]<<32)+((uint64_t)k[ 5]<<40)+((uint64_t)k[ 6]<<48)+((uint64_t)k[ 7]<<56)); + b += (k[8] +((uint64_t)k[ 9]<< 8)+((uint64_t)k[10]<<16)+((uint64_t)k[11]<<24) + +((uint64_t)k[12]<<32)+((uint64_t)k[13]<<40)+((uint64_t)k[14]<<48)+((uint64_t)k[15]<<56)); + c += (k[16] +((uint64_t)k[17]<< 8)+((uint64_t)k[18]<<16)+((uint64_t)k[19]<<24) + +((uint64_t)k[20]<<32)+((uint64_t)k[21]<<40)+((uint64_t)k[22]<<48)+((uint64_t)k[23]<<56)); + _c_mix64(a,b,c); + k += 24; len -= 24; + } + + /* handle the last 23 bytes */ + c += length; + switch(len) { + case 23: c+=((uint64_t)k[22]<<56); + case 22: c+=((uint64_t)k[21]<<48); + case 21: c+=((uint64_t)k[20]<<40); + case 20: c+=((uint64_t)k[19]<<32); + case 19: c+=((uint64_t)k[18]<<24); + case 18: c+=((uint64_t)k[17]<<16); + case 17: c+=((uint64_t)k[16]<<8); + /* the first byte of c is reserved for the length */ + case 16: b+=((uint64_t)k[15]<<56); + case 15: b+=((uint64_t)k[14]<<48); + case 14: b+=((uint64_t)k[13]<<40); + case 13: b+=((uint64_t)k[12]<<32); + case 12: b+=((uint64_t)k[11]<<24); + case 11: b+=((uint64_t)k[10]<<16); + case 10: b+=((uint64_t)k[ 9]<<8); + case 9: b+=((uint64_t)k[ 8]); + case 8: a+=((uint64_t)k[ 7]<<56); + case 7: a+=((uint64_t)k[ 6]<<48); + case 6: a+=((uint64_t)k[ 5]<<40); + case 5: a+=((uint64_t)k[ 4]<<32); + case 4: a+=((uint64_t)k[ 3]<<24); + case 3: a+=((uint64_t)k[ 2]<<16); + case 2: a+=((uint64_t)k[ 1]<<8); + case 1: a+=((uint64_t)k[ 0]); + /* case 0: nothing left to add */ + } + _c_mix64(a,b,c); + + return c; +} + +/** + * }@ + */ +#endif /* _C_JHASH_H */ + diff --git a/src/csync/std/c_lib.h b/src/csync/std/c_lib.h new file mode 100644 index 000000000..b9c1ea8d3 --- /dev/null +++ b/src/csync/std/c_lib.h @@ -0,0 +1,30 @@ +/* + * cynapses libc functions + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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 +#include + +#include "c_macro.h" +#include "c_alloc.h" +#include "c_path.h" +#include "c_rbtree.h" +#include "c_string.h" +#include "c_time.h" +#include "c_private.h" diff --git a/src/csync/std/c_macro.h b/src/csync/std/c_macro.h new file mode 100644 index 000000000..a4a0e1c1c --- /dev/null +++ b/src/csync/std/c_macro.h @@ -0,0 +1,111 @@ +/* + * cynapses libc functions + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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_macro.h + * + * @brief cynapses libc macro definitions + * + * @defgroup cynMacroInternals cynapses libc macro definitions + * @ingroup cynLibraryAPI + * + * @{ + */ +#ifndef _C_MACRO_H +#define _C_MACRO_H + +#include +#include + +#define INT_TO_POINTER(i) (void *) i +#define POINTER_TO_INT(p) *((int *) (p)) + +/** Zero a structure */ +#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) + +/** Zero a structure given a pointer to the structure */ +#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0) + +/** Free memory and zero the pointer */ +#define SAFE_FREE(x) do { if ((x) != NULL) {free((void*)x); x=NULL;} } while(0) + +/** Get the smaller value */ +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +/** Get the bigger value */ +#define MAX(a,b) ((a) < (b) ? (b) : (a)) + +/** Get the size of an array */ +#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) + +/** + * This is a hack to fix warnings. The idea is to use this everywhere that we + * get the "discarding const" warning by the compiler. That doesn't actually + * fix the real issue, but marks the place and you can search the code for + * discard_const. + * + * Please use this macro only when there is no other way to fix the warning. + * We should use this function in only in a very few places. + * + * Also, please call this via the discard_const_p() macro interface, as that + * makes the return type safe. + */ +#define discard_const(ptr) ((void *)((uintptr_t)(ptr))) + +/** + * Type-safe version of discard_const + */ +#define discard_const_p(type, ptr) ((type *)discard_const(ptr)) + +#if (__GNUC__ >= 3) +# ifndef likely +# define likely(x) __builtin_expect(!!(x), 1) +# endif +# ifndef unlikely +# define unlikely(x) __builtin_expect(!!(x), 0) +# endif +#else /* __GNUC__ */ +# ifndef likely +# define likely(x) (x) +# endif +# ifndef unlikely +# define unlikely(x) (x) +# endif +#endif /* __GNUC__ */ + +/** + * }@ + */ + +#ifdef _WIN32 +/* missing errno codes on mingw */ +#ifndef ENOTBLK +#define ENOTBLK 15 +#endif +#ifndef ETXTBSY +#define ETXTBSY 26 +#endif +#ifndef ENOBUFS +#define ENOBUFS WSAENOBUFS +#endif +#endif /* _WIN32 */ + +#endif /* _C_MACRO_H */ + diff --git a/src/csync/std/c_path.c b/src/csync/std/c_path.c new file mode 100644 index 000000000..1094a1c67 --- /dev/null +++ b/src/csync/std/c_path.c @@ -0,0 +1,451 @@ +/* + * cynapses libc functions + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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 _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +#include "c_private.h" +#include "c_alloc.h" +#include "c_path.h" +#include "c_string.h" + +/* + * dirname - parse directory component. + */ +char *c_dirname (const char *path) { + char *newbuf = NULL; + unsigned int len; + + if (path == NULL || *path == '\0') { + return c_strdup("."); + } + + len = strlen(path); + + /* Remove trailing slashes */ + while(len > 0 && path[len - 1] == '/') --len; + + /* We have only slashes */ + if (len == 0) { + return c_strdup("/"); + } + + /* goto next slash */ + while(len > 0 && path[len - 1] != '/') --len; + + if (len == 0) { + return c_strdup("."); + } else if (len == 1) { + return c_strdup("/"); + } + + /* Remove slashes again */ + while(len > 0 && path[len - 1] == '/') --len; + + newbuf = c_malloc(len + 1); + + strncpy(newbuf, path, len); + newbuf[len] = '\0'; + + return newbuf; +} + +char *c_basename (const char *path) { + char *newbuf = NULL; + const char *s; + unsigned int len; + + if (path == NULL || *path == '\0') { + return c_strdup("."); + } + + len = strlen(path); + /* Remove trailing slashes */ + while(len > 0 && path[len - 1] == '/') --len; + + /* We have only slashes */ + if (len == 0) { + return c_strdup("/"); + } + + while(len > 0 && path[len - 1] != '/') --len; + + if (len > 0) { + s = path + len; + len = strlen(s); + + while(len > 0 && s[len - 1] == '/') --len; + } else { + return c_strdup(path); + } + + newbuf = c_malloc(len + 1); + + strncpy(newbuf, s, len); + newbuf[len] = '\0'; + + return newbuf; +} + +int c_parse_uri(const char *uri, + char **scheme, + char **user, char **passwd, + char **host, unsigned int *port, + char **path) { + const char *p, *z; + + if (uri == NULL || *uri == '\0') { + return -1; + } + + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + */ + p = z = uri; + + /* check for valid scheme; git+ssh, pop3 */ + while (isalpha((int) *p) || isdigit((int) *p) || + *p == '+' || *p == '-') { + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + */ + p++; + } + + /* get scheme */ + if (*p == ':') { + if (scheme != NULL) { + *scheme = c_strndup(z, p - z); + + if (*scheme == NULL) { + errno = ENOMEM; + return -1; + } + } + p++; + z = p; + } + + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + */ + p = z; + + /* do we have a hostname */ + if (p[0] == '/' && p[1] == '/') { + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + */ + z += 2; + p = z; + + /* check for user and passwd */ + while (*p && *p != '@' && *p != '/') { + /* + * uri = scheme://user:password@host:port/path + * p = ^ or ^ + * z = ^ + */ + p++; + } + + /* check for user and password */ + if (*p == '@') { + const char *q; + + q = p; + + /* check if we have a password */ + while (q > z && *q != ':') { + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + * q = ^ + */ + q--; + } + + /* password found */ + if (*q == ':') { + if (user != NULL) { + *user = c_strndup(z, q - z); + if (*user == NULL) { + errno = ENOMEM; + if (scheme != NULL) SAFE_FREE(*scheme); + return -1; + } + } + + if (passwd != NULL) { + *passwd = c_strndup(q + 1, p - (q + 1)); + if (*passwd == NULL) { + if (scheme != NULL) SAFE_FREE(*scheme); + if (user != NULL) SAFE_FREE(*user); + errno = ENOMEM; + return -1; + } + } + } else { + /* user only */ + if (user != NULL) { + *user = c_strndup(z, p - z); + if( *user == NULL) { + if (scheme != NULL) SAFE_FREE(*scheme); + errno = ENOMEM; + return -1; + } + } + } + + p++; + z = p; + } + + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + */ + p = z; + + /* check for IPv6 address */ + if (*p == '[') { + /* + * uri = scheme://user:password@[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:port/path + * p = ^ + * z = ^ + */ + p++; + + /* check if we have a valid IPv6 address */ + while (*p && (isxdigit((int) *p) || *p == '.' || *p == ':')) { + /* + * uri = scheme://user:password@[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:port/path + * p = ^ + * z = ^ + */ + p++; + } + + /* valid IPv6 address found */ + if (*p == ']') { + /* + * uri = scheme://user:password@[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:port/path + * p = ^ + * z = ^ + */ + z++; + + if (host != NULL) { + *host = c_strndup(z, p - z); + if (*host == NULL) { + if (scheme != NULL) SAFE_FREE(*scheme); + if (user != NULL) SAFE_FREE(*user); + if (passwd != NULL) SAFE_FREE(*passwd); + errno = ENOMEM; + return -1; + } + } + + /* + * uri = scheme://user:password@[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:port/path + * p = ^ + * z = ^ + */ + p++; + } else { + /* invalid IPv6 address, assume a hostname */ + p = z; + + while (*p && *p != ':' && *p != '/') { + p++; + /* + * uri = scheme://user:password@host:port/path + * p = ^ or ^ + * z = ^ + */ + } + + if (host != NULL) { + *host = c_strndup(z, p - z); + if (*host == NULL) { + if (scheme != NULL) SAFE_FREE(*scheme); + if (user != NULL) SAFE_FREE(*user); + if (passwd != NULL) SAFE_FREE(*passwd); + errno = ENOMEM; + return -1; + } + } + } + } else { + /* check for hostname */ + while (*p && *p != ':' && *p != '/') { + /* + * uri = scheme://user:password@host:port/path + * p = ^ ^ + * z = ^ + */ + p++; + } + + if (host != NULL) { + *host = c_strndup(z, p - z); + if (*host == NULL) { + if (scheme != NULL) SAFE_FREE(*scheme); + if (user != NULL) SAFE_FREE(*user); + if (passwd != NULL) SAFE_FREE(*passwd); + errno = ENOMEM; + return -1; + } + } + } + + /* check for port */ + if (*p == ':') { + char **e = NULL; + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + */ + z = ++p; + + /* get only the digits */ + while (isdigit((int) *p)) { + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + */ + e = (char **) &p; + p++; + } + + if (port != NULL) { + *port = strtoul(z, e, 0); + } + + /* + * uri = scheme://user:password@host:port/path + * p = ^ + */ + } + } + + if (*p == '\0') { + return 0; + } + + /* get the path with the leading slash */ + if (*p == '/') { + if (path != NULL) { + *path = c_strdup(p); + if (*path == NULL) { + if (scheme != NULL) SAFE_FREE(*scheme); + if (user != NULL) SAFE_FREE(*user); + if (passwd != NULL) SAFE_FREE(*passwd); + if (host != NULL) SAFE_FREE(*host); + errno = ENOMEM; + return -1; + } + } + + return 0; + } + + return -1; +} + + +/* + * This function takes a path and converts it to a UNC representation of the + * string. That means that it prepends a \\?\ (unless already UNC) and converts + * all slashes to backslashes. + * + * Note the following: + * - The string must be absolute. + * - it needs to contain a drive character to be a valid UNC + * - A conversion is only done if the path len is larger than 245. Otherwise + * the windows API functions work with the normal "unixoid" representation too. + * + * This function allocates memory that must be freed by the caller. + */ + const char *c_path_to_UNC(const char *str) + { + int len = 0; + char *longStr = NULL; + + len = strlen(str); + longStr = c_malloc(len+5); + *longStr = '\0'; + + // prepend \\?\ and convert '/' => '\' to support long names + if( str[0] == '/' || str[0] == '\\' ) { + // Don't prepend if already UNC + if( !(len > 1 && (str[1] == '/' || str[1] == '\\')) ) { + strcpy( longStr, "\\\\?"); + } + } else { + strcpy( longStr, "\\\\?\\"); // prepend string by this four magic chars. + } + strncat( longStr, str, len ); + + /* replace all occurences of / with the windows native \ */ + char *c = longStr; + for (; *c; ++c) { + if(*c == '/') { + *c = '\\'; + } + } + return longStr; + } + + mbchar_t* c_utf8_path_to_locale(const char *str) + { + if( str == NULL ) { + return NULL; + } else { + #ifdef _WIN32 + const char *unc_str = c_path_to_UNC(str); + mbchar_t *dst = c_utf8_string_to_locale(unc_str); + SAFE_FREE(unc_str); + return dst; + #else + return c_utf8_string_to_locale(str); + #endif + } + } diff --git a/src/csync/std/c_path.h b/src/csync/std/c_path.h new file mode 100644 index 000000000..291b1b8d3 --- /dev/null +++ b/src/csync/std/c_path.h @@ -0,0 +1,142 @@ +/* + * cynapses libc functions + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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_path.h + * + * @brief Interface of the cynapses libc path functions + * + * @defgroup cynPathInternals cynapses libc path functions + * @ingroup cynLibraryAPI + * + * @{ + */ + +#ifndef _C_PATH_H +#define _C_PATH_H + +#include "c_macro.h" +#include "c_private.h" + +/** + * @brief Parse directory component. + * + * dirname breaks a null-terminated pathname string into a directory component. + * In the usual case, c_dirname() returns the string up to, but not including, + * the final '/'. Trailing '/' characters are not counted as part of the + * pathname. The caller must free the memory. + * + * @param path The path to parse. + * + * @return The dirname of path or NULL if we can't allocate memory. If path + * does not contain a slash, c_dirname() returns the string ".". If + * path is the string "/", it returns the string "/". If path is + * NULL or an empty string, "." is returned. + */ +char *c_dirname(const char *path); + +/** + * @brief basename - parse filename component. + * + * basename breaks a null-terminated pathname string into a filename component. + * c_basename() returns the component following the final '/'. Trailing '/' + * characters are not counted as part of the pathname. + * + * @param path The path to parse. + * + * @return The filename of path or NULL if we can't allocate memory. If path + * is a the string "/", basename returns the string "/". If path is + * NULL or an empty string, "." is returned. + */ +char *c_basename (const char *path); + +/** + * @brief parse a uri and split it into components. + * + * parse_uri parses an uri in the format + * + * [:][//[[:]@][:]]/[] + * + * into its compoments. If you only want a special component, + * pass NULL for all other components. All components will be allocated if they have + * been found. + * + * @param uri The uri to parse. + * @param scheme String for the scheme component + * @param user String for the username component + * @param passwd String for the password component + * @param host String for the password component + * @param port Integer for the port + * @param path String for the path component with a leading slash. + * + * @return 0 on success, < 0 on error. + */ +int c_parse_uri(const char *uri, char **scheme, char **user, char **passwd, + char **host, unsigned int *port, char **path); + +/** + * @brief Parts of a path. + * + * @param directory '\0' terminated path including the final '/' + * + * @param filename '\0' terminated string + * + * @param extension '\0' terminated string + * + */ +typedef struct +{ + char * directory; + char * filename; + char * extension; +} C_PATHINFO; + +/** + * @brief c_path_to_UNC converts a unixoid path to UNC format. + * + * It converts the '/' to '\' and prepends \\?\ to the path. + * + * A proper windows path has to have a drive letter, otherwise it is not + * valid UNC. + * + * @param str The path to convert + * + * @return a pointer to the converted string. Caller has to free it. + */ +const char *c_path_to_UNC(const char *str); + +/** + * @brief c_utf8_path_to_locale converts a unixoid path to the locale aware format + * + * On windows, it converts to UNC and multibyte. + * On Mac, it converts to the correct utf8 using iconv. + * On Linux, it returns utf8 + * + * @param str The path to convert + * + * @return a pointer to the converted string. Caller has to free it using the + * function c_free_locale_string. + */ +mbchar_t* c_utf8_path_to_locale(const char *str); + +/** + * }@ + */ +#endif /* _C_PATH_H */ diff --git a/src/csync/std/c_private.h b/src/csync/std/c_private.h new file mode 100644 index 000000000..26bba70db --- /dev/null +++ b/src/csync/std/c_private.h @@ -0,0 +1,173 @@ +/* + * cynapses libc functions + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2012-2013 by Dominik Schmidt + * Copyright (c) 2012-2013 by Klaas Freitag + * + * 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 _C_PRIVATE_H +#define _C_PRIVATE_H + +#include "config_csync.h" + +/* cross platform defines */ +#include "config_csync.h" +#include +#include + +#ifdef _WIN32 +#include +#include +#include +#include +#else +#include +#endif + +#include + +#ifdef __MINGW32__ +#define EDQUOT 0 +#define ENODATA 0 +#ifndef S_IRGRP +#define S_IRGRP 0 +#endif +#ifndef S_IROTH +#define S_IROTH 0 +#endif +#ifndef S_IXGRP +#define S_IXGRP 0 +#endif +#ifndef S_IXOTH +#define S_IXOTH 0 +#endif + +#define S_IFSOCK 10000 /* dummy val on Win32 */ +#define S_IFLNK 10001 /* dummy val on Win32 */ + +#define O_NOFOLLOW 0 +#define O_NOCTTY 0 + +#define uid_t int +#define gid_t int +#define nlink_t int +#define getuid() 0 +#define geteuid() 0 +#elif defined(_WIN32) +#define mode_t int +#else +#include +#endif + +#ifndef ENODATA +#define ENODATA EPIPE +#endif + + +#ifdef _WIN32 +typedef struct stat64 csync_stat_t; +#define _FILE_OFFSET_BITS 64 +#else +typedef struct stat csync_stat_t; +#endif + +#ifndef O_NOATIME +#define O_NOATIME 0 +#endif + +#ifndef ENODATA +#define ENODATA EBADF +#endif + +#if !defined(HAVE_ASPRINTF) +#if defined(HAVE___MINGW_ASPRINTF) +#define asprintf __mingw_asprintf +#else +#include "asprintf.h" +#endif +#endif + +#ifndef HAVE_STRERROR_R +#define strerror_r(errnum, buf, buflen) snprintf(buf, buflen, "%s", strerror(errnum)) +#endif + +#ifndef HAVE_LSTAT +#define lstat _stat +#endif + +/* tchar definitions for clean win32 filenames */ +#ifndef _UNICODE +#define _UNICODE +#endif + +#if defined _WIN32 && defined _UNICODE +typedef wchar_t mbchar_t; +#define _topen _wopen +#define _tdirent _wdirent +#define _topendir _wopendir +#define _tclosedir _wclosedir +#define _treaddir _wreaddir +#define _trewinddir _wrewinddir +#define _ttelldir _wtelldir +#define _tseekdir _wseekdir +#define _tcreat _wcreat +#define _tstat _wstat64 +#define _tfstat _fstat64 +#define _tunlink _wunlink +#define _tmkdir(X,Y) _wmkdir(X) +#define _trmdir _wrmdir +#define _tchmod _wchmod +#define _trewinddir _wrewinddir +#define _tchown(X, Y, Z) 0 /* no chown on Win32 */ +#define _tchdir _wchdir +#define _tgetcwd _wgetcwd +#else +typedef char mbchar_t; +#define _tdirent dirent +#define _topen open +#define _topendir opendir +#define _tclosedir closedir +#define _treaddir readdir +#define _trewinddir rewinddir +#define _ttelldir telldir +#define _tseekdir seekdir +#define _tcreat creat +#define _tstat lstat +#define _tfstat fstat +#define _tunlink unlink +#define _tmkdir(X,Y) mkdir(X,Y) +#define _trmdir rmdir +#define _tchmod chmod +#define _trewinddir rewinddir +#define _tchown(X,Y,Z) chown(X,Y,Z) +#define _tchdir chdir +#define _tgetcwd getcwd +#endif + +/* FIXME: Implement TLS for OS X */ +#if defined(__GNUC__) && !defined(__APPLE__) +# define CSYNC_THREAD __thread +#elif defined(_MSC_VER) +# define CSYNC_THREAD __declspec(thread) +#else +# define CSYNC_THREAD +#endif + +#endif //_C_PRIVATE_H + +/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/src/csync/std/c_rbtree.c b/src/csync/std/c_rbtree.c new file mode 100644 index 000000000..9a38fd0a6 --- /dev/null +++ b/src/csync/std/c_rbtree.c @@ -0,0 +1,743 @@ +/* + * cynapses libc functions + * + * Copyright (c) 2003-2004 by Andrew Suffield + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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 + */ + +/* + * This code was originally released under GPL but Andrew Suffield agreed to + * change it to LGPL. + */ + +/* + * static function don't have NULL pointer checks, segfaults are intended. + */ + +#include +#include +#include + +#include "c_alloc.h" +#include "c_rbtree.h" + +#define NIL &_sentinel /* all leafs are sentinels */ +static c_rbnode_t _sentinel = {NULL, NIL, NIL, NULL, NULL, BLACK}; + +void c_rbtree_create(c_rbtree_t **rbtree, c_rbtree_compare_func *key_compare, c_rbtree_compare_func *data_compare) { + assert(rbtree); + assert(key_compare); + assert(data_compare); + + c_rbtree_t *tree = NULL; + + tree = c_malloc(sizeof(*tree)); + tree->root = NIL; + tree->key_compare = key_compare; + tree->data_compare = data_compare; + tree->size = 0; + + *rbtree = tree; +} + +static c_rbnode_t *_rbtree_subtree_dup(const c_rbnode_t *node, c_rbtree_t *new_tree, c_rbnode_t *new_parent) { + c_rbnode_t *new_node = NULL; + + new_node = (c_rbnode_t*) c_malloc(sizeof(c_rbnode_t)); + + new_node->tree = new_tree; + new_node->data = node->data; + new_node->color = node->color; + new_node->parent = new_parent; + + if (node->left == NIL) { + new_node->left = NIL; + } else { + new_node->left = _rbtree_subtree_dup(node->left, new_tree, new_node); + } + + if (node->right == NIL) { + new_node->right = NIL; + } else { + new_node->right = _rbtree_subtree_dup(node->right, new_tree, new_node); + } + + return new_node; +} + +c_rbtree_t *c_rbtree_dup(const c_rbtree_t *tree) { + c_rbtree_t *new_tree = NULL; + + new_tree = (c_rbtree_t*) c_malloc(sizeof(c_rbtree_t)); + + new_tree->key_compare = tree->key_compare; + new_tree->data_compare = tree->data_compare; + new_tree->size = tree->size; + new_tree->root = _rbtree_subtree_dup(tree->root, new_tree, NULL); + + return new_tree; +} + +static int _rbtree_subtree_free(c_rbnode_t *node) { + assert(node); + + if (node->left != NIL) { + if (_rbtree_subtree_free(node->left) < 0) { + /* TODO: set errno? ECANCELED? */ + return -1; + } + } + + if (node->right != NIL) { + if (_rbtree_subtree_free(node->right) < 0) { + /* TODO: set errno? ECANCELED? */ + return -1; + } + } + + SAFE_FREE(node); + + return 0; +} + +int c_rbtree_free(c_rbtree_t *tree) { + if (tree == NULL) { + errno = EINVAL; + return -1; + } + + if (tree->root != NIL) { + _rbtree_subtree_free(tree->root); + } + + SAFE_FREE(tree); + + return 0; +} + +static int _rbtree_subtree_walk(c_rbnode_t *node, void *data, c_rbtree_visit_func *visitor) { + assert(node); + assert(data); + assert(visitor); + + if (node == NIL) { + return 0; + } + + if (_rbtree_subtree_walk(node->left, data, visitor) < 0) { + return -1; + } + + if ((*visitor)(node->data, data) < 0) { + return -1; + } + + if (_rbtree_subtree_walk(node->right, data, visitor) < 0) { + return -1; + } + + return 0; +} + +int c_rbtree_walk(c_rbtree_t *tree, void *data, c_rbtree_visit_func *visitor) { + if (tree == NULL || data == NULL || visitor == NULL) { + errno = EINVAL; + return -1; + } + + if (_rbtree_subtree_walk(tree->root, data, visitor) < 0) { + return -1; + } + + return 0; +} + +static c_rbnode_t *_rbtree_subtree_head(c_rbnode_t *node) { + assert(node); + + if (node == NIL) { + return node; + } + + while (node->left != NIL) { + node = node->left; + } + + return node; +} + +static c_rbnode_t *_rbtree_subtree_tail(c_rbnode_t *node) { + assert(node); + + if (node == NIL) { + return node; + } + + while (node->right != NIL) { + node = node->right; + } + + return node; +} + +c_rbnode_t *c_rbtree_head(c_rbtree_t *tree) { + c_rbnode_t *node = NULL; + + if (tree == NULL) { + errno = EINVAL; + return NULL; + } + + node = _rbtree_subtree_head(tree->root); + + return node != NIL ? node : NULL; +} + +c_rbnode_t *c_rbtree_tail(c_rbtree_t *tree) { + c_rbnode_t *node = NULL; + + if (tree == NULL) { + errno = EINVAL; + return NULL; + } + + node = _rbtree_subtree_tail(tree->root); + + return node != NIL ? node : NULL; +} + +c_rbnode_t *c_rbtree_node_next(c_rbnode_t *node) { + c_rbnode_t *parent = NULL; + + if (node == NULL) { + errno = EINVAL; + return NULL; + } + + if (node->right != NIL) { + c_rbnode_t *next = NULL; + next = _rbtree_subtree_head(node->right); + + return next != NIL ? next : NULL; + } + + parent = node->parent; + while (parent && node == parent->right) { + node = parent; + parent = node->parent; + } + + return parent != NULL ? parent : NULL; +} + +c_rbnode_t *c_rbtree_node_prev(c_rbnode_t *node) { + c_rbnode_t *parent = NULL; + + if (node == NULL) { + return NULL; + } + + if (node->left != NIL) { + c_rbnode_t *prev = NULL; + prev = _rbtree_subtree_tail(node->left); + return prev != NIL ? prev : NULL; + } + + parent = node->parent; + while (parent && node == parent->left) { + node = parent; + parent = node->parent; + } + + return parent != NULL ? parent : NULL; +} + +c_rbnode_t *c_rbtree_find(c_rbtree_t *tree, const void *key) { + int cmp = 0; + c_rbnode_t *node = NULL; + + if (tree == NULL) { + errno = EINVAL; + return NULL; + } + node = tree->root; + + while (node != NIL) { + cmp = tree->key_compare(key, node->data); + if (cmp == 0) { + return node; + } + + if (cmp < 0) { + node = node->left; + } else { + node = node->right; + } + } + + return NULL; +} + +static void _rbtree_subtree_left_rotate(c_rbnode_t *x) { + c_rbnode_t *y = NULL; + + assert(x); + + y = x->right; + + /* establish x-right link */ + x->right = y->left; + + if (y->left != NIL) { + y->left->parent = x; + } + + /* establish y->parent link */ + if (y != NIL) { + y->parent = x->parent; + } + + if (x->parent) { + if (x == x->parent->left) { + x->parent->left = y; + } else { + x->parent->right = y; + } + } else { + x->tree->root = y; + } + + /* link x and y */ + y->left = x; + if (x != NIL) { + x->parent = y; + } +} + +/* rotat node x to the right */ +static void _rbtree_subtree_right_rotate(c_rbnode_t *x) { + c_rbnode_t *y = NULL; + + assert(x); + + y = x->left; + + /* establish x->left link */ + x->left = y->right; + + if (y->right != NIL) { + y->right->parent = x; + } + + /* establish y->parent link */ + if (y != NIL) { + y->parent = x->parent; + } + + if (x->parent) { + if (x == x->parent->right) { + x->parent->right = y; + } else { + x->parent->left = y; + } + } else { + x->tree->root = y; + } + + /* link x and y */ + y->right = x; + if (x != NIL) { + x->parent = y; + } +} + +int c_rbtree_insert(c_rbtree_t *tree, void *data) { + int cmp = 0; + c_rbnode_t *current = NULL; + c_rbnode_t *parent = NULL; + c_rbnode_t *x = NULL; + + if (tree == NULL) { + errno = EINVAL; + return -1; + } + + /* First we do a classic binary tree insert */ + current = tree->root; + parent = NULL; + + while (current != NIL) { + cmp = tree->data_compare(data, current->data); + parent = current; + if (cmp == 0) { + return 1; + } else if (cmp < 0) { + current = current->left; + } else { + current = current->right; + } + } + + x = (c_rbnode_t *) c_malloc(sizeof(c_rbnode_t)); + + x->tree = tree; + x->data = data; + x->parent = parent; + x->left = NIL; + x->right = NIL; + x->color = RED; + + if (parent) { + /* Note that cmp still contains the comparison of data with + * parent->data, from the last pass through the loop above + */ + if (cmp < 0) { + parent->left = x; + } else { + parent->right = x; + } + } else { + tree->root = x; + } + + /* Insert fixup - check red-black properties */ + while (x != tree->root && x->parent->color == RED) { + /* we have a violation */ + if (x->parent == x->parent->parent->left) { + c_rbnode_t *y = NULL; + + y = x->parent->parent->right; + if (y->color == RED) { + x->parent->color = BLACK; + y->color = BLACK; + x->parent->parent->color = RED; + x = x->parent->parent; + } else { + /* uncle is back */ + if (x == x->parent->right) { + /* make x a left child */ + x = x->parent; + _rbtree_subtree_left_rotate(x); + } + x->parent->color = BLACK; + x->parent->parent->color = RED; + _rbtree_subtree_right_rotate(x->parent->parent); + } + } else { + c_rbnode_t *y = NULL; + + y = x->parent->parent->left; + if (y->color == RED) { + x->parent->color = BLACK; + y->color = BLACK; + x->parent->parent->color = RED; + x = x->parent->parent; + } else { + /* uncle is back */ + if (x == x->parent->left) { + x = x->parent; + _rbtree_subtree_right_rotate(x); + } + x->parent->color = BLACK; + x->parent->parent->color = RED; + _rbtree_subtree_left_rotate(x->parent->parent); + } + } + } /* end while */ + tree->root->color = BLACK; + + tree->size++; + + return 0; +} + +int c_rbtree_node_delete(c_rbnode_t *node) { + c_rbtree_t *tree; + c_rbnode_t *y; + c_rbnode_t *x; + + if (node == NULL || node == NIL) { + errno = EINVAL; + return -1; + } + + tree = node->tree; + + if (node->left == NIL || node->right == NIL) { + /* y has a NIL node as a child */ + y = node; + } else { + /* find tree successor with a NIL node as a child */ + y = node; + while(y->left != NIL) { + y = y->left; + } + } + + /* x is y's only child */ + if (y->left != NIL) { + x = y->left; + } else { + x = y->right; + } + + /* remove y from the parent chain */ + x->parent = y->parent; + + if (y->parent) { + if (y == y->parent->left) { + y->parent->left = x; + } else { + y->parent->right = x; + } + } else { + y->tree->root = x; + } + + /* If y is not the node we're deleting, splice it in place of that + * node + * + * The traditional code would call for us to simply copy y->data, but + * that would invalidate the wrong pointer - there might be external + * references to this node, and we must preserve its address. + */ + if (y != node) { + /* Update y */ + y->parent = node->parent; + y->left = node->left; + y->right = node->right; + + /* Update the children and the parent */ + if (y->left != NIL) { + y->left->parent = y; + } + if (y->right != NIL) { + y->right->parent = y; + } + if (y->parent != NULL) { + if (node == y->parent->left) { + y->parent->left = y; + } else { + y->parent->right = y; + } + } else { + y->tree->root = y; + } + } + + if (y->color == BLACK) { + while (x != y->tree->root && x->color == BLACK) { + if (x == x->parent->left) { + c_rbnode_t *w = NULL; + + w = x->parent->right; + + if (w->color == RED) { + w->color = BLACK; + x->parent->color = RED; + _rbtree_subtree_left_rotate(x->parent); + w = x->parent->right; + } + + if (w->left->color == BLACK && w->right->color == BLACK) { + w->color = RED; + x = x->parent; + } else { + if (w->right->color == BLACK) { + w->left->color = BLACK; + w->color = RED; + _rbtree_subtree_right_rotate(w); + w = x->parent->right; + } + w->color = x->parent->color; + x->parent->color = BLACK; + w->right->color = BLACK; + _rbtree_subtree_left_rotate(x->parent); + x = y->tree->root; + } + } else { + c_rbnode_t *w = NULL; + + w = x->parent->left; + if (w->color == RED) { + w->color = BLACK; + x->parent->color = RED; + _rbtree_subtree_right_rotate(x->parent); + w = x->parent->left; + } + + if (w->right->color == BLACK && w->left->color == BLACK) { + w->color = RED; + x = x->parent; + } else { + if (w->left->color == BLACK) { + w->right->color = BLACK; + w->color = RED; + _rbtree_subtree_left_rotate(w); + w = x->parent->left; + } + w->color = x->parent->color; + x->parent->color = BLACK; + w->left->color = BLACK; + _rbtree_subtree_right_rotate(x->parent); + x = y->tree->root; + } + } + } + x->color = BLACK; + } /* end if: y->color == BLACK */ + + /* node has now been spliced out of the tree */ + SAFE_FREE(y); + tree->size--; + + return 0; +} + +static int _rbtree_subtree_check_black_height(c_rbnode_t *node) { + int left = 0; + int right = 0; + + assert(node); + + if (node == NIL) { + return 0; + } + + left = _rbtree_subtree_check_black_height(node->left); + right = _rbtree_subtree_check_black_height(node->right); + if (left != right) { + return -1; + } + + return left + (node->color == BLACK); +} + +int c_rbtree_check_sanity(c_rbtree_t *tree) { + c_rbnode_t *node = NULL; + c_rbnode_t *prev = NULL; + c_rbnode_t *next = NULL; + c_rbnode_t *tail = NULL; + size_t size = 0; + + if (tree == NULL) { + errno = EINVAL; + return -1; + } + + if (! tree->key_compare || ! tree->data_compare) { + errno = EINVAL; + return -2; + } + + /* Iterate the tree */ + tail = c_rbtree_tail(tree); + for (node = c_rbtree_head(tree); node; node = next) { + if (node->tree != tree) { + return -4; + } + + /* We should never see a nil while iterating */ + if (node == NIL) { + return -5; + } + + /* node == tree-root iff node->parent == NIL */ + if (node == tree->root) { + if (node->parent != NULL) { + return -6; + } + } else { + if (node->parent == NULL) { + return -7; + } + } + + /* Invertability of the iterate functions */ + if (prev != c_rbtree_node_prev(node)) { + return -8; + } + + /* Check the iteration sequence */ + if (prev) { + if (tree->data_compare(prev->data, node->data) > 0) { + return -9; + } + + /* And the other way around, to make sure data_compare is stable */ + if (tree->data_compare(node->data, prev->data) < 0) { + return -10; + } + } + + /* The binary tree property */ + if (node->left != NIL) { + if (tree->data_compare(node->left->data, node->data) > 0) { + return -11; + } + + if (tree->data_compare(node->data, node->left->data) < 0) { + return -11; + } + } + + if (node->right != NIL) { + if (tree->data_compare(node->data, node->right->data) > 0) { + return -12; + } + + if (tree->data_compare(node->right->data, node->data) < 0) { + return -13; + } + } + + /* Red-black tree property 3: red nodes have black children */ + if (node->color == RED) { + if (node->left->color == RED) { + return -14; + } + if (node->right->color == RED) { + return -15; + } + } + + /* next == NULL if node == tail */ + next = c_rbtree_node_next(node); + if (next) { + if (node == tail) { + return -16; + } + } else { + if (node != tail) { + return -17; + } + } + + prev = node; + size++; + } /* end for loop */ + + if (size != tree->size) { + return -18; + } + + if (_rbtree_subtree_check_black_height(tree->root) < 0) { + return -19; + } + + return 0; +} diff --git a/src/csync/std/c_rbtree.h b/src/csync/std/c_rbtree.h new file mode 100644 index 000000000..635458fd2 --- /dev/null +++ b/src/csync/std/c_rbtree.h @@ -0,0 +1,309 @@ +/* + * cynapses libc functions + * + * Copyright (c) 2003-2004 by Andrew Suffield + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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_rbtree.h + * + * @brief Interface of the cynapses libc red-black tree implementation + * + * A red-black tree is a type of self-balancing binary search tree. It is + * complex, but has good worst-case running time for its operations and is + * efficient in practice: it can search, insert, and delete in O(log n) + * time, where n is the number of elements in the tree. + * + * In red-black trees, the leaf nodes are not relevant and do not contain + * data. Therefore we use a sentinal node to save memory. All references + * from internal nodes to leaf nodes instead point to the sentinel node. + * + * In a red-black tree each node has a color attribute, the value of which + * is either red or black. In addition to the ordinary requirements imposed + * on binary search trees, the following additional requirements of any + * valid red-black tree apply: + * + * 1. A node is either red or black. + * 2. The root is black. + * 3. All leaves are black, even when the parent is black + * (The leaves are the null children.) + * 4. Both children of every red node are black. + * 5. Every simple path from a node to a descendant leaf contains the same + * number of black nodes, either counting or not counting the null black + * nodes. (Counting or not counting the null black nodes does not affect + * the structure as long as the choice is used consistently.). + * + * These constraints enforce a critical property of red-black trees: that the + * longest path from the root to a leaf is no more than twice as long as the + * shortest path from the root to a leaf in that tree. The result is that the + * tree is roughly balanced. Since operations such as inserting, deleting, and + * finding values requires worst-case time proportional to the height of the + * tree, this theoretical upper bound on the height allows red-black trees to + * be efficient in the worst-case, unlike ordinary binary search trees. + * + * http://en.wikipedia.org/wiki/Red-black_tree + * + * @defgroup cynRBTreeInternals cynapses libc red-black tree functions + * @ingroup cynLibraryAPI + * + * @{ + */ +#ifndef _C_RBTREE_H +#define _C_RBTREE_H + +/* Forward declarations */ +struct c_rbtree_s; typedef struct c_rbtree_s c_rbtree_t; +struct c_rbnode_s; typedef struct c_rbnode_s c_rbnode_t; + +/** + * Define the two colors for the red-black tree + */ +enum xrbcolor_e { BLACK = 0, RED }; typedef enum xrbcolor_e xrbcolor_t; + +/** + * @brief Callback function to compare a key with the data from a + * red-black tree node. + * + * @param key key as a generic pointer + * @param data data as a generic pointer + * + * @return It returns an integer less than, equal to, or greater than zero + * depending on the key or data you use. The function is similar + * to strcmp(). + */ +typedef int c_rbtree_compare_func(const void *key, const void *data); + +/** + * @brief Visit function for the c_rbtree_walk() function. + * + * This function will be called by c_rbtree_walk() for every node. It is up to + * the developer what the function does. The fist parameter is a node object + * the second can be of any kind. + * + * @param obj The node data that will be passed by c_rbtree_walk(). + * @param data Generic data pointer. + * + * @return 0 on success, < 0 on error. You should set errno. + * + */ +typedef int c_rbtree_visit_func(void *, void *); + +/** + * Structure that represents a red-black tree + */ +struct c_rbtree_s { + c_rbnode_t *root; + c_rbtree_compare_func *key_compare; + c_rbtree_compare_func *data_compare; + size_t size; +}; + +/** + * Structure that represents a node of a red-black tree + */ +struct c_rbnode_s { + c_rbtree_t *tree; + c_rbnode_t *left; + c_rbnode_t *right; + c_rbnode_t *parent; + void *data; + xrbcolor_t color; +}; + +/** + * @brief Create the red-black tree + * + * @param rbtree The pointer to assign the allocated memory. + * + * @param key_compare Callback function to compare a key with the data + * inside a reb-black tree node. + * + * @param data_compare Callback function to compare a key as data with thee + * data inside a red-black tree node. + */ +void c_rbtree_create(c_rbtree_t **rbtree, c_rbtree_compare_func *key_compare, c_rbtree_compare_func *data_compare); + +/** + * @brief Duplicate a red-black tree. + * + * @param tree Tree to duplicate. + * + * @return Pointer to a new allocated duplicated rbtree. NULL if an error + * occurred. + */ +c_rbtree_t *c_rbtree_dup(const c_rbtree_t *tree); + +/** + * @brief Free the structure of a red-black tree. + * + * You should call c_rbtree_destroy() before you call this function. + * + * @param tree The tree to free. + * + * @return 0 on success, less than 0 if an error occurred. + */ +int c_rbtree_free(c_rbtree_t *tree); + +/** + * @brief Destroy the content and the nodes of an red-black tree. + * + * This is far from the most efficient way to walk a tree, but it is + * the *safest* way to destroy a tree - the destructor can do almost + * anything (as long as it does not create an infinite loop) to the + * tree structure without risk. + * + * If for some strange reason you need a faster destructor (think + * twice - speed and memory deallocation don't mix well) then consider + * stashing an llist of dataects and destroying that instead, and just + * using c_rbtree_free() on your tree. + * + * @param T The tree to destroy. + * @param DESTRUCTOR The destructor to call on a node to destroy. + */ +#define c_rbtree_destroy(T, DESTRUCTOR) \ + do { \ + if (T) { \ + c_rbnode_t *_c_rbtree_temp; \ + while ((_c_rbtree_temp = c_rbtree_head(T))) { \ + (DESTRUCTOR)(_c_rbtree_temp->data); \ + if (_c_rbtree_temp == c_rbtree_head(T)) { \ + c_rbtree_node_delete(_c_rbtree_temp); \ + } \ + } \ + } \ + SAFE_FREE(T); \ + } while (0); + +/** + * @brief Inserts a node into a red black tree. + * + * @param tree The red black tree to insert the node. + * @param data The data to insert into the tree. + * + * @return 0 on success, 1 if a duplicate has been found and < 0 if an error + * occurred with errno set. + * EINVAL if a null pointer has been passed as the tree. + * ENOMEM if there is no memory left. + */ +int c_rbtree_insert(c_rbtree_t *tree, void *data); + +/** + * @brief Find a node in a red-black tree. + * + * c_rbtree_find() is searching for the given key in a red-black tree and + * returns the node if the key has been found. + * + * @param tree The tree to search. + * @param key The key to search for. + * + * @return If the key was found the node will be returned. On error NULL + * will be returned. + */ +c_rbnode_t *c_rbtree_find(c_rbtree_t *tree, const void *key); + +/** + * @brief Get the head of the red-black tree. + * + * @param tree The tree to get the head for. + * + * @return The head node. NULL if an error occurred. + */ +c_rbnode_t *c_rbtree_head(c_rbtree_t *tree); + +/** + * @brief Get the tail of the red-black tree. + * + * @param tree The tree to get the tail for. + * + * @return The tail node. NULL if an error occurred. + */ +c_rbnode_t *c_rbtree_tail(c_rbtree_t *tree); + +/** + * @brief Get the size of the red-black tree. + * + * @param T The tree to get the size from. + * + * @return The size of the red-black tree. + */ +#define c_rbtree_size(T) (T) == NULL ? 0 : ((T)->size) + +/** + * @brief Walk over a red-black tree. + * + * Walk over a red-black tree calling a visitor function for each node found. + * + * @param tree Tree to walk. + * @param data Data which should be passed to the visitor function. + * @param visitor Visitor function. This will be called for each node passed. + * + * @return 0 on sucess, less than 0 if an error occurred. + */ +int c_rbtree_walk(c_rbtree_t *tree, void *data, c_rbtree_visit_func *visitor); + +/** + * @brief Delete a node in a red-black tree. + * + * @param node Node which should be deleted. + * + * @return 0 on success, -1 if an error occurred. + */ +int c_rbtree_node_delete(c_rbnode_t *node); + +/** + * @brief Get the next node. + * + * @param node The node of which you want the next node. + * + * @return The next node, NULL if an error occurred. + */ +c_rbnode_t *c_rbtree_node_next(c_rbnode_t *node); + +/** + * @brief Get the previous node. + * + * @param node The node of which you want the previous node. + * + * @return The previous node, NULL if an error occurred. + */ +c_rbnode_t *c_rbtree_node_prev(c_rbnode_t *node); + +/** + * @brief Get the data of a node. + * + * @param N The node to get the data from. + * + * @return The data, NULL if an error occurred. + */ +#define c_rbtree_node_data(N) ((N) ? ((N)->data) : NULL) + +/** + * @brief Perform a sanity check for a red-black tree. + * + * This is mostly for testing purposes. + * + * @param tree The tree to check. + * + * @return 0 on success, less than 0 if an error occurred. + */ +int c_rbtree_check_sanity(c_rbtree_t *tree); + +/** + * }@ + */ +#endif /* _C_RBTREE_H */ diff --git a/src/csync/std/c_string.c b/src/csync/std/c_string.c new file mode 100644 index 000000000..8929f2458 --- /dev/null +++ b/src/csync/std/c_string.c @@ -0,0 +1,169 @@ +/* + * cynapses libc functions + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2012-2013 by Klaas Freitag + * + * 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 "config_csync.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "c_string.h" +#include "c_path.h" +#include "c_alloc.h" +#include "c_macro.h" + +#ifdef _WIN32 +#include +#endif + +int c_strncasecmp(const char *a, const char *b, size_t n) { +#ifdef _WIN32 + return _strnicmp(a, b, n); +#else + return strncasecmp(a, b, n); +#endif +} + +int c_streq(const char *a, const char *b) { + register const char *s1 = a; + register const char *s2 = b; + + if (s1 == NULL || s2 == NULL) { + return 0; + } + + while (*s1 == *s2++) { + if (*s1++ == '\0') { + return 1; + } + } + + return 0; +} + +c_strlist_t *c_strlist_new(size_t size) { + c_strlist_t *strlist = NULL; + + if (size == 0) { + errno = EINVAL; + return NULL; + } + + strlist = c_malloc(sizeof(c_strlist_t)); + if (strlist == NULL) { + return NULL; + } + + strlist->vector = (char **) c_malloc(size * sizeof(char *)); + strlist->count = 0; + strlist->size = size; + + return strlist; +} + +c_strlist_t *c_strlist_expand(c_strlist_t *strlist, size_t size) { + if (strlist == NULL || size == 0) { + errno = EINVAL; + return NULL; + } + + if (strlist->size >= size) { + return strlist; + } + + strlist->vector = (char **) c_realloc(strlist->vector, size * sizeof(char *)); + if (strlist->vector == NULL) { + return NULL; + } + + strlist->size = size; + + return strlist; +} + +int c_strlist_add(c_strlist_t *strlist, const char *string) { + if (strlist == NULL || string == NULL) { + return -1; + } + + if (strlist->count < strlist->size) { + strlist->vector[strlist->count] = c_strdup(string); + if (strlist->vector[strlist->count] == NULL) { + return -1; + } + strlist->count++; + } else { + errno = ENOBUFS; + return -1; + } + + return 0; +} + +int c_strlist_add_grow(c_strlist_t **strlist, const char *string) { + if (*strlist == NULL) { + *strlist = c_strlist_new(32); + if (*strlist == NULL) { + return -1; + } + } + + if ((*strlist)->count == (*strlist)->size) { + c_strlist_t *list = c_strlist_expand(*strlist, 2 * (*strlist)->size); + if (list == NULL) { + return -1; + } + *strlist = list; + } + + return c_strlist_add(*strlist, string); +} + +void c_strlist_clear(c_strlist_t *strlist) { + size_t i = 0; + + if (strlist == NULL) { + return; + } + + for (i = 0; i < strlist->count; i++) { + SAFE_FREE(strlist->vector[i]); + } + + strlist->count = 0; +} + +void c_strlist_destroy(c_strlist_t *strlist) { + + if (strlist == NULL) { + return; + } + + c_strlist_clear(strlist); + SAFE_FREE(strlist->vector); + SAFE_FREE(strlist); +} diff --git a/src/csync/std/c_string.h b/src/csync/std/c_string.h new file mode 100644 index 000000000..304c598a2 --- /dev/null +++ b/src/csync/std/c_string.h @@ -0,0 +1,221 @@ +/* + * cynapses libc functions + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2012-2013 by Klaas Freitag + * + * 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_string.h + * + * @brief Interface of the cynapses string implementations + * + * @defgroup cynStringInternals cynapses libc string functions + * @ingroup cynLibraryAPI + * + * @{ + */ +#ifndef _C_STR_H +#define _C_STR_H + +#include "c_private.h" +#include "c_macro.h" + +#include + +struct c_strlist_s; typedef struct c_strlist_s c_strlist_t; + +/** + * @brief Structure for a stringlist + * + * Using a for loop you can access the strings saved in the vector. + * + * c_strlist_t strlist; + * int i; + * for (i = 0; i < strlist->count; i++) { + * printf("value: %s", strlist->vector[i]; + * } + */ +struct c_strlist_s { + /** The string vector */ + char **vector; + /** The count of the strings saved in the vector */ + size_t count; + /** Size of strings allocated */ + size_t size; +}; + +/** + * @brief Compare to strings case insensitively. + * + * @param a First string to compare. + * @param b Second string to compare. + * @param n Max comparison length. + * + * @return see strncasecmp + */ +int c_strncasecmp(const char *a, const char *b, size_t n); + +/** + * @brief Compare to strings if they are equal. + * + * @param a First string to compare. + * @param b Second string to compare. + * + * @return 1 if they are equal, 0 if not. + */ +int c_streq(const char *a, const char *b); + +/** + * @brief Create a new stringlist. + * + * @param size Size to allocate. + * + * @return Pointer to the newly allocated stringlist. NULL if an error occured. + */ +c_strlist_t *c_strlist_new(size_t size); + +/** + * @brief Expand the stringlist + * + * @param strlist Stringlist to expand + * @param size New size of the strlinglist to expand + * + * @return Pointer to the expanded stringlist. NULL if an error occured. + */ +c_strlist_t *c_strlist_expand(c_strlist_t *strlist, size_t size); + +/** + * @brief Add a string to the stringlist. + * + * Duplicates the string and stores it in the stringlist. + * + * @param strlist Stringlist to add the string. + * @param string String to add. + * + * @return 0 on success, less than 0 and errno set if an error occured. + * ENOBUFS if the list is full. + */ +int c_strlist_add(c_strlist_t *strlist, const char *string); + +/** + * @brief Add a string to the stringlist, growing it if necessary + * + * Duplicates the string and stores it in the stringlist. + * It also initializes the stringlist if it starts out as null. + * + * @param strlist Stringlist to add the string. + * @param string String to add. + * + * @return 0 on success, less than 0 and errno set if an error occured. + */ +int c_strlist_add_grow(c_strlist_t **strlist, const char *string); + +/** + * @brief Removes all strings from the list. + * + * Frees the strings. + * + * @param strlist Stringlist to clear + */ +void c_strlist_clear(c_strlist_t *strlist); + +/** + * @brief Destroy the memory of the stringlist. + * + * Frees the strings and the stringlist. + * + * @param strlist Stringlist to destroy + */ +void c_strlist_destroy(c_strlist_t *strlist); + +/** + * @brief Convert a platform locale string to utf8. + * + * This function is part of the multi platform abstraction of basic file + * operations to handle various platform encoding correctly. + * + * Instead of using the standard file operations the multi platform aliases + * defined in c_private.h have to be used instead. + * + * To convert path names returned by these functions to the internally used + * utf8 format this function has to be used. The returned string has to + * be freed by c_free_locale_string(). On some platforms this method allocates + * memory and on others not but it has never to be cared about. + * + * @param str The multibyte encoded string to convert + * + * @return The malloced converted string or NULL on error. + * + * @see c_free_locale_string() + * @see c_utf8_to_locale() + * + */ + char* c_utf8_from_locale(const mbchar_t *str); + +/** + * @brief Convert a utf8 encoded string to platform specific locale. + * + * This function is part of the multi platform abstraction of basic file + * operations to handle various platform encoding correctly. + * + * Instead of using the standard file operations the multi platform aliases + * defined in c_private.h have to be used instead. + * + * To convert strings as input for the cross platform functions from the + * internally used utf8 format, this function has to be used. + * The returned string has to be freed by c_free_locale_string(). On some + * platforms this method allocates memory and on others not but it has never + * sto be cared about. + * + * If the string to convert is a path, consider using c_utf8_path_to_locale(). + * + * @param str The utf8 string to convert. + * + * @return The malloced converted multibyte string or NULL on error. + * + * @see c_free_locale_string() + * @see c_utf8_from_locale() + * + */ +mbchar_t* c_utf8_string_to_locale(const char *wstr); + +/** + * @brief Free buffer malloced by c_utf8_from_locale or c_utf8_to_locale(). + * + * This function is part of the multi platform abstraction of basic file + * operations to handle various platform encoding correctly. + * + * Instead of using the standard file operations the multi platform aliases + * defined in c_private.h have to be used instead. + * + * This function frees the memory that was allocated by a previous call to + * c_utf8_to_locale() or c_utf8_from_locale(). + * + * @param buf The buffer to free. + * + * @see c_utf8_from_locale(), c_utf8_to_locale() + * + */ +#define c_free_locale_string(x) SAFE_FREE(x) + + +/** + * }@ + */ +#endif /* _C_STR_H */ + diff --git a/src/csync/std/c_time.c b/src/csync/std/c_time.c new file mode 100644 index 000000000..ad43fed02 --- /dev/null +++ b/src/csync/std/c_time.c @@ -0,0 +1,154 @@ +/* + * c_time - time functions + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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 "config_csync.h" +#include "c_private.h" +#include "c_string.h" + +#include "c_path.h" +#include "c_time.h" + +#ifndef _WIN32 +#include +#endif + +struct timespec c_tspecdiff(struct timespec time1, struct timespec time0) { + struct timespec ret; + int xsec = 0; + int sign = 1; + + if (time0.tv_nsec > time1.tv_nsec) { + xsec = (int) ((time0.tv_nsec - time1.tv_nsec) / (1E9 + 1)); + time0.tv_nsec -= (long int) (1E9 * xsec); + time0.tv_sec += xsec; + } + + if ((time1.tv_nsec - time0.tv_nsec) > 1E9) { + xsec = (int) ((time1.tv_nsec - time0.tv_nsec) / 1E9); + time0.tv_nsec += (long int) (1E9 * xsec); + time0.tv_sec -= xsec; + } + + ret.tv_sec = time1.tv_sec - time0.tv_sec; + ret.tv_nsec = time1.tv_nsec - time0.tv_nsec; + + if (time1.tv_sec < time0.tv_sec) { + sign = -1; + } + + ret.tv_sec = ret.tv_sec * sign; + + return ret; +} + +double c_secdiff(struct timespec clock1, struct timespec clock0) { + double ret; + struct timespec diff; + + diff = c_tspecdiff(clock1, clock0); + + ret = diff.tv_sec; + ret += (double) diff.tv_nsec / (double) 1E9; + + return ret; +} + + +#ifdef HAVE_UTIMES +int c_utimes(const char *uri, const struct timeval *times) { + mbchar_t *wuri = c_utf8_path_to_locale(uri); + int ret = utimes(wuri, times); + c_free_locale_string(wuri); + return ret; +} +#else // HAVE_UTIMES + +#ifdef _WIN32 +// implementation for utimes taken from KDE mingw headers + +#include +#include +#define CSYNC_SECONDS_SINCE_1601 11644473600LL +#define CSYNC_USEC_IN_SEC 1000000LL +//after Microsoft KB167296 +static void UnixTimevalToFileTime(struct timeval t, LPFILETIME pft) +{ + LONGLONG ll; + ll = Int32x32To64(t.tv_sec, CSYNC_USEC_IN_SEC*10) + t.tv_usec*10 + CSYNC_SECONDS_SINCE_1601*CSYNC_USEC_IN_SEC*10; + pft->dwLowDateTime = (DWORD)ll; + pft->dwHighDateTime = ll >> 32; +} + +int c_utimes(const char *uri, const struct timeval *times) { + FILETIME LastAccessTime; + FILETIME LastModificationTime; + HANDLE hFile; + + mbchar_t *wuri = c_utf8_path_to_locale( uri ); + + if(times) { + UnixTimevalToFileTime(times[0], &LastAccessTime); + UnixTimevalToFileTime(times[1], &LastModificationTime); + } + else { + GetSystemTimeAsFileTime(&LastAccessTime); + GetSystemTimeAsFileTime(&LastModificationTime); + } + + hFile=CreateFileW(wuri, FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL+FILE_FLAG_BACKUP_SEMANTICS, NULL); + if(hFile==INVALID_HANDLE_VALUE) { + switch(GetLastError()) { + case ERROR_FILE_NOT_FOUND: + errno=ENOENT; + break; + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: + errno=ENOTDIR; + break; + /*case ERROR_WRITE_PROTECT: //CreateFile sets ERROR_ACCESS_DENIED on read-only devices + * errno=EROFS; + * break;*/ + case ERROR_ACCESS_DENIED: + errno=EACCES; + break; + default: + errno=ENOENT; //what other errors can occur? + } + + return -1; + } + + if(!SetFileTime(hFile, NULL, &LastAccessTime, &LastModificationTime)) { + //can this happen? + errno=ENOENT; + CloseHandle(hFile); + c_free_locale_string(wuri); + return -1; + } + + CloseHandle(hFile); + c_free_locale_string(wuri); + + return 0; +} + +#endif // _WIN32 +#endif // HAVE_UTIMES diff --git a/src/csync/std/c_time.h b/src/csync/std/c_time.h new file mode 100644 index 000000000..aa8ef2f16 --- /dev/null +++ b/src/csync/std/c_time.h @@ -0,0 +1,55 @@ +/* + * c_time - time functions + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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 _C_TIME_H +#define _C_TIME_H + +#include + +/** + * @brief Calculate time difference + * + * The c_tspecdiff function returns the time elapsed between time time1 and time + * time0 represented as timespec. + * + * @param time1 The time. + * @param time0 The time. + * + * @return time elapsed between time1 and time0. + */ +struct timespec c_tspecdiff(struct timespec time1, struct timespec time0); + +/** + * @brief Calculate time difference. + * + * The function returns the time elapsed between time clock1 and time + * clock0 represented as double (in seconds and milliseconds). + * + * @param clock1 The time. + * @param clock0 The time. + * + * @return time elapsed between clock1 and clock0 in seconds and + * milliseconds. + */ +double c_secdiff(struct timespec clock1, struct timespec clock0); + +int c_utimes(const char *uri, const struct timeval *times); + +#endif /* _C_TIME_H */ diff --git a/src/csync/std/c_utf8.cc b/src/csync/std/c_utf8.cc new file mode 100644 index 000000000..4bd5d75ac --- /dev/null +++ b/src/csync/std/c_utf8.cc @@ -0,0 +1,104 @@ +/* + * cynapses libc functions + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2012-2013 by Klaas Freitag + * + * 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 "config_csync.h" + +#ifdef _WIN32 +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#endif + +extern "C" { +#include "c_alloc.h" +#include "c_string.h" + +/* Convert a locale String to UTF8 */ +char* c_utf8_from_locale(const mbchar_t *wstr) +{ + if (wstr == NULL) { + return NULL; + } + +#ifdef _WIN32 + char *dst = NULL; + char *mdst = NULL; + int size_needed; + size_t len; + len = wcslen(wstr); + /* Call once to get the required size. */ + size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, len, NULL, 0, NULL, NULL); + if (size_needed > 0) { + mdst = (char*)c_malloc(size_needed + 1); + + memset(mdst, 0, size_needed + 1); + WideCharToMultiByte(CP_UTF8, 0, wstr, len, mdst, size_needed, NULL, NULL); + dst = mdst; + } + return dst; +#else + QTextDecoder dec(QTextCodec::codecForLocale()); + QString s = dec.toUnicode(wstr, qstrlen(wstr)); + if (s.isEmpty() || dec.hasFailure()) { + /* Conversion error: since we can't report error from this function, just return the original + string. We take care of invalid utf-8 in SyncEngine::treewalkFile */ + return c_strdup(wstr); + } +#ifdef __APPLE__ + s = s.normalized(QString::NormalizationForm_C); +#endif + return c_strdup(std::move(s).toUtf8().constData()); +#endif +} + +/* Convert a an UTF8 string to locale */ +mbchar_t* c_utf8_string_to_locale(const char *str) +{ + if (str == NULL ) { + return NULL; + } +#ifdef _WIN32 + mbchar_t *dst = NULL; + size_t len; + int size_needed; + + len = strlen(str); + size_needed = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0); + if (size_needed > 0) { + int size_char = (size_needed + 1) * sizeof(mbchar_t); + dst = (mbchar_t*)c_malloc(size_char); + memset((void*)dst, 0, size_char); + MultiByteToWideChar(CP_UTF8, 0, str, -1, dst, size_needed); + } + return dst; +#else + return c_strdup(QFile::encodeName(QString::fromUtf8(str))); +#endif +} + +} diff --git a/src/csync/vio/csync_vio.c b/src/csync/vio/csync_vio.c new file mode 100644 index 000000000..909117836 --- /dev/null +++ b/src/csync/vio/csync_vio.c @@ -0,0 +1,133 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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 _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include + +#include "csync_private.h" +#include "csync_util.h" +#include "vio/csync_vio.h" +#include "vio/csync_vio_local.h" +#include "csync_statedb.h" +#include "std/c_jhash.h" + +#define CSYNC_LOG_CATEGORY_NAME "csync.vio.main" + +#include "csync_log.h" + +csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name) { + switch(ctx->replica) { + case REMOTE_REPLICA: + if(ctx->remote.read_from_db) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Read from db flag is true, should not!" ); + } + return ctx->callbacks.remote_opendir_hook(name, ctx->callbacks.vio_userdata); + break; + case LOCAL_REPLICA: + if( ctx->callbacks.update_callback ) { + ctx->callbacks.update_callback(ctx->replica, name, ctx->callbacks.update_callback_userdata); + } + return csync_vio_local_opendir(name); + break; + default: + CSYNC_LOG(CSYNC_LOG_PRIORITY_ALERT, "Invalid replica (%d)", (int)ctx->replica); + break; + } + return NULL; +} + +int csync_vio_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle) { + int rc = -1; + + if (dhandle == NULL) { + errno = EBADF; + return -1; + } + + switch(ctx->replica) { + case REMOTE_REPLICA: + if( ctx->remote.read_from_db ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote ReadFromDb is true, should not!"); + } + ctx->callbacks.remote_closedir_hook(dhandle, ctx->callbacks.vio_userdata); + rc = 0; + break; + case LOCAL_REPLICA: + rc = csync_vio_local_closedir(dhandle); + break; + default: + CSYNC_LOG(CSYNC_LOG_PRIORITY_ALERT, "Invalid replica (%d)", (int)ctx->replica); + break; + } + return rc; +} + +csync_vio_file_stat_t *csync_vio_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle) { + switch(ctx->replica) { + case REMOTE_REPLICA: + if( ctx->remote.read_from_db ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote readfromdb is true, should not!"); + } + return ctx->callbacks.remote_readdir_hook(dhandle, ctx->callbacks.vio_userdata); + break; + case LOCAL_REPLICA: + return csync_vio_local_readdir(dhandle); + break; + default: + CSYNC_LOG(CSYNC_LOG_PRIORITY_ALERT, "Invalid replica (%d)", (int)ctx->replica); + break; + } + + return NULL; +} + + +int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) { + int rc = -1; + + switch(ctx->replica) { + case REMOTE_REPLICA: + 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); + if (rc < 0) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Local stat failed, errno %d for %s", errno, uri); + } + break; + default: + break; + } + + return rc; +} + +char *csync_vio_get_status_string(CSYNC *ctx) { + if(ctx->error_string) { + return ctx->error_string; + } + return 0; +} diff --git a/src/csync/vio/csync_vio.h b/src/csync/vio/csync_vio.h new file mode 100644 index 000000000..715b18542 --- /dev/null +++ b/src/csync/vio/csync_vio.h @@ -0,0 +1,44 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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_VIO_H +#define _CSYNC_VIO_H + +#include +#include +#include +#include "c_private.h" +#include "csync.h" +#include "csync_private.h" + +typedef struct fhandle_s { + int fd; +} fhandle_t; + +csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name); +int csync_vio_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle); +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); + +char *csync_vio_get_status_string(CSYNC *ctx); + + +#endif /* _CSYNC_VIO_H */ diff --git a/src/csync/vio/csync_vio_file_stat.c b/src/csync/vio/csync_vio_file_stat.c new file mode 100644 index 000000000..8ebb64f33 --- /dev/null +++ b/src/csync/vio/csync_vio_file_stat.c @@ -0,0 +1,85 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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 "c_lib.h" +#include "csync.h" +#include "csync_log.h" + +csync_vio_file_stat_t *csync_vio_file_stat_new(void) { + 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; +} + +csync_vio_file_stat_t* csync_vio_file_stat_copy(csync_vio_file_stat_t *file_stat) { + csync_vio_file_stat_t *file_stat_cpy = csync_vio_file_stat_new(); + memcpy(file_stat_cpy, file_stat, sizeof(csync_vio_file_stat_t)); + if (file_stat_cpy->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) { + file_stat_cpy->etag = c_strdup(file_stat_cpy->etag); + } + if (file_stat_cpy->directDownloadCookies) { + file_stat_cpy->directDownloadCookies = c_strdup(file_stat_cpy->directDownloadCookies); + } + if (file_stat_cpy->directDownloadUrl) { + file_stat_cpy->directDownloadUrl = c_strdup(file_stat_cpy->directDownloadUrl); + } + if (file_stat_cpy->checksumHeader) { + file_stat_cpy->checksumHeader = c_strdup(file_stat_cpy->checksumHeader); + } + file_stat_cpy->name = c_strdup(file_stat_cpy->name); + return file_stat_cpy; +} + +void csync_vio_file_stat_destroy(csync_vio_file_stat_t *file_stat) { + /* FIXME: free rest */ + if (file_stat == NULL) { + return; + } + + 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->original_name); + SAFE_FREE(file_stat->checksumHeader); + SAFE_FREE(file_stat); +} + +void csync_vio_file_stat_set_file_id( csync_vio_file_stat_t *dst, const char* src ) { + + csync_vio_set_file_id( dst->file_id, src ); + if( c_streq( dst->file_id, "" )) { + return; + } + dst->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FILE_ID; +} + +void csync_vio_set_file_id( char* dst, const char *src ) { + if( src && dst ) { + if( strlen(src) > FILE_ID_BUF_SIZE ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Ignoring file_id because it is too long: %s", src); + strcpy(dst, ""); + } else { + strcpy(dst, src); + } + } +} diff --git a/src/csync/vio/csync_vio_local.h b/src/csync/vio/csync_vio_local.h new file mode 100644 index 000000000..294383121 --- /dev/null +++ b/src/csync/vio/csync_vio_local.h @@ -0,0 +1,30 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * + * 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_VIO_LOCAL_H +#define _CSYNC_VIO_LOCAL_H + +csync_vio_handle_t OCSYNC_EXPORT *csync_vio_local_opendir(const char *name); +int OCSYNC_EXPORT csync_vio_local_closedir(csync_vio_handle_t *dhandle); +csync_vio_file_stat_t OCSYNC_EXPORT *csync_vio_local_readdir(csync_vio_handle_t *dhandle); + +int OCSYNC_EXPORT csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf); + +#endif /* _CSYNC_VIO_LOCAL_H */ diff --git a/src/csync/vio/csync_vio_local_unix.c b/src/csync/vio/csync_vio_local_unix.c new file mode 100644 index 000000000..5d5666688 --- /dev/null +++ b/src/csync/vio/csync_vio_local_unix.c @@ -0,0 +1,223 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2013- by Klaas Freitag + * + * 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 +#include +#include +#include +#include +#include + +#include "c_private.h" +#include "c_lib.h" +#include "c_string.h" +#include "csync_util.h" +#include "csync_log.h" +#include "csync_vio.h" + +#include "vio/csync_vio_local.h" + +/* + * directory functions + */ + +typedef struct dhandle_s { + DIR *dh; + char *path; +} dhandle_t; + +csync_vio_handle_t *csync_vio_local_opendir(const char *name) { + dhandle_t *handle = NULL; + mbchar_t *dirname = NULL; + + handle = c_malloc(sizeof(dhandle_t)); + + dirname = c_utf8_path_to_locale(name); + + handle->dh = _topendir( dirname ); + if (handle->dh == NULL) { + c_free_locale_string(dirname); + SAFE_FREE(handle); + return NULL; + } + + handle->path = c_strdup(name); + c_free_locale_string(dirname); + + return (csync_vio_handle_t *) handle; +} + +int csync_vio_local_closedir(csync_vio_handle_t *dhandle) { + dhandle_t *handle = NULL; + int rc = -1; + + if (dhandle == NULL) { + errno = EBADF; + return -1; + } + + handle = (dhandle_t *) dhandle; + rc = _tclosedir(handle->dh); + + SAFE_FREE(handle->path); + SAFE_FREE(handle); + + return rc; +} + +csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) { + + dhandle_t *handle = NULL; + csync_vio_file_stat_t *file_stat = NULL; + + handle = (dhandle_t *) dhandle; + + errno = 0; + file_stat = csync_vio_file_stat_new(); + if (file_stat == NULL) { + goto err; + } + file_stat->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE; + + struct _tdirent *dirent = NULL; + + dirent = _treaddir(handle->dh); + if (dirent == NULL) { + goto err; + } + file_stat->name = c_utf8_from_locale(dirent->d_name); + if (file_stat->name == NULL) { + //file_stat->original_name = c_strdup(dirent->d_name); + if (asprintf(&file_stat->original_name, "%s/%s", handle->path, dirent->d_name) < 0) { + goto err; + } + CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Invalid characters in file/directory name, please rename: \"%s\" (%s)", + dirent->d_name, handle->path); + } + + /* Check for availability of d_type, see manpage. */ +#if defined(_DIRENT_HAVE_D_TYPE) || defined(__APPLE__) + switch (dirent->d_type) { + case DT_FIFO: + case DT_SOCK: + case DT_CHR: + case DT_BLK: + break; + case DT_DIR: + case DT_REG: + file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; + if (dirent->d_type == DT_DIR) { + file_stat->type = CSYNC_VIO_FILE_TYPE_DIRECTORY; + } else { + file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR; + } + break; + case DT_UNKNOWN: + file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; + file_stat->type = CSYNC_VIO_FILE_TYPE_UNKNOWN; + default: + break; + } +#endif + + return file_stat; + +err: + csync_vio_file_stat_destroy(file_stat); + + return NULL; +} + + +int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) { + csync_stat_t sb; + + mbchar_t *wuri = c_utf8_path_to_locale( uri ); + + if( _tstat(wuri, &sb) < 0) { + c_free_locale_string(wuri); + return -1; + } + + buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE; + + switch(sb.st_mode & S_IFMT) { + case S_IFBLK: + buf->type = CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE; + break; + case S_IFCHR: + buf->type = CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE; + break; + case S_IFDIR: + buf->type = CSYNC_VIO_FILE_TYPE_DIRECTORY; + break; + case S_IFIFO: + buf->type = CSYNC_VIO_FILE_TYPE_FIFO; + break; + case S_IFREG: + buf->type = CSYNC_VIO_FILE_TYPE_REGULAR; + break; + case S_IFLNK: + buf->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; + break; + case S_IFSOCK: + buf->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; + break; + default: + buf->type = CSYNC_VIO_FILE_TYPE_UNKNOWN; + break; + } + buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; + + buf->mode = sb.st_mode; + buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MODE; + + if (buf->type == CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK) { + /* FIXME: handle symlink */ + buf->flags = CSYNC_VIO_FILE_FLAGS_SYMLINK; + } 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->inode = sb.st_ino; + buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE; + + buf->atime = sb.st_atime; + buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME; + + buf->mtime = sb.st_mtime; + buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME; + + buf->ctime = sb.st_ctime; + buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME; + + buf->size = sb.st_size; + buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE; + + c_free_locale_string(wuri); + return 0; +} diff --git a/src/csync/vio/csync_vio_local_win.c b/src/csync/vio/csync_vio_local_win.c new file mode 100644 index 000000000..fc4eea512 --- /dev/null +++ b/src/csync/vio/csync_vio_local_win.c @@ -0,0 +1,275 @@ +/* + * libcsync -- a library to sync a directory with another + * + * Copyright (c) 2008-2013 by Andreas Schneider + * Copyright (c) 2013- by Klaas Freitag + * + * 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 +#include +#include +#include +#include + +#include "windows.h" + +#include "c_private.h" +#include "c_lib.h" +#include "c_string.h" +#include "csync_util.h" +#include "csync_log.h" +#include "csync_vio.h" + +#include "vio/csync_vio_local.h" + + +/* + * directory functions + */ + +typedef struct dhandle_s { + WIN32_FIND_DATA ffd; + HANDLE hFind; + int firstFind; + char *path; +} dhandle_t; + +csync_vio_handle_t *csync_vio_local_opendir(const char *name) { + dhandle_t *handle = NULL; + mbchar_t *dirname = NULL; + + handle = c_malloc(sizeof(dhandle_t)); + + // the file wildcard has to be attached + int len_name = strlen(name); + if( len_name ) { + char *h = NULL; + + // alloc an enough large buffer to take the name + '/*' + the closing zero. + h = c_malloc(len_name+3); + strncpy( h, name, 1+len_name); + strncat(h, "/*", 2); + + dirname = c_utf8_path_to_locale(h); + SAFE_FREE(h); + } + + if( dirname ) { + handle->hFind = FindFirstFile(dirname, &(handle->ffd)); + } + + if (!dirname || handle->hFind == INVALID_HANDLE_VALUE) { + int retcode = GetLastError(); + if( retcode == ERROR_FILE_NOT_FOUND ) { + errno = ENOENT; + } else { + errno = EACCES; + } + SAFE_FREE(handle); + return NULL; + } + + handle->firstFind = 1; // Set a flag that there first fileinfo is available. + + handle->path = c_strdup(name); + c_free_locale_string(dirname); + + return (csync_vio_handle_t *) handle; +} + +int csync_vio_local_closedir(csync_vio_handle_t *dhandle) { + dhandle_t *handle = NULL; + int rc = -1; + + if (dhandle == NULL) { + errno = EBADF; + return -1; + } + + handle = (dhandle_t *) dhandle; + // FindClose returns non-zero on success + if( FindClose(handle->hFind) != 0 ) { + rc = 0; + } else { + // error case, set errno + errno = EBADF; + } + + SAFE_FREE(handle->path); + SAFE_FREE(handle); + + return rc; +} + + +static time_t FileTimeToUnixTime(FILETIME *filetime, DWORD *remainder) +{ + long long int t = filetime->dwHighDateTime; + t <<= 32; + t += (UINT32)filetime->dwLowDateTime; + t -= 116444736000000000LL; + if (t < 0) + { + if (remainder) *remainder = 9999999 - (-t - 1) % 10000000; + return -1 - ((-t - 1) / 10000000); + } + else + { + if (remainder) *remainder = t % 10000000; + return t / 10000000; + } +} + +csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) { + + dhandle_t *handle = NULL; + csync_vio_file_stat_t *file_stat = NULL; + DWORD rem; + + handle = (dhandle_t *) dhandle; + + errno = 0; + file_stat = csync_vio_file_stat_new(); + if (file_stat == NULL) { + errno = ENOMEM; + goto err; + } + file_stat->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE; + + // the win32 functions get the first valid entry with the opendir + // thus we must not jump to next entry if it was the first find. + if( handle->firstFind ) { + handle->firstFind = 0; + } else { + if( FindNextFile(handle->hFind, &(handle->ffd)) == 0 ) { + // might be error, check! + int dwError = GetLastError(); + if (dwError != ERROR_NO_MORE_FILES) { + errno = EACCES; // no more files is fine. Otherwise EACCESS + } + goto err; + } + } + file_stat->name = c_utf8_from_locale(handle->ffd.cFileName); + + file_stat->flags = CSYNC_VIO_FILE_FLAGS_NONE; + file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; + if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + // Detect symlinks, and treat junctions as symlinks too. + if (handle->ffd.dwReserved0 == IO_REPARSE_TAG_SYMLINK + || handle->ffd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT) { + file_stat->flags |= CSYNC_VIO_FILE_FLAGS_SYMLINK; + file_stat->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; + } else { + // The SIS and DEDUP reparse points should be treated as + // regular files. We don't know about the other ones yet, + // but will also treat them normally for now. + file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR; + } + } else if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE + || handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE + || handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) { + file_stat->type = CSYNC_VIO_FILE_TYPE_UNKNOWN; + } else if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + file_stat->type = CSYNC_VIO_FILE_TYPE_DIRECTORY; + } else { + file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR; + } + + /* Check for the hidden flag */ + if( handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) { + file_stat->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN; + } + + file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS; + file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; + + file_stat->size = (handle->ffd.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + handle->ffd.nFileSizeLow; + file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE; + + file_stat->atime = FileTimeToUnixTime(&handle->ffd.ftLastAccessTime, &rem); + file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME; + + file_stat->mtime = FileTimeToUnixTime(&handle->ffd.ftLastWriteTime, &rem); + /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Local File MTime: %llu", (unsigned long long) buf->mtime ); */ + file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME; + + file_stat->ctime = FileTimeToUnixTime(&handle->ffd.ftCreationTime, &rem); + file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME; + + return file_stat; + +err: + SAFE_FREE(file_stat); + + return NULL; +} + + + +int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) { + /* Almost nothing to do since csync_vio_local_readdir already filled up most of the information + But we still need to fetch the file ID. + Possible optimisation: only fetch the file id when we need it (for new files) + */ + + HANDLE h; + BY_HANDLE_FILE_INFORMATION fileInfo; + ULARGE_INTEGER FileIndex; + mbchar_t *wuri = c_utf8_path_to_locale( uri ); + + h = CreateFileW( wuri, 0, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, + NULL ); + if( h == INVALID_HANDLE_VALUE ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "CreateFileW failed on %s", uri ); + errno = GetLastError(); + c_free_locale_string(wuri); + return -1; + } + + if(!GetFileInformationByHandle( h, &fileInfo ) ) { + CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "GetFileInformationByHandle failed on %s", uri ); + errno = GetLastError(); + c_free_locale_string(wuri); + CloseHandle(h); + return -1; + } + + /* Get the Windows file id as an inode replacement. */ + FileIndex.HighPart = fileInfo.nFileIndexHigh; + FileIndex.LowPart = fileInfo.nFileIndexLow; + FileIndex.QuadPart &= 0x0000FFFFFFFFFFFF; + /* printf("Index: %I64i\n", FileIndex.QuadPart); */ + buf->inode = FileIndex.QuadPart; + + if (!(buf->fields & CSYNC_VIO_FILE_STAT_FIELDS_SIZE)) { + buf->size = (fileInfo.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + fileInfo.nFileSizeLow; + buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE; + } + if (!(buf->fields & CSYNC_VIO_FILE_STAT_FIELDS_MTIME)) { + DWORD rem; + buf->mtime = FileTimeToUnixTime(&fileInfo.ftLastWriteTime, &rem); + /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Local File MTime: %llu", (unsigned long long) buf->mtime ); */ + buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME; + } + + c_free_locale_string(wuri); + CloseHandle(h); + return 0; +} diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 2157d3cd6..f7cc0a9db 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -181,11 +181,9 @@ set(3rdparty_INC include_directories(${3rdparty_INC}) # csync is required. -include_directories(${CMAKE_SOURCE_DIR}/csync/src - ${CMAKE_BINARY_DIR}/csync - ${CMAKE_BINARY_DIR}/csync/src +include_directories(${CMAKE_SOURCE_DIR}/src/csync + ${CMAKE_BINARY_DIR}/src/csync ) - include_directories(../libsync ${CMAKE_CURRENT_BINARY_DIR}/../libsync) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} diff --git a/src/libsync/CMakeLists.txt b/src/libsync/CMakeLists.txt index 65d68823d..865dad895 100644 --- a/src/libsync/CMakeLists.txt +++ b/src/libsync/CMakeLists.txt @@ -5,9 +5,8 @@ configure_file( version.h.in "${CMAKE_CURRENT_BINARY_DIR}/version.h" ) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) # csync is required. -include_directories(${CMAKE_SOURCE_DIR}/csync/src - ${CMAKE_BINARY_DIR}/csync - ${CMAKE_BINARY_DIR}/csync/src +include_directories(${CMAKE_SOURCE_DIR}/src/csync + ${CMAKE_BINARY_DIR}/src/csync ) if ( APPLE ) diff --git a/src/libsync/syncjournaldb.cpp b/src/libsync/syncjournaldb.cpp index 0eb34e609..203c14988 100644 --- a/src/libsync/syncjournaldb.cpp +++ b/src/libsync/syncjournaldb.cpp @@ -31,7 +31,7 @@ #include "asserts.h" #include "checksums.h" -#include "../../csync/src/std/c_jhash.h" +#include "std/c_jhash.h" namespace OCC { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ebf349207..d6b68cb5c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,7 +1,17 @@ -include_directories(${CMAKE_BINARY_DIR}/csync ${CMAKE_BINARY_DIR}/csync/src ${CMAKE_BINARY_DIR}/src) -include_directories(${CMAKE_SOURCE_DIR}/csync/src/) -include_directories(${CMAKE_SOURCE_DIR}/csync/src/std ${CMAKE_SOURCE_DIR}/src) -include_directories(${CMAKE_SOURCE_DIR}/src/3rdparty/qtokenizer) +include_directories(${QT_INCLUDES} + ${CMAKE_SOURCE_DIR}/src + ${CMAKE_SOURCE_DIR}/src/3rdparty/qtokenizer + ${CMAKE_SOURCE_DIR}/src/csync + ${CMAKE_SOURCE_DIR}/src/csync/std + ${CMAKE_SOURCE_DIR}/src/gui + ${CMAKE_SOURCE_DIR}/src/libsync + ${CMAKE_BINARY_DIR}/src/csync + ${CMAKE_BINARY_DIR}/src/libsync + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ) + +include_directories() include(QtVersionAbstraction) setup_qt() diff --git a/test/csync/csync_tests/check_csync_exclude.c b/test/csync/csync_tests/check_csync_exclude.c index ea9ca0e2f..1d145b240 100644 --- a/test/csync/csync_tests/check_csync_exclude.c +++ b/test/csync/csync_tests/check_csync_exclude.c @@ -27,7 +27,7 @@ #define CSYNC_TEST 1 #include "csync_exclude.c" -#define EXCLUDE_LIST_FILE SOURCEDIR"/../sync-exclude.lst" +#define EXCLUDE_LIST_FILE SOURCEDIR"/../../sync-exclude.lst" static int setup(void **state) { CSYNC *csync; diff --git a/test/owncloud_add_test.cmake b/test/owncloud_add_test.cmake index cefe264ea..7e7cc5057 100644 --- a/test/owncloud_add_test.cmake +++ b/test/owncloud_add_test.cmake @@ -1,11 +1,4 @@ macro(owncloud_add_test test_class additional_cpp) - include_directories(${QT_INCLUDES} - "${PROJECT_SOURCE_DIR}/src/gui" - "${PROJECT_SOURCE_DIR}/src/libsync" - "${CMAKE_BINARY_DIR}/src/libsync" - "${CMAKE_CURRENT_BINARY_DIR}" - ) - set(CMAKE_AUTOMOC TRUE) set(OWNCLOUD_TEST_CLASS ${test_class}) string(TOLOWER "${OWNCLOUD_TEST_CLASS}" OWNCLOUD_TEST_CLASS_LOWERCASE) @@ -27,14 +20,6 @@ macro(owncloud_add_test test_class additional_cpp) endmacro() macro(owncloud_add_benchmark test_class additional_cpp) - include_directories(${CMAKE_CURRENT_SOURCE_DIR} - ${QT_INCLUDES} - "${PROJECT_SOURCE_DIR}/src/gui" - "${PROJECT_SOURCE_DIR}/src/libsync" - "${CMAKE_BINARY_DIR}/src/libsync" - "${CMAKE_CURRENT_BINARY_DIR}" - ) - set(CMAKE_AUTOMOC TRUE) set(OWNCLOUD_TEST_CLASS ${test_class}) string(TOLOWER "${OWNCLOUD_TEST_CLASS}" OWNCLOUD_TEST_CLASS_LOWERCASE) diff --git a/test/testexcludedfiles.cpp b/test/testexcludedfiles.cpp index b52bfb5a9..cfaf73499 100644 --- a/test/testexcludedfiles.cpp +++ b/test/testexcludedfiles.cpp @@ -11,7 +11,7 @@ using namespace OCC; -#define EXCLUDE_LIST_FILE SOURCEDIR"/../sync-exclude.lst" +#define EXCLUDE_LIST_FILE SOURCEDIR"/../../sync-exclude.lst" class TestExcludedFiles: public QObject { diff --git a/test/testsyncjournaldb.cpp b/test/testsyncjournaldb.cpp index 881bb865d..9e412aa85 100644 --- a/test/testsyncjournaldb.cpp +++ b/test/testsyncjournaldb.cpp @@ -8,8 +8,8 @@ #include -#include "libsync/syncjournaldb.h" -#include "libsync/syncjournalfilerecord.h" +#include "syncjournaldb.h" +#include "syncjournalfilerecord.h" using namespace OCC;