static int delete_dir_recursive (const char *repo_id, int repo_version, const char *dir_path, SeafDir *dir, const char *worktree, struct index_state *istate) { GList *ptr; SeafDirent *dent; char *sub_path; SeafDir *sub_dir; for (ptr = dir->entries; ptr; ptr = ptr->next) { dent = ptr->data; sub_path = g_strconcat (dir_path, "/", dent->name, NULL); if (S_ISDIR(dent->mode)) { if (strcmp(dent->id, EMPTY_SHA1) == 0) { delete_path (worktree, sub_path, dent->mode, 0); } else { sub_dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr, repo_id, repo_version, dent->id); if (!sub_dir) { seaf_warning ("Failed to find dir %s in repo %.8s.\n", sub_path, repo_id); g_free (sub_path); return -1; } if (delete_dir_recursive (repo_id, repo_version, sub_path, sub_dir, worktree, istate) < 0) { g_free (sub_path); return -1; } seaf_dir_free (sub_dir); } } else if (S_ISREG(dent->mode)) { struct cache_entry *ce; ce = index_name_exists (istate, sub_path, strlen(sub_path), 0); if (ce) { delete_path (worktree, sub_path, dent->mode, ce->ce_mtime.sec); } } g_free (sub_path); } char *full_path = g_build_filename (worktree, dir_path, NULL); if (seaf_remove_empty_dir (full_path) < 0) { seaf_warning ("Failed to remove dir %s: %s.\n", full_path, strerror(errno)); return -1; } return 0; }
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; }
int delete_dir_with_check (const char *repo_id, int repo_version, const char *root_id, const char *dir_path, const char *worktree, struct index_state *istate) { SeafDir *dir; int ret; dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr, repo_id, repo_version, root_id, dir_path, NULL); if (!dir) { seaf_warning ("Failed to find dir %s in repo %.8s.\n", dir_path, repo_id); return -1; } ret = delete_dir_recursive (repo_id, repo_version, dir_path, dir, worktree, istate); seaf_dir_free (dir); /* Remove all index entries under this directory */ remove_from_index_with_prefix (istate, dir_path); return ret; }
static int traverse_dir (const char *id) { SeafDir *dir; GList *p; SeafDirent *seaf_dent; dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr, id); if (!dir) { fprintf (stderr, "Failed to read dir %s\n", id); return -1; } for (p = dir->entries; p; p = p->next) { seaf_dent = (SeafDirent *)p->data; if (S_ISREG(seaf_dent->mode)) { printf ("check file %s\n", seaf_dent->name); return check_seafile (seaf_dent->id); } else if (S_ISDIR(seaf_dent->mode)) { printf ("check directory %s\n", seaf_dent->name); return traverse_dir (seaf_dent->id); } } seaf_dir_free (dir); return 0; }
static int get_file_modifier_mtime_v1 (const char *repo_id, const char *store_id, int version, const char *head, const char *path, char **modifier, gint64 *mtime) { SeafCommit *commit = NULL; SeafDir *dir = NULL; SeafDirent *dent = NULL; int ret = 0; commit = seaf_commit_manager_get_commit (seaf->commit_mgr, repo_id, version, head); if (!commit) { seaf_warning ("Failed to get commit %s.\n", head); return -1; } char *parent = g_path_get_dirname (path); if (strcmp(parent, ".") == 0) { g_free (parent); parent = g_strdup(""); } char *filename = g_path_get_basename (path); dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr, store_id, version, commit->root_id, parent, NULL); if (!dir) { seaf_warning ("dir %s doesn't exist in repo %s.\n", parent, repo_id); ret = -1; goto out; } GList *p; for (p = dir->entries; p; p = p->next) { SeafDirent *d = p->data; if (strcmp (d->name, filename) == 0) { dent = d; break; } } if (!dent) { goto out; } *modifier = g_strdup(dent->modifier); *mtime = dent->mtime; out: g_free (parent); g_free (filename); seaf_commit_unref (commit); seaf_dir_free (dir); return ret; }
/* * 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); }
void wt_status_collect_changes_index (struct index_state *index, GList **results, SeafRepo *repo) { SeafFSManager *fs_mgr; SeafCommit *head; int pos = 0; DiffEntry *de; fs_mgr = repo->manager->seaf->fs_mgr; head = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id, repo->version, repo->head->commit_id); if (!head) { seaf_warning ("Failed to get commit %s.\n", repo->head->commit_id); return; } mark_all_ce_unused (index); /* if repo is initial, we don't need to check index changes */ if (strncmp(EMPTY_SHA1, head->root_id, 40) != 0) { SeafDir *root; /* call diff_index to get status */ root = seaf_fs_manager_get_seafdir (fs_mgr, repo->id, repo->version, head->root_id); if (!root) { seaf_warning ("Failed to get root %s.\n", head->root_id); seaf_commit_unref (head); return; } if (diff_index(repo->id, repo->version, index, root, results) < 0) g_warning("diff index failed\n"); seaf_dir_free (root); seaf_commit_unref (head); return; } seaf_commit_unref (head); while (1) { struct cache_entry *ce = next_cache_entry(index, &pos); if (!ce || ce_stage(ce)) break; ce->ce_flags |= CE_UNPACKED; de = diff_entry_new (DIFF_TYPE_INDEX, DIFF_STATUS_ADDED, ce->sha1, ce->name); *results = g_list_prepend (*results, de); } }
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 recv_fs_object (CcnetProcessor *processor, char *content, int clen) { USE_PRIV; ObjectPack *pack = (ObjectPack *)content; uint32_t type; /* TransferTask *task = ((SeafileGetfsProc *)processor)->tx_task; */ if (clen < sizeof(ObjectPack)) { g_warning ("[getfs] invalid object id.\n"); goto bad; } --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 ("[getfs] Bad directory object %s.\n", pack->id); goto bad; } g_queue_push_tail (priv->inspect_queue, g_strdup(dir->dir_id)); seaf_dir_free (dir); } 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 ("[getfs] Invalid object type.\n"); goto bad; } if (save_fs_object (pack, clen) < 0) { goto bad; } g_hash_table_remove (priv->fs_objects, pack->id); return 0; bad: g_warning ("Bad fs object received.\n"); transfer_task_set_error (((SeafileGetfsProc *)processor)->tx_task, TASK_ERR_DOWNLOAD_FS); ccnet_processor_send_update (processor, SC_BAD_OBJECT, SS_BAD_OBJECT, NULL, 0); ccnet_processor_done (processor, FALSE); return -1; }
void seaf_repo_manager_cleanup_virtual_repos (SeafRepoManager *mgr, const char *origin_repo_id) { SeafRepo *repo = NULL; SeafCommit *head = NULL; GList *vinfo_list = NULL, *ptr; SeafVirtRepo *vinfo; SeafDir *dir; GError *error = NULL; repo = seaf_repo_manager_get_repo (mgr, origin_repo_id); if (!repo) { seaf_warning ("Failed to get repo %.10s.\n", origin_repo_id); goto out; } head = seaf_commit_manager_get_commit (seaf->commit_mgr, repo->id, repo->version, repo->head->commit_id); if (!head) { seaf_warning ("Failed to get commit %s:%.8s.\n", repo->id, repo->head->commit_id); goto out; } vinfo_list = seaf_repo_manager_get_virtual_info_by_origin (mgr, origin_repo_id); for (ptr = vinfo_list; ptr; ptr = ptr->next) { vinfo = ptr->data; dir = seaf_fs_manager_get_seafdir_by_path (seaf->fs_mgr, repo->store_id, repo->version, head->root_id, vinfo->path, &error); if (error) { if (error->code == SEAF_ERR_PATH_NO_EXIST) { handle_missing_virtual_repo (mgr, repo, head, vinfo); } g_clear_error (&error); } else seaf_dir_free (dir); seaf_virtual_repo_info_free (vinfo); } out: seaf_repo_unref (repo); seaf_commit_unref (head); g_list_free (vinfo_list); }
static int readdir_repo(SeafileSession *seaf, const char *user, const char *repo_id, const char *repo_path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *info) { SeafRepo *repo = NULL; SeafBranch *branch; SeafCommit *commit = NULL; SeafDir *dir = NULL; GList *l; int ret = 0; repo = seaf_repo_manager_get_repo(seaf->repo_mgr, repo_id); if (!repo) { seaf_warning ("Failed to get repo %s.\n", repo_id); ret = -ENOENT; goto out; } branch = repo->head; commit = seaf_commit_manager_get_commit(seaf->commit_mgr, repo->id, repo->version, branch->commit_id); if (!commit) { seaf_warning ("Failed to get commit %.8s.\n", branch->commit_id); ret = -ENOENT; goto out; } dir = seaf_fs_manager_get_seafdir_by_path(seaf->fs_mgr, repo->store_id, repo->version, commit->root_id, repo_path, NULL); if (!dir) { seaf_warning ("Path %s doesn't exist in repo %s.\n", repo_path, repo_id); ret = -ENOENT; goto out; } for (l = dir->entries; l; l = l->next) { SeafDirent *seaf_dent = (SeafDirent *) l->data; /* FIXME: maybe we need to return stbuf */ filler(buf, seaf_dent->name, NULL, 0); } out: seaf_repo_unref (repo); seaf_commit_unref (commit); seaf_dir_free (dir); return ret; }
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 export_repo_files_recursive (const char *repo_id, const char *id, const char *parent_dir) { SeafDir *dir; GList *p; SeafDirent *seaf_dent; char *path; SeafFSManager *mgr = seaf->fs_mgr; int version = 1; dir = seaf_fs_manager_get_seafdir (mgr, repo_id, version, id); if (!dir) { return; } for (p = dir->entries; p; p = p->next) { seaf_dent = p->data; path = g_build_filename (parent_dir, seaf_dent->name, NULL); if (S_ISREG(seaf_dent->mode)) { // create file create_file (repo_id, seaf_dent->id, path); } else if (S_ISDIR(seaf_dent->mode)) { if (g_mkdir (path, 0777) < 0) { seaf_warning ("Failed to mkdir %s: %s.\n", path, strerror (errno)); g_free (path); continue; } else { seaf_message ("Export dir %s.\n", path); } export_repo_files_recursive (repo_id, seaf_dent->id, path); } g_free (path); } seaf_dir_free (dir); }
GList * seaf_repo_manager_list_dir_with_perm (SeafRepoManager *mgr, const char *repo_id, const char *dir_path, const char *dir_id, const char *user, int offset, int limit, GError **error) { SeafRepo *repo; char *perm = NULL; SeafDir *dir; SeafDirent *dent; SeafileDirent *d; GList *res = NULL; GList *p; if (!repo_id || !is_uuid_valid(repo_id) || dir_id == NULL || !user) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_DIR_ID, "Bad dir id"); return NULL; } perm = seaf_repo_manager_check_permission (mgr, repo_id, user, error); if (!perm) { if (*error == NULL) g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Access denied"); return NULL; } repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (!repo) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Bad repo id"); g_free (perm); return NULL; } dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr, repo->store_id, repo->version, dir_id); if (!dir) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_DIR_ID, "Bad dir id"); seaf_repo_unref (repo); g_free (perm); return NULL; } dir->entries = g_list_sort (dir->entries, comp_dirent_func); if (offset < 0) { offset = 0; } int index = 0; gboolean is_shared; char *cur_path; GHashTable *shared_sub_dirs = NULL; if (!repo->virtual_info) { char *repo_owner = seaf_repo_manager_get_repo_owner (seaf->repo_mgr, repo_id); if (repo_owner && strcmp (user, repo_owner) == 0) { shared_sub_dirs = seaf_share_manager_get_shared_sub_dirs (seaf->share_mgr, repo->store_id, dir_path); } g_free (repo_owner); } for (p = dir->entries; p != NULL; p = p->next, index++) { if (index < offset) { continue; } if (limit > 0) { if (index >= offset + limit) break; } dent = p->data; d = g_object_new (SEAFILE_TYPE_DIRENT, "obj_id", dent->id, "obj_name", dent->name, "mode", dent->mode, "version", dent->version, "mtime", dent->mtime, "size", dent->size, "permission", perm, NULL); if (shared_sub_dirs && S_ISDIR(dent->mode)) { if (strcmp (dir_path, "/") == 0) { cur_path = g_strconcat (dir_path, dent->name, NULL); } else { cur_path = g_strconcat (dir_path, "/", dent->name, NULL); } is_shared = g_hash_table_lookup (shared_sub_dirs, cur_path) ? TRUE : FALSE; g_free (cur_path); g_object_set (d, "is_shared", is_shared, NULL); } res = g_list_prepend (res, d); } if (shared_sub_dirs) g_hash_table_destroy (shared_sub_dirs); seaf_dir_free (dir); seaf_repo_unref (repo); g_free (perm); if (res) res = g_list_reverse (res); return res; }
int commit_trees_cb (struct cache_tree *it, struct cache_entry **cache, int entries, const char *base, int baselen) { SeafDir *seaf_dir; GList *dirents = NULL; int i; for (i = 0; i < entries; i++) { SeafDirent *seaf_dent; char *dirname; 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; 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_assert (sub != NULL); /* Skip cache entries in the sub level. */ i += sub->cache_tree->entry_count - 1; sha1 = sub->cache_tree->sha1; mode = S_IFDIR; dirname = g_strndup(path + baselen, entlen); rawdata_to_hex (sha1, hex, 20); seaf_dent = seaf_dirent_new (hex, mode, dirname); g_free(dirname); dirents = g_list_prepend (dirents, seaf_dent); } else { sha1 = ce->sha1; mode = ce->ce_mode; entlen = pathlen - baselen; dirname = g_strndup(path + baselen, entlen); rawdata_to_hex (sha1, hex, 20); seaf_dent = seaf_dirent_new (hex, mode, dirname); g_free(dirname); 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, 0); hex_to_rawdata (seaf_dir->dir_id, it->sha1, 20); seaf_dir_save (seaf->fs_mgr, 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; }
static char* fsck_check_dir_recursive (const char *id, const char *parent_dir, FsckData *fsck_data) { SeafDir *dir; SeafDir *new_dir; GList *p; SeafDirent *seaf_dent; char *dir_id = NULL; char *path = NULL; gboolean io_error = FALSE; SeafFSManager *mgr = seaf->fs_mgr; char *store_id = fsck_data->repo->store_id; int version = fsck_data->repo->version; gboolean is_corrupted = FALSE; dir = seaf_fs_manager_get_seafdir (mgr, store_id, version, id); for (p = dir->entries; p; p = p->next) { seaf_dent = p->data; io_error = FALSE; if (S_ISREG(seaf_dent->mode)) { path = g_strdup_printf ("%s%s", parent_dir, seaf_dent->name); if (!path) { seaf_warning ("Out of memory, stop to run fsck for repo %.8s.\n", fsck_data->repo->id); goto out; } if (!fsck_verify_seafobj (store_id, version, seaf_dent->id, &io_error, VERIFY_FILE, fsck_data->repair)) { if (io_error) { g_free (path); goto out; } is_corrupted = TRUE; if (fsck_data->repair) { seaf_message ("File %s(%.8s) is corrupted, recreate an empty file.\n", path, seaf_dent->id); } else { seaf_message ("File %s(%.8s) is corrupted.\n", path, seaf_dent->id); } // file corrupted, set it empty memcpy (seaf_dent->id, EMPTY_SHA1, 40); seaf_dent->size = 0; } else { if (check_blocks (seaf_dent->id, fsck_data, &io_error) < 0) { if (io_error) { g_free (path); goto out; } is_corrupted = TRUE; if (fsck_data->repair) { seaf_message ("File %s(%.8s) is corrupted, recreate an empty file.\n", path, seaf_dent->id); } else { seaf_message ("File %s(%.8s) is corrupted.\n", path, seaf_dent->id); } // file corrupted, set it empty memcpy (seaf_dent->id, EMPTY_SHA1, 40); seaf_dent->size = 0; } } g_free (path); } else if (S_ISDIR(seaf_dent->mode)) { path = g_strdup_printf ("%s%s/", parent_dir, seaf_dent->name); if (!path) { seaf_warning ("Out of memory, stop to run fsck for repo %.8s.\n", fsck_data->repo->id); goto out; } if (!fsck_verify_seafobj (store_id, version, seaf_dent->id, &io_error, VERIFY_DIR, fsck_data->repair)) { if (io_error) { g_free (path); goto out; } if (fsck_data->repair) { seaf_message ("Dir %s(%.8s) is corrupted, recreate an empty dir.\n", path, seaf_dent->id); } else { seaf_message ("Dir %s(%.8s) is corrupted.\n", path, seaf_dent->id); } is_corrupted = TRUE; // dir corrupted, set it empty memcpy (seaf_dent->id, EMPTY_SHA1, 40); } else { dir_id = fsck_check_dir_recursive (seaf_dent->id, path, fsck_data); if (dir_id == NULL) { // IO error g_free (path); goto out; } if (strcmp (dir_id, seaf_dent->id) != 0) { is_corrupted = TRUE; // dir corrupted, set it to new dir_id memcpy (seaf_dent->id, dir_id, 41); } g_free (dir_id); } g_free (path); } } if (is_corrupted) { new_dir = seaf_dir_new (NULL, dir->entries, version); if (fsck_data->repair) { if (seaf_dir_save (mgr, store_id, version, new_dir) < 0) { seaf_warning ("Failed to save dir\n"); seaf_dir_free (new_dir); goto out; } } dir_id = g_strdup (new_dir->dir_id); seaf_dir_free (new_dir); dir->entries = NULL; } else { dir_id = g_strdup (dir->dir_id); } out: seaf_dir_free (dir); return dir_id; }
GList * seaf_repo_manager_list_dir_with_perm (SeafRepoManager *mgr, const char *repo_id, const char *dir_path, const char *dir_id, const char *user, int offset, int limit, GError **error) { SeafRepo *repo; char *perm = NULL; SeafDir *dir; SeafDirent *dent; SeafileDirent *d; GList *res = NULL; GList *p; if (!repo_id || !is_uuid_valid(repo_id) || dir_id == NULL || !user) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_DIR_ID, "Bad dir id"); return NULL; } perm = seaf_repo_manager_check_permission (mgr, repo_id, user, error); if (!perm) { if (*error == NULL) g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Access denied"); return NULL; } repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id); if (!repo) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Bad repo id"); g_free (perm); return NULL; } dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr, repo->store_id, repo->version, dir_id); if (!dir) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_DIR_ID, "Bad dir id"); seaf_repo_unref (repo); g_free (perm); return NULL; } dir->entries = g_list_sort (dir->entries, comp_dirent_func); if (offset < 0) { offset = 0; } int index = 0; for (p = dir->entries; p != NULL; p = p->next, index++) { if (index < offset) { continue; } if (limit > 0) { if (index >= offset + limit) break; } dent = p->data; d = g_object_new (SEAFILE_TYPE_DIRENT, "obj_id", dent->id, "obj_name", dent->name, "mode", dent->mode, "version", dent->version, "mtime", dent->mtime, "size", dent->size, "permission", perm, NULL); res = g_list_prepend (res, d); } seaf_dir_free (dir); seaf_repo_unref (repo); g_free (perm); res = g_list_reverse (res); return res; }
/* * Merge the commits h1 and h2, return merged tree root id * and a flag indicating the cleanness of the merge. * Return 0 if merge is done (no matter clean or not); -1 otherwise. */ int merge_recursive(struct merge_options *o, const char *h1_root, const char *h2_root, const char *ca_root, int *clean, char **root_id) { SeafDir *head, *remote, *common; int code, ret = 0; struct unpack_trees_options opts; char *error = NULL; *clean = 1; head = seaf_fs_manager_get_seafdir (seaf->fs_mgr, h1_root); remote = seaf_fs_manager_get_seafdir (seaf->fs_mgr, h2_root); common = seaf_fs_manager_get_seafdir (seaf->fs_mgr, ca_root); if (!head || !remote || !common) { g_warning ("Invalid commits!\n"); return -1; } /* Get merged index. */ code = seafile_merge_trees(o, &opts, common, head, remote, &error); if (code != 0) { ret = -1; goto out; } /* If only collect blocks, return success. */ if (o->collect_blocks_only) { process_unmerged_entries (o, head, remote); goto out; } /* Update worktree. */ /* On windows, we have to Check if any files need to be updated * are locked by other program (e.g. Office). If no file is locked, * update worktree; otherwise just quit. * * Note that if we're recovering merge on startup, we need to update * worktree no matter files are locked or not, since we cannot retry * this operation. This will produce more confusing results, but * it doesn't hurt data integrity. */ #ifdef WIN32 if (o->recover_merge || o->force_merge || !files_locked_on_windows (o->index, o->worktree)) { update_worktree (&opts, o->recover_merge, o->remote_head, o->branch2, NULL); *clean = process_unmerged_entries (o, head, remote); } else { /* Don't update anything. */ g_debug ("[merge] files are locked, quit merge now.\n"); ret = -1; goto out; } #else update_worktree (&opts, o->recover_merge, o->remote_head, o->branch2, NULL); *clean = process_unmerged_entries (o, head, remote); #endif if (*clean) *root_id = write_tree_from_memory(o); out: seaf_dir_free (head); seaf_dir_free (remote); seaf_dir_free (common); return ret; }
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; }
static int getattr_repo(SeafileSession *seaf, const char *user, const char *repo_id, const char *repo_path, struct stat *stbuf) { SeafRepo *repo = NULL; SeafBranch *branch; SeafCommit *commit = NULL; guint32 mode = 0; char *id = NULL; int ret = 0; repo = seaf_repo_manager_get_repo(seaf->repo_mgr, repo_id); if (!repo) { seaf_warning ("Failed to get repo %s.\n", repo_id); ret = -ENOENT; goto out; } branch = repo->head; commit = seaf_commit_manager_get_commit(seaf->commit_mgr, branch->commit_id); if (!commit) { seaf_warning ("Failed to get commit %.8s.\n", branch->commit_id); ret = -ENOENT; goto out; } id = seaf_fs_manager_path_to_obj_id(seaf->fs_mgr, commit->root_id, repo_path, &mode, NULL); if (!id) { seaf_warning ("Path %s doesn't exist in repo %s.\n", repo_path, repo_id); ret = -ENOENT; goto out; } if (S_ISDIR(mode)) { SeafDir *dir; GList *l; int cnt = 2; /* '.' and '..' */ dir = seaf_fs_manager_get_seafdir(seaf->fs_mgr, id); if (dir) { for (l = dir->entries; l; l = l->next) cnt++; } stbuf->st_size += cnt * sizeof(SeafDirent); stbuf->st_mode = mode | 0755; stbuf->st_nlink = 2; seaf_dir_free (dir); } else if (S_ISREG(mode)) { Seafile *file; file = seaf_fs_manager_get_seafile(seaf->fs_mgr, id); if (file) stbuf->st_size = file->file_size; stbuf->st_mode = mode | 0644; stbuf->st_nlink = 1; seafile_unref (file); } else { return -ENOENT; } out: g_free (id); seaf_repo_unref (repo); seaf_commit_unref (commit); return ret; }