1085 int sync_success = 0; |
1085 int sync_success = 0; |
1086 int sync_delete = 0; |
1086 int sync_delete = 0; |
1087 int sync_skipped = 0; |
1087 int sync_skipped = 0; |
1088 int sync_error = 0; |
1088 int sync_error = 0; |
1089 |
1089 |
|
1090 UcxList *ls_put = NULL; |
|
1091 UcxList *ls_conflict = NULL; |
|
1092 UcxList *ls_update = NULL; |
|
1093 UcxList *ls_delete = NULL; |
|
1094 |
1090 // upload all changed files |
1095 // upload all changed files |
1091 //UcxList *resources = cmd_getoption(a, "read") ? |
1096 //UcxList *resources = cmd_getoption(a, "read") ? |
1092 // read_changes(dir, db) : local_scan(dir, db); |
1097 // read_changes(dir, db) : local_scan(dir, db); |
1093 UcxList *resources = local_scan(dir, db); |
1098 UcxList *resources = local_scan(dir, db); |
1094 |
1099 UcxMap *resources_map = ucx_map_new(ucx_list_size(resources)+16); |
1095 UcxMap *lclres = ucx_map_new(db->resources->count); |
1100 |
1096 int ret = 0; |
|
1097 UCX_FOREACH(elm, resources) { |
1101 UCX_FOREACH(elm, resources) { |
1098 LocalResource *local_res = elm->data; |
1102 LocalResource *local_res = elm->data; |
1099 int error = 0; |
1103 |
1100 |
1104 // ignore all files, that are excluded by a static filter (sync.xml) |
1101 DavBool res_filtered = FALSE; |
1105 |
|
1106 // static include/exclude filter |
1102 if(res_matches_filter(dir, local_res->path+1)) { |
1107 if(res_matches_filter(dir, local_res->path+1)) { |
1103 res_filtered = TRUE; |
1108 continue; |
1104 } else { |
1109 } |
1105 UCX_FOREACH(elm, dir->tagfilter) { |
1110 // static tag filter |
1106 SyncTagFilter *tf = elm->data; |
1111 UCX_FOREACH(elm, dir->tagfilter) { |
1107 if(!localres_matches_tags(dir, local_res, tf)) { |
1112 SyncTagFilter *tf = elm->data; |
1108 res_filtered = TRUE; |
1113 if(!localres_matches_tags(dir, local_res, tf)) { |
1109 break; |
1114 continue; |
1110 } |
1115 } |
1111 } |
1116 } |
1112 } |
1117 |
1113 if (res_filtered) { |
1118 // we need a fast file lookup map later |
1114 local_res->keep = TRUE; |
1119 ucx_map_cstr_put(resources_map, local_res->path, local_res); |
1115 } else if (!localres_matches_tags(dir, local_res, tagfilter)) { |
1120 |
|
1121 // dynamic tag filter |
|
1122 if(!localres_matches_tags(dir, local_res, tagfilter)) { |
1116 if(!remove_file) { |
1123 if(!remove_file) { |
1117 local_res->keep = TRUE; |
1124 LocalResource *dbres = ucx_map_cstr_get( |
1118 } |
1125 db->resources, |
1119 } else { |
1126 local_res->path); |
1120 if(sync_shutdown) { |
1127 if(dbres) { |
1121 LocalResource *lr = ucx_map_cstr_remove(db->resources, local_res->path); |
1128 // this makes sure the file will not be deleted later |
1122 if(lr) { |
1129 dbres->keep = TRUE; |
1123 local_res->size = lr->size; |
1130 } |
1124 local_res->last_modified = lr->last_modified; |
1131 } |
1125 local_res->etag = lr->etag ? strdup(lr->etag) : NULL; |
1132 continue; |
1126 local_resource_free(lr); |
1133 } |
1127 ucx_map_cstr_put(lclres, local_res->path, local_res); |
1134 |
1128 } |
1135 if(res_isconflict(db, local_res)) { |
1129 elm->data = NULL; |
1136 ls_conflict = ucx_list_append(ls_conflict, local_res); |
1130 continue; |
1137 continue; |
1131 } |
1138 } |
1132 |
1139 |
1133 |
1140 int is_changed = local_resource_is_changed( |
1134 if(res_isconflict(db, local_res)) { |
|
1135 printf("skip: %s\n", local_res->path); |
|
1136 sync_skipped++; |
|
1137 continue; |
|
1138 } |
|
1139 |
|
1140 // upload every changed file |
|
1141 int is_changed = local_resource_is_changed( |
|
1142 dir, |
1141 dir, |
1143 db, |
1142 db, |
1144 local_res, |
1143 local_res, |
1145 svrres, |
1144 svrres, |
1146 restore_removed, |
1145 restore_removed, |
1147 restore_modified); |
1146 restore_modified); |
1148 if (is_changed || local_res->tags_updated) { |
1147 if(is_changed) { |
1149 DavResource *res = dav_resource_new(sn, local_res->path); |
1148 ls_put = ucx_list_append(ls_put, local_res); |
1150 if(!res) { |
1149 } else if(local_res->tags_updated) { |
1151 print_resource_error(sn, local_res->path); |
1150 ls_update = ucx_list_append(ls_update, local_res); |
|
1151 } |
|
1152 } |
|
1153 |
|
1154 // find all deleted files and cleanup the database |
|
1155 UcxMapIterator i = ucx_map_iterator(db->resources); |
|
1156 LocalResource *local; |
|
1157 UCX_MAP_FOREACH(key, local, i) { |
|
1158 // all filtered files should be removed from the database |
|
1159 if(res_matches_filter(dir, local->path+1)) { |
|
1160 ucx_map_cstr_remove(db->resources, local->path); |
|
1161 continue; |
|
1162 } |
|
1163 UCX_FOREACH(elm, dir->tagfilter) { |
|
1164 SyncTagFilter *tf = elm->data; |
|
1165 if(!localres_matches_tags(dir, local, tf)) { |
|
1166 ucx_map_cstr_remove(db->resources, local->path); |
|
1167 continue; |
|
1168 } |
|
1169 } |
|
1170 |
|
1171 if(!ucx_map_get(resources_map, key)) { |
|
1172 // The current LocalResource is in the database but doesn't exist |
|
1173 // in the filesystem anymore. This means the file was deleted |
|
1174 // and should be deleted on server |
|
1175 if(!archive) { |
|
1176 ls_delete = ucx_list_append(ls_delete, local); |
|
1177 } else { |
|
1178 ucx_map_cstr_remove(db->resources, local->path); |
|
1179 } |
|
1180 } |
|
1181 } |
|
1182 |
|
1183 ls_delete = ucx_list_sort(ls_delete, (cmp_func)resource_pathlen_cmp, NULL); |
|
1184 |
|
1185 // |
|
1186 // BEGIN PUSH |
|
1187 // |
|
1188 |
|
1189 // upload changed files |
|
1190 int ret = 0; |
|
1191 int error = 0; |
|
1192 for(UcxList *elm=ls_put;elm && !sync_shutdown;elm=elm->next) { |
|
1193 LocalResource *local_res = elm->data; |
|
1194 |
|
1195 DavResource *res = dav_resource_new(sn, local_res->path); |
|
1196 if(!res) { |
|
1197 print_resource_error(sn, local_res->path); |
|
1198 ret = -1; |
|
1199 sync_error++; |
|
1200 } |
|
1201 |
|
1202 if(local_res->isdirectory) { |
|
1203 dav_exists(res); |
|
1204 if(sn->error == DAV_NOT_FOUND) { |
|
1205 int abort = 0; |
|
1206 // make sure to store tags for newly created cols |
|
1207 local_res->tags_updated = 1; |
|
1208 // create collection |
|
1209 // TODO: show 405 |
|
1210 printf("mkcol: %s\n", local_res->path); |
|
1211 if(sync_mkdir(dir, res, local_res) && sn->error != DAV_METHOD_NOT_ALLOWED) { |
|
1212 print_resource_error(sn, res->path); |
1152 ret = -1; |
1213 ret = -1; |
1153 sync_error++; |
1214 sync_error++; |
1154 } |
1215 error = 1; |
1155 |
1216 abort = 1; |
1156 if(local_res->isdirectory) { |
1217 } |
1157 dav_exists(res); |
1218 |
1158 if(sn->error == DAV_NOT_FOUND) { |
1219 if(dir->tagconfig && local_res->tags_updated && !abort) { |
1159 int abort = 0; |
1220 sync_update_tags(dir, sn, res, local_res); |
1160 // make sure to store tags for newly created cols |
1221 } |
1161 local_res->tags_updated = 1; |
1222 } else if(sn->error != DAV_OK) { |
1162 // create collection |
1223 // dav_exists() failed |
1163 // TODO: show 405 |
1224 print_resource_error(sn, local_res->path); |
1164 printf("mkcol: %s\n", local_res->path); |
1225 ret = -1; |
1165 if(sync_mkdir(dir, res, local_res) && sn->error != DAV_METHOD_NOT_ALLOWED) { |
1226 sync_error++; |
1166 print_resource_error(sn, res->path); |
1227 error = 1; |
1167 ret = -1; |
1228 } |
1168 sync_error++; |
1229 } else { |
1169 error = 1; |
1230 if(cdt && remote_resource_is_changed(sn, dir, db, local_res)) { |
1170 abort = 1; |
1231 printf("conflict: %s\n", local_res->path); |
1171 } |
1232 local_res->last_modified = 0; |
1172 |
1233 local_res->skipped = TRUE; |
1173 if(dir->tagconfig && local_res->tags_updated && !abort) { |
1234 sync_skipped++; |
1174 sync_update_tags(dir, sn, res, local_res); |
1235 } else { |
1175 } |
1236 printf("put: %s\n", local_res->path); |
1176 } else if(sn->error != DAV_OK) { |
1237 if(sync_put_resource(dir, res, local_res, &sync_success)) { |
1177 // dav_exists() failed |
1238 sync_error++; |
1178 print_resource_error(sn, local_res->path); |
1239 print_resource_error(sn, res->path); |
1179 ret = -1; |
1240 ret = -1; |
1180 sync_error++; |
1241 error = 1; |
1181 error = 1; |
1242 } |
1182 } |
1243 } |
1183 } else if(!is_changed) { |
1244 } |
1184 if(dir->tagconfig && local_res->tags_updated) { |
1245 dav_resource_free(res); |
1185 sync_update_tags(dir, sn, res, local_res); |
1246 |
1186 } |
1247 LocalResource *dbres = ucx_map_cstr_remove(db->resources, local_res->path); |
1187 } else { |
1248 ucx_map_cstr_put(db->resources, local_res->path, local_res); |
1188 if(cdt && remote_resource_is_changed(sn, dir, db, local_res)) { |
1249 //if(dbres) local_resource_free(dbres); |
1189 printf("conflict: %s\n", local_res->path); |
1250 } |
1190 local_res->last_modified = 0; |
1251 |
1191 local_res->skipped = TRUE; |
1252 // metadata updates |
1192 sync_skipped++; |
1253 for(UcxList *elm=ls_update;elm && !sync_shutdown;elm=elm->next) { |
1193 } else { |
1254 LocalResource *local_res = elm->data; |
1194 printf("put: %s\n", local_res->path); |
1255 |
1195 if(sync_put_resource(dir, res, local_res, &sync_success)) { |
1256 DavResource *res = dav_resource_new(sn, local_res->path); |
1196 sync_error++; |
1257 |
1197 print_resource_error(sn, res->path); |
1258 if(dir->tagconfig && local_res->tags_updated) { |
1198 ret = -1; |
1259 sync_update_tags(dir, sn, res, local_res); |
1199 error = 1; |
1260 } |
1200 } |
1261 } |
1201 } |
1262 |
1202 } |
|
1203 dav_resource_free(res); |
|
1204 } |
|
1205 } |
|
1206 |
|
1207 // remove every locally available resource from db->resource |
|
1208 // the remaining elements are all deleted files |
|
1209 elm->data = NULL; |
|
1210 if(!error) { |
|
1211 ucx_map_cstr_put(lclres, local_res->path, local_res); |
|
1212 } |
|
1213 |
|
1214 LocalResource *lr = ucx_map_cstr_remove(db->resources, local_res->path); |
|
1215 if(lr) { |
|
1216 local_resource_free(lr); |
|
1217 } |
|
1218 } |
|
1219 |
|
1220 // delete all removed files |
1263 // delete all removed files |
1221 if(ret == 0 && !archive) { |
1264 UcxList *cols = NULL; |
1222 UcxList *cols = NULL; |
1265 UcxList **col_list = &cols; |
1223 |
1266 UcxList *deletelist = ls_delete; |
1224 UcxMapIterator i = ucx_map_iterator(db->resources); |
1267 for(int i=0;i<2;i++) { |
1225 LocalResource *local; |
1268 // the first iteration deletes everything from ls_delete except |
1226 UCX_MAP_FOREACH(key, local, i) { |
1269 // all collections, which are stored in cols |
1227 if (!local->keep && !res_matches_filter(dir, local->path+1)) { |
1270 // in the second run all collections will be deleted |
1228 if(sync_shutdown) { |
1271 for(UcxList *elm=deletelist;elm && !sync_shutdown;elm=elm->next) { |
1229 ucx_map_cstr_put(lclres, local->path, local_resource_copy(local)); |
1272 LocalResource *local = elm->data; |
1230 } else if(sync_delete_remote_resource(dir, sn, local, &sync_delete, &cols)) { |
1273 if(local->keep) { |
1231 ucx_map_cstr_put(lclres, local->path, local_resource_copy(local)); |
1274 continue; |
1232 if(sn->error != DAV_NOT_FOUND) { |
1275 } |
1233 print_resource_error(sn, local->path); |
1276 if(sync_delete_remote_resource(dir, sn, local, &sync_delete, col_list)) { |
1234 sync_error++; |
1277 if(sn->error != DAV_NOT_FOUND) { |
1235 break; |
1278 print_resource_error(sn, local->path); |
1236 } |
1279 sync_error++; |
1237 } |
1280 break; |
1238 } |
1281 } |
1239 } |
1282 } else { |
1240 |
1283 LocalResource *dbres = ucx_map_cstr_remove(db->resources, local->path); |
1241 cols = ucx_list_sort(cols, (cmp_func)resource_pathlen_cmp, NULL); |
1284 //local_resource_free(dbres); |
1242 |
1285 } |
1243 UCX_FOREACH(elm, cols) { |
1286 } |
1244 local = elm->data; |
1287 deletelist = cols; |
1245 if (!local->keep && !res_matches_filter(dir, local->path+1)) { |
1288 col_list = NULL; |
1246 if(sync_shutdown) { |
1289 } |
1247 ucx_map_cstr_put(lclres, local->path, local_resource_copy(local)); |
|
1248 } else if(sync_delete_remote_resource(dir, sn, local, &sync_delete, NULL)) { |
|
1249 ucx_map_cstr_put(lclres, local->path, local_resource_copy(local)); |
|
1250 if(sn->error != DAV_NOT_FOUND) { |
|
1251 print_resource_error(sn, local->path); |
|
1252 sync_error++; |
|
1253 break; |
|
1254 } |
|
1255 } |
|
1256 } |
|
1257 } |
|
1258 |
|
1259 ucx_list_free(cols); |
|
1260 } |
|
1261 ucx_map_free_content(db->resources, (ucx_destructor)local_resource_free); |
|
1262 ucx_map_free(db->resources); |
|
1263 db->resources = lclres; |
|
1264 |
1290 |
1265 // unlock repository |
1291 // unlock repository |
1266 if(locked) { |
1292 if(locked) { |
1267 if(dav_unlock(root)) { |
1293 if(dav_unlock(root)) { |
1268 print_resource_error(sn, "/"); |
1294 print_resource_error(sn, "/"); |