diff options
author | peter <peter@FreeBSD.org> | 1996-08-20 23:46:10 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1996-08-20 23:46:10 +0000 |
commit | 8982e501c77217c860f79bba431f46a62b607a21 (patch) | |
tree | 70187fdf5be4cbefd0baf46bddac7e5e32c13c24 /contrib/cvs/src/fileattr.c | |
parent | 01ee40fd6a76f6ff7ef247fc1b2cf6e337f216c5 (diff) | |
download | FreeBSD-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.c | 517 |
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; +} |