/* * Recursively check fs tree rooted at @dir_id. This function returns when * all non-existent or invalid objects have been put into data->fetch_objs. */ static void check_seafdir (CcnetProcessor *processor, const char *dir_id) { SeafileGetfsProc *proc = (SeafileGetfsProc *)processor; USE_PRIV; SeafDir *dir = NULL; GList *ptr; SeafDirent *dent; if (!seaf_fs_manager_object_exists(seaf->fs_mgr, dir_id)) { priv->fetch_objs = g_list_prepend (priv->fetch_objs, g_strdup(dir_id)); return; } dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr, dir_id); if (!dir) { /* corrupt dir object */ priv->fetch_objs = g_list_prepend (priv->fetch_objs, g_strdup(dir_id)); return; } for (ptr = dir->entries; ptr; ptr = ptr->next) { dent = ptr->data; /* Don't check objects that have been checked before. */ if (g_hash_table_lookup (priv->fs_objects, dent->id)) continue; g_hash_table_insert (priv->fs_objects, g_strdup(dent->id), (gpointer)1); if (!seaf_fs_manager_object_exists(seaf->fs_mgr, dent->id)) { priv->fetch_objs = g_list_prepend (priv->fetch_objs, g_strdup(dent->id)); continue; } if (S_ISDIR(dent->mode)) { check_seafdir (processor, dent->id); } else if (S_ISREG (dent->mode) && proc->tx_task->is_clone) { /* Only check seafile object integrity when clone. * This is for the purpose of recovery. * In ordinary sync, checking every file object's integrity would * take too much CPU time. */ gboolean ok; gboolean err = FALSE; ok = seaf_fs_manager_verify_seafile (seaf->fs_mgr, dent->id, TRUE, &err); if (!ok && !err) { seaf_warning ("File object %.8s is corrupt, recover from server.\n", dent->id); priv->fetch_objs = g_list_prepend (priv->fetch_objs, g_strdup(dent->id)); } } } seaf_dir_free (dir); }
static int check_object (CcnetProcessor *processor) { USE_PRIV; char *obj_id; SeafDir *dir; static int i = 0; request_object_batch_begin(priv); /* process inspect queue */ /* Note: All files in a directory must be checked in an iteration, * so we may send out more items than REQUEST_THRESHOLD */ while (g_hash_table_size (priv->fs_objects) < MAX_NUM_UNREVD) { obj_id = (char *) g_queue_pop_head (priv->inspect_queue); if (obj_id == NULL) break; if (!seaf_fs_manager_object_exists(seaf->fs_mgr, obj_id)) { request_object_batch (processor, priv, obj_id); } else { dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr, obj_id); if (!dir) { /* corrupt dir object */ request_object_batch (processor, priv, obj_id); } else { check_seafdir(processor, dir); seaf_dir_free (dir); } } g_free (obj_id); /* free the memory */ } request_object_batch_flush (processor, priv); /* check end condition */ if (i%10 == 0) seaf_debug ("[getfs] pending objects num: %d\n", priv->pending_objects); ++i; if (priv->pending_objects == 0 && g_queue_is_empty(priv->inspect_queue)) { ccnet_processor_send_update (processor, SC_END, SS_END, NULL, 0); ccnet_processor_done (processor, TRUE); return FALSE; } else return TRUE; }
static void check_seafdir (CcnetProcessor *processor, SeafDir *dir) { USE_PRIV; GList *ptr; SeafDirent *dent; for (ptr = dir->entries; ptr; ptr = ptr->next) { dent = ptr->data; if (!seaf_fs_manager_object_exists(seaf->fs_mgr, dent->id)) { request_object_batch (processor, priv, dent->id); continue; } if (S_ISDIR(dent->mode)) { g_queue_push_tail (priv->inspect_queue, g_strdup(dent->id)); } /* TODO: check seafile object integrity. */ } }
static gboolean fsck_verify_seafobj (const char *store_id, int version, const char *obj_id, gboolean *io_error, VerifyType type, gboolean repair) { gboolean valid = TRUE; valid = seaf_fs_manager_object_exists (seaf->fs_mgr, store_id, version, obj_id); if (!valid) { if (type == VERIFY_FILE) { seaf_message ("File %s is missing.\n", obj_id); } else if (type == VERIFY_DIR) { seaf_message ("Dir %s is missing.\n", obj_id); } return valid; } if (type == VERIFY_FILE) { valid = seaf_fs_manager_verify_seafile (seaf->fs_mgr, store_id, version, obj_id, TRUE, io_error); if (!valid && !*io_error && repair) { seaf_message ("File %s is corrupted, remove it.\n", obj_id); seaf_fs_manager_delete_object (seaf->fs_mgr, store_id, version, obj_id); } } else if (type == VERIFY_DIR) { valid = seaf_fs_manager_verify_seafdir (seaf->fs_mgr, store_id, version, obj_id, TRUE, io_error); if (!valid && !*io_error && repair) { seaf_message ("Dir %s is corrupted, remove it.\n", obj_id); seaf_fs_manager_delete_object (seaf->fs_mgr, store_id, version, obj_id); } } return valid; }
int commit_trees_cb (const char *repo_id, int version, const char *worktree, struct cache_tree *it, struct cache_entry **cache, int entries, const char *base, int baselen) { SeafDir *seaf_dir; GList *dirents = NULL, *ptr; int i; for (i = 0; i < entries; i++) { SeafDirent *seaf_dent; char *name; struct cache_entry *ce = cache[i]; struct cache_tree_sub *sub; const char *path, *slash; int pathlen, entlen; const unsigned char *sha1; char hex[41]; unsigned mode; guint64 mtime; gint64 size; char *modifier; if (ce->ce_flags & CE_REMOVE) continue; /* entry being removed */ path = ce->name; pathlen = ce_namelen(ce); if (pathlen <= baselen || memcmp(base, path, baselen)) break; /* at the end of this level */ slash = strchr(path + baselen, '/'); if (slash) { entlen = slash - (path + baselen); sub = cache_tree_find_subtree(it, path + baselen, entlen, 0); g_return_val_if_fail (sub != NULL, -1); /* Skip cache entries in the sub level. */ i += sub->cache_tree->entry_count - 1; sha1 = sub->cache_tree->sha1; mtime = sub->cache_tree->mtime; mode = S_IFDIR; name = g_strndup(path + baselen, entlen); rawdata_to_hex (sha1, hex, 20); seaf_dent = seaf_dirent_new (dir_version_from_repo_version(version), hex, mode, name, mtime, NULL, -1); g_free(name); dirents = g_list_prepend (dirents, seaf_dent); } else { sha1 = ce->sha1; mode = ce->ce_mode; mtime = ce->ce_mtime.sec; size = ce->ce_size; modifier = ce->modifier; entlen = pathlen - baselen; name = g_strndup(path + baselen, entlen); rawdata_to_hex (sha1, hex, 20); if (version > 0) { seaf_dent = seaf_dirent_new (dir_version_from_repo_version(version), hex, mode, name, mtime, modifier, size); } else { seaf_dent = seaf_dirent_new (0, hex, mode, name, 0, NULL, -1); } g_free(name); dirents = g_list_prepend (dirents, seaf_dent); } #if DEBUG fprintf(stderr, "cache-tree update-one %o %.*s\n", mode, entlen, path + baselen); #endif } /* Sort dirents in descending order. */ dirents = g_list_sort (dirents, compare_dirents); seaf_dir = seaf_dir_new (NULL, dirents, dir_version_from_repo_version(version)); hex_to_rawdata (seaf_dir->dir_id, it->sha1, 20); /* Dir's mtime is the latest of all dir entires. */ guint64 dir_mtime = 0; SeafDirent *dent; for (ptr = dirents; ptr; ptr = ptr->next) { dent = ptr->data; if (dent->mtime > dir_mtime) dir_mtime = dent->mtime; } it->mtime = dir_mtime; if (!seaf_fs_manager_object_exists (seaf->fs_mgr, repo_id, version, seaf_dir->dir_id)) seaf_dir_save (seaf->fs_mgr, repo_id, version, seaf_dir); #if DEBUG for (p = dirents; p; p = p->next) { SeafDirent *tmp = (SeafDirent *)p->data; fprintf(stderr, "dump dirent name %s id %s\n", tmp->name, tmp->id); } #endif seaf_dir_free (seaf_dir); return 0; }