[BACK]Return to co.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / rcs

Annotation of src/usr.bin/rcs/co.c, Revision 1.126

1.126   ! deraadt     1: /*     $OpenBSD: co.c,v 1.125 2019/04/26 19:11:01 millert Exp $        */
1.1       joris       2: /*
                      3:  * Copyright (c) 2005 Joris Vink <joris@openbsd.org>
                      4:  * All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  *
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. The name of the author may not be used to endorse or promote products
                     13:  *    derived from this software without specific prior written permission.
                     14:  *
                     15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
                     16:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
                     17:  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
                     18:  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     19:  * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     20:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     21:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     22:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     23:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     24:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     25:  */
                     26:
1.105     xsa        27: #include <sys/stat.h>
1.116     chl        28: #include <sys/time.h>
1.105     xsa        29:
                     30: #include <err.h>
                     31: #include <fcntl.h>
                     32: #include <stdio.h>
                     33: #include <stdlib.h>
                     34: #include <string.h>
                     35: #include <unistd.h>
1.1       joris      36:
                     37: #include "rcsprog.h"
1.100     millert    38: #include "diff.h"
1.1       joris      39:
1.70      xsa        40: #define CO_OPTSTRING   "d:f::I::k:l::M::p::q::r::s:Tu::Vw::x::z::"
1.38      xsa        41:
1.43      xsa        42: static void    checkout_err_nobranch(RCSFILE *, const char *, const char *,
                     43:     const char *, int);
