xref: /dflybsd-src/contrib/cvs-1.12/src/remove.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1*86d7f5d3SJohn Marino /*
2*86d7f5d3SJohn Marino  * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
3*86d7f5d3SJohn Marino  *
4*86d7f5d3SJohn Marino  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
5*86d7f5d3SJohn Marino  *                                  and others.
6*86d7f5d3SJohn Marino  *
7*86d7f5d3SJohn Marino  * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8*86d7f5d3SJohn Marino  * Portions Copyright (C) 1989-1992, Brian Berliner
9*86d7f5d3SJohn Marino  *
10*86d7f5d3SJohn Marino  * You may distribute under the terms of the GNU General Public License as
11*86d7f5d3SJohn Marino  * specified in the README file that comes with the CVS source distribution.
12*86d7f5d3SJohn Marino  *
13*86d7f5d3SJohn Marino  * Remove a File
14*86d7f5d3SJohn Marino  *
15*86d7f5d3SJohn Marino  * Removes entries from the present version. The entries will be removed from
16*86d7f5d3SJohn Marino  * the RCS repository upon the next "commit".
17*86d7f5d3SJohn Marino  *
18*86d7f5d3SJohn Marino  * "remove" accepts no options, only file names that are to be removed.  The
19*86d7f5d3SJohn Marino  * file must not exist in the current directory for "remove" to work
20*86d7f5d3SJohn Marino  * correctly.
21*86d7f5d3SJohn Marino  */
22*86d7f5d3SJohn Marino 
23*86d7f5d3SJohn Marino #include "cvs.h"
24*86d7f5d3SJohn Marino 
25*86d7f5d3SJohn Marino #ifdef CLIENT_SUPPORT
26*86d7f5d3SJohn Marino static int remove_force_fileproc (void *callerdat,
27*86d7f5d3SJohn Marino 					 struct file_info *finfo);
28*86d7f5d3SJohn Marino #endif
29*86d7f5d3SJohn Marino static int remove_fileproc (void *callerdat, struct file_info *finfo);
30*86d7f5d3SJohn Marino static Dtype remove_dirproc (void *callerdat, const char *dir,
31*86d7f5d3SJohn Marino                              const char *repos, const char *update_dir,
32*86d7f5d3SJohn Marino                              List *entries);
33*86d7f5d3SJohn Marino 
34*86d7f5d3SJohn Marino static int force;
35*86d7f5d3SJohn Marino static int local;
36*86d7f5d3SJohn Marino static int removed_files;
37*86d7f5d3SJohn Marino static int existing_files;
38*86d7f5d3SJohn Marino 
39*86d7f5d3SJohn Marino static const char *const remove_usage[] =
40*86d7f5d3SJohn Marino {
41*86d7f5d3SJohn Marino     "Usage: %s %s [-flR] [files...]\n",
42*86d7f5d3SJohn Marino     "\t-f\tDelete the file before removing it.\n",
43*86d7f5d3SJohn Marino     "\t-l\tProcess this directory only (not recursive).\n",
44*86d7f5d3SJohn Marino     "\t-R\tProcess directories recursively.\n",
45*86d7f5d3SJohn Marino     "(Specify the --help global option for a list of other help options)\n",
46*86d7f5d3SJohn Marino     NULL
47*86d7f5d3SJohn Marino };
48*86d7f5d3SJohn Marino 
49*86d7f5d3SJohn Marino int
cvsremove(int argc,char ** argv)50*86d7f5d3SJohn Marino cvsremove (int argc, char **argv)
51*86d7f5d3SJohn Marino {
52*86d7f5d3SJohn Marino     int c, err;
53*86d7f5d3SJohn Marino 
54*86d7f5d3SJohn Marino     if (argc == -1)
55*86d7f5d3SJohn Marino 	usage (remove_usage);
56*86d7f5d3SJohn Marino 
57*86d7f5d3SJohn Marino     optind = 0;
58*86d7f5d3SJohn Marino     while ((c = getopt (argc, argv, "+flR")) != -1)
59*86d7f5d3SJohn Marino     {
60*86d7f5d3SJohn Marino 	switch (c)
61*86d7f5d3SJohn Marino 	{
62*86d7f5d3SJohn Marino 	    case 'f':
63*86d7f5d3SJohn Marino 		force = 1;
64*86d7f5d3SJohn Marino 		break;
65*86d7f5d3SJohn Marino 	    case 'l':
66*86d7f5d3SJohn Marino 		local = 1;
67*86d7f5d3SJohn Marino 		break;
68*86d7f5d3SJohn Marino 	    case 'R':
69*86d7f5d3SJohn Marino 		local = 0;
70*86d7f5d3SJohn Marino 		break;
71*86d7f5d3SJohn Marino 	    case '?':
72*86d7f5d3SJohn Marino 	    default:
73*86d7f5d3SJohn Marino 		usage (remove_usage);
74*86d7f5d3SJohn Marino 		break;
75*86d7f5d3SJohn Marino 	}
76*86d7f5d3SJohn Marino     }
77*86d7f5d3SJohn Marino     argc -= optind;
78*86d7f5d3SJohn Marino     argv += optind;
79*86d7f5d3SJohn Marino 
80*86d7f5d3SJohn Marino     wrap_setup ();
81*86d7f5d3SJohn Marino 
82*86d7f5d3SJohn Marino #ifdef CLIENT_SUPPORT
83*86d7f5d3SJohn Marino     if (current_parsed_root->isremote) {
84*86d7f5d3SJohn Marino 	/* Call expand_wild so that the local removal of files will
85*86d7f5d3SJohn Marino            work.  It's ok to do it always because we have to send the
86*86d7f5d3SJohn Marino            file names expanded anyway.  */
87*86d7f5d3SJohn Marino 	expand_wild (argc, argv, &argc, &argv);
88*86d7f5d3SJohn Marino 
89*86d7f5d3SJohn Marino 	if (force)
90*86d7f5d3SJohn Marino 	{
91*86d7f5d3SJohn Marino 	    if (!noexec)
92*86d7f5d3SJohn Marino 	    {
93*86d7f5d3SJohn Marino 		start_recursion (remove_force_fileproc, NULL, NULL, NULL,
94*86d7f5d3SJohn Marino 				 NULL, argc, argv, local, W_LOCAL,
95*86d7f5d3SJohn Marino 				 0, CVS_LOCK_NONE, NULL, 0, NULL);
96*86d7f5d3SJohn Marino 	    }
97*86d7f5d3SJohn Marino 	    /* else FIXME should probably act as if the file doesn't exist
98*86d7f5d3SJohn Marino 	       in doing the following checks.  */
99*86d7f5d3SJohn Marino 	}
100*86d7f5d3SJohn Marino 
101*86d7f5d3SJohn Marino 	start_server ();
102*86d7f5d3SJohn Marino 	ign_setup ();
103*86d7f5d3SJohn Marino 	if (local)
104*86d7f5d3SJohn Marino 	    send_arg("-l");
105*86d7f5d3SJohn Marino 	send_arg ("--");
106*86d7f5d3SJohn Marino 	/* FIXME: Can't we set SEND_NO_CONTENTS here?  Needs investigation.  */
107*86d7f5d3SJohn Marino 	send_files (argc, argv, local, 0, 0);
108*86d7f5d3SJohn Marino 	send_file_names (argc, argv, 0);
109*86d7f5d3SJohn Marino 	free_names (&argc, argv);
110*86d7f5d3SJohn Marino 	send_to_server ("remove\012", 0);
111*86d7f5d3SJohn Marino         return get_responses_and_close ();
112*86d7f5d3SJohn Marino     }
113*86d7f5d3SJohn Marino #endif
114*86d7f5d3SJohn Marino 
115*86d7f5d3SJohn Marino     /* start the recursion processor */
116*86d7f5d3SJohn Marino     err = start_recursion (remove_fileproc, NULL, remove_dirproc, NULL,
117*86d7f5d3SJohn Marino 			   NULL, argc, argv, local, W_LOCAL, 0,
118*86d7f5d3SJohn Marino 			   CVS_LOCK_READ, NULL, 1, NULL);
119*86d7f5d3SJohn Marino 
120*86d7f5d3SJohn Marino     if (removed_files && !really_quiet)
121*86d7f5d3SJohn Marino 	error (0, 0, "use `%s commit' to remove %s permanently", program_name,
122*86d7f5d3SJohn Marino 	       (removed_files == 1) ? "this file" : "these files");
123*86d7f5d3SJohn Marino 
124*86d7f5d3SJohn Marino     if (existing_files)
125*86d7f5d3SJohn Marino 	error (0, 0,
126*86d7f5d3SJohn Marino 	       ((existing_files == 1) ?
127*86d7f5d3SJohn Marino 		"%d file exists; remove it first" :
128*86d7f5d3SJohn Marino 		"%d files exist; remove them first"),
129*86d7f5d3SJohn Marino 	       existing_files);
130*86d7f5d3SJohn Marino 
131*86d7f5d3SJohn Marino     return (err);
132*86d7f5d3SJohn Marino }
133*86d7f5d3SJohn Marino 
134*86d7f5d3SJohn Marino #ifdef CLIENT_SUPPORT
135*86d7f5d3SJohn Marino 
136*86d7f5d3SJohn Marino /*
137*86d7f5d3SJohn Marino  * This is called via start_recursion if we are running as the client
138*86d7f5d3SJohn Marino  * and the -f option was used.  We just physically remove the file.
139*86d7f5d3SJohn Marino  */
140*86d7f5d3SJohn Marino 
141*86d7f5d3SJohn Marino /*ARGSUSED*/
142*86d7f5d3SJohn Marino static int
remove_force_fileproc(void * callerdat,struct file_info * finfo)143*86d7f5d3SJohn Marino remove_force_fileproc (void *callerdat, struct file_info *finfo)
144*86d7f5d3SJohn Marino {
145*86d7f5d3SJohn Marino     if (CVS_UNLINK (finfo->file) < 0 && ! existence_error (errno))
146*86d7f5d3SJohn Marino 	error (0, errno, "unable to remove %s", finfo->fullname);
147*86d7f5d3SJohn Marino     return 0;
148*86d7f5d3SJohn Marino }
149*86d7f5d3SJohn Marino 
150*86d7f5d3SJohn Marino #endif
151*86d7f5d3SJohn Marino 
152*86d7f5d3SJohn Marino /*
153*86d7f5d3SJohn Marino  * remove the file, only if it has already been physically removed
154*86d7f5d3SJohn Marino  */
155*86d7f5d3SJohn Marino /* ARGSUSED */
156*86d7f5d3SJohn Marino static int
remove_fileproc(void * callerdat,struct file_info * finfo)157*86d7f5d3SJohn Marino remove_fileproc (void *callerdat, struct file_info *finfo)
158*86d7f5d3SJohn Marino {
159*86d7f5d3SJohn Marino     Vers_TS *vers;
160*86d7f5d3SJohn Marino 
161*86d7f5d3SJohn Marino     if (force)
162*86d7f5d3SJohn Marino     {
163*86d7f5d3SJohn Marino 	if (!noexec)
164*86d7f5d3SJohn Marino 	{
165*86d7f5d3SJohn Marino 	    if ( CVS_UNLINK (finfo->file) < 0 && ! existence_error (errno))
166*86d7f5d3SJohn Marino 	    {
167*86d7f5d3SJohn Marino 		error (0, errno, "unable to remove %s", finfo->fullname);
168*86d7f5d3SJohn Marino 	    }
169*86d7f5d3SJohn Marino 	}
170*86d7f5d3SJohn Marino 	/* else FIXME should probably act as if the file doesn't exist
171*86d7f5d3SJohn Marino 	   in doing the following checks.  */
172*86d7f5d3SJohn Marino     }
173*86d7f5d3SJohn Marino 
174*86d7f5d3SJohn Marino     vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
175*86d7f5d3SJohn Marino 
176*86d7f5d3SJohn Marino     if (vers->ts_user != NULL)
177*86d7f5d3SJohn Marino     {
178*86d7f5d3SJohn Marino 	existing_files++;
179*86d7f5d3SJohn Marino 	if (!quiet)
180*86d7f5d3SJohn Marino 	    error (0, 0, "file `%s' still in working directory",
181*86d7f5d3SJohn Marino 		   finfo->fullname);
182*86d7f5d3SJohn Marino     }
183*86d7f5d3SJohn Marino     else if (vers->vn_user == NULL)
184*86d7f5d3SJohn Marino     {
185*86d7f5d3SJohn Marino 	if (!quiet)
186*86d7f5d3SJohn Marino 	    error (0, 0, "nothing known about `%s'", finfo->fullname);
187*86d7f5d3SJohn Marino     }
188*86d7f5d3SJohn Marino     else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
189*86d7f5d3SJohn Marino     {
190*86d7f5d3SJohn Marino 	char *fname;
191*86d7f5d3SJohn Marino 
192*86d7f5d3SJohn Marino 	/*
193*86d7f5d3SJohn Marino 	 * It's a file that has been added, but not commited yet. So,
194*86d7f5d3SJohn Marino 	 * remove the ,t file for it and scratch it from the
195*86d7f5d3SJohn Marino 	 * entries file.  */
196*86d7f5d3SJohn Marino 	Scratch_Entry (finfo->entries, finfo->file);
197*86d7f5d3SJohn Marino 	fname = Xasprintf ("%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
198*86d7f5d3SJohn Marino 	if (unlink_file (fname) < 0
199*86d7f5d3SJohn Marino 	    && !existence_error (errno))
200*86d7f5d3SJohn Marino 	    error (0, errno, "cannot remove %s", CVSEXT_LOG);
201*86d7f5d3SJohn Marino 	if (!quiet)
202*86d7f5d3SJohn Marino 	    error (0, 0, "removed `%s'", finfo->fullname);
203*86d7f5d3SJohn Marino 
204*86d7f5d3SJohn Marino #ifdef SERVER_SUPPORT
205*86d7f5d3SJohn Marino 	if (server_active)
206*86d7f5d3SJohn Marino 	    server_checked_in (finfo->file, finfo->update_dir, finfo->repository);
207*86d7f5d3SJohn Marino #endif
208*86d7f5d3SJohn Marino 	free (fname);
209*86d7f5d3SJohn Marino     }
210*86d7f5d3SJohn Marino     else if (vers->vn_user[0] == '-')
211*86d7f5d3SJohn Marino     {
212*86d7f5d3SJohn Marino 	if (!quiet)
213*86d7f5d3SJohn Marino 	    error (0, 0, "file `%s' already scheduled for removal",
214*86d7f5d3SJohn Marino 		   finfo->fullname);
215*86d7f5d3SJohn Marino     }
216*86d7f5d3SJohn Marino     else if (vers->tag != NULL && isdigit ((unsigned char) *vers->tag))
217*86d7f5d3SJohn Marino     {
218*86d7f5d3SJohn Marino 	/* Commit will just give an error, and so there seems to be
219*86d7f5d3SJohn Marino 	   little reason to allow the remove.  I mean, conflicts that
220*86d7f5d3SJohn Marino 	   arise out of parallel development are one thing, but conflicts
221*86d7f5d3SJohn Marino 	   that arise from sticky tags are quite another.
222*86d7f5d3SJohn Marino 
223*86d7f5d3SJohn Marino 	   I would have thought that non-branch sticky tags should be the
224*86d7f5d3SJohn Marino 	   same but at least now, removing a file with a non-branch sticky
225*86d7f5d3SJohn Marino 	   tag means to delete the tag from the file.  I'm not sure that
226*86d7f5d3SJohn Marino 	   is a good behavior, but until it is changed, we need to allow
227*86d7f5d3SJohn Marino 	   it.  */
228*86d7f5d3SJohn Marino 	error (0, 0, "\
229*86d7f5d3SJohn Marino cannot remove file `%s' which has a numeric sticky tag of `%s'",
230*86d7f5d3SJohn Marino 	       finfo->fullname, vers->tag);
231*86d7f5d3SJohn Marino     }
232*86d7f5d3SJohn Marino     else if (vers->date != NULL)
233*86d7f5d3SJohn Marino     {
234*86d7f5d3SJohn Marino 	/* Commit will just give an error, and so there seems to be
235*86d7f5d3SJohn Marino 	   little reason to allow the remove.  */
236*86d7f5d3SJohn Marino 	error (0, 0, "\
237*86d7f5d3SJohn Marino cannot remove file `%s' which has a sticky date of `%s'",
238*86d7f5d3SJohn Marino 	       finfo->fullname, vers->date);
239*86d7f5d3SJohn Marino     }
240*86d7f5d3SJohn Marino     else
241*86d7f5d3SJohn Marino     {
242*86d7f5d3SJohn Marino 	char *fname;
243*86d7f5d3SJohn Marino 
244*86d7f5d3SJohn Marino 	/* Re-register it with a negative version number.  */
245*86d7f5d3SJohn Marino 	fname = Xasprintf ("-%s", vers->vn_user);
246*86d7f5d3SJohn Marino 	Register (finfo->entries, finfo->file, fname, vers->ts_rcs,
247*86d7f5d3SJohn Marino 		  vers->options, vers->tag, vers->date, vers->ts_conflict);
248*86d7f5d3SJohn Marino 	if (!quiet)
249*86d7f5d3SJohn Marino 	    error (0, 0, "scheduling `%s' for removal", finfo->fullname);
250*86d7f5d3SJohn Marino 	removed_files++;
251*86d7f5d3SJohn Marino 
252*86d7f5d3SJohn Marino #ifdef SERVER_SUPPORT
253*86d7f5d3SJohn Marino 	if (server_active)
254*86d7f5d3SJohn Marino 	    server_checked_in (finfo->file, finfo->update_dir, finfo->repository);
255*86d7f5d3SJohn Marino #endif
256*86d7f5d3SJohn Marino 	free (fname);
257*86d7f5d3SJohn Marino     }
258*86d7f5d3SJohn Marino 
259*86d7f5d3SJohn Marino     freevers_ts (&vers);
260*86d7f5d3SJohn Marino     return (0);
261*86d7f5d3SJohn Marino }
262*86d7f5d3SJohn Marino 
263*86d7f5d3SJohn Marino 
264*86d7f5d3SJohn Marino 
265*86d7f5d3SJohn Marino /*
266*86d7f5d3SJohn Marino  * Print a warm fuzzy message
267*86d7f5d3SJohn Marino  */
268*86d7f5d3SJohn Marino /* ARGSUSED */
269*86d7f5d3SJohn Marino static Dtype
remove_dirproc(void * callerdat,const char * dir,const char * repos,const char * update_dir,List * entries)270*86d7f5d3SJohn Marino remove_dirproc (void *callerdat, const char *dir, const char *repos,
271*86d7f5d3SJohn Marino                 const char *update_dir, List *entries)
272*86d7f5d3SJohn Marino {
273*86d7f5d3SJohn Marino     if (!quiet)
274*86d7f5d3SJohn Marino 	error (0, 0, "Removing %s", update_dir);
275*86d7f5d3SJohn Marino     return (R_PROCESS);
276*86d7f5d3SJohn Marino }
277