| GCC Code Coverage Report | |||||||||||||||||||||
        
  | 
    |||||||||||||||||||||
| Line | Branch | Exec | Source | 
1  | 
    /* $OpenBSD: co.c,v 1.123 2017/08/29 16:47:33 otto Exp $ */  | 
    ||
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  | 
    |||
27  | 
    #include <sys/stat.h>  | 
    ||
28  | 
    #include <sys/time.h>  | 
    ||
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>  | 
    ||
36  | 
    |||
37  | 
    #include "rcsprog.h"  | 
    ||
38  | 
    #include "diff.h"  | 
    ||
39  | 
    |||
40  | 
    #define CO_OPTSTRING "d:f::I::k:l::M::p::q::r::s:Tu::Vw::x::z::"  | 
    ||
41  | 
    |||
42  | 
    static void checkout_err_nobranch(RCSFILE *, const char *, const char *,  | 
    ||
43  | 
    const char *, int);  | 
    ||
44  | 
    static int checkout_file_has_diffs(RCSFILE *, RCSNUM *, const char *);  | 
    ||
45  | 
    |||
46  | 
    int  | 
    ||
47  | 
    checkout_main(int argc, char **argv)  | 
    ||
48  | 
    { | 
    ||
49  | 
    int fd, i, ch, flags, kflag, ret;  | 
    ||
50  | 
    RCSNUM *rev;  | 
    ||
51  | 
    RCSFILE *file;  | 
    ||
52  | 
    const char *author, *date, *state;  | 
    ||
53  | 
    98  | 
    char fpath[PATH_MAX];  | 
    |
54  | 
    49  | 
    char *rev_str, *username;  | 
    |
55  | 
    time_t rcs_mtime = -1;  | 
    ||
56  | 
    |||
57  | 
    flags = ret = 0;  | 
    ||
58  | 
    kflag = RCS_KWEXP_ERR;  | 
    ||
59  | 
    49  | 
    rev_str = NULL;  | 
    |
60  | 
    author = date = state = NULL;  | 
    ||
61  | 
    |||
62  | 
    ✓✓ | 191  | 
    	while ((ch = rcs_getopt(argc, argv, CO_OPTSTRING)) != -1) { | 
    
63  | 
    ✗✗✗✗ ✓✗✗✓ ✗✗✗✓ ✗✗✗✗ ✗  | 
    93  | 
    		switch (ch) { | 
    
64  | 
    case 'd':  | 
    ||
65  | 
    date = rcs_optarg;  | 
    ||
66  | 
    break;  | 
    ||
67  | 
    case 'f':  | 
    ||
68  | 
    rcs_setrevstr(&rev_str, rcs_optarg);  | 
    ||
69  | 
    flags |= FORCE;  | 
    ||
70  | 
    break;  | 
    ||
71  | 
    case 'I':  | 
    ||
72  | 
    rcs_setrevstr(&rev_str, rcs_optarg);  | 
    ||
73  | 
    flags |= INTERACTIVE;  | 
    ||
74  | 
    break;  | 
    ||
75  | 
    |||
76  | 
    case 'k':  | 
    ||
77  | 
    kflag = rcs_kflag_get(rcs_optarg);  | 
    ||
78  | 
    			if (RCS_KWEXP_INVAL(kflag)) { | 
    ||
79  | 
    				warnx("invalid RCS keyword substitution mode"); | 
    ||
80  | 
    (usage)();  | 
    ||
81  | 
    }  | 
    ||
82  | 
    break;  | 
    ||
83  | 
    case 'l':  | 
    ||
84  | 
    ✗✓ | 33  | 
    			if (flags & CO_UNLOCK) { | 
    
85  | 
    				warnx("warning: -u overridden by -l"); | 
    ||
86  | 
    flags &= ~CO_UNLOCK;  | 
    ||
87  | 
    }  | 
    ||
88  | 
    33  | 
    rcs_setrevstr(&rev_str, rcs_optarg);  | 
    |
89  | 
    33  | 
    flags |= CO_LOCK;  | 
    |
90  | 
    33  | 
    break;  | 
    |
91  | 
    case 'M':  | 
    ||
92  | 
    rcs_setrevstr(&rev_str, rcs_optarg);  | 
    ||
93  | 
    flags |= CO_REVDATE;  | 
    ||
94  | 
    break;  | 
    ||
95  | 
    case 'p':  | 
    ||
96  | 
    rcs_setrevstr(&rev_str, rcs_optarg);  | 
    ||
97  | 
    flags |= PIPEOUT;  | 
    ||
98  | 
    break;  | 
    ||
99  | 
    case 'q':  | 
    ||
100  | 
    49  | 
    rcs_setrevstr(&rev_str, rcs_optarg);  | 
    |
101  | 
    49  | 
    flags |= QUIET;  | 
    |
102  | 
    49  | 
    break;  | 
    |
103  | 
    case 'r':  | 
    ||
104  | 
    rcs_setrevstr(&rev_str, rcs_optarg);  | 
    ||
105  | 
    break;  | 
    ||
106  | 
    case 's':  | 
    ||
107  | 
    state = rcs_optarg;  | 
    ||
108  | 
    flags |= CO_STATE;  | 
    ||
109  | 
    break;  | 
    ||
110  | 
    case 'T':  | 
    ||
111  | 
    flags |= PRESERVETIME;  | 
    ||
112  | 
    break;  | 
    ||
113  | 
    case 'u':  | 
    ||
114  | 
    11  | 
    rcs_setrevstr(&rev_str, rcs_optarg);  | 
    |
115  | 
    ✗✓ | 11  | 
    			if (flags & CO_LOCK) { | 
    
116  | 
    				warnx("warning: -l overridden by -u"); | 
    ||
117  | 
    flags &= ~CO_LOCK;  | 
    ||
118  | 
    }  | 
    ||
119  | 
    11  | 
    flags |= CO_UNLOCK;  | 
    |
120  | 
    11  | 
    break;  | 
    |
121  | 
    case 'V':  | 
    ||
122  | 
    			printf("%s\n", rcs_version); | 
    ||
123  | 
    exit(0);  | 
    ||
124  | 
    case 'w':  | 
    ||
125  | 
    /* if no argument, assume current user */  | 
    ||
126  | 
    			if (rcs_optarg == NULL) { | 
    ||
127  | 
    if ((author = getlogin()) == NULL)  | 
    ||
128  | 
    err(1, "getlogin");  | 
    ||
129  | 
    } else  | 
    ||
130  | 
    author = rcs_optarg;  | 
    ||
131  | 
    flags |= CO_AUTHOR;  | 
    ||
132  | 
    break;  | 
    ||
133  | 
    case 'x':  | 
    ||
134  | 
    /* Use blank extension if none given. */  | 
    ||
135  | 
    rcs_suffixes = rcs_optarg ? rcs_optarg : "";  | 
    ||
136  | 
    break;  | 
    ||
137  | 
    case 'z':  | 
    ||
138  | 
    timezone_flag = rcs_optarg;  | 
    ||
139  | 
    break;  | 
    ||
140  | 
    default:  | 
    ||
141  | 
    (usage)();  | 
    ||
142  | 
    }  | 
    ||
143  | 
    }  | 
    ||
144  | 
    |||
145  | 
    49  | 
    argc -= rcs_optind;  | 
    |
146  | 
    49  | 
    argv += rcs_optind;  | 
    |
147  | 
    |||
148  | 
    ✗✓ | 49  | 
    	if (argc == 0) { | 
    
149  | 
    		warnx("no input file"); | 
    ||
150  | 
    (usage)();  | 
    ||
151  | 
    }  | 
    ||
152  | 
    |||
153  | 
    ✗✓ | 49  | 
    if ((username = getlogin()) == NULL)  | 
    
154  | 
    err(1, "getlogin");  | 
    ||
155  | 
    |||
156  | 
    ✓✓ | 194  | 
    	for (i = 0; i < argc; i++) { | 
    
157  | 
    49  | 
    fd = rcs_choosefile(argv[i], fpath, sizeof(fpath));  | 
    |
158  | 
    ✗✓ | 49  | 
    		if (fd < 0) { | 
    
159  | 
    			warn("%s", fpath); | 
    ||
160  | 
    ret = 1;  | 
    ||
161  | 
    continue;  | 
    ||
162  | 
    }  | 
    ||
163  | 
    49  | 
    rcs_strip_suffix(argv[i]);  | 
    |
164  | 
    |||
165  | 
    ✗✓ | 49  | 
    if (!(flags & QUIET))  | 
    
166  | 
    (void)fprintf(stderr, "%s --> %s\n", fpath,  | 
    ||
167  | 
    (flags & PIPEOUT) ? "standard output" : argv[i]);  | 
    ||
168  | 
    |||
169  | 
    ✓✓✗✓ | 
    82  | 
    		if ((flags & CO_LOCK) && (kflag & RCS_KWEXP_VAL)) { | 
    
170  | 
    			warnx("%s: cannot combine -kv and -l", fpath); | 
    ||
171  | 
    (void)close(fd);  | 
    ||
172  | 
    continue;  | 
    ||
173  | 
    }  | 
    ||
174  | 
    |||
175  | 
    ✓✗ | 96  | 
    if ((file = rcs_open(fpath, fd,  | 
    
176  | 
    48  | 
    RCS_RDWR|RCS_PARSE_FULLY)) == NULL)  | 
    |
177  | 
    continue;  | 
    ||
178  | 
    |||
179  | 
    ✗✓ | 48  | 
    if (flags & PRESERVETIME)  | 
    
180  | 
    rcs_mtime = rcs_get_mtime(file);  | 
    ||
181  | 
    |||
182  | 
    48  | 
    rcs_kwexp_set(file, kflag);  | 
    |
183  | 
    |||
184  | 
    ✗✓ | 48  | 
    		if (rev_str != NULL) { | 
    
185  | 
    if ((rev = rcs_getrevnum(rev_str, file)) == NULL)  | 
    ||
186  | 
    errx(1, "invalid revision: %s", rev_str);  | 
    ||
187  | 
    		} else { | 
    ||
188  | 
    /* no revisions in RCS file, generate empty 0.0 */  | 
    ||
189  | 
    ✓✓ | 48  | 
    			if (file->rf_ndelta == 0) { | 
    
190  | 
    2  | 
    				rev = rcsnum_parse("0.0"); | 
    |
191  | 
    ✗✓ | 2  | 
    if (rev == NULL)  | 
    
192  | 
    errx(1, "failed to generate rev 0.0");  | 
    ||
193  | 
    			} else { | 
    ||
194  | 
    46  | 
    rev = rcsnum_alloc();  | 
    |
195  | 
    46  | 
    rcsnum_cpy(file->rf_head, rev, 0);  | 
    |
196  | 
    }  | 
    ||
197  | 
    }  | 
    ||
198  | 
    |||
199  | 
    ✗✓ | 96  | 
    if (checkout_rev(file, rev, argv[i], flags,  | 
    
200  | 
    48  | 
    		    username, author, state, date) < 0) { | 
    |
201  | 
    rcs_close(file);  | 
    ||
202  | 
    rcsnum_free(rev);  | 
    ||
203  | 
    ret = 1;  | 
    ||
204  | 
    continue;  | 
    ||
205  | 
    }  | 
    ||
206  | 
    |||
207  | 
    ✗✓ | 48  | 
    if (!(flags & QUIET))  | 
    
208  | 
    (void)fprintf(stderr, "done\n");  | 
    ||
209  | 
    |||
210  | 
    48  | 
    rcsnum_free(rev);  | 
    |
211  | 
    |||
212  | 
    48  | 
    rcs_write(file);  | 
    |
213  | 
    ✗✓ | 48  | 
    if (flags & PRESERVETIME)  | 
    
214  | 
    rcs_set_mtime(file, rcs_mtime);  | 
    ||
215  | 
    48  | 
    rcs_close(file);  | 
    |
216  | 
    48  | 
    }  | 
    |
217  | 
    |||
218  | 
    48  | 
    return (ret);  | 
    |
219  | 
    48  | 
    }  | 
    |
220  | 
    |||
221  | 
    __dead void  | 
    ||
222  | 
    checkout_usage(void)  | 
    ||
223  | 
    { | 
    ||
224  | 
    fprintf(stderr,  | 
    ||
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");  | 
    ||
228  | 
    |||
229  | 
    exit(1);  | 
    ||
230  | 
    }  | 
    ||
231  | 
    |||
232  | 
    /*  | 
    ||
233  | 
    * Checkout revision <rev> from RCSFILE <file>, writing it to the path <dst>  | 
    ||
234  | 
    * Currently recognised <flags> are CO_LOCK, CO_UNLOCK and CO_REVDATE.  | 
    ||
235  | 
    *  | 
    ||
236  | 
    * Looks up revision based upon <lockname>, <author>, <state> and <date>  | 
    ||
237  | 
    *  | 
    ||
238  | 
    * Returns 0 on success, -1 on failure.  | 
    ||
239  | 
    */  | 
    ||
240  | 
    int  | 
    ||
241  | 
    checkout_rev(RCSFILE *file, RCSNUM *frev, const char *dst, int flags,  | 
    ||
242  | 
    const char *lockname, const char *author, const char *state,  | 
    ||
243  | 
    const char *date)  | 
    ||
244  | 
    { | 
    ||
245  | 
    BUF *bp;  | 
    ||
246  | 
    u_int i;  | 
    ||
247  | 
    int fd, lcount;  | 
    ||
248  | 
    154  | 
    char buf[RCS_REV_BUFSZ];  | 
    |
249  | 
    mode_t mode = DEFFILEMODE;  | 
    ||
250  | 
    77  | 
    struct stat st;  | 
    |
251  | 
    struct rcs_delta *rdp;  | 
    ||
252  | 
    struct rcs_lock *lkp;  | 
    ||
253  | 
    char *fdate;  | 
    ||
254  | 
    const char *fstatus;  | 
    ||
255  | 
    time_t rcsdate, givendate;  | 
    ||
256  | 
    RCSNUM *rev;  | 
    ||
257  | 
    |||
258  | 
    givendate = -1;  | 
    ||
259  | 
    ✗✓✗✗ | 
    77  | 
    	if (date != NULL && (givendate = date_parse(date)) == -1) { | 
    
260  | 
    		warnx("invalid date: %s", date); | 
    ||
261  | 
    return -1;  | 
    ||
262  | 
    }  | 
    ||
263  | 
    |||
264  | 
    ✓✓✗✓ | 
    79  | 
    if (file->rf_ndelta == 0 && !(flags & QUIET))  | 
    
265  | 
    (void)fprintf(stderr,  | 
    ||
266  | 
    "no revisions present; generating empty revision 0.0\n");  | 
    ||
267  | 
    |||
268  | 
    /* XXX rcsnum_cmp()  | 
    ||
269  | 
    * Check out the latest revision if <frev> is greater than HEAD  | 
    ||
270  | 
    */  | 
    ||
271  | 
    ✓✓ | 77  | 
    	if (file->rf_ndelta != 0) { | 
    
272  | 
    ✓✓ | 450  | 
    		for (i = 0; i < file->rf_head->rn_len; i++) { | 
    
273  | 
    ✗✓ | 150  | 
    			if (file->rf_head->rn_id[i] < frev->rn_id[i]) { | 
    
274  | 
    frev = file->rf_head;  | 
    ||
275  | 
    break;  | 
    ||
276  | 
    }  | 
    ||
277  | 
    }  | 
    ||
278  | 
    }  | 
    ||
279  | 
    |||
280  | 
    lcount = 0;  | 
    ||
281  | 
    ✓✓ | 190  | 
    	TAILQ_FOREACH(lkp, &(file->rf_locks), rl_list) { | 
    
282  | 
    ✓✗ | 18  | 
    if (!strcmp(lkp->rl_name, lockname))  | 
    
283  | 
    18  | 
    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;  | 
    ||
293  | 
    ✓✓✓✓ | 
    152  | 
    	if (file->rf_ndelta != 0 && frev == file->rf_head) { | 
    
294  | 
    ✗✓ | 29  | 
    		if (lcount > 1) { | 
    
295  | 
    			warnx("multiple revisions locked by %s; " | 
    ||
296  | 
    "please specify one", lockname);  | 
    ||
297  | 
    return (-1);  | 
    ||
298  | 
    }  | 
    ||
299  | 
    |||
300  | 
    ✓✗ | 58  | 
    		TAILQ_FOREACH(rdp, &file->rf_delta, rd_list) { | 
    
301  | 
    ✗✓ | 29  | 
    			if (date != NULL) { | 
    
302  | 
    fdate = asctime(&rdp->rd_date);  | 
    ||
303  | 
    				if ((rcsdate = date_parse(fdate)) == -1) { | 
    ||
304  | 
    					warnx("invalid date: %s", fdate); | 
    ||
305  | 
    return -1;  | 
    ||
306  | 
    }  | 
    ||
307  | 
    if (givendate <= rcsdate)  | 
    ||
308  | 
    continue;  | 
    ||
309  | 
    }  | 
    ||
310  | 
    |||
311  | 
    ✓✓✓✗ | 
    30  | 
    if (author != NULL &&  | 
    
312  | 
    1  | 
    strcmp(rdp->rd_author, author))  | 
    |
313  | 
    continue;  | 
    ||
314  | 
    |||
315  | 
    ✗✓✗✗ | 
    29  | 
    if (state != NULL &&  | 
    
316  | 
    strcmp(rdp->rd_state, state))  | 
    ||
317  | 
    continue;  | 
    ||
318  | 
    |||
319  | 
    29  | 
    frev = rdp->rd_num;  | 
    |
320  | 
    29  | 
    break;  | 
    |
321  | 
    }  | 
    ||
322  | 
    ✓✓ | 48  | 
    	} else if (file->rf_ndelta != 0) { | 
    
323  | 
    46  | 
    rdp = rcs_findrev(file, frev);  | 
    |
324  | 
    46  | 
    }  | 
    |
325  | 
    |||
326  | 
    ✗✓ | 77  | 
    	if (file->rf_ndelta != 0 && rdp == NULL) { | 
    
327  | 
    checkout_err_nobranch(file, author, date, state, flags);  | 
    ||
328  | 
    return (-1);  | 
    ||
329  | 
    }  | 
    ||
330  | 
    |||
331  | 
    ✓✓ | 77  | 
    if (file->rf_ndelta == 0)  | 
    
332  | 
    2  | 
    rev = frev;  | 
    |
333  | 
    else  | 
    ||
334  | 
    75  | 
    rev = rdp->rd_num;  | 
    |
335  | 
    |||
336  | 
    77  | 
    rcsnum_tostr(rev, buf, sizeof(buf));  | 
    |
337  | 
    |||
338  | 
    ✓✓✓✓ | 
    152  | 
    	if (file->rf_ndelta != 0 && rdp->rd_locker != NULL) { | 
    
339  | 
    ✗✓ | 18  | 
    		if (strcmp(lockname, rdp->rd_locker)) { | 
    
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" : "");  | 
    ||
343  | 
    return (-1);  | 
    ||
344  | 
    }  | 
    ||
345  | 
    }  | 
    ||
346  | 
    |||
347  | 
    ✗✓✗✗ ✗✗  | 
    77  | 
    if (!(flags & QUIET) && !(flags & NEWFILE) &&  | 
    
348  | 
    !(flags & CO_REVERT) && file->rf_ndelta != 0)  | 
    ||
349  | 
    (void)fprintf(stderr, "revision %s", buf);  | 
    ||
350  | 
    |||
351  | 
    ✓✓ | 77  | 
    	if (file->rf_ndelta != 0) { | 
    
352  | 
    ✗✓ | 75  | 
    		if ((bp = rcs_getrev(file, rev)) == NULL) { | 
    
353  | 
    			warnx("cannot find revision `%s'", buf); | 
    ||
354  | 
    return (-1);  | 
    ||
355  | 
    }  | 
    ||
356  | 
    	} else { | 
    ||
357  | 
    2  | 
    bp = buf_alloc(1);  | 
    |
358  | 
    }  | 
    ||
359  | 
    |||
360  | 
    /*  | 
    ||
361  | 
    * Do keyword expansion if required.  | 
    ||
362  | 
    */  | 
    ||
363  | 
    ✓✓ | 77  | 
    if (file->rf_ndelta != 0)  | 
    
364  | 
    75  | 
    bp = rcs_kwexp_buf(bp, file, rev);  | 
    |
365  | 
    /*  | 
    ||
366  | 
    * File inherits permissions from its ,v file  | 
    ||
367  | 
    */  | 
    ||
368  | 
    ✓✓ | 77  | 
    	if (file->rf_file != NULL) { | 
    
369  | 
    ✓✗✗✓ | 
    192  | 
    if (fstat(fileno(file->rf_file), &st) == -1)  | 
    
370  | 
    err(1, "%s", file->rf_path);  | 
    ||
371  | 
    64  | 
    file->rf_mode = mode = st.st_mode;  | 
    |
372  | 
    64  | 
    	} else { | 
    |
373  | 
    13  | 
    mode = file->rf_mode;  | 
    |
374  | 
    }  | 
    ||
375  | 
    |||
376  | 
    ✓✓ | 77  | 
    	if (flags & CO_LOCK) { | 
    
377  | 
    ✓✓ | 120  | 
    		if (file->rf_ndelta != 0) { | 
    
378  | 
    ✗✓ | 119  | 
    if (lockname != NULL &&  | 
    
379  | 
    59  | 
    			    rcs_lock_add(file, lockname, rev) < 0) { | 
    |
380  | 
    59  | 
    if (rcs_errno != RCS_ERR_DUPENT)  | 
    |
381  | 
    return (-1);  | 
    ||
382  | 
    }  | 
    ||
383  | 
    }  | 
    ||
384  | 
    |||
385  | 
    /* File should only be writable by owner. */  | 
    ||
386  | 
    60  | 
    mode &= ~(S_IWGRP|S_IWOTH);  | 
    |
387  | 
    60  | 
    mode |= S_IWUSR;  | 
    |
388  | 
    |||
389  | 
    ✓✓ | 60  | 
    		if (file->rf_ndelta != 0) { | 
    
390  | 
    ✗✓✗✗ ✗✗  | 
    59  | 
    if (!(flags & QUIET) && !(flags & NEWFILE) &&  | 
    
391  | 
    !(flags & CO_REVERT))  | 
    ||
392  | 
    (void)fprintf(stderr, " (locked)");  | 
    ||
393  | 
    }  | 
    ||
394  | 
    ✓✓ | 17  | 
    	} else if (flags & CO_UNLOCK) { | 
    
395  | 
    ✓✗ | 13  | 
    		if (file->rf_ndelta != 0) { | 
    
396  | 
    ✗✓ | 26  | 
    			if (rcs_lock_remove(file, lockname, rev) < 0) { | 
    
397  | 
    13  | 
    if (rcs_errno != RCS_ERR_NOENT)  | 
    |
398  | 
    return (-1);  | 
    ||
399  | 
    }  | 
    ||
400  | 
    }  | 
    ||
401  | 
    |||
402  | 
    /* Strip all write bits from mode */  | 
    ||
403  | 
    13  | 
    mode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);  | 
    |
404  | 
    |||
405  | 
    ✓✗ | 13  | 
    		if (file->rf_ndelta != 0) { | 
    
406  | 
    ✗✓✗✗ ✗✗  | 
    13  | 
    if (!(flags & QUIET) && !(flags & NEWFILE) &&  | 
    
407  | 
    !(flags & CO_REVERT))  | 
    ||
408  | 
    (void)fprintf(stderr, " (unlocked)");  | 
    ||
409  | 
    }  | 
    ||
410  | 
    }  | 
    ||
411  | 
    |||
412  | 
    /* If strict locking is disabled, make file writable by owner. */  | 
    ||
413  | 
    ✗✓ | 77  | 
    if (rcs_lock_getmode(file) == RCS_LOCK_LOOSE)  | 
    
414  | 
    mode |= S_IWUSR;  | 
    ||
415  | 
    |||
416  | 
    ✓✓✗✓ ✗✗  | 
    79  | 
    if (file->rf_ndelta == 0 && !(flags & QUIET) &&  | 
    
417  | 
    	    ((flags & CO_LOCK) || (flags & CO_UNLOCK))) { | 
    ||
418  | 
    (void)fprintf(stderr, "no revisions, so nothing can be %s\n",  | 
    ||
419  | 
    (flags & CO_LOCK) ? "locked" : "unlocked");  | 
    ||
420  | 
    ✓✓ | 77  | 
    	} else if (file->rf_ndelta != 0) { | 
    
421  | 
    /* XXX - Not a good way to detect if a newline is needed. */  | 
    ||
422  | 
    ✗✓✗✗ ✗✗  | 
    75  | 
    if (!(flags & QUIET) && !(flags & NEWFILE) &&  | 
    
423  | 
    !(flags & CO_REVERT))  | 
    ||
424  | 
    (void)fprintf(stderr, "\n");  | 
    ||
425  | 
    }  | 
    ||
426  | 
    |||
427  | 
    ✓✓ | 77  | 
    	if (flags & CO_LOCK) { | 
    
428  | 
    ✓✓ | 60  | 
    if (rcs_errno != RCS_ERR_DUPENT)  | 
    
429  | 
    41  | 
    lcount++;  | 
    |
430  | 
    ✗✓✗✗ | 
    60  | 
    if (!(flags & QUIET) && lcount > 1 && !(flags & CO_REVERT))  | 
    
431  | 
    			warnx("%s: warning: You now have %d locks.", | 
    ||
432  | 
    file->rf_path, lcount);  | 
    ||
433  | 
    }  | 
    ||
434  | 
    |||
435  | 
    ✓✗✗✓ | 
    154  | 
    	if ((flags & (PIPEOUT|FORCE)) == 0 && stat(dst, &st) != -1) { | 
    
436  | 
    /*  | 
    ||
437  | 
    * Prompt the user if the file is writable or the file is  | 
    ||
438  | 
    * not writable but is different from the RCS head version.  | 
    ||
439  | 
    * This is different from GNU which will silently overwrite  | 
    ||
440  | 
    * the file regardless of its contents so long as it is  | 
    ||
441  | 
    * read-only.  | 
    ||
442  | 
    */  | 
    ||
443  | 
    if (st.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))  | 
    ||
444  | 
    fstatus = "writable";  | 
    ||
445  | 
    else if (checkout_file_has_diffs(file, frev, dst) != D_SAME)  | 
    ||
446  | 
    fstatus = "modified";  | 
    ||
447  | 
    else  | 
    ||
448  | 
    fstatus = NULL;  | 
    ||
449  | 
    		if (fstatus) { | 
    ||
450  | 
    (void)fprintf(stderr, "%s %s exists%s; ", fstatus, dst,  | 
    ||
451  | 
    (getuid() == st.st_uid) ? "" :  | 
    ||
452  | 
    ", and you do not own it");  | 
    ||
453  | 
    (void)fprintf(stderr, "remove it? [ny](n): ");  | 
    ||
454  | 
    			if (rcs_yesno('n') == 'n') { | 
    ||
455  | 
    if (!(flags & QUIET) && isatty(STDIN_FILENO))  | 
    ||
456  | 
    					warnx("%s %s exists; checkout aborted", | 
    ||
457  | 
    fstatus, dst);  | 
    ||
458  | 
    else  | 
    ||
459  | 
    					warnx("checkout aborted"); | 
    ||
460  | 
    return (-1);  | 
    ||
461  | 
    }  | 
    ||
462  | 
    }  | 
    ||
463  | 
    }  | 
    ||
464  | 
    |||
465  | 
    ✗✓ | 77  | 
    if (flags & PIPEOUT)  | 
    
466  | 
    buf_write_fd(bp, STDOUT_FILENO);  | 
    ||
467  | 
    	else { | 
    ||
468  | 
    77  | 
    (void)unlink(dst);  | 
    |
469  | 
    |||
470  | 
    ✗✓ | 77  | 
    if ((fd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0)  | 
    
471  | 
    err(1, "%s", dst);  | 
    ||
472  | 
    |||
473  | 
    ✗✓ | 77  | 
    		if (buf_write_fd(bp, fd) < 0) { | 
    
474  | 
    			warnx("failed to write revision to file"); | 
    ||
475  | 
    buf_free(bp);  | 
    ||
476  | 
    (void)close(fd);  | 
    ||
477  | 
    return (-1);  | 
    ||
478  | 
    }  | 
    ||
479  | 
    |||
480  | 
    ✗✓ | 77  | 
    if (fchmod(fd, mode) == -1)  | 
    
481  | 
    			warn("%s", dst); | 
    ||
482  | 
    |||
483  | 
    ✗✓ | 77  | 
    		if (flags & CO_REVDATE) { | 
    
484  | 
    struct timeval tv[2];  | 
    ||
485  | 
    memset(&tv, 0, sizeof(tv));  | 
    ||
486  | 
    tv[0].tv_sec = rcs_rev_getdate(file, rev);  | 
    ||
487  | 
    tv[1].tv_sec = tv[0].tv_sec;  | 
    ||
488  | 
    if (futimes(fd, (const struct timeval *)&tv) < 0)  | 
    ||
489  | 
    				warn("utimes"); | 
    ||
490  | 
    }  | 
    ||
491  | 
    |||
492  | 
    77  | 
    (void)close(fd);  | 
    |
493  | 
    }  | 
    ||
494  | 
    |||
495  | 
    77  | 
    buf_free(bp);  | 
    |
496  | 
    |||
497  | 
    77  | 
    return (0);  | 
    |
498  | 
    77  | 
    }  | 
    |
499  | 
    |||
500  | 
    /*  | 
    ||
501  | 
    * checkout_err_nobranch()  | 
    ||
502  | 
    *  | 
    ||
503  | 
    * XXX - should handle the dates too.  | 
    ||
504  | 
    */  | 
    ||
505  | 
    static void  | 
    ||
506  | 
    checkout_err_nobranch(RCSFILE *file, const char *author, const char *date,  | 
    ||
507  | 
    const char *state, int flags)  | 
    ||
508  | 
    { | 
    ||
509  | 
    if (!(flags & CO_AUTHOR))  | 
    ||
510  | 
    author = NULL;  | 
    ||
511  | 
    if (!(flags & CO_STATE))  | 
    ||
512  | 
    state = NULL;  | 
    ||
513  | 
    |||
514  | 
    	warnx("%s: No revision on branch has %s%s%s%s%s%s%s%s.", | 
    ||
515  | 
    file->rf_path,  | 
    ||
516  | 
    date ? "a date before " : "",  | 
    ||
517  | 
    date ? date : "",  | 
    ||
518  | 
    (date && author) ? " and " : "",  | 
    ||
519  | 
    author ? "author " : "",  | 
    ||
520  | 
    author ? author : "",  | 
    ||
521  | 
    ((date || author) && state) ? " and " : "",  | 
    ||
522  | 
    state ? "state " : "",  | 
    ||
523  | 
    state ? state : "");  | 
    ||
524  | 
    |||
525  | 
    }  | 
    ||
526  | 
    |||
527  | 
    /*  | 
    ||
528  | 
    * checkout_file_has_diffs()  | 
    ||
529  | 
    *  | 
    ||
530  | 
    * Check for diffs between the working file and its current revision.  | 
    ||
531  | 
    * Same return values as diffreg()  | 
    ||
532  | 
    */  | 
    ||
533  | 
    static int  | 
    ||
534  | 
    checkout_file_has_diffs(RCSFILE *rfp, RCSNUM *frev, const char *dst)  | 
    ||
535  | 
    { | 
    ||
536  | 
    char *tempfile;  | 
    ||
537  | 
    BUF *bp;  | 
    ||
538  | 
    int ret;  | 
    ||
539  | 
    |||
540  | 
    tempfile = NULL;  | 
    ||
541  | 
    |||
542  | 
    	if ((bp = rcs_getrev(rfp, frev)) == NULL) { | 
    ||
543  | 
    		warnx("failed to load revision"); | 
    ||
544  | 
    return (D_ERROR);  | 
    ||
545  | 
    }  | 
    ||
546  | 
    	if ((bp = rcs_kwexp_buf(bp, rfp, frev)) == NULL) { | 
    ||
547  | 
    		warnx("failed to expand tags"); | 
    ||
548  | 
    return (D_ERROR);  | 
    ||
549  | 
    }  | 
    ||
550  | 
    |||
551  | 
    (void)xasprintf(&tempfile, "%s/diff.XXXXXXXXXX", rcs_tmpdir);  | 
    ||
552  | 
    buf_write_stmp(bp, tempfile);  | 
    ||
553  | 
    buf_empty(bp);  | 
    ||
554  | 
    |||
555  | 
    diff_format = D_RCSDIFF;  | 
    ||
556  | 
    ret = diffreg(dst, tempfile, bp, D_FORCEASCII);  | 
    ||
557  | 
    |||
558  | 
    buf_free(bp);  | 
    ||
559  | 
    unlink(tempfile);  | 
    ||
560  | 
    free(tempfile);  | 
    ||
561  | 
    |||
562  | 
    return (ret);  | 
    ||
563  | 
    }  | 
    
| Generated by: GCOVR (Version 3.3) |