xref: /openbsd-src/usr.bin/cvs/remove.c (revision cf2525843d483a385de106a1361b2b9c18d96583)
1 /*	$OpenBSD: remove.c,v 1.54 2006/06/19 05:05:17 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 "includes.h"
19 
20 #include "cvs.h"
21 #include "log.h"
22 
23 extern char *__progname;
24 
25 int		cvs_remove(int, char **);
26 void		cvs_remove_local(struct cvs_file *);
27 
28 static int	force_remove = 0;
29 static int	removed = 0;
30 static int	existing = 0;
31 
32 struct cvs_cmd cvs_cmd_remove = {
33 	CVS_OP_REMOVE, 0, "remove",
34 	{ "rm", "delete" },
35 	"Remove an entry from the repository",
36 	"[-flR] [file ...]",
37 	"flR",
38 	NULL,
39 	cvs_remove
40 };
41 
42 int
43 cvs_remove(int argc, char **argv)
44 {
45 	int ch;
46 	int flags;
47 	char *arg = ".";
48 	struct cvs_recursion cr;
49 
50 	flags = CR_RECURSE_DIRS;
51 	while ((ch = getopt(argc, argv, cvs_cmd_remove.cmd_opts)) != -1) {
52 		switch (ch) {
53 		case 'f':
54 			force_remove = 1;
55 			break;
56 		case 'l':
57 			flags &= ~CR_RECURSE_DIRS;
58 			break;
59 		case 'R':
60 			break;
61 		default:
62 			fatal("%s", cvs_cmd_remove.cmd_synopsis);
63 		}
64 	}
65 
66 	argc -= optind;
67 	argv += optind;
68 
69 	cr.enterdir = NULL;
70 	cr.leavedir = NULL;
71 	cr.fileproc = cvs_remove_local;
72 	cr.flags = flags;
73 
74 	if (argc > 0)
75 		cvs_file_run(argc, argv, &cr);
76 	else
77 		cvs_file_run(1, &arg, &cr);
78 
79 	if (existing != 0) {
80 		cvs_log(LP_ERR, "%d file(s) exist, remove them first",
81 		    existing);
82 	}
83 
84 	if (removed != 0) {
85 		if (verbosity > 1)
86 			cvs_log(LP_NOTICE, "use '%s commit' to remove %s "
87 			    "permanently", __progname, (removed > 1) ?
88 			    "these files" : "this file");
89 	}
90 
91 	return (0);
92 }
93 
94 void
95 cvs_remove_local(struct cvs_file *cf)
96 {
97 	int l;
98 	CVSENTRIES *entlist;
99 	char *entry, buf[MAXPATHLEN], tbuf[32], rbuf[16];
100 
101 	cvs_log(LP_TRACE, "cvs_remove_local(%s)", cf->file_path);
102 
103 	if (cf->file_type == CVS_DIR) {
104 		if (verbosity > 1)
105 			cvs_log(LP_NOTICE, "Removing %s", cf->file_path);
106 		return;
107 	}
108 
109 	cvs_file_classify(cf, NULL, 0);
110 
111 	if (cf->file_status == FILE_UNKNOWN) {
112 		if (verbosity > 1)
113 			cvs_log(LP_NOTICE, "nothing known about '%s'",
114 			    cf->file_path);
115 		return;
116 	}
117 
118 	if (force_remove == 1) {
119 		if (unlink(cf->file_path) == -1)
120 			fatal("cvs_remove_local: %s", strerror(errno));
121 		(void)close(cf->fd);
122 		cf->fd = -1;
123 	}
124 
125 	if (cf->fd != -1) {
126 		if (verbosity > 1)
127 			cvs_log(LP_ERR, "file `%s' still in working directory",
128 			    cf->file_name);
129 		existing++;
130 	} else {
131 		switch(cf->file_status) {
132 		case FILE_ADDED:
133 			entlist = cvs_ent_open(cf->file_wd);
134 			cvs_ent_remove(entlist, cf->file_name);
135 			cvs_ent_close(entlist, ENT_SYNC);
136 
137 			l = snprintf(buf, sizeof(buf), "%s/%s/%s%s",
138 			    cf->file_path, CVS_PATH_CVSDIR, cf->file_name,
139 			    CVS_DESCR_FILE_EXT);
140 			if (l == -1 || l >= (int)sizeof(buf))
141 				fatal("cvs_remove_local: overflow");
142 
143 			(void)unlink(buf);
144 
145 			if (verbosity > 1) {
146 				cvs_log(LP_NOTICE, "removed `%s'",
147 				    cf->file_name);
148 			}
149 			return;
150 		case FILE_REMOVED:
151 			if (verbosity > 1 ) {
152 				cvs_log(LP_ERR,
153 				    "file `%s' already scheduled for removal",
154 				    cf->file_name);
155 			}
156 			return;
157 		default:
158 			rcsnum_tostr(cf->file_ent->ce_rev, rbuf,
159 			     sizeof(rbuf));
160 
161 			ctime_r(&cf->file_ent->ce_mtime, tbuf);
162 			if (tbuf[strlen(tbuf) - 1] == '\n')
163 				tbuf[strlen(tbuf) - 1] = '\0';
164 
165 			entry = xmalloc(CVS_ENT_MAXLINELEN);
166 			l = snprintf(entry, CVS_ENT_MAXLINELEN,
167 			     "/%s/-%s/%s//", cf->file_name, rbuf, tbuf);
168 			if (l == -1 || l >= CVS_ENT_MAXLINELEN)
169 				fatal("cvs_remove_local: overflow");
170 
171 			entlist = cvs_ent_open(cf->file_wd);
172 			cvs_ent_add(entlist, entry);
173 			cvs_ent_close(entlist, ENT_SYNC);
174 
175 			xfree(entry);
176 
177 			if (verbosity > 1) {
178 				cvs_log(LP_NOTICE,
179 				    "scheduling file `%s' for removal",
180 				    cf->file_name);
181 			}
182 
183 			cf->file_status = FILE_REMOVED;
184 			removed++;
185 			break;
186 		}
187 	}
188 }
189