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