1.100     millert    44: static int     checkout_file_has_diffs(RCSFILE *, RCSNUM *, const char *);
1.4       joris      45:
1.1       joris      46: int
                     47: checkout_main(int argc, char **argv)
                     48: {
1.106     xsa        49:        int fd, i, ch, flags, kflag, ret;
1.78      pat        50:        RCSNUM *rev;
1.1       joris      51:        RCSFILE *file;
1.94      ray        52:        const char *author, *date, *state;
1.120     deraadt    53:        char fpath[PATH_MAX];
1.94      ray        54:        char *rev_str, *username;
1.37      xsa        55:        time_t rcs_mtime = -1;
1.1       joris      56:
1.106     xsa        57:        flags = ret = 0;
1.33      xsa        58:        kflag = RCS_KWEXP_ERR;
1.73      ray        59:        rev_str = NULL;
1.94      ray        60:        author = date = state = NULL;
1.4       joris      61:
1.38      xsa        62:        while ((ch = rcs_getopt(argc, argv, CO_OPTSTRING)) != -1) {
1.1       joris      63:                switch (ch) {
1.49      joris      64:                case 'd':
1.94      ray        65:                        date = rcs_optarg;
1.49      joris      66:                        break;
1.18      joris      67:                case 'f':
1.73      ray        68:                        rcs_setrevstr(&rev_str, rcs_optarg);
1.24      niallo     69:                        flags |= FORCE;
1.18      joris      70:                        break;
1.65      niallo     71:                case 'I':
1.73      ray        72:                        rcs_setrevstr(&rev_str, rcs_optarg);
1.65      niallo     73:                        flags |= INTERACTIVE;
                     74:                        break;
                     75:
1.33      xsa        76:                case 'k':
                     77:                        kflag = rcs_kflag_get(rcs_optarg);
                     78:                        if (RCS_KWEXP_INVAL(kflag)) {
1.83      xsa        79:                                warnx("invalid RCS keyword substitution mode");
1.33      xsa        80:                                (usage)();
                     81:                        }
                     82:                        break;
1.4       joris      83:                case 'l':
1.53      xsa        84:                        if (flags & CO_UNLOCK) {
1.81      xsa        85:                                warnx("warning: -u overridden by -l");
1.53      xsa        86:                                flags &= ~CO_UNLOCK;
                     87:                        }
1.73      ray        88:                        rcs_setrevstr(&rev_str, rcs_optarg);
1.24      niallo     89:                        flags |= CO_LOCK;
1.26      niallo     90:                        break;
                     91:                case 'M':
1.73      ray        92:                        rcs_setrevstr(&rev_str, rcs_optarg);
1.26      niallo     93:                        flags |= CO_REVDATE;
1.4       joris      94:                        break;
1.20      joris      95:                case 'p':
1.73      ray        96:                        rcs_setrevstr(&rev_str, rcs_optarg);
1.80      xsa        97:                        flags |= PIPEOUT;
1.20      joris      98:                        break;
1.3       joris      99:                case 'q':
1.73      ray       100:                        rcs_setrevstr(&rev_str, rcs_optarg);
1.79      xsa       101:                        flags |= QUIET;
1.3       joris     102:                        break;
1.1       joris     103:                case 'r':
1.73      ray       104:                        rcs_setrevstr(&rev_str, rcs_optarg);
1.4       joris     105:                        break;
1.24      niallo    106:                case 's':
1.94      ray       107:                        state = rcs_optarg;
1.24      niallo    108:                        flags |= CO_STATE;
1.34      xsa       109:                        break;
                    110:                case 'T':
                    111:                        flags |= PRESERVETIME;
1.24      niallo    112:                        break;
1.4       joris     113:                case 'u':
1.73      ray       114:                        rcs_setrevstr(&rev_str, rcs_optarg);
1.53      xsa       115:                        if (flags & CO_LOCK) {
1.81      xsa       116:                                warnx("warning: -l overridden by -u");
1.53      xsa       117:                                flags &= ~CO_LOCK;
                    118:                        }
1.24      niallo    119:                        flags |= CO_UNLOCK;
1.1       joris     120:                        break;
1.7       joris     121:                case 'V':
                    122:                        printf("%s\n", rcs_version);
                    123:                        exit(0);
1.38      xsa       124:                case 'w':
1.44      joris     125:                        /* if no argument, assume current user */
                    126:                        if (rcs_optarg == NULL) {
1.48      xsa       127:                                if ((author = getlogin()) == NULL)
1.84      xsa       128:                                        err(1, "getlogin");
1.94      ray       129:                        } else
                    130:                                author = rcs_optarg;
1.43      xsa       131:                        flags |= CO_AUTHOR;
1.38      xsa       132:                        break;
1.30      xsa       133:                case 'x':
1.66      ray       134:                        /* Use blank extension if none given. */
                    135:                        rcs_suffixes = rcs_optarg ? rcs_optarg : "";
1.59      joris     136:                        break;
                    137:                case 'z':
                    138:                        timezone_flag = rcs_optarg;
1.30      xsa       139:                        break;
1.1       joris     140:                default:
                    141:                        (usage)();
                    142:                }
                    143:        }
                    144:
1.13      joris     145:        argc -= rcs_optind;
                    146:        argv += rcs_optind;
1.1       joris     147:
                    148:        if (argc == 0) {
1.81      xsa       149:                warnx("no input file");
1.1       joris     150:                (usage)();
                    151:        }
1.11      deraadt   152:
1.81      xsa       153:        if ((username = getlogin()) == NULL)
1.84      xsa       154:                err(1, "getlogin");
1.104     otto      155:
1.1       joris     156:        for (i = 0; i < argc; i++) {
1.92      ray       157:                fd = rcs_choosefile(argv[i], fpath, sizeof(fpath));
                    158:                if (fd < 0) {
1.98      niallo    159:                        warn("%s", fpath);
1.106     xsa       160:                        ret = 1;
1.1       joris     161:                        continue;
1.92      ray       162:                }
1.104     otto      163:                rcs_strip_suffix(argv[i]);
1.1       joris     164:
1.79      xsa       165:                if (!(flags & QUIET))
1.90      xsa       166:                        (void)fprintf(stderr, "%s  -->  %s\n", fpath,
1.80      xsa       167:                            (flags & PIPEOUT) ? "standard output" : argv[i]);
1.35      xsa       168:
                    169:                if ((flags & CO_LOCK) && (kflag & RCS_KWEXP_VAL)) {
1.81      xsa       170:                        warnx("%s: cannot combine -kv and -l", fpath);
1.86      joris     171:                        (void)close(fd);
1.35      xsa       172:                        continue;
                    173:                }
1.21      niallo    174:
1.86      joris     175:                if ((file = rcs_open(fpath, fd,
                    176:                    RCS_RDWR|RCS_PARSE_FULLY)) == NULL)
1.1       joris     177:                        continue;
                    178:
1.37      xsa       179:                if (flags & PRESERVETIME)
1.86      joris     180:                        rcs_mtime = rcs_get_mtime(file);
1.37      xsa       181:
1.72      xsa       182:                rcs_kwexp_set(file, kflag);
1.37      xsa       183:
1.75      ray       184:                if (rev_str != NULL) {
                    185:                        if ((rev = rcs_getrevnum(rev_str, file)) == NULL)
1.84      xsa       186:                                errx(1, "invalid revision: %s", rev_str);
1.75      ray       187:                } else {
1.76      joris     188:                        /* no revisions in RCS file, generate empty 0.0 */
                    189:                        if (file->rf_ndelta == 0) {
                    190:                                rev = rcsnum_parse("0.0");
                    191:                                if (rev == NULL)
1.84      xsa       192:                                        errx(1, "failed to generate rev 0.0");
1.76      joris     193:                        } else {
                    194:                                rev = rcsnum_alloc();
                    195:                                rcsnum_cpy(file->rf_head, rev, 0);
                    196:                        }
1.73      ray       197:                }
1.17      joris     198:
1.106     xsa       199:                if (checkout_rev(file, rev, argv[i], flags,
                    200:                    username, author, state, date) < 0) {
1.73      ray       201:                        rcs_close(file);
                    202:                        rcsnum_free(rev);
1.106     xsa       203:                        ret = 1;
1.73      ray       204:                        continue;
1.8       niallo    205:                }
1.58      xsa       206:
1.79      xsa       207:                if (!(flags & QUIET))
1.90      xsa       208:                        (void)fprintf(stderr, "done\n");
1.17      joris     209:
1.73      ray       210:                rcsnum_free(rev);
1.37      xsa       211:
1.86      joris     212:                rcs_write(file);
1.37      xsa       213:                if (flags & PRESERVETIME)
1.86      joris     214:                        rcs_set_mtime(file, rcs_mtime);
                    215:                rcs_close(file);
1.1       joris     216:        }
                    217:
1.106     xsa       218:        return (ret);
1.1       joris     219: }
                    220:
