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 #include <sys/cdefs.h> 23 __RCSID("$NetBSD: remove.c,v 1.4 2016/05/17 14:00:09 christos Exp $"); 24 25 #include "cvs.h" 26 27 #ifdef CLIENT_SUPPORT 28 static int remove_force_fileproc (void *callerdat, 29 struct file_info *finfo); 30 #endif 31 static int remove_fileproc (void *callerdat, struct file_info *finfo); 32 static Dtype remove_dirproc (void *callerdat, const char *dir, 33 const char *repos, const char *update_dir, 34 List *entries); 35 36 static int force; 37 static int local; 38 static int removed_files; 39 static int existing_files; 40 41 static const char *const remove_usage[] = 42 { 43 "Usage: %s %s [-flR] [files...]\n", 44 "\t-f\tDelete the file before removing it.\n", 45 "\t-l\tProcess this directory only (not recursive).\n", 46 "\t-R\tProcess directories recursively.\n", 47 "(Specify the --help global option for a list of other help options)\n", 48 NULL 49 }; 50 51 int 52 cvsremove (int argc, char **argv) 53 { 54 int c, err; 55 56 if (argc == -1) 57 usage (remove_usage); 58 59 getoptreset (); 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, NULL, NULL, NULL, 96 NULL, argc, argv, local, W_LOCAL, 97 0, CVS_LOCK_NONE, NULL, 0, NULL); 98 } 99 /* else FIXME should probably act as if the file doesn't exist 100 in doing the following checks. */ 101 } 102 103 start_server (); 104 ign_setup (); 105 if (local) 106 send_arg("-l"); 107 send_arg ("--"); 108 /* FIXME: Can't we set SEND_NO_CONTENTS here? Needs investigation. */ 109 send_files (argc, argv, local, 0, 0); 110 send_file_names (argc, argv, 0); 111 free_names (&argc, argv); 112 send_to_server ("remove\012", 0); 113 return get_responses_and_close (); 114 } 115 #endif 116 117 /* start the recursion processor */ 118 err = start_recursion (remove_fileproc, NULL, remove_dirproc, NULL, 119 NULL, argc, argv, local, W_LOCAL, 0, 120 CVS_LOCK_READ, NULL, 1, NULL); 121 122 if (removed_files && !really_quiet) 123 error (0, 0, "use `%s commit' to remove %s permanently", program_name, 124 (removed_files == 1) ? "this file" : "these files"); 125 126 if (existing_files) 127 error (0, 0, 128 ((existing_files == 1) ? 129 "%d file exists; remove it first" : 130 "%d files exist; remove them first"), 131 existing_files); 132 133 return (err); 134 } 135 136 #ifdef CLIENT_SUPPORT 137 138 /* 139 * This is called via start_recursion if we are running as the client 140 * and the -f option was used. We just physically remove the file. 141 */ 142 143 /*ARGSUSED*/ 144 static int 145 remove_force_fileproc (void *callerdat, struct file_info *finfo) 146 { 147 if (CVS_UNLINK (finfo->file) < 0 && ! existence_error (errno)) 148 error (0, errno, "unable to remove %s", finfo->fullname); 149 return 0; 150 } 151 152 #endif 153 154 /* 155 * remove the file, only if it has already been physically removed 156 */ 157 /* ARGSUSED */ 158 static int 159 remove_fileproc (void *callerdat, struct file_info *finfo) 160 { 161 Vers_TS *vers; 162 163 if (force) 164 { 165 if (!noexec) 166 { 167 if ( CVS_UNLINK (finfo->file) < 0 && ! existence_error (errno)) 168 { 169 error (0, errno, "unable to remove %s", finfo->fullname); 170 } 171 } 172 /* else FIXME should probably act as if the file doesn't exist 173 in doing the following checks. */ 174 } 175 176 vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0); 177 178 if (vers->ts_user != NULL) 179 { 180 existing_files++; 181 if (!quiet) 182 error (0, 0, "file `%s' still in working directory", 183 finfo->fullname); 184 } 185 else if (vers->vn_user == NULL) 186 { 187 if (!quiet) 188 error (0, 0, "nothing known about `%s'", finfo->fullname); 189 } 190 else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0') 191 { 192 char *fname; 193 194 /* 195 * It's a file that has been added, but not commited yet. So, 196 * remove the ,t file for it and scratch it from the 197 * entries file. */ 198 Scratch_Entry (finfo->entries, finfo->file); 199 fname = Xasprintf ("%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG); 200 if (unlink_file (fname) < 0 201 && !existence_error (errno)) 202 error (0, errno, "cannot remove %s", CVSEXT_LOG); 203 if (!quiet) 204 error (0, 0, "removed `%s'", finfo->fullname); 205 206 #ifdef SERVER_SUPPORT 207 if (server_active) 208 server_checked_in (finfo->file, finfo->update_dir, finfo->repository); 209 #endif 210 free (fname); 211 } 212 else if (vers->vn_user[0] == '-') 213 { 214 if (!quiet) 215 error (0, 0, "file `%s' already scheduled for removal", 216 finfo->fullname); 217 } 218 else if (vers->tag != NULL && isdigit ((unsigned char) *vers->tag)) 219 { 220 /* Commit will just give an error, and so there seems to be 221 little reason to allow the remove. I mean, conflicts that 222 arise out of parallel development are one thing, but conflicts 223 that arise from sticky tags are quite another. 224 225 I would have thought that non-branch sticky tags should be the 226 same but at least now, removing a file with a non-branch sticky 227 tag means to delete the tag from the file. I'm not sure that 228 is a good behavior, but until it is changed, we need to allow 229 it. */ 230 error (0, 0, "\ 231 cannot remove file `%s' which has a numeric sticky tag of `%s'", 232 finfo->fullname, vers->tag); 233 } 234 else if (vers->date != NULL) 235 { 236 /* Commit will just give an error, and so there seems to be 237 little reason to allow the remove. */ 238 error (0, 0, "\ 239 cannot remove file `%s' which has a sticky date of `%s'", 240 finfo->fullname, vers->date); 241 } 242 else 243 { 244 char *fname; 245 246 /* cvsacl patch */ 247 #ifdef SERVER_SUPPORT 248 if (use_cvs_acl /* && server_active */) 249 { 250 if (!access_allowed (finfo->file, finfo->repository, vers->tag, 7, 251 NULL, NULL, 1)) 252 { 253 if (stop_at_first_permission_denied) 254 error (1, 0, "permission denied for %s", 255 Short_Repository (finfo->repository)); 256 else 257 error (0, 0, "permission denied for %s/%s", 258 Short_Repository (finfo->repository), finfo->file); 259 260 return (0); 261 } 262 } 263 #endif 264 265 /* Re-register it with a negative version number. */ 266 fname = Xasprintf ("-%s", vers->vn_user); 267 Register (finfo->entries, finfo->file, fname, vers->ts_rcs, 268 vers->options, vers->tag, vers->date, vers->ts_conflict); 269 if (!quiet) 270 error (0, 0, "scheduling `%s' for removal", finfo->fullname); 271 removed_files++; 272 273 #ifdef SERVER_SUPPORT 274 if (server_active) 275 server_checked_in (finfo->file, finfo->update_dir, finfo->repository); 276 #endif 277 free (fname); 278 } 279 280 freevers_ts (&vers); 281 return (0); 282 } 283 284 285 286 /* 287 * Print a warm fuzzy message 288 */ 289 /* ARGSUSED */ 290 static Dtype 291 remove_dirproc (void *callerdat, const char *dir, const char *repos, 292 const char *update_dir, List *entries) 293 { 294 if (!quiet) 295 error (0, 0, "Removing %s", update_dir); 296 return (R_PROCESS); 297 } 298