home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / cvs-1.8 / cvs-1 / cvs-1.8.1 / src / add.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-06  |  12.7 KB  |  515 lines

  1. /*
  2.  * Copyright (c) 1992, Brian Berliner and Jeff Polk
  3.  * Copyright (c) 1989-1992, Brian Berliner
  4.  * 
  5.  * You may distribute under the terms of the GNU General Public License as
  6.  * specified in the README file that comes with the CVS 1.4 kit.
  7.  * 
  8.  * Add
  9.  * 
  10.  * Adds a file or directory to the RCS source repository.  For a file,
  11.  * the entry is marked as "needing to be added" in the user's own CVS
  12.  * directory, and really added to the repository when it is committed.
  13.  * For a directory, it is added at the appropriate place in the source
  14.  * repository and a CVS directory is generated within the directory.
  15.  * 
  16.  * The -m option is currently the only supported option.  Some may wish to
  17.  * supply standard "rcs" options here, but I've found that this causes more
  18.  * trouble than anything else.
  19.  * 
  20.  * The user files or directories must already exist.  For a directory, it must
  21.  * not already have a CVS file in it.
  22.  * 
  23.  * An "add" on a file that has been "remove"d but not committed will cause the
  24.  * file to be resurrected.
  25.  */
  26.  
  27. #include "cvs.h"
  28. #include "savecwd.h"
  29.  
  30. static int add_directory PROTO((char *repository, char *dir));
  31. static int build_entry PROTO((char *repository, char *user, char *options,
  32.                 char *message, List * entries, char *tag));
  33.  
  34. static const char *const add_usage[] =
  35. {
  36.     "Usage: %s %s [-k rcs-kflag] [-m message] files...\n",
  37.     "\t-k\tUse \"rcs-kflag\" to add the file with the specified kflag.\n",
  38.     "\t-m\tUse \"message\" for the creation log.\n",
  39.     NULL
  40. };
  41.  
  42. int
  43. add (argc, argv)
  44.     int argc;
  45.     char **argv;
  46. {
  47.     char *message = NULL;
  48.     char *user;
  49.     int i;
  50.     char *repository;
  51.     int c;
  52.     int err = 0;
  53.     int added_files = 0;
  54.     char *options = NULL;
  55.     List *entries;
  56.     Vers_TS *vers;
  57.  
  58.     if (argc == 1 || argc == -1)
  59.     usage (add_usage);
  60.  
  61.     wrap_setup ();
  62.  
  63.     /* parse args */
  64.     optind = 1;
  65.     while ((c = getopt (argc, argv, "k:m:")) != -1)
  66.     {
  67.     switch (c)
  68.     {
  69.         case 'k':
  70.         if (options)
  71.             free (options);
  72.         options = RCS_check_kflag (optarg);
  73.         break;
  74.  
  75.         case 'm':
  76.         message = xstrdup (optarg);
  77.         break;
  78.         case '?':
  79.         default:
  80.         usage (add_usage);
  81.         break;
  82.     }
  83.     }
  84.     argc -= optind;
  85.     argv += optind;
  86.  
  87.     if (argc <= 0)
  88.     usage (add_usage);
  89.  
  90.     /* find the repository associated with our current dir */
  91.     repository = Name_Repository ((char *) NULL, (char *) NULL);
  92.  
  93. #ifdef CLIENT_SUPPORT
  94.     if (client_active)
  95.       {
  96.     int i;
  97.     start_server ();
  98.     ign_setup ();
  99.     if (options) send_arg(options);
  100.     option_with_arg ("-m", message);
  101.     for (i = 0; i < argc; ++i)
  102.       /* FIXME: Does this erroneously call Create_Admin in error
  103.          conditions which are only detected once the server gets its
  104.          hands on things?  */
  105.       if (isdir (argv[i]))
  106.         {
  107.           char *tag;
  108.           char *date;
  109.           char *rcsdir = xmalloc (strlen (repository)
  110.                       + strlen (argv[i]) + 10);
  111.  
  112.           /* before we do anything else, see if we have any
  113.          per-directory tags */
  114.           ParseTag (&tag, &date);
  115.  
  116.           sprintf (rcsdir, "%s/%s", repository, argv[i]);
  117.  
  118.           Create_Admin (argv[i], argv[i], rcsdir, tag, date);
  119.  
  120.           if (tag)
  121.         free (tag);
  122.           if (date)
  123.         free (date);
  124.           free (rcsdir);
  125.         }
  126.     send_file_names (argc, argv, SEND_EXPAND_WILD);
  127.     send_files (argc, argv, 0, 0);
  128.     send_to_server ("add\012", 0);
  129.     return get_responses_and_close ();
  130.       }
  131. #endif
  132.  
  133.     entries = Entries_Open (0);
  134.  
  135.     /* walk the arg list adding files/dirs */
  136.     for (i = 0; i < argc; i++)
  137.     {
  138.     int begin_err = err;
  139.     int begin_added_files = added_files;
  140.  
  141.     user = argv[i];
  142.     strip_trailing_slashes (user);
  143.     if (strchr (user, '/') != NULL)
  144.     {
  145.         error (0, 0,
  146.          "cannot add files with '/' in their name; %s not added", user);
  147.         err++;
  148.         continue;
  149.     }
  150.  
  151.     vers = Version_TS (repository, options, (char *) NULL, (char *) NULL,
  152.                user, 0, 0, entries, (RCSNode *) NULL);
  153.     if (vers->vn_user == NULL)
  154.     {
  155.         /* No entry available, ts_rcs is invalid */
  156.         if (vers->vn_rcs == NULL)
  157.         {
  158.         /* There is no RCS file either */
  159.         if (vers->ts_user == NULL)
  160.         {
  161.             /* There is no user file either */
  162.             error (0, 0, "nothing known about %s", user);
  163.             err++;
  164.         }
  165.         else if (!isdir (user) || wrap_name_has (user, WRAP_TOCVS))
  166.         {
  167.             /*
  168.              * See if a directory exists in the repository with
  169.              * the same name.  If so, blow this request off.
  170.              */
  171.             char dname[PATH_MAX];
  172.             (void) sprintf (dname, "%s/%s", repository, user);
  173.             if (isdir (dname))
  174.             {
  175.             error (0, 0,
  176.                    "cannot add file `%s' since the directory",
  177.                    user);
  178.             error (0, 0, "`%s' already exists in the repository",
  179.                    dname);
  180.             error (1, 0, "illegal filename overlap");
  181.             }
  182.  
  183.             /* There is a user file, so build the entry for it */
  184.             if (build_entry (repository, user, vers->options,
  185.                      message, entries, vers->tag) != 0)
  186.             err++;
  187.             else 
  188.             {
  189.             added_files++;
  190.             if (!quiet)
  191.             {
  192.                 if (vers->tag)
  193.                 error (0, 0, "\
  194. scheduling %s `%s' for addition on branch `%s'",
  195.                        (wrap_name_has (user, WRAP_TOCVS)
  196.                     ? "wrapper"
  197.                     : "file"),
  198.                        user, vers->tag);
  199.                 else
  200.                 error (0, 0, "scheduling %s `%s' for addition",
  201.                    (wrap_name_has (user, WRAP_TOCVS)
  202.                     ? "wrapper"
  203.                     : "file"),
  204.                    user);
  205.             }
  206.             }
  207.         }
  208.         }
  209.         else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
  210.         {
  211.         if (isdir (user) && !wrap_name_has (user, WRAP_TOCVS))
  212.         {
  213.             error (0, 0, "the directory `%s' cannot be added because a file of the", user);
  214.             error (1, 0, "same name already exists in the repository.");
  215.         }
  216.         else
  217.         {
  218.             if (vers->tag)
  219.             error (0, 0, "file `%s' will be added on branch `%s' from version %s",
  220.                    user, vers->tag, vers->vn_rcs);
  221.             else
  222.             error (0, 0, "version %s of `%s' will be resurrected",
  223.                    vers->vn_rcs, user);
  224.             Register (entries, user, "0", vers->ts_user, NULL,
  225.                   vers->tag, NULL, NULL);
  226.             ++added_files;
  227.         }
  228.         }
  229.         else
  230.         {
  231.         /*
  232.          * There is an RCS file already, so somebody else must've
  233.          * added it
  234.          */
  235.         error (0, 0, "%s added independently by second party", user);
  236.         err++;
  237.         }
  238.     }
  239.     else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
  240.     {
  241.  
  242.         /*
  243.          * An entry for a new-born file, ts_rcs is dummy, but that is
  244.          * inappropriate here
  245.          */
  246.         error (0, 0, "%s has already been entered", user);
  247.         err++;
  248.     }
  249.     else if (vers->vn_user[0] == '-')
  250.     {
  251.         /* An entry for a removed file, ts_rcs is invalid */
  252.         if (vers->ts_user == NULL)
  253.         {
  254.         /* There is no user file (as it should be) */
  255.         if (vers->vn_rcs == NULL)
  256.         {
  257.  
  258.             /*
  259.              * There is no RCS file, so somebody else must've removed
  260.              * it from under us
  261.              */
  262.             error (0, 0,
  263.                "cannot resurrect %s; RCS file removed by second party", user);
  264.             err++;
  265.         }
  266.         else
  267.         {
  268.  
  269.             /*
  270.              * There is an RCS file, so remove the "-" from the
  271.              * version number and restore the file
  272.              */
  273.             char *tmp = xmalloc (strlen (user) + 50);
  274.  
  275.             (void) strcpy (tmp, vers->vn_user + 1);
  276.             (void) strcpy (vers->vn_user, tmp);
  277.             (void) sprintf (tmp, "Resurrected %s", user);
  278.             Register (entries, user, vers->vn_user, tmp, vers->options,
  279.                   vers->tag, vers->date, vers->ts_conflict);
  280.             free (tmp);
  281.  
  282.             /* XXX - bugs here; this really resurrect the head */
  283.             /* Note that this depends on the Register above actually
  284.                having written Entries, or else it won't really
  285.                check the file out.  */
  286.             if (update (2, argv + i - 1) == 0)
  287.             {
  288.             error (0, 0, "%s, version %s, resurrected", user,
  289.                    vers->vn_user);
  290.             }
  291.             else
  292.             {
  293.             error (0, 0, "could not resurrect %s", user);
  294.             err++;
  295.             }
  296.         }
  297.         }
  298.         else
  299.         {
  300.         /* The user file shouldn't be there */
  301.         error (0, 0, "%s should be removed and is still there (or is back again)", user);
  302.         err++;
  303.         }
  304.     }
  305.     else
  306.     {
  307.         /* A normal entry, ts_rcs is valid, so it must already be there */
  308.         error (0, 0, "%s already exists, with version number %s", user,
  309.            vers->vn_user);
  310.         err++;
  311.     }
  312.     freevers_ts (&vers);
  313.  
  314.     /* passed all the checks.  Go ahead and add it if its a directory */
  315.     if (begin_err == err
  316.         && isdir (user)
  317.         && !wrap_name_has (user, WRAP_TOCVS))
  318.     {
  319.         err += add_directory (repository, user);
  320.         continue;
  321.     }
  322. #ifdef SERVER_SUPPORT
  323.     if (server_active && begin_added_files != added_files)
  324.         server_checked_in (user, ".", repository);
  325. #endif
  326.     }
  327.     if (added_files)
  328.     error (0, 0, "use 'cvs commit' to add %s permanently",
  329.            (added_files == 1) ? "this file" : "these files");
  330.  
  331.     Entries_Close (entries);
  332.  
  333.     if (message)
  334.     free (message);
  335.  
  336.     return (err);
  337. }
  338.  
  339. /*
  340.  * The specified user file is really a directory.  So, let's make sure that
  341.  * it is created in the RCS source repository, and that the user's directory
  342.  * is updated to include a CVS directory.
  343.  * 
  344.  * Returns 1 on failure, 0 on success.
  345.  */
  346. static int
  347. add_directory (repository, dir)
  348.     char *repository;
  349.     char *dir;
  350. {
  351.     char rcsdir[PATH_MAX];
  352.     struct saved_cwd cwd;
  353.     char message[PATH_MAX + 100];
  354.     char *tag, *date;
  355.  
  356.     if (strchr (dir, '/') != NULL)
  357.     {
  358.     error (0, 0,
  359.            "directory %s not added; must be a direct sub-directory", dir);
  360.     return (1);
  361.     }
  362.     if (strcmp (dir, CVSADM) == 0)
  363.     {
  364.     error (0, 0, "cannot add a `%s' directory", CVSADM);
  365.     return (1);
  366.     }
  367.  
  368.     /* before we do anything else, see if we have any per-directory tags */
  369.     ParseTag (&tag, &date);
  370.  
  371.     /* now, remember where we were, so we can get back */
  372.     if (save_cwd (&cwd))
  373.     return (1);
  374.     if (chdir (dir) < 0)
  375.     {
  376.     error (0, errno, "cannot chdir to %s", dir);
  377.     return (1);
  378.     }
  379. #ifdef SERVER_SUPPORT
  380.     if (!server_active && isfile (CVSADM))
  381. #else
  382.     if (isfile (CVSADM))
  383. #endif
  384.     {
  385.     error (0, 0, "%s/%s already exists", dir, CVSADM);
  386.     goto out;
  387.     }
  388.  
  389.     (void) sprintf (rcsdir, "%s/%s", repository, dir);
  390.     if (isfile (rcsdir) && !isdir (rcsdir))
  391.     {
  392.     error (0, 0, "%s is not a directory; %s not added", rcsdir, dir);
  393.     goto out;
  394.     }
  395.  
  396.     /* setup the log message */
  397.     (void) sprintf (message, "Directory %s added to the repository\n", rcsdir);
  398.     if (tag)
  399.     {
  400.     (void) strcat (message, "--> Using per-directory sticky tag `");
  401.     (void) strcat (message, tag);
  402.     (void) strcat (message, "'\n");
  403.     }
  404.     if (date)
  405.     {
  406.     (void) strcat (message, "--> Using per-directory sticky date `");
  407.     (void) strcat (message, date);
  408.     (void) strcat (message, "'\n");
  409.     }
  410.  
  411.     if (!isdir (rcsdir))
  412.     {
  413.     mode_t omask;
  414.     Node *p;
  415.     List *ulist;
  416.  
  417. #if 0
  418.     char line[MAXLINELEN];
  419.  
  420.     (void) printf ("Add directory %s to the repository (y/n) [n] ? ",
  421.                rcsdir);
  422.     (void) fflush (stdout);
  423.     clearerr (stdin);
  424.     if (fgets (line, sizeof (line), stdin) == NULL ||
  425.         (line[0] != 'y' && line[0] != 'Y'))
  426.     {
  427.         error (0, 0, "directory %s not added", rcsdir);
  428.         goto out;
  429.     }
  430. #endif
  431.  
  432.     omask = umask (cvsumask);
  433.     if (CVS_MKDIR (rcsdir, 0777) < 0)
  434.     {
  435.         error (0, errno, "cannot mkdir %s", rcsdir);
  436.         (void) umask (omask);
  437.         goto out;
  438.     }
  439.     (void) umask (omask);
  440.  
  441.     /*
  442.      * Set up an update list with a single title node for Update_Logfile
  443.      */
  444.     ulist = getlist ();
  445.     p = getnode ();
  446.     p->type = UPDATE;
  447.     p->delproc = update_delproc;
  448.     p->key = xstrdup ("- New directory");
  449.     p->data = (char *) T_TITLE;
  450.     (void) addnode (ulist, p);
  451.     Update_Logfile (rcsdir, message, (char *) NULL, (FILE *) NULL, ulist);
  452.     dellist (&ulist);
  453.     }
  454.  
  455. #ifdef SERVER_SUPPORT
  456.     if (!server_active)
  457.     Create_Admin (".", dir, rcsdir, tag, date);
  458. #else
  459.     Create_Admin (".", dir, rcsdir, tag, date);
  460. #endif
  461.     if (tag)
  462.     free (tag);
  463.     if (date)
  464.     free (date);
  465.  
  466.     (void) printf ("%s", message);
  467. out:
  468.     if (restore_cwd (&cwd, NULL))
  469.       exit (EXIT_FAILURE);
  470.     free_cwd (&cwd);
  471.     return (0);
  472. }
  473.  
  474. /*
  475.  * Builds an entry for a new file and sets up "CVS/file",[pt] by
  476.  * interrogating the user.  Returns non-zero on error.
  477.  */
  478. static int
  479. build_entry (repository, user, options, message, entries, tag)
  480.     char *repository;
  481.     char *user;
  482.     char *options;
  483.     char *message;
  484.     List *entries;
  485.     char *tag;
  486. {
  487.     char fname[PATH_MAX];
  488.     char line[MAXLINELEN];
  489.     FILE *fp;
  490.  
  491.     if (noexec)
  492.     return (0);
  493.  
  494.     /*
  495.      * The requested log is read directly from the user and stored in the
  496.      * file user,t.  If the "message" argument is set, use it as the
  497.      * initial creation log (which typically describes the file).
  498.      */
  499.     (void) sprintf (fname, "%s/%s%s", CVSADM, user, CVSEXT_LOG);
  500.     fp = open_file (fname, "w+");
  501.     if (message && fputs (message, fp) == EOF)
  502.         error (1, errno, "cannot write to %s", fname);
  503.     if (fclose(fp) == EOF)
  504.         error(1, errno, "cannot close %s", fname);
  505.  
  506.     /*
  507.      * Create the entry now, since this allows the user to interrupt us above
  508.      * without needing to clean anything up (well, we could clean up the
  509.      * ,t file, but who cares).
  510.      */
  511.     (void) sprintf (line, "Initial %s", user);
  512.     Register (entries, user, "0", line, options, tag, (char *) 0, (char *) 0);
  513.     return (0);
  514. }
  515.