2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 * Copyright (c) 1989-1992, Brian Berliner
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.
10 * Removes entries from the present version. The entries will be removed from
11 * the RCS repository upon the next "commit".
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
21 static int remove_force_fileproc PROTO ((void *callerdat,
22 struct file_info *finfo));
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,
31 static int removed_files;
32 static int existing_files;
34 static const char *const remove_usage[] =
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",
45 cvsremove (argc, argv)
55 while ((c = getopt (argc, argv, "+flR")) != -1)
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);
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,
96 /* else FIXME should probably act as if the file doesn't exist
97 in doing the following checks. */
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 ();
114 /* start the recursion processor */
115 err = start_recursion (remove_fileproc, (FILESDONEPROC) NULL,
116 remove_dirproc, (DIRLEAVEPROC) NULL, NULL,
118 local, W_LOCAL, 0, CVS_LOCK_READ, (char *) NULL, 1,
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");
127 ((existing_files == 1) ?
128 "%d file exists; remove it first" :
129 "%d files exist; remove them first"),
135 #ifdef CLIENT_SUPPORT
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.
144 remove_force_fileproc (callerdat, finfo)
146 struct file_info *finfo;
148 if (CVS_UNLINK (finfo->file) < 0 && ! existence_error (errno))
149 error (0, errno, "unable to remove %s", finfo->fullname);
156 * remove the file, only if it has already been physically removed
160 remove_fileproc (callerdat, finfo)
162 struct file_info *finfo;
170 if ( CVS_UNLINK (finfo->file) < 0 && ! existence_error (errno))
172 error (0, errno, "unable to remove %s", finfo->fullname);
175 /* else FIXME should probably act as if the file doesn't exist
176 in doing the following checks. */
179 vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
181 if (vers->ts_user != NULL)
185 error (0, 0, "file `%s' still in working directory",
188 else if (vers->vn_user == NULL)
191 error (0, 0, "nothing known about `%s'", finfo->fullname);
193 else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
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
201 Scratch_Entry (finfo->entries, finfo->file);
202 fname = xmalloc (strlen (finfo->file)
204 + sizeof (CVSEXT_LOG)
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);
211 error (0, 0, "removed `%s'", finfo->fullname);
213 #ifdef SERVER_SUPPORT
215 server_checked_in (finfo->file, finfo->update_dir, finfo->repository);
219 else if (vers->vn_user[0] == '-')
222 error (0, 0, "file `%s' already scheduled for removal",
225 else if (vers->tag != NULL && isdigit ((unsigned char) *vers->tag))
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.
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
238 cannot remove file `%s' which has a numeric sticky tag of `%s'",
239 finfo->fullname, vers->tag);
241 else if (vers->date != NULL)
243 /* Commit will just give an error, and so there seems to be
244 little reason to allow the remove. */
246 cannot remove file `%s' which has a sticky date of `%s'",
247 finfo->fullname, vers->date);
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);
260 error (0, 0, "scheduling `%s' for removal", finfo->fullname);
263 #ifdef SERVER_SUPPORT
265 server_checked_in (finfo->file, finfo->update_dir, finfo->repository);
275 * Print a warm fuzzy message
279 remove_dirproc (callerdat, dir, repos, update_dir, entries)
283 const char *update_dir;
287 error (0, 0, "Removing %s", update_dir);