OpenSync  0.22
opensync_changecmds.c
1 /*
2  * libopensync - A synchronization framework
3  * Copyright (C) 2004-2005 Armin Bauer <armin.bauer@opensync.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  */
20 
21 #include "opensync.h"
22 #include "opensync_internals.h"
23 
24 
29 static osync_bool target_fn_fmtnames(const void *data, OSyncObjFormat *fmt)
30 {
31  const char * const *list = data;
32  const char * const *i;
33  for (i = list; *i; i++) {
34  if (!strcmp(fmt->name, *i))
35  /* Found */
36  return TRUE;
37  }
38 
39  /* Not found */
40  return FALSE;
41 }
42 
47 static osync_bool target_fn_simple(const void *data, OSyncObjFormat *fmt)
48 {
49  const OSyncObjFormat *target = data;
50  return target == fmt;
51 }
52 
57 static osync_bool target_fn_fmtname(const void *data, OSyncObjFormat *fmt)
58 {
59  const char *name = data;
60  return !strcmp(name, fmt->name);
61 }
62 
67 static osync_bool target_fn_membersink(const void *data, OSyncObjFormat *fmt)
68 {
69  const OSyncMember *memb = data;
70  GList *i;
71  for (i = memb->format_sinks; i; i = i->next) {
72  OSyncObjFormatSink *sink = i->data;
73  if (sink->format == fmt)
74  return TRUE;
75  }
76 
77  /* Not found */
78  return FALSE;
79 }
80 
87 
98 {
99  g_assert(change);
100  if (!change->has_data)
101  return NULL;
102 
103  OSyncObjFormat *format = osync_change_get_objformat(change);
104  g_assert(format);
105 
106  if (!format->print_func)
107  return g_strndup(change->data, change->size);
108 
109  return format->print_func(change);
110 }
111 
120 {
121  osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, change, error);
122 
123  g_assert(change);
124  if (!change->has_data) {
125  osync_error_set(error, OSYNC_ERROR_GENERIC, "No data set when asking for the timestamp");
126  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
127  return -1;
128  }
129 
130  OSyncObjFormat *format = osync_change_get_objformat(change);
131  g_assert(format);
132 
133  if (!format->revision_func) {
134  osync_error_set(error, OSYNC_ERROR_GENERIC, "No revision function set");
135  osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
136  return -1;
137  }
138 
139  time_t time = format->revision_func(change, error);
140 
141  osync_trace(osync_error_is_set(error) ? TRACE_EXIT_ERROR : TRACE_EXIT, "%s: %s, %i", __func__, osync_error_print(error), time);
142  return time;
143 }
144 
158 {
159  osync_trace(TRACE_ENTRY, "osync_change_compare_data(%p, %p)", leftchange, rightchange);
160 
161  g_assert(rightchange);
162  g_assert(leftchange);
163 
164  OSyncError *error = NULL;
165  if (!osync_change_convert_to_common(leftchange, &error)) {
166  osync_trace(TRACE_INTERNAL, "osync_change_compare_data: %s", osync_error_print(&error));
167  osync_error_free(&error);
168  osync_trace(TRACE_EXIT, "osync_change_compare_data: MISMATCH: Could not convert leftchange to common format");
169  return CONV_DATA_MISMATCH;
170  }
171  if (!osync_change_convert_to_common(rightchange, &error)) {
172  osync_trace(TRACE_INTERNAL, "osync_change_compare_data: %s", osync_error_print(&error));
173  osync_error_free(&error);
174  osync_trace(TRACE_EXIT, "osync_change_compare_data: MISMATCH: Could not convert rightchange to common format");
175  return CONV_DATA_MISMATCH;
176  }
177 
178  if (!(rightchange->data == leftchange->data)) {
179  if (!(osync_change_get_objtype(leftchange) == osync_change_get_objtype(rightchange))) {
180  osync_trace(TRACE_EXIT, "osync_change_compare_data: MISMATCH: Objtypes do not match");
181  return CONV_DATA_MISMATCH;
182  }
183  if (leftchange->format != rightchange->format) {
184  osync_trace(TRACE_EXIT, "osync_change_compare_data: MISMATCH: Objformats do not match");
185  return CONV_DATA_MISMATCH;
186  }
187  if (!rightchange->data || !leftchange->data) {
188  osync_trace(TRACE_EXIT, "osync_change_compare_data: MISMATCH: One change has no data");
189  return CONV_DATA_MISMATCH;
190  }
191  OSyncObjFormat *format = osync_change_get_objformat(leftchange);
192  g_assert(format);
193 
194  OSyncConvCmpResult ret = format->cmp_func(leftchange, rightchange);
195  osync_trace(TRACE_EXIT, "osync_change_compare_data: %i", ret);
196  return ret;
197  } else {
198  osync_trace(TRACE_EXIT, "osync_change_compare_data: SAME: OK. data point to same memory");
199  return CONV_DATA_SAME;
200  }
201 }
202 
218 {
219  osync_trace(TRACE_ENTRY, "osync_change_compare(%p, %p)", leftchange, rightchange);
220 
221  g_assert(rightchange);
222  g_assert(leftchange);
223 
224  OSyncError *error = NULL;
225  if (!osync_change_convert_to_common(leftchange, &error)) {
226  osync_trace(TRACE_INTERNAL, "osync_change_compare: %s", osync_error_print(&error));
227  osync_error_free(&error);
228  osync_trace(TRACE_EXIT, "osync_change_compare: MISMATCH: Could not convert leftchange to common format");
229  return CONV_DATA_MISMATCH;
230  }
231  if (!osync_change_convert_to_common(rightchange, &error)) {
232  osync_trace(TRACE_INTERNAL, "osync_change_compare: %s", osync_error_print(&error));
233  osync_error_free(&error);
234  osync_trace(TRACE_EXIT, "osync_change_compare: MISMATCH: Could not convert leftchange to common format");
235  return CONV_DATA_MISMATCH;
236  }
237 
238  if (rightchange->changetype == leftchange->changetype) {
239  OSyncConvCmpResult ret = osync_change_compare_data(leftchange, rightchange);
240  osync_trace(TRACE_EXIT, "osync_change_compare: Compare data: %i", ret);
241  return ret;
242  } else {
243  osync_trace(TRACE_EXIT, "osync_change_compare: MISMATCH: Change types do not match");
244  return CONV_DATA_MISMATCH;
245  }
246 }
247 
256 osync_bool osync_change_copy_data(OSyncChange *source, OSyncChange *target, OSyncError **error)
257 {
258  osync_trace(TRACE_ENTRY, "osync_change_copy_data(%p, %p, %p)", source, target, error);
259 
260  OSyncObjFormat *format = NULL;
261  format = source->format;
262  if (!format)
263  format = target->format;
264 
265  if (target->data)
266  osync_change_free_data(target);
267 
268  if (!source->data) {
269  target->data = NULL;
270  target->size = 0;
271  osync_trace(TRACE_EXIT, "%s: Source had not data", __func__);
272  return TRUE;
273  }
274 
275  if (!format || !format->copy_func) {
276  osync_trace(TRACE_INTERNAL, "We cannot copy the change, falling back to memcpy");
277  target->data = g_malloc0(sizeof(char) * (source->size + 1));
278  memcpy(target->data, source->data, source->size);
279 
280  /* Make sure that its null terminated */
281  target->data[source->size] = 0;
282  target->size = source->size;
283  } else {
284  if (!format->copy_func(source->data, source->size, &(target->data), &(target->size))) {
285  osync_error_set(error, OSYNC_ERROR_GENERIC, "Something went wrong during copying");
286  osync_trace(TRACE_EXIT_ERROR, "osync_change_copy_data: %s", osync_error_print(error));
287  return FALSE;
288  }
289  }
290 
291  osync_trace(TRACE_EXIT, "osync_change_copy_data");
292  return TRUE;
293 }
294 
303 {
304  osync_trace(TRACE_ENTRY, "osync_change_copy(%p, %p)", source, error);
305  g_assert(source);
306 
307  OSyncChange *newchange = osync_change_new();
308  newchange->uid = g_strdup(source->uid);
309  newchange->hash = g_strdup(source->hash);
310 
311  newchange->has_data = source->has_data;
312  newchange->changetype = source->changetype;
313  newchange->format = osync_change_get_objformat(source);
314  newchange->objtype = osync_change_get_objtype(source);
315  newchange->sourceobjtype = g_strdup(osync_change_get_objtype(source)->name);
316  newchange->changes_db = source->changes_db;
317  newchange->member = source->member;
318 
319  if (!osync_change_copy_data(source, newchange, error)) {
320  osync_change_free(newchange);
321  osync_trace(TRACE_EXIT_ERROR, "osync_change_copy: %s", osync_error_print(error));
322  return NULL;
323  }
324 
325  osync_trace(TRACE_EXIT, "osync_change_copy: %p", newchange);
326  return newchange;
327 }
328 
339 {
340  g_assert(change);
341  OSyncObjFormat *format = osync_change_get_objformat(change);
342  osync_debug("OSCONV", 3, "Duplicating change %s with format %s\n", change->uid, format->name);
343  if (!format || !format->duplicate_func)
344  return FALSE;
345  format->duplicate_func(change);
346  return TRUE;
347 }
348 
363 osync_bool osync_change_convert_extension(OSyncFormatEnv *env, OSyncChange *change, OSyncObjFormat *targetformat, const char *extension_name, OSyncError **error)
364 {
365  osync_trace(TRACE_ENTRY, "osync_change_convert(%p, %p, %p:%s, %s, %p)", env, change, targetformat, targetformat ? targetformat->name : "NONE", extension_name, error);
366  if (osync_conv_convert_fn(env, change, target_fn_simple, targetformat, extension_name, error)) {
367  osync_trace(TRACE_EXIT, "osync_change_convert: TRUE");
368  return TRUE;
369  } else {
370  osync_trace(TRACE_EXIT_ERROR, "osync_change_convert: %s", osync_error_print(error));
371  return FALSE;
372  }
373 }
374 
387 osync_bool osync_change_convert(OSyncFormatEnv *env, OSyncChange *change, OSyncObjFormat *targetformat, OSyncError **error)
388 {
389  return osync_change_convert_extension(env, change, targetformat, NULL, error);
390 }
391 
400 {
401  osync_trace(TRACE_ENTRY, "osync_change_convert_to_common(%p, %p)", change, error);
402 
403  if (!osync_change_get_objtype(change)) {
404  osync_error_set(error, OSYNC_ERROR_GENERIC, "The change has no objtype");
405  osync_trace(TRACE_EXIT_ERROR, "osync_change_convert_to_common: %s", osync_error_print(error));
406  return FALSE;
407  }
408  OSyncFormatEnv *env = osync_change_get_objtype(change)->env;
409 
410  if (!osync_change_get_objtype(change)->common_format) {
411  osync_trace(TRACE_EXIT, "osync_change_convert_to_common: No common format set");
412  return TRUE;
413  }
414 
415  osync_trace(TRACE_INTERNAL, "Converting from %s to %s", osync_change_get_objformat(change)->name, osync_change_get_objtype(change)->common_format->name);
416 
417  if (osync_change_convert(env, change, osync_change_get_objtype(change)->common_format, error)) {
418  osync_trace(TRACE_EXIT, "osync_change_convert_to_common: TRUE");
419  return TRUE;
420  } else {
421  osync_trace(TRACE_EXIT_ERROR, "osync_change_convert_to_common: %s", osync_error_print(error));
422  return FALSE;
423  }
424 }
425 
438 osync_bool osync_change_convert_fmtname(OSyncFormatEnv *env, OSyncChange *change, const char *targetname, OSyncError **error)
439 {
440  return osync_conv_convert_fn(env, change, target_fn_fmtname, targetname, NULL, error);
441 }
442 
455 osync_bool osync_change_convert_fmtnames(OSyncFormatEnv *env, OSyncChange *change, const char **targetnames, OSyncError **error)
456 {
457  return osync_conv_convert_fn(env, change, target_fn_fmtnames, targetnames, NULL, error);
458 }
459 
471 {
472  if (!osync_member_require_sink_info(member, error))
473  return FALSE;
474 
475  return osync_conv_convert_fn(env, change, target_fn_membersink, member, member->extension, error);
476 }
477 
490 {
491  OSyncObjFormat *format = NULL;
492  if (!(format = osync_change_detect_objformat(env, change, error)))
493  return NULL;
494  return format->objtype;
495 }
496 
510 {
511  OSyncObjFormat *format = NULL;
512  if (!(format = osync_change_detect_objformat_full(env, change, error)))
513  return NULL;
514  return format->objtype;
515 }
516 
529 {
530  osync_trace(TRACE_ENTRY, "osync_change_detect_objformat(%p, %p, %p)", env, change, error);
531  if (!change->has_data) {
532  osync_error_set(error, OSYNC_ERROR_GENERIC, "The change has no data");
533  osync_trace(TRACE_EXIT_ERROR, "osync_change_detect_objformat: %s", osync_error_print(error));
534  return NULL;
535  }
536 
537  //Run all datadetectors for our source type
538  GList *d = NULL;
539  for (d = env->converters; d; d = d->next) {
540  OSyncFormatConverter *converter = d->data;
541  osync_trace(TRACE_INTERNAL, "running detector %s for format %s\n", converter->source_format->name, osync_change_get_objformat(change)->name);
542  if (!strcmp(converter->source_format->name, osync_change_get_objformat(change)->name)) {
543  if (converter->detect_func && converter->detect_func(env, change->data, change->size)) {
544  osync_trace(TRACE_EXIT, "osync_change_detect_objformat: %p:%s", converter->target_format, converter->target_format->name);
545  return converter->target_format;
546  }
547  }
548  }
549 
550  osync_error_set(error, OSYNC_ERROR_GENERIC, "None of the detectors was able to recognize this data");
551  osync_trace(TRACE_EXIT_ERROR, "osync_change_detect_objformat: %s", osync_error_print(error));
552  return NULL;
553 }
554 
568 {
569  osync_trace(TRACE_ENTRY, "osync_change_detect_objformat_full(%p, %p, %p)", env, change, error);
570  if (!change->has_data) {
571  osync_error_set(error, OSYNC_ERROR_GENERIC, "The change has no data");
572  osync_trace(TRACE_EXIT_ERROR, "osync_change_detect_objformat: %s", osync_error_print(error));
573  return NULL;
574  }
575  OSyncChange *new_change = change;
576 
577  //Try to decap the change as far as possible
578  while (1) {
579  GList *d = NULL;
580  for (d = env->converters; d; d = d->next) {
581  OSyncFormatConverter *converter = d->data;
582  if (!strcmp(converter->source_format->name, osync_change_get_objformat(change)->name) && converter->type == CONVERTER_DECAP) {
583  osync_bool free_output = FALSE;
584  if (!(new_change = osync_converter_invoke_decap(converter, new_change, &free_output))) {
585  osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to decap the change");
586  osync_trace(TRACE_EXIT_ERROR, "osync_change_detect_objformat_full: %s", osync_error_print(error));
587  return NULL;
588  }
589  continue;
590  }
591  }
592  break;
593  }
594 
595  OSyncObjFormat *ret = osync_change_detect_objformat(env, new_change, error);
596  if (!ret)
597  osync_trace(TRACE_EXIT_ERROR, "osync_change_detect_objformat_full: %s", osync_error_print(error));
598  else
599  osync_trace(TRACE_EXIT, "osync_change_detect_objformat_full: %p:%s", ret, ret->name);
600  return ret;
601 }
602