/* $Header$ * * GAT library. Sorry, this library is GPL only. * * Copyright (C)2005 by Valentin Hilbig * Based on ideas presented in GIT from Linus Torvalds. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Log$ */ #include "gat-exitcodes.h" /**********************************************************************/ /* Never assume anything about this structure! * Only access it through library functions. */ typedef struct GAT_gat { char *gatroot; char *logname; FILE *logfd; char pwd[PATH_MAX]; int dirs; struct gat_dir *dir; } *GAT; struct gat_dir { const char *name; int inode, drive; int files; int dirt; struct gat_file *file; }; struct gat_check { unsigned char md5[16]; }; struct gat_version { char version[40]; }; struct gat_file { const char *name; struct gat_version version; /* Version checked out */ struct gat_check check; /* Checksum as checked in */ unsigned long long time; /* mod time, unix time */ /* We do not save the flags as bit flags, we save the flags as a string. * The first character defines what type this flags are. * U is Unix filesystem type. */ char *flags; /* Urwxrwxrwx */ }; /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /* Supporting functions to external library * * Perhaps I sometimes find the time to get rid of this external * dependencies. */ /* Exit wrapper */ static void GAT_exit(GAT g, const char *s, ...) { va_list list; va_start(list, s); tino_vexit(s, list); va_end(list); } const char * GAT_escape(const char *s) { char *buf; int i, n, max; char c; n = 1; for (i=0; s[i]; i++) if (s[i]=='|' || s[i]=='`') n++; max = i+n; buf = malloc(max); for (n=0, i=0; (c=s[i])!=0; i++) { switch (c) { case '|': case '`': c--; buf[n++] = '`'; break; } tino_FATAL(n>=max); buf[n++] = c; } tino_FATAL(n>=max); buf[n] = 0; return buf; } const char * GAT_unescape(GAT g, const char *s) { char *buf; int i, max; char c; max = strlen(s)+1; buf = malloc(max); for (n=0, i=0; (c=s[i])!=0; i++) { if (c=='`') { c = s[++i]; if (!c || !++c) GAT_err(g, "illegal unescape value"); } buf[n++] = c; } tino_FATAL(n>=max); buf[n] = 0; return buf; } void GAT_log(GAT g, const char *what, const char *dir, const char *name) { if (! if (!g->logname) g->logname = tino_file_glue_path(NULL, BUFSIZ, g->gatroot, "gatlog.txt"); if ((g->logfd=fopen(g->logname, "at"))==NULL) GAT_exit(g, "cannot write to log: %s", g->logname); what = GAT_escape(what); dir = GAT_escape(dir); name = GAT_escape(name); fprintf(g->logfd, "%s|%s|%s|%s\n", what, dir, name); free(name); free(dir); free(what); if (fclose(g->logfd)) GAT_exit(g, "cannot write to log: %s", g->logname); } /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ static void gat_add(GAT g, struct gat_dir *d, const char *name) { int i; for (i=d->files; --i>=0; ) { if (!strcmp(d->file[i].name, name)) GAT_exit(g, "already known %s: %s", d->name, name); 000; } } /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ GAT GAT_init(const char *app, const char *env, const char *stdpath) { GAT g; if (!app) app = "gatclient_gen"; if (!env) env = "GATROOT"; if (!stdpath) stdpath = ".GATROOT"; g = tino_alloc(sizeof *g); memset(g, 0, sizeof *g); g->gatroot = getenv(env); if (!g->gatroot) { /* How to find out we are on Windows? * I do not like conditional compiles. */ #ifdef __CYGWIN__ g->gatroot = "/cygdrive/c/gatroot"; #else g->gatroot = tino_file_glue_path(NULL, BUFSIZ, getenv("HOME"), stdpath); #endif } if (!g->gatroot) tino_exit("cannot find repository environment, set env var %s", env); if (tino_file_notexists(g->gatroot)) { if (mkdir(g->gatroot, 0777)) GAT_exit(g, "cannot crate repository directory %s", g->gatroot); else GAT_log(g, "created", g->gatroot, ""); } if (tino_file_notdir(g->gatroot)) GAT_exit(g, "repository environment %s does not point to a directory: %s", env, g->gatroot); return g; } static void GAT_add(GAT g, const char *s) { char *dir, *file; dir = tino_file_dirname(NULL, 0, s); file = tino_file_filename(NULL, 0, s); gat_add(g, gat_dir_get(g, dir), file); free(file); free(dir); } static void GAT_flush(GAT g) { int i; for (i=0; idirs; i++) gat_flush_dir(g, g->dir+i); } /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/