1.118     otto      221: __dead void
1.1       joris     222: checkout_usage(void)
                    223: {
1.11      deraadt   224:        fprintf(stderr,
1.42      xsa       225:            "usage: co [-TV] [-ddate] [-f[rev]] [-I[rev]] [-kmode] [-l[rev]]\n"
                    226:            "          [-M[rev]] [-p[rev]] [-q[rev]] [-r[rev]] [-sstate]\n"
                    227:            "          [-u[rev]] [-w[user]] [-xsuffixes] [-ztz] file ...\n");
1.118     otto      228:
                    229:        exit(1);
1.1       joris     230: }
1.14      niallo    231:
                    232: /*
                    233:  * Checkout revision <rev> from RCSFILE <file>, writing it to the path <dst>
1.88      ray       234:  * Currently recognised <flags> are CO_LOCK, CO_UNLOCK and CO_REVDATE.
1.14      niallo    235:  *
1.49      joris     236:  * Looks up revision based upon <lockname>, <author>, <state> and <date>
1.44      joris     237:  *
1.14      niallo    238:  * Returns 0 on success, -1 on failure.
                    239:  */
                    240: int
1.24      niallo    241: checkout_rev(RCSFILE *file, RCSNUM *frev, const char *dst, int flags,
1.49      joris     242:     const char *lockname, const char *author, const char *state,
                    243:     const char *date)
1.14      niallo    244: {
1.44      joris     245:        BUF *bp;
1.69      joris     246:        u_int i;
1.86      joris     247:        int fd, lcount;
1.108     xsa       248:        char buf[RCS_REV_BUFSZ];
1.99      millert   249:        mode_t mode = DEFFILEMODE;
1.18      joris     250:        struct stat st;
1.44      joris     251:        struct rcs_delta *rdp;
                    252:        struct rcs_lock *lkp;
1.97      ray       253:        char *fdate;
1.100     millert   254:        const char *fstatus;
1.49      joris     255:        time_t rcsdate, givendate;
1.69      joris     256:        RCSNUM *rev;
1.49      joris     257:
1.119     otto      258:        givendate = -1;
1.113     ray       259:        if (date != NULL && (givendate = date_parse(date)) == -1) {
                    260:                warnx("invalid date: %s", date);
                    261:                return -1;
                    262:        }
1.14      niallo    263:
1.90      xsa       264:        if (file->rf_ndelta == 0 && !(flags & QUIET))
                    265:                (void)fprintf(stderr,
                    266:                    "no revisions present; generating empty revision 0.0\n");
1.76      joris     267:
1.69      joris     268:        /* XXX rcsnum_cmp()
                    269:         * Check out the latest revision if <frev> is greater than HEAD
                    270:         */
1.76      joris     271:        if (file->rf_ndelta != 0) {
                    272:                for (i = 0; i < file->rf_head->rn_len; i++) {
                    273:                        if (file->rf_head->rn_id[i] < frev->rn_id[i]) {
                    274:                                frev = file->rf_head;
                    275:                                break;
                    276:                        }
1.69      joris     277:                }
                    278:        }
1.15      niallo    279:
1.44      joris     280:        lcount = 0;
                    281:        TAILQ_FOREACH(lkp, &(file->rf_locks), rl_list) {
                    282:                if (!strcmp(lkp->rl_name, lockname))
                    283:                        lcount++;
                    284:        }
                    285:
                    286:        /*
                    287:         * If the user didn't specify any revision, we cycle through
                    288:         * revisions to lookup the first one that matches what he specified.
                    289:         *
                    290:         * If we cannot find one, we return an error.
                    291:         */
                    292:        rdp = NULL;
1.77      deraadt   293:        if (file->rf_ndelta != 0 && frev == file->rf_head) {
1.44      joris     294:                if (lcount > 1) {
1.81      xsa       295:                        warnx("multiple revisions locked by %s; "
1.44      joris     296:                            "please specify one", lockname);
                    297:                        return (-1);
                    298:                }
                    299:
                    300:                TAILQ_FOREACH(rdp, &file->rf_delta, rd_list) {
1.49      joris     301:                        if (date != NULL) {
                    302:                                fdate = asctime(&rdp->rd_date);
1.113     ray       303:                                if ((rcsdate = date_parse(fdate)) == -1) {
                    304:                                        warnx("invalid date: %s", fdate);
                    305:                                        return -1;
                    306:                                }
1.49      joris     307:                                if (givendate <= rcsdate)
                    308:                                        continue;
                    309:                        }
                    310:
1.77      deraadt   311:                        if (author != NULL &&
                    312:                            strcmp(rdp->rd_author, author))
1.44      joris     313:                                continue;
1.49      joris     314:
1.77      deraadt   315:                        if (state != NULL &&
                    316:                            strcmp(rdp->rd_state, state))
1.44      joris     317:                                continue;
                    318:
                    319:                        frev = rdp->rd_num;
                    320:                        break;
                    321:                }
1.76      joris     322:        } else if (file->rf_ndelta != 0) {
1.44      joris     323:                rdp = rcs_findrev(file, frev);
                    324:        }
                    325:
1.77      deraadt   326:        if (file->rf_ndelta != 0 && rdp == NULL) {
1.49      joris     327:                checkout_err_nobranch(file, author, date, state, flags);
1.44      joris     328:                return (-1);
                    329:        }
                    330:
1.76      joris     331:        if (file->rf_ndelta == 0)
                    332:                rev = frev;
                    333:        else
                    334:                rev = rdp->rd_num;
                    335:
1.69      joris     336:        rcsnum_tostr(rev, buf, sizeof(buf));
1.15      niallo    337:
1.77      deraadt   338:        if (file->rf_ndelta != 0 && rdp->rd_locker != NULL) {
1.44      joris     339:                if (strcmp(lockname, rdp->rd_locker)) {
1.97      ray       340:                        warnx("Revision %s is already locked by %s; %s",
                    341:                            buf, rdp->rd_locker,
                    342:                            (flags & CO_UNLOCK) ? "use co -r or rcs -u" : "");
1.44      joris     343:                        return (-1);
                    344:                }
                    345:        }
                    346:
1.79      xsa       347:        if (!(flags & QUIET) && !(flags & NEWFILE) &&
1.77      deraadt   348:            !(flags & CO_REVERT) && file->rf_ndelta != 0)
1.91      xsa       349:                (void)fprintf(stderr, "revision %s", buf);
1.74      deraadt   350:
1.76      joris     351:        if (file->rf_ndelta != 0) {
                    352:                if ((bp = rcs_getrev(file, rev)) == NULL) {
1.81      xsa       353:                        warnx("cannot find revision `%s'", buf);
1.76      joris     354:                        return (-1);
                    355:                }
                    356:        } else {
1.112     ray       357:                bp = buf_alloc(1);
1.14      niallo    358:        }
1.69      joris     359:
1.55      niallo    360:        /*
1.67      niallo    361:         * File inherits permissions from its ,v file
                    362:         */
1.115     tobias    363:        if (file->rf_file != NULL) {
                    364:                if (fstat(fileno(file->rf_file), &st) == -1)
1.86      joris     365:                        err(1, "%s", file->rf_path);
1.102     xsa       366:                file->rf_mode = mode = st.st_mode;
1.103     niallo    367:        } else {
                    368:                mode = file->rf_mode;
1.86      joris     369:        }
1.67      niallo    370:
1.24      niallo    371:        if (flags & CO_LOCK) {
1.99      millert   372:                /* File should only be writable by owner. */
                    373:                mode &= ~(S_IWGRP|S_IWOTH);
1.67      niallo    374:                mode |= S_IWUSR;
1.76      joris     375:
                    376:                if (file->rf_ndelta != 0) {
1.79      xsa       377:                        if (!(flags & QUIET) && !(flags & NEWFILE) &&
1.77      deraadt   378:                            !(flags & CO_REVERT))
1.124     joris     379:                                (void)fprintf(stderr, " (locked)\n");
1.76      joris     380:                }
1.24      niallo    381:        } else if (flags & CO_UNLOCK) {
1.76      joris     382:                if (file->rf_ndelta != 0) {
                    383:                        if (rcs_lock_remove(file, lockname, rev) < 0) {
                    384:                                if (rcs_errno != RCS_ERR_NOENT)
                    385:                                        return (-1);
                    386:                        }
1.46      joris     387:                }
1.18      joris     388:
1.67      niallo    389:                /* Strip all write bits from mode */
1.99      millert   390:                mode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
1.76      joris     391:
                    392:                if (file->rf_ndelta != 0) {
1.79      xsa       393:                        if (!(flags & QUIET) && !(flags & NEWFILE) &&
1.77      deraadt   394:                            !(flags & CO_REVERT))
1.124     joris     395:                                (void)fprintf(stderr, " (unlocked)\n");
1.76      joris     396:                }
1.125     millert   397:        } else {
                    398:                if (file->rf_ndelta != 0) {
                    399:                        if (!(flags & QUIET) && !(flags & NEWFILE) &&
                    400:                            !(flags & CO_REVERT))
                    401:                                (void)fprintf(stderr, "\n");
                    402:                }
1.18      joris     403:        }
1.107     xsa       404:
1.100     millert   405:        if ((flags & (PIPEOUT|FORCE)) == 0 && stat(dst, &st) != -1) {
1.68      ray       406:                /*
1.100     millert   407:                 * Prompt the user if the file is writable or the file is
                    408:                 * not writable but is different from the RCS head version.
                    409:                 * This is different from GNU which will silently overwrite
                    410:                 * the file regardless of its contents so long as it is
                    411:                 * read-only.
1.68      ray       412:                 */
                    413:                if (st.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))
1.100     millert   414:                        fstatus = "writable";
                    415:                else if (checkout_file_has_diffs(file, frev, dst) != D_SAME)
                    416:                        fstatus = "modified";
                    417:                else
                    418:                        fstatus = NULL;
                    419:                if (fstatus) {
                    420:                        (void)fprintf(stderr, "%s %s exists%s; ", fstatus, dst,
                    421:                            (getuid() == st.st_uid) ? "" :
                    422:                            ", and you do not own it");
                    423:                        (void)fprintf(stderr, "remove it? [ny](n): ");
                    424:                        if (rcs_yesno('n') == 'n') {
                    425:                                if (!(flags & QUIET) && isatty(STDIN_FILENO))
                    426:                                        warnx("%s %s exists; checkout aborted",
                    427:                                            fstatus, dst);
                    428:                                else
                    429:                                        warnx("checkout aborted");
                    430:                                return (-1);
                    431:                        }
1.18      joris     432:                }
1.14      niallo    433:        }
1.124     joris     434:
                    435:        if (flags & CO_LOCK) {
                    436:                if (file->rf_ndelta != 0) {
                    437:                        if (lockname != NULL &&
                    438:                            rcs_lock_add(file, lockname, rev) < 0) {
                    439:                                if (rcs_errno != RCS_ERR_DUPENT)
                    440:                                        return (-1);
                    441:                        }
                    442:                }
                    443:        }
                    444:
                    445:        /* If strict locking is disabled, make file writable by owner. */
                    446:        if (rcs_lock_getmode(file) == RCS_LOCK_LOOSE)
                    447:                mode |= S_IWUSR;
                    448:
                    449:        if (file->rf_ndelta == 0 && !(flags & QUIET) &&
                    450:            ((flags & CO_LOCK) || (flags & CO_UNLOCK))) {
                    451:                (void)fprintf(stderr, "no revisions, so nothing can be %s\n",
                    452:                    (flags & CO_LOCK) ? "locked" : "unlocked");
                    453:        }
                    454:
                    455:        if (flags & CO_LOCK) {
                    456:                if (rcs_errno != RCS_ERR_DUPENT)
                    457:                        lcount++;
                    458:                if (!(flags & QUIET) && lcount > 1 && !(flags & CO_REVERT))
                    459:                        warnx("%s: warning: You now have %d locks.",
                    460:                            file->rf_path, lcount);
                    461:        }
                    462:
                    463:        /* Finally do keyword expansion if required. */
                    464:        if (file->rf_ndelta != 0)
                    465:                bp = rcs_kwexp_buf(bp, file, rev);
1.17      joris     466:
1.96      ray       467:        if (flags & PIPEOUT)
1.111     ray       468:                buf_write_fd(bp, STDOUT_FILENO);
1.96      ray       469:        else {
1.86      joris     470:                (void)unlink(dst);
                    471:
1.126   ! deraadt   472:                if ((fd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1)
1.86      joris     473:                        err(1, "%s", dst);
                    474:
1.111     ray       475:                if (buf_write_fd(bp, fd) < 0) {
1.81      xsa       476:                        warnx("failed to write revision to file");
1.111     ray       477:                        buf_free(bp);
1.86      joris     478:                        (void)close(fd);
1.20      joris     479:                        return (-1);
                    480:                }
1.86      joris     481:
                    482:                if (fchmod(fd, mode) == -1)
                    483:                        warn("%s", dst);
                    484:
1.24      niallo    485:                if (flags & CO_REVDATE) {
                    486:                        struct timeval tv[2];
1.36      xsa       487:                        memset(&tv, 0, sizeof(tv));
1.117     deraadt   488:                        tv[0].tv_sec = rcs_rev_getdate(file, rev);
1.24      niallo    489:                        tv[1].tv_sec = tv[0].tv_sec;
1.126   ! deraadt   490:                        if (futimes(fd, (const struct timeval *)&tv) == -1)
1.81      xsa       491:                                warn("utimes");
1.24      niallo    492:                }
1.86      joris     493:
                    494:                (void)close(fd);
1.14      niallo    495:        }
1.96      ray       496:
1.111     ray       497:        buf_free(bp);
1.17      joris     498:
1.14      niallo    499:        return (0);
1.43      xsa       500: }
                    501:
                    502: /*
                    503:  * checkout_err_nobranch()
                    504:  *
                    505:  * XXX - should handle the dates too.
                    506:  */
                    507: static void
                    508: checkout_err_nobranch(RCSFILE *file, const char *author, const char *date,
                    509:     const char *state, int flags)
                    510: {
                    511:        if (!(flags & CO_AUTHOR))
                    512:                author = NULL;
                    513:        if (!(flags & CO_STATE))
                    514:                state = NULL;
                    515:
1.123     otto      516:        warnx("%s: No revision on branch has %s%s%s%s%s%s%s%s.",
1.43      xsa       517:            file->rf_path,
1.123     otto      518:            date ? "a date before " : "",
1.43      xsa       519:            date ? date : "",
1.123     otto      520:            (date && author) ? " and " : "",
                    521:            author ? "author " : "",
1.43      xsa       522:            author ? author : "",
1.123     otto      523:            ((date || author) && state) ? " and " : "",
                    524:            state ? "state " : "",
                    525:            state ? state : "");
                    526:
1.100     millert   527: }
                    528:
                    529: /*
                    530:  * checkout_file_has_diffs()
                    531:  *
                    532:  * Check for diffs between the working file and its current revision.
1.109     ray       533:  * Same return values as diffreg()
1.100     millert   534:  */
                    535: static int
                    536: checkout_file_has_diffs(RCSFILE *rfp, RCSNUM *frev, const char *dst)
                    537: {
                    538:        char *tempfile;
                    539:        BUF *bp;
                    540:        int ret;
                    541:
                    542:        tempfile = NULL;
                    543:
                    544:        if ((bp = rcs_getrev(rfp, frev)) == NULL) {
                    545:                warnx("failed to load revision");
1.101     millert   546:                return (D_ERROR);
                    547:        }
                    548:        if ((bp = rcs_kwexp_buf(bp, rfp, frev)) == NULL) {
                    549:                warnx("failed to expand tags");
1.100     millert   550:                return (D_ERROR);
                    551:        }
                    552:
                    553:        (void)xasprintf(&tempfile, "%s/diff.XXXXXXXXXX", rcs_tmpdir);
1.111     ray       554:        buf_write_stmp(bp, tempfile);
                    555:        buf_empty(bp);
1.100     millert   556:
                    557:        diff_format = D_RCSDIFF;
1.110     ray       558:        ret = diffreg(dst, tempfile, bp, D_FORCEASCII);
1.100     millert   559:
1.111     ray       560:        buf_free(bp);
1.100     millert   561:        unlink(tempfile);
1.121     nicm      562:        free(tempfile);
1.100     millert   563:
                    564:        return (ret);
1.24      niallo    565: }