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, char *dir, 26 char *repos, 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, 0, (char *) NULL, 0); 94 } 95 /* else FIXME should probably act as if the file doesn't exist 96 in doing the following checks. */ 97 } 98 99 start_server (); 100 ign_setup (); 101 if (local) 102 send_arg("-l"); 103 /* FIXME: Can't we set SEND_NO_CONTENTS here? Needs investigation. */ 104 send_files (argc, argv, local, 0, 0); 105 send_file_names (argc, argv, 0); 106 free_names (&argc, argv); 107 send_to_server ("remove\012", 0); 108 return get_responses_and_close (); 109 } 110 #endif 111 112 /* start the recursion processor */ 113 err = start_recursion (remove_fileproc, (FILESDONEPROC) NULL, 114 remove_dirproc, (DIRLEAVEPROC) NULL, NULL, 115 argc, argv, 116 local, W_LOCAL, 0, 1, (char *) NULL, 1); 117 118 if (removed_files && !really_quiet) 119 error (0, 0, "use '%s commit' to remove %s permanently", program_name, 120 (removed_files == 1) ? "this file" : "these files"); 121 122 if (existing_files) 123 error (0, 0, 124 ((existing_files == 1) ? 125 "%d file exists; remove it first" : 126 "%d files exist; remove them first"), 127 existing_files); 128 129 return (err); 130 } 131 132 #ifdef CLIENT_SUPPORT 133 134 /* 135 * This is called via start_recursion if we are running as the client 136 * and the -f option was used. We just physically remove the file. 137 */ 138 139 /*ARGSUSED*/ 140 static int 141 remove_force_fileproc (callerdat, finfo) 142 void *callerdat; 143 struct file_info *finfo; 144 { 145 if (CVS_UNLINK (finfo->file) < 0 && ! existence_error (errno)) 146 error (0, errno, "unable to remove %s", finfo->fullname); 147 return 0; 148 } 149 150 #endif 151 152 /* 153 * remove the file, only if it has already been physically removed 154 */ 155 /* ARGSUSED */ 156 static int 157 remove_fileproc (callerdat, finfo) 158 void *callerdat; 159 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 = xmalloc (strlen (finfo->file) 200 + sizeof (CVSADM) 201 + sizeof (CVSEXT_LOG) 202 + 10); 203 (void) sprintf (fname, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG); 204 if (unlink_file (fname) < 0 205 && !existence_error (errno)) 206 error (0, errno, "cannot remove %s", CVSEXT_LOG); 207 if (!quiet) 208 error (0, 0, "removed `%s'", finfo->fullname); 209 210 #ifdef SERVER_SUPPORT 211 if (server_active) 212 server_checked_in (finfo->file, finfo->update_dir, finfo->repository); 213 #endif 214 free (fname); 215 } 216 else if (vers->vn_user[0] == '-') 217 { 218 if (!quiet) 219 error (0, 0, "file `%s' already scheduled for removal", 220 finfo->fullname); 221 } 222 else if (vers->tag != NULL && isdigit ((unsigned char) *vers->tag)) 223 { 224 /* Commit will just give an error, and so there seems to be 225 little reason to allow the remove. I mean, conflicts that 226 arise out of parallel development are one thing, but conflicts 227 that arise from sticky tags are quite another. 228 229 I would have thought that non-branch sticky tags should be the 230 same but at least now, removing a file with a non-branch sticky 231 tag means to delete the tag from the file. I'm not sure that 232 is a good behavior, but until it is changed, we need to allow 233 it. */ 234 error (0, 0, "\ 235 cannot remove file `%s' which has a numeric sticky tag of `%s'", 236 finfo->fullname, vers->tag); 237 } 238 else 239 { 240 char *fname; 241 242 /* Re-register it with a negative version number. */ 243 fname = xmalloc (strlen (vers->vn_user) + 5); 244 (void) strcpy (fname, "-"); 245 (void) strcat (fname, vers->vn_user); 246 Register (finfo->entries, finfo->file, fname, vers->ts_rcs, vers->options, 247 vers->tag, vers->date, vers->ts_conflict); 248 if (!quiet) 249 error (0, 0, "scheduling `%s' for removal", finfo->fullname); 250 removed_files++; 251 252 #ifdef SERVER_SUPPORT 253 if (server_active) 254 server_checked_in (finfo->file, finfo->update_dir, finfo->repository); 255 #endif 256 free (fname); 257 } 258 259 freevers_ts (&vers); 260 return (0); 261 } 262 263 /* 264 * Print a warm fuzzy message 265 */ 266 /* ARGSUSED */ 267 static Dtype 268 remove_dirproc (callerdat, dir, repos, update_dir, entries) 269 void *callerdat; 270 char *dir; 271 char *repos; 272 char *update_dir; 273 List *entries; 274 { 275 if (!quiet) 276 error (0, 0, "Removing %s", update_dir); 277 return (R_PROCESS); 278 } 279