commit 979c284928e43915f93a863f770e977c2e1532f4
parent 0422f39b741cb9e80362f83f21a5c4ab279d27c3
Author: Mohamed Aslan <maslan@sce.carleton.ca>
Date: Mon, 9 Jun 2014 19:42:51 -0400
code refactored
* objects (FILE, DIR, COMMIT, ...) now are structures.
* DIR, COMMIT are now loaded in memory :(
Diffstat:
M | Makefile | | | 2 | +- |
M | cmd-branch.c | | | 41 | +++++++++++++++++++++++++++-------------- |
M | cmd-checkout.c | | | 14 | -------------- |
M | cmd-log.c | | | 73 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
M | dircache-simple.c | | | 258 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
M | dircache.h | | | 8 | +++++--- |
A | helper.c | | | 68 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | helper.h | | | 25 | +++++++++++++++++++++++++ |
M | objdb-fs.c | | | 238 | ++++++++++++++++++++++++++++++++++++------------------------------------------- |
M | objdb.h | | | 25 | ++++++------------------- |
A | objects.c | | | 227 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | objects.h | | | 90 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | session.c | | | 4 | ++-- |
M | session.h | | | 2 | ++ |
14 files changed, 774 insertions(+), 301 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,7 +1,7 @@
PROG= baseline
BINDIR= /usr/bin
-SRCS= baseline.c config.c common.c session.c
+SRCS= baseline.c config.c common.c session.c objects.c helper.c
SRCS+= cmd-add.c cmd-branch.c cmd-checkout.c cmd-commit.c cmd-help.c cmd-init.c cmd-log.c cmd-version.c
SRCS+= objdb-fs.c
SRCS+= dircache-simple.c
diff --git a/cmd-branch.c b/cmd-branch.c
@@ -39,22 +39,27 @@ cmd_branch(int argc, char **argv)
O_LISTCUR,
O_LISTALL,
O_CREATE,
+ O_SWITCH
} op = O_LISTCUR;
- int ch, error = 0;
+ int ch, error = 0, exist = 0;
struct session s;
baseline_session_begin(&s, 0);
/* parse command line options */
- while ((ch = getopt(argc, argv, "ac:")) != -1) {
+ while ((ch = getopt(argc, argv, "c:ls:")) != -1) {
switch (ch) {
- case 'a':
- op = O_LISTALL;
- break;
case 'c':
op = O_CREATE;
branch = strdup(optarg);
break;
+ case 'l':
+ op = O_LISTALL;
+ break;
+ case 's':
+ op = O_SWITCH;
+ branch = strdup(optarg);
+ break;
default:
error = 1;
break;
@@ -68,6 +73,16 @@ cmd_branch(int argc, char **argv)
}
switch (op) {
+ case O_CREATE:
+ /* create a new branch from the current one */
+ if (s.db_ops->branch_create_from(s.db_ctx, branch, s.branch) == EXIT_FAILURE)
+ errx(EXIT_FAILURE, "error, failed to create branch \'%s\'.", branch);
+ break;
+ case O_LISTALL:
+ /* list all branches */
+ if (s.db_ops->branch_ls(s.db_ctx) == EXIT_FAILURE)
+ errx(EXIT_FAILURE, "error, failed to list branches.");
+ break;
case O_LISTCUR:
/* list current branch */
if (s.db_ops->branch_get_head(s.db_ctx, s.branch, &head) == EXIT_FAILURE)
@@ -75,15 +90,13 @@ cmd_branch(int argc, char **argv)
printf("current branch: %s\nhead: %s\n", s.branch, head);
free(head);
break;
- case O_LISTALL:
- /* list all branches */
- if (s.db_ops->branch_ls(s.db_ctx) == EXIT_FAILURE)
- errx(EXIT_FAILURE, "error, failed to list branches.");
- break;
- case O_CREATE:
- /* create a new branch from the current one */
- if (s.db_ops->branch_create_from(s.db_ctx, branch, s.branch) == EXIT_FAILURE)
- errx(EXIT_FAILURE, "error, failed to create branch \'%s\'.", branch);
+ case O_SWITCH:
+ if (s.db_ops->branch_if_exists(s.db_ctx, branch, &exist) == EXIT_FAILURE)
+ errx(EXIT_FAILURE, "error, failed to query branch.");
+ if (exist)
+ s.dc_ops->branch_set(s.dc_ctx, branch);
+ else
+ errx(EXIT_FAILURE, "branch \'%s\' does not exist.", branch);
break;
}
diff --git a/cmd-checkout.c b/cmd-checkout.c
@@ -31,22 +31,8 @@ extern int dircache_simple_get_ops(struct dircache_ops **);
int cmd_branch(int, char **);
-/*
- * creates a new branch.
- */
static int
checkout(struct session *s, const char *branch_name) {
- int exist;
-
- /* TODO: branch existence check should be moved to dircache */
- if (s->db_ops->branch_if_exists(s->db_ctx, branch_name, &exist) == EXIT_FAILURE) {
- return EXIT_FAILURE;
- }
- if (exist)
- s->dc_ops->checkout(s->dc_ctx, branch_name);
- else
- errx(EXIT_FAILURE, "branch \'%s\' does not exist.", branch_name);
-
return EXIT_SUCCESS;
}
diff --git a/cmd-log.c b/cmd-log.c
@@ -18,17 +18,76 @@
#include <stdlib.h> /* EXIT_SUCCESS */
#include "cmd.h"
-#include "common.h"
+#include "session.h"
+
+#include "objects.h"
int
cmd_log(int argc, char **argv)
{
- const char *ptr = baseline_repo_get_rootdir();
- const char *ptr2 = baseline_repo_get_rootdir();
- if (ptr != NULL)
- printf("%s\n", ptr);
- if (ptr2 != NULL)
- printf("%s\n", ptr2);
+ char *x;
+ struct session s;
+ baseline_session_begin(&s, 0);
+
+ struct commit tmp = {
+ .id = "deadbeaf",
+ .dir = "badcode",
+ .n_parents = 0,
+ .author.name = "mohamed",
+ .author.email = "maslan@maslan.info",
+ .committer.name = "mohamed",
+ .committer.email = "maslan@maslan.info",
+ .message = "XXXLARAXXX"
+ };
+ x = baseline_commit_serialize(&tmp);
+ printf("%s", x);
+
+ struct dirent ent2 = {
+ .id = "02",
+ .name = "dir2.txt",
+ .type = T_DIR,
+ .mode = 1777,
+ .next = NULL
+ };
+ struct dirent ent1 = {
+ .id = "01",
+ .name = "file1.txt",
+ .type = T_FILE,
+ .mode = 777,
+ .next = &ent2
+ };
+/*
+ struct dir d = {
+ .id = "f0cd",
+ .children = &ent1
+ };
+*/
+ //struct dir d = {.children = NULL};
+ struct dir *d = baseline_dir_new();
+ baseline_dir_append(d, &ent1);
+ baseline_dir_append(d, &ent2);
+ x = baseline_dir_serialize(d);
+ printf("%s", x);
+ x = baseline_gen_id(d, O_DIR);
+ printf("%s\n", x);
+ baseline_dir_free(d);
+
+ struct file f1 = {
+ .id = "00001",
+ .loc = ON_MEM,
+ };
+ f1.buffer = strdup("hello");
+ x = baseline_gen_id(&f1, O_FILE);
+ printf("%s\n", x);
+ struct file f2 = {
+ .id = "00002",
+ .loc = ON_FS,
+ };
+ f2.fd = open("hi.txt", O_RDONLY);
+ x = baseline_gen_id(&f2, O_FILE);
+ printf("%s\n", x);
+
+ baseline_session_end(&s);
return EXIT_SUCCESS;
}
diff --git a/dircache-simple.c b/dircache-simple.c
@@ -21,21 +21,26 @@
#include <string.h> /* str*(2), mem*(2) */
#include <unistd.h> /* close(2), rmdir(2), unlink(2) */
+#include <fcntl.h> /* O_* macros */
#include <fts.h> /* fts_*(3) */
#include "defaults.h"
#include "config.h"
#include "objdb.h"
#include "dircache.h"
+#include "objects.h"
+#include "helper.h"
int dircache_simple_get_ops(struct dircache_ops **);
static int simple_open(struct dircache_ctx **, struct objdb_ctx *, struct objdb_ops *, const char *, const char *);
static int simple_close(struct dircache_ctx *);
static int simple_init(struct dircache_ctx *);
static int simple_insert(struct dircache_ctx *, const char *);
-static int simple_checkout(struct dircache_ctx *, const char *);
static int simple_commit(struct dircache_ctx *, const char *);
-static int simple_get_branch(struct dircache_ctx *, char **);
+static int simple_branch_get(struct dircache_ctx *, char **);
+static int simple_branch_set(struct dircache_ctx *, const char *);
+static int simple_workdir_get(struct dircache_ctx *, char **);
+static int simple_workdir_set(struct dircache_ctx *, const char *);
static struct dircache_ops simple_ops = {
.name = "simple",
@@ -46,8 +51,10 @@ static struct dircache_ops simple_ops = {
.insert = simple_insert,
.remove = NULL,
.commit = simple_commit,
- .checkout = simple_checkout,
- .get_branch = simple_get_branch,
+ .branch_get = simple_branch_get,
+ .branch_set = simple_branch_set,
+ .workdir_get = simple_workdir_get,
+ .workdir_set = simple_workdir_set,
.fsck = NULL,
.compress = NULL,
.dedup = NULL
@@ -170,8 +177,8 @@ simple_init(struct dircache_ctx *dc_ctx)
{
char *branch_name = NULL, *branch_path;
char *dc_path;
- int exist, retval;
- size_t size = 0;
+ char *workdir_fname;
+ int exist, fd, retval;
struct stat s;
FILE *branch_fp;
@@ -187,21 +194,21 @@ simple_init(struct dircache_ctx *dc_ctx)
}
}
/* check if '.baseline/branch' file exists */
- /* TODO: some of that code should be moved to cmd-init */
+ /* TODO: a lot of that code should be moved to is_init() func or cmd-init file */
+ /* may be already initialized ... should just return failure? */
if(stat(branch_path, &s) == 0) {
- if ((branch_fp = fopen(branch_path, "r")) == NULL) {
+ if (!S_ISREG(s.st_mode)) {
retval = EXIT_FAILURE;
goto ret;
}
- if (getline(&branch_name, &size, branch_fp) == -1) {
+ if (!(s.st_mode & S_IRUSR) || !(s.st_mode & S_IWUSR)) {
retval = EXIT_FAILURE;
- free(branch_name);
goto ret;
}
- fclose(branch_fp);
}
else {
asprintf(&branch_name, "%s", DEFAULT_BRANCH);
+ /* this piece of code does not belong here */
if (dc_ctx->db_ops->branch_if_exists(dc_ctx->db_ctx, branch_name, &exist) == EXIT_FAILURE) {
retval = EXIT_FAILURE;
free(branch_name);
@@ -214,13 +221,21 @@ simple_init(struct dircache_ctx *dc_ctx)
retval = EXIT_FAILURE;
goto ret;
}
- fprintf(branch_fp, branch_name);
+ fprintf(branch_fp, "%s", branch_name);
fclose(branch_fp);
+ free(branch_name);
}
+ /* create '.baseline/workdir' file */
+ asprintf(&workdir_fname, "%s/workdir", dc_ctx->repo_baselinepath);
+ if ((fd = open(workdir_fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) {
+ free(workdir_fname);
+ retval = EXIT_FAILURE;
+ goto ret;
+ }
+ close(fd);
ret:
free(dc_path);
free(branch_path);
- free(branch_name);
return EXIT_SUCCESS;
}
@@ -233,6 +248,7 @@ simple_insert(struct dircache_ctx *dc_ctx, const char *path)
FILE *fp;
FTS *dir;
FTSENT *entry;
+ struct file *file;
dc_path = get_dircache_path(dc_ctx);
if (stat(path, &s) == -1)
@@ -270,8 +286,15 @@ simple_insert(struct dircache_ctx *dc_ctx, const char *path)
#endif
if (stat(entry->fts_path, &fs) == -1)
return EXIT_FAILURE;
- if (dc_ctx->db_ops->insert_from_file(dc_ctx->db_ctx, T_FILE, entry->fts_path, &objid) == EXIT_FAILURE)
- return EXIT_FAILURE;
+ /* TODO: baseline_file_new2() */
+ file = baseline_file_new();
+ file->loc = ON_FS;
+ if ((file->fd = open(entry->fts_path, O_RDONLY, 0)) == -1)
+ return EXIT_FAILURE;
+ dc_ctx->db_ops->insert_file(dc_ctx->db_ctx, file);
+ close(file->fd);
+ objid = strdup(file->id);
+ baseline_file_free(file);
#ifdef DEBUG
printf("\t ID = %s\n", objid);
#endif
@@ -295,8 +318,16 @@ simple_insert(struct dircache_ctx *dc_ctx, const char *path)
/* it's a file, why the hell would we wait, insert it immediately */
if (stat(path, &fs) == -1)
return EXIT_FAILURE;
- if (dc_ctx->db_ops->insert_from_file(dc_ctx->db_ctx, T_FILE, path, &objid) == EXIT_FAILURE)
+ /* TODO: baseline_file_new2() */
+ file = baseline_file_new();
+ file->loc = ON_FS;
+ if ((file->fd = open(path, O_RDONLY, 0)) == -1)
return EXIT_FAILURE;
+ dc_ctx->db_ops->insert_file(dc_ctx->db_ctx, file);
+ close(file->fd);
+ objid = strdup(file->id);
+ baseline_file_free(file);
+
if (mkdirp(dc_path, dir_diff(path, dc_ctx->repo_rootpath)) == EXIT_FAILURE)
return EXIT_FAILURE;
asprintf(&cache_path, "%s/%s", dc_path, dir_diff(path, dc_ctx->repo_rootpath));
@@ -306,13 +337,14 @@ simple_insert(struct dircache_ctx *dc_ctx, const char *path)
}
fprintf(fp, "F %s %06o\n", objid, fs.st_mode);
fclose(fp);
+ free(objid);
free(cache_path);
}
return EXIT_SUCCESS;
}
static int
-simple_gen_dindex(struct dircache_ctx *dc_ctx, char **didx)
+gen_dindex(struct dircache_ctx *dc_ctx, char **didx)
{
char *dircache_path, *didx_path = NULL;
char *paths[2];
@@ -359,85 +391,12 @@ simple_gen_dindex(struct dircache_ctx *dc_ctx, char **didx)
return EXIT_SUCCESS;
}
-/* TODO: support commits with multiple parents */
-static int
-simple_gen_commit(struct dircache_ctx *dc_ctx, const char *dir_id, const char *parent_head, const char *msg_file, char **commit_file)
-{
- char *dc_path;
- char *cmt_path;
- char *msg = NULL;
- const char *user_name, *user_email;
- int cfd;
- size_t size = 0;
- struct stat s;
- FILE *cfp, *mfp;
-
- dc_path = get_dircache_path(dc_ctx);
- user_name = baseline_config_get_val("username");
- user_email = baseline_config_get_val("useremail");
- if (user_name == NULL || user_email == NULL)
- return EXIT_FAILURE;
- if (msg_file == NULL)
- return EXIT_FAILURE;
- if (stat(dc_path, &s) == -1)
- return EXIT_FAILURE;
- if (!S_ISDIR(s.st_mode))
- return EXIT_FAILURE;
- /* commit message */
- if ((mfp = fopen(msg_file, "r")) == NULL)
- return EXIT_FAILURE;
- /* create commit */
- asprintf(&cmt_path, "%s/commit.XXXXXXX", dc_path);
- if ((cfd = mkstemp(cmt_path)) == -1) {
- return EXIT_FAILURE;
- }
- if ((cfp = fdopen(cfd, "w")) == NULL) {
- unlink(cmt_path);
- close(cfd);
- return EXIT_FAILURE;
- }
- fprintf(cfp, "dir %s\n", dir_id);
- if (parent_head != NULL)
- fprintf(cfp, "parent %s\n", parent_head);
- fprintf(cfp, "author %s <%s>\n", user_name, user_email);
- fprintf(cfp, "committer %s <%s>\n", user_name, user_email);
- while (getline(&msg, &size, mfp) != -1) {
- fprintf(cfp, "%s", msg);
- }
- fclose(cfp);
- fclose(mfp);
- *commit_file = cmt_path;
- return EXIT_SUCCESS;
-}
-
-static int
-simple_get_branch(struct dircache_ctx *dc_ctx, char **branch_name)
-{
- char *branch_fname;
- size_t size = 0;
- FILE *branch_fp;
-
- asprintf(&branch_fname, "%s/branch", dc_ctx->repo_baselinepath);
- *branch_name = NULL;
- if ((branch_fp = fopen(branch_fname, "r")) == NULL) {
- return EXIT_FAILURE;
- }
- if (getline(branch_name, &size, branch_fp) == -1) {
- free(*branch_name);
- return EXIT_FAILURE;
- }
- fclose(branch_fp);
- free(branch_fname);
- return EXIT_SUCCESS;
-}
-
static int
simple_commit(struct dircache_ctx *dc_ctx, const char *msgfile)
{
char *cur_branch, *cur_head;
char *objid, *path, *paths[2], tmp_objid[1024];
char *dircache_path, *didx_path;
- struct objdb_dirhandle *handle;
struct stat s;
FILE *didx_fp, *fp;
FTS *dir;
@@ -446,6 +405,9 @@ simple_commit(struct dircache_ctx *dc_ctx, const char *msgfile)
size_t size;
ssize_t len;
char type;
+ struct dir *ndir;
+ struct dirent *ent;
+ struct commit *com;
dircache_path = get_dircache_path(dc_ctx);
if (stat(dircache_path, &s) == -1)
@@ -453,9 +415,10 @@ simple_commit(struct dircache_ctx *dc_ctx, const char *msgfile)
if (!S_ISDIR(s.st_mode))
return EXIT_FAILURE;
/* FIXME: empty dirache directory */
- simple_gen_dindex(dc_ctx, &didx_path);
+ gen_dindex(dc_ctx, &didx_path);
if ((didx_fp = fopen(didx_path, "r")) == NULL)
return EXIT_FAILURE;
+ objid = NULL;
size = 0;
path = NULL; /* if not set to NULL, realloc() will get pissed. And, it can waste your day! */
while ((len = getline(&path, &size, didx_fp)) != -1) {
@@ -463,7 +426,8 @@ simple_commit(struct dircache_ctx *dc_ctx, const char *msgfile)
path[len-1] = 0;
--len;
}
- dc_ctx->db_ops->dir_begin(dc_ctx->db_ctx, &handle);
+ ndir = baseline_dir_new();
+
paths[0] = (char *)path;
paths[1] = NULL;
if ((dir = fts_open(paths, FTS_NOCHDIR, 0)) == NULL)
@@ -481,11 +445,21 @@ simple_commit(struct dircache_ctx *dc_ctx, const char *msgfile)
return EXIT_FAILURE;
fscanf(fp, "%c %s %o", &type, tmp_objid, &mode);
if (type == 'F') {
- dc_ctx->db_ops->dir_insert_object(dc_ctx->db_ctx, handle, tmp_objid, entry->fts_name, T_FILE, mode);
+ ent = (struct dirent *)calloc(1, sizeof(struct dirent));
+ ent->id = strdup(tmp_objid);
+ ent->name = strdup(entry->fts_name);
+ ent->mode = mode;
+ ent->type = T_FILE;
+ baseline_dir_append(ndir, ent);
printf("[+] F %06o\t%s\n", mode, entry->fts_name);
}
else if (type == 'D') {
- dc_ctx->db_ops->dir_insert_object(dc_ctx->db_ctx, handle, tmp_objid, entry->fts_name, T_DIR, mode);
+ ent = (struct dirent *)calloc(1, sizeof(struct dirent));
+ ent->id = strdup(tmp_objid);
+ ent->name = strdup(entry->fts_name);
+ ent->mode = mode;
+ ent->type = T_DIR;
+ baseline_dir_append(ndir, ent);
/* FIXME: dir mode are copied from dircache, hence not preserved */
printf("[+] D %06o\t%s\n", mode, entry->fts_name);
}
@@ -499,7 +473,10 @@ simple_commit(struct dircache_ctx *dc_ctx, const char *msgfile)
}
}
fts_close(dir);
- dc_ctx->db_ops->dir_end(dc_ctx->db_ctx, handle, &objid);
+ dc_ctx->db_ops->insert_dir(dc_ctx->db_ctx, ndir);
+ free(objid);
+ objid = strdup(ndir->id);
+ baseline_dir_free(ndir);
#ifdef DEBUG
printf("dir \'%s\' commited with ID = %s\n", path, objid);
#endif
@@ -522,40 +499,99 @@ simple_commit(struct dircache_ctx *dc_ctx, const char *msgfile)
return EXIT_FAILURE;
}
/* get commit's parent */
- if (simple_get_branch(dc_ctx, &cur_branch) == EXIT_FAILURE)
+ if (simple_branch_get(dc_ctx, &cur_branch) == EXIT_FAILURE)
return EXIT_FAILURE;
if (dc_ctx->db_ops->branch_get_head(dc_ctx->db_ctx, cur_branch, &cur_head) == EXIT_FAILURE)
return EXIT_FAILURE;
- /* create commit */
- if (simple_gen_commit(dc_ctx, objid, cur_head, msgfile, &path) == EXIT_FAILURE)
- return EXIT_FAILURE;
- if (dc_ctx->db_ops->insert_from_file(dc_ctx->db_ctx, T_COMMIT, path, &objid) == EXIT_FAILURE)
+ if ((com = baseline_helper_commit_build(dc_ctx, objid, cur_head, msgfile)) == NULL)
return EXIT_FAILURE;
- printf("commit id: %s\n", objid);
+ dc_ctx->db_ops->insert_commit(dc_ctx->db_ctx, com);
+ printf("commit id: %s\n", com->id);
unlink(path);
- dc_ctx->db_ops->branch_set_head(dc_ctx->db_ctx, cur_branch, objid);
+ dc_ctx->db_ops->branch_set_head(dc_ctx->db_ctx, cur_branch, com->id);
free(cur_branch);
free(cur_head);
free(path);
free(objid);
+ baseline_commit_free(com);
return EXIT_SUCCESS;
}
static int
-simple_checkout(struct dircache_ctx *dc_ctx, const char *branch_name)
+simple_branch_get(struct dircache_ctx *dc_ctx, char **branch_name)
{
- char *branch_fname;
- FILE *branch_fp;
+ char *fname;
+ size_t size = 0;
+ FILE *fp;
- asprintf(&branch_fname, "%s/branch", dc_ctx->repo_baselinepath);
- if ((branch_fp = fopen(branch_fname, "w")) == NULL) {
+ if (dc_ctx == NULL || branch_name == NULL)
+ return EXIT_FAILURE;
+ asprintf(&fname, "%s/branch", dc_ctx->repo_baselinepath);
+ *branch_name = NULL;
+ if ((fp = fopen(fname, "r")) == NULL)
+ return EXIT_FAILURE;
+ if (getline(branch_name, &size, fp) == -1) {
+ free(*branch_name);
return EXIT_FAILURE;
}
- fprintf(branch_fp, branch_name);
- fclose(branch_fp);
- /* TODO: copy head files into working dir */
- free(branch_fname);
+ fclose(fp);
+ free(fname);
return EXIT_SUCCESS;
}
+static int
+simple_branch_set(struct dircache_ctx *dc_ctx, const char *branch_name)
+{
+ char *fname;
+ FILE *fp;
+
+ if (dc_ctx == NULL || branch_name == NULL)
+ return EXIT_FAILURE;
+ asprintf(&fname, "%s/branch", dc_ctx->repo_baselinepath);
+ if ((fp = fopen(fname, "w")) == NULL)
+ return EXIT_FAILURE;
+ fprintf(fp, "%s", branch_name);
+ fclose(fp);
+ free(fname);
+ return EXIT_SUCCESS;
+}
+
+static int
+simple_workdir_get(struct dircache_ctx *dc_ctx, char **commit_id)
+{
+ char *fname;
+ size_t size = 0;
+ FILE *fp;
+
+ if (dc_ctx == NULL || commit_id == NULL)
+ return EXIT_FAILURE;
+ asprintf(&fname, "%s/workdir", dc_ctx->repo_baselinepath);
+ *commit_id = NULL;
+ if ((fp = fopen(fname, "r")) == NULL)
+ return EXIT_FAILURE;
+ if (getline(commit_id, &size, fp) == -1) {
+ free(*commit_id);
+ return EXIT_FAILURE;
+ }
+ fclose(fp);
+ free(fname);
+ return EXIT_SUCCESS;
+}
+
+static int
+simple_workdir_set(struct dircache_ctx *dc_ctx, const char *commit_id)
+{
+ char *fname;
+ FILE *fp;
+
+ if (dc_ctx == NULL || commit_id == NULL)
+ return EXIT_FAILURE;
+ asprintf(&fname, "%s/workdir", dc_ctx->repo_baselinepath);
+ if ((fp = fopen(fname, "w")) == NULL)
+ return EXIT_FAILURE;
+ fprintf(fp, "%s", commit_id);
+ fclose(fp);
+ free(fname);
+ return EXIT_SUCCESS;
+}
diff --git a/dircache.h b/dircache.h
@@ -15,7 +15,7 @@
*/
#ifndef _DIRCACHE_H_
-#define _DIRCAHCE_H_
+#define _DIRCACHE_H_
#include <sys/types.h>
#include "objdb.h"
@@ -36,8 +36,10 @@ struct dircache_ops {
int (*insert)(struct dircache_ctx *, const char *);
int (*remove)(struct dircache_ctx *, const char *);
int (*commit)(struct dircache_ctx *, const char *);
- int (*checkout)(struct dircache_ctx *, const char *);
- int (*get_branch)(struct dircache_ctx *, char **);
+ int (*branch_get)(struct dircache_ctx *, char **);
+ int (*branch_set)(struct dircache_ctx *, const char *);
+ int (*workdir_get)(struct dircache_ctx *, char **);
+ int (*workdir_set)(struct dircache_ctx *, const char *);
int (*fsck)(struct dircache_ctx *);
int (*compress)(struct dircache_ctx *);
int (*dedup)(struct dircache_ctx *);
diff --git a/helper.c b/helper.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2014 Mohamed Aslan <maslan@sce.carleton.ca>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "helper.h"
+#include "config.h"
+
+/* TODO: add support for multiple parents */
+struct commit *
+baseline_helper_commit_build(struct dircache_ctx *dc_ctx, const char *dir_id, const char *parent_head, const char *msg_file)
+{
+ char *line = NULL;
+ const char *user_name, *user_email;
+ size_t size = 0;
+ struct stat s;
+ struct commit *comm;
+ FILE *mfp;
+
+ comm = baseline_commit_new();
+ if ((user_name = baseline_config_get_val("username")) == NULL)
+ return NULL;
+ if ((user_email = baseline_config_get_val("useremail")) == NULL)
+ return NULL;
+ if (msg_file == NULL)
+ return NULL;
+ if (stat(msg_file, &s) == -1)
+ return NULL;
+ comm->dir = strdup(dir_id);
+ comm->author.name = strdup(user_name);
+ comm->author.email = strdup(user_email);
+ comm->committer.name = strdup(user_name);
+ comm->committer.email = strdup(user_email);
+ if (parent_head != NULL) {
+ comm->parents[0] = strdup(parent_head);
+ comm->n_parents = 1;
+ }
+ else {
+ comm->n_parents = 0;
+ }
+ /* commit message */
+ if ((mfp = fopen(msg_file, "r")) == NULL)
+ return NULL;
+ /* FIXME: loading the whole message file in memory */
+ if ((comm->message = (char *)malloc(s.st_size)) == NULL)
+ return NULL;
+ while (getline(&line, &size, mfp) != -1)
+ strlcat(comm->message, line, s.st_size);
+ fclose(mfp);
+ return comm;
+}
+
diff --git a/helper.h b/helper.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2014 Mohamed Aslan <maslan@sce.carleton.ca>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _HELPER_H_
+#define _HELPER_H_
+
+#include "objects.h"
+#include "dircache.h"
+
+struct commit* baseline_helper_commit_build(struct dircache_ctx *, const char *, const char *, const char *);
+
+#endif
diff --git a/objdb-fs.c b/objdb-fs.c
@@ -26,6 +26,7 @@
#include <fts.h> /* fts_*(3) */
#include "defaults.h"
+#include "objects.h"
#include "objdb.h"
int objdb_baseline_get_ops(struct objdb_ops **);
@@ -33,12 +34,10 @@ static char * get_objdb_dir(struct objdb_ctx *);
static int objdb_bl_open(struct objdb_ctx **, const char *, const char *);
static int objdb_bl_close(struct objdb_ctx *);
static int objdb_bl_init(struct objdb_ctx *);
-static int objdb_bl_insert(struct objdb_ctx *, enum objdb_type, const u_int8_t *, char **);
-static int objdb_bl_insert_from_file(struct objdb_ctx *, enum objdb_type, const char *, char **);
+static int objdb_bl_insert_file(struct objdb_ctx *, struct file *);
+static int objdb_bl_insert_dir(struct objdb_ctx *, struct dir *);
+static int objdb_bl_insert_commit(struct objdb_ctx *, struct commit *);
static int objdb_bl_remove(struct objdb_ctx *, const char *, const char *);
-static int objdb_bl_dir_begin(struct objdb_ctx *, struct objdb_dirhandle **);
-static int objdb_bl_dir_insert_object(struct objdb_ctx *, struct objdb_dirhandle *, const char *, const char *, enum objdb_type, mode_t);
-static int objdb_bl_dir_end(struct objdb_ctx *, struct objdb_dirhandle *, char **);
static int objdb_bl_branch_create(struct objdb_ctx *, const char *);
static int objdb_bl_branch_create_from(struct objdb_ctx *, const char *, const char *);
static int objdb_bl_branch_if_exists(struct objdb_ctx *, const char *, int *);
@@ -53,12 +52,10 @@ static const struct objdb_ops baseline_objdb_ops = {
.init = objdb_bl_init,
.open = objdb_bl_open,
.close = objdb_bl_close,
- .insert = objdb_bl_insert,
- .insert_from_file = objdb_bl_insert_from_file,
+ .insert_file = objdb_bl_insert_file,
+ .insert_dir = objdb_bl_insert_dir,
+ .insert_commit = objdb_bl_insert_commit,
.remove = objdb_bl_remove,
- .dir_begin = objdb_bl_dir_begin,
- .dir_insert_object = objdb_bl_dir_insert_object,
- .dir_end = objdb_bl_dir_end,
.branch_create = objdb_bl_branch_create,
.branch_create_from = objdb_bl_branch_create_from,
.branch_if_exists = objdb_bl_branch_if_exists,
@@ -155,74 +152,80 @@ ret:
}
static int
-objdb_bl_insert(struct objdb_ctx *ctx, enum objdb_type type, const u_int8_t *data, char **obj_id)
+objdb_bl_insert_file(struct objdb_ctx *ctx, struct file *file)
{
- return EXIT_SUCCESS;
-}
+ char *db_dir_name, *full_path, *obj_file_name, *obj_hash, *tmp_file_name;
+ char *buf[4096];
+ int n, retval, tmpfd;
+ off_t offset;
-static int
-objdb_bl_insert_from_file(struct objdb_ctx *ctx, enum objdb_type type, const char *file_name, char **obj_id)
-{
- char *db_dir_name, *full_path, *obj_file_name, *obj_hash, *ptr, *tmp_file_name;
- int count, i, len, retval, tmpfd;
- FILE *fp, *tmpfp;
- SHA2_CTX hash_ctx;
- struct stat s;
- u_int8_t buf[4096], digest[SHA256_DIGEST_LENGTH];
-
- if (file_name == NULL) {
- retval = EXIT_FAILURE;
- goto ret;
- }
- if ((fp = fopen(file_name, "r")) == NULL) {
- retval = EXIT_FAILURE;
- goto ret;
- }
db_dir_name = get_objdb_dir(ctx);
if (db_dir_name == NULL) {
retval = EXIT_FAILURE;
goto ret;
}
- /* check object's type */
- if (type == T_FILE) {
- /* malloc() + strlcpy() + strlcat() = asprintf() */
- len = asprintf(&full_path, "%s/%s", db_dir_name, "files");
+ asprintf(&full_path, "%s/%s", db_dir_name, "files");
+ obj_hash = baseline_gen_id(file, O_FILE);
+ /* create a temp file */
+ asprintf(&tmp_file_name, "%s/tmp.XXXXXX", full_path);
+ if ((tmpfd = mkstemp(tmp_file_name)) == -1) {
+ retval = EXIT_FAILURE;
+ goto ret;
}
- else if (type == T_DIR) {
- len = asprintf(&full_path, "%s/%s", db_dir_name, "dirs");
+ if (file->loc == ON_FS) {
+ /* save file offset */
+ offset = lseek(file->fd, 0, SEEK_CUR);
+ /* copy file content */
+ while((n = read(file->fd, buf, sizeof(buf))) > 0)
+ write(tmpfd, buf, n);
+ /* restore file offset */
+ lseek(file->fd, offset, SEEK_SET);
}
- else if (type == T_COMMIT) {
- len = asprintf(&full_path, "%s/%s", db_dir_name, "commits");
+ else if (file->loc == ON_MEM) {
+ write(tmpfd, file->buffer, strlen(file->buffer));
}
- else if (type == T_TAG) {
- len = asprintf(&full_path, "%s/%s", db_dir_name, "tags");
+ close(tmpfd);
+ asprintf(&obj_file_name, "%s/%s", full_path, obj_hash);
+ /* check if file is already there */
+ if (access(obj_file_name, F_OK) != -1) {
+ unlink(tmp_file_name);
+ goto success;
}
- else {
- len = asprintf(&full_path, "%s", db_dir_name);
+ if (rename(tmp_file_name, obj_file_name)) {
+ retval = EXIT_FAILURE;
+ goto ret;
}
-#ifdef DEBUG
- printf("[DEBUG] DB: checking for path = %s\n", full_path);
-#endif
- /* check if path exists */
- if (stat(full_path, &s) != 0) {
-#ifdef DEBUG
- printf("\t[DEBUG] DB: creating new dir %s\n", full_path);
-#endif
- if (mkdir(full_path, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
- retval = EXIT_FAILURE;
- goto ret;
- }
- }
- else {
- if (!S_ISDIR(s.st_mode)) {
- retval = EXIT_FAILURE;
- goto ret;
- }
+success:
+ retval = EXIT_SUCCESS;
+ret:
+ /* assuming free(NULL) is safe */
+ free(db_dir_name);
+ free(full_path);
+ free(obj_file_name);
+ free(tmp_file_name);
+ return retval;
+}
+
+static int
+objdb_bl_insert_dir(struct objdb_ctx *ctx, struct dir *dir)
+{
+ char *db_dir_name, *full_path, *obj_file_name, *obj_hash, *tmp_file_name;
+ char *data;
+ int retval, tmpfd;
+ FILE *tmpfp;
+
+ db_dir_name = get_objdb_dir(ctx);
+ if (db_dir_name == NULL) {
+ retval = EXIT_FAILURE;
+ goto ret;
}
+ asprintf(&full_path, "%s/%s", db_dir_name, "dirs");
+ data = baseline_dir_serialize(dir);
+ obj_hash = baseline_gen_id(dir, O_DIR);
+
/* create a temp file */
- /* malloc() + strlcpy() + strlcat() = asprintf() */
- len = asprintf(&tmp_file_name, "%s/tmp.XXXXXX", full_path);
+ asprintf(&tmp_file_name, "%s/tmp.XXXXXX", full_path);
if ((tmpfd = mkstemp(tmp_file_name)) == -1) {
retval = EXIT_FAILURE;
goto ret;
@@ -233,25 +236,9 @@ objdb_bl_insert_from_file(struct objdb_ctx *ctx, enum objdb_type type, const cha
retval = EXIT_FAILURE;
goto ret;
}
- SHA256Init(&hash_ctx);
- do {
- count = fread(buf, sizeof(u_int8_t), sizeof(buf), fp);
- fwrite(buf, sizeof(u_int8_t), count, tmpfp); /* faster for new a file, but slower if the file already exist! */
- SHA256Update(&hash_ctx, buf, count);
- } while (!feof(fp));
- SHA256Final(digest, &hash_ctx);
- fclose(fp);
- fclose(tmpfp);
- /* TODO: think of something safer */
- obj_hash = (char *)malloc(SHA256_DIGEST_LENGTH * 2 + 1);
- for (i=0, ptr=obj_hash ; i<SHA256_DIGEST_LENGTH ; i++, ptr+=2) {
- snprintf(ptr, 3, "%02x", digest[i]);
- }
- /* malloc() + strlcpy() + strlcat() = asprintf() */
+ fwrite(data, sizeof(u_int8_t), strlen(data), tmpfp);
+ fclose(tmpfp);
asprintf(&obj_file_name, "%s/%s", full_path, obj_hash);
-#ifdef DEBUG
- printf("[DEBUG] DB: object file name = %s\n", obj_file_name);
-#endif
/* check if file is already there */
if (access(obj_file_name, F_OK) != -1) {
unlink(tmp_file_name);
@@ -263,7 +250,6 @@ objdb_bl_insert_from_file(struct objdb_ctx *ctx, enum objdb_type type, const cha
}
success:
- *obj_id = obj_hash;
retval = EXIT_SUCCESS;
ret:
/* assuming free(NULL) is safe */
@@ -275,73 +261,65 @@ ret:
}
static int
-objdb_bl_remove(struct objdb_ctx *ctx, const char *group_name, const char *obj_name)
+objdb_bl_insert_commit(struct objdb_ctx *ctx, struct commit *comm)
{
- return EXIT_SUCCESS;
-}
-
-static int
-objdb_bl_dir_begin(struct objdb_ctx *ctx, struct objdb_dirhandle **handle)
-{
- char *db_dir_name;
- char *tmp_file_name;
- int len, tmpfd;
+ char *db_dir_name, *full_path, *obj_file_name, *obj_hash, *tmp_file_name;
+ char *data;
+ int retval, tmpfd;
FILE *tmpfp;
+
db_dir_name = get_objdb_dir(ctx);
- /* malloc() + strlcpy() + strlcat() = asprintf() */
- len = asprintf(&tmp_file_name, "%s/tmp.XXXXXX", db_dir_name);
+ if (db_dir_name == NULL) {
+ retval = EXIT_FAILURE;
+ goto ret;
+ }
+ asprintf(&full_path, "%s/%s", db_dir_name, "commits");
+ data = baseline_commit_serialize(comm);
+ obj_hash = baseline_gen_id(comm, O_COMMIT);
+
+ /* create a temp file */
+ asprintf(&tmp_file_name, "%s/tmp.XXXXXX", full_path);
if ((tmpfd = mkstemp(tmp_file_name)) == -1) {
- return EXIT_FAILURE;
+ retval = EXIT_FAILURE;
+ goto ret;
}
if ((tmpfp = fdopen(tmpfd, "w")) == NULL) {
unlink(tmp_file_name);
close(tmpfd);
- return EXIT_FAILURE;
+ retval = EXIT_FAILURE;
+ goto ret;
}
- *handle = (struct objdb_dirhandle *)malloc(sizeof(struct objdb_dirhandle));
- (*handle)->id = tmpfd;
- (*handle)->name = strdup(tmp_file_name);
+ fwrite(data, sizeof(u_int8_t), strlen(data), tmpfp);
+ fclose(tmpfp);
+ asprintf(&obj_file_name, "%s/%s", full_path, obj_hash);
+ /* check if file is already there */
+ if (access(obj_file_name, F_OK) != -1) {
+ unlink(tmp_file_name);
+ goto success;
+ }
+ if (rename(tmp_file_name, obj_file_name)) {
+ retval = EXIT_FAILURE;
+ goto ret;
+ }
+
+success:
+ retval = EXIT_SUCCESS;
+ret:
+ /* assuming free(NULL) is safe */
free(db_dir_name);
+ free(full_path);
+ free(obj_file_name);
free(tmp_file_name);
- return EXIT_SUCCESS;
+ return retval;
}
static int
-objdb_bl_dir_insert_object(struct objdb_ctx *ctx, struct objdb_dirhandle *handle, const char *objid, const char *name, enum objdb_type type, mode_t mode)
+objdb_bl_remove(struct objdb_ctx *ctx, const char *group_name, const char *obj_name)
{
- char *entry;
- int len;
- /* TODO: check if obj exists! */
- if (type == T_FILE) {
- /* FIXME: non-portable code */
- len = asprintf(&entry, "%c %s %06o %s\n", 'F', objid, mode, name);
- /* FIXME: error checking */
- write(handle->id, entry, len);
- }
- else if (type == T_DIR) {
- /* FIXME: non-portable code */
- len = asprintf(&entry, "%c %s %06o %s\n", 'D', objid, mode, name);
- /* FIXME: error checking */
- write(handle->id, entry, len);
- }
return EXIT_SUCCESS;
}
static int
-objdb_bl_dir_end(struct objdb_ctx *ctx, struct objdb_dirhandle *handle, char **objid)
-{
- enum objdb_type type = T_DIR;
- int retval;
- close(handle->id);
- retval = objdb_bl_insert_from_file(ctx, type, handle->name, objid);
- if (retval == EXIT_SUCCESS)
- unlink(handle->name);
- free(handle->name);
- free(handle);
- return retval;
-}
-
-static int
objdb_bl_branch_create(struct objdb_ctx *ctx, const char *branch_name)
{
char *db_dir_name = NULL;
diff --git a/objdb.h b/objdb.h
@@ -18,18 +18,7 @@
#define _OBJDB_H_
#include <sys/types.h>
-
-enum objdb_type {
- T_FILE,
- T_DIR,
- T_COMMIT,
- T_TAG
-};
-
-struct objdb_dirhandle {
- int id;
- char *name;
-};
+#include "objects.h"
struct objdb_ctx {
char *db_name;
@@ -44,13 +33,11 @@ struct objdb_ops {
int (*open)(struct objdb_ctx **, const char *, const char *);
int (*close)(struct objdb_ctx *);
int (*init)(struct objdb_ctx *);
- /* file ops*/
- int (*insert)(struct objdb_ctx *, enum objdb_type, const u_int8_t *, char **);
- int (*insert_from_file)(struct objdb_ctx *, enum objdb_type, const char *, char **);
- /* dir ops */
- int (*dir_begin)(struct objdb_ctx *, struct objdb_dirhandle **);
- int (*dir_insert_object)(struct objdb_ctx *, struct objdb_dirhandle *, const char *, const char *, enum objdb_type, mode_t);
- int (*dir_end)(struct objdb_ctx *, struct objdb_dirhandle *, char **);
+ /* file ops */
+ //int (*insert_from_file)(struct objdb_ctx *, enum objdb_type, const char *, char **);
+ int (*insert_file)(struct objdb_ctx *, struct file *);
+ int (*insert_dir)(struct objdb_ctx *, struct dir *);
+ int (*insert_commit)(struct objdb_ctx *, struct commit *);
/* branch ops */
int (*branch_create)(struct objdb_ctx *, const char *);
int (*branch_create_from)(struct objdb_ctx *, const char *, const char *);
diff --git a/objects.c b/objects.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2014 Mohamed Aslan <maslan@sce.carleton.ca>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h> /* read(2) */
+
+#include <sha2.h>
+
+#include "objects.h"
+
+struct file *
+baseline_file_new()
+{
+ struct file *file = (struct file *)calloc(1, sizeof(struct file));
+ return file;
+}
+
+void
+baseline_file_free(struct file *file)
+{
+ if (file == NULL)
+ return;
+ free(file->id);
+ if (file->loc == ON_MEM)
+ free(file->buffer);
+ free(file);
+}
+
+struct commit *
+baseline_commit_new()
+{
+ struct commit *comm = (struct commit *)calloc(1, sizeof(struct commit));
+ return comm;
+}
+
+void
+baseline_commit_free(struct commit *comm)
+{
+ int i;
+ if (comm == NULL)
+ return;
+ free(comm->id);
+ free(comm->dir);
+ for (i=0 ; i<comm->n_parents ; i++)
+ free(comm->parents[i]);
+ free(comm->message);
+ free(comm);
+}
+
+/*
+ * converts struct commit to char*
+ */
+char*
+baseline_commit_serialize(struct commit *comm)
+{
+ char *raw = NULL;
+
+ if (comm == NULL)
+ goto ret;
+ if (comm->n_parents == 0)
+ asprintf(&raw, "dir %s\nauthor %s <%s>\ncommitter %s <%s>\n%s\n",
+ comm->dir, comm->author.name, comm->author.email,
+ comm->committer.name, comm->committer.email, comm->message);
+ else if (comm->n_parents == 1)
+ asprintf(&raw, "dir %s\nparent %s\nauthor %s <%s>\ncommitter %s <%s>\n%s\n",
+ comm->dir, comm->parents[0], comm->author.name, comm->author.email,
+ comm->committer.name, comm->committer.email, comm->message);
+ /* TODO: support more than 1 parent */
+ret:
+ return raw;
+}
+
+struct dir *
+baseline_dir_new()
+{
+ struct dir *dir = (struct dir *)calloc(1, sizeof(struct dir));
+ dir->children = NULL;
+ return dir;
+}
+
+void
+baseline_dir_free(struct dir *dir)
+{
+ struct dirent *it, *ptr;
+
+ if (dir == NULL)
+ return;
+ if (dir->children == NULL) {
+ free(dir);
+ return;
+ }
+ for (it = dir->children ; it != NULL ;) {
+ ptr = it;
+ it = it->next;
+ free(ptr);
+ }
+ free(dir);
+}
+
+void
+baseline_dir_append(struct dir *dir, struct dirent *ent)
+{
+ struct dirent *it;
+
+ if (dir == NULL || ent == NULL)
+ return;
+ if (dir->children == NULL) {
+ dir->children = ent;
+ }
+ else {
+ for (it = dir->children ; it->next != NULL ; it = it->next);
+ it->next = ent;
+ }
+ ent->next = NULL;
+}
+
+/*
+ * converts struct dir to char*
+ */
+char*
+baseline_dir_serialize(struct dir *dir)
+{
+ char *entry = NULL, *raw = NULL, *ptr, ch = ' ';
+ size_t size = 1, newsize;
+ struct dirent *it;
+
+ if (dir == NULL)
+ goto ret;
+ raw = (char *)malloc(sizeof(char));
+ *raw = '\0';
+ if (dir->children == NULL)
+ goto ret;
+ for (it = dir->children ; it != NULL ; it = it->next) {
+ if (it->type == T_FILE)
+ ch = 'F';
+ else if (it->type == T_DIR)
+ ch = 'D';
+ /* assuming asprintf() uses realloc() */
+ entry = NULL;
+ asprintf(&entry, "%c %s %06o %s\n", ch, it->id, it->mode, it->name);
+ /* allocation failed, need to do something! */
+ if (entry == NULL)
+ return NULL;
+ newsize = size + strlen(entry);
+ if ((ptr = realloc(raw, newsize)) == NULL) {
+ /* allocation failed, need to do something! */
+ return NULL;
+ }
+ raw = ptr;
+ size = newsize;
+ strlcat(raw, entry, size);
+ }
+ free(entry);
+ret:
+ return raw;
+}
+
+char*
+baseline_gen_id(void *obj, enum objtype type)
+{
+ char **objid = NULL, *ptr, *serialized = NULL;
+ char buf[4096];
+ int i, n;
+ off_t offset;
+ u_int8_t digest[SHA256_DIGEST_LENGTH];
+ SHA2_CTX hash_ctx;
+
+ SHA256Init(&hash_ctx);
+ switch (type) {
+ case O_COMMIT:
+ serialized = baseline_commit_serialize((struct commit *)obj);
+ SHA256Update(&hash_ctx, serialized, strlen(serialized));
+ free(serialized);
+ objid = &(((struct commit *)obj)->id);
+ break;
+ case O_DIR:
+ serialized = baseline_dir_serialize((struct dir *)obj);
+ SHA256Update(&hash_ctx, serialized, strlen(serialized));
+ free(serialized);
+ objid = &(((struct dir *)obj)->id);
+ break;
+ case O_FILE:
+ if (((struct file *)obj)->loc == ON_FS) {
+ /* save file offset */
+ offset = lseek(((struct file *)obj)->fd, 0, SEEK_CUR);
+ do {
+ n = read(((struct file *)obj)->fd, buf, sizeof(buf));
+ if (n == -1)
+ return NULL;
+ SHA256Update(&hash_ctx, buf, n);
+ if (n <= sizeof(buf))
+ break;
+ } while (1);
+ /* restore file offset */
+ lseek(((struct file *)obj)->fd, offset, SEEK_SET);
+ }
+ else {
+ SHA256Update(&hash_ctx, ((struct file *)obj)->buffer, strlen(((struct file *)obj)->buffer));
+ }
+ objid = &(((struct file *)obj)->id);
+ break;
+ default:
+ break;
+ }
+ SHA256Final(digest, &hash_ctx);
+ *objid = (char *)malloc(SHA256_DIGEST_LENGTH * 2 + 1);
+ for (i=0, ptr=*objid ; i<SHA256_DIGEST_LENGTH ; i++, ptr+=2) {
+ snprintf(ptr, 3, "%02x", digest[i]);
+ }
+ return *objid;
+}
+
diff --git a/objects.h b/objects.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2014 Mohamed Aslan <maslan@sce.carleton.ca>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _OBJECTS_H_
+#define _OBJECTS_H_
+
+#include <fcntl.h>
+
+#define MAX_PARENTS 1
+
+enum objtype {
+ O_FILE,
+ O_DIR,
+ O_COMMIT,
+ O_TAG
+};
+
+struct user {
+ char *name;
+ char *email;
+};
+
+struct commit {
+ char *id; /* do we really need that? */
+ char *dir;
+ struct user author;
+ struct user committer;
+ u_int8_t n_parents;
+ char *parents[MAX_PARENTS];
+ char *message;
+};
+
+struct dirent {
+ char *id;
+ char *name;
+ enum {
+ T_FILE,
+ T_DIR
+ } type;
+ mode_t mode;
+ struct dirent *next;
+};
+
+struct dir {
+ char *id;
+ struct dir *parent; /* currently unused */
+ struct dirent *children;
+};
+
+struct file {
+ char *id;
+ enum {
+ ON_FS,
+ ON_MEM
+ } loc;
+ union {
+ int fd;
+ char *buffer;
+ };
+};
+
+/* file ops */
+struct file* baseline_file_new();
+void baseline_file_free(struct file *);
+/* commit ops */
+struct commit* baseline_commit_new();
+void baseline_commit_free(struct commit *);
+char* baseline_commit_serialize(struct commit *);
+/* dir ops */
+struct dir* baseline_dir_new();
+void baseline_dir_free(struct dir *);
+void baseline_dir_append(struct dir *, struct dirent *);
+char* baseline_dir_serialize(struct dir *);
+/* id ops */
+char *baseline_gen_id(void *, enum objtype);
+
+#endif
diff --git a/session.c b/session.c
@@ -46,7 +46,7 @@ baseline_session_begin(struct session *s, u_int8_t options)
s->repo_baselinedir = baseline_repo_get_baselinedir();
if (s->repo_rootdir == NULL)
- errx(EXIT_FAILURE, "error, no repository is found.");
+ errx(EXIT_FAILURE, "error, no repository was found.");
if (s->db_ops->open(&(s->db_ctx), BASELINE_DB, s->repo_baselinedir) == EXIT_FAILURE)
return EXIT_FAILURE;
if (s->dc_ops->open(&(s->dc_ctx), s->db_ctx, s->db_ops, s->repo_rootdir, s->repo_baselinedir) == EXIT_FAILURE)
@@ -59,7 +59,7 @@ baseline_session_begin(struct session *s, u_int8_t options)
free(config);
/* get current branch */
- s->dc_ops->get_branch(s->dc_ctx, (char **)&(s->branch));
+ s->dc_ops->branch_get(s->dc_ctx, (char **)&(s->branch));
return EXIT_SUCCESS;
}
diff --git a/session.h b/session.h
@@ -17,6 +17,8 @@
#ifndef _SESSION_H_
#define _SESSION_H_
+#include <limits.h>
+
#include "objdb.h"
#include "dircache.h"
#include "common.h"