summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/fileattr.c
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1996-08-20 23:46:10 +0000
committerpeter <peter@FreeBSD.org>1996-08-20 23:46:10 +0000
commit8982e501c77217c860f79bba431f46a62b607a21 (patch)
tree70187fdf5be4cbefd0baf46bddac7e5e32c13c24 /contrib/cvs/src/fileattr.c
parent01ee40fd6a76f6ff7ef247fc1b2cf6e337f216c5 (diff)
downloadFreeBSD-src-8982e501c77217c860f79bba431f46a62b607a21.zip
FreeBSD-src-8982e501c77217c860f79bba431f46a62b607a21.tar.gz
Import of slightly trimmed cvs-1.8 distribution. Generated files
and non-unix code has been left out.
Diffstat (limited to 'contrib/cvs/src/fileattr.c')
-rw-r--r--contrib/cvs/src/fileattr.c517
1 files changed, 517 insertions, 0 deletions
diff --git a/contrib/cvs/src/fileattr.c b/contrib/cvs/src/fileattr.c
new file mode 100644
index 0000000..827c69c
--- /dev/null
+++ b/contrib/cvs/src/fileattr.c
@@ -0,0 +1,517 @@
+/* Implementation for file attribute munging features.
+
+ 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#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 *));
+
+/* Where to look for CVSREP_FILEATTR. */
+static char *fileattr_stored_repos;
+
+/* The in-memory attributes. */
+static List *attrlist;
+static char *fileattr_default_attrs;
+/* We have already tried to read attributes and failed in this directory
+ (for example, there is no CVSREP_FILEATTR file). */
+static int attr_read_attempted;
+
+/* Have the in-memory attributes been modified since we read them? */
+static int attrs_modified;
+
+/* Note that if noone calls fileattr_get, this is very cheap. No stat(),
+ no open(), no nothing. */
+void
+fileattr_startdir (repos)
+ char *repos;
+{
+ assert (fileattr_stored_repos == NULL);
+ fileattr_stored_repos = xstrdup (repos);
+ assert (attrlist == NULL);
+ attr_read_attempted = 0;
+}
+
+static void
+fileattr_delproc (node)
+ Node *node;
+{
+ assert (node->data != NULL);
+ free (node->data);
+ node->data = NULL;
+}
+
+/* Read all the attributes for the current directory into memory. */
+static void
+fileattr_read ()
+{
+ char *fname;
+ FILE *fp;
+ char *line = NULL;
+ size_t line_len = 0;
+
+ /* If there are no attributes, don't waste time repeatedly looking
+ for the CVSREP_FILEATTR file. */
+ if (attr_read_attempted)
+ return;
+
+ /* If NULL was passed to fileattr_startdir, then it isn't kosher to look
+ at attributes. */
+ 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 = 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;
+ /* Remove trailing newline. */
+ line[nread - 1] = '\0';
+ if (line[0] == 'F')
+ {
+ char *p;
+ Node *newnode;
+
+ p = strchr (line, '\t');
+ *p++ = '\0';
+ newnode = getnode ();
+ newnode->type = FILEATTR;
+ newnode->delproc = fileattr_delproc;
+ newnode->key = xstrdup (line + 1);
+ newnode->data = xstrdup (p);
+ addnode (attrlist, newnode);
+ }
+ else if (line[0] == 'D')
+ {
+ char *p;
+ /* Currently nothing to skip here, but for future expansion,
+ ignore anything located here. */
+ p = strchr (line, '\t');
+ ++p;
+ fileattr_default_attrs = xstrdup (p);
+ }
+ /* else just ignore the line, for future expansion. */
+ }
+ 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)
+ char *filename;
+ char *attrname;
+{
+ Node *node;
+ size_t attrname_len = strlen (attrname);
+ char *p;
+
+ if (attrlist == NULL)
+ fileattr_read ();
+ if (attrlist == NULL)
+ /* Either nothing has any attributes, or fileattr_read already printed
+ an error message. */
+ return NULL;
+
+ if (filename == NULL)
+ p = fileattr_default_attrs;
+ else
+ {
+ node = findnode (attrlist, filename);
+ if (node == NULL)
+ /* A file not mentioned has no attributes. */
+ return NULL;
+ p = node->data;
+ }
+ while (p)
+ {
+ if (strncmp (attrname, p, attrname_len) == 0
+ && p[attrname_len] == '=')
+ {
+ /* Found it. */
+ return p + attrname_len + 1;
+ }
+ p = strchr (p, ';');
+ if (p == NULL)
+ break;
+ ++p;
+ }
+ /* The file doesn't have this attribute. */
+ return NULL;
+}
+
+char *
+fileattr_get0 (filename, attrname)
+ char *filename;
+ 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;
+ char *attrname;
+ char *attrval;
+ int namevalsep;
+ int entsep;
+{
+ char *retval;
+ char *rp;
+ size_t attrname_len = strlen (attrname);
+
+ /* Portion of list before the attribute to be replaced. */
+ char *pre;
+ char *preend;
+ /* Portion of list after the attribute to be replaced. */
+ char *post;
+
+ char *p;
+ char *p2;
+
+ p = list;
+ pre = list;
+ preend = NULL;
+ /* post is NULL unless set otherwise. */
+ 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)
+ {
+ /* Found it. */
+ preend = p;
+ if (preend > list)
+ /* Don't include the preceding entsep. */
+ --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)
+ char *filename;
+ char *attrname;
+ char *attrval;
+{
+ Node *node;
+ char *p;
+
+ attrs_modified = 1;
+
+ if (filename == NULL)
+ {
+ p = fileattr_modify (fileattr_default_attrs, attrname, attrval,
+ '=', ';');
+ if (fileattr_default_attrs != NULL)
+ free (fileattr_default_attrs);
+ fileattr_default_attrs = p;
+ return;
+ }
+ if (attrlist == NULL)
+ fileattr_read ();
+ if (attrlist == NULL)
+ {
+ /* Not sure this is a graceful way to handle things
+ in the case where fileattr_read was unable to read the file. */
+ /* No attributes existed previously. */
+ attrlist = getlist ();
+ }
+
+ node = findnode (attrlist, filename);
+ if (node == NULL)
+ {
+ if (attrval == NULL)
+ /* Attempt to remove an attribute which wasn't there. */
+ return;
+
+ /* First attribute for this file. */
+ 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, '=', ';');
+ free (node->data);
+ node->data = NULL;
+ if (p == NULL)
+ delnode (node);
+ else
+ node->data = p;
+}
+
+void
+fileattr_newfile (filename)
+ char *filename;
+{
+ Node *node;
+
+ if (attrlist == NULL)
+ fileattr_read ();
+
+ if (fileattr_default_attrs == NULL)
+ return;
+
+ if (attrlist == NULL)
+ {
+ /* Not sure this is a graceful way to handle things
+ in the case where fileattr_read was unable to read the file. */
+ /* No attributes existed previously. */
+ 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;
+
+ /* If NULL was passed to fileattr_startdir, then it isn't kosher to set
+ attributes. */
+ 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)
+ {
+ /* There are no attributes. */
+ if (unlink_file (fname) < 0)
+ {
+ if (!existence_error (errno))
+ {
+ error (0, errno, "cannot remove %s", fname);
+ }
+ }
+
+ /* Now remove CVSREP directory, if empty. The main reason we bother
+ is that CVS 1.6 and earlier will choke if a CVSREP directory
+ exists, so provide the user a graceful way to remove it. */
+ strcpy (fname, fileattr_stored_repos);
+ strcat (fname, "/");
+ strcat (fname, CVSREP);
+ if (rmdir (fname) < 0)
+ {
+ if (errno != ENOTEMPTY
+
+ /* Don't know why we would be here if there is no CVSREP
+ directory, but it seemed to be happening anyway, so
+ check for it. */
+ && !existence_error (errno))
+ error (0, errno, "cannot remove %s", fname);
+ }
+
+ free (fname);
+ return;
+ }
+
+ omask = umask (cvsumask);
+ fp = fopen (fname, FOPEN_BINARY_WRITE);
+ if (fp == NULL)
+ {
+ if (existence_error (errno))
+ {
+ /* Maybe the CVSREP directory doesn't exist. Try creating it. */
+ 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 = 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);
+ }
+ 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;
+}
OpenPOWER on IntegriCloud