/contrib/cvs/src/remove.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 294 lines · 205 code · 29 blank · 60 comment · 50 complexity · ca799cbc8f82e7f7556dda045cf85878 MD5 · raw file

  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 "cvs.h"
  23. #ifdef CLIENT_SUPPORT
  24. static int remove_force_fileproc PROTO ((void *callerdat,
  25. struct file_info *finfo));
  26. #endif
  27. static int remove_fileproc PROTO ((void *callerdat, struct file_info *finfo));
  28. static Dtype remove_dirproc PROTO ((void *callerdat, const char *dir,
  29. const char *repos, const char *update_dir,
  30. List *entries));
  31. static int force;
  32. static int local;
  33. static int removed_files;
  34. static int existing_files;
  35. static const char *const remove_usage[] =
  36. {
  37. "Usage: %s %s [-flR] [files...]\n",
  38. "\t-f\tDelete the file before removing it.\n",
  39. "\t-l\tProcess this directory only (not recursive).\n",
  40. "\t-R\tProcess directories recursively.\n",
  41. "(Specify the --help global option for a list of other help options)\n",
  42. NULL
  43. };
  44. int
  45. cvsremove (argc, argv)
  46. int argc;
  47. char **argv;
  48. {
  49. int c, err;
  50. if (argc == -1)
  51. usage (remove_usage);
  52. optind = 0;
  53. while ((c = getopt (argc, argv, "+flR")) != -1)
  54. {
  55. switch (c)
  56. {
  57. case 'f':
  58. force = 1;
  59. break;
  60. case 'l':
  61. local = 1;
  62. break;
  63. case 'R':
  64. local = 0;
  65. break;
  66. case '?':
  67. default:
  68. usage (remove_usage);
  69. break;
  70. }
  71. }
  72. argc -= optind;
  73. argv += optind;
  74. wrap_setup ();
  75. #ifdef CLIENT_SUPPORT
  76. if (current_parsed_root->isremote) {
  77. /* Call expand_wild so that the local removal of files will
  78. work. It's ok to do it always because we have to send the
  79. file names expanded anyway. */
  80. expand_wild (argc, argv, &argc, &argv);
  81. if (force)
  82. {
  83. if (!noexec)
  84. {
  85. start_recursion (remove_force_fileproc, (FILESDONEPROC) NULL,
  86. (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL,
  87. (void *) NULL, argc, argv, local, W_LOCAL,
  88. 0, CVS_LOCK_NONE, (char *) NULL, 0,
  89. (char *) NULL);
  90. }
  91. /* else FIXME should probably act as if the file doesn't exist
  92. in doing the following checks. */
  93. }
  94. start_server ();
  95. ign_setup ();
  96. if (local)
  97. send_arg("-l");
  98. send_arg ("--");
  99. /* FIXME: Can't we set SEND_NO_CONTENTS here? Needs investigation. */
  100. send_files (argc, argv, local, 0, 0);
  101. send_file_names (argc, argv, 0);
  102. free_names (&argc, argv);
  103. send_to_server ("remove\012", 0);
  104. return get_responses_and_close ();
  105. }
  106. #endif
  107. /* start the recursion processor */
  108. err = start_recursion (remove_fileproc, (FILESDONEPROC) NULL,
  109. remove_dirproc, (DIRLEAVEPROC) NULL, NULL,
  110. argc, argv,
  111. local, W_LOCAL, 0, CVS_LOCK_READ, (char *) NULL, 1,
  112. (char *) NULL);
  113. if (removed_files && !really_quiet)
  114. error (0, 0, "use '%s commit' to remove %s permanently", program_name,
  115. (removed_files == 1) ? "this file" : "these files");
  116. if (existing_files)
  117. error (0, 0,
  118. ((existing_files == 1) ?
  119. "%d file exists; remove it first" :
  120. "%d files exist; remove them first"),
  121. existing_files);
  122. return (err);
  123. }
  124. #ifdef CLIENT_SUPPORT
  125. /*
  126. * This is called via start_recursion if we are running as the client
  127. * and the -f option was used. We just physically remove the file.
  128. */
  129. /*ARGSUSED*/
  130. static int
  131. remove_force_fileproc (callerdat, finfo)
  132. void *callerdat;
  133. struct file_info *finfo;
  134. {
  135. if (CVS_UNLINK (finfo->file) < 0 && ! existence_error (errno))
  136. error (0, errno, "unable to remove %s", finfo->fullname);
  137. return 0;
  138. }
  139. #endif
  140. /*
  141. * remove the file, only if it has already been physically removed
  142. */
  143. /* ARGSUSED */
  144. static int
  145. remove_fileproc (callerdat, finfo)
  146. void *callerdat;
  147. struct file_info *finfo;
  148. {
  149. Vers_TS *vers;
  150. if (force)
  151. {
  152. if (!noexec)
  153. {
  154. if ( CVS_UNLINK (finfo->file) < 0 && ! existence_error (errno))
  155. {
  156. error (0, errno, "unable to remove %s", finfo->fullname);
  157. }
  158. }
  159. /* else FIXME should probably act as if the file doesn't exist
  160. in doing the following checks. */
  161. }
  162. vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
  163. if (vers->ts_user != NULL)
  164. {
  165. existing_files++;
  166. if (!quiet)
  167. error (0, 0, "file `%s' still in working directory",
  168. finfo->fullname);
  169. }
  170. else if (vers->vn_user == NULL)
  171. {
  172. if (!quiet)
  173. error (0, 0, "nothing known about `%s'", finfo->fullname);
  174. }
  175. else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
  176. {
  177. char *fname;
  178. /*
  179. * It's a file that has been added, but not commited yet. So,
  180. * remove the ,t file for it and scratch it from the
  181. * entries file. */
  182. Scratch_Entry (finfo->entries, finfo->file);
  183. fname = xmalloc (strlen (finfo->file)
  184. + sizeof (CVSADM)
  185. + sizeof (CVSEXT_LOG)
  186. + 10);
  187. (void) sprintf (fname, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
  188. if (unlink_file (fname) < 0
  189. && !existence_error (errno))
  190. error (0, errno, "cannot remove %s", CVSEXT_LOG);
  191. if (!quiet)
  192. error (0, 0, "removed `%s'", finfo->fullname);
  193. #ifdef SERVER_SUPPORT
  194. if (server_active)
  195. server_checked_in (finfo->file, finfo->update_dir, finfo->repository);
  196. #endif
  197. free (fname);
  198. }
  199. else if (vers->vn_user[0] == '-')
  200. {
  201. if (!quiet)
  202. error (0, 0, "file `%s' already scheduled for removal",
  203. finfo->fullname);
  204. }
  205. else if (vers->tag != NULL && isdigit ((unsigned char) *vers->tag))
  206. {
  207. /* Commit will just give an error, and so there seems to be
  208. little reason to allow the remove. I mean, conflicts that
  209. arise out of parallel development are one thing, but conflicts
  210. that arise from sticky tags are quite another.
  211. I would have thought that non-branch sticky tags should be the
  212. same but at least now, removing a file with a non-branch sticky
  213. tag means to delete the tag from the file. I'm not sure that
  214. is a good behavior, but until it is changed, we need to allow
  215. it. */
  216. error (0, 0, "\
  217. cannot remove file `%s' which has a numeric sticky tag of `%s'",
  218. finfo->fullname, vers->tag);
  219. }
  220. else if (vers->date != NULL)
  221. {
  222. /* Commit will just give an error, and so there seems to be
  223. little reason to allow the remove. */
  224. error (0, 0, "\
  225. cannot remove file `%s' which has a sticky date of `%s'",
  226. finfo->fullname, vers->date);
  227. }
  228. else
  229. {
  230. char *fname;
  231. /* Re-register it with a negative version number. */
  232. fname = xmalloc (strlen (vers->vn_user) + 5);
  233. (void) strcpy (fname, "-");
  234. (void) strcat (fname, vers->vn_user);
  235. Register (finfo->entries, finfo->file, fname, vers->ts_rcs, vers->options,
  236. vers->tag, vers->date, vers->ts_conflict);
  237. if (!quiet)
  238. error (0, 0, "scheduling `%s' for removal", finfo->fullname);
  239. removed_files++;
  240. #ifdef SERVER_SUPPORT
  241. if (server_active)
  242. server_checked_in (finfo->file, finfo->update_dir, finfo->repository);
  243. #endif
  244. free (fname);
  245. }
  246. freevers_ts (&vers);
  247. return (0);
  248. }
  249. /*
  250. * Print a warm fuzzy message
  251. */
  252. /* ARGSUSED */
  253. static Dtype
  254. remove_dirproc (callerdat, dir, repos, update_dir, entries)
  255. void *callerdat;
  256. const char *dir;
  257. const char *repos;
  258. const char *update_dir;
  259. List *entries;
  260. {
  261. if (!quiet)
  262. error (0, 0, "Removing %s", update_dir);
  263. return (R_PROCESS);
  264. }