home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / cvs-1.8.7-src.tgz / tar.out / fsf / cvs / src / fileattr.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  12KB  |  519 lines

  1. /* Implementation for file attribute munging features.
  2.  
  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2, or (at your option)
  6.    any later version.
  7.  
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.  
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  16.  
  17. #include "cvs.h"
  18. #include "getline.h"
  19. #include "fileattr.h"
  20. #include <assert.h>
  21.  
  22. static void fileattr_read PROTO ((void));
  23. static int writeattr_proc PROTO ((Node *, void *));
  24.  
  25. /* Where to look for CVSREP_FILEATTR.  */
  26. static char *fileattr_stored_repos;
  27.  
  28. /* The in-memory attributes.  */
  29. static List *attrlist;
  30. static char *fileattr_default_attrs;
  31. /* We have already tried to read attributes and failed in this directory
  32.    (for example, there is no CVSREP_FILEATTR file).  */
  33. static int attr_read_attempted;
  34.  
  35. /* Have the in-memory attributes been modified since we read them?  */
  36. static int attrs_modified;
  37.  
  38. /* Note that if noone calls fileattr_get, this is very cheap.  No stat(),
  39.    no open(), no nothing.  */
  40. void
  41. fileattr_startdir (repos)
  42.     char *repos;
  43. {
  44.     assert (fileattr_stored_repos == NULL);
  45.     fileattr_stored_repos = xstrdup (repos);
  46.     assert (attrlist == NULL);
  47.     attr_read_attempted = 0;
  48. }
  49.  
  50. static void
  51. fileattr_delproc (node)
  52.     Node *node;
  53. {
  54.     assert (node->data != NULL);
  55.     free (node->data);
  56.     node->data = NULL;
  57. }
  58.  
  59. /* Read all the attributes for the current directory into memory.  */
  60. static void
  61. fileattr_read ()
  62. {
  63.     char *fname;
  64.     FILE *fp;
  65.     char *line = NULL;
  66.     size_t line_len = 0;
  67.  
  68.     /* If there are no attributes, don't waste time repeatedly looking
  69.        for the CVSREP_FILEATTR file.  */
  70.     if (attr_read_attempted)
  71.     return;
  72.  
  73.     /* If NULL was passed to fileattr_startdir, then it isn't kosher to look
  74.        at attributes.  */
  75.     assert (fileattr_stored_repos != NULL);
  76.  
  77.     fname = xmalloc (strlen (fileattr_stored_repos)
  78.              + 1
  79.              + sizeof (CVSREP_FILEATTR)
  80.              + 1);
  81.  
  82.     strcpy (fname, fileattr_stored_repos);
  83.     strcat (fname, "/");
  84.     strcat (fname, CVSREP_FILEATTR);
  85.  
  86.     attr_read_attempted = 1;
  87.     fp = CVS_FOPEN (fname, FOPEN_BINARY_READ);
  88.     if (fp == NULL)
  89.     {
  90.     if (!existence_error (errno))
  91.         error (0, errno, "cannot read %s", fname);
  92.     free (fname);
  93.     return;
  94.     }
  95.     attrlist = getlist ();
  96.     while (1) {
  97.     int nread;
  98.     nread = getline (&line, &line_len, fp);
  99.     if (nread < 0)
  100.         break;
  101.     /* Remove trailing newline.  */
  102.     line[nread - 1] = '\0';
  103.     if (line[0] == 'F')
  104.     {
  105.         char *p;
  106.         Node *newnode;
  107.  
  108.         p = strchr (line, '\t');
  109.         *p++ = '\0';
  110.         newnode = getnode ();
  111.         newnode->type = FILEATTR;
  112.         newnode->delproc = fileattr_delproc;
  113.         newnode->key = xstrdup (line + 1);
  114.         newnode->data = xstrdup (p);
  115.         addnode (attrlist, newnode);
  116.     }
  117.     else if (line[0] == 'D')
  118.     {
  119.         char *p;
  120.         /* Currently nothing to skip here, but for future expansion,
  121.            ignore anything located here.  */
  122.         p = strchr (line, '\t');
  123.         ++p;
  124.         fileattr_default_attrs = xstrdup (p);
  125.     }
  126.     /* else just ignore the line, for future expansion.  */
  127.     }
  128.     if (ferror (fp))
  129.     error (0, errno, "cannot read %s", fname);
  130.     if (line != NULL)
  131.     free (line);
  132.     if (fclose (fp) < 0)
  133.     error (0, errno, "cannot close %s", fname);
  134.     attrs_modified = 0;
  135.     free (fname);
  136. }
  137.  
  138. char *
  139. fileattr_get (filename, attrname)
  140.     const char *filename;
  141.     const char *attrname;
  142. {
  143.     Node *node;
  144.     size_t attrname_len = strlen (attrname);
  145.     char *p;
  146.  
  147.     if (attrlist == NULL)
  148.     fileattr_read ();
  149.     if (attrlist == NULL)
  150.     /* Either nothing has any attributes, or fileattr_read already printed
  151.        an error message.  */
  152.     return NULL;
  153.  
  154.     if (filename == NULL)
  155.     p = fileattr_default_attrs;
  156.     else
  157.     {
  158.     node = findnode (attrlist, filename);
  159.     if (node == NULL)
  160.         /* A file not mentioned has no attributes.  */
  161.         return NULL;
  162.     p = node->data;
  163.     }
  164.     while (p)
  165.     {
  166.     if (strncmp (attrname, p, attrname_len) == 0
  167.         && p[attrname_len] == '=')
  168.     {
  169.         /* Found it.  */
  170.         return p + attrname_len + 1;
  171.     }
  172.     p = strchr (p, ';');
  173.     if (p == NULL)
  174.         break;
  175.     ++p;
  176.     }
  177.     /* The file doesn't have this attribute.  */
  178.     return NULL;
  179. }
  180.  
  181. char *
  182. fileattr_get0 (filename, attrname)
  183.     const char *filename;
  184.     const char *attrname;
  185. {
  186.     char *cp;
  187.     char *cpend;
  188.     char *retval;
  189.  
  190.     cp = fileattr_get (filename, attrname);
  191.     if (cp == NULL)
  192.     return NULL;
  193.     cpend = strchr (cp, ';');
  194.     if (cpend == NULL)
  195.     cpend = cp + strlen (cp);
  196.     retval = xmalloc (cpend - cp + 1);
  197.     strncpy (retval, cp, cpend - cp);
  198.     retval[cpend - cp] = '\0';
  199.     return retval;
  200. }
  201.  
  202. char *
  203. fileattr_modify (list, attrname, attrval, namevalsep, entsep)
  204.     char *list;
  205.     const char *attrname;
  206.     const char *attrval;
  207.     int namevalsep;
  208.     int entsep;
  209. {
  210.     char *retval;
  211.     char *rp;
  212.     size_t attrname_len = strlen (attrname);
  213.  
  214.     /* Portion of list before the attribute to be replaced.  */
  215.     char *pre;
  216.     char *preend;
  217.     /* Portion of list after the attribute to be replaced.  */
  218.     char *post;
  219.  
  220.     char *p;
  221.     char *p2;
  222.  
  223.     p = list;
  224.     pre = list;
  225.     preend = NULL;
  226.     /* post is NULL unless set otherwise.  */
  227.     post = NULL;
  228.     p2 = NULL;
  229.     if (list != NULL)
  230.     {
  231.     while (1) {
  232.         p2 = strchr (p, entsep);
  233.         if (p2 == NULL)
  234.         {
  235.         p2 = p + strlen (p);
  236.         if (preend == NULL)
  237.             preend = p2;
  238.         }
  239.         else
  240.         ++p2;
  241.         if (strncmp (attrname, p, attrname_len) == 0
  242.         && p[attrname_len] == namevalsep)
  243.         {
  244.         /* Found it.  */
  245.         preend = p;
  246.         if (preend > list)
  247.             /* Don't include the preceding entsep.  */
  248.             --preend;
  249.  
  250.         post = p2;
  251.         }
  252.         if (p2[0] == '\0')
  253.         break;
  254.         p = p2;
  255.     }
  256.     }
  257.     if (post == NULL)
  258.     post = p2;
  259.  
  260.     if (preend == pre && attrval == NULL && post == p2)
  261.     return NULL;
  262.  
  263.     retval = xmalloc ((preend - pre)
  264.               + 1
  265.               + (attrval == NULL ? 0 : (attrname_len + 1
  266.                         + strlen (attrval)))
  267.               + 1
  268.               + (p2 - post)
  269.               + 1);
  270.     if (preend != pre)
  271.     {
  272.     strncpy (retval, pre, preend - pre);
  273.     rp = retval + (preend - pre);
  274.     if (attrval != NULL)
  275.         *rp++ = entsep;
  276.     *rp = '\0';
  277.     }
  278.     else
  279.     retval[0] = '\0';
  280.     if (attrval != NULL)
  281.     {
  282.     strcat (retval, attrname);
  283.     rp = retval + strlen (retval);
  284.     *rp++ = namevalsep;
  285.     strcpy (rp, attrval);
  286.     }
  287.     if (post != p2)
  288.     {
  289.     rp = retval + strlen (retval);
  290.     if (preend != pre || attrval != NULL)
  291.         *rp++ = entsep;
  292.     strncpy (rp, post, p2 - post);
  293.     rp += p2 - post;
  294.     *rp = '\0';
  295.     }
  296.     return retval;
  297. }
  298.  
  299. void
  300. fileattr_set (filename, attrname, attrval)
  301.     const char *filename;
  302.     const char *attrname;
  303.     const char *attrval;
  304. {
  305.     Node *node;
  306.     char *p;
  307.  
  308.     attrs_modified = 1;
  309.  
  310.     if (filename == NULL)
  311.     {
  312.     p = fileattr_modify (fileattr_default_attrs, attrname, attrval,
  313.                  '=', ';');
  314.     if (fileattr_default_attrs != NULL)
  315.         free (fileattr_default_attrs);
  316.     fileattr_default_attrs = p;
  317.     return;
  318.     }
  319.     if (attrlist == NULL)
  320.     fileattr_read ();
  321.     if (attrlist == NULL)
  322.     {
  323.     /* Not sure this is a graceful way to handle things
  324.        in the case where fileattr_read was unable to read the file.  */
  325.         /* No attributes existed previously.  */
  326.     attrlist = getlist ();
  327.     }
  328.  
  329.     node = findnode (attrlist, filename);
  330.     if (node == NULL)
  331.     {
  332.     if (attrval == NULL)
  333.         /* Attempt to remove an attribute which wasn't there.  */
  334.         return;
  335.  
  336.     /* First attribute for this file.  */
  337.     node = getnode ();
  338.     node->type = FILEATTR;
  339.     node->delproc = fileattr_delproc;
  340.     node->key = xstrdup (filename);
  341.     node->data = xmalloc (strlen (attrname) + 1 + strlen (attrval) + 1);
  342.     strcpy (node->data, attrname);
  343.     strcat (node->data, "=");
  344.     strcat (node->data, attrval);
  345.     addnode (attrlist, node);
  346.     }
  347.  
  348.     p = fileattr_modify (node->data, attrname, attrval, '=', ';');
  349.     if (p == NULL)
  350.     delnode (node);
  351.     else
  352.     {
  353.     free (node->data);
  354.     node->data = p;
  355.     }
  356. }
  357.  
  358. void
  359. fileattr_newfile (filename)
  360.     const char *filename;
  361. {
  362.     Node *node;
  363.  
  364.     if (attrlist == NULL)
  365.     fileattr_read ();
  366.  
  367.     if (fileattr_default_attrs == NULL)
  368.     return;
  369.  
  370.     if (attrlist == NULL)
  371.     {
  372.     /* Not sure this is a graceful way to handle things
  373.        in the case where fileattr_read was unable to read the file.  */
  374.         /* No attributes existed previously.  */
  375.     attrlist = getlist ();
  376.     }
  377.  
  378.     node = getnode ();
  379.     node->type = FILEATTR;
  380.     node->delproc = fileattr_delproc;
  381.     node->key = xstrdup (filename);
  382.     node->data = xstrdup (fileattr_default_attrs);
  383.     addnode (attrlist, node);
  384.     attrs_modified = 1;
  385. }
  386.  
  387. static int
  388. writeattr_proc (node, data)
  389.     Node *node;
  390.     void *data;
  391. {
  392.     FILE *fp = (FILE *)data;
  393.     fputs ("F", fp);
  394.     fputs (node->key, fp);
  395.     fputs ("\t", fp);
  396.     fputs (node->data, fp);
  397.     fputs ("\012", fp);
  398.     return 0;
  399. }
  400.  
  401. void
  402. fileattr_write ()
  403. {
  404.     FILE *fp;
  405.     char *fname;
  406.     mode_t omask;
  407.  
  408.     if (!attrs_modified)
  409.     return;
  410.  
  411.     if (noexec)
  412.     return;
  413.  
  414.     /* If NULL was passed to fileattr_startdir, then it isn't kosher to set
  415.        attributes.  */
  416.     assert (fileattr_stored_repos != NULL);
  417.  
  418.     fname = xmalloc (strlen (fileattr_stored_repos)
  419.              + 1
  420.              + sizeof (CVSREP_FILEATTR)
  421.              + 1);
  422.  
  423.     strcpy (fname, fileattr_stored_repos);
  424.     strcat (fname, "/");
  425.     strcat (fname, CVSREP_FILEATTR);
  426.  
  427.     if (list_isempty (attrlist) && fileattr_default_attrs == NULL)
  428.     {
  429.     /* There are no attributes.  */
  430.     if (unlink_file (fname) < 0)
  431.     {
  432.         if (!existence_error (errno))
  433.         {
  434.         error (0, errno, "cannot remove %s", fname);
  435.         }
  436.     }
  437.  
  438.     /* Now remove CVSREP directory, if empty.  The main reason we bother
  439.        is that CVS 1.6 and earlier will choke if a CVSREP directory
  440.        exists, so provide the user a graceful way to remove it.  */
  441.     strcpy (fname, fileattr_stored_repos);
  442.     strcat (fname, "/");
  443.     strcat (fname, CVSREP);
  444.     if (CVS_RMDIR (fname) < 0)
  445.     {
  446.         if (errno != ENOTEMPTY
  447.  
  448.         /* Don't know why we would be here if there is no CVSREP
  449.            directory, but it seemed to be happening anyway, so
  450.            check for it.  */
  451.         && !existence_error (errno))
  452.         error (0, errno, "cannot remove %s", fname);
  453.     }
  454.  
  455.     free (fname);
  456.     return;
  457.     }
  458.  
  459.     omask = umask (cvsumask);
  460.     fp = CVS_FOPEN (fname, FOPEN_BINARY_WRITE);
  461.     if (fp == NULL)
  462.     {
  463.     if (existence_error (errno))
  464.     {
  465.         /* Maybe the CVSREP directory doesn't exist.  Try creating it.  */
  466.         char *repname;
  467.  
  468.         repname = xmalloc (strlen (fileattr_stored_repos)
  469.                    + 1
  470.                    + sizeof (CVSREP)
  471.                    + 1);
  472.         strcpy (repname, fileattr_stored_repos);
  473.         strcat (repname, "/");
  474.         strcat (repname, CVSREP);
  475.  
  476.         if (CVS_MKDIR (repname, 0777) < 0 && errno != EEXIST)
  477.         {
  478.         error (0, errno, "cannot make directory %s", repname);
  479.         (void) umask (omask);
  480.         free (repname);
  481.         return;
  482.         }
  483.         free (repname);
  484.  
  485.         fp = CVS_FOPEN (fname, FOPEN_BINARY_WRITE);
  486.     }
  487.     if (fp == NULL)
  488.     {
  489.         error (0, errno, "cannot write %s", fname);
  490.         (void) umask (omask);
  491.         return;
  492.     }
  493.     }
  494.     (void) umask (omask);
  495.     walklist (attrlist, writeattr_proc, fp);
  496.     if (fileattr_default_attrs != NULL)
  497.     {
  498.     fputs ("D\t", fp);
  499.     fputs (fileattr_default_attrs, fp);
  500.     fputs ("\012", fp);
  501.     }
  502.     if (fclose (fp) < 0)
  503.     error (0, errno, "cannot close %s", fname);
  504.     attrs_modified = 0;
  505.     free (fname);
  506. }
  507.  
  508. void
  509. fileattr_free ()
  510. {
  511.     dellist (&attrlist);
  512.     if (fileattr_stored_repos != NULL)
  513.     free (fileattr_stored_repos);
  514.     fileattr_stored_repos = NULL;
  515.     if (fileattr_default_attrs != NULL)
  516.     free (fileattr_default_attrs);
  517.     fileattr_default_attrs = NULL;
  518. }
  519.