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