static void on_seafdir_read (OSAsyncResult *res, void *cb_data) { CcnetProcessor *processor = cb_data; SeafDir *dir; USE_PRIV; --(priv->inspect_objects); --(priv->checking_dirs); if (!res->success) { request_object_batch (processor, priv, res->obj_id); return; } #ifdef DEBUG seaf_debug ("[recvfs] Read seafdir %s.\n", res->obj_id); #endif dir = seaf_dir_from_data (res->obj_id, res->data, res->len, (priv->repo_version > 0)); if (!dir) { seaf_warning ("[recvfs] Corrupt dir object %s.\n", res->obj_id); request_object_batch (processor, priv, res->obj_id); return; } int ret = check_seafdir (processor, dir); seaf_dir_free (dir); if (ret < 0) return; }
/* * 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 void * check_objects_thread (void *vdata) { CcnetProcessor *processor = vdata; USE_PRIV; check_seafdir (processor, priv->root_id); return vdata; }
static int recv_fs_object (CcnetProcessor *processor, char *content, int clen) { USE_PRIV; ObjectPack *pack = (ObjectPack *)content; SeafFSObject *fs_obj = NULL; if (clen < sizeof(ObjectPack)) { seaf_warning ("invalid object id.\n"); goto bad; } seaf_debug ("[recvfs] Recv fs object %.8s.\n", pack->id); fs_obj = seaf_fs_object_from_data(pack->id, pack->object, clen - sizeof(ObjectPack), (priv->repo_version > 0)); if (!fs_obj) { seaf_warning ("Bad fs object %s.\n", pack->id); goto bad; } if (fs_obj->type == SEAF_METADATA_TYPE_DIR) { SeafDir *dir = (SeafDir *)fs_obj; int ret = check_seafdir (processor, dir); if (ret < 0) goto bad; } else if (fs_obj->type == SEAF_METADATA_TYPE_FILE) { /* TODO: check seafile format. */ #if 0 int ret = seafile_check_data_format (pack->object, clen - 41); if (ret < 0) { goto bad; } #endif } seaf_fs_object_free (fs_obj); if (save_fs_object (processor, pack, clen) < 0) { goto bad; } return 0; bad: ccnet_processor_send_response (processor, SC_BAD_OBJECT, SS_BAD_OBJECT, NULL, 0); seaf_warning ("[recvfs] Bad fs object received.\n"); ccnet_processor_done (processor, FALSE); seaf_fs_object_free (fs_obj); return -1; }
static int recv_fs_object (CcnetProcessor *processor, char *content, int clen) { USE_PRIV; ObjectPack *pack = (ObjectPack *)content; uint32_t type; if (clen < sizeof(ObjectPack)) { g_warning ("invalid object id.\n"); goto bad; } seaf_debug ("[recvfs] Recv fs object %.8s.\n", pack->id); --priv->pending_objects; type = seaf_metadata_type_from_data(pack->object, clen); if (type == SEAF_METADATA_TYPE_DIR) { SeafDir *dir; dir = seaf_dir_from_data (pack->id, pack->object, clen - 41); if (!dir) { g_warning ("Bad directory object %s.\n", pack->id); goto bad; } int ret = check_seafdir (processor, dir); seaf_dir_free (dir); if (ret < 0) goto bad; } else if (type == SEAF_METADATA_TYPE_FILE) { /* TODO: check seafile format. */ #if 0 int ret = seafile_check_data_format (pack->object, clen - 41); if (ret < 0) { goto bad; } #endif } else { g_warning ("Invalid object type.\n"); goto bad; } if (save_fs_object (processor, pack, clen) < 0) { goto bad; } return 0; bad: ccnet_processor_send_response (processor, SC_BAD_OBJECT, SS_BAD_OBJECT, NULL, 0); g_warning ("[recvfs] Bad fs object received.\n"); ccnet_processor_done (processor, FALSE); return -1; }
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; }