1*37fdff3fStobias /* $OpenBSD: checkout.c,v 1.125 2008/02/04 15:07:32 tobias Exp $ */ 208f90673Sjfb /* 33ad3fb45Sjoris * Copyright (c) 2006 Joris Vink <joris@openbsd.org> 408f90673Sjfb * 53ad3fb45Sjoris * Permission to use, copy, modify, and distribute this software for any 63ad3fb45Sjoris * purpose with or without fee is hereby granted, provided that the above 73ad3fb45Sjoris * copyright notice and this permission notice appear in all copies. 808f90673Sjfb * 93ad3fb45Sjoris * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 103ad3fb45Sjoris * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 113ad3fb45Sjoris * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 123ad3fb45Sjoris * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 133ad3fb45Sjoris * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 143ad3fb45Sjoris * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 153ad3fb45Sjoris * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1608f90673Sjfb */ 1708f90673Sjfb 181f8531bdSotto #include <sys/param.h> 191f8531bdSotto #include <sys/dirent.h> 201f8531bdSotto #include <sys/stat.h> 21bed6eeadStobias #include <sys/time.h> 221f8531bdSotto 231f8531bdSotto #include <errno.h> 241f8531bdSotto #include <fcntl.h> 251526ef95Stobias #include <libgen.h> 261f8531bdSotto #include <string.h> 271f8531bdSotto #include <unistd.h> 2808f90673Sjfb 2908f90673Sjfb #include "cvs.h" 303ad3fb45Sjoris #include "diff.h" 319fac60a5Sjoris #include "remote.h" 3208f90673Sjfb 3390f9bb03Sxsa static void checkout_check_repository(int, char **); 34b0d656e9Stobias static int checkout_classify(const char *, const char *); 353ad3fb45Sjoris static void checkout_repository(const char *, const char *); 3608f90673Sjfb 377ac78d1dSjoris extern int print_stdout; 389f820608Sjoris extern int prune_dirs; 39cabc4131Sjoris extern int build_dirs; 409f820608Sjoris 41a2f23aefSxsa static int flags = CR_REPO | CR_RECURSE_DIRS; 42dbeb8705Sjoris static char *dflag = NULL; 43*37fdff3fStobias static char *koptstr = NULL; 44a2f23aefSxsa 45e4276007Sjfb struct cvs_cmd cvs_cmd_checkout = { 46f331ff59Stobias CVS_OP_CHECKOUT, CVS_USE_WDIR, "checkout", 47e4276007Sjfb { "co", "get" }, 483ad3fb45Sjoris "Checkout a working copy of a repository", 4938019573Sxsa "[-AcflNnPpRs] [-D date | -r tag] [-d dir] [-j rev] [-k mode] " 50e4276007Sjfb "[-t id] module ...", 51e3095c02Sxsa "AcD:d:fj:k:lNnPpRr:st:", 52e4276007Sjfb NULL, 533ad3fb45Sjoris cvs_checkout 5416cfc147Sjoris }; 5516cfc147Sjoris 5625654a94Sjoris struct cvs_cmd cvs_cmd_export = { 57f331ff59Stobias CVS_OP_EXPORT, CVS_USE_WDIR, "export", 5825654a94Sjoris { "exp", "ex" }, 5925654a94Sjoris "Export sources from CVS, similar to checkout", 6090f9bb03Sxsa "[-flNnR] [-d dir] [-k mode] -D date | -r rev module ...", 6190f9bb03Sxsa "D:d:k:flNnRr:", 6225654a94Sjoris NULL, 6390f9bb03Sxsa cvs_export 6425654a94Sjoris }; 6525654a94Sjoris 663ad3fb45Sjoris int 673ad3fb45Sjoris cvs_checkout(int argc, char **argv) 6808f90673Sjfb { 69a2f23aefSxsa int ch; 7008f90673Sjfb 713ad3fb45Sjoris while ((ch = getopt(argc, argv, cvs_cmd_checkout.cmd_opts)) != -1) { 7208f90673Sjfb switch (ch) { 733734fd29Sxsa case 'A': 743734fd29Sxsa reset_stickies = 1; 753734fd29Sxsa break; 76dbeb8705Sjoris case 'd': 77dbeb8705Sjoris if (dflag != NULL) 78dbeb8705Sjoris fatal("-d specified two or more times"); 79dbeb8705Sjoris dflag = optarg; 80dbeb8705Sjoris break; 81*37fdff3fStobias case 'k': 82*37fdff3fStobias koptstr = optarg; 83*37fdff3fStobias kflag = rcs_kflag_get(koptstr); 84*37fdff3fStobias if (RCS_KWEXP_INVAL(kflag)) { 85*37fdff3fStobias cvs_log(LP_ERR, 86*37fdff3fStobias "invalid RCS keyword expension mode"); 87*37fdff3fStobias fatal("%s", cvs_cmd_add.cmd_synopsis); 88*37fdff3fStobias } 89*37fdff3fStobias break; 90e3095c02Sxsa case 'l': 91e3095c02Sxsa flags &= ~CR_RECURSE_DIRS; 92e3095c02Sxsa break; 9351ef6581Sjoris case 'N': 9451ef6581Sjoris break; 959f820608Sjoris case 'P': 969f820608Sjoris prune_dirs = 1; 979f820608Sjoris break; 987ac78d1dSjoris case 'p': 99f331ff59Stobias cmdp->cmd_flags &= ~CVS_USE_WDIR; 1007ac78d1dSjoris print_stdout = 1; 1017ac78d1dSjoris cvs_noexec = 1; 1027ac78d1dSjoris break; 103e3095c02Sxsa case 'R': 104bcf22459Stobias flags |= CR_RECURSE_DIRS; 105e3095c02Sxsa break; 106ca2dc546Sniallo case 'r': 1075dd120b0Sjoris cvs_specified_tag = optarg; 108ca2dc546Sniallo break; 10908f90673Sjfb default: 1103ad3fb45Sjoris fatal("%s", cvs_cmd_checkout.cmd_synopsis); 11108f90673Sjfb } 11208f90673Sjfb } 11308f90673Sjfb 11408f90673Sjfb argc -= optind; 11508f90673Sjfb argv += optind; 11608f90673Sjfb 1173ad3fb45Sjoris if (argc == 0) 1183ad3fb45Sjoris fatal("%s", cvs_cmd_checkout.cmd_synopsis); 119e4276007Sjfb 12090f9bb03Sxsa checkout_check_repository(argc, argv); 12190f9bb03Sxsa 12290f9bb03Sxsa return (0); 12390f9bb03Sxsa } 12490f9bb03Sxsa 12590f9bb03Sxsa int 12690f9bb03Sxsa cvs_export(int argc, char **argv) 12790f9bb03Sxsa { 128a2f23aefSxsa int ch; 12990f9bb03Sxsa 13090f9bb03Sxsa prune_dirs = 1; 13190f9bb03Sxsa 13290f9bb03Sxsa while ((ch = getopt(argc, argv, cvs_cmd_export.cmd_opts)) != -1) { 13390f9bb03Sxsa switch (ch) { 134*37fdff3fStobias case 'k': 135*37fdff3fStobias koptstr = optarg; 136*37fdff3fStobias kflag = rcs_kflag_get(koptstr); 137*37fdff3fStobias if (RCS_KWEXP_INVAL(kflag)) { 138*37fdff3fStobias cvs_log(LP_ERR, 139*37fdff3fStobias "invalid RCS keyword expension mode"); 140*37fdff3fStobias fatal("%s", cvs_cmd_add.cmd_synopsis); 141*37fdff3fStobias } 142*37fdff3fStobias break; 14390f9bb03Sxsa case 'l': 14490f9bb03Sxsa flags &= ~CR_RECURSE_DIRS; 14590f9bb03Sxsa break; 14690f9bb03Sxsa case 'R': 147bcf22459Stobias flags |= CR_RECURSE_DIRS; 14890f9bb03Sxsa break; 1490ab67f86Sxsa case 'r': 1500ab67f86Sxsa cvs_specified_tag = optarg; 1510ab67f86Sxsa break; 15290f9bb03Sxsa default: 15390f9bb03Sxsa fatal("%s", cvs_cmd_export.cmd_synopsis); 15490f9bb03Sxsa } 15590f9bb03Sxsa } 15690f9bb03Sxsa 15790f9bb03Sxsa argc -= optind; 15890f9bb03Sxsa argv += optind; 15990f9bb03Sxsa 1605e1effbaStobias if (cvs_specified_tag == NULL) 1615e1effbaStobias fatal("must specify a tag or date"); 1625e1effbaStobias 16390f9bb03Sxsa if (argc == 0) 16490f9bb03Sxsa fatal("%s", cvs_cmd_export.cmd_synopsis); 16590f9bb03Sxsa 16690f9bb03Sxsa checkout_check_repository(argc, argv); 16790f9bb03Sxsa 16890f9bb03Sxsa return (0); 16990f9bb03Sxsa } 17090f9bb03Sxsa 17190f9bb03Sxsa static void 17290f9bb03Sxsa checkout_check_repository(int argc, char **argv) 17390f9bb03Sxsa { 17459b603d6Sxsa int i; 1757fca5395Sjoris char *wdir, *d; 1765219eee5Sjoris struct cvs_recursion cr; 177bf6291b7Sjoris struct module_checkout *mc; 1787fca5395Sjoris struct cvs_ignpat *ip; 1797fca5395Sjoris struct cvs_filelist *fl, *nxt; 1807fca5395Sjoris char repo[MAXPATHLEN], fpath[MAXPATHLEN], *f[1]; 1815219eee5Sjoris 18246bff1c6Stobias build_dirs = print_stdout ? 0 : 1; 18346bff1c6Stobias 1845219eee5Sjoris if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { 1855219eee5Sjoris cvs_client_connect_to_server(); 1865219eee5Sjoris 1875dd120b0Sjoris if (cvs_specified_tag != NULL) 1885dd120b0Sjoris cvs_client_send_request("Argument -r%s", 1895dd120b0Sjoris cvs_specified_tag); 1905219eee5Sjoris if (reset_stickies == 1) 1915219eee5Sjoris cvs_client_send_request("Argument -A"); 1925219eee5Sjoris 193*37fdff3fStobias if (kflag) 194*37fdff3fStobias cvs_client_send_request("Argument -k%s", koptstr); 195*37fdff3fStobias 1968dead7d9Sjoris if (dflag != NULL) 1978dead7d9Sjoris cvs_client_send_request("Argument -d%s", dflag); 1988dead7d9Sjoris 19925e75a48Sxsa if (!(flags & CR_RECURSE_DIRS)) 20025e75a48Sxsa cvs_client_send_request("Argument -l"); 20125e75a48Sxsa 2025219eee5Sjoris if (cvs_cmdop == CVS_OP_CHECKOUT && prune_dirs == 1) 2035219eee5Sjoris cvs_client_send_request("Argument -P"); 2045219eee5Sjoris 2057ac78d1dSjoris if (print_stdout == 1) 2067ac78d1dSjoris cvs_client_send_request("Argument -p"); 2077ac78d1dSjoris 2085219eee5Sjoris cr.enterdir = NULL; 2095219eee5Sjoris cr.leavedir = NULL; 210c634bf10Stobias if (print_stdout) 21146bff1c6Stobias cr.fileproc = NULL; 212c634bf10Stobias else 213c634bf10Stobias cr.fileproc = cvs_client_sendfile; 214c634bf10Stobias 215c634bf10Stobias flags &= ~CR_REPO; 2165219eee5Sjoris cr.flags = flags; 2175219eee5Sjoris 2185e1effbaStobias if (cvs_cmdop != CVS_OP_EXPORT) 2195219eee5Sjoris cvs_file_run(argc, argv, &cr); 2205219eee5Sjoris 2215219eee5Sjoris cvs_client_send_files(argv, argc); 2225219eee5Sjoris cvs_client_senddir("."); 2235219eee5Sjoris 2245219eee5Sjoris cvs_client_send_request("%s", 2255219eee5Sjoris (cvs_cmdop == CVS_OP_CHECKOUT) ? "co" : "export"); 2265219eee5Sjoris 2275219eee5Sjoris cvs_client_get_responses(); 2285219eee5Sjoris 2295219eee5Sjoris return; 2305219eee5Sjoris } 23190f9bb03Sxsa 23251ef6581Sjoris cvs_directory_tag = cvs_specified_tag; 23351ef6581Sjoris 2343ad3fb45Sjoris for (i = 0; i < argc; i++) { 235bf6291b7Sjoris mc = cvs_module_lookup(argv[i]); 236bf6291b7Sjoris current_module = mc; 237fc22209eSjfb 2387fca5395Sjoris TAILQ_FOREACH(fl, &(mc->mc_ignores), flist) 2397fca5395Sjoris cvs_file_ignore(fl->file_path, &checkout_ign_pats); 2407fca5395Sjoris 2417fca5395Sjoris TAILQ_FOREACH(fl, &(mc->mc_modules), flist) { 24275bebbccSjoris (void)xsnprintf(repo, sizeof(repo), "%s/%s", 2437fca5395Sjoris current_cvsroot->cr_dir, fl->file_path); 24475bebbccSjoris 245dbeb8705Sjoris if (!(mc->mc_flags & MODULE_ALIAS) || dflag != NULL) 2467fca5395Sjoris module_repo_root = fl->file_path; 247bf6291b7Sjoris 248bf659b2eSjoris if (mc->mc_flags & MODULE_NORECURSE) 249bf659b2eSjoris flags &= ~CR_RECURSE_DIRS; 250bf659b2eSjoris 251dbeb8705Sjoris if (dflag != NULL) 252dbeb8705Sjoris wdir = dflag; 253f748429cSjoris else if (mc->mc_flags & MODULE_ALIAS) 254f748429cSjoris wdir = fl->file_path; 255dbeb8705Sjoris else 256f748429cSjoris wdir = mc->mc_name; 257dbeb8705Sjoris 2587fca5395Sjoris switch (checkout_classify(repo, fl->file_path)) { 259b0d656e9Stobias case CVS_FILE: 2601526ef95Stobias cr.fileproc = cvs_update_local; 2611526ef95Stobias cr.flags = flags; 26246bff1c6Stobias 2637fca5395Sjoris if (!(mc->mc_flags & MODULE_ALIAS)) { 2647fca5395Sjoris module_repo_root = 2657fca5395Sjoris dirname(fl->file_path); 2667fca5395Sjoris d = wdir; 2677fca5395Sjoris (void)xsnprintf(fpath, sizeof(fpath), 2687fca5395Sjoris "%s/%s", d, 2697fca5395Sjoris basename(fl->file_path)); 2707fca5395Sjoris } else { 2717fca5395Sjoris d = dirname(wdir); 2727fca5395Sjoris strlcpy(fpath, fl->file_path, 2737fca5395Sjoris sizeof(fpath)); 2747fca5395Sjoris } 2757fca5395Sjoris 27646bff1c6Stobias if (build_dirs == 1) 2777fca5395Sjoris cvs_mkpath(d, cvs_specified_tag); 2787fca5395Sjoris 2797fca5395Sjoris f[0] = fpath; 2807fca5395Sjoris cvs_file_run(1, f, &cr); 281b0d656e9Stobias break; 282b0d656e9Stobias case CVS_DIR: 28346bff1c6Stobias if (build_dirs == 1) 284dbeb8705Sjoris cvs_mkpath(wdir, cvs_specified_tag); 285dbeb8705Sjoris checkout_repository(repo, wdir); 286b0d656e9Stobias break; 287b0d656e9Stobias default: 288b0d656e9Stobias break; 2893ad3fb45Sjoris } 2907fca5395Sjoris } 2917fca5395Sjoris 2927fca5395Sjoris if (mc->mc_canfree == 1) { 2937fca5395Sjoris for (fl = TAILQ_FIRST(&(mc->mc_modules)); 2947fca5395Sjoris fl != TAILQ_END(&(mc->mc_modules)); fl = nxt) { 2957fca5395Sjoris nxt = TAILQ_NEXT(fl, flist); 2967fca5395Sjoris TAILQ_REMOVE(&(mc->mc_modules), fl, flist); 2977fca5395Sjoris xfree(fl->file_path); 2987fca5395Sjoris xfree(fl); 2997fca5395Sjoris } 3007fca5395Sjoris } 3017fca5395Sjoris 3027fca5395Sjoris while ((ip = TAILQ_FIRST(&checkout_ign_pats)) != NULL) { 3037fca5395Sjoris TAILQ_REMOVE(&checkout_ign_pats, ip, ip_list); 3047fca5395Sjoris xfree(ip); 3057fca5395Sjoris } 306bf6291b7Sjoris 307bf6291b7Sjoris xfree(mc); 30862f911b4Sjfb } 309b0d656e9Stobias } 310b0d656e9Stobias 311b0d656e9Stobias static int 312b0d656e9Stobias checkout_classify(const char *repo, const char *arg) 313b0d656e9Stobias { 314b0d656e9Stobias char *d, *f, fpath[MAXPATHLEN]; 315b0d656e9Stobias struct stat sb; 316b0d656e9Stobias 317b0d656e9Stobias if (stat(repo, &sb) == 0) { 3187fca5395Sjoris if (S_ISDIR(sb.st_mode)) 319b0d656e9Stobias return CVS_DIR; 320b0d656e9Stobias } 321b0d656e9Stobias 322b0d656e9Stobias d = dirname(repo); 323b0d656e9Stobias f = basename(repo); 324b0d656e9Stobias 325b0d656e9Stobias (void)xsnprintf(fpath, sizeof(fpath), "%s/%s%s", d, f, RCS_FILE_EXT); 326b0d656e9Stobias if (stat(fpath, &sb) == 0) { 327b0d656e9Stobias if (!S_ISREG(sb.st_mode)) { 328b0d656e9Stobias cvs_log(LP_ERR, "ignoring %s: not a regular file", arg); 329b0d656e9Stobias return 0; 330b0d656e9Stobias } 331b0d656e9Stobias return CVS_FILE; 332b0d656e9Stobias } 333b0d656e9Stobias 334b0d656e9Stobias (void)xsnprintf(fpath, sizeof(fpath), "%s/%s/%s%s", 335b0d656e9Stobias d, CVS_PATH_ATTIC, f, RCS_FILE_EXT); 336b0d656e9Stobias if (stat(fpath, &sb) == 0) { 337b0d656e9Stobias if (!S_ISREG(sb.st_mode)) { 338b0d656e9Stobias cvs_log(LP_ERR, "ignoring %s: not a regular file", arg); 339b0d656e9Stobias return 0; 340b0d656e9Stobias } 341b0d656e9Stobias return CVS_FILE; 342b0d656e9Stobias } 343b0d656e9Stobias 344b0d656e9Stobias cvs_log(LP_ERR, "cannot find module `%s' - ignored", arg); 345b0d656e9Stobias return 0; 346b0d656e9Stobias } 34708f90673Sjfb 3483ad3fb45Sjoris static void 3493ad3fb45Sjoris checkout_repository(const char *repobase, const char *wdbase) 35016cfc147Sjoris { 3513ad3fb45Sjoris struct cvs_flisthead fl, dl; 3523ad3fb45Sjoris struct cvs_recursion cr; 3535191afffSjoris 3543ad3fb45Sjoris TAILQ_INIT(&fl); 3553ad3fb45Sjoris TAILQ_INIT(&dl); 3565191afffSjoris 357a76e09e0Sxsa cvs_history_add((cvs_cmdop == CVS_OP_CHECKOUT) ? 358a76e09e0Sxsa CVS_HISTORY_CHECKOUT : CVS_HISTORY_EXPORT, NULL, wdbase); 3593901dfa5Sjoris 360f331ff59Stobias if (print_stdout) { 361f331ff59Stobias cr.enterdir = NULL; 362f331ff59Stobias cr.leavedir = NULL; 363f331ff59Stobias } else { 3643ad3fb45Sjoris cr.enterdir = cvs_update_enterdir; 365fec3e093Stobias cr.leavedir = prune_dirs ? cvs_update_leavedir : NULL; 366f331ff59Stobias } 367bc5d89feSjoris cr.fileproc = cvs_update_local; 368a2f23aefSxsa cr.flags = flags; 369e4276007Sjfb 3703ad3fb45Sjoris cvs_repository_lock(repobase); 37157448823Stobias cvs_repository_getdir(repobase, wdbase, &fl, &dl, 37257448823Stobias flags & CR_RECURSE_DIRS ? 1 : 0); 37350b634f9Sjoris 3743ad3fb45Sjoris cvs_file_walklist(&fl, &cr); 3753ad3fb45Sjoris cvs_file_freelist(&fl); 376e4276007Sjfb 3773ad3fb45Sjoris cvs_repository_unlock(repobase); 37850b634f9Sjoris 3793ad3fb45Sjoris cvs_file_walklist(&dl, &cr); 3803ad3fb45Sjoris cvs_file_freelist(&dl); 38150b634f9Sjoris } 38250b634f9Sjoris 383f9872b43Sjoris void 3845d320860Sjoris cvs_checkout_file(struct cvs_file *cf, RCSNUM *rnum, char *tag, int co_flags) 3855191afffSjoris { 386*37fdff3fStobias int cf_kflag, oflags, exists; 3873ad3fb45Sjoris time_t rcstime; 3883ad3fb45Sjoris CVSENTRIES *ent; 3893ad3fb45Sjoris struct timeval tv[2]; 390828954c0Sjoris char *tosend; 3915dd120b0Sjoris char template[MAXPATHLEN], entry[CVS_ENT_MAXLINELEN]; 3924967382bSxsa char kbuf[8], sticky[CVS_REV_BUFSZ], rev[CVS_REV_BUFSZ]; 3930a7da307Sxsa char timebuf[CVS_TIME_BUFSZ], tbuf[CVS_TIME_BUFSZ]; 3945191afffSjoris 395828954c0Sjoris exists = 0; 396828954c0Sjoris tosend = NULL; 39751ef6581Sjoris 39851ef6581Sjoris if (!(co_flags & CO_REMOVE)) 3993ad3fb45Sjoris rcsnum_tostr(rnum, rev, sizeof(rev)); 4005191afffSjoris 4019fac60a5Sjoris cvs_log(LP_TRACE, "cvs_checkout_file(%s, %s, %d) -> %s", 402a2f23aefSxsa cf->file_path, rev, co_flags, 4039fac60a5Sjoris (cvs_server_active) ? "to client" : "to disk"); 4045191afffSjoris 405a2f23aefSxsa if (co_flags & CO_DUMP) { 40687d368dcStobias rcs_rev_write_fd(cf->file_rcs, rnum, STDOUT_FILENO, 0); 407b17342c4Sreyk return; 408b17342c4Sreyk } 409b17342c4Sreyk 4109fac60a5Sjoris if (cvs_server_active == 0) { 411828954c0Sjoris if (!(co_flags & CO_MERGE)) { 4123ad3fb45Sjoris oflags = O_WRONLY | O_TRUNC; 4133ad3fb45Sjoris if (cf->fd != -1) { 4143ad3fb45Sjoris exists = 1; 4153ad3fb45Sjoris (void)close(cf->fd); 4163ad3fb45Sjoris } else { 4173ad3fb45Sjoris oflags |= O_CREAT; 4183ad3fb45Sjoris } 4193ad3fb45Sjoris 4203ad3fb45Sjoris cf->fd = open(cf->file_path, oflags); 4213ad3fb45Sjoris if (cf->fd == -1) 422828954c0Sjoris fatal("cvs_checkout_file: open: %s", 423828954c0Sjoris strerror(errno)); 4243ad3fb45Sjoris 42587d368dcStobias rcs_rev_write_fd(cf->file_rcs, rnum, cf->fd, 0); 426828954c0Sjoris } else { 427828954c0Sjoris cvs_merge_file(cf, 1); 428828954c0Sjoris } 4293ad3fb45Sjoris 4303ad3fb45Sjoris if (fchmod(cf->fd, 0644) == -1) 4313ad3fb45Sjoris fatal("cvs_checkout_file: fchmod: %s", strerror(errno)); 4323ad3fb45Sjoris 433828954c0Sjoris if ((exists == 0) && (cf->file_ent == NULL) && 434828954c0Sjoris !(co_flags & CO_MERGE)) 4353ad3fb45Sjoris rcstime = rcs_rev_getdate(cf->file_rcs, rnum); 43647e5fe63Sjoris else 4373ad3fb45Sjoris time(&rcstime); 4383ad3fb45Sjoris 4393ad3fb45Sjoris tv[0].tv_sec = rcstime; 4403ad3fb45Sjoris tv[0].tv_usec = 0; 4413ad3fb45Sjoris tv[1] = tv[0]; 4423ad3fb45Sjoris if (futimes(cf->fd, tv) == -1) 4439fac60a5Sjoris fatal("cvs_checkout_file: futimes: %s", 4449fac60a5Sjoris strerror(errno)); 4459fac60a5Sjoris } else { 4469fac60a5Sjoris time(&rcstime); 4479fac60a5Sjoris } 4483ad3fb45Sjoris 44947e5fe63Sjoris asctime_r(gmtime(&rcstime), tbuf); 4502820b891Stobias tbuf[strcspn(tbuf, "\n")] = '\0'; 451f9872b43Sjoris 452a2f23aefSxsa if (co_flags & CO_MERGE) { 453c486465dSxsa (void)xsnprintf(timebuf, sizeof(timebuf), "Result of merge+%s", 454f9872b43Sjoris tbuf); 455f9872b43Sjoris } else { 456f9872b43Sjoris strlcpy(timebuf, tbuf, sizeof(timebuf)); 457f9872b43Sjoris } 4583ad3fb45Sjoris 459c486465dSxsa if (co_flags & CO_SETSTICKY) 4605d320860Sjoris if (tag != NULL) 4610bf9adf7Sxsa (void)xsnprintf(sticky, sizeof(sticky), "T%s", tag); 462ca2dc546Sniallo else 4630bf9adf7Sxsa (void)xsnprintf(sticky, sizeof(sticky), "T%s", rev); 464ebd8626fStobias else if (!reset_stickies && cf->file_ent != NULL && 465ebd8626fStobias cf->file_ent->ce_tag != NULL) 4660bf9adf7Sxsa (void)xsnprintf(sticky, sizeof(sticky), "T%s", 467ebd8626fStobias cf->file_ent->ce_tag); 468c486465dSxsa else 4690bf9adf7Sxsa sticky[0] = '\0'; 4706fba94e7Sjoris 47156f996a2Sxsa kbuf[0] = '\0'; 472*37fdff3fStobias if (cf->file_rcs->rf_expand != NULL) { 473*37fdff3fStobias cf_kflag = rcs_kflag_get(cf->file_rcs->rf_expand); 474*37fdff3fStobias if (kflag || cf_kflag != RCS_KWEXP_DEFAULT) 475c486465dSxsa (void)xsnprintf(kbuf, sizeof(kbuf), 47656f996a2Sxsa "-k%s", cf->file_rcs->rf_expand); 477*37fdff3fStobias } else if (!reset_stickies && cf->file_ent != NULL) { 478*37fdff3fStobias if (cf->file_ent->ce_opts != NULL) 479*37fdff3fStobias strlcpy(kbuf, cf->file_ent->ce_opts, sizeof(kbuf)); 48056f996a2Sxsa } 48156f996a2Sxsa 482c486465dSxsa (void)xsnprintf(entry, CVS_ENT_MAXLINELEN, "/%s/%s/%s/%s/%s", 4830bf9adf7Sxsa cf->file_name, rev, timebuf, kbuf, sticky); 4843ad3fb45Sjoris 4859fac60a5Sjoris if (cvs_server_active == 0) { 4865e1effbaStobias if (!(co_flags & CO_REMOVE) && cvs_cmdop != CVS_OP_EXPORT) { 4873ad3fb45Sjoris ent = cvs_ent_open(cf->file_wd); 4883ad3fb45Sjoris cvs_ent_add(ent, entry); 4893ad3fb45Sjoris cvs_ent_close(ent, ENT_SYNC); 49052979273Sjoris } 4919fac60a5Sjoris } else { 492828954c0Sjoris if (co_flags & CO_MERGE) { 493828954c0Sjoris cvs_merge_file(cf, 1); 494828954c0Sjoris tosend = cf->file_path; 495828954c0Sjoris } 496828954c0Sjoris 497a2f23aefSxsa if (co_flags & CO_COMMIT) 498408908afSjoris cvs_server_update_entry("Checked-in", cf); 499828954c0Sjoris else if (co_flags & CO_MERGE) 500828954c0Sjoris cvs_server_update_entry("Merged", cf); 50152979273Sjoris else if (co_flags & CO_REMOVE) 50252979273Sjoris cvs_server_update_entry("Removed", cf); 503408908afSjoris else 504408908afSjoris cvs_server_update_entry("Updated", cf); 5057fffa3ccSjoris 50652979273Sjoris if (!(co_flags & CO_REMOVE)) 5079fac60a5Sjoris cvs_remote_output(entry); 5087fffa3ccSjoris 50952979273Sjoris if (!(co_flags & CO_COMMIT) && !(co_flags & CO_REMOVE)) { 510828954c0Sjoris if (!(co_flags & CO_MERGE)) { 511c486465dSxsa (void)xsnprintf(template, MAXPATHLEN, 512bb510330Sjoris "%s/checkout.XXXXXXXXXX", cvs_tmpdir); 513c486465dSxsa 514828954c0Sjoris rcs_rev_write_stmp(cf->file_rcs, rnum, 515828954c0Sjoris template, 0); 516828954c0Sjoris tosend = template; 517828954c0Sjoris } 5189fac60a5Sjoris 519828954c0Sjoris cvs_remote_send_file(tosend); 520828954c0Sjoris 521828954c0Sjoris if (!(co_flags & CO_MERGE)) { 522828954c0Sjoris (void)unlink(template); 523828954c0Sjoris cvs_worklist_run(&temp_files, 524828954c0Sjoris cvs_worklist_unlink); 525828954c0Sjoris } 5267fffa3ccSjoris } 5279fac60a5Sjoris } 5283ad3fb45Sjoris } 529