/** * Get the user who last changed a file. * @head: head commit to start the search. * @path: path of the file. */ char * get_last_changer_of_file (const char *head, const char *path) { char commit_id[41]; SeafCommit *commit = NULL; char *file_id = NULL; int changed; char *ret = NULL; GError *error = NULL; memcpy (commit_id, head, 41); while (1) { commit = seaf_commit_manager_get_commit (seaf->commit_mgr, commit_id); if (!commit) break; /* We hit the initial commit. */ if (!commit->parent_id) break; file_id = seaf_fs_manager_path_to_obj_id (seaf->fs_mgr, commit->root_id, path, NULL, &error); if (error) { g_clear_error (&error); break; } /* We expect commit to have this file. */ if (!file_id) break; changed = diff_parents_with_path (commit, path, file_id, commit_id, &error); if (error) { g_clear_error (&error); break; } if (changed) { ret = g_strdup (commit->creator_name); break; } else { /* If this commit doesn't change the file, commit_id will be set * to the parent commit to traverse. */ g_free (file_id); seaf_commit_unref (commit); } } g_free (file_id); if (commit) seaf_commit_unref (commit); return ret; }
static int get_file_modifier_mtime_v0 (const char *repo_id, const char *store_id, int version, const char *head, const char *path, char **modifier, gint64 *mtime) { char commit_id[41]; SeafCommit *commit = NULL; char *file_id = NULL; int changed; int ret = 0; GError *error = NULL; *modifier = NULL; *mtime = 0; memcpy (commit_id, head, 41); while (1) { commit = seaf_commit_manager_get_commit (seaf->commit_mgr, repo_id, version, commit_id); if (!commit) { ret = -1; break; } /* We hit the initial commit. */ if (!commit->parent_id) break; file_id = seaf_fs_manager_path_to_obj_id (seaf->fs_mgr, store_id, version, commit->root_id, path, NULL, &error); if (error) { g_clear_error (&error); ret = -1; break; } /* We expect commit to have this file. */ if (!file_id) { ret = -1; break; } changed = diff_parents_with_path (commit, repo_id, store_id, version, path, file_id, commit_id, &error); if (error) { g_clear_error (&error); ret = -1; break; } if (changed) { *modifier = g_strdup (commit->creator_name); *mtime = commit->ctime; break; } else { /* If this commit doesn't change the file, commit_id will be set * to the parent commit to traverse. */ g_free (file_id); seaf_commit_unref (commit); } } g_free (file_id); if (commit) seaf_commit_unref (commit); return ret; }
/** * Diff a specific file with parent(s). * If @commit is a merge, both parents will be compared. * @commit must have this file and it's id is given in @file_id. * * Returns 0 if there is no difference; 1 otherwise. * If returns 0, @parent will point to the next commit to traverse. * If I/O error occurs, @error will be set. */ static int diff_parents_with_path (SeafCommit *commit, const char *repo_id, const char *store_id, int version, const char *path, const char *file_id, char *parent, GError **error) { SeafCommit *p1 = NULL, *p2 = NULL; char *file_id_p1 = NULL, *file_id_p2 = NULL; int ret = 0; p1 = seaf_commit_manager_get_commit (seaf->commit_mgr, commit->repo_id, commit->version, commit->parent_id); if (!p1) { g_warning ("Failed to find commit %s.\n", commit->parent_id); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, " "); return 0; } if (strcmp (p1->root_id, EMPTY_SHA1) == 0) { seaf_commit_unref (p1); return 1; } if (commit->second_parent_id) { p2 = seaf_commit_manager_get_commit (seaf->commit_mgr, commit->repo_id, commit->version, commit->second_parent_id); if (!p2) { g_warning ("Failed to find commit %s.\n", commit->second_parent_id); seaf_commit_unref (p1); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, " "); return 0; } } if (!p2) { file_id_p1 = seaf_fs_manager_path_to_obj_id (seaf->fs_mgr, store_id, version, p1->root_id, path, NULL, error); if (*error) goto out; if (!file_id_p1 || strcmp (file_id, file_id_p1) != 0) ret = 1; else memcpy (parent, p1->commit_id, 41); } else { file_id_p1 = seaf_fs_manager_path_to_obj_id (seaf->fs_mgr, store_id, version, p1->root_id, path, NULL, error); if (*error) goto out; file_id_p2 = seaf_fs_manager_path_to_obj_id (seaf->fs_mgr, store_id, version, p2->root_id, path, NULL, error); if (*error) goto out; if (file_id_p1 && file_id_p2) { if (strcmp(file_id, file_id_p1) != 0 && strcmp(file_id, file_id_p2) != 0) ret = 1; else if (strcmp(file_id, file_id_p1) == 0) memcpy (parent, p1->commit_id, 41); else memcpy (parent, p2->commit_id, 41); } else if (file_id_p1 && !file_id_p2) { if (strcmp(file_id, file_id_p1) != 0) ret = 1; else memcpy (parent, p1->commit_id, 41); } else if (!file_id_p1 && file_id_p2) { if (strcmp(file_id, file_id_p2) != 0) ret = 1; else memcpy (parent, p2->commit_id, 41); } else { ret = 1; } } out: g_free (file_id_p1); g_free (file_id_p2); if (p1) seaf_commit_unref (p1); if (p2) seaf_commit_unref (p2); return ret; }
static int seaf_fuse_open(const char *path, struct fuse_file_info *info) { int n_parts; char *user, *repo_id, *repo_path; SeafRepo *repo = NULL; SeafBranch *branch = NULL; SeafCommit *commit = NULL; guint32 mode = 0; int ret = 0; /* Now we only support read-only mode */ if ((info->flags & 3) != O_RDONLY) return -EACCES; if (parse_fuse_path (path, &n_parts, &user, &repo_id, &repo_path) < 0) { seaf_warning ("Invalid input path %s.\n", path); return -ENOENT; } if (n_parts != 2 && n_parts != 3) { seaf_warning ("Invalid input path for open: %s.\n", path); ret = -EACCES; goto out; } 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 %s:%.8s.\n", repo->id, branch->commit_id); ret = -ENOENT; goto out; } char *id = seaf_fs_manager_path_to_obj_id(seaf->fs_mgr, repo->store_id, repo->version, 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; } g_free (id); if (!S_ISREG(mode)) return -EACCES; out: g_free (user); g_free (repo_id); g_free (repo_path); seaf_repo_unref (repo); seaf_commit_unref (commit); return ret; }
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; }