├── .gitignore
├── LICENSE
├── README.md
├── android
├── AndroidManifest.xml
├── proguard-project.txt
├── project.properties
├── res
│ ├── drawable
│ │ └── ic_launcher.png
│ ├── layout
│ │ └── activity_crsync.xml
│ └── values
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
└── src
│ └── com
│ └── shaddock
│ └── crsync
│ ├── Crsync.java
│ ├── CrsyncActivity.java
│ ├── CrsyncConstants.java
│ ├── CrsyncInfo.java
│ ├── CrsyncProvider.java
│ ├── CrsyncService.java
│ └── OnepieceObserver.java
├── doc
├── README.md
└── crsync-基于rsync rolling算法的文件增量更新.md
├── extra
├── dictionary.c
├── dictionary.h
├── iniparser.c
├── iniparser.h
├── md5.c
├── md5.h
├── tpl.c
├── tpl.h
├── uthash.h
├── utlist.h
├── utstring.h
└── win
│ ├── mman.h
│ └── mmap.c
├── libcurl
├── include
│ └── curl
│ │ ├── curl.h
│ │ ├── curlbuild.h
│ │ ├── curlrules.h
│ │ ├── curlver.h
│ │ ├── easy.h
│ │ ├── mprintf.h
│ │ ├── multi.h
│ │ ├── stdcheaders.h
│ │ └── typecheck-gcc.h
└── lib
│ ├── armeabi-v7a
│ └── libcurl.a
│ ├── m32
│ ├── libcurl.a
│ ├── libcurl.dll
│ └── libcurldll.a
│ └── x86
│ └── libcurl.a
└── src
├── crsync-build.cmd
├── crsync-console.c
├── crsync-jni.c
├── crsync.c
├── crsync.h
├── crsync.mk
├── crsync.pro
├── crsync.rc
├── crsyncver.h
├── deployment.pri
├── diff.c
├── diff.h
├── digest.c
├── digest.h
├── global.h
├── helper.c
├── helper.h
├── http.c
├── http.h
├── log.c
├── log.h
├── magnet.c
├── magnet.h
├── onepiece.c
├── onepiece.h
├── onepiecetool.c
├── onepiecetool.h
├── patch.c
├── patch.h
├── util.c
└── util.h
/.gitignore:
--------------------------------------------------------------------------------
1 | # Object files
2 | *.o
3 | *.ko
4 | *.obj
5 | *.elf
6 | *.d
7 | src/Makefile
8 | src/Makefile.Debug
9 | src/Makefile.Release
10 | src/object_script.crsync.Debug
11 | src/object_script.crsync.Release
12 | src/m32/
13 | src/obj/
14 | src/libs/
15 |
16 | # Precompiled Headers
17 | *.gch
18 | *.pch
19 |
20 | # Executables
21 | *.exe
22 | *.out
23 | *.app
24 | *.i*86
25 | *.x86_64
26 | *.hex
27 |
28 | # Debug files
29 | *.dSYM/
30 |
31 | # User files
32 | *.user
33 |
34 | # Android Project files
35 | android/.project
36 | android/.classpath
37 | android/.settings/
38 | android/bin/
39 | android/gen/
40 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 chenqi
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Go-joy/crsync/0af4f53c2dd2d2fe180a756f7f6b98fe6d60bf1f/README.md
--------------------------------------------------------------------------------
/android/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
21 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/android/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/android/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-15
15 |
--------------------------------------------------------------------------------
/android/res/drawable/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Go-joy/crsync/0af4f53c2dd2d2fe180a756f7f6b98fe6d60bf1f/android/res/drawable/ic_launcher.png
--------------------------------------------------------------------------------
/android/res/layout/activity_crsync.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/android/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CrsyncAndroid
5 |
6 |
7 |
--------------------------------------------------------------------------------
/android/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/android/src/com/shaddock/crsync/Crsync.java:
--------------------------------------------------------------------------------
1 | package com.shaddock.crsync;
2 |
3 | import java.util.Vector;
4 |
5 | public class Crsync {
6 |
7 | public static final int Action_Idle = 0;
8 | public static final int Action_Query = 1;
9 | public static final int Action_UserConfirm = 2;
10 | public static final int Action_UpdateApp = 3;
11 | public static final int Action_UserInstall = 4;
12 | public static final int Action_UpdateRes = 5;
13 | public static final int Action_Done = 6;
14 |
15 | /* The same as crsync.h ENUM CRSYNCcode */
16 | public static final int Code_OK = 0;
17 | public static final int Code_Failed_Init = 1;
18 | public static final int Code_Invalid_Opt = 2;
19 | public static final int Code_File_Error = 3;
20 | public static final int Code_CURL_Error = 4;
21 | public static final int Code_BUG = 100;
22 |
23 | public static final int OPT_MagnetID = 0;
24 | public static final int OPT_BaseUrl = 1;
25 | public static final int OPT_LocalApp = 2;
26 | public static final int OPT_LocalRes = 3;
27 | public static final int OPT_Action = 4;
28 |
29 | private static OnepieceObserver mObserver = null;
30 |
31 | public static void setObserver(OnepieceObserver ob) {
32 | mObserver = ob;
33 | }
34 |
35 | public static void delObserver() {
36 | mObserver = null;
37 | }
38 |
39 | static {
40 | System.loadLibrary("crsync");
41 | }
42 |
43 | //native crsync functions
44 | public static native int JNI_onepiece_init();
45 | public static native int JNI_onepiece_setopt(int opt, String value);
46 | public static native String JNI_onepiece_getinfo_magnet();
47 | public static native int JNI_onepiece_perform_query();
48 | public static native int JNI_onepiece_perform_updateapp();
49 | public static native int JNI_onepiece_perform_updateres();
50 | public static native void JNI_onepiece_cleanup();
51 |
52 | public static void java_onepiece_xfer(String hash, int percent) {
53 | if(null != mObserver) {
54 | mObserver.onepiece_xfer(hash, percent);
55 | }
56 | }
57 |
58 | public static class Res {
59 | public String name = "";
60 | public String hash = "";
61 | public int size = 0;
62 | }
63 |
64 | public static class Magnet {
65 | public String curr_id = "";
66 | public String next_id = "";
67 | public String app_hash = "";
68 | public Vector res_list = new Vector();
69 |
70 | public static Magnet getValue(String value) {
71 | String [] s = value.split(";");
72 | if(s.length < 3) {
73 | return null;
74 | }
75 | int i = 0;
76 | Magnet m = new Magnet();
77 | m.curr_id = s[i++];
78 | m.next_id = s[i++];
79 | m.app_hash = s[i++];
80 | while(i ri = CrsyncInfo.queryRes(getContentResolver());
168 | sb.append("Res size : " + ri.size() + "\n");
169 | for(CrsyncInfo.ResInfo x : ri) {
170 | sb.append(x.mName + " : " + x.mPercent + "\n");
171 | }
172 | break;
173 | case Crsync.Action_Done:
174 | break;
175 | default:
176 | break;
177 | }
178 | mTV.setText(sb.toString());
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/android/src/com/shaddock/crsync/CrsyncConstants.java:
--------------------------------------------------------------------------------
1 | package com.shaddock.crsync;
2 |
3 | import java.io.IOException;
4 | import java.util.logging.FileHandler;
5 | import java.util.logging.Level;
6 | import java.util.logging.Logger;
7 | import java.util.logging.SimpleFormatter;
8 |
9 | import android.net.Uri;
10 | import android.os.Environment;
11 |
12 | public class CrsyncConstants {
13 |
14 | public static final Logger logger = Logger.getLogger("crsync");
15 | private static final boolean mDebug = true;
16 |
17 | static {
18 | logger.setLevel( mDebug ? Level.ALL : Level.OFF );
19 | if(mDebug) {
20 | try {
21 | String file = Environment.getExternalStorageDirectory().getAbsolutePath() + "/crsync.log";
22 | FileHandler fh = new FileHandler(file, true);
23 | fh.setFormatter(new SimpleFormatter());
24 | logger.addHandler(fh);
25 | } catch (IOException e) {
26 | e.printStackTrace();
27 | }
28 | }
29 | }
30 |
31 | /** The same as AndroidManifest.xml provider authority */
32 | public static final String URIAUTHORITY = "com.shaddock.crsync.CrsyncProvider";
33 |
34 | public static final String URIPATH_CONTENT = "content";
35 | public static final String URIPATH_STATE = "state";
36 | public static final String URIPATH_APP = "app";
37 | public static final String URIPATH_RESOURCE = "res";
38 |
39 | public static final Uri URI_BASE = Uri.parse("content://" + URIAUTHORITY);
40 | public static final Uri URI_CONTENT = Uri.parse("content://" + URIAUTHORITY + "/" + URIPATH_CONTENT);
41 | public static final Uri URI_STATE = Uri.parse("content://" + URIAUTHORITY + "/" + URIPATH_STATE);
42 | public static final Uri URI_APP = Uri.parse("content://" + URIAUTHORITY + "/" + URIPATH_APP);
43 | public static final Uri URI_RES = Uri.parse("content://" + URIAUTHORITY + "/" + URIPATH_RESOURCE);
44 |
45 | public static final String COLUMN_CONTENT_MAGNET = "content_magnet";
46 | public static final String COLUMN_CONTENT_BASEURL = "content_baseurl";
47 | public static final String COLUMN_CONTENT_LOCALAPP = "content_localapp";
48 | public static final String COLUMN_CONTENT_LOCALRES = "content_localres";
49 |
50 | public static final String COLUMN_STATE_ACTION = "state_action";
51 | public static final String COLUMN_STATE_CODE = "state_code";
52 |
53 | public static final String COLUMN_APP_HASH = "app_hash";
54 | public static final String COLUMN_APP_PERCENT = "app_percent";
55 |
56 | public static final String COLUMN_RES_NAME = "res_name";
57 | public static final String COLUMN_RES_HASH = "res_hash";
58 | public static final String COLUMN_RES_SIZE = "res_size";
59 | public static final String COLUMN_RES_PERCENT = "res_percent";
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/android/src/com/shaddock/crsync/CrsyncInfo.java:
--------------------------------------------------------------------------------
1 | package com.shaddock.crsync;
2 |
3 | import static com.shaddock.crsync.CrsyncConstants.logger;
4 |
5 | import java.util.Vector;
6 |
7 | import android.content.ContentResolver;
8 | import android.content.ContentValues;
9 | import android.database.Cursor;
10 |
11 | public class CrsyncInfo {
12 | public static class StateInfo {
13 | public int mAction = Crsync.Action_Idle;
14 | public int mCode = Crsync.Code_OK;
15 |
16 | public void dump() {
17 | logger.info("####StateInfo Action : " + mAction);
18 | logger.info("####StateInfo Code : " + mCode);
19 | }
20 | }
21 |
22 | public static StateInfo queryState(ContentResolver cr) {
23 | StateInfo info = new StateInfo();
24 |
25 | Cursor c = cr.query(CrsyncConstants.URI_STATE, null, null, null, null);
26 |
27 | if(c != null && c.moveToFirst()) {
28 | int actionColumn = c.getColumnIndex(CrsyncConstants.COLUMN_STATE_ACTION);
29 | int codeColumn = c.getColumnIndex(CrsyncConstants.COLUMN_STATE_CODE);
30 |
31 | info.mAction = c.getInt( actionColumn );
32 | info.mCode = c.getInt( codeColumn );
33 | } else {
34 | logger.severe("####StateInfo query URI fail");
35 | }
36 | if(c != null) {
37 | c.close();
38 | }
39 | return info;
40 | }
41 |
42 | public static void updateState(ContentResolver cr, StateInfo info) {
43 | ContentValues values = new ContentValues();
44 | values.put(CrsyncConstants.COLUMN_STATE_ACTION, info.mAction);
45 | values.put(CrsyncConstants.COLUMN_STATE_CODE, info.mCode);
46 | cr.update(CrsyncConstants.URI_STATE, values, null, null);
47 | }
48 |
49 | public static class ContentInfo {
50 | public String mMagnet = "";
51 | public String mBaseUrl = "";
52 | public String mLocalApp = "";
53 | public String mLocalRes = "";
54 |
55 | public void dump() {
56 | logger.info("####ContentInfo mMagnet : " + mMagnet);
57 | logger.info("####ContentInfo mBaseUrl : " + mBaseUrl);
58 | logger.info("####ContentInfo mLocalApp : " + mLocalApp);
59 | logger.info("####ContentInfo mLocalRes : " + mLocalRes);
60 | }
61 | }
62 |
63 | public static ContentInfo queryContent(ContentResolver cr) {
64 | ContentInfo info = new ContentInfo();
65 | Cursor c = cr.query(CrsyncConstants.URI_CONTENT, null, null, null, null);
66 |
67 | if(c != null && c.moveToFirst()) {
68 | int magnetColumn = c.getColumnIndex(CrsyncConstants.COLUMN_CONTENT_MAGNET);
69 | int baseUrlColumn = c.getColumnIndex(CrsyncConstants.COLUMN_CONTENT_BASEURL);
70 | int localAppColumn = c.getColumnIndex(CrsyncConstants.COLUMN_CONTENT_LOCALAPP);
71 | int localResColumn = c.getColumnIndex(CrsyncConstants.COLUMN_CONTENT_LOCALRES);
72 |
73 | info.mMagnet = c.getString(magnetColumn);
74 | info.mBaseUrl = c.getString(baseUrlColumn);
75 | info.mLocalApp = c.getString(localAppColumn);
76 | info.mLocalRes = c.getString(localResColumn);
77 | } else {
78 | logger.severe("####ContentInfo query URI fail");
79 | }
80 | if(c != null) {
81 | c.close();
82 | }
83 | return info;
84 | }
85 |
86 | public static void updateContent(ContentResolver cr, ContentInfo info) {
87 | ContentValues values = new ContentValues();
88 | values.put(CrsyncConstants.COLUMN_CONTENT_MAGNET, info.mMagnet);
89 | values.put(CrsyncConstants.COLUMN_CONTENT_BASEURL, info.mBaseUrl);
90 | values.put(CrsyncConstants.COLUMN_CONTENT_LOCALAPP, info.mLocalApp);
91 | values.put(CrsyncConstants.COLUMN_CONTENT_LOCALRES, info.mLocalRes);
92 | cr.update(CrsyncConstants.URI_CONTENT, values, null, null);
93 | }
94 |
95 | public static class AppInfo {
96 | public String mHash = "";
97 | public int mPercent = 0;
98 |
99 | public void dump() {
100 | logger.info("####AppInfo Hash : " + mHash);
101 | logger.info("####AppInfo Percent : " + mPercent);
102 | }
103 | }
104 |
105 | public static AppInfo queryApp(ContentResolver cr) {
106 | AppInfo info = new AppInfo();
107 |
108 | Cursor c = cr.query(CrsyncConstants.URI_APP, null, null, null, null);
109 |
110 | if(c != null && c.moveToFirst()) {
111 | int hashColumn = c.getColumnIndex(CrsyncConstants.COLUMN_APP_HASH);
112 | int percentColumn = c.getColumnIndex(CrsyncConstants.COLUMN_APP_PERCENT);
113 |
114 | info.mHash = c.getString(hashColumn);
115 | info.mPercent = c.getInt( percentColumn );
116 | } else {
117 | logger.severe("####AppInfo query URI fail");
118 | }
119 | if(c != null) {
120 | c.close();
121 | }
122 | return info;
123 | }
124 |
125 | public static void updateApp(ContentResolver cr, AppInfo info) {
126 | ContentValues values = new ContentValues();
127 | values.put(CrsyncConstants.COLUMN_APP_HASH, info.mHash);
128 | values.put(CrsyncConstants.COLUMN_APP_PERCENT, info.mPercent);
129 | cr.update(CrsyncConstants.URI_APP, values, null, null);
130 | }
131 |
132 | public static class ResInfo {
133 | public String mName = "";
134 | public String mHash = "";
135 | public int mSize = 0;
136 | public int mPercent = 0;
137 |
138 | public void dump() {
139 | logger.info("####ResInfo name : " + mName);
140 | logger.info("####ResInfo hash : " + mHash);
141 | logger.info("####ResInfo size : " + mSize);
142 | logger.info("####ResInfo percent : " + mPercent);
143 | }
144 | }
145 |
146 | public static Vector queryRes(ContentResolver cr) {
147 | Vector infos = new Vector();
148 | Cursor c = cr.query(CrsyncConstants.URI_RES, null, null, null, null);
149 | if(c != null && c.moveToFirst()) {
150 |
151 | int nameColumn = c.getColumnIndex(CrsyncConstants.COLUMN_RES_NAME);
152 | int hashColumn = c.getColumnIndex(CrsyncConstants.COLUMN_RES_HASH);
153 | int sizeColumn = c.getColumnIndex(CrsyncConstants.COLUMN_RES_SIZE);
154 | int percentColumn = c.getColumnIndex(CrsyncConstants.COLUMN_RES_PERCENT);
155 |
156 | for( ; !c.isAfterLast(); c.moveToNext()) {
157 | ResInfo info = new ResInfo();
158 | info.mName = c.getString(nameColumn);
159 | info.mHash = c.getString(hashColumn);
160 | info.mSize = c.getInt(sizeColumn);
161 | info.mPercent = c.getInt(percentColumn);
162 | infos.add(info);
163 | }
164 | } else {
165 | logger.severe("ResInfo query URI fail");
166 | }
167 |
168 | if(c != null) {
169 | c.close();
170 | }
171 | return infos;
172 | }
173 |
174 | public static void bulkInsertRes(ContentResolver cr, ResInfo[] infos) {
175 | ContentValues values[] = new ContentValues[infos.length];
176 | for(int i=0; i mRes = new Vector();
80 |
81 | @Override
82 | public boolean onCreate() {
83 | logger.info("CrsyncProvider onCreate");
84 | //Context ctx = getContext();
85 | //mSP = ctx.getApplicationContext().getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
86 | startCrsyncService();
87 | return true;
88 | }
89 | /*
90 | * private static final long UPDATE_CHECK_PERIOD_MILLISECONDS = 24*60*60*1000; //24hours
91 | private static boolean isUpdateCheckRequired() {
92 | long last = IBApplication.mSP.getLong(IBApplication.KSP_update, -1);
93 | if(last == -1) {
94 | //first time to check
95 | return true;
96 | }
97 | Calendar now = Calendar.getInstance();
98 | Calendar old = Calendar.getInstance();
99 | old.setTimeInMillis(last);
100 | if(now.before(old)) {
101 | //device time have been changed
102 | return true;
103 | }
104 | old.setTimeInMillis(last + UPDATE_CHECK_PERIOD_MILLISECONDS);
105 | if(now.after(old)) {
106 | //pass check period
107 | return true;
108 | }
109 | return false;
110 | }
111 | *
112 | * */
113 | @Override
114 | public Cursor query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder) {
115 | Cursor c = null;
116 | int match = sURIMatcher.match(uri);
117 | switch (match) {
118 | case CODE_STATE:
119 | {
120 | MatrixCursor mc = new MatrixCursor(CURSOR_COLUMN_STATE);
121 | mc.addRow( new Object[] {mAction, mCode});
122 | c = mc;
123 | break;
124 | }
125 | case CODE_CONTENT:
126 | {
127 | MatrixCursor mc = new MatrixCursor(CURSOR_COLUMN_CONTENT);
128 | mc.addRow( new Object[] {mMagnet, mBaseUrl, mLocalApp, mLocalRes});
129 | c = mc;
130 | break;
131 | }
132 | case CODE_APP:
133 | {
134 | MatrixCursor mc = new MatrixCursor(CURSOR_COLUMN_APP);
135 | mc.addRow( new Object[] {mAppHash, mAppPercent});
136 | c = mc;
137 | break;
138 | }
139 | case CODE_RESOURCE:
140 | {
141 | MatrixCursor mc = new MatrixCursor(CURSOR_COLUMN_RESOURCE);
142 | for(CrsyncInfo.ResInfo x : mRes) {
143 | mc.addRow( new Object[] { x.mName, x.mHash, x.mSize, x.mPercent });
144 | }
145 | c = mc;
146 | break;
147 | }
148 | default:
149 | logger.severe("Unknown URI: " + uri);
150 | throw new IllegalArgumentException("query Unknown URI: " + uri);
151 | }
152 | return c;
153 | }
154 |
155 | @Override
156 | public String getType(final Uri uri) {
157 | int match = sURIMatcher.match(uri);
158 | switch (match) {
159 | case CODE_CONTENT:
160 | case CODE_STATE:
161 | case CODE_APP:
162 | return TYPE_ITEM;
163 | case CODE_RESOURCE:
164 | return TYPE_DIR;
165 | default:
166 | logger.severe("Unknown URI: " + uri);
167 | throw new IllegalArgumentException("getType Unknown URI: " + uri);
168 | }
169 | }
170 |
171 | @Override
172 | public Uri insert(Uri uri, ContentValues values) {
173 | throw new IllegalArgumentException("insert Unimplement URI: " + uri);
174 | }
175 |
176 | @Override
177 | public int bulkInsert(Uri uri, ContentValues[] values) {
178 | int match = sURIMatcher.match(uri);
179 | switch (match) {
180 | case CODE_RESOURCE:
181 | mRes.clear();
182 | for(ContentValues v : values) {
183 | CrsyncInfo.ResInfo r = new CrsyncInfo.ResInfo();
184 | r.mName = v.getAsString(CrsyncConstants.COLUMN_RES_NAME);
185 | r.mHash = v.getAsString(CrsyncConstants.COLUMN_RES_HASH);
186 | r.mSize = v.getAsInteger(CrsyncConstants.COLUMN_RES_SIZE);
187 | r.mPercent = v.getAsInteger(CrsyncConstants.COLUMN_RES_PERCENT);
188 | mRes.add(r);
189 | }
190 | notifyChange(uri);
191 | return values.length;
192 | default:
193 | logger.severe("Unknown URI: " + uri);
194 | throw new IllegalArgumentException("bulkInsert Unknown URI: " + uri);
195 | }
196 | }
197 |
198 | @Override
199 | public int delete(Uri uri, String selection, String[] selectionArgs) {
200 | throw new IllegalArgumentException("delete Unimplement URI: " + uri);
201 | }
202 |
203 | @Override
204 | public int update(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs) {
205 | int match = sURIMatcher.match(uri);
206 | switch (match) {
207 | case CODE_STATE:
208 | mAction = values.getAsInteger(CrsyncConstants.COLUMN_STATE_ACTION);
209 | mCode = values.getAsInteger(CrsyncConstants.COLUMN_STATE_CODE);
210 | notifyChange(uri);
211 | return 1;
212 | case CODE_CONTENT:
213 | mMagnet = values.getAsString(CrsyncConstants.COLUMN_CONTENT_MAGNET);
214 | mBaseUrl = values.getAsString(CrsyncConstants.COLUMN_CONTENT_BASEURL);
215 | mLocalApp = values.getAsString(CrsyncConstants.COLUMN_CONTENT_LOCALAPP);
216 | mLocalRes = values.getAsString(CrsyncConstants.COLUMN_CONTENT_LOCALRES);
217 | notifyChange(uri);
218 | return 1;
219 | case CODE_APP:
220 | mAppHash = values.getAsString(CrsyncConstants.COLUMN_APP_HASH);
221 | mAppPercent = values.getAsInteger(CrsyncConstants.COLUMN_APP_PERCENT);
222 | notifyChange(uri);
223 | return 1;
224 | case CODE_RESOURCE:
225 | CrsyncInfo.ResInfo r = new CrsyncInfo.ResInfo();
226 | r.mName = values.getAsString(CrsyncConstants.COLUMN_RES_NAME);
227 | r.mHash = values.getAsString(CrsyncConstants.COLUMN_RES_HASH);
228 | r.mSize = values.getAsInteger(CrsyncConstants.COLUMN_RES_SIZE);
229 | r.mPercent = values.getAsInteger(CrsyncConstants.COLUMN_RES_PERCENT);
230 | for (CrsyncInfo.ResInfo x : mRes) {
231 | if(x.mName.equalsIgnoreCase(r.mName) || x.mHash.equalsIgnoreCase(r.mHash)) {
232 | x.mPercent = r.mPercent;
233 | notifyChange(uri);
234 | return 1;
235 | }
236 | }
237 | logger.severe("update resource not found : " + r.toString());
238 | return 0;
239 | default:
240 | logger.severe("Unknown URI: " + uri);
241 | throw new IllegalArgumentException("update Unknown URI: " + uri);
242 | }
243 | }
244 |
245 | private void startCrsyncService() {
246 | if(CrsyncService.isRunning) {
247 | return;
248 | }
249 | Context ctx = getContext();
250 | ComponentName result = ctx.startService(new Intent(ctx, CrsyncService.class));
251 | logger.info("CrsyncProvider startService : " + result);
252 | }
253 |
254 | private void notifyChange(Uri uri) {
255 | getContext().getContentResolver().notifyChange(uri, null);
256 | startCrsyncService();
257 | }
258 | }
259 |
--------------------------------------------------------------------------------
/android/src/com/shaddock/crsync/CrsyncService.java:
--------------------------------------------------------------------------------
1 | package com.shaddock.crsync;
2 |
3 | import static com.shaddock.crsync.CrsyncConstants.logger;
4 |
5 | import java.io.File;
6 |
7 | import android.app.Service;
8 | import android.content.Intent;
9 | import android.database.ContentObserver;
10 | import android.net.NetworkInfo;
11 | import android.os.Handler;
12 | import android.os.IBinder;
13 |
14 | public class CrsyncService extends Service implements OnepieceObserver {
15 |
16 | public static volatile boolean isRunning = false;
17 |
18 | private CrsyncContentObserver mObserver = null;
19 |
20 | private UpdateThread mUpdateThread = null;
21 |
22 | private boolean mPendingUpdate = false;
23 |
24 | private String mAppHash = "";
25 |
26 | private class CrsyncContentObserver extends ContentObserver {
27 |
28 | public CrsyncContentObserver() {
29 | super(new Handler());
30 | }
31 |
32 | @Override
33 | public boolean deliverSelfNotifications() {
34 | return false;
35 | }
36 |
37 | @Override
38 | public void onChange(final boolean selfChange) {
39 | updateFromProvider();
40 | }
41 |
42 | }
43 |
44 | @Override
45 | public IBinder onBind(Intent intent) {
46 | throw new UnsupportedOperationException("Cannot bind to CrsyncService");
47 | }
48 |
49 | @Override
50 | public void onCreate() {
51 | super.onCreate();
52 | logger.info("CrsyncService onCreate");
53 |
54 | mObserver = new CrsyncContentObserver();
55 | getContentResolver().registerContentObserver(CrsyncConstants.URI_BASE, true, mObserver);
56 | isRunning = true;
57 | }
58 |
59 | @Override
60 | public int onStartCommand(Intent intent, int flags, int startId) {
61 | logger.info("CrsyncService onStartCommand");
62 | int returnValue = super.onStartCommand(intent, flags, startId);
63 | updateFromProvider();
64 | return returnValue;
65 | }
66 |
67 | @Override
68 | public void onDestroy() {
69 | logger.info("CrsyncService onDestroy");
70 | isRunning = false;
71 | getContentResolver().unregisterContentObserver(mObserver);
72 | mObserver = null;
73 | super.onDestroy();
74 | }
75 |
76 | private void updateFromProvider() {
77 | synchronized (this) {
78 | mPendingUpdate = true;
79 | if (mUpdateThread == null) {
80 | mUpdateThread = new UpdateThread();
81 | mUpdateThread.start();
82 | }
83 | }
84 | }
85 |
86 | private class UpdateThread extends Thread {
87 | public UpdateThread() {
88 | super("CrsyncServiceUpdateThread");
89 | }
90 |
91 | @Override
92 | public void run() {
93 | while (true) {
94 | synchronized (CrsyncService.this) {
95 | if (mUpdateThread != this) {
96 | logger.severe("CrsyncService occur multiple UpdateThreads");
97 | break;
98 | }
99 | if (!mPendingUpdate) {
100 | mUpdateThread = null;
101 | break;
102 | }
103 | mPendingUpdate = false;
104 | }
105 | Crsync.setObserver(CrsyncService.this);
106 | CrsyncInfo.StateInfo stateInfo = CrsyncInfo.queryState(getContentResolver());
107 | handleFromProvider(stateInfo);
108 | Crsync.delObserver();
109 | }
110 | }
111 | }// End of class UpdateThread
112 |
113 | private void handleFromProvider(CrsyncInfo.StateInfo stateInfo) {
114 | logger.info("CrsyncService handleFromProvider");
115 | stateInfo.dump();
116 | switch (stateInfo.mAction) {
117 | case Crsync.Action_Idle:
118 | handleIdle(stateInfo);
119 | break;
120 | case Crsync.Action_Query:
121 | handleQuery(stateInfo);
122 | break;
123 | case Crsync.Action_UserConfirm:
124 | //do nothing
125 | break;
126 | case Crsync.Action_UpdateApp:
127 | handleUpdateApp(stateInfo);
128 | break;
129 | case Crsync.Action_UserInstall:
130 | //do nothing
131 | break;
132 | case Crsync.Action_UpdateRes:
133 | handleUpdateRes(stateInfo);
134 | break;
135 | case Crsync.Action_Done:
136 | handleDone(stateInfo);
137 | break;
138 | default:
139 | logger.severe("wrong action");
140 | break;
141 | }
142 | }
143 |
144 | private void handleIdle(CrsyncInfo.StateInfo stateInfo) {
145 | logger.info("CrsyncService handleIdle");
146 | CrsyncInfo.ContentInfo contentInfo = CrsyncInfo.queryContent(getContentResolver());
147 | if(contentInfo.mMagnet.isEmpty() ||
148 | contentInfo.mBaseUrl.isEmpty() ||
149 | contentInfo.mLocalApp.isEmpty() ||
150 | contentInfo.mLocalRes.isEmpty()) {
151 | return;
152 | }
153 |
154 | new File( contentInfo.mLocalRes ).mkdirs();
155 |
156 | int code;
157 | do {
158 | code = Crsync.JNI_onepiece_init();
159 | if(Crsync.Code_OK != code) break;
160 | code = Crsync.JNI_onepiece_setopt(Crsync.OPT_MagnetID, contentInfo.mMagnet);
161 | if(Crsync.Code_OK != code) break;
162 | code = Crsync.JNI_onepiece_setopt(Crsync.OPT_BaseUrl, contentInfo.mBaseUrl);
163 | if(Crsync.Code_OK != code) break;
164 | code = Crsync.JNI_onepiece_setopt(Crsync.OPT_LocalApp, contentInfo.mLocalApp);
165 | if(Crsync.Code_OK != code) break;
166 | code = Crsync.JNI_onepiece_setopt(Crsync.OPT_LocalRes, contentInfo.mLocalRes);
167 | if(Crsync.Code_OK != code) break;
168 | } while(false);
169 |
170 | if(Crsync.Code_OK == code) {
171 | stateInfo.mAction = Crsync.Action_Query;
172 | stateInfo.mCode = Crsync.Code_OK;
173 | } else {
174 | stateInfo.mAction = Crsync.Action_Done;
175 | stateInfo.mCode = code;
176 | }
177 | CrsyncInfo.updateState(getContentResolver(), stateInfo);
178 | handleFromProvider(stateInfo);
179 | }
180 |
181 | private void handleQuery(CrsyncInfo.StateInfo stateInfo) {
182 | logger.info("CrsyncService handleQuery");
183 | int code = Crsync.JNI_onepiece_perform_query();
184 | if(Crsync.Code_OK == code) {
185 | CrsyncInfo.ContentInfo ci = CrsyncInfo.queryContent(getContentResolver());
186 | String magnetString = Crsync.JNI_onepiece_getinfo_magnet();
187 | logger.info("INFO_Magnet = " + magnetString);
188 | Crsync.Magnet magnet = Crsync.Magnet.getValue(magnetString);
189 | int size = magnet.res_list.size();
190 | CrsyncInfo.ResInfo ri[] = new CrsyncInfo.ResInfo[size];
191 | for(int i=0; i < size; i++) {
192 | CrsyncInfo.ResInfo r = new CrsyncInfo.ResInfo();
193 | Crsync.Res res = magnet.res_list.get(i);
194 | r.mName = res.name;
195 | r.mHash = res.hash;
196 | r.mSize = res.size;
197 | r.mPercent = 0;
198 | ri[i] = r;
199 | }
200 | CrsyncInfo.bulkInsertRes(getContentResolver(), ri);
201 | if(magnet.curr_id.equalsIgnoreCase(ci.mMagnet)) {
202 | stateInfo.mAction = Crsync.Action_UpdateRes;
203 | stateInfo.mCode = Crsync.Code_OK;
204 | } else {
205 | mAppHash = magnet.app_hash;
206 | CrsyncInfo.AppInfo ai = new CrsyncInfo.AppInfo();
207 | ai.mHash = magnet.app_hash;
208 | CrsyncInfo.updateApp(getContentResolver(), ai);
209 | stateInfo.mAction = Crsync.Action_UserConfirm;
210 | stateInfo.mCode = Crsync.Code_OK;
211 | }
212 | } else {
213 | stateInfo.mAction = Crsync.Action_Done;
214 | stateInfo.mCode = code;
215 | }
216 | CrsyncInfo.updateState(getContentResolver(), stateInfo);
217 | handleFromProvider(stateInfo);
218 | }
219 |
220 | private void handleUpdateApp(CrsyncInfo.StateInfo stateInfo) {
221 | int code = Crsync.JNI_onepiece_perform_updateapp();
222 | if(Crsync.Code_OK == code) {
223 | stateInfo.mAction = Crsync.Action_UserInstall;
224 | } else {
225 | stateInfo.mAction = Crsync.Action_Done;
226 | }
227 | stateInfo.mCode = code;
228 | CrsyncInfo.updateState(getContentResolver(), stateInfo);
229 | handleFromProvider(stateInfo);
230 | }
231 |
232 | private void handleUpdateRes(CrsyncInfo.StateInfo stateInfo) {
233 | int code = Crsync.JNI_onepiece_perform_updateres();
234 | stateInfo.mAction = Crsync.Action_Done;
235 | stateInfo.mCode = code;
236 | CrsyncInfo.updateState(getContentResolver(), stateInfo);
237 | handleFromProvider(stateInfo);
238 | }
239 |
240 | private void handleDone(CrsyncInfo.StateInfo stateInfo) {
241 | Crsync.JNI_onepiece_cleanup();
242 | }
243 |
244 | @Override
245 | public void onepiece_xfer(String hash, int percent) {
246 | logger.info("onepiece_xfer : " + hash + " " + percent + "%");
247 | if(hash.equalsIgnoreCase(mAppHash)) {
248 | CrsyncInfo.AppInfo ai = new CrsyncInfo.AppInfo();
249 | ai.mHash = mAppHash;
250 | ai.mPercent = percent;
251 | CrsyncInfo.updateApp(getContentResolver(), ai);
252 | } else {
253 | CrsyncInfo.ResInfo ri = new CrsyncInfo.ResInfo();
254 | ri.mHash = hash;
255 | ri.mPercent = percent;
256 | CrsyncInfo.updateRes(getContentResolver(), ri);
257 | }
258 | }
259 |
260 | }
261 |
--------------------------------------------------------------------------------
/android/src/com/shaddock/crsync/OnepieceObserver.java:
--------------------------------------------------------------------------------
1 | package com.shaddock.crsync;
2 |
3 | public interface OnepieceObserver {
4 |
5 | public void onepiece_xfer(final String hash, int percent);
6 | }
7 |
--------------------------------------------------------------------------------
/doc/README.md:
--------------------------------------------------------------------------------
1 | # test 1
2 |
3 | File: base14009.obb to base14012.obb
4 | Device: DELL PC, Intel i3 550 (4core 3.2GHz) 4GB RAM
5 | Build: MinGW 32bit release
6 |
7 | | block size | hash bloom | hatch speed | match speed | hatch blocks | match blocks | delta size |
8 | | ---------- | :--------- | :---------: | :---------: | :----------: | :----------: | ---------: |
9 | | 2048 | 0 | 2189 ms | 14620 ms | 46328 | 40418 | 11820 KB |
10 | | 4096 | 0 | 2158 ms | 9675 ms | 23164 | 18960 | 16816 KB |
11 | | 8192 | 0 | 2137 ms | 8580 ms | 11582 | 9249 | 18664 KB |
12 | | 2048 | 20 | 2182 ms | 3753 ms | 46328 | 40418 | 11820 KB |
13 | | 4096 | 20 | 2156 ms | 2914 ms | 23164 | 18960 | 16816 KB |
14 | | 8192 | 20 | 2154 ms | 2719 ms | 11582 | 9249 | 18664 KB |
15 |
--------------------------------------------------------------------------------
/doc/crsync-基于rsync rolling算法的文件增量更新.md:
--------------------------------------------------------------------------------
1 | **最终实现效果:**
2 | 1. 无版本概念,任何本地文件均可增量升级到最新.服务器不用管理多版本
3 | 2. 内存小,100M文件升级时只占用500KB内存.
4 |
5 | **使用流程:**
6 | 1. 制作新版本,上传HTTP File Server.
7 | 2. Client自动计算差异,下载差异,合并差异.
8 | 3. done!
9 |
10 | #0.缘起
11 | 目前主流的文件增量更新方案是**bs diff/patch**,以及google chrome Courgette改进方案。
12 | 无尽之剑Android版最初使用该方案,在封测期间发现存在问题:
13 |
14 | 1. 多版本运营繁琐。
15 | 假设目前先后开发了5个版本,1.0~5.0,运营中需要制作
16 | 1-2.patch
17 | 2-3.patch
18 | 3-4.patch
19 | 4-5.patch
20 | **n个版本,n-1个patch包**
21 | 或者
22 | 1-2.patch
23 | 1-3.patch 2-3.patch
24 | 1-4.patch 2-4.patch 3-4.patch
25 | 1-5.patch 2-5.patch 3-5.patch 4-5.patch
26 | **n个版本,(n-1)阶乘个patch包**
27 |
28 | 2. patch依赖本地版本文件完整性
29 | 如果本地文件损坏或被篡改,就无法增量升级,只能重新下载完整包.
30 |
31 | 3. bs diff/patch算法性能和**内存**开销太高
32 | > from [bsdiff官网](http://www.daemonology.net/bsdiff/)
33 | > bsdiff is quite memory-hungry. It requires max(17*n,9*n+m)+O(1) bytes of memory, where n is the size of the old file and m is the size of the new file. bspatch requires **n+m+O(1)** bytes.
34 | > bsdiff runs in O((n+m) log n) time; on a 200MHz Pentium Pro, building a binary patch for a 4MB file takes about 90 seconds.
35 | > bspatch runs in O(n+m) time; on the same machine, applying that patch takes about two seconds.
36 |
37 | bsdiff执行慢,可以,200M文件制作patch包需要运行64位版本,可以.
38 | bspatch执行慢,可以。需要占用**n+m**内存,这点无法接受.
39 | 无尽之剑Android版的资源包单个最大200M,在游戏运行同时进行200M+内存开销的patch操作,非常容易OOM.
40 |
41 | **那么问题来了:有没有一种版本无关,内容无关,内存开销小的增量升级方案呢?**
42 | 这就是我的**crsync**:
43 | 纯C语言实现,基于rsync rolling算法, Client Side计算diff和执行patch,通过curl进行HTTP range增量下载
44 | (同类方案有zsync,用于ubuntu package增量更新)
45 |
46 | 1. 客户端计算本地版本和服务器最新版本之间的diff,然后通过http range下载差异部分.
47 |
48 | 2. 内存开销 = 文件size/分块size * 40字节 + HashTable开销.
49 | 假设文件size 100M,分块size 16K,那么patch操作最多只需500KB内存。
50 |
51 | 3. 版本无关, 本地文件是否改动无关,只关注本地和远端之间的内容差异.
52 |
53 | #1.rsync rolling
54 | 检测2个文件的差异和重复数据,有2种策略:定长分块和变长分块.
55 | rsync算法属于前者,RDC算法属于后者,多轮rsync可以看作是对定长分块的变长优化.
56 |
57 | 定长分块是将A文件按固定块大小切分,计算校验值。在B文件中遍历,计算所有相同块大小的校验值,相同即一致,不同即差异.
58 | 以下假设文件size=100M, 分块size=1KB,测试数据基于公司开发机i7-3770 CPU.
59 |
60 | A文件切分,计算[0]~[1023], [1024]~[2047],[2048]~[3071]...的校验值,输出一张A表.
61 | B文件遍历,计算[0]~[1023], [1]~[1024],[2]~[1025],...的校验值,在A表中遍历比对.相同即重复,不同即差异.
62 |
63 | 不足1KB的数据,rsync补齐0再计算校验值,与B文件遍历计算比对.
64 | crsync不计算,直接将之存入A表末尾,当作差异.
65 |
66 | 校验算法很多,常用MD4,MD5,SHA-1,BLAKE2均可.
67 | 这样明显很慢,如何优化?
68 |
69 | rsync使用2个校验值,**弱校验**和**强校验**.
70 | 弱校验是计算一个32位的CRC值,优点: 快; 缺点: 冲突率高;校验值相同时数据可能不同.
71 | 强校验是上面说到的各种算法,优点: 冲突率低; 缺点: 慢.
72 | 首先做弱校验,值相同再做强校验.以此保证快速与准确.
73 | 遍历文件[0]~[1023], [1]~[1024],[2]~[1025],...需计算104856577次弱校验
74 | 这样依然很慢,如何优化?
75 |
76 | CRC校验算法很多,rsync使用**adler32**算法,因此有了**rolling**的特性.
77 | alder32算法由Mark Adler于1995发明,用于zlib.
78 | 一个32位的adler32值由2个16位的A和B值构成。
79 | A值=buffer中所有byte相加,对2^16取模(65536).
80 | b值=buffer中所有A相加,对2^16取模(65536).
81 | 公式如下:
82 | > A = 1 + D1 + D2 + ... + Dn (mod 65521)
83 | > B = (1 + D1) + (1 + D1 + D2) + ... + (1 + D1 + D2 + ... + Dn) (mod 65521)
84 | > = n×D1 + (n−1)×D2 + (n−2)×D3 + ... + Dn + n (mod 65521)
85 | > Adler-32(D) = B × 65536 + A
86 |
87 | 65521是65536范围内的最大素数,因此mod=65521即可.
88 | librsync(rdiff)在A和B值计算时再偏移31,rsync偏移0,crsync偏移0.
89 |
90 | 有趣的是,这个公式等价于:
91 | > A += data[i];
92 | > B += A;
93 |
94 | rolling是什么?
95 | 计算出[0]~[1023]的校验值,再计算[1]~[1024]的校验值时,只需减去data[0],加上data[1024]即可!不需重新计算!
96 | > A -= data[0];
97 | > A += data[1024];
98 | > B -= 1024 * data[0];
99 | > B += A;
100 |
101 | 如此滑动遍历,即可得到整个文件的所有分块的校验值.(大赞!)
102 | 实测文件size 100M,分块size 2K,遍历计算仅耗时275ms.
103 |
104 | #2.rsync HashTable
105 | **rolling计算足够快了,用B文件每个块的校验值check A文件的校验表,如何优化?**
106 |
107 | A文件的校验表size = 102400,冒泡?快速?折半?
108 | rsync使用二段HashTable来存储校验值,即H(A, H(B, MD5))
109 | 用adler32的A做key, B+MD5做value, 其中再用alder32的B做key, MD5做value.
110 | 表大小2^16,满足A的值范围.冲突值用LinkList存储.
111 |
112 | 首先命中A,再命中B,最后顺序遍历LinkList命中MD5.完成!
113 | 直接使用adler32值做key,MD5做value也可以,选择合适的散列算法即可.
114 |
115 | **HashTable解决了命中率的问题,但是实际中存在大量的missing查找.如何优化?**
116 |
117 | zsync在此基础上,使用一个bitbuffer来构建"缺失表",每个分块用3个bit表示,首先做位运算,若存在再访问HashTable,否则直接跳过.
118 |
119 | crsync使用2^20的Bloom filter做faster missing. 为什么是2^20? 兼顾速度提升和内存开销(2^20 = 128KB)
120 |
121 | #3.client-side rsync
122 | rsync是C/S架构,依赖rsyncd服务端存在,执行流程是:
123 |
124 | 1. client生成本地校验表.发送给server
125 | 2. server执行rsync rolling,发送相同块的index和差异块的数据.
126 | 3. client接受指令,执行merge.
127 |
128 | 是否可以去掉rsyncd server,只依赖HttpServer(CDN)存储文件和校验表,客户端执行rsync rolling?
129 | crsync和zsync为此而生.
130 |
131 | 1. 制作新版本文件,生成校验表,一并上传CDN.
132 | 2. client下载新版本的校验表.
133 | 3. client根据本地文件和新校验表,执行rsync rolling,得到重复数据index和差异数据的块index.
134 | 4. client重用本地数据,下载差异数据,合并写入新文件.
135 | 5. done!
136 |
137 | #4.crsync VS bs diff/patch
138 |
139 | **测试对比1:**
140 | 测试文件: 无尽之剑Android版资源包, base14009.obb ~ base14012.obb 92MB~93MB
141 | 编译版本: MinGW 32bit release
142 | Bloom filter: 2^20
143 | 纯本地差异查找与合并,无网络开销
144 |
145 | 测试机: DELL PC, Intel i3 550 (4core 3.2GHz) 4GB RAM
146 |
147 | | 分块大小 | 校验表生成时间 | 校验块数量 | 差异查找时间 | 重复块数量 | 差异块大小 |
148 | | :------- | :----------: | :-------: | :---------: | :------: | --------: |
149 | | 2K | 2182 ms | 46328 | 3753 ms | 40418 | 11820 KB |
150 | | 4K | 2156 ms | 23164 | 2914 ms | 18960 | 16816 KB |
151 | | 8K | 2154 ms | 11582 | 2719 ms | 9249 | 18664 KB |
152 |
153 | 测试机 HP PC, Intel i7-3770 (8core 3.4GHz) 8GB RAM:
154 |
155 | | 分块大小 | 校验表生成时间 | 校验块数量 | 差异查找时间 | 重复块数量 | 差异块大小 |
156 | | :------- | :----------: | :-------: | :---------: | :------: | --------: |
157 | | 2K | 1745 ms | 46328 | 2974 ms | 40418 | 11820 KB |
158 |
159 | **crsync VS bspatch**
160 |
161 | | 算法 | 差异量 | 内存开销 |
162 | | :--- | :----------: | --------: |
163 | | bsdiff | 16.7MB (diff文件) | 108.7MB (92MB+16.7MB) |
164 | | crsync | **12.36MB**(校验表835KB + 差异数据11820KB) | **1.76MB** |
165 |
166 | **测试对比2:**
167 | 测试文件: [我叫MT online Android标准版](http://update2.locojoy.com/android/IamMT/150413/IamMT_200100100_locojoy_standard_ac_4.5.4.0_4540.apk) 90.7MB ~ [我叫MT online Android高清版](http://update.locojoy.com/Client/Android/MT-A/0324/IamMT_200100100_locojoy_ac_hd_4.5.4.0_4540.apk) 102MB
168 | (测试版本基于2015.4.4官网下载,目前已变更)
169 |
170 |
171 | 测试机 HP PC, Intel i7-3770 (8core 3.4GHz) 8GB RAM:
172 |
173 | | 分块大小 | 校验表生成时间 | 差异查找时间 | merge时间 |
174 | | :------- | :----------: | :---------: | --------: |
175 | | 2K | 1379 ms | 2950 ms | 90ms |
176 |
177 | **crsync VS bs diff/patch**
178 |
179 | | 算法 | 差异量 | 内存开销 |
180 | | :------- | :----------: | --------: |
181 | | bsdiff | **29.5MB** (diff文件) | 120.2MB (90.7MB+29.5MB) |
182 | | crsync | 40.8MB | **1.7MB** |
183 |
184 | **这里发现, 为什么无尽之剑资源包使用crsync得到的差异量更小?**
185 | **那么问题来了, 如何设计出适合差异更新的文件格式**
186 | 几种格式对比:
187 |
188 | 1. 整个文件不压缩,完整下载量大,更新量小,bsdiff更优,因为diff文件使用bzip2压缩格式.crsync使用原始数据http range下载.
189 | 2. 整个文件zip压缩,完整下载量大,更新量更大,这时bsdiff和crsync都无效.因为少量改动就会造成整个文件的大量差异.
190 | 3. 文件内容用zip压缩,再序列化到一起,完整下载量小,更新量小.这时crsync更优,因为bsdiff对zip压缩过的数据处理会生成额外数据量.
191 |
192 | UnrealEngine3 Android使用的obb格式为:**文件头**(贴图原始大小, 压缩大小,文件体偏移位置)+**文件体**(贴图内容zip压缩).
193 | 资源更改只影响zip压缩部分和文件头索引内容.对其他未更改资源无影响.
194 |
195 | Android APK是zip压缩格式,但是特定后缀名的文件不压缩,常见图片音视频文件为了支持流式read保持原始格式.
196 | 因此crsync对比bsdiff的差异量大些.
197 |
198 | #5.源码
199 | 纯C语言实现, 遵循C99, 核心部分仅2个文件 crsync.h crsync.c 880行代码.static-link libcurl.
200 | release版Android so 166KB, Windows mingw32 exe 299KB.
201 | API实现参考curl设计
202 |
203 | ```c
204 | CRSYNCcode crsync_global_init();
205 | crsync_handle_t* crsync_easy_init();
206 |
207 | CRSYNCcode crsync_easy_setopt(crsync_handle_t *handle, CRSYNCoption opt, ...);
208 |
209 | CRSYNCcode crsync_easy_perform_match(crsync_handle_t *handle);
210 | CRSYNCcode crsync_easy_perform_patch(crsync_handle_t *handle);
211 |
212 | void crsync_easy_cleanup(crsync_handle_t *handle);
213 | void crsync_global_cleanup();
214 | ```
215 |
216 | 源码托管在[https://github.com/9468305/crsync](https://github.com/9468305/crsync)
217 |
218 | #6.附录
219 | - [rsync官网](http://rsync.samba.org/)
220 | - [rsync算法论文](http://samba.org/~tridge/phd_thesis.pdf)
221 | - [librsync](http://librsync.sourceforge.net/)
222 | - [zsync](http://zsync.moria.org.uk/)
223 | - [BS diff/patch](http://www.daemonology.net/bsdiff/)
224 | - [Jarsync - a Java rsync implementation](http://sourceforge.net/projects/jarsync/)
225 | - [rsync教程](http://tutorials.jenkov.com/rsync/index.html)
226 | - [rsync java教程](http://javaforu.blogspot.com/2014/01/rsync-in-java-quick-and-partial-hack.html)
227 | - [REBL算法](http://www.research.ibm.com/people/f/fdouglis/papers/rebl.pdf)
228 | - [TAPER算法](http://www.usenix.org/events/fast05/tech/full_papers/jain/jain.pdf)
229 |
--------------------------------------------------------------------------------
/extra/dictionary.h:
--------------------------------------------------------------------------------
1 |
2 | /*-------------------------------------------------------------------------*/
3 | /**
4 | @file dictionary.h
5 | @author N. Devillard
6 | @brief Implements a dictionary for string variables.
7 |
8 | This module implements a simple dictionary object, i.e. a list
9 | of string/string associations. This object is useful to store e.g.
10 | informations retrieved from a configuration file (ini files).
11 | */
12 | /*--------------------------------------------------------------------------*/
13 |
14 | #ifndef _DICTIONARY_H_
15 | #define _DICTIONARY_H_
16 |
17 | /*---------------------------------------------------------------------------
18 | Includes
19 | ---------------------------------------------------------------------------*/
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | #ifdef __cplusplus
27 | extern "C" {
28 | #endif
29 |
30 | /*---------------------------------------------------------------------------
31 | New types
32 | ---------------------------------------------------------------------------*/
33 |
34 |
35 | /*-------------------------------------------------------------------------*/
36 | /**
37 | @brief Dictionary object
38 |
39 | This object contains a list of string/string associations. Each
40 | association is identified by a unique string key. Looking up values
41 | in the dictionary is speeded up by the use of a (hopefully collision-free)
42 | hash function.
43 | */
44 | /*-------------------------------------------------------------------------*/
45 | typedef struct _dictionary_ {
46 | int n ; /** Number of entries in dictionary */
47 | ssize_t size ; /** Storage size */
48 | char ** val ; /** List of string values */
49 | char ** key ; /** List of string keys */
50 | unsigned * hash ; /** List of hash values for keys */
51 | } dictionary ;
52 |
53 |
54 | /*---------------------------------------------------------------------------
55 | Function prototypes
56 | ---------------------------------------------------------------------------*/
57 |
58 | /*-------------------------------------------------------------------------*/
59 | /**
60 | @brief Compute the hash key for a string.
61 | @param key Character string to use for key.
62 | @return 1 unsigned int on at least 32 bits.
63 |
64 | This hash function has been taken from an Article in Dr Dobbs Journal.
65 | This is normally a collision-free function, distributing keys evenly.
66 | The key is stored anyway in the struct so that collision can be avoided
67 | by comparing the key itself in last resort.
68 | */
69 | /*--------------------------------------------------------------------------*/
70 | unsigned dictionary_hash(const char * key);
71 |
72 | /*-------------------------------------------------------------------------*/
73 | /**
74 | @brief Create a new dictionary object.
75 | @param size Optional initial size of the dictionary.
76 | @return 1 newly allocated dictionary objet.
77 |
78 | This function allocates a new dictionary object of given size and returns
79 | it. If you do not know in advance (roughly) the number of entries in the
80 | dictionary, give size=0.
81 | */
82 | /*--------------------------------------------------------------------------*/
83 | dictionary * dictionary_new(size_t size);
84 |
85 | /*-------------------------------------------------------------------------*/
86 | /**
87 | @brief Delete a dictionary object
88 | @param d dictionary object to deallocate.
89 | @return void
90 |
91 | Deallocate a dictionary object and all memory associated to it.
92 | */
93 | /*--------------------------------------------------------------------------*/
94 | void dictionary_del(dictionary * vd);
95 |
96 | /*-------------------------------------------------------------------------*/
97 | /**
98 | @brief Get a value from a dictionary.
99 | @param d dictionary object to search.
100 | @param key Key to look for in the dictionary.
101 | @param def Default value to return if key not found.
102 | @return 1 pointer to internally allocated character string.
103 |
104 | This function locates a key in a dictionary and returns a pointer to its
105 | value, or the passed 'def' pointer if no such key can be found in
106 | dictionary. The returned character pointer points to data internal to the
107 | dictionary object, you should not try to free it or modify it.
108 | */
109 | /*--------------------------------------------------------------------------*/
110 | const char * dictionary_get(const dictionary * d, const char * key, const char * def);
111 |
112 |
113 | /*-------------------------------------------------------------------------*/
114 | /**
115 | @brief Set a value in a dictionary.
116 | @param d dictionary object to modify.
117 | @param key Key to modify or add.
118 | @param val Value to add.
119 | @return int 0 if Ok, anything else otherwise
120 |
121 | If the given key is found in the dictionary, the associated value is
122 | replaced by the provided one. If the key cannot be found in the
123 | dictionary, it is added to it.
124 |
125 | It is Ok to provide a NULL value for val, but NULL values for the dictionary
126 | or the key are considered as errors: the function will return immediately
127 | in such a case.
128 |
129 | Notice that if you dictionary_set a variable to NULL, a call to
130 | dictionary_get will return a NULL value: the variable will be found, and
131 | its value (NULL) is returned. In other words, setting the variable
132 | content to NULL is equivalent to deleting the variable from the
133 | dictionary. It is not possible (in this implementation) to have a key in
134 | the dictionary without value.
135 |
136 | This function returns non-zero in case of failure.
137 | */
138 | /*--------------------------------------------------------------------------*/
139 | int dictionary_set(dictionary * vd, const char * key, const char * val);
140 |
141 | /*-------------------------------------------------------------------------*/
142 | /**
143 | @brief Delete a key in a dictionary
144 | @param d dictionary object to modify.
145 | @param key Key to remove.
146 | @return void
147 |
148 | This function deletes a key in a dictionary. Nothing is done if the
149 | key cannot be found.
150 | */
151 | /*--------------------------------------------------------------------------*/
152 | void dictionary_unset(dictionary * d, const char * key);
153 |
154 |
155 | /*-------------------------------------------------------------------------*/
156 | /**
157 | @brief Dump a dictionary to an opened file pointer.
158 | @param d Dictionary to dump
159 | @param f Opened file pointer.
160 | @return void
161 |
162 | Dumps a dictionary onto an opened file pointer. Key pairs are printed out
163 | as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
164 | output file pointers.
165 | */
166 | /*--------------------------------------------------------------------------*/
167 | void dictionary_dump(const dictionary * d, FILE * out);
168 |
169 | #ifdef __cplusplus
170 | }
171 | #endif
172 |
173 | #endif
174 |
--------------------------------------------------------------------------------
/extra/md5.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
3 | * MD5 Message-Digest Algorithm (RFC 1321).
4 | *
5 | * Homepage:
6 | * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
7 | *
8 | * Author:
9 | * Alexander Peslyak, better known as Solar Designer
10 | *
11 | * This software was written by Alexander Peslyak in 2001. No copyright is
12 | * claimed, and the software is hereby placed in the public domain.
13 | * In case this attempt to disclaim copyright and place the software in the
14 | * public domain is deemed null and void, then the software is
15 | * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
16 | * general public under the following terms:
17 | *
18 | * Redistribution and use in source and binary forms, with or without
19 | * modification, are permitted.
20 | *
21 | * There's ABSOLUTELY NO WARRANTY, express or implied.
22 | *
23 | * See md5.c for more information.
24 | */
25 |
26 | #ifndef _MD5_H
27 | #define _MD5_H
28 |
29 | #define MD5_OUTBYTES 16
30 |
31 | /* Any 32-bit or wider unsigned integer data type will do */
32 | typedef unsigned int MD5_u32plus;
33 |
34 | typedef struct {
35 | MD5_u32plus lo, hi;
36 | MD5_u32plus a, b, c, d;
37 | unsigned char buffer[64];
38 | MD5_u32plus block[16];
39 | } MD5_CTX;
40 |
41 | void MD5_Init(MD5_CTX *ctx);
42 | void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
43 | void MD5_Final(MD5_CTX *ctx, unsigned char *result);
44 |
45 | /* Author: chenqi, <9468305@gmail.com> */
46 | void MD5_Data(const void *data, unsigned long size, unsigned char *result);
47 | int MD5_File(const char *filename, unsigned char *result);
48 | int MD5_File_Parallel(const char *filename, unsigned char *result);
49 |
50 | #endif
51 |
--------------------------------------------------------------------------------
/extra/tpl.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2005-2013, Troy D. Hanson http://troydhanson.github.com/tpl/
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright
9 | notice, this list of conditions and the following disclaimer.
10 |
11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 | */
23 |
24 | #ifndef TPL_H
25 | #define TPL_H
26 |
27 | #include /* size_t */
28 |
29 | #include /* va_list */
30 |
31 | #ifdef __INTEL_COMPILER
32 | # include
33 | #endif /* Intel Compiler efficient memcpy etc */
34 |
35 | #ifdef _MSC_VER
36 | typedef unsigned int uint32_t;
37 | #else
38 | # include /* uint32_t */
39 | #endif
40 |
41 | #if defined __cplusplus
42 | extern "C" {
43 | #endif
44 |
45 | #define TPL_NOLIB
46 |
47 | #ifdef _WIN32
48 | # ifdef TPL_EXPORTS
49 | # define TPL_API __declspec(dllexport)
50 | # else /* */
51 | # ifdef TPL_NOLIB
52 | # define TPL_API
53 | # else
54 | # define TPL_API __declspec(dllimport)
55 | # endif /* TPL_NOLIB */
56 | # endif /* TPL_EXPORTS*/
57 | #else
58 | # define TPL_API
59 | #endif
60 |
61 | /* bit flags (external) */
62 | #define TPL_FILE (1 << 0)
63 | #define TPL_MEM (1 << 1)
64 | #define TPL_PREALLOCD (1 << 2)
65 | #define TPL_EXCESS_OK (1 << 3)
66 | #define TPL_FD (1 << 4)
67 | #define TPL_UFREE (1 << 5)
68 | #define TPL_DATAPEEK (1 << 6)
69 | #define TPL_FXLENS (1 << 7)
70 | #define TPL_GETSIZE (1 << 8)
71 | /* do not add flags here without renumbering the internal flags! */
72 |
73 | /* flags for tpl_gather mode */
74 | #define TPL_GATHER_BLOCKING 1
75 | #define TPL_GATHER_NONBLOCKING 2
76 | #define TPL_GATHER_MEM 3
77 |
78 | /* Hooks for error logging, memory allocation functions and fatal */
79 | typedef int (tpl_print_fcn)(const char *fmt, ...);
80 | typedef void *(tpl_malloc_fcn)(size_t sz);
81 | typedef void *(tpl_realloc_fcn)(void *ptr, size_t sz);
82 | typedef void (tpl_free_fcn)(void *ptr);
83 | typedef void (tpl_fatal_fcn)(const char *fmt, ...);
84 |
85 | typedef struct tpl_hook_t {
86 | tpl_print_fcn *oops;
87 | tpl_malloc_fcn *malloc;
88 | tpl_realloc_fcn *realloc;
89 | tpl_free_fcn *free;
90 | tpl_fatal_fcn *fatal;
91 | size_t gather_max;
92 | } tpl_hook_t;
93 |
94 | typedef struct tpl_node {
95 | int type;
96 | void *addr;
97 | void *data; /* r:tpl_root_data*. A:tpl_atyp*. ow:szof type */
98 | int num; /* length of type if its a C array */
99 | size_t ser_osz; /* serialization output size for subtree */
100 | struct tpl_node *children; /* my children; linked-list */
101 | struct tpl_node *next,*prev; /* my siblings (next child of my parent) */
102 | struct tpl_node *parent; /* my parent */
103 | } tpl_node;
104 |
105 | /* used when un/packing 'B' type (binary buffers) */
106 | typedef struct tpl_bin {
107 | void *addr;
108 | uint32_t sz;
109 | } tpl_bin;
110 |
111 | /* for async/piecemeal reading of tpl images */
112 | typedef struct tpl_gather_t {
113 | char *img;
114 | int len;
115 | } tpl_gather_t;
116 |
117 | /* Callback used when tpl_gather has read a full tpl image */
118 | typedef int (tpl_gather_cb)(void *img, size_t sz, void *data);
119 |
120 | /* Prototypes */
121 | TPL_API tpl_node *tpl_map(const char *fmt,...); /* define tpl using format */
122 | TPL_API void tpl_free(tpl_node *r); /* free a tpl map */
123 | TPL_API int tpl_pack(tpl_node *r, int i); /* pack the n'th packable */
124 | TPL_API int tpl_unpack(tpl_node *r, int i); /* unpack the n'th packable */
125 | TPL_API int tpl_dump(tpl_node *r, int mode, ...); /* serialize to mem/file */
126 | TPL_API int tpl_load(tpl_node *r, int mode, ...); /* set mem/file to unpack */
127 | TPL_API int tpl_Alen(tpl_node *r, int i); /* array len of packable i */
128 | TPL_API char* tpl_peek(int mode, ...); /* sneak peek at format string */
129 | TPL_API int tpl_gather( int mode, ...); /* non-blocking image gather */
130 | TPL_API int tpl_jot(int mode, ...); /* quick write a simple tpl */
131 |
132 | TPL_API tpl_node *tpl_map_va(const char *fmt, va_list ap);
133 |
134 | /* mmap record */
135 | typedef struct tpl_mmap_rec {
136 | int fd;
137 | void *text;
138 | size_t text_sz;
139 | } tpl_mmap_rec;
140 |
141 | TPL_API int tpl_mmap_output_file(const char *filename, size_t sz, void **text_out);
142 | TPL_API int tpl_mmap_file(const char *filename, tpl_mmap_rec *map_rec);
143 | TPL_API int tpl_unmap_file(tpl_mmap_rec *mr);
144 | TPL_API void tpl_bin_malloc(tpl_bin *bin, size_t len);
145 | TPL_API void tpl_bin_free(tpl_bin *bin);
146 |
147 | #if defined __cplusplus
148 | }
149 | #endif
150 |
151 | #endif /* TPL_H */
152 |
153 |
--------------------------------------------------------------------------------
/extra/win/mman.h:
--------------------------------------------------------------------------------
1 | #ifndef _MMAN_H_
2 | #define _MMAN_H_
3 |
4 | /* Protections */
5 | #define PROT_NONE 0x00 /* no permissions */
6 | #define PROT_READ 0x01 /* pages can be read */
7 | #define PROT_WRITE 0x02 /* pages can be written */
8 | #define PROT_EXEC 0x04 /* pages can be executed */
9 |
10 | /* Sharing type and options */
11 | #define MAP_SHARED 0x0001 /* share changes */
12 | #define MAP_PRIVATE 0x0002 /* changes are private */
13 | #define MAP_COPY MAP_PRIVATE /* Obsolete */
14 | #define MAP_FIXED 0x0010 /* map addr must be exactly as requested */
15 | #define MAP_RENAME 0x0020 /* Sun: rename private pages to file */
16 | #define MAP_NORESERVE 0x0040 /* Sun: don't reserve needed swap area */
17 | #define MAP_INHERIT 0x0080 /* region is retained after exec */
18 | #define MAP_NOEXTEND 0x0100 /* for MAP_FILE, don't change file size */
19 | #define MAP_HASSEMAPHORE 0x0200 /* region may contain semaphores */
20 | #define MAP_STACK 0x0400 /* region grows down, like a stack */
21 |
22 | /* Error returned from mmap() */
23 | #define MAP_FAILED ((void *)-1)
24 |
25 | /* Flags to msync */
26 | #define MS_ASYNC 0x01 /* perform asynchronous writes */
27 | #define MS_SYNC 0x02 /* perform synchronous writes */
28 | #define MS_INVALIDATE 0x04 /* invalidate cached data */
29 |
30 | /* File modes for 'open' not defined in MinGW32 (not used by mmap) */
31 | #ifndef S_IWGRP
32 | #define S_IWGRP 0
33 | #define S_IRGRP 0
34 | #define S_IROTH 0
35 | #endif
36 |
37 | /**
38 | * Map a file to a memory region
39 | */
40 | void *mmap(void *addr, unsigned int len, int prot, int flags, int fd, unsigned int offset);
41 |
42 | /**
43 | * Unmap a memory region
44 | */
45 | int munmap(void *addr, int len);
46 |
47 | /**
48 | * Synchronize a mapped region
49 | */
50 | int msync(char *addr, int len, int flags);
51 |
52 | #endif /* _MMAN_H_ */
53 |
--------------------------------------------------------------------------------
/extra/win/mmap.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #ifdef _WIN32
4 | #include
5 | #endif
6 | #include
7 | #include "mman.h"
8 |
9 | static const char id[]="$Id: tpl.c 107 2007-04-20 17:11:29Z thanson $";
10 |
11 | /**
12 | * @brief Map a file to a memory region
13 | *
14 | * This function emulates the POSIX mmap() using CreateFileMapping() and
15 | * MapViewOfFile()
16 | *
17 | * @param addr the suggested start address (if != 0)
18 | * @param len length of the region
19 | * @param prot region accesibility, bitwise OR of PROT_READ, PROT_WRITE, PROT_EXEC
20 | * @param flags mapping type and options (ignored)
21 | * @param fd object to be mapped into memory
22 | * @param offset offset into mapped object
23 | * @return pointer to the memory region, or NULL in case of error
24 | */
25 | void *mmap(void *addr, unsigned int len, int prot, int flags, int fd, unsigned int offset)
26 | {
27 | (void)addr;
28 | (void)flags;
29 | (void)offset;
30 | DWORD wprot;
31 | DWORD waccess;
32 | HANDLE h;
33 | void *region;
34 |
35 | /* Translate read/write/exec flags into WIN32 constants */
36 | switch (prot) {
37 | case PROT_READ:
38 | wprot = PAGE_READONLY;
39 | break;
40 | case PROT_EXEC:
41 | wprot = PAGE_EXECUTE_READ;
42 | break;
43 | case PROT_READ | PROT_EXEC:
44 | wprot = PAGE_EXECUTE_READ;
45 | break;
46 | case PROT_WRITE:
47 | wprot = PAGE_READWRITE;
48 | break;
49 | case PROT_READ | PROT_WRITE:
50 | wprot = PAGE_READWRITE;
51 | break;
52 | case PROT_READ | PROT_WRITE | PROT_EXEC:
53 | wprot = PAGE_EXECUTE_READWRITE;
54 | break;
55 | case PROT_WRITE | PROT_EXEC:
56 | wprot = PAGE_EXECUTE_READWRITE;
57 | break;
58 | default:
59 | return MAP_FAILED;
60 | }
61 |
62 | /* Obtaing handle to map region */
63 | h = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, wprot, 0, len, 0);
64 | if (h == NULL) {
65 | DWORD error = GetLastError();
66 |
67 | /* Try and translate some error codes */
68 | switch (error) {
69 | case ERROR_ACCESS_DENIED:
70 | case ERROR_INVALID_ACCESS:
71 | errno = EACCES;
72 | break;
73 | case ERROR_OUTOFMEMORY:
74 | case ERROR_NOT_ENOUGH_MEMORY:
75 | errno = ENOMEM;
76 | break;
77 | default:
78 | errno = EINVAL;
79 | break;
80 | }
81 | return MAP_FAILED;
82 | }
83 |
84 |
85 | /* Translate sharing options into WIN32 constants */
86 | switch (wprot) {
87 | case PAGE_READONLY:
88 | waccess = FILE_MAP_READ;
89 | break;
90 | case PAGE_READWRITE:
91 | waccess = FILE_MAP_WRITE;
92 | break;
93 | default:
94 | CloseHandle(h);
95 | return MAP_FAILED;
96 | }
97 |
98 | /* Map file and return pointer */
99 | region = MapViewOfFile(h, waccess, 0, 0, 0);
100 | if (region == NULL) {
101 | DWORD error = GetLastError();
102 |
103 | /* Try and translate some error codes */
104 | switch (error) {
105 | case ERROR_ACCESS_DENIED:
106 | case ERROR_INVALID_ACCESS:
107 | errno = EACCES;
108 | break;
109 | case ERROR_INVALID_HANDLE:
110 | errno = EBADF;
111 | break;
112 | default:
113 | errno = EINVAL;
114 | break;
115 | }
116 | CloseHandle(h);
117 | return MAP_FAILED;
118 | }
119 | CloseHandle(h); /* ok to call UnmapViewOfFile after this */
120 |
121 | /* All fine */
122 | return region;
123 | }
124 |
125 |
126 | /**
127 | * @brief Unmap a memory region
128 | *
129 | * This is a wrapper around UnmapViewOfFile in the win32 API
130 | *
131 | * @param addr start address
132 | * @param len length of the region
133 | * @return 0 for success, -1 for error
134 | */
135 | int munmap(void *addr, int len)
136 | {
137 | (void)len;
138 | if (UnmapViewOfFile(addr)) {
139 | return 0;
140 | }
141 | else {
142 | errno = EINVAL;
143 | return -1;
144 | }
145 | }
146 |
147 |
148 | /**
149 | * Synchronize a mapped region
150 | *
151 | * This is a wrapper around FlushViewOfFile
152 | *
153 | * @param addr start address
154 | * @param len number of bytes to flush
155 | * @param flags sync options -- currently ignored
156 | * @return 0 for success, -1 for error
157 | */
158 | int msync(char *addr, int len, int flags)
159 | {
160 | (void)flags;
161 | if (FlushViewOfFile(addr, len) == 0) {
162 | DWORD error = GetLastError();
163 |
164 | /* Try and translate some error codes */
165 | switch (error) {
166 | case ERROR_INVALID_PARAMETER:
167 | errno = EINVAL;
168 | break;
169 | case ERROR_WRITE_FAULT:
170 | errno = EIO;
171 | break;
172 | default:
173 | errno = EINVAL;
174 | break;
175 | }
176 | return -1;
177 | }
178 |
179 | /* Success */
180 | return 0;
181 | }
182 |
--------------------------------------------------------------------------------
/libcurl/include/curl/curlrules.h:
--------------------------------------------------------------------------------
1 | #ifndef __CURL_CURLRULES_H
2 | #define __CURL_CURLRULES_H
3 | /***************************************************************************
4 | * _ _ ____ _
5 | * Project ___| | | | _ \| |
6 | * / __| | | | |_) | |
7 | * | (__| |_| | _ <| |___
8 | * \___|\___/|_| \_\_____|
9 | *
10 | * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al.
11 | *
12 | * This software is licensed as described in the file COPYING, which
13 | * you should have received as part of this distribution. The terms
14 | * are also available at http://curl.haxx.se/docs/copyright.html.
15 | *
16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell
17 | * copies of the Software, and permit persons to whom the Software is
18 | * furnished to do so, under the terms of the COPYING file.
19 | *
20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 | * KIND, either express or implied.
22 | *
23 | ***************************************************************************/
24 |
25 | /* ================================================================ */
26 | /* COMPILE TIME SANITY CHECKS */
27 | /* ================================================================ */
28 |
29 | /*
30 | * NOTE 1:
31 | * -------
32 | *
33 | * All checks done in this file are intentionally placed in a public
34 | * header file which is pulled by curl/curl.h when an application is
35 | * being built using an already built libcurl library. Additionally
36 | * this file is also included and used when building the library.
37 | *
38 | * If compilation fails on this file it is certainly sure that the
39 | * problem is elsewhere. It could be a problem in the curlbuild.h
40 | * header file, or simply that you are using different compilation
41 | * settings than those used to build the library.
42 | *
43 | * Nothing in this file is intended to be modified or adjusted by the
44 | * curl library user nor by the curl library builder.
45 | *
46 | * Do not deactivate any check, these are done to make sure that the
47 | * library is properly built and used.
48 | *
49 | * You can find further help on the libcurl development mailing list:
50 | * http://cool.haxx.se/mailman/listinfo/curl-library/
51 | *
52 | * NOTE 2
53 | * ------
54 | *
55 | * Some of the following compile time checks are based on the fact
56 | * that the dimension of a constant array can not be a negative one.
57 | * In this way if the compile time verification fails, the compilation
58 | * will fail issuing an error. The error description wording is compiler
59 | * dependent but it will be quite similar to one of the following:
60 | *
61 | * "negative subscript or subscript is too large"
62 | * "array must have at least one element"
63 | * "-1 is an illegal array size"
64 | * "size of array is negative"
65 | *
66 | * If you are building an application which tries to use an already
67 | * built libcurl library and you are getting this kind of errors on
68 | * this file, it is a clear indication that there is a mismatch between
69 | * how the library was built and how you are trying to use it for your
70 | * application. Your already compiled or binary library provider is the
71 | * only one who can give you the details you need to properly use it.
72 | */
73 |
74 | /*
75 | * Verify that some macros are actually defined.
76 | */
77 |
78 | #ifndef CURL_SIZEOF_LONG
79 | # error "CURL_SIZEOF_LONG definition is missing!"
80 | Error Compilation_aborted_CURL_SIZEOF_LONG_is_missing
81 | #endif
82 |
83 | #ifndef CURL_TYPEOF_CURL_SOCKLEN_T
84 | # error "CURL_TYPEOF_CURL_SOCKLEN_T definition is missing!"
85 | Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_is_missing
86 | #endif
87 |
88 | #ifndef CURL_SIZEOF_CURL_SOCKLEN_T
89 | # error "CURL_SIZEOF_CURL_SOCKLEN_T definition is missing!"
90 | Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_is_missing
91 | #endif
92 |
93 | #ifndef CURL_TYPEOF_CURL_OFF_T
94 | # error "CURL_TYPEOF_CURL_OFF_T definition is missing!"
95 | Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_is_missing
96 | #endif
97 |
98 | #ifndef CURL_FORMAT_CURL_OFF_T
99 | # error "CURL_FORMAT_CURL_OFF_T definition is missing!"
100 | Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_is_missing
101 | #endif
102 |
103 | #ifndef CURL_FORMAT_CURL_OFF_TU
104 | # error "CURL_FORMAT_CURL_OFF_TU definition is missing!"
105 | Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_is_missing
106 | #endif
107 |
108 | #ifndef CURL_FORMAT_OFF_T
109 | # error "CURL_FORMAT_OFF_T definition is missing!"
110 | Error Compilation_aborted_CURL_FORMAT_OFF_T_is_missing
111 | #endif
112 |
113 | #ifndef CURL_SIZEOF_CURL_OFF_T
114 | # error "CURL_SIZEOF_CURL_OFF_T definition is missing!"
115 | Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_is_missing
116 | #endif
117 |
118 | #ifndef CURL_SUFFIX_CURL_OFF_T
119 | # error "CURL_SUFFIX_CURL_OFF_T definition is missing!"
120 | Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_is_missing
121 | #endif
122 |
123 | #ifndef CURL_SUFFIX_CURL_OFF_TU
124 | # error "CURL_SUFFIX_CURL_OFF_TU definition is missing!"
125 | Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_is_missing
126 | #endif
127 |
128 | /*
129 | * Macros private to this header file.
130 | */
131 |
132 | #define CurlchkszEQ(t, s) sizeof(t) == s ? 1 : -1
133 |
134 | #define CurlchkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1
135 |
136 | /*
137 | * Verify that the size previously defined and expected for long
138 | * is the same as the one reported by sizeof() at compile time.
139 | */
140 |
141 | typedef char
142 | __curl_rule_01__
143 | [CurlchkszEQ(long, CURL_SIZEOF_LONG)];
144 |
145 | /*
146 | * Verify that the size previously defined and expected for
147 | * curl_off_t is actually the the same as the one reported
148 | * by sizeof() at compile time.
149 | */
150 |
151 | typedef char
152 | __curl_rule_02__
153 | [CurlchkszEQ(curl_off_t, CURL_SIZEOF_CURL_OFF_T)];
154 |
155 | /*
156 | * Verify at compile time that the size of curl_off_t as reported
157 | * by sizeof() is greater or equal than the one reported for long
158 | * for the current compilation.
159 | */
160 |
161 | typedef char
162 | __curl_rule_03__
163 | [CurlchkszGE(curl_off_t, long)];
164 |
165 | /*
166 | * Verify that the size previously defined and expected for
167 | * curl_socklen_t is actually the the same as the one reported
168 | * by sizeof() at compile time.
169 | */
170 |
171 | typedef char
172 | __curl_rule_04__
173 | [CurlchkszEQ(curl_socklen_t, CURL_SIZEOF_CURL_SOCKLEN_T)];
174 |
175 | /*
176 | * Verify at compile time that the size of curl_socklen_t as reported
177 | * by sizeof() is greater or equal than the one reported for int for
178 | * the current compilation.
179 | */
180 |
181 | typedef char
182 | __curl_rule_05__
183 | [CurlchkszGE(curl_socklen_t, int)];
184 |
185 | /* ================================================================ */
186 | /* EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS */
187 | /* ================================================================ */
188 |
189 | /*
190 | * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow
191 | * these to be visible and exported by the external libcurl interface API,
192 | * while also making them visible to the library internals, simply including
193 | * curl_setup.h, without actually needing to include curl.h internally.
194 | * If some day this section would grow big enough, all this should be moved
195 | * to its own header file.
196 | */
197 |
198 | /*
199 | * Figure out if we can use the ## preprocessor operator, which is supported
200 | * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__
201 | * or __cplusplus so we need to carefully check for them too.
202 | */
203 |
204 | #if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
205 | defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \
206 | defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \
207 | defined(__ILEC400__)
208 | /* This compiler is believed to have an ISO compatible preprocessor */
209 | #define CURL_ISOCPP
210 | #else
211 | /* This compiler is believed NOT to have an ISO compatible preprocessor */
212 | #undef CURL_ISOCPP
213 | #endif
214 |
215 | /*
216 | * Macros for minimum-width signed and unsigned curl_off_t integer constants.
217 | */
218 |
219 | #if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551)
220 | # define __CURL_OFF_T_C_HLPR2(x) x
221 | # define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x)
222 | # define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \
223 | __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T)
224 | # define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \
225 | __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU)
226 | #else
227 | # ifdef CURL_ISOCPP
228 | # define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix
229 | # else
230 | # define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix
231 | # endif
232 | # define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix)
233 | # define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T)
234 | # define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU)
235 | #endif
236 |
237 | /*
238 | * Get rid of macros private to this header file.
239 | */
240 |
241 | #undef CurlchkszEQ
242 | #undef CurlchkszGE
243 |
244 | /*
245 | * Get rid of macros not intended to exist beyond this point.
246 | */
247 |
248 | #undef CURL_PULL_WS2TCPIP_H
249 | #undef CURL_PULL_SYS_TYPES_H
250 | #undef CURL_PULL_SYS_SOCKET_H
251 | #undef CURL_PULL_SYS_POLL_H
252 | #undef CURL_PULL_STDINT_H
253 | #undef CURL_PULL_INTTYPES_H
254 |
255 | #undef CURL_TYPEOF_CURL_SOCKLEN_T
256 | #undef CURL_TYPEOF_CURL_OFF_T
257 |
258 | #ifdef CURL_NO_OLDIES
259 | #undef CURL_FORMAT_OFF_T /* not required since 7.19.0 - obsoleted in 7.20.0 */
260 | #endif
261 |
262 | #endif /* __CURL_CURLRULES_H */
263 |
--------------------------------------------------------------------------------
/libcurl/include/curl/curlver.h:
--------------------------------------------------------------------------------
1 | #ifndef __CURL_CURLVER_H
2 | #define __CURL_CURLVER_H
3 | /***************************************************************************
4 | * _ _ ____ _
5 | * Project ___| | | | _ \| |
6 | * / __| | | | |_) | |
7 | * | (__| |_| | _ <| |___
8 | * \___|\___/|_| \_\_____|
9 | *
10 | * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al.
11 | *
12 | * This software is licensed as described in the file COPYING, which
13 | * you should have received as part of this distribution. The terms
14 | * are also available at http://curl.haxx.se/docs/copyright.html.
15 | *
16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell
17 | * copies of the Software, and permit persons to whom the Software is
18 | * furnished to do so, under the terms of the COPYING file.
19 | *
20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 | * KIND, either express or implied.
22 | *
23 | ***************************************************************************/
24 |
25 | /* This header file contains nothing but libcurl version info, generated by
26 | a script at release-time. This was made its own header file in 7.11.2 */
27 |
28 | /* This is the global package copyright */
29 | #define LIBCURL_COPYRIGHT "1996 - 2015 Daniel Stenberg, ."
30 |
31 | /* This is the version number of the libcurl package from which this header
32 | file origins: */
33 | #define LIBCURL_VERSION "7.41.0"
34 |
35 | /* The numeric version number is also available "in parts" by using these
36 | defines: */
37 | #define LIBCURL_VERSION_MAJOR 7
38 | #define LIBCURL_VERSION_MINOR 41
39 | #define LIBCURL_VERSION_PATCH 0
40 |
41 | /* This is the numeric version of the libcurl version number, meant for easier
42 | parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
43 | always follow this syntax:
44 |
45 | 0xXXYYZZ
46 |
47 | Where XX, YY and ZZ are the main version, release and patch numbers in
48 | hexadecimal (using 8 bits each). All three numbers are always represented
49 | using two digits. 1.2 would appear as "0x010200" while version 9.11.7
50 | appears as "0x090b07".
51 |
52 | This 6-digit (24 bits) hexadecimal number does not show pre-release number,
53 | and it is always a greater number in a more recent release. It makes
54 | comparisons with greater than and less than work.
55 | */
56 | #define LIBCURL_VERSION_NUM 0x072900
57 |
58 | /*
59 | * This is the date and time when the full source package was created. The
60 | * timestamp is not stored in git, as the timestamp is properly set in the
61 | * tarballs by the maketgz script.
62 | *
63 | * The format of the date should follow this template:
64 | *
65 | * "Mon Feb 12 11:35:33 UTC 2007"
66 | */
67 | #define LIBCURL_TIMESTAMP "Wed Feb 25 07:36:13 UTC 2015"
68 |
69 | #endif /* __CURL_CURLVER_H */
70 |
--------------------------------------------------------------------------------
/libcurl/include/curl/easy.h:
--------------------------------------------------------------------------------
1 | #ifndef __CURL_EASY_H
2 | #define __CURL_EASY_H
3 | /***************************************************************************
4 | * _ _ ____ _
5 | * Project ___| | | | _ \| |
6 | * / __| | | | |_) | |
7 | * | (__| |_| | _ <| |___
8 | * \___|\___/|_| \_\_____|
9 | *
10 | * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al.
11 | *
12 | * This software is licensed as described in the file COPYING, which
13 | * you should have received as part of this distribution. The terms
14 | * are also available at http://curl.haxx.se/docs/copyright.html.
15 | *
16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell
17 | * copies of the Software, and permit persons to whom the Software is
18 | * furnished to do so, under the terms of the COPYING file.
19 | *
20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 | * KIND, either express or implied.
22 | *
23 | ***************************************************************************/
24 | #ifdef __cplusplus
25 | extern "C" {
26 | #endif
27 |
28 | CURL_EXTERN CURL *curl_easy_init(void);
29 | CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
30 | CURL_EXTERN CURLcode curl_easy_perform(CURL *curl);
31 | CURL_EXTERN void curl_easy_cleanup(CURL *curl);
32 |
33 | /*
34 | * NAME curl_easy_getinfo()
35 | *
36 | * DESCRIPTION
37 | *
38 | * Request internal information from the curl session with this function. The
39 | * third argument MUST be a pointer to a long, a pointer to a char * or a
40 | * pointer to a double (as the documentation describes elsewhere). The data
41 | * pointed to will be filled in accordingly and can be relied upon only if the
42 | * function returns CURLE_OK. This function is intended to get used *AFTER* a
43 | * performed transfer, all results from this function are undefined until the
44 | * transfer is completed.
45 | */
46 | CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
47 |
48 |
49 | /*
50 | * NAME curl_easy_duphandle()
51 | *
52 | * DESCRIPTION
53 | *
54 | * Creates a new curl session handle with the same options set for the handle
55 | * passed in. Duplicating a handle could only be a matter of cloning data and
56 | * options, internal state info and things like persistent connections cannot
57 | * be transferred. It is useful in multithreaded applications when you can run
58 | * curl_easy_duphandle() for each new thread to avoid a series of identical
59 | * curl_easy_setopt() invokes in every thread.
60 | */
61 | CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl);
62 |
63 | /*
64 | * NAME curl_easy_reset()
65 | *
66 | * DESCRIPTION
67 | *
68 | * Re-initializes a CURL handle to the default values. This puts back the
69 | * handle to the same state as it was in when it was just created.
70 | *
71 | * It does keep: live connections, the Session ID cache, the DNS cache and the
72 | * cookies.
73 | */
74 | CURL_EXTERN void curl_easy_reset(CURL *curl);
75 |
76 | /*
77 | * NAME curl_easy_recv()
78 | *
79 | * DESCRIPTION
80 | *
81 | * Receives data from the connected socket. Use after successful
82 | * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
83 | */
84 | CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen,
85 | size_t *n);
86 |
87 | /*
88 | * NAME curl_easy_send()
89 | *
90 | * DESCRIPTION
91 | *
92 | * Sends data over the connected socket. Use after successful
93 | * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
94 | */
95 | CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer,
96 | size_t buflen, size_t *n);
97 |
98 | #ifdef __cplusplus
99 | }
100 | #endif
101 |
102 | #endif
103 |
--------------------------------------------------------------------------------
/libcurl/include/curl/mprintf.h:
--------------------------------------------------------------------------------
1 | #ifndef __CURL_MPRINTF_H
2 | #define __CURL_MPRINTF_H
3 | /***************************************************************************
4 | * _ _ ____ _
5 | * Project ___| | | | _ \| |
6 | * / __| | | | |_) | |
7 | * | (__| |_| | _ <| |___
8 | * \___|\___/|_| \_\_____|
9 | *
10 | * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al.
11 | *
12 | * This software is licensed as described in the file COPYING, which
13 | * you should have received as part of this distribution. The terms
14 | * are also available at http://curl.haxx.se/docs/copyright.html.
15 | *
16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell
17 | * copies of the Software, and permit persons to whom the Software is
18 | * furnished to do so, under the terms of the COPYING file.
19 | *
20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 | * KIND, either express or implied.
22 | *
23 | ***************************************************************************/
24 |
25 | #include
26 | #include /* needed for FILE */
27 |
28 | #include "curl.h"
29 |
30 | #ifdef __cplusplus
31 | extern "C" {
32 | #endif
33 |
34 | CURL_EXTERN int curl_mprintf(const char *format, ...);
35 | CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...);
36 | CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...);
37 | CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength,
38 | const char *format, ...);
39 | CURL_EXTERN int curl_mvprintf(const char *format, va_list args);
40 | CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args);
41 | CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args);
42 | CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength,
43 | const char *format, va_list args);
44 | CURL_EXTERN char *curl_maprintf(const char *format, ...);
45 | CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args);
46 |
47 | #ifdef _MPRINTF_REPLACE
48 | # undef printf
49 | # undef fprintf
50 | # undef sprintf
51 | # undef vsprintf
52 | # undef snprintf
53 | # undef vprintf
54 | # undef vfprintf
55 | # undef vsnprintf
56 | # undef aprintf
57 | # undef vaprintf
58 | # define printf curl_mprintf
59 | # define fprintf curl_mfprintf
60 | #ifdef CURLDEBUG
61 | /* When built with CURLDEBUG we define away the sprintf functions since we
62 | don't want internal code to be using them */
63 | # define sprintf sprintf_was_used
64 | # define vsprintf vsprintf_was_used
65 | #else
66 | # define sprintf curl_msprintf
67 | # define vsprintf curl_mvsprintf
68 | #endif
69 | # define snprintf curl_msnprintf
70 | # define vprintf curl_mvprintf
71 | # define vfprintf curl_mvfprintf
72 | # define vsnprintf curl_mvsnprintf
73 | # define aprintf curl_maprintf
74 | # define vaprintf curl_mvaprintf
75 | #endif
76 |
77 | #ifdef __cplusplus
78 | }
79 | #endif
80 |
81 | #endif /* __CURL_MPRINTF_H */
82 |
--------------------------------------------------------------------------------
/libcurl/include/curl/stdcheaders.h:
--------------------------------------------------------------------------------
1 | #ifndef __STDC_HEADERS_H
2 | #define __STDC_HEADERS_H
3 | /***************************************************************************
4 | * _ _ ____ _
5 | * Project ___| | | | _ \| |
6 | * / __| | | | |_) | |
7 | * | (__| |_| | _ <| |___
8 | * \___|\___/|_| \_\_____|
9 | *
10 | * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al.
11 | *
12 | * This software is licensed as described in the file COPYING, which
13 | * you should have received as part of this distribution. The terms
14 | * are also available at http://curl.haxx.se/docs/copyright.html.
15 | *
16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell
17 | * copies of the Software, and permit persons to whom the Software is
18 | * furnished to do so, under the terms of the COPYING file.
19 | *
20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 | * KIND, either express or implied.
22 | *
23 | ***************************************************************************/
24 |
25 | #include
26 |
27 | size_t fread (void *, size_t, size_t, FILE *);
28 | size_t fwrite (const void *, size_t, size_t, FILE *);
29 |
30 | int strcasecmp(const char *, const char *);
31 | int strncasecmp(const char *, const char *, size_t);
32 |
33 | #endif /* __STDC_HEADERS_H */
34 |
--------------------------------------------------------------------------------
/libcurl/lib/armeabi-v7a/libcurl.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Go-joy/crsync/0af4f53c2dd2d2fe180a756f7f6b98fe6d60bf1f/libcurl/lib/armeabi-v7a/libcurl.a
--------------------------------------------------------------------------------
/libcurl/lib/m32/libcurl.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Go-joy/crsync/0af4f53c2dd2d2fe180a756f7f6b98fe6d60bf1f/libcurl/lib/m32/libcurl.a
--------------------------------------------------------------------------------
/libcurl/lib/m32/libcurl.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Go-joy/crsync/0af4f53c2dd2d2fe180a756f7f6b98fe6d60bf1f/libcurl/lib/m32/libcurl.dll
--------------------------------------------------------------------------------
/libcurl/lib/m32/libcurldll.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Go-joy/crsync/0af4f53c2dd2d2fe180a756f7f6b98fe6d60bf1f/libcurl/lib/m32/libcurldll.a
--------------------------------------------------------------------------------
/libcurl/lib/x86/libcurl.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Go-joy/crsync/0af4f53c2dd2d2fe180a756f7f6b98fe6d60bf1f/libcurl/lib/x86/libcurl.a
--------------------------------------------------------------------------------
/src/crsync-build.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 | rem ndk-build parameters:
3 | rem NDK_PROJECT_PATH = where is project path
4 | rem NDK_APPLICATION_MK = where is Application.mk
5 | rem APP_BUILD_SCRIPT = where is Android.mk
6 | rem APP_PLATFORM = android-3 default
7 | rem APP_ABI = all or armeabi,armeabi-v7a,x86,mips
8 | rem NDK_DEBUG = 0 or 1
9 | rem clean
10 | rem -B force rebuild
11 | rem V=1 show NDK log
12 |
13 | call %NDKROOT%/ndk-build -B NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./crsync.mk APP_ABI=armeabi-v7a,x86 APP_PLATFORM=android-15
14 | pause
15 |
--------------------------------------------------------------------------------
/src/crsync-jni.c:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #ifdef ANDROID
25 | #include
26 | #include
27 |
28 | #include "global.h"
29 | #include "log.h"
30 | #include "helper.h"
31 | #include "utstring.h"
32 | #include "utlist.h"
33 | #include "util.h"
34 | #include "http.h"
35 |
36 | #define ARRAY_COUNT(x) ((int) (sizeof(x) / sizeof((x)[0])))
37 |
38 | typedef struct JNIJavaMethods {
39 | jmethodID *JavaMethod;
40 | const char *FunctionName;
41 | const char *FunctionParams;
42 | } JNIJavaMethods;
43 |
44 | static JavaVM *gJavaVM = NULL;
45 | static jclass gJavaClass = NULL;
46 | static jmethodID gMethod_onProgress = NULL;
47 | static jmethodID gMethod_onDiff = NULL;
48 |
49 | static time_t gTime = 0;
50 |
51 | static bulkHelper_t *gBulkHelper = NULL;
52 |
53 | int crs_callback_patch(const char *basename, const unsigned int bytes, const int isComplete, const int immediate) {
54 | time_t nowTime;
55 | time(&nowTime);
56 | double diff = difftime(nowTime, gTime);
57 | if( diff < 1 && immediate == 0 ) {
58 | return 0;
59 | }
60 | gTime = nowTime;
61 |
62 | JNIEnv *env = NULL;
63 | int isCancel = 0;
64 | if ((*gJavaVM)->GetEnv(gJavaVM, (void**)&env, JNI_VERSION_1_6) == JNI_OK) {
65 | jstring jname = (*env)->NewStringUTF( env, basename );
66 | isCancel = (*env)->CallStaticIntMethod(env, gJavaClass, gMethod_onProgress, jname, (jlong)bytes, (jint)isComplete);
67 | (*env)->DeleteLocalRef(env, jname);
68 | }
69 | return isCancel;
70 | }
71 |
72 | void crs_callback_diff(const char *basename, const unsigned int bytes, const int isComplete) {
73 | JNIEnv *env = NULL;
74 | if ((*gJavaVM)->GetEnv(gJavaVM, (void**)&env, JNI_VERSION_1_6) == JNI_OK) {
75 | jstring jname = (*env)->NewStringUTF( env, basename );
76 | (*env)->CallStaticVoidMethod(env, gJavaClass, gMethod_onDiff, jname, (jlong)bytes, (jint)isComplete);
77 | (*env)->DeleteLocalRef(env, jname);
78 | }
79 | }
80 |
81 | jint JNI_crsync_init(JNIEnv *env, jclass clazz, jstring j_fileDir, jstring j_baseUrl) {
82 | const char *fileDir = (*env)->GetStringUTFChars(env, j_fileDir, NULL);
83 | const char *baseUrl = (*env)->GetStringUTFChars(env, j_baseUrl, NULL);
84 |
85 | log_open();
86 | CRScode code = CRS_OK;
87 | do {
88 | code = HTTP_global_init();
89 | if(code != CRS_OK) break;
90 | free(gBulkHelper);
91 | gBulkHelper = bulkHelper_malloc();
92 | gBulkHelper->fileDir = strdup(fileDir);
93 | gBulkHelper->baseUrl = strdup(baseUrl);
94 | } while(0);
95 |
96 | (*env)->ReleaseStringUTFChars(env, j_fileDir, fileDir);
97 | (*env)->ReleaseStringUTFChars(env, j_baseUrl, baseUrl);
98 | return (jint)code;
99 | }
100 |
101 | jint JNI_crsync_perform_magnet(JNIEnv *env, jclass clazz) {
102 | jint r = 0;//(jint)bulkHelper_perform_magnet(gBulkHelper);
103 | return r;
104 | }
105 |
106 | jstring JNI_crsync_get_magnet(JNIEnv *env, jclass clazz) {
107 | UT_string *result = NULL;
108 | utstring_new(result);
109 |
110 | magnet_t *m = gBulkHelper->currentMagnet;
111 | if(m) {
112 | sum_t *elt=NULL;
113 | LL_FOREACH(m->file, elt) {
114 | utstring_printf(result, "%s;", elt->name);
115 | char * hashStr = Util_hex_string(elt->digest, CRS_STRONG_DIGEST_SIZE);
116 | utstring_printf(result, "%s;", hashStr);
117 | free(hashStr);
118 | utstring_printf(result, "%u;", elt->size);
119 | }
120 | }
121 | jstring jinfo = (*env)->NewStringUTF( env, utstring_body(result) );
122 | utstring_free(result);
123 | return jinfo;
124 | }
125 |
126 | void JNI_crsync_set_magnet(JNIEnv *env, jclass clazz, jstring jMagnetString) {
127 | const char *magnetString = (*env)->GetStringUTFChars(env, jMagnetString, NULL);
128 | bulkHelper_set_magnet(gBulkHelper, magnetString);
129 | (*env)->ReleaseStringUTFChars(env, jMagnetString, magnetString);
130 | }
131 |
132 | jint JNI_crsync_perform_diff(JNIEnv *env, jclass clazz) {
133 | jint r = (jint)bulkHelper_perform_diff(gBulkHelper);
134 | return r;
135 | }
136 |
137 | jint JNI_crsync_perform_patch(JNIEnv *env, jclass clazz) {
138 | jint r = (jint)bulkHelper_perform_patch(gBulkHelper);
139 | return r;
140 | }
141 |
142 | void JNI_crsync_cleanup(JNIEnv *env, jclass clazz) {
143 | bulkHelper_free(gBulkHelper);
144 | gBulkHelper = NULL;
145 | HTTP_global_cleanup();
146 | log_close();
147 | }
148 |
149 | jint JNI_OnLoad(JavaVM* vm, void* reserved) {
150 | log_open();
151 | LOGI("crsync JNI_OnLoad\n");
152 | JNIEnv *env;
153 | if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) {
154 | return JNI_ERR;
155 | }
156 |
157 | // hook up native functions to string names and params
158 | JNINativeMethod NativeMethods[] = {
159 | { "JNI_crsync_init", "(Ljava/lang/String;Ljava/lang/String;)I", (void*)JNI_crsync_init },
160 | { "JNI_crsync_get_magnet", "()Ljava/lang/String;", (void*)JNI_crsync_get_magnet },
161 | { "JNI_crsync_set_magnet", "(Ljava/lang/String;)V", (void*)JNI_crsync_set_magnet },
162 | { "JNI_crsync_perform_magnet", "()I", (void*)JNI_crsync_perform_magnet },
163 | { "JNI_crsync_perform_diff", "()I", (void*)JNI_crsync_perform_diff },
164 | { "JNI_crsync_perform_patch", "()I", (void*)JNI_crsync_perform_patch },
165 | { "JNI_crsync_cleanup", "()V", (void*)JNI_crsync_cleanup },
166 | };
167 |
168 | // get the java class from JNI
169 | jclass crsyncClass = (*env)->FindClass(env, "com/shaddock/crsync/Crsync");
170 | gJavaClass = (*env)->NewGlobalRef(env, crsyncClass);
171 | (*env)->RegisterNatives(env, gJavaClass, NativeMethods, ARRAY_COUNT(NativeMethods));
172 |
173 | // hook up java functions to string names and param
174 | JNIJavaMethods JavaMethods[] = {
175 | { &gMethod_onProgress, "java_onProgress", "(Ljava/lang/String;JI)I" }, //public static int java_onProgress(String, long, int);
176 | { &gMethod_onDiff, "java_onDiff", "(Ljava/lang/String;JI)V" },//public static void java_onDiff(String, long, int);
177 | };
178 |
179 | int result = 1;
180 | for( int MethodIter = 0; MethodIter < ARRAY_COUNT(JavaMethods); MethodIter++ ) {
181 | *JavaMethods[MethodIter].JavaMethod = (*env)->GetStaticMethodID(env, gJavaClass, JavaMethods[MethodIter].FunctionName, JavaMethods[MethodIter].FunctionParams);
182 | if( 0 == *JavaMethods[MethodIter].JavaMethod ) {
183 | LOGE("JavaMethod not found! %s(%s)", JavaMethods[MethodIter].FunctionName, JavaMethods[MethodIter].FunctionParams);
184 | result = 0;
185 | break;
186 | }
187 | }
188 | gJavaVM = vm;
189 | return (result == 1) ? JNI_VERSION_1_6 : JNI_ERR;
190 | }
191 |
192 | /* At Android Platform, JNI_OnUnload() will never been called */
193 | void JNI_OnUnload(JavaVM* vm, void* InReserved) {
194 | log_close();
195 | gJavaVM = NULL;
196 | JNIEnv *env =NULL;
197 | if( (*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) == JNI_OK ) {
198 | (*env)->DeleteGlobalRef(env, gJavaClass);
199 | gJavaClass = NULL;
200 | }
201 | }
202 |
203 | #endif
204 |
--------------------------------------------------------------------------------
/src/crsync.c:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #include
25 | #if ( defined __CYGWIN__ || defined __MINGW32__ || defined _WIN32 )
26 | # include "win/mman.h" /* mmap */
27 | #else
28 | # include /* mmap */
29 | #endif
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | #include "crsync.h"
37 | #include "http.h"
38 | #include "log.h"
39 | #include "util.h"
40 |
41 | CRScode crs_perform_digest(const char *srcFilename, const char *dstFilename, const uint32_t blockSize) {
42 | LOGI("begin\n");
43 | if(srcFilename == NULL || dstFilename == NULL) {
44 | LOGE("end %d\n", CRS_PARAM_ERROR);
45 | return CRS_PARAM_ERROR;
46 | }
47 |
48 | fileDigest_t *fd = fileDigest_malloc();
49 | CRScode code = CRS_OK;
50 | do {
51 | code = Digest_Perform(srcFilename, blockSize, fd);
52 | if(code != CRS_OK) break;
53 | code = Digest_Save(dstFilename, fd);
54 | } while(0);
55 |
56 | fileDigest_free(fd);
57 |
58 | LOGI("end %d\n", code);
59 | return code;
60 | }
61 |
62 | CRScode crs_perform_diff(const char *srcFilename, const char *dstFilename, const char *digestUrl,
63 | fileDigest_t *fd, diffResult_t *dr) {
64 | LOGI("begin\n");
65 |
66 | if(!srcFilename || !dstFilename || !digestUrl || !fd || !dr) {
67 | LOGE("end %d\n", CRS_PARAM_ERROR);
68 | return CRS_PARAM_ERROR;
69 | }
70 |
71 | CRScode code = CRS_OK;
72 | char *digestFilename = Util_strcat(dstFilename, DIGEST_EXT);
73 | LOGI("digestFilename = %s\n", digestFilename);
74 |
75 | do {
76 | if(0 != Digest_checkfile(digestFilename)) {
77 | code = HTTP_File(digestUrl, digestFilename, 1, NULL);
78 | if(code != CRS_OK) break;
79 | }
80 |
81 | code = Digest_Load(digestFilename, fd);
82 | if(code != CRS_OK) break;
83 | code = Diff_perform(srcFilename, dstFilename, fd, dr);
84 | } while(0);
85 |
86 | free(digestFilename);
87 | fileDigest_dump(fd);
88 | diffResult_dump(dr);
89 | LOGI("end %d\n", code);
90 | return code;
91 | }
92 |
93 | CRScode crs_perform_patch(const char *srcFilename, const char *dstFilename, const char *url,
94 | const fileDigest_t *fd, const diffResult_t *dr) {
95 | LOGI("begin\n");
96 | CRScode code = CRS_OK;
97 | code = Patch_perform(srcFilename, dstFilename, url, fd, dr);
98 | LOGI("end %d\n", code);
99 | return code;
100 | }
101 |
102 | CRScode crs_perform_update(const char *srcFilename, const char *dstFilename, const char *digestUrl, const char *url) {
103 | LOGI("begin\n");
104 |
105 | if(!srcFilename || !dstFilename || !url) {
106 | LOGE("end %d\n", CRS_PARAM_ERROR);
107 | return CRS_PARAM_ERROR;
108 | }
109 |
110 | CRScode code = CRS_OK;
111 |
112 | fileDigest_t *fd = fileDigest_malloc();
113 | diffResult_t *dr = diffResult_malloc();
114 | do {
115 | code = crs_perform_diff(srcFilename, dstFilename, digestUrl, fd, dr);
116 | if(code != CRS_OK) break;
117 | code = crs_perform_patch(srcFilename, dstFilename, url, fd, dr);
118 | } while(0);
119 |
120 | fileDigest_free(fd);
121 | diffResult_free(dr);
122 |
123 | LOGI("end %d\n", code);
124 | return code;
125 | }
126 |
--------------------------------------------------------------------------------
/src/crsync.h:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #ifndef CRSYNC_H
25 | #define CRSYNC_H
26 |
27 | #if defined __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | #include "global.h"
32 | #include "crsyncver.h" /* crsync version defines */
33 | #include "digest.h"
34 | #include "diff.h"
35 | #include "patch.h"
36 | #include "uthash.h"
37 | #include "utlist.h"
38 | #include "utstring.h"
39 | #include "tpl.h"
40 | #include "curl/curl.h"
41 |
42 | CRScode crs_perform_digest (const char *srcFilename, const char *dstFilename, const uint32_t blocksize);
43 |
44 | CRScode crs_perform_diff (const char *srcFilename, const char *dstFilename, const char *digestUrl,
45 | fileDigest_t *fd, diffResult_t *dr);
46 |
47 | CRScode crs_perform_patch (const char *srcFilename, const char *dstFilename, const char *url,
48 | const fileDigest_t *fd, const diffResult_t *dr);
49 |
50 | CRScode crs_perform_update (const char *srcFilename, const char *dstFilename, const char *digestUrl, const char *url);
51 |
52 | #if defined __cplusplus
53 | }
54 | #endif
55 |
56 | #endif // CRSYNC_H
57 |
--------------------------------------------------------------------------------
/src/crsync.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH:= $(call my-dir)
2 |
3 | include $(CLEAR_VARS)
4 | LOCAL_MODULE := curl
5 | LOCAL_SRC_FILES := $(LOCAL_PATH)/../libcurl/lib/$(TARGET_ARCH_ABI)/libcurl.a
6 | LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../libcurl/include
7 | include $(PREBUILT_STATIC_LIBRARY)
8 |
9 | include $(CLEAR_VARS)
10 | LOCAL_MODULE := crsync
11 | LOCAL_SRC_FILES := digest.c diff.c patch.c http.c helper.c magnet.c util.c log.c crsync.c crsync-jni.c ../extra/md5.c ../extra/tpl.c
12 | LOCAL_C_INCLUDES += ../extra
13 | LOCAL_STATIC_LIBRARIES := curl
14 | LOCAL_CFLAGS += -DHASH_BLOOM=21 -DCURL_STATICLIB -std=c99 -fopenmp
15 | LOCAL_LDLIBS += -lc -lz -llog
16 | LOCAL_LDFLAGS += -fopenmp
17 |
18 | include $(BUILD_SHARED_LIBRARY)
19 |
--------------------------------------------------------------------------------
/src/crsync.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = app
2 | CONFIG += console
3 | CONFIG -= app_bundle
4 | CONFIG -= qt
5 |
6 | TARGET = crsync
7 | DESTDIR = m32
8 |
9 | SOURCES += \
10 | digest.c \
11 | diff.c \
12 | patch.c \
13 | http.c \
14 | magnet.c \
15 | helper.c \
16 | util.c \
17 | log.c \
18 | crsync.c \
19 | crsync-console.c \
20 | ../extra/md5.c \
21 | ../extra/tpl.c \
22 | ../extra/win/mmap.c \
23 | ../extra/dictionary.c \
24 | ../extra/iniparser.c
25 |
26 | HEADERS += \
27 | global.h \
28 | digest.h \
29 | diff.h \
30 | patch.h \
31 | http.h \
32 | magnet.h \
33 | helper.h \
34 | util.h \
35 | log.h \
36 | crsync.h \
37 | crsyncver.h \
38 | ../extra/md5.h \
39 | ../extra/tpl.h \
40 | ../extra/win/mman.h \
41 | ../extra/uthash.h \
42 | ../extra/utstring.h \
43 | ../extra/utlist.h \
44 | ../extra/dictionary.h \
45 | ../extra/iniparser.h
46 |
47 | DEFINES += HASH_BLOOM=21 CURL_STATICLIB
48 | INCLUDEPATH += $${_PRO_FILE_PWD_}/../libcurl/include
49 | LIBS += -L$${_PRO_FILE_PWD_}/../libcurl/lib/m32 -lcurl -lws2_32
50 |
51 | INCLUDEPATH += $${_PRO_FILE_PWD_}/../extra/
52 |
53 | QMAKE_CFLAGS += -O3 -std=c99 -fopenmp
54 | QMAKE_LFLAGS += -static -static-libgcc -fopenmp
55 |
56 | win32:RC_FILE = crsync.rc
57 |
58 | include(deployment.pri)
59 | qtcAddDeployment()
60 |
--------------------------------------------------------------------------------
/src/crsync.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Go-joy/crsync/0af4f53c2dd2d2fe180a756f7f6b98fe6d60bf1f/src/crsync.rc
--------------------------------------------------------------------------------
/src/crsyncver.h:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #ifndef __CRSYNCVER_H
25 | #define __CRSYNCVER_H
26 |
27 | /* This is the global package copyright */
28 | #define CRSYNC_COPYRIGHT "2015 chenqi, <9468305@qq.com>."
29 |
30 | /* This is the version number of the crsync package from which this header file origins: */
31 | #define CRSYNC_VERSION "0.1.0"
32 |
33 | /* The numeric version number is also available "in parts" by using these defines: */
34 | #define CRSYNC_VERSION_MAJOR 0
35 | #define CRSYNC_VERSION_MINOR 1
36 | #define CRSYNC_VERSION_PATCH 0
37 |
38 | /* This is the numeric version of the crsync version number, meant for easier
39 | parsing and comparions by programs. The CRSYNC_VERSION_NUM define will
40 | always follow this syntax:
41 |
42 | 0xXXYYZZ
43 |
44 | Where XX, YY and ZZ are the main version, release and patch numbers in
45 | hexadecimal (using 8 bits each). All three numbers are always represented
46 | using two digits. 1.2.3 would appear as "0x010203".
47 |
48 | This 6-digit (24 bits) hexadecimal number does not show pre-release number,
49 | and it is always a greater number in a more recent release. It makes
50 | comparisons with greater than and less than work.
51 | */
52 | #define CRSYNC_VERSION_NUM 0x000100
53 |
54 | #endif //__CRSYNCVER_H
55 |
--------------------------------------------------------------------------------
/src/deployment.pri:
--------------------------------------------------------------------------------
1 | # This file was generated by an application wizard of Qt Creator.
2 | # The code below handles deployment to Android and Maemo, aswell as copying
3 | # of the application data to shadow build directories on desktop.
4 | # It is recommended not to modify this file, since newer versions of Qt Creator
5 | # may offer an updated version of it.
6 |
7 | defineTest(qtcAddDeployment) {
8 | for(deploymentfolder, DEPLOYMENTFOLDERS) {
9 | item = item$${deploymentfolder}
10 | greaterThan(QT_MAJOR_VERSION, 4) {
11 | itemsources = $${item}.files
12 | } else {
13 | itemsources = $${item}.sources
14 | }
15 | $$itemsources = $$eval($${deploymentfolder}.source)
16 | itempath = $${item}.path
17 | $$itempath= $$eval($${deploymentfolder}.target)
18 | export($$itemsources)
19 | export($$itempath)
20 | DEPLOYMENT += $$item
21 | }
22 |
23 | MAINPROFILEPWD = $$PWD
24 |
25 | android-no-sdk {
26 | for(deploymentfolder, DEPLOYMENTFOLDERS) {
27 | item = item$${deploymentfolder}
28 | itemfiles = $${item}.files
29 | $$itemfiles = $$eval($${deploymentfolder}.source)
30 | itempath = $${item}.path
31 | $$itempath = /data/user/qt/$$eval($${deploymentfolder}.target)
32 | export($$itemfiles)
33 | export($$itempath)
34 | INSTALLS += $$item
35 | }
36 |
37 | target.path = /data/user/qt
38 |
39 | export(target.path)
40 | INSTALLS += target
41 | } else:android {
42 | for(deploymentfolder, DEPLOYMENTFOLDERS) {
43 | item = item$${deploymentfolder}
44 | itemfiles = $${item}.files
45 | $$itemfiles = $$eval($${deploymentfolder}.source)
46 | itempath = $${item}.path
47 | $$itempath = /assets/$$eval($${deploymentfolder}.target)
48 | export($$itemfiles)
49 | export($$itempath)
50 | INSTALLS += $$item
51 | }
52 |
53 | x86 {
54 | target.path = /libs/x86
55 | } else: armeabi-v7a {
56 | target.path = /libs/armeabi-v7a
57 | } else {
58 | target.path = /libs/armeabi
59 | }
60 |
61 | export(target.path)
62 | INSTALLS += target
63 | } else:win32 {
64 | copyCommand =
65 | for(deploymentfolder, DEPLOYMENTFOLDERS) {
66 | source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source)
67 | source = $$replace(source, /, \\)
68 | sourcePathSegments = $$split(source, \\)
69 | target = $$OUT_PWD/$$eval($${deploymentfolder}.target)/$$last(sourcePathSegments)
70 | target = $$replace(target, /, \\)
71 | target ~= s,\\\\\\.?\\\\,\\,
72 | !isEqual(source,$$target) {
73 | !isEmpty(copyCommand):copyCommand += &&
74 | isEqual(QMAKE_DIR_SEP, \\) {
75 | copyCommand += $(COPY_DIR) \"$$source\" \"$$target\"
76 | } else {
77 | source = $$replace(source, \\\\, /)
78 | target = $$OUT_PWD/$$eval($${deploymentfolder}.target)
79 | target = $$replace(target, \\\\, /)
80 | copyCommand += test -d \"$$target\" || mkdir -p \"$$target\" && cp -r \"$$source\" \"$$target\"
81 | }
82 | }
83 | }
84 | !isEmpty(copyCommand) {
85 | copyCommand = @echo Copying application data... && $$copyCommand
86 | copydeploymentfolders.commands = $$copyCommand
87 | first.depends = $(first) copydeploymentfolders
88 | export(first.depends)
89 | export(copydeploymentfolders.commands)
90 | QMAKE_EXTRA_TARGETS += first copydeploymentfolders
91 | }
92 | } else:ios {
93 | copyCommand =
94 | for(deploymentfolder, DEPLOYMENTFOLDERS) {
95 | source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source)
96 | source = $$replace(source, \\\\, /)
97 | target = $CODESIGNING_FOLDER_PATH/$$eval($${deploymentfolder}.target)
98 | target = $$replace(target, \\\\, /)
99 | sourcePathSegments = $$split(source, /)
100 | targetFullPath = $$target/$$last(sourcePathSegments)
101 | targetFullPath ~= s,/\\.?/,/,
102 | !isEqual(source,$$targetFullPath) {
103 | !isEmpty(copyCommand):copyCommand += &&
104 | copyCommand += mkdir -p \"$$target\"
105 | copyCommand += && cp -r \"$$source\" \"$$target\"
106 | }
107 | }
108 | !isEmpty(copyCommand) {
109 | copyCommand = echo Copying application data... && $$copyCommand
110 | !isEmpty(QMAKE_POST_LINK): QMAKE_POST_LINK += ";"
111 | QMAKE_POST_LINK += "$$copyCommand"
112 | export(QMAKE_POST_LINK)
113 | }
114 | } else:unix {
115 | maemo5 {
116 | desktopfile.files = $${TARGET}.desktop
117 | desktopfile.path = /usr/share/applications/hildon
118 | icon.files = $${TARGET}64.png
119 | icon.path = /usr/share/icons/hicolor/64x64/apps
120 | } else:!isEmpty(MEEGO_VERSION_MAJOR) {
121 | desktopfile.files = $${TARGET}_harmattan.desktop
122 | desktopfile.path = /usr/share/applications
123 | icon.files = $${TARGET}80.png
124 | icon.path = /usr/share/icons/hicolor/80x80/apps
125 | } else { # Assumed to be a Desktop Unix
126 | copyCommand =
127 | for(deploymentfolder, DEPLOYMENTFOLDERS) {
128 | source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source)
129 | source = $$replace(source, \\\\, /)
130 | macx {
131 | target = $$OUT_PWD/$${TARGET}.app/Contents/Resources/$$eval($${deploymentfolder}.target)
132 | } else {
133 | target = $$OUT_PWD/$$eval($${deploymentfolder}.target)
134 | }
135 | target = $$replace(target, \\\\, /)
136 | sourcePathSegments = $$split(source, /)
137 | targetFullPath = $$target/$$last(sourcePathSegments)
138 | targetFullPath ~= s,/\\.?/,/,
139 | !isEqual(source,$$targetFullPath) {
140 | !isEmpty(copyCommand):copyCommand += &&
141 | copyCommand += $(MKDIR) \"$$target\"
142 | copyCommand += && $(COPY_DIR) \"$$source\" \"$$target\"
143 | }
144 | }
145 | !isEmpty(copyCommand) {
146 | copyCommand = @echo Copying application data... && $$copyCommand
147 | copydeploymentfolders.commands = $$copyCommand
148 | first.depends = $(first) copydeploymentfolders
149 | export(first.depends)
150 | export(copydeploymentfolders.commands)
151 | QMAKE_EXTRA_TARGETS += first copydeploymentfolders
152 | }
153 | }
154 | !isEmpty(target.path) {
155 | installPrefix = $${target.path}
156 | } else {
157 | installPrefix = /opt/$${TARGET}
158 | }
159 | for(deploymentfolder, DEPLOYMENTFOLDERS) {
160 | item = item$${deploymentfolder}
161 | itemfiles = $${item}.files
162 | $$itemfiles = $$eval($${deploymentfolder}.source)
163 | itempath = $${item}.path
164 | $$itempath = $${installPrefix}/$$eval($${deploymentfolder}.target)
165 | export($$itemfiles)
166 | export($$itempath)
167 | INSTALLS += $$item
168 | }
169 |
170 | !isEmpty(desktopfile.path) {
171 | export(icon.files)
172 | export(icon.path)
173 | export(desktopfile.files)
174 | export(desktopfile.path)
175 | INSTALLS += icon desktopfile
176 | }
177 |
178 | isEmpty(target.path) {
179 | target.path = $${installPrefix}/bin
180 | export(target.path)
181 | }
182 | INSTALLS += target
183 | }
184 |
185 | export (ICON)
186 | export (INSTALLS)
187 | export (DEPLOYMENT)
188 | export (LIBS)
189 | export (QMAKE_EXTRA_TARGETS)
190 | }
191 |
192 |
--------------------------------------------------------------------------------
/src/diff.c:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | #include "diff.h"
30 | #include "uthash.h"
31 | #include "log.h"
32 |
33 | typedef struct diffHash_t {
34 | uint32_t weak; //first key
35 | int32_t seq; //second key
36 | uint8_t *strong; //reference pointer
37 | struct diffHash_t *sub; //sub HashTable
38 | UT_hash_handle hh;
39 | } diffHash_t;
40 |
41 | static diffHash_t* diffHash_malloc() {
42 | diffHash_t *dh = calloc(1, sizeof(diffHash_t));
43 | return dh;
44 | }
45 |
46 | static void diffHash_free(diffHash_t **dh) {
47 | diffHash_t *sumItem=NULL, *sumTemp=NULL, *sumIter=NULL, *sumTemp2=NULL;
48 | HASH_ITER(hh, *dh, sumItem, sumTemp) {
49 | HASH_ITER(hh, sumItem->sub, sumIter, sumTemp2 ) {
50 | HASH_DEL(sumItem->sub, sumIter);
51 | free(sumIter);
52 | }
53 | HASH_DEL(*dh, sumItem);
54 | free(sumItem);
55 | }
56 | }
57 |
58 | diffResult_t* diffResult_malloc() {
59 | diffResult_t *dr = calloc(1, sizeof(diffResult_t));
60 | return dr;
61 | }
62 |
63 | void diffResult_free(diffResult_t *dr) {
64 | if(dr) {
65 | free(dr->offsets);
66 | free(dr);
67 | }
68 | }
69 |
70 | void diffResult_dump(const diffResult_t *dr) {
71 | if(dr){
72 | LOGI("totalNum = %d\n", dr->totalNum);
73 | LOGI("matchNum = %d\n", dr->matchNum);
74 | LOGI("cacheNum = %d\n", dr->cacheNum);
75 | LOGI("missNum = %d\n", dr->totalNum - dr->matchNum - dr->cacheNum);
76 | } else {
77 | LOGI("none\n");
78 | }
79 | }
80 |
81 | static diffHash_t* Diff_hash(const fileDigest_t *fd) {
82 | diffHash_t *dh = NULL;
83 | diffHash_t *item = NULL, *temp = NULL;
84 | uint32_t blockNum = fd->fileSize / fd->blockSize;
85 |
86 | for(size_t i=0; iweak = fd->blockDigest[i].weak;
90 | item->seq = i;
91 | item->strong = fd->blockDigest[i].strong;
92 |
93 | HASH_FIND_INT(dh, &item->weak, temp);
94 | if (!temp) {
95 | HASH_ADD_INT( dh, weak, item );
96 | } else {
97 | HASH_ADD_INT( temp->sub, seq, item );
98 | }
99 | }
100 | return dh;
101 | }
102 |
103 |
104 | #define DIFF_PARALLELISM_DEGREE 4
105 |
106 | static void Diff_match(const char *filename, const fileDigest_t *fd, const diffHash_t **dh, diffResult_t *dr) {
107 | dr->totalNum = fd->fileSize / fd->blockSize;
108 | dr->matchNum = 0;
109 | dr->cacheNum = 0;
110 | dr->offsets = malloc(dr->totalNum * sizeof(int32_t));
111 | memset(dr->offsets, -1, dr->totalNum * sizeof(int32_t));
112 |
113 | struct stat st;
114 | if(stat(filename, &st)!=0 || (size_t)st.st_size <= fd->blockSize*DIFF_PARALLELISM_DEGREE) {
115 | // file not exist || small file
116 | return;
117 | }
118 |
119 | const size_t parallel_size = (st.st_size + DIFF_PARALLELISM_DEGREE - 1) / DIFF_PARALLELISM_DEGREE;
120 |
121 | #pragma omp parallel shared(fd, dh, dr), num_threads(DIFF_PARALLELISM_DEGREE)
122 | {
123 | size_t id__ = omp_get_thread_num();
124 | FILE *file = fopen(filename, "rb");
125 | if(file)
126 | {
127 | size_t read_begin = 0;
128 | size_t read_end = 0;
129 | if(id__ == 0) {
130 | read_begin = 0;
131 | read_end = parallel_size;
132 | } else if(id__ == DIFF_PARALLELISM_DEGREE-1) {
133 | read_begin = id__ * parallel_size - fd->blockSize + 1;
134 | read_end = st.st_size;
135 | } else {
136 | read_begin = id__ * parallel_size - fd->blockSize + 1;
137 | read_end = (id__+1) * parallel_size;
138 | }
139 | size_t read_len = read_end - read_begin;
140 | size_t offset = read_begin;
141 |
142 | unsigned char *buf1 = malloc(fd->blockSize);
143 | unsigned char *buf2 = malloc(fd->blockSize);
144 |
145 | size_t r;
146 |
147 | r = fseek(file, read_begin, SEEK_SET);
148 | if(r != 0) {
149 | LOGE("error fseek\n");
150 | }
151 | r = fread(buf1, 1, fd->blockSize, file);
152 | read_len -= fd->blockSize;
153 | if(r != fd->blockSize) {
154 | LOGE("error fread\n");
155 | }
156 | uint32_t weak;
157 | uint8_t strong[CRS_STRONG_DIGEST_SIZE];
158 | diffHash_t *sumItem = NULL, *sumIter = NULL, *sumTemp = NULL;
159 |
160 | //Digest_match_first
161 | Digest_CalcWeak_Data(buf1, fd->blockSize, &weak);
162 | HASH_FIND_INT( *dh, &weak, sumItem );
163 | if(sumItem) {
164 | Digest_CalcStrong_Data(buf1, fd->blockSize, strong);
165 | if (0 == memcmp(strong, sumItem->strong, CRS_STRONG_DIGEST_SIZE)) {
166 | dr->offsets[sumItem->seq] = offset;
167 | }
168 | HASH_ITER(hh, sumItem->sub, sumIter, sumTemp) {
169 | if (0 == memcmp(strong, sumIter->strong, CRS_STRONG_DIGEST_SIZE)) {
170 | dr->offsets[sumIter->seq] = offset;
171 | }
172 | }
173 | }
174 |
175 | //Digest_match_loop
176 | while(read_len >= fd->blockSize) {
177 | r = fread(buf2, 1, fd->blockSize, file);
178 | if(r != fd->blockSize) {
179 | LOGE("error fread\n");
180 | }
181 | read_len -= fd->blockSize;
182 |
183 | for(size_t i=0; iblockSize;) {
184 | Digest_CalcWeak_Roll(buf1[i], buf2[i], fd->blockSize, &weak);
185 | ++i;
186 | ++offset;
187 | HASH_FIND_INT( *dh, &weak, sumItem );
188 | if(sumItem) {
189 | Digest_CalcStrong_Data2(buf1, buf2, fd->blockSize, i, strong);
190 | if (0 == memcmp(strong, sumItem->strong, CRS_STRONG_DIGEST_SIZE)) {
191 | dr->offsets[sumItem->seq] = offset;
192 | }
193 | HASH_ITER(hh, sumItem->sub, sumIter, sumTemp) {
194 | if (0 == memcmp(strong, sumIter->strong, CRS_STRONG_DIGEST_SIZE)) {
195 | dr->offsets[sumIter->seq] = offset;
196 | }
197 | }
198 | }
199 | }
200 | //switch buffer
201 | uint8_t *tmpbuf = buf1;
202 | buf1 = buf2;
203 | buf2 = tmpbuf;
204 | }
205 |
206 | //Digest_match_end
207 | if(read_len > 0) {
208 | r = fread(buf2, 1, read_len, file);
209 | if(r != read_len) {
210 | LOGE("error fread\n");
211 | }
212 | for(size_t i=0; iblockSize, &weak);
214 | ++i;
215 | ++offset;
216 | HASH_FIND_INT( *dh, &weak, sumItem );
217 | if(sumItem) {
218 | Digest_CalcStrong_Data2(buf1, buf2, fd->blockSize, i, strong);
219 | if (0 == memcmp(strong, sumItem->strong, CRS_STRONG_DIGEST_SIZE)) {
220 | dr->offsets[sumItem->seq] = offset;
221 | }
222 | HASH_ITER(hh, sumItem->sub, sumIter, sumTemp) {
223 | if (0 == memcmp(strong, sumIter->strong, CRS_STRONG_DIGEST_SIZE)) {
224 | dr->offsets[sumIter->seq] = offset;
225 | }
226 | }
227 | }
228 | }
229 | }
230 |
231 | free(buf1);
232 | free(buf2);
233 | fclose(file);
234 | }//end of if(file)
235 | }//end of omp parallel (DIFF_PARALLELISM_DEGREE)
236 |
237 | for(int32_t i=0; i< dr->totalNum; ++i) {
238 | if(dr->offsets[i] >= 0) {
239 | dr->matchNum++;
240 | }
241 | }
242 | }
243 |
244 | static CRScode Diff_cache(const char *dstFilename, const fileDigest_t *fd, diffResult_t *dr) {
245 | if(!dstFilename || !fd || !dr) {
246 | LOGE("end %d\n", CRS_PARAM_ERROR);
247 | return CRS_PARAM_ERROR;
248 | }
249 |
250 | if(0 != access(dstFilename, F_OK)) {
251 | LOGI("end file not exist\n");
252 | return CRS_OK;
253 | }
254 |
255 | struct stat st;
256 | if(stat(dstFilename, &st) != 0) {
257 | LOGE("dstFile stat fail %s\n", strerror(errno));
258 | LOGE("%s\n", dstFilename);
259 | //should return CRS_FILE_ERROR, but I do not want break workflow;
260 | return CRS_OK;
261 | }
262 |
263 | if((size_t)st.st_size != fd->fileSize) {
264 | if(0 != truncate(dstFilename, fd->fileSize)) {
265 | LOGE("dest file truncate %dBytes error %s\n", fd->fileSize, strerror(errno));
266 | //should return CRS_FILE_ERROR, but I do not want break workflow;
267 | return CRS_OK;
268 | }
269 | }
270 |
271 | FILE *f = fopen(dstFilename, "rb");
272 | if(!f){
273 | LOGE("dest file fopen rb error %s\n", strerror(errno));
274 | //should return CRS_FILE_ERROR, but I do not want break workflow;
275 | return CRS_OK;
276 | }
277 |
278 | uint8_t *buf = malloc(fd->blockSize);
279 | uint8_t hash[CRS_STRONG_DIGEST_SIZE];
280 |
281 | for(int i=0; itotalNum; ++i) {
282 | if(dr->offsets[i] == -1) {
283 | fseek(f, i*fd->blockSize, SEEK_SET);
284 | fread(buf, 1, fd->blockSize, f);
285 |
286 | Digest_CalcStrong_Data(buf, fd->blockSize, hash);
287 | if(0 == memcmp(hash, fd->blockDigest[i].strong, CRS_STRONG_DIGEST_SIZE)) {
288 | dr->offsets[i] = -2;
289 | dr->cacheNum++;
290 | }
291 | }
292 | }
293 | free(buf);
294 | fclose(f);
295 | return CRS_OK;
296 | }
297 |
298 | CRScode Diff_perform(const char *srcFilename, const char *dstFilename, const fileDigest_t *fd, diffResult_t *dr) {
299 | LOGI("begin\n");
300 | if(!srcFilename || !dstFilename || !fd || !dr) {
301 | LOGE("end %d\n", CRS_PARAM_ERROR);
302 | return CRS_PARAM_ERROR;
303 | }
304 |
305 | CRScode code = CRS_OK;
306 | diffHash_t *dh = Diff_hash(fd);
307 |
308 | Diff_match(srcFilename, fd, (const diffHash_t **)&dh, dr);
309 |
310 | Diff_cache(dstFilename, fd, dr);
311 |
312 | diffHash_free(&dh);
313 |
314 | LOGI("end %d\n", code);
315 | return code;
316 | }
317 |
--------------------------------------------------------------------------------
/src/diff.h:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #ifndef CRS_DIFF_H
25 | #define CRS_DIFF_H
26 |
27 | #if defined __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | #include
32 |
33 | #include "global.h"
34 | #include "digest.h"
35 |
36 | typedef struct diffResult_t {
37 | int32_t totalNum; //should be fileDigest_t.fileSize / fileDigest_t.blockSize;
38 | int32_t matchNum; //calc from fileDigest_t.offsets, compare to source file
39 | int32_t cacheNum; //dst file already got
40 | int32_t *offsets; //performed result, -1(default) miss, -2 cache, >=0 offset at source file;
41 | } diffResult_t;
42 |
43 | diffResult_t* diffResult_malloc();
44 | void diffResult_free(diffResult_t *dr);
45 |
46 | void diffResult_dump(const diffResult_t *dr);
47 |
48 | CRScode Diff_perform(const char *srcFilename, const char *dstFilename, const fileDigest_t *fd, diffResult_t *dr);
49 |
50 | #if defined __cplusplus
51 | }
52 | #endif
53 |
54 | #endif // CRS_DIFF_H
55 |
--------------------------------------------------------------------------------
/src/digest.c:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #include
25 | #include
26 |
27 | #include "digest.h"
28 | #include "md5.h"
29 | //#include "blake2.h"
30 | #include "md5.h"
31 | #include "log.h"
32 | #include "util.h"
33 | #include "tpl.h"
34 |
35 | const char *DIGEST_EXT = ".sum";
36 |
37 | void Digest_CalcWeak_Data(const uint8_t *data, const uint32_t size, uint32_t *out) {
38 | uint32_t i = 0, a = 0, b = 0;
39 | const uint8_t *p = data;
40 | for ( ; i < size - 4; i += 4) {
41 | b += 4 * (a + p[i]) + 3 * p[i + 1] + 2 * p[i + 2] + p[i + 3];
42 | a += p[i + 0] + p[i + 1] + p[i + 2] + p[i + 3];
43 | }
44 | for ( ; i < size; i++) {
45 | a += p[i];
46 | b += a;
47 | }
48 | *out = (a & 0xffff) | (b << 16);
49 | }
50 |
51 | void Digest_CalcWeak_Roll(const uint8_t out, const uint8_t in, const uint32_t blockSize, uint32_t *weak) {
52 | uint32_t a = *weak & 0xffff;
53 | uint32_t b = *weak >> 16;
54 |
55 | a += in - out;
56 | b += a - blockSize * out;
57 |
58 | *weak = (a & 0xffff) | (b << 16);
59 | }
60 |
61 | void Digest_CalcStrong_Data(const uint8_t *data, const uint32_t size, uint8_t *out) {
62 | MD5_Data(data, size, out);
63 | /*
64 | blake2b_state ctx;
65 | blake2b_init(&ctx, CRS_STRONG_DIGEST_SIZE);
66 | blake2b_update(&ctx, data, size);
67 | blake2b_final(&ctx, (uint8_t *)out, CRS_STRONG_DIGEST_SIZE);*/
68 | }
69 |
70 | void Digest_CalcStrong_Data2(const uint8_t *buf1, const uint8_t *buf2, const uint32_t size, const uint32_t offset, uint8_t *out) {
71 | MD5_CTX ctx;
72 | MD5_Init(&ctx);
73 | MD5_Update(&ctx, buf1+offset, size-offset);
74 | MD5_Update(&ctx, buf2, offset);
75 | MD5_Final(&ctx, out);
76 | /*
77 | blake2b_state ctx;
78 | blake2b_init(&ctx, CRS_STRONG_DIGEST_SIZE);
79 | blake2b_update(&ctx, buf1+offset, size-offset);
80 | blake2b_update(&ctx, buf2, offset);
81 | blake2b_final(&ctx, (uint8_t *)out, CRS_STRONG_DIGEST_SIZE);*/
82 | }
83 |
84 | int Digest_CalcStrong_File(const char *filename, uint8_t *out) {
85 | return MD5_File(filename, out);
86 | //return blake2b_File(filename, out, CRS_STRONG_DIGEST_SIZE);
87 | }
88 |
89 | fileDigest_t* fileDigest_malloc() {
90 | return calloc(1, sizeof(fileDigest_t));
91 | }
92 |
93 | void fileDigest_free(fileDigest_t* fd) {
94 | if(fd) {
95 | free(fd->blockDigest);
96 | free(fd->restData);
97 | free(fd);
98 | }
99 | }
100 |
101 | void fileDigest_dump(const fileDigest_t* fd) {
102 | if(fd) {
103 | LOGI("fileSize = %d\n", fd->fileSize);
104 | LOGI("blockSize = %d KiB\n", fd->blockSize/1024);
105 | char *hashString = Util_hex_string(fd->fileDigest, CRS_STRONG_DIGEST_SIZE);
106 | LOGI("fileDigest = %s\n", hashString);
107 | free(hashString);
108 | size_t restSize = (fd->blockSize == 0) ? 0 : (fd->fileSize % fd->blockSize);
109 | LOGI("restSize = %d Bytes\n", restSize);
110 | } else {
111 | LOGI("none\n");
112 | }
113 | }
114 |
115 | CRScode Digest_Perform(const char *filename, const uint32_t blockSize, fileDigest_t *fd) {
116 | LOGI("begin\n");
117 |
118 | if(!filename || blockSize == 0 || !fd) {
119 | LOGE("end %d\n", CRS_PARAM_ERROR);
120 | return CRS_PARAM_ERROR;
121 | }
122 |
123 | struct stat st;
124 | if(stat(filename, &st)!=0 || st.st_size==0){
125 | // file not exist || file size is zero
126 | LOGE("end %s stat\n", filename);
127 | return CRS_FILE_ERROR;
128 | }
129 |
130 | FILE *f = fopen(filename, "rb");
131 | if(!f) {
132 | LOGE("end %s fopen\n", filename);
133 | return CRS_FILE_ERROR;
134 | }
135 |
136 | CRScode code = CRS_OK;
137 | uint8_t *buf = malloc(blockSize);
138 | uint32_t blockNum = st.st_size / blockSize;
139 | uint32_t restSize = st.st_size % blockSize;
140 | uint8_t *restData = (restSize > 0) ? malloc(restSize) : NULL;
141 | digest_t *digests = (blockNum > 0) ? malloc(sizeof(digest_t) * blockNum) : NULL;
142 |
143 | for(uint32_t i=0; i< blockNum; ++i) {
144 | if(fread(buf, 1, blockSize, f) == blockSize) {
145 | Digest_CalcWeak_Data(buf, blockSize, &digests[i].weak);
146 | Digest_CalcStrong_Data(buf, blockSize, digests[i].strong);
147 | } else {
148 | code = CRS_FILE_ERROR;
149 | LOGE("error %s fread\n", filename);
150 | break;
151 | }
152 | }
153 |
154 | if(code == CRS_OK && restSize > 0) {
155 | if(fread(buf, 1, restSize, f) == restSize) {
156 | memcpy(restData, buf, restSize);
157 | } else {
158 | code = CRS_FILE_ERROR;
159 | LOGE("error %s fread\n", filename);
160 | }
161 | }
162 | free(buf);
163 | fclose(f);
164 |
165 | if(code != CRS_OK) {
166 | LOGE("end %d\n", code);
167 | return code;
168 | }
169 |
170 | uint8_t fileDigest[CRS_STRONG_DIGEST_SIZE];
171 | if(0 != Digest_CalcStrong_File(filename, fileDigest)) {
172 | LOGE("end %s Digest_CalcStrong_File\n", filename);
173 | return CRS_FILE_ERROR;
174 | }
175 |
176 | fd->fileSize = st.st_size;
177 | fd->blockSize = blockSize;
178 | fd->blockDigest = digests;
179 | fd->restData = restData;
180 | memcpy(fd->fileDigest, fileDigest, CRS_STRONG_DIGEST_SIZE);
181 |
182 | LOGI("end %d\n", code);
183 | return code;
184 | }
185 |
186 | static const char *DIGEST_TPLMAP_FORMAT = "uuc#BA(uc#)";
187 |
188 | CRScode Digest_Load(const char *filename, fileDigest_t *fd) {
189 | LOGI("begin\n");
190 |
191 | if(!filename || !fd) {
192 | LOGE("end %d\n", CRS_PARAM_ERROR);
193 | return CRS_PARAM_ERROR;
194 | }
195 |
196 | if(0 != Digest_checkfile(filename)) {
197 | LOGI("end %s miss\n", filename);
198 | return CRS_FILE_ERROR;
199 | }
200 |
201 | CRScode code = CRS_OK;
202 | tpl_bin tb = {NULL, 0};
203 | digest_t digest;
204 |
205 | tpl_node *tn = tpl_map( DIGEST_TPLMAP_FORMAT,
206 | &fd->fileSize,
207 | &fd->blockSize,
208 | fd->fileDigest,
209 | CRS_STRONG_DIGEST_SIZE,
210 | &tb,
211 | &digest.weak,
212 | &digest.strong,
213 | CRS_STRONG_DIGEST_SIZE);
214 | if(0 == tpl_load(tn, TPL_FILE, filename)) {
215 | tpl_unpack(tn, 0);
216 |
217 | uint32_t blockNum = fd->fileSize / fd->blockSize;
218 | fd->blockDigest = (blockNum > 0) ? malloc(sizeof(digest_t) * blockNum) : NULL;
219 | fd->restData = tb.addr;
220 |
221 | for (uint32_t i = 0; i < blockNum; i++) {
222 | tpl_unpack(tn, 1);
223 | fd->blockDigest[i].weak = digest.weak;
224 | memcpy(fd->blockDigest[i].strong, digest.strong, CRS_STRONG_DIGEST_SIZE);
225 | }
226 | } else {
227 | LOGE("error tpl_load %s\n", filename);
228 | code = CRS_FILE_ERROR;
229 | }
230 | tpl_free(tn);
231 |
232 | LOGI("end %d\n", code);
233 | return code;
234 | }
235 |
236 | CRScode Digest_Save(const char *filename, fileDigest_t *fd) {
237 | LOGI("begin\n");
238 |
239 | if(!filename || !fd) {
240 | LOGE("end %d\n", CRS_PARAM_ERROR);
241 | return CRS_PARAM_ERROR;
242 | }
243 |
244 | CRScode code = CRS_OK;
245 | tpl_bin tb = {NULL, 0};
246 | tb.addr = fd->restData;
247 | tb.sz = fd->fileSize % fd->blockSize;
248 |
249 | digest_t digest;
250 |
251 | tpl_node *tn = tpl_map( DIGEST_TPLMAP_FORMAT,
252 | &fd->fileSize,
253 | &fd->blockSize,
254 | fd->fileDigest,
255 | CRS_STRONG_DIGEST_SIZE,
256 | &tb,
257 | &digest.weak,
258 | &digest.strong,
259 | CRS_STRONG_DIGEST_SIZE);
260 | tpl_pack(tn, 0);
261 |
262 | uint32_t blockNum = fd->fileSize / fd->blockSize;
263 | for (uint32_t i = 0; i < blockNum; ++i) {
264 | digest.weak = fd->blockDigest[i].weak;
265 | memcpy(digest.strong, fd->blockDigest[i].strong, CRS_STRONG_DIGEST_SIZE);
266 | tpl_pack(tn, 1);
267 | }
268 |
269 | if(0 != tpl_dump(tn, TPL_FILE, filename)) {
270 | LOGE("error tpl_dump %s\n", filename);
271 | code = CRS_FILE_ERROR;
272 | }
273 | tpl_free(tn);
274 |
275 | LOGI("end %d\n", code);
276 | return code;
277 | }
278 |
279 | int Digest_checkfile(const char *filename) {
280 | return Util_tplcmp(filename, DIGEST_TPLMAP_FORMAT);
281 | }
282 |
--------------------------------------------------------------------------------
/src/digest.h:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #ifndef CRS_DIGEST_H
25 | #define CRS_DIGEST_H
26 |
27 | #if defined __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | #include
32 |
33 | #include "global.h"
34 |
35 | extern const char *DIGEST_EXT;
36 |
37 | void Digest_CalcWeak_Data(const uint8_t *data, const uint32_t len, uint32_t *out);
38 | void Digest_CalcWeak_Roll(const uint8_t out, const uint8_t in, const uint32_t blockSize, uint32_t *weak);
39 |
40 | void Digest_CalcStrong_Data(const uint8_t *data, const uint32_t len, uint8_t *out);
41 | void Digest_CalcStrong_Data2(const uint8_t *buf1, const uint8_t *buf2, const uint32_t size, const uint32_t offset, uint8_t *out);
42 | int Digest_CalcStrong_File(const char *filename, uint8_t *out);
43 |
44 | typedef struct digest_t {
45 | uint8_t strong[CRS_STRONG_DIGEST_SIZE]; // strong digest (md5, blake2 etc.)
46 | uint32_t weak; // Adler32, used for Rolling calc
47 | } digest_t;
48 |
49 | typedef struct fileDigest_t {
50 | uint32_t fileSize; //file size
51 | uint32_t blockSize; //block size
52 | uint8_t fileDigest[CRS_STRONG_DIGEST_SIZE]; //file strong sum
53 | digest_t *blockDigest; //every block's rsum_t data
54 | uint8_t *restData; //rest binary data, size = fileSize % blockSize
55 | } fileDigest_t;
56 |
57 | fileDigest_t* fileDigest_malloc();
58 | void fileDigest_free(fileDigest_t* fd);
59 | void fileDigest_dump(const fileDigest_t* fd);
60 |
61 | CRScode Digest_Perform(const char *filename, const uint32_t blockSize, fileDigest_t *fd);
62 | CRScode Digest_Load(const char *filename, fileDigest_t *fd);
63 | CRScode Digest_Save(const char *filename, fileDigest_t *fd);
64 | int Digest_checkfile(const char *filename);
65 |
66 | #if defined __cplusplus
67 | }
68 | #endif
69 |
70 | #endif // CRS_DIGEST_H
71 |
--------------------------------------------------------------------------------
/src/global.h:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #ifndef CRS_GLOBAL_H
25 | #define CRS_GLOBAL_H
26 |
27 | #if defined __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | typedef enum {
32 | CRS_OK = 0,
33 | CRS_INIT_ERROR, //mostly curl init error
34 | CRS_PARAM_ERROR, //input parameters wrong
35 | CRS_FILE_ERROR, //file io error
36 | CRS_HTTP_ERROR, //http io error
37 | CRS_USER_CANCEL, //user cancel (manual operation, Network Policy)
38 |
39 | CRS_BUG = 100, //Internal error
40 | } CRScode;
41 |
42 | #define CRS_STRONG_DIGEST_SIZE 16
43 |
44 | extern void crs_callback_diff (const char *basename, const unsigned int bytes, const int isComplete);
45 | extern int crs_callback_patch (const char *basename, const unsigned int bytes, const int isComplete, const int immediate);
46 |
47 | #if defined __cplusplus
48 | }
49 | #endif
50 |
51 | #endif // CRS_GLOBAL_H
52 |
--------------------------------------------------------------------------------
/src/helper.h:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #ifndef CRS_HELPER_H
25 | #define CRS_HELPER_H
26 |
27 | #if defined __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | #include
32 |
33 | #include "global.h"
34 | #include "magnet.h"
35 | #include "diff.h"
36 |
37 | CRScode helper_perform_version();
38 |
39 | typedef struct helper_t {
40 | //here is constant ref pointer, never change
41 | char *fileDir; //file directory, end with '/', ref to bulkhelper_t.fileDir
42 | char *baseUrl; //base url, end with '/', ref to bulkhelper_t.baseUrl
43 |
44 | //here is constant, never change
45 | char *fileName; //file name
46 | uint32_t fileSize; //whole file size
47 | uint8_t fileDigest[CRS_STRONG_DIGEST_SIZE]; //whole file digest
48 | struct helper_t *next; //used by bulkhelper with utlist(single-link)
49 |
50 | //here is variable, which may change in diff and patch
51 |
52 | uint32_t cacheSize; //local, cache, same file size
53 | int isComplete; //0 not; 1 complete
54 | fileDigest_t *fd;
55 | diffResult_t *dr;
56 |
57 | } helper_t;
58 |
59 | helper_t* helper_malloc ();
60 | void helper_free (helper_t *h);
61 |
62 | CRScode helper_perform_diff (helper_t *h);
63 |
64 | CRScode helper_perform_patch(helper_t *h);
65 |
66 | typedef struct bulkHelper_t {
67 | //here is constant, never change
68 | char *fileDir;
69 | char *baseUrl;
70 |
71 | //here is bulk file struct
72 | magnet_t *currentMagnet; //currVersion's magnet
73 | helper_t *currentBulk; //used with utlist(signle-link)
74 |
75 | } bulkHelper_t;
76 |
77 | bulkHelper_t * bulkHelper_malloc ();
78 | void bulkHelper_free (bulkHelper_t *bh);
79 |
80 | //CRScode bulkHelper_perform_magnet (bulkHelper_t *bh);
81 | CRScode bulkHelper_set_magnet (bulkHelper_t *bh, const char *magnetString);
82 |
83 | CRScode bulkHelper_perform_diff (bulkHelper_t *bh);
84 |
85 | CRScode bulkHelper_perform_patch (bulkHelper_t *bh);
86 |
87 | #if defined __cplusplus
88 | }
89 | #endif
90 |
91 | #endif // CRS_HELPER_H
92 |
--------------------------------------------------------------------------------
/src/http.c:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #include
25 | #include
26 | #include
27 |
28 | #include "http.h"
29 | #include "util.h"
30 | #include "log.h"
31 |
32 | CRScode HTTP_global_init() {
33 | CURLcode code = curl_global_init(CURL_GLOBAL_DEFAULT);
34 | return (code == CURLE_OK) ? CRS_OK : CRS_INIT_ERROR;
35 | }
36 |
37 | void HTTP_global_cleanup() {
38 | curl_global_cleanup();
39 | }
40 |
41 | #if 0
42 | static const char s_infotype[CURLINFO_END][3] = {"* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
43 | static int HTTP_curl_debug(CURL *curl, curl_infotype type, char *data, size_t size, void *userptr) {
44 | (void)curl;
45 | (void)size;
46 | (void)userptr;
47 | switch (type) {
48 | case CURLINFO_TEXT:
49 | case CURLINFO_HEADER_IN:
50 | case CURLINFO_HEADER_OUT:
51 | LOGD("%s: %s\n", s_infotype[type], data);
52 | break;
53 | default:
54 | break;
55 | }
56 | return 0;
57 | }
58 | #endif
59 |
60 | static void HTTP_curl_setopt(CURL *curl) {
61 | #if 0
62 | curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
63 | curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, HTTP_curl_debug);
64 | #endif
65 | curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
66 | curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP); /* http protocol only */
67 | curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); /* request failure on HTTP response >= 400 */
68 | curl_easy_setopt(curl, CURLOPT_AUTOREFERER, 1L); /* allow auto referer */
69 | curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); /* allow follow location */
70 | curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5L); /* allow redir 5 times */
71 | curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L); /* connection timeout */
72 | /*Do not setup CURLOPT_TIMEOUT, since range and file download may cost lots of time*/
73 | /*curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L);*/
74 | }
75 |
76 | static const char *response200 = "HTTP/1.0 200 OK";
77 | static const char *response200_1 = "HTTP/1.1 200 OK";
78 | static const size_t responselen = 15; //as above strlen
79 |
80 | static size_t header_callback(void *data, size_t size, size_t nmemb, void *userp)
81 | {
82 | (void)userp;
83 | size_t realSize = size * nmemb;
84 | size_t minSize = realSize < responselen ? realSize : responselen;
85 | if( 0 == strncasecmp((const char*)data, response200, minSize) ||
86 | 0 == strncasecmp((const char*)data, response200_1, minSize) ) {
87 | LOGE("range response 200\n");
88 | return 0;
89 | }
90 | return realSize;
91 | }
92 |
93 | CURLcode HTTP_Range(CURL *curl, const char *url, const char *range, void *callback, void *data) {
94 | HTTP_curl_setopt(curl);
95 | curl_easy_setopt(curl, CURLOPT_URL, url);
96 | curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
97 | curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (void*)header_callback);
98 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
99 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, data);
100 | curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
101 | curl_easy_setopt(curl, CURLOPT_RANGE, range);
102 |
103 | CURLcode curlcode = curl_easy_perform(curl);
104 | if(CURLE_OK != curlcode) {
105 | LOGI("curlcode %d\n", curlcode);
106 | }
107 |
108 | curl_easy_reset(curl);
109 | return curlcode;
110 | }
111 |
112 | typedef struct filecache_t {
113 | const char *name;
114 | long bytes;
115 | FILE *file;
116 | } filecache_t;
117 |
118 | static size_t HTTP_writefile_func(void *ptr, size_t size, size_t nmemb, void *userdata)
119 | {
120 | filecache_t * cache = (filecache_t*)userdata;
121 | size_t w = fwrite(ptr, size, nmemb, cache->file);
122 | cache->bytes += w;
123 | int isCancel = 0;
124 | if(cache->name) {
125 | isCancel = crs_callback_patch(cache->name, cache->bytes, 0, 0);
126 | }
127 | return (isCancel == 0) ? w : 0;
128 | }
129 |
130 | CRScode HTTP_File(const char *url, const char *filename, int retry, const char *cbname) {
131 | if(!url || !filename) {
132 | LOGE("%d\n", CRS_PARAM_ERROR);
133 | return CRS_PARAM_ERROR;
134 | }
135 |
136 | CURL *curl = curl_easy_init();
137 | if(!curl) {
138 | LOGE("%d\n", CRS_INIT_ERROR);
139 | return CRS_INIT_ERROR;
140 | }
141 |
142 | CRScode code = CRS_OK;
143 | filecache_t cache;
144 | cache.name = cbname;
145 |
146 | struct stat st;
147 | while(retry-- >= 0) {
148 | if(0 == stat(filename, &st)) {
149 | cache.bytes = st.st_size;
150 | } else {
151 | cache.bytes = 0L;
152 | }
153 |
154 | FILE *f = fopen(filename, "ab+");
155 | if(!f) {
156 | code = CRS_FILE_ERROR;
157 | break;
158 | }
159 | cache.file = f;
160 |
161 | HTTP_curl_setopt(curl);
162 | curl_easy_setopt(curl, CURLOPT_URL, url);
163 | curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
164 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HTTP_writefile_func);
165 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&cache);
166 | curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
167 | curl_easy_setopt(curl, CURLOPT_RESUME_FROM, cache.bytes);
168 |
169 | CURLcode curlcode = curl_easy_perform(curl);
170 | fclose(f);
171 | curl_easy_reset(curl);
172 |
173 | switch(curlcode) {
174 | case CURLE_OK:
175 | code = CRS_OK;
176 | break;
177 | case CURLE_HTTP_RETURNED_ERROR: // server connect OK, remote file not exist
178 | retry = -1;
179 | code = CRS_HTTP_ERROR;
180 | break;
181 | case CURLE_OPERATION_TIMEDOUT: //timeout, go on
182 | retry++;
183 | code = CRS_HTTP_ERROR;
184 | break;
185 | default:
186 | code = CRS_HTTP_ERROR;
187 | break;
188 | }
189 |
190 | if(code == CRS_OK) {
191 | break;
192 | }
193 | LOGI("curlcode %d\n", curlcode);
194 |
195 | }//end of while(retry)
196 | curl_easy_cleanup(curl);
197 |
198 | return code;
199 | }
200 |
--------------------------------------------------------------------------------
/src/http.h:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #ifndef CRS_HTTP_H
25 | #define CRS_HTTP_H
26 |
27 | #if defined __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | #include "global.h"
32 | #include "curl/curl.h"
33 |
34 | CRScode HTTP_global_init();
35 | void HTTP_global_cleanup();
36 |
37 | //callback should be int (Range_callback)(void *data, size_t size, size_t nmemb, void *userp);
38 | CURLcode HTTP_Range(CURL *curl, const char *url, const char *range, void *callback, void *data);
39 |
40 | CRScode HTTP_File(const char *url, const char *filename, int retry, const char *cbname);
41 |
42 | #if defined __cplusplus
43 | }
44 | #endif
45 |
46 | #endif // CRS_HTTP_H
47 |
--------------------------------------------------------------------------------
/src/log.c:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #include
25 |
26 | #include "log.h"
27 | #include "utlist.h"
28 |
29 | #if defined ANDROID
30 | # define LOG_FILENAME "/sdcard/crsync_core.log"
31 | #else
32 | # define LOG_FILENAME "crsync_core.log"
33 | #endif
34 |
35 | FILE *logfile = NULL;
36 |
37 | void log_open() {
38 | #if CRSYNC_DEBUG
39 | if(!logfile) logfile = fopen(LOG_FILENAME, "at+");
40 | #endif
41 | }
42 |
43 | void log_close() {
44 | #if CRSYNC_DEBUG
45 | if(logfile) {
46 | fflush(logfile);
47 | fclose(logfile);
48 | logfile = NULL;
49 | }
50 | #endif
51 | }
52 |
53 | void log_timestamp(char *ts) {
54 | time_t t;
55 | time(&t);
56 | #if defined ANDROID
57 | struct tm tmv;
58 | localtime_r(&t, &tmv);
59 | strftime(ts, LOG_TIME_STRING_SIZE, "%Y%m%d %H:%M:%S", &tmv);
60 | #else
61 | struct tm *tmv = localtime(&t);
62 | strftime(ts, LOG_TIME_STRING_SIZE, "%Y%m%d %H:%M:%S", tmv);
63 | #endif
64 | }
65 |
--------------------------------------------------------------------------------
/src/log.h:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #ifndef CRSYNC_LOG_H
25 | #define CRSYNC_LOG_H
26 |
27 | #if defined __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | #include
32 | #include
33 |
34 | #define CRSYNC_DEBUG 1
35 |
36 | extern FILE *logfile;
37 |
38 | void log_open();
39 | void log_close();
40 |
41 | #define LOG_TIME_STRING_SIZE 20
42 | void log_timestamp(char *ts);
43 |
44 | #if defined ANDROID
45 | #include
46 | # define LOG_TAG "crsync_core"
47 | # define LEVEL_D ANDROID_LOG_DEBUG
48 | # define LEVEL_I ANDROID_LOG_INFO
49 | # define LEVEL_W ANDROID_LOG_WARN
50 | # define LEVEL_E ANDROID_LOG_ERROR
51 | # define LOG_PRINT(level, fmt, ...) __android_log_print(level, LOG_TAG, "[%s]: " fmt, __func__, ##__VA_ARGS__)
52 | #else
53 | # define LEVEL_D 1
54 | # define LEVEL_I 2
55 | # define LEVEL_W 3
56 | # define LEVEL_E 4
57 | # define LOG_PRINT(level, fmt, ...) printf("%s %d [%s]: " fmt, ts, level, __func__, ##__VA_ARGS__)
58 | #endif
59 |
60 | #define LOG_FILE(level, fmt, ...) \
61 | if(logfile) { \
62 | fprintf(logfile, "%s %d [%s]: " fmt, ts, level, __func__, ##__VA_ARGS__); \
63 | fflush(logfile); \
64 | }
65 |
66 | #define LOG_OUTPUT(level, fmt, ...) \
67 | do{\
68 | char ts[LOG_TIME_STRING_SIZE];\
69 | log_timestamp(ts);\
70 | LOG_PRINT(level, fmt, ##__VA_ARGS__);\
71 | LOG_FILE(level, fmt, ##__VA_ARGS__);\
72 | } while(0)
73 |
74 | #if CRSYNC_DEBUG
75 | # define LOGD(fmt, ...) LOG_OUTPUT(LEVEL_D, fmt, ##__VA_ARGS__)
76 | # define LOGI(fmt, ...) LOG_OUTPUT(LEVEL_I, fmt, ##__VA_ARGS__)
77 | # define LOGW(fmt, ...) LOG_OUTPUT(LEVEL_W, fmt, ##__VA_ARGS__)
78 | # define LOGE(fmt, ...) LOG_OUTPUT(LEVEL_E, fmt, ##__VA_ARGS__)
79 | #else
80 | # define LOGD(...)
81 | # define LOGI(...)
82 | # define LOGW(...)
83 | # define LOGE(...)
84 | #endif //CRSYNC_DEBUG
85 |
86 | #if defined __cplusplus
87 | }
88 | #endif
89 |
90 | #endif // CRSYNC_LOG_H
91 |
--------------------------------------------------------------------------------
/src/magnet.c:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #include
25 | #include
26 |
27 | #include "magnet.h"
28 | #include "utlist.h"
29 | #include "tpl.h"
30 | #include "util.h"
31 | #include "log.h"
32 |
33 | const char *MAGNET_EXT = ".fdi";
34 | static const char *MAGNET_TPL_FORMAT = "ssA(suc#)";
35 |
36 | sum_t* sum_malloc() {
37 | return calloc(1, sizeof(sum_t));
38 | }
39 |
40 | void sum_free(sum_t *s) {
41 | sum_t *elt, *tmp;
42 | LL_FOREACH_SAFE(s,elt,tmp) {
43 | LL_DELETE(s,elt);
44 | free(elt->name);
45 | free(elt);
46 | }
47 | }
48 |
49 | magnet_t* magnet_malloc() {
50 | return calloc(1, sizeof(magnet_t));
51 | }
52 |
53 | void magnet_free(magnet_t *m) {
54 | if(m) {
55 | free(m->currVersion);
56 | free(m->nextVersion);
57 | sum_free(m->file);
58 | }
59 | }
60 |
61 | void magnet_toString(magnet_t *m, UT_string **str) {
62 | if(!m || !str || !*str)
63 | return;
64 | UT_string *s = *str;
65 | utstring_clear(s);
66 | sum_t *elt;
67 | LL_FOREACH(m->file, elt) {
68 | char *hash = Util_hex_string(elt->digest, CRS_STRONG_DIGEST_SIZE);
69 | utstring_printf(s, "%s;%s;%u;", elt->name, hash, elt->size);
70 | free(hash);
71 | }
72 | }
73 |
74 | magnet_t* magnet_fromString(UT_string **str) {
75 | if(!str || !*str) {
76 | return NULL;
77 | }
78 | magnet_t *m = magnet_malloc();
79 | UT_string *s = *str;
80 | int findPos = -1;
81 | int startPos = 0;
82 | int order = 0;
83 |
84 | sum_t *sum = NULL;
85 | char findStr[128];//should enough mostly
86 |
87 | while(-1 != (findPos = utstring_find(s, startPos, ";", 1))) {
88 | if(!sum)
89 | sum = sum_malloc();
90 | strncpy(findStr, utstring_body(s) + startPos, findPos - startPos);
91 | findStr[findPos - startPos] = '\0';
92 |
93 | switch(order) {
94 | case 0: {
95 | sum->name = strdup(findStr);
96 | break;
97 | }
98 | case 1: {
99 | unsigned char *digest = Util_string_hex(findStr);
100 | memcpy(sum->digest, digest, CRS_STRONG_DIGEST_SIZE);
101 | free(digest);
102 | break;
103 | }
104 | case 2: {
105 | sum->size = (unsigned int)atoi(findStr);
106 | LL_APPEND(m->file, sum);
107 | sum = NULL;
108 | break;
109 | }
110 | }
111 | order = (order >= 2) ? 0 : order+1;
112 | startPos = findPos + 1;
113 | }
114 |
115 | return m;
116 | }
117 |
118 | CRScode magnet_load(magnet_t *m, const char *file) {
119 | LOGI("begin\n");
120 | CRScode code = CRS_OK;
121 | char *name = NULL;
122 | unsigned int size = 0;
123 | unsigned char digest[CRS_STRONG_DIGEST_SIZE];
124 | tpl_node *tn = tpl_map(MAGNET_TPL_FORMAT,
125 | &m->currVersion,
126 | &m->nextVersion,
127 | &name,
128 | &size,
129 | &digest,
130 | CRS_STRONG_DIGEST_SIZE);
131 | if (0 == tpl_load(tn, TPL_FILE, file) ) {
132 | tpl_unpack(tn, 0);
133 | while (tpl_unpack(tn, 1) > 0) {
134 | sum_t *s = sum_malloc();
135 | s->name = strdup(name);
136 | s->size = size;
137 | memcpy(s->digest, digest, CRS_STRONG_DIGEST_SIZE);
138 | LL_APPEND(m->file, s);
139 | }
140 | } else {
141 | code = CRS_FILE_ERROR;
142 | }
143 | tpl_free(tn);
144 | LOGI("end %d\n", code);
145 | return code;
146 | }
147 |
148 | CRScode magnet_save(magnet_t *m, const char *file) {
149 | LOGI("begin\n");
150 | char *name = NULL;
151 | unsigned int size = 0;
152 | unsigned char digest[CRS_STRONG_DIGEST_SIZE];
153 | tpl_node *tn = tpl_map(MAGNET_TPL_FORMAT,
154 | &m->currVersion,
155 | &m->nextVersion,
156 | &name,
157 | &size,
158 | &digest,
159 | CRS_STRONG_DIGEST_SIZE);
160 | tpl_pack(tn, 0);
161 |
162 | sum_t *elt=NULL;
163 | LL_FOREACH(m->file,elt) {
164 | name = elt->name;
165 | size = elt->size;
166 | memcpy(digest,elt->digest, CRS_STRONG_DIGEST_SIZE);
167 | tpl_pack(tn, 1);
168 | }
169 | int result = tpl_dump(tn, TPL_FILE, file);
170 | tpl_free(tn);
171 | CRScode code = (-1 == result) ? CRS_FILE_ERROR : CRS_OK;
172 | LOGI("end %d\n", code);
173 | return code;
174 | }
175 |
176 | int Magnet_checkfile(const char *filename) {
177 | return Util_tplcmp(filename, MAGNET_TPL_FORMAT);
178 | }
179 |
--------------------------------------------------------------------------------
/src/magnet.h:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #ifndef CRS_MAGNET_H
25 | #define CRS_MAGNET_H
26 |
27 | #include "global.h"
28 | #include "utstring.h"
29 |
30 | extern const char *MAGNET_EXT;
31 |
32 | typedef struct sum_t {
33 | char *name;
34 | unsigned int size;
35 | unsigned char digest[CRS_STRONG_DIGEST_SIZE];
36 | struct sum_t *next; //utlist(single-link)
37 | } sum_t;
38 |
39 | sum_t* sum_malloc();
40 | void sum_free(sum_t *s);
41 |
42 | typedef struct magnet_t {
43 | char *currVersion;
44 | char *nextVersion;
45 | sum_t *file; //utlist(single-link)
46 | } magnet_t;
47 |
48 | magnet_t* magnet_malloc();
49 | void magnet_free(magnet_t *m);
50 |
51 | void magnet_toString(magnet_t *m, UT_string **str);
52 | magnet_t* magnet_fromString(UT_string **str);
53 |
54 | CRScode magnet_load(magnet_t *m, const char *file);
55 | CRScode magnet_save(magnet_t *m, const char *file);
56 |
57 | int Magnet_checkfile(const char *filename);
58 |
59 | #endif // CRS_MAGNET_H
60 |
61 |
--------------------------------------------------------------------------------
/src/onepiece.h:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #ifndef CRSYNC_ONEPIECE_H
25 | #define CRSYNC_ONEPIECE_H
26 |
27 | #if defined __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | #include "crsync.h"
32 |
33 | #define MAGNET_SUFFIX ".magnet"
34 | #define MAGNET_TPLMAP_FORMAT "sssA(ss)"
35 |
36 | typedef struct res_t {
37 | char *name;
38 | char *hash;
39 | uint32_t size;
40 | uint32_t diff_size;
41 | struct res_t *next;
42 | } res_t;
43 |
44 | void res_free(res_t *res);
45 |
46 | typedef struct oldmagnet_t {
47 | char *curr_id; /* current magnet info id */
48 | char *next_id; /* next magnet info id */
49 | res_t *app; /* android apk hash */
50 | res_t *res_list; /* resource list */
51 | } oldmagnet_t;
52 |
53 | oldmagnet_t* onepiece_magnet_malloc();
54 | void onepiece_magnet_free(oldmagnet_t *m);
55 |
56 | CRSYNCcode onepiece_magnet_load(const char *filename, oldmagnet_t *magnet);
57 | CRSYNCcode onepiece_magnet_save(const char *filename, oldmagnet_t *magnet);
58 |
59 | typedef struct onepiece_t onepiece_t;
60 |
61 | typedef enum {
62 | ONEPIECEOPT_STARTID = 0,
63 | ONEPIECEOPT_BASEURL,
64 | ONEPIECEOPT_LOCALAPP,
65 | ONEPIECEOPT_LOCALRES,
66 | ONEPIECEOPT_NEVERUPDATE,
67 | ONEPIECEOPT_XFER,
68 | } ONEPIECEoption;
69 |
70 | typedef enum {
71 | ONEPIECEINFO_MAGNET = 0,
72 | } ONEPIECEinfo;
73 |
74 | CRSYNCcode onepiece_init();
75 | CRSYNCcode onepiece_setopt(ONEPIECEoption opt, void *value);
76 | oldmagnet_t* onepiece_getinfo_magnet();
77 | CRSYNCcode onepiece_perform_query();
78 | CRSYNCcode onepiece_perform_MatchApp();
79 | CRSYNCcode onepiece_perform_PatchApp();
80 | CRSYNCcode onepiece_perform_MatchRes();
81 | CRSYNCcode onepiece_perform_PatchRes();
82 | //CRSYNCcode onepiece_perform_updateapp();
83 | //CRSYNCcode onepiece_perform_updateres();
84 | void onepiece_cleanup();
85 |
86 | #if defined __cplusplus
87 | }
88 | #endif
89 |
90 | #endif // CRSYNC_ONEPIECE_H
91 |
--------------------------------------------------------------------------------
/src/onepiecetool.c:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #include
25 | #include
26 |
27 | #include "onepiecetool.h"
28 | #include "log.h"
29 |
30 | static const uint32_t Default_BLOCK_SIZE = 8*1024; //default block size to 8K
31 |
32 | onepiecetool_option_t* onepiecetool_option_malloc() {
33 | onepiecetool_option_t* op = calloc(1, sizeof(onepiecetool_option_t));
34 | op->block_size = Default_BLOCK_SIZE;
35 | return op;
36 | }
37 |
38 | void resname_free(resname_t *res) {
39 | resname_t *elt=NULL, *tmp=NULL;
40 | LL_FOREACH_SAFE(res, elt, tmp) {
41 | LL_DELETE(res, elt);
42 | free(elt->name);
43 | free(elt);
44 | }
45 | }
46 |
47 | void onepiecetool_option_free(onepiecetool_option_t *option) {
48 | if(option) {
49 | free(option->curr_id);
50 | free(option->next_id);
51 | free(option->app_name);
52 | free(option->res_dir);
53 | resname_free(option->res_list);
54 | free(option->output_dir);
55 | free(option);
56 | }
57 | }
58 |
59 | /* 1. copy input file to output dir with hashname
60 | 2. move input file's rsum file to output dir with hashname.rsum
61 | */
62 | static CRSYNCcode util_movefile(const char *inputfile, const char *outputdir, const char *hash) {
63 | CRSYNCcode code = CRSYNCE_FILE_ERROR;
64 | UT_string *input = NULL;
65 | utstring_new(input);
66 | utstring_printf(input, "%s%s", inputfile, RSUM_SUFFIX);
67 |
68 | UT_string *output = NULL;
69 | utstring_new(output);
70 | utstring_printf(output, "%s%s", outputdir, hash);
71 |
72 | do {
73 | tpl_mmap_rec recin = {-1, NULL, 0};
74 | tpl_mmap_rec recout = {-1, NULL, 0};
75 | if(0 == tpl_mmap_file(inputfile, &recin)) {
76 | recout.fd = tpl_mmap_output_file(utstring_body(output), recin.text_sz, &recout.text);
77 | if(-1 != recout.fd) {
78 | memcpy(recout.text, recin.text, recin.text_sz);
79 | tpl_unmap_file(&recout);
80 | code = CRSYNCE_OK;
81 | }
82 | tpl_unmap_file(&recin);
83 | }
84 | if(CRSYNCE_OK != code) break;
85 |
86 | utstring_printf(output, "%s", RSUM_SUFFIX);
87 | int i = rename(utstring_body(input), utstring_body(output));
88 | code = (0 == i) ? CRSYNCE_OK : CRSYNCE_FILE_ERROR;
89 | } while (0);
90 |
91 | utstring_free(input);
92 | utstring_free(output);
93 | return code;
94 | }
95 |
96 | CRSYNCcode onepiecetool_perform(onepiecetool_option_t *option) {
97 | LOGI("onepiecetool_perform\n");
98 | CRSYNCcode code = CRSYNCE_OK;
99 |
100 | UT_string *input = NULL;
101 | utstring_new(input);
102 |
103 | UT_string *output = NULL;
104 | utstring_new(output);
105 |
106 | UT_string *hash = NULL;
107 | utstring_new(hash);
108 |
109 | LOGI("clean up %s\n", option->output_dir);
110 | DIR *dirp = opendir(option->output_dir);
111 | if(dirp) {
112 | struct dirent *direntp = NULL;
113 | while ((direntp = readdir(dirp)) != NULL) {
114 | if(0 == strcmp(direntp->d_name, ".") ||
115 | 0 == strcmp(direntp->d_name, "..")) {
116 | continue;
117 | }
118 | LOGD("remove %s\n", direntp->d_name);
119 | utstring_clear(output);
120 | utstring_printf(output, "%s%s", option->output_dir, direntp->d_name);
121 | remove(utstring_body(output));
122 | }
123 | closedir(dirp);
124 | } else {
125 | #ifndef _WIN32
126 | mkdir(option->output_dir, S_IRUSR|S_IWUSR|S_IWGRP|S_IRGRP|S_IROTH);
127 | #else
128 | mkdir(option->output_dir);
129 | #endif
130 | }
131 |
132 | oldmagnet_t *magnet = onepiece_magnet_malloc();
133 | magnet->curr_id = strdup(option->curr_id);
134 | magnet->next_id = strdup(option->next_id);
135 |
136 | do {
137 | LOGI("generate app rsum file\n");
138 | LOGI("perform %s\n", option->app_name);
139 | code = crsync_rsum_generate(option->app_name, option->block_size, hash);
140 | if(CRSYNCE_OK != code) break;
141 | res_t *app = calloc(1, sizeof(res_t));
142 | app->hash = strdup(utstring_body(hash));
143 | LL_APPEND(magnet->app, app);
144 | code = util_movefile(option->app_name, option->output_dir, utstring_body(hash));
145 | if(CRSYNCE_OK != code) break;
146 |
147 | LOGI("generate resource rsum file\n");
148 | resname_t *elt=NULL;
149 | LL_FOREACH(option->res_list, elt) {
150 | LOGI("perform %s\n", elt->name);
151 | utstring_clear(input);
152 | utstring_printf(input, "%s%s", option->res_dir, elt->name);
153 | code = crsync_rsum_generate(utstring_body(input), option->block_size, hash);
154 | if(CRSYNCE_OK != code) break;
155 | struct stat file_info;
156 | stat(utstring_body(input), &file_info);
157 | code = util_movefile(utstring_body(input), option->output_dir, utstring_body(hash));
158 | if(CRSYNCE_OK != code) break;
159 |
160 | res_t *res = calloc(1, sizeof(res_t));
161 | res->name = strdup(elt->name);
162 | res->hash = strdup(utstring_body(hash));
163 | res->size = file_info.st_size;
164 | LL_APPEND(magnet->res_list, res);
165 | }
166 | if(CRSYNCE_OK != code) break;
167 |
168 | LOGI("generate magnet file\n");
169 | utstring_clear(output);
170 | utstring_printf(output, "%s%s%s", option->output_dir, option->curr_id, MAGNET_SUFFIX);
171 | code = onepiece_magnet_save(utstring_body(output), magnet);
172 | } while (0);
173 |
174 | onepiece_magnet_free(magnet);
175 | utstring_free(input);
176 | utstring_free(output);
177 | utstring_free(hash);
178 | LOGI("onepiecetool_perform code = %d\n", code);
179 | return code;
180 | }
181 |
--------------------------------------------------------------------------------
/src/onepiecetool.h:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #ifndef ONEPIECE_TOOL_H
25 | #define ONEPIECE_TOOL_H
26 |
27 | #if defined __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | #include "onepiece.h"
32 |
33 | typedef struct resname_t {
34 | char *name;
35 | struct resname_t *next;
36 | } resname_t;
37 |
38 | void resname_free(resname_t *res);
39 |
40 | typedef struct onepiecetool_option_t {
41 | char *curr_id; //current magnet info id
42 | char *next_id; //next magnet info id
43 | char *app_name; //app full filename
44 | char *res_dir; //resource directory, end with '/'
45 | resname_t *res_list; //resource file list
46 | char *output_dir; //output directory
47 | uint32_t block_size; //block size, default 8K
48 | } onepiecetool_option_t;
49 |
50 | onepiecetool_option_t* onepiecetool_option_malloc();
51 | void onepiecetool_option_free(onepiecetool_option_t *option);
52 |
53 | CRSYNCcode onepiecetool_perform(onepiecetool_option_t *option);
54 |
55 | #if defined __cplusplus
56 | }
57 | #endif
58 |
59 | #endif // ONEPIECE_TOOL_H
60 |
--------------------------------------------------------------------------------
/src/patch.c:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | #include "patch.h"
31 | #include "util.h"
32 | #include "log.h"
33 | #include "http.h"
34 |
35 | static CRScode Patch_match(const char *srcFilename, const char *dstFilename,
36 | const fileDigest_t *fd, const diffResult_t *dr) {
37 | LOGI("begin\n");
38 | if(!srcFilename || !dstFilename || !fd || !dr) {
39 | LOGE("end %d\n", CRS_PARAM_ERROR);
40 | return CRS_PARAM_ERROR;
41 | }
42 |
43 | FILE *f1 = fopen(srcFilename, "rb");
44 | if(!f1){
45 | LOGE("source file fopen error %s\n", strerror(errno));
46 | return CRS_FILE_ERROR;
47 | }
48 |
49 | FILE *f2 = fopen(dstFilename, "rb+");
50 | if(!f2){
51 | LOGE("dest file fopen error %s\n", strerror(errno));
52 | fclose(f1);
53 | return CRS_FILE_ERROR;
54 | }
55 |
56 | CRScode code = CRS_OK;
57 | uint8_t *buf = malloc(fd->blockSize);
58 |
59 | for(int i=0; itotalNum; ++i) {
60 | if(dr->offsets[i] >= 0) {
61 | fseek(f1, dr->offsets[i], SEEK_SET);
62 | fread(buf, 1, fd->blockSize, f1);
63 |
64 | fseek(f2, i*fd->blockSize, SEEK_SET);
65 | fwrite(buf, 1, fd->blockSize, f2);
66 | }
67 | }
68 |
69 | size_t restSize = fd->fileSize % fd->blockSize;
70 | if(restSize > 0){
71 |
72 | fseek(f2, -restSize, SEEK_END);
73 | fwrite(fd->restData, 1, restSize, f2);
74 | }
75 |
76 | free(buf);
77 | fclose(f1);
78 | fclose(f2);
79 | LOGI("end %d\n", code);
80 | return code;
81 | }
82 |
83 | //continuous blocks, used for reduce http range frequency
84 | typedef struct combineblock_t {
85 | size_t pos; //block start position
86 | size_t got; //data fwrite size, used for HTTP retry
87 | size_t len; //block length
88 | } combineblock_t;
89 |
90 | static uint32_t Patch_missCombine(const diffResult_t *dr, combineblock_t *cb, uint32_t blockSize) {
91 | uint32_t combineNum = 0;
92 | int missNum = dr->totalNum - dr->matchNum - dr->cacheNum;
93 | if(missNum == 0) {
94 | LOGW("missNum is Zero, maybe cache done!\n");
95 | return combineNum;
96 | }
97 | if(missNum < 0) {
98 | LOGE("WTF: matchNum %d bigger than totalNum %d\n", dr->matchNum, dr->totalNum);
99 | return combineNum;
100 | }
101 | int i;
102 | uint32_t j;
103 | for(i=0; itotalNum; ++i) {
104 | if(dr->offsets[i] == -1) {
105 | for(j=0; j < combineNum; ++j) {
106 | if(cb[j].pos + cb[j].len == i * blockSize) {
107 | cb[j].len += blockSize;
108 | break;
109 | }
110 | }
111 | if(j == combineNum) {
112 | cb[combineNum].pos = i*blockSize;
113 | cb[combineNum].len = blockSize;
114 | ++combineNum;
115 | }
116 | }
117 | }
118 | LOGI("combineblocks Num = %d\n", combineNum);
119 | return combineNum;
120 | }
121 |
122 | typedef struct rangedata_t {
123 | combineblock_t *cb; //ref to one Patch_miss()
124 | FILE *file; //ref to one Patch_miss()
125 | char *basename; //ref to one Patch_miss()
126 | size_t cacheBytes;
127 | } rangedata_t;
128 |
129 | static size_t Range_callback(void *data, size_t size, size_t nmemb, void *userp) {
130 | rangedata_t *rd = (rangedata_t*)userp;
131 | size_t realSize = size * nmemb;
132 | fseek(rd->file, rd->cb->pos + rd->cb->got, SEEK_SET);
133 | fwrite(data, size, nmemb, rd->file);
134 | rd->cb->got += realSize;
135 | rd->cacheBytes += realSize;
136 | int isCancel = crs_callback_patch(rd->basename, rd->cacheBytes, 0, 0);
137 | return (isCancel == 0) ? realSize : 0;
138 | }
139 |
140 | static CRScode Patch_miss(const char *srcFilename, const char *dstFilename, const char *url,
141 | const fileDigest_t *fd, const diffResult_t *dr) {
142 | LOGI("begin\n");
143 | if(!srcFilename || !dstFilename || !fd || !dr) {
144 | LOGE("end %d\n", CRS_PARAM_ERROR);
145 | return CRS_PARAM_ERROR;
146 | }
147 |
148 | int missNum = dr->totalNum - dr->matchNum - dr->cacheNum;
149 | if(missNum == 0) {
150 | LOGI("end missblocks = 0\n");
151 | return CRS_OK;
152 | }
153 |
154 | FILE *f = fopen(dstFilename, "rb+");
155 | if(!f){
156 | LOGE("%s\n", dstFilename);
157 | LOGE("end fopen error %s\n", strerror(errno));
158 | return CRS_FILE_ERROR;
159 | }
160 |
161 | //combine continuous blocks, no more than missNum
162 | combineblock_t *cb = calloc(missNum, sizeof(combineblock_t) );
163 | uint32_t cbNum = Patch_missCombine(dr, cb, fd->blockSize);
164 |
165 | CRScode code = CRS_OK;
166 | rangedata_t rd;
167 | rd.file = f;
168 | rd.cacheBytes = fd->fileSize - (missNum * fd->blockSize);
169 |
170 | //Some compiler maybe change basename() param
171 | //Do not free(basename) since it maybe inside of fullname
172 | char *tempname = strdup(srcFilename);
173 | rd.basename = basename(tempname);
174 | CURL *curl = curl_easy_init();
175 | for(uint32_t i=0; i< cbNum; ++i) {
176 | rd.cb = &cb[i];
177 | char range[32];
178 | long rangeFrom;
179 | long rangeTo;
180 |
181 | int retry = 10;
182 | while(retry-- > 0) {
183 | rangeFrom = cb[i].pos + cb[i].got;
184 | rangeTo = cb[i].pos + cb[i].len - 1;
185 | snprintf(range, 32, "%ld-%ld", rangeFrom, rangeTo);
186 |
187 | if(rangeFrom >= rangeTo) {
188 | LOGE("range request %ld-%ld wrong\n", rangeFrom, rangeTo);
189 | LOGE("This should not happend! But continue NextBlock\n");
190 | code = CRS_OK;
191 | break;
192 | }
193 |
194 | CURLcode curlcode = HTTP_Range(curl, url, range, (void*)Range_callback, &rd);
195 |
196 | switch(curlcode) {
197 | case CURLE_OK:
198 | code = CRS_OK;
199 | break;
200 | case CURLE_HTTP_RETURNED_ERROR:
201 | LOGE("HTTP request/response header wrong!\n");
202 | retry = -1;
203 | code = CRS_HTTP_ERROR;
204 | break;
205 | case CURLE_OPERATION_TIMEDOUT: //timeout
206 | retry++;
207 | code = CRS_HTTP_ERROR;
208 | break;
209 | default:
210 | code = CRS_HTTP_ERROR;
211 | break;
212 | }
213 |
214 | if(CRS_OK == code) { //got it
215 | break;
216 | } else {
217 | LOGE("curl code %d\n", curlcode);
218 | }
219 | }//end of while
220 |
221 | }//end of for
222 |
223 | curl_easy_cleanup(curl);
224 | free(tempname);
225 | free(cb);
226 | fclose(f);
227 | LOGI("end %d\n", code);
228 | return code;
229 | }
230 |
231 | CRScode Patch_perform(const char *srcFilename, const char *dstFilename, const char *url,
232 | const fileDigest_t *fd, const diffResult_t *dr) {
233 | LOGI("begin\n");
234 |
235 | if(!srcFilename || !dstFilename || !url || !fd || !dr) {
236 | LOGE("end %d\n", CRS_PARAM_ERROR);
237 | return CRS_PARAM_ERROR;
238 | }
239 |
240 | CRScode code = CRS_OK;
241 | do {
242 | if(0 != access(srcFilename, F_OK)) {
243 | LOGE("src file not exist %s\n", strerror(errno));
244 | LOGE("%s\n", srcFilename);
245 | code = CRS_FILE_ERROR;
246 | break;
247 | }
248 | if(0 != access(dstFilename, F_OK)) {
249 | FILE *f = fopen(dstFilename, "ab+");
250 | if(f) {
251 | fclose(f);
252 | } else {
253 | LOGE("dst file create fail %s\n", strerror(errno));
254 | LOGE("%s\n", dstFilename);
255 | code = CRS_FILE_ERROR;
256 | break;
257 | }
258 | }
259 | struct stat st;
260 | if(stat(dstFilename, &st) != 0) {
261 | LOGE("dst file stat fail %s\n", strerror(errno));
262 | LOGE("%s\n", dstFilename);
263 | code = CRS_FILE_ERROR;
264 | break;
265 | }
266 | if((size_t)st.st_size != fd->fileSize) {
267 | if(0 != truncate(dstFilename, fd->fileSize)) {
268 | LOGE("dest file truncate %dBytes error %s\n", fd->fileSize, strerror(errno));
269 | code = CRS_FILE_ERROR;
270 | break;
271 | }
272 | }
273 |
274 | //Patch_match Blocks
275 | code = Patch_match(srcFilename, dstFilename, fd, dr);
276 | if(code != CRS_OK) break;
277 |
278 | //Patch_miss Blocks
279 | code = Patch_miss(srcFilename, dstFilename, url, fd, dr);
280 | if(code != CRS_OK) break;
281 |
282 | char *tempname = strdup(srcFilename);
283 | char *name = basename(tempname);
284 | crs_callback_patch(name, fd->fileSize, 0, 1);
285 | free(tempname);
286 |
287 | uint8_t hash[CRS_STRONG_DIGEST_SIZE];
288 | Digest_CalcStrong_File(dstFilename, hash);
289 | char * hashString = Util_hex_string(hash, CRS_STRONG_DIGEST_SIZE);
290 | LOGI("fileDigest = %s\n", hashString);
291 | free(hashString);
292 | code = (0 == memcmp(hash, fd->fileDigest, CRS_STRONG_DIGEST_SIZE)) ? CRS_OK : CRS_BUG ;
293 |
294 | } while (0);
295 |
296 | LOGI("end %d\n", code);
297 | return code;
298 | }
299 |
--------------------------------------------------------------------------------
/src/patch.h:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #ifndef CRS_PATCH_H
25 | #define CRS_PATCH_H
26 |
27 | #if defined __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | #include "diff.h"
32 |
33 | CRScode Patch_perform(const char *srcFilename, const char *dstFilename, const char *url,
34 | const fileDigest_t *fd, const diffResult_t *dr);
35 |
36 | #if defined __cplusplus
37 | }
38 | #endif
39 |
40 | #endif // CRS_PATCH_H
41 |
42 |
--------------------------------------------------------------------------------
/src/util.c:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | #include "util.h"
32 | #include "tpl.h"
33 | #include "log.h"
34 |
35 | static const char* s_hexTable[256] = {
36 | "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
37 | "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
38 | "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
39 | "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
40 | "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
41 | "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
42 | "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
43 | "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
44 | "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
45 | "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
46 | "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
47 | "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
48 | "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
49 | "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", "dc", "dd", "de", "df",
50 | "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
51 | "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff"
52 | };
53 |
54 | char* Util_hex_string(const unsigned char *in, const unsigned int inlen) {
55 | unsigned int outlen = inlen * 2;
56 | char *out = malloc(outlen+1);
57 | for(unsigned int i=0; i= '0' && c <= '9') return c - '0';
67 | if(c >= 'a' && c <= 'f') return c - 'a' + 10;
68 | if(c >= 'A' && c <= 'F') return c - 'A' + 10;
69 | return 255;
70 | }
71 |
72 | unsigned char* Util_string_hex(const char *in) {
73 | unsigned char *retval;
74 | unsigned char *p;
75 | int len, i;
76 |
77 | len = strlen(in) / 2;
78 | retval = malloc(len+1);
79 | for(i=0, p = (unsigned char *) in; i 0) {
124 | fwrite(buf, 1, size, d);
125 | }
126 | free(buf);
127 |
128 | fclose(s);
129 | fclose(d);
130 |
131 | struct stat stSrc, stDst;
132 | if(stat(src, &stSrc) == 0 && stat(dst, &stDst) == 0) {
133 | if(stSrc.st_size == stDst.st_size) {
134 | return 0;
135 | }
136 | }
137 | LOGE("stat error %s, %s", src, dst);
138 | return -1;
139 | }
140 |
141 | int Util_filemove(const char *src, const char *dst) {
142 | if(0 == Util_filecpy(src, dst)) {
143 | if(0 == remove(src)) {
144 | return 0;
145 | } else {
146 | LOGE("remove %s\n", strerror(errno));
147 | return -1;
148 | }
149 | } else {
150 | LOGE("filecpy fail\n");
151 | return -1;
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/src/util.h:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 chenqi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | #ifndef CRS_UTIL_H
25 | #define CRS_UTIL_H
26 |
27 | #if defined __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | char* Util_hex_string(const unsigned char *in, const unsigned int inlen);
32 |
33 | unsigned char* Util_string_hex(const char *in);
34 |
35 | char* Util_strcat(const char* s1, const char *s2);
36 |
37 | int Util_tplcmp(const char *filename, const char* fmt);
38 |
39 | int Util_filecpy(const char *src, const char *dst);
40 |
41 | int Util_filemove(const char *src, const char *dst);
42 |
43 | #if defined __cplusplus
44 | }
45 | #endif
46 |
47 | #endif // CRS_UTIL_H
48 |
--------------------------------------------------------------------------------