dav/sync.c

changeset 501
868da3f76267
parent 497
411bd1098175
child 502
a23fedac340c
equal deleted inserted replaced
500:0fe1514667e6 501:868da3f76267
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, "/");
1281 // cleanup 1307 // cleanup
1282 if(!locked && locktokenfile) { 1308 if(!locked && locktokenfile) {
1283 remove(locktokenfile); 1309 remove(locktokenfile);
1284 } 1310 }
1285 1311
1312 //ucx_map_free_content(db->resources, (ucx_destructor)local_resource_free);
1313 //ucx_map_free(db->resources);
1314
1286 dav_session_destroy(sn); 1315 dav_session_destroy(sn);
1287 while(resources) {
1288 UcxList *next = resources->next;
1289 if(resources->data) {
1290 local_resource_free(resources->data);
1291 }
1292 free(resources);
1293 resources = next;
1294 }
1295 1316
1296 // Report 1317 // Report
1297 if(ret != -2) { 1318 if(ret != -2) {
1298 char *str_success = sync_success == 1 ? "file" : "files"; 1319 char *str_success = sync_success == 1 ? "file" : "files";
1299 char *str_delete = sync_delete == 1 ? "file" : "files"; 1320 char *str_delete = sync_delete == 1 ? "file" : "files";

mercurial