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