#include "cvs.h"
#include "getline.h"
#include "fileattr.h"
#include <assert.h>
static void fileattr_read PROTO ((void));
static int writeattr_proc PROTO ((Node *, void *));
static char *fileattr_stored_repos;
static List *attrlist;
static char *fileattr_default_attrs;
static int attr_read_attempted;
static int attrs_modified;
struct unrecog {
char *line;
struct unrecog *next;
};
static struct unrecog *unrecog_head;
void
fileattr_startdir (repos)
char *repos;
{
assert (fileattr_stored_repos == NULL);
fileattr_stored_repos = xstrdup (repos);
assert (attrlist == NULL);
attr_read_attempted = 0;
assert (unrecog_head == NULL);
}
static void
fileattr_delproc (node)
Node *node;
{
assert (node->data != NULL);
free (node->data);
node->data = NULL;
}
static void
fileattr_read ()
{
char *fname;
FILE *fp;
char *line = NULL;
size_t line_len = 0;
if (attr_read_attempted)
return;
assert (fileattr_stored_repos != NULL);
fname = xmalloc (strlen (fileattr_stored_repos)
+ 1
+ sizeof (CVSREP_FILEATTR)
+ 1);
strcpy (fname, fileattr_stored_repos);
strcat (fname, "/");
strcat (fname, CVSREP_FILEATTR);
attr_read_attempted = 1;
fp = CVS_FOPEN (fname, FOPEN_BINARY_READ);
if (fp == NULL)
{
if (!existence_error (errno))
error (0, errno, "cannot read %s", fname);
free (fname);
return;
}
attrlist = getlist ();
while (1) {
int nread;
nread = getline (&line, &line_len, fp);
if (nread < 0)
break;
line[nread - 1] = '\0';
if (line[0] == 'F')
{
char *p;
Node *newnode;
p = strchr (line, '\t');
if (p == NULL)
error (1, 0,
"file attribute database corruption: tab missing in %s",
fname);
*p++ = '\0';
newnode = getnode ();
newnode->type = FILEATTR;
newnode->delproc = fileattr_delproc;
newnode->key = xstrdup (line + 1);
newnode->data = xstrdup (p);
if (addnode (attrlist, newnode) != 0)
free (newnode);
}
else if (line[0] == 'D')
{
char *p;
p = strchr (line, '\t');
if (p == NULL)
error (1, 0,
"file attribute database corruption: tab missing in %s",
fname);
++p;
fileattr_default_attrs = xstrdup (p);
}
else
{
struct unrecog *new;
new = (struct unrecog *) xmalloc (sizeof (struct unrecog));
new->line = xstrdup (line);
new->next = unrecog_head;
unrecog_head = new;
}
}
if (ferror (fp))
error (0, errno, "cannot read %s", fname);
if (line != NULL)
free (line);
if (fclose (fp) < 0)
error (0, errno, "cannot close %s", fname);
attrs_modified = 0;
free (fname);
}
char *
fileattr_get (filename, attrname)
const char *filename;
const char *attrname;
{
Node *node;
size_t attrname_len = strlen (attrname);
char *p;
if (attrlist == NULL)
fileattr_read ();
if (attrlist == NULL)
return NULL;
if (filename == NULL)
p = fileattr_default_attrs;
else
{
node = findnode (attrlist, filename);
if (node == NULL)
return NULL;
p = node->data;
}
while (p)
{
if (strncmp (attrname, p, attrname_len) == 0
&& p[attrname_len] == '=')
{
return p + attrname_len + 1;
}
p = strchr (p, ';');
if (p == NULL)
break;
++p;
}
return NULL;
}
char *
fileattr_get0 (filename, attrname)
const char *filename;
const char *attrname;
{
char *cp;
char *cpend;
char *retval;
cp = fileattr_get (filename, attrname);
if (cp == NULL)
return NULL;
cpend = strchr (cp, ';');
if (cpend == NULL)
cpend = cp + strlen (cp);
retval = xmalloc (cpend - cp + 1);
strncpy (retval, cp, cpend - cp);
retval[cpend - cp] = '\0';
return retval;
}
char *
fileattr_modify (list, attrname, attrval, namevalsep, entsep)
char *list;
const char *attrname;
const char *attrval;
int namevalsep;
int entsep;
{
char *retval;
char *rp;
size_t attrname_len = strlen (attrname);
char *pre;
char *preend;
char *post;
char *p;
char *p2;
p = list;
pre = list;
preend = NULL;
post = NULL;
p2 = NULL;
if (list != NULL)
{
while (1) {
p2 = strchr (p, entsep);
if (p2 == NULL)
{
p2 = p + strlen (p);
if (preend == NULL)
preend = p2;
}
else
++p2;
if (strncmp (attrname, p, attrname_len) == 0
&& p[attrname_len] == namevalsep)
{
preend = p;
if (preend > list)
--preend;
post = p2;
}
if (p2[0] == '\0')
break;
p = p2;
}
}
if (post == NULL)
post = p2;
if (preend == pre && attrval == NULL && post == p2)
return NULL;
retval = xmalloc ((preend - pre)
+ 1
+ (attrval == NULL ? 0 : (attrname_len + 1
+ strlen (attrval)))
+ 1
+ (p2 - post)
+ 1);
if (preend != pre)
{
strncpy (retval, pre, preend - pre);
rp = retval + (preend - pre);
if (attrval != NULL)
*rp++ = entsep;
*rp = '\0';
}
else
retval[0] = '\0';
if (attrval != NULL)
{
strcat (retval, attrname);
rp = retval + strlen (retval);
*rp++ = namevalsep;
strcpy (rp, attrval);
}
if (post != p2)
{
rp = retval + strlen (retval);
if (preend != pre || attrval != NULL)
*rp++ = entsep;
strncpy (rp, post, p2 - post);
rp += p2 - post;
*rp = '\0';
}
return retval;
}
void
fileattr_set (filename, attrname, attrval)
const char *filename;
const char *attrname;
const char *attrval;
{
Node *node;
char *p;
if (filename == NULL)
{
p = fileattr_modify (fileattr_default_attrs, attrname, attrval,
'=', ';');
if (fileattr_default_attrs != NULL)
free (fileattr_default_attrs);
fileattr_default_attrs = p;
attrs_modified = 1;
return;
}
if (attrlist == NULL)
fileattr_read ();
if (attrlist == NULL)
{
attrlist = getlist ();
}
node = findnode (attrlist, filename);
if (node == NULL)
{
if (attrval == NULL)
return;
node = getnode ();
node->type = FILEATTR;
node->delproc = fileattr_delproc;
node->key = xstrdup (filename);
node->data = xmalloc (strlen (attrname) + 1 + strlen (attrval) + 1);
strcpy (node->data, attrname);
strcat (node->data, "=");
strcat (node->data, attrval);
addnode (attrlist, node);
}
p = fileattr_modify (node->data, attrname, attrval, '=', ';');
if (p == NULL)
delnode (node);
else
{
free (node->data);
node->data = p;
}
attrs_modified = 1;
}
char *
fileattr_getall (filename)
const char *filename;
{
Node *node;
char *p;
if (attrlist == NULL)
fileattr_read ();
if (attrlist == NULL)
return NULL;
if (filename == NULL)
p = fileattr_default_attrs;
else
{
node = findnode (attrlist, filename);
if (node == NULL)
return NULL;
p = node->data;
}
return xstrdup (p);
}
void
fileattr_setall (filename, attrs)
const char *filename;
const char *attrs;
{
Node *node;
if (filename == NULL)
{
if (fileattr_default_attrs != NULL)
free (fileattr_default_attrs);
fileattr_default_attrs = xstrdup (attrs);
attrs_modified = 1;
return;
}
if (attrlist == NULL)
fileattr_read ();
if (attrlist == NULL)
{
attrlist = getlist ();
}
node = findnode (attrlist, filename);
if (node == NULL)
{
if (attrs != NULL)
{
node = getnode ();
node->type = FILEATTR;
node->delproc = fileattr_delproc;
node->key = xstrdup (filename);
node->data = xstrdup (attrs);
addnode (attrlist, node);
}
}
else
{
if (attrs == NULL)
delnode (node);
else
{
free (node->data);
node->data = xstrdup (attrs);
}
}
attrs_modified = 1;
}
void
fileattr_newfile (filename)
const char *filename;
{
Node *node;
if (attrlist == NULL)
fileattr_read ();
if (fileattr_default_attrs == NULL)
return;
if (attrlist == NULL)
{
attrlist = getlist ();
}
node = getnode ();
node->type = FILEATTR;
node->delproc = fileattr_delproc;
node->key = xstrdup (filename);
node->data = xstrdup (fileattr_default_attrs);
addnode (attrlist, node);
attrs_modified = 1;
}
static int
writeattr_proc (node, data)
Node *node;
void *data;
{
FILE *fp = (FILE *)data;
fputs ("F", fp);
fputs (node->key, fp);
fputs ("\t", fp);
fputs (node->data, fp);
fputs ("\012", fp);
return 0;
}
void
fileattr_write ()
{
FILE *fp;
char *fname;
mode_t omask;
if (!attrs_modified)
return;
if (noexec)
return;
assert (fileattr_stored_repos != NULL);
fname = xmalloc (strlen (fileattr_stored_repos)
+ 1
+ sizeof (CVSREP_FILEATTR)
+ 1);
strcpy (fname, fileattr_stored_repos);
strcat (fname, "/");
strcat (fname, CVSREP_FILEATTR);
if (list_isempty (attrlist)
&& fileattr_default_attrs == NULL
&& unrecog_head == NULL)
{
if (unlink_file (fname) < 0)
{
if (!existence_error (errno))
{
error (0, errno, "cannot remove %s", fname);
}
}
strcpy (fname, fileattr_stored_repos);
strcat (fname, "/");
strcat (fname, CVSREP);
if (CVS_RMDIR (fname) < 0)
{
if (errno != ENOTEMPTY
&& !existence_error (errno))
error (0, errno, "cannot remove %s", fname);
}
free (fname);
return;
}
omask = umask (cvsumask);
fp = CVS_FOPEN (fname, FOPEN_BINARY_WRITE);
if (fp == NULL)
{
if (existence_error (errno))
{
char *repname;
repname = xmalloc (strlen (fileattr_stored_repos)
+ 1
+ sizeof (CVSREP)
+ 1);
strcpy (repname, fileattr_stored_repos);
strcat (repname, "/");
strcat (repname, CVSREP);
if (CVS_MKDIR (repname, 0777) < 0 && errno != EEXIST)
{
error (0, errno, "cannot make directory %s", repname);
(void) umask (omask);
free (repname);
return;
}
free (repname);
fp = CVS_FOPEN (fname, FOPEN_BINARY_WRITE);
}
if (fp == NULL)
{
error (0, errno, "cannot write %s", fname);
(void) umask (omask);
return;
}
}
(void) umask (omask);
walklist (attrlist, writeattr_proc, fp);
if (fileattr_default_attrs != NULL)
{
fputs ("D\t", fp);
fputs (fileattr_default_attrs, fp);
fputs ("\012", fp);
}
while (unrecog_head != NULL)
{
struct unrecog *p;
p = unrecog_head;
fputs (p->line, fp);
fputs ("\012", fp);
unrecog_head = p->next;
free (p->line);
free (p);
}
if (fclose (fp) < 0)
error (0, errno, "cannot close %s", fname);
attrs_modified = 0;
free (fname);
}
void
fileattr_free ()
{
dellist (&attrlist);
if (fileattr_stored_repos != NULL)
free (fileattr_stored_repos);
fileattr_stored_repos = NULL;
if (fileattr_default_attrs != NULL)
free (fileattr_default_attrs);
fileattr_default_attrs = NULL;
}