From 8c67dd78e1894dd526eb87d5eed5c9300201f29b Mon Sep 17 00:00:00 2001
From: Nikias Bassen <nikias@gmx.li>
Date: Tue, 25 Aug 2009 14:24:38 +0200
Subject: [PATCH 09/14] Write iTunesDB and sqlitedb's to temporary path, then copy them.

---
 src/itdb_itunesdb.c |  189 +++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 170 insertions(+), 19 deletions(-)

diff --git a/src/itdb_itunesdb.c b/src/itdb_itunesdb.c
index 3fdf21e..5b4b260 100644
--- a/src/itdb_itunesdb.c
+++ b/src/itdb_itunesdb.c
@@ -116,6 +116,7 @@
 #include <glib-object.h>
 #include <glib/gi18n-lib.h>
 #include <glib/gstdio.h>
+#include <gio/gio.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/types.h>
@@ -6350,6 +6351,118 @@ err:
     return result;
 }
 
+static gboolean itdb_copy_itdb_files (const gchar *itunespath, const gchar *from_dir, GError **error)
+{
+    gboolean result = FALSE;
+    gchar *itlpdir;
+    GFile *gf;
+    gboolean exists;
+    GFileEnumerator *direnum = NULL;
+    GFileInfo *info = NULL;
+    int cpcnt = 0;
+
+    g_return_val_if_fail (itunespath, result);
+    g_return_val_if_fail (from_dir, result);
+
+    itlpdir = g_build_filename (itunespath, "iTunes Library.itlp", NULL);
+    gf = g_file_new_for_path (itlpdir);
+    exists = g_file_query_exists (gf, NULL);
+    if (exists && (g_file_query_file_type (gf, G_FILE_QUERY_INFO_NONE, NULL) != G_FILE_TYPE_DIRECTORY)) {
+	if (!g_file_delete (gf, NULL, error)) {
+	    printf("error on file_delete\n");
+	    goto leave;
+	}
+	exists = FALSE;
+    }
+    if (!exists && !g_file_make_directory (gf, NULL, error)) {
+	printf("error on make_directory\n");
+	goto leave;
+    }
+    g_object_unref (gf);
+
+    gf = g_file_new_for_path (from_dir);
+    direnum = g_file_enumerate_children (gf, "standard::*", G_FILE_QUERY_INFO_NONE, NULL, error);
+    if (!direnum) {
+	printf("error on g_file_enumerate_children\n");
+	goto leave;
+    }
+
+    while ((info = g_file_enumerator_next_file (direnum, NULL, error))) {
+	const char *fname = g_file_info_get_name (info);
+	gchar *srcname = g_build_filename (from_dir, fname, NULL);
+	gchar *dstname = g_build_filename (itlpdir, fname, NULL);
+
+	if (!itdb_cp (srcname, dstname, error)) {
+	    g_free (dstname);
+	    g_free (srcname);
+	    g_object_unref (info);
+	    break;
+	} else {
+	    cpcnt++;
+	}
+
+	g_free (dstname);
+	g_free (srcname);
+	g_object_unref (info);
+    }
+    g_file_enumerator_close (direnum, NULL, NULL);
+
+leave:
+    if (*error) {
+	fprintf(stderr, "%s: ERROR: %s\n", __func__, (*error)->message);
+    }
+    g_object_unref (direnum);
+    g_object_unref (gf);
+    g_free (itlpdir);
+
+    if (cpcnt > 0) {
+	printf("%s: %d files transferred.\n", __func__, cpcnt);
+	result = TRUE;
+    }
+
+    return result;
+}
+
+static void rmdir_recursive (const gchar *path)
+{
+    GFile *gf;
+    GFileEnumerator *direnum;
+    GError *error = NULL;
+    GFileInfo *info = NULL;
+
+    g_return_if_fail(path);
+
+    gf = g_file_new_for_path (path);
+    direnum = g_file_enumerate_children (gf, "standard::*", G_FILE_QUERY_INFO_NONE, NULL, &error);
+    if (!direnum) {
+	return;
+    }
+    
+    while ((info = g_file_enumerator_next_file (direnum, NULL, &error))) {
+	GFile *nf;
+	gchar *fullname = g_build_filename (path, g_file_info_get_name (info), NULL);
+	if (g_file_info_get_file_type(info) == G_FILE_TYPE_DIRECTORY) {
+	    rmdir_recursive (fullname);
+	} else {
+		nf = g_file_new_for_path (fullname);
+		if (!g_file_delete (nf, NULL, &error)) {
+		    fprintf(stderr, "Error deleting '%s': %s\n", fullname, error->message);
+		}
+		g_object_unref (nf);
+	}
+	g_free (fullname);
+	g_object_unref (info);
+    }
+    g_file_enumerator_close (direnum, NULL, NULL);
+    g_object_unref (direnum);
+
+    if (!g_file_delete (gf, NULL, &error)) {
+	    fprintf(stderr, "Error deleting '%s': %s\n", path, error->message);
+    }
+
+    g_object_unref (gf);
+}
+
 /**
  * itdb_write:
  * @itdb:   the #Itdb_iTunesDB to write to disk
@@ -6368,6 +6481,9 @@ gboolean itdb_write (Itdb_iTunesDB *itdb, GError **error)
 {
     gchar *itunes_filename, *itunes_path;
     gboolean result = FALSE;
+    gchar *tmpdir;
+    gchar *tmpdb = NULL;
+    GFile *gf;
 #ifdef HAVE_LIBIPHONE
     gchar *uuid = NULL;
     itdbprep_t prepdata = NULL;
@@ -6398,40 +6514,64 @@ gboolean itdb_write (Itdb_iTunesDB *itdb, GError **error)
 	itunes_filename = g_build_filename (itunes_path, "iTunesDB", NULL);
     }
 
-#ifdef HAVE_LIBIPHONE
+    tmpdir = g_build_path (g_get_tmp_dir(), tmpnam(NULL), NULL);
+    gf = g_file_new_for_path (tmpdir);
+    if (!g_file_make_directory(gf, NULL, error)) {
+	fprintf(stderr, "Could not create temporary dir '%s'\n", tmpdir);
+	result = FALSE;
+	goto leave;
+    }
+
+    tmpdb = g_build_filename (tmpdir, "iTunesDB.tmp", NULL);
+    result = itdb_write_file (itdb, tmpdb, error);
+    if (!result) {
+	goto leave_cleanup;
+    }
+
     /* don't free uuid! it's just a pointer that'll be freed elsewhere */
     uuid = itdb_device_get_uuid(itdb->device);
     if (!uuid) {
-	fprintf(stderr, "Couldn't find get device UUID itdbprep processing won't work!");
-    } else {
-	if (itdbprep_start_sync(uuid, &prepdata) != 0) {
-	    fprintf(stderr, "ERROR: Could not start sync!\n");
-	}
+	fprintf(stderr, "ERROR: Couldn't get device UUID. itdbprep processing won't work!");
+	result = FALSE;
+	goto leave_cleanup;
     }
-#endif
 
-    result = itdb_write_file (itdb, itunes_filename, error);
-
-    if (result != FALSE) {
-	gchar *itlpdir;
-	itlpdir = g_build_filename (itunes_path, "iTunes Library.itlp", NULL);
-	if (itdbprep_generate_itdbs(itdb, itlpdir, uuid) != 0) {
-	    fprintf(stderr, "ERROR: There was an error while generating the itdb sqlite database files.\n");
-	}
-	g_free (itlpdir);
+    if ((itdb->version >= 0x28)
+	    && itdbprep_generate_itdbs(itdb, tmpdir, uuid) != 0)
+    {
+	fprintf(stderr, "ERROR: There was an error while generating the itdb sqlite database files.\n");
+	result = FALSE;
+	goto leave_cleanup;
     }
 
-    g_free (itunes_filename);
-    g_free (itunes_path);
+    /* start copying */
 
+#ifdef HAVE_LIBIPHONE
+    if (itdbprep_start_sync(uuid, &prepdata) != 0) {
+	fprintf(stderr, "ERROR: Could not start sync!\n");
+    }
+#endif
+
+    result = itdb_cp (tmpdb, itunes_filename, error);
     if (result != FALSE)
     {
+	g_free (itdb->filename);
+	itdb->filename = g_strdup (itunes_filename);
+
+	/* copy *.itdb files */
+	if (itdb->version >= 0x28) {
+	    if (!itdb_copy_itdb_files (itunes_path, tmpdir, error)) {
+		fprintf(stderr, "Error copying itdb files!\n");
+	    }
+	}
+
+
 	/* Write SysInfo file if it has changed */
 	if (itdb->device->sysinfo_changed)
 	{
 	    itdb_device_write_sysinfo (itdb->device, error);
 	}
-	result = itdb_rename_files (itdb_get_mountpoint (itdb), error);
+	/*result = itdb_rename_files (itdb_get_mountpoint (itdb), error);*/
     }
 
     /* make sure all buffers are flushed as some people tend to
@@ -6444,6 +6584,17 @@ gboolean itdb_write (Itdb_iTunesDB *itdb, GError **error)
     }
 #endif
 
+leave_cleanup:
+    /* delete all files in tmpdir, this will also delete tmpdir itself */
+    rmdir_recursive(tmpdir);
+
+leave:
+    g_object_unref (gf);
+    g_free (itunes_filename);
+    g_free (itunes_path);
+    g_free (tmpdir);
+    g_free (tmpdb);
+
     return result;
 }
 
-- 
1.6.4.4

