1 /* $OpenBSD: remove.c,v 1.80 2009/02/21 14:50:53 joris Exp $ */ 2 /* 3 * Copyright (c) 2005, 2006 Xavier Santolaria <xsa@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <errno.h> 19 #include <string.h> 20 #include <unistd.h> 21 22 #include "cvs.h" 23 #include "remote.h" 24 25 extern char *__progname; 26 27 void cvs_remove_force(struct cvs_file *); 28 29 static int force_remove = 0; 30 static int removed = 0; 31 static int existing = 0; 32 33 struct cvs_cmd cvs_cmd_remove = { 34 CVS_OP_REMOVE, CVS_USE_WDIR, "remove", 35 { "rm", "delete" }, 36 "Remove an entry from the repository", 37 "[-flR] [file ...]", 38 "flR", 39 NULL, 40 cvs_remove 41 }; 42 43 int 44 cvs_remove(int argc, char **argv) 45 { 46 int ch; 47 int flags; 48 char *arg = "."; 49 struct cvs_recursion cr; 50 51 flags = CR_RECURSE_DIRS; 52 while ((ch = getopt(argc, argv, cvs_cmd_remove.cmd_opts)) != -1) { 53 switch (ch) { 54 case 'f': 55 force_remove = 1; 56 break; 57 case 'l': 58 flags &= ~CR_RECURSE_DIRS; 59 break; 60 case 'R': 61 flags |= CR_RECURSE_DIRS; 62 break; 63 default: 64 fatal("%s", cvs_cmd_remove.cmd_synopsis); 65 } 66 } 67 68 argc -= optind; 69 argv += optind; 70 71 cr.enterdir = NULL; 72 cr.leavedir = NULL; 73 cr.flags = flags; 74 75 if (force_remove == 1 && cvs_noexec == 0) { 76 cr.fileproc = cvs_remove_force; 77 if (argc > 0) 78 cvs_file_run(argc, argv, &cr); 79 else 80 cvs_file_run(1, &arg, &cr); 81 } 82 83 if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { 84 cvs_client_connect_to_server(); 85 cr.fileproc = cvs_client_sendfile; 86 87 if (!(flags & CR_RECURSE_DIRS)) 88 cvs_client_send_request("Argument -l"); 89 } else { 90 cr.fileproc = cvs_remove_local; 91 } 92 93 if (argc > 0) 94 cvs_file_run(argc, argv, &cr); 95 else 96 cvs_file_run(1, &arg, &cr); 97 98 if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { 99 cvs_client_send_files(argv, argc); 100 cvs_client_senddir("."); 101 cvs_client_send_request("remove"); 102 cvs_client_get_responses(); 103 } else { 104 if (existing != 0) { 105 cvs_log(LP_ERR, (existing == 1) ? 106 "%d file exists; remove it first" : 107 "%d files exist; remove them first", existing); 108 } 109 110 if (removed != 0) { 111 if (verbosity > 0) { 112 cvs_log(LP_NOTICE, 113 "use '%s commit' to remove %s " 114 "permanently", __progname, (removed > 1) ? 115 "these files" : "this file"); 116 } 117 } 118 } 119 120 return (0); 121 } 122 123 void 124 cvs_remove_force(struct cvs_file *cf) 125 { 126 if (cf->file_type != CVS_DIR) { 127 if (cf->file_flags & FILE_ON_DISK) { 128 if (unlink(cf->file_path) == -1) 129 fatal("cvs_remove_force: %s", strerror(errno)); 130 (void)close(cf->fd); 131 cf->fd = -1; 132 } 133 } 134 } 135 136 void 137 cvs_remove_local(struct cvs_file *cf) 138 { 139 CVSENTRIES *entlist; 140 char *entry, buf[MAXPATHLEN], tbuf[CVS_TIME_BUFSZ], rbuf[CVS_REV_BUFSZ]; 141 char sticky[CVS_ENT_MAXLINELEN]; 142 143 cvs_log(LP_TRACE, "cvs_remove_local(%s)", cf->file_path); 144 145 if (cf->file_type == CVS_DIR) { 146 if (verbosity > 1) 147 cvs_log(LP_NOTICE, "Removing %s", cf->file_path); 148 return; 149 } 150 151 if (cvs_cmdop != CVS_OP_CHECKOUT && cvs_cmdop != CVS_OP_UPDATE) 152 cvs_file_classify(cf, cvs_directory_tag); 153 154 if (cf->file_status == FILE_UNKNOWN) { 155 if (verbosity > 1) 156 cvs_log(LP_NOTICE, "nothing known about '%s'", 157 cf->file_path); 158 return; 159 } 160 161 if (cf->file_flags & FILE_ON_DISK) { 162 if (verbosity > 1) 163 cvs_log(LP_ERR, "file `%s' still in working directory", 164 cf->file_name); 165 existing++; 166 } else { 167 switch (cf->file_status) { 168 case FILE_REMOVE_ENTRY: 169 entlist = cvs_ent_open(cf->file_wd); 170 cvs_ent_remove(entlist, cf->file_name); 171 172 (void)xsnprintf(buf, sizeof(buf), "%s/%s/%s%s", 173 cf->file_wd, CVS_PATH_CVSDIR, cf->file_name, 174 CVS_DESCR_FILE_EXT); 175 176 (void)unlink(buf); 177 178 if (verbosity > 1) { 179 cvs_log(LP_NOTICE, "removed `%s'", 180 cf->file_name); 181 } 182 return; 183 case FILE_REMOVED: 184 if (verbosity > 0) { 185 cvs_log(LP_ERR, 186 "file `%s' already scheduled for removal", 187 cf->file_name); 188 } 189 return; 190 case FILE_LOST: 191 rcsnum_tostr(cf->file_ent->ce_rev, rbuf, sizeof(rbuf)); 192 193 ctime_r(&cf->file_ent->ce_mtime, tbuf); 194 tbuf[strcspn(tbuf, "\n")] = '\0'; 195 196 sticky[0] = '\0'; 197 if (cf->file_ent->ce_tag != NULL) 198 (void)xsnprintf(sticky, sizeof(sticky), "T%s", 199 cf->file_ent->ce_tag); 200 201 entry = xmalloc(CVS_ENT_MAXLINELEN); 202 cvs_ent_line_str(cf->file_name, rbuf, tbuf, 203 cf->file_ent->ce_opts ? 204 cf->file_ent->ce_opts : "", sticky, 0, 1, 205 entry, CVS_ENT_MAXLINELEN); 206 207 if (cvs_server_active == 1) { 208 cvs_server_update_entry("Checked-in", cf); 209 cvs_remote_output(entry); 210 } else { 211 entlist = cvs_ent_open(cf->file_wd); 212 cvs_ent_add(entlist, entry); 213 } 214 215 xfree(entry); 216 217 if (verbosity > 0) { 218 cvs_log(LP_NOTICE, 219 "scheduling file `%s' for removal", 220 cf->file_name); 221 } 222 223 cf->file_status = FILE_REMOVED; 224 removed++; 225 break; 226 } 227 } 228 } 229