Call folder/get_contents for updated folders in device/get_changes

- it is not enough to rely on the parent information of updated files
   because that misses files and folders that were completely removed
   (even from trash)
This commit is contained in:
josch
2014-09-27 23:04:45 +02:00
parent 53981a2229
commit 690091721a
2 changed files with 89 additions and 16 deletions

View File

@@ -913,9 +913,13 @@ static int folder_tree_rebuild_helper(folder_tree * tree, mfconn * conn,
mffile **file_result; mffile **file_result;
h_entry *entry; h_entry *entry;
int i; int i;
const char *key;
bool found;
/* /*
* free the old children array of this folder * free the old children array of this folder to make sure that any
* entries that do not exist on the remote are removed locally
*
* we don't free the children it references because they might be * we don't free the children it references because they might be
* referenced by someone else * referenced by someone else
*/ */
@@ -941,11 +945,36 @@ static int folder_tree_rebuild_helper(folder_tree * tree, mfconn * conn,
} }
for (i = 0; folder_result[i] != NULL; i++) { for (i = 0; folder_result[i] != NULL; i++) {
if (folder_get_key(folder_result[i]) == NULL) { key = folder_get_key(folder_result[i]);
if (key == NULL) {
fprintf(stderr, "folder_get_key returned NULL\n"); fprintf(stderr, "folder_get_key returned NULL\n");
folder_free(folder_result[i]); folder_free(folder_result[i]);
} }
/* if this folder existed before, then folder_tree_add_folder will not
* add it to this folder's children. Thus we do this now */
found = false;
if (folder_tree_lookup_key(tree, key) != NULL) {
curr_entry->num_children++;
curr_entry->children =
(h_entry **) realloc(curr_entry->children,
curr_entry->num_children *
sizeof(h_entry *));
if (curr_entry->children == NULL) {
fprintf(stderr, "realloc failed\n");
return -1;
}
found = true;
}
entry = folder_tree_add_folder(tree, folder_result[i], curr_entry); entry = folder_tree_add_folder(tree, folder_result[i], curr_entry);
/* we are using a new variable "found" here because after doing a
* folder_tree_add_folder, folder_tree_lookup_key will always succeed
*
* if this entry was not present before, then folder_tree_add_folder
* already added it to this folder's children
*/
if (found) {
curr_entry->children[curr_entry->num_children - 1] = entry;
}
/* recurse */ /* recurse */
if (recurse) if (recurse)
folder_tree_rebuild_helper(tree, conn, entry, true); folder_tree_rebuild_helper(tree, conn, entry, true);
@@ -971,11 +1000,36 @@ static int folder_tree_rebuild_helper(folder_tree * tree, mfconn * conn,
} }
for (i = 0; file_result[i] != NULL; i++) { for (i = 0; file_result[i] != NULL; i++) {
if (file_get_key(file_result[i]) == NULL) { key = file_get_key(file_result[i]);
if (key == NULL) {
fprintf(stderr, "file_get_key returned NULL\n"); fprintf(stderr, "file_get_key returned NULL\n");
file_free(file_result[i]); file_free(file_result[i]);
} }
/* if this folder existed before, then folder_tree_add_folder will not
* add it to this folder's children. Thus we do this now */
found = false;
if (folder_tree_lookup_key(tree, key) != NULL) {
curr_entry->num_children++;
curr_entry->children =
(h_entry **) realloc(curr_entry->children,
curr_entry->num_children *
sizeof(h_entry *));
if (curr_entry->children == NULL) {
fprintf(stderr, "realloc failed\n");
return -1;
}
found = true;
}
entry = folder_tree_add_file(tree, file_result[i], curr_entry); entry = folder_tree_add_file(tree, file_result[i], curr_entry);
/* we are using a new variable "found" here because after doing a
* folder_tree_add_folder, folder_tree_lookup_key will always succeed
*
* if this entry was not present before, then folder_tree_add_folder
* already added it to this folder's children
*/
if (found) {
curr_entry->children[curr_entry->num_children - 1] = entry;
}
file_free(file_result[i]); file_free(file_result[i]);
} }
free(file_result); free(file_result);
@@ -1072,6 +1126,7 @@ void folder_tree_update(folder_tree * tree, mfconn * conn)
uint64_t i; uint64_t i;
struct mfconn_device_change *changes; struct mfconn_device_change *changes;
int retval; int retval;
h_entry *tmp_entry;
mfconn_api_device_get_status(conn, &revision_remote); mfconn_api_device_get_status(conn, &revision_remote);
mfconn_update_secret_key(conn); mfconn_update_secret_key(conn);
@@ -1082,11 +1137,26 @@ void folder_tree_update(folder_tree * tree, mfconn * conn)
} }
/* /*
* root never shows up in device_get_changes but since we rely on the * we maintain the information of each entries parent but that does not
* parent information of files and folders, we do not manually retrieve * mean that we can rely on it when fetching updates via
* its content * device/get_changes. If a remote object has been permanently removed
* (trash was emptied) then it will not show up in the results of
* device/get_changes and thus a remote file will vanish without that file
* showing up in the device/get_changes output. The only way to clean up
* those removed files is to use folder/get_content for all folders that
* changed.
*/ */
/*
* we have to manually check the root because it never shows up in the
* results from device_get_changes
*
* we don't need to be recursive here because we rely on
* device/get_changes reporting all changes to its children
*/
folder_tree_rebuild_helper(tree, conn, &(tree->root), false);
/* /*
* changes have to be applied in the right order but the result of * changes have to be applied in the right order but the result of
* mfconn_api_device_get_changes is already sorted by revision * mfconn_api_device_get_changes is already sorted by revision
@@ -1100,12 +1170,6 @@ void folder_tree_update(folder_tree * tree, mfconn * conn)
return; return;
} }
/*
* TODO: before calling remote functions here, check if the revision of
* the local object is lower than the one of the reported change
*
* TODO: only use the latest revision of the same file-/folderkey
*/
for (i = 0; changes[i].change != MFCONN_DEVICE_CHANGE_END; i++) { for (i = 0; changes[i].change != MFCONN_DEVICE_CHANGE_END; i++) {
switch (changes[i].change) { switch (changes[i].change) {
case MFCONN_DEVICE_CHANGE_DELETED_FOLDER: case MFCONN_DEVICE_CHANGE_DELETED_FOLDER:
@@ -1120,10 +1184,19 @@ void folder_tree_update(folder_tree * tree, mfconn * conn)
if (strcmp(changes[i].parent, "trash") == 0) if (strcmp(changes[i].parent, "trash") == 0)
continue; continue;
/* if a folder has been updated then its name or location /* if a folder has been updated then its name or location
* might have changed */ * might have changed... */
folder_tree_update_folder_info(tree, conn, changes[i].key); folder_tree_update_folder_info(tree, conn, changes[i].key);
/* its content might also have changed but we use the changes /* ...or its contents changed
* to files to update it */ * the last call made sure that an entry for this folder has
* been added locally, so the following should succeed */
tmp_entry = folder_tree_lookup_key(tree, changes[i].key);
if (tmp_entry == NULL) {
fprintf(stderr, "folder_tree_lookup_key failed\n");
continue;
}
/* we don't need to be recursive here because we rely on
* device/get_changes reporting all changes to its children */
folder_tree_rebuild_helper(tree, conn, tmp_entry, false);
break; break;
case MFCONN_DEVICE_CHANGE_UPDATED_FILE: case MFCONN_DEVICE_CHANGE_UPDATED_FILE:
/* ignore files updated in trash */ /* ignore files updated in trash */

View File

@@ -219,7 +219,7 @@ int main(int argc, char *argv[])
//folder_tree_housekeep(tree); //folder_tree_housekeep(tree);
//folder_tree_debug(tree, NULL, 0); folder_tree_debug(tree, NULL, 0);
return fuse_main(args.argc, args.argv, &mediafirefs_oper, NULL); return fuse_main(args.argc, args.argv, &mediafirefs_oper, NULL);
} }