1*53ce2177Sfcambus /* $OpenBSD: entries.c,v 1.107 2016/10/13 20:51:25 fcambus Exp $ */
26c121f58Sjfb /*
33ad3fb45Sjoris * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
46c121f58Sjfb *
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.
86c121f58Sjfb *
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.
166c121f58Sjfb */
176c121f58Sjfb
181f8531bdSotto #include <errno.h>
19397ddb8aSnicm #include <stdlib.h>
201f8531bdSotto #include <string.h>
21169ade7eSchl #include <time.h>
221f8531bdSotto #include <unistd.h>
236c121f58Sjfb
246c121f58Sjfb #include "cvs.h"
25a1742a04Sjoris #include "remote.h"
266c121f58Sjfb
27691ee54dSjfb #define CVS_ENTRIES_NFIELDS 6
286c121f58Sjfb #define CVS_ENTRIES_DELIM '/'
296c121f58Sjfb
303ad3fb45Sjoris static struct cvs_ent_line *ent_get_line(CVSENTRIES *, const char *);
316c121f58Sjfb
327c1a09a6Sjoris CVSENTRIES *current_list = NULL;
337c1a09a6Sjoris
346c121f58Sjfb CVSENTRIES *
cvs_ent_open(const char * dir)353ad3fb45Sjoris cvs_ent_open(const char *dir)
366c121f58Sjfb {
376c121f58Sjfb FILE *fp;
386c121f58Sjfb CVSENTRIES *ep;
39b9fc9a72Sderaadt char *p, buf[PATH_MAX];
403ad3fb45Sjoris struct cvs_ent *ent;
413ad3fb45Sjoris struct cvs_ent_line *line;
426c121f58Sjfb
437c1a09a6Sjoris cvs_log(LP_TRACE, "cvs_ent_open(%s)", dir);
4408bd75e9Sjfb
45e40de241Sxsa (void)xsnprintf(buf, sizeof(buf), "%s/%s", dir, CVS_PATH_ENTRIES);
4617681b67Sxsa
477c1a09a6Sjoris if (current_list != NULL && !strcmp(current_list->cef_path, buf))
487c1a09a6Sjoris return (current_list);
497c1a09a6Sjoris
507c1a09a6Sjoris if (current_list != NULL) {
517c1a09a6Sjoris cvs_ent_close(current_list, ENT_SYNC);
527c1a09a6Sjoris current_list = NULL;
537c1a09a6Sjoris }
547c1a09a6Sjoris
55cfff592fSderaadt ep = xcalloc(1, sizeof(*ep));
563ad3fb45Sjoris ep->cef_path = xstrdup(buf);
575885ecaeSxsa
58e40de241Sxsa (void)xsnprintf(buf, sizeof(buf), "%s/%s",
59e40de241Sxsa dir, CVS_PATH_BACKUPENTRIES);
6017681b67Sxsa
613ad3fb45Sjoris ep->cef_bpath = xstrdup(buf);
6256fd4a10Sxsa
63e40de241Sxsa (void)xsnprintf(buf, sizeof(buf), "%s/%s", dir, CVS_PATH_LOGENTRIES);
6417681b67Sxsa
653ad3fb45Sjoris ep->cef_lpath = xstrdup(buf);
66a3864909Sjoris
67b96e54a5Sjfb TAILQ_INIT(&(ep->cef_ent));
68858fe57bSjfb
693ad3fb45Sjoris if ((fp = fopen(ep->cef_path, "r")) != NULL) {
703ad3fb45Sjoris while (fgets(buf, sizeof(buf), fp)) {
71b625fa02Sgilles buf[strcspn(buf, "\n")] = '\0';
723ad3fb45Sjoris
733ad3fb45Sjoris if (buf[0] == 'D' && buf[1] == '\0')
741dace6d2Sjfb break;
756c121f58Sjfb
76cfff592fSderaadt line = xmalloc(sizeof(*line));
773ad3fb45Sjoris line->buf = xstrdup(buf);
783ad3fb45Sjoris TAILQ_INSERT_TAIL(&(ep->cef_ent), line, entries_list);
796c121f58Sjfb }
80a3864909Sjoris
816c121f58Sjfb (void)fclose(fp);
82a3864909Sjoris }
83a3864909Sjoris
843ad3fb45Sjoris if ((fp = fopen(ep->cef_lpath, "r")) != NULL) {
853ad3fb45Sjoris while (fgets(buf, sizeof(buf), fp)) {
86b625fa02Sgilles buf[strcspn(buf, "\n")] = '\0';
87a3864909Sjoris
88d2442498Stobias if (strlen(buf) < 2)
89d2442498Stobias fatal("cvs_ent_open: %s: malformed line %s",
90d2442498Stobias ep->cef_lpath, buf);
91d2442498Stobias
92d2442498Stobias p = &buf[2];
933ad3fb45Sjoris
943ad3fb45Sjoris if (buf[0] == 'A') {
953ad3fb45Sjoris line = xmalloc(sizeof(*line));
963ad3fb45Sjoris line->buf = xstrdup(p);
973ad3fb45Sjoris TAILQ_INSERT_TAIL(&(ep->cef_ent), line,
983ad3fb45Sjoris entries_list);
993ad3fb45Sjoris } else if (buf[0] == 'R') {
100a3864909Sjoris ent = cvs_ent_parse(p);
1013ad3fb45Sjoris line = ent_get_line(ep, ent->ce_name);
10202553c88Sjoris if (line != NULL) {
1033ad3fb45Sjoris TAILQ_REMOVE(&(ep->cef_ent), line,
1043ad3fb45Sjoris entries_list);
105397ddb8aSnicm free(line->buf);
106397ddb8aSnicm free(line);
10702553c88Sjoris }
1083ad3fb45Sjoris cvs_ent_free(ent);
109a3864909Sjoris }
1103ad3fb45Sjoris }
111a3864909Sjoris
1123ad3fb45Sjoris (void)fclose(fp);
113a3864909Sjoris }
11475059454Sjfb
1157c1a09a6Sjoris current_list = ep;
1166c121f58Sjfb return (ep);
1176c121f58Sjfb }
1186c121f58Sjfb
1196c121f58Sjfb struct cvs_ent *
cvs_ent_parse(const char * entry)1206c121f58Sjfb cvs_ent_parse(const char *entry)
1216c121f58Sjfb {
1226c121f58Sjfb int i;
1239159bf17Sjoris struct tm t, dt;
124d20177feSxsa struct cvs_ent *ent;
12509d28507Stobias char *fields[CVS_ENTRIES_NFIELDS], *buf, *sp, *dp, *p;
1266c121f58Sjfb
12738ae64d1Sjoris buf = sp = xstrdup(entry);
1286c121f58Sjfb i = 0;
1296c121f58Sjfb do {
1306c121f58Sjfb dp = strchr(sp, CVS_ENTRIES_DELIM);
1316c121f58Sjfb if (dp != NULL)
1326c121f58Sjfb *(dp++) = '\0';
1336c121f58Sjfb fields[i++] = sp;
1346c121f58Sjfb sp = dp;
135d593696fSderaadt } while (dp != NULL && i < CVS_ENTRIES_NFIELDS);
1366c121f58Sjfb
1373ad3fb45Sjoris if (i < CVS_ENTRIES_NFIELDS)
1383ad3fb45Sjoris fatal("missing fields in entry line '%s'", entry);
139691ee54dSjfb
14038ae64d1Sjoris ent = xmalloc(sizeof(*ent));
141d20177feSxsa ent->ce_buf = buf;
142691ee54dSjfb
143691ee54dSjfb if (*fields[0] == '\0')
144d20177feSxsa ent->ce_type = CVS_ENT_FILE;
145691ee54dSjfb else if (*fields[0] == 'D')
146d20177feSxsa ent->ce_type = CVS_ENT_DIR;
147691ee54dSjfb else
148d20177feSxsa ent->ce_type = CVS_ENT_NONE;
149691ee54dSjfb
150d20177feSxsa ent->ce_status = CVS_ENT_REG;
151d20177feSxsa ent->ce_name = fields[1];
1523ad3fb45Sjoris ent->ce_rev = NULL;
1537f0c79fcSjoris ent->ce_date = -1;
1547f0c79fcSjoris ent->ce_tag = NULL;
155694b1da3Sstsp ent->ce_time = NULL;
1566c121f58Sjfb
157d20177feSxsa if (ent->ce_type == CVS_ENT_FILE) {
1589a795badSjfb if (*fields[2] == '-') {
159d20177feSxsa ent->ce_status = CVS_ENT_REMOVED;
1609a795badSjfb sp = fields[2] + 1;
161bf2db54cSjoris } else if (*fields[2] == CVS_SERVER_QUESTIONABLE) {
162bf2db54cSjoris sp = NULL;
163bf2db54cSjoris ent->ce_status = CVS_ENT_UNKNOWN;
1649a795badSjfb } else {
1659a795badSjfb sp = fields[2];
166d593696fSderaadt if (fields[2][0] == '0' && fields[2][1] == '\0')
167d20177feSxsa ent->ce_status = CVS_ENT_ADDED;
1689a795badSjfb }
169a8778568Sjoris
170bf2db54cSjoris if (sp != NULL) {
171bf2db54cSjoris if ((ent->ce_rev = rcsnum_parse(sp)) == NULL) {
172bf2db54cSjoris fatal("failed to parse entry revision '%s'",
173bf2db54cSjoris entry);
174bf2db54cSjoris }
175bf2db54cSjoris }
1769a795badSjfb
17738ae64d1Sjoris if (fields[3][0] == '\0' ||
178bf2db54cSjoris strncmp(fields[3], CVS_DATE_DUMMY,
179bf2db54cSjoris sizeof(CVS_DATE_DUMMY) - 1) == 0 ||
1803ad3fb45Sjoris strncmp(fields[3], "Initial ", 8) == 0 ||
18109d28507Stobias strcmp(fields[3], "Result of merge") == 0) {
182d20177feSxsa ent->ce_mtime = CVS_DATE_DMSEC;
183a1742a04Sjoris } else if (cvs_server_active == 1 &&
184a1742a04Sjoris strncmp(fields[3], CVS_SERVER_UNCHANGED,
185a1742a04Sjoris strlen(CVS_SERVER_UNCHANGED)) == 0) {
186a1742a04Sjoris ent->ce_mtime = CVS_SERVER_UPTODATE;
187a1742a04Sjoris } else {
18809d28507Stobias p = fields[3];
18909d28507Stobias if (strncmp(fields[3], "Result of merge+", 16) == 0)
19009d28507Stobias p += 16;
19109d28507Stobias
192694b1da3Sstsp ent->ce_time = xstrdup(p);
193694b1da3Sstsp
19420303d3dSniallo /* Date field can be a '+=' with remote to indicate
19520303d3dSniallo * conflict. In this case do nothing. */
19609d28507Stobias if (strptime(p, "%a %b %d %T %Y", &t) != NULL) {
197bf3ff189Sxsa t.tm_isdst = -1; /* Figure out DST. */
19847e5fe63Sjoris t.tm_gmtoff = 0;
19947e5fe63Sjoris ent->ce_mtime = mktime(&t);
200597deb30Sotto ent->ce_mtime += t.tm_gmtoff;
20147e5fe63Sjoris }
20219624ea1Sjfb }
20320303d3dSniallo }
2049a795badSjfb
2053ad3fb45Sjoris ent->ce_conflict = fields[3];
2063ad3fb45Sjoris if ((dp = strchr(ent->ce_conflict, '+')) != NULL)
2073ad3fb45Sjoris *dp = '\0';
2083ad3fb45Sjoris else
2093ad3fb45Sjoris ent->ce_conflict = NULL;
2103ad3fb45Sjoris
2113ad3fb45Sjoris if (strcmp(fields[4], ""))
212d20177feSxsa ent->ce_opts = fields[4];
2133ad3fb45Sjoris else
2143ad3fb45Sjoris ent->ce_opts = NULL;
2153ad3fb45Sjoris
2169159bf17Sjoris if (strcmp(fields[5], "")) {
2179159bf17Sjoris switch (*fields[5]) {
2189159bf17Sjoris case 'D':
2199159bf17Sjoris if (sscanf(fields[5] + 1, "%d.%d.%d.%d.%d.%d",
2209159bf17Sjoris &dt.tm_year, &dt.tm_mon, &dt.tm_mday,
2219159bf17Sjoris &dt.tm_hour, &dt.tm_min, &dt.tm_sec) != 6)
2229159bf17Sjoris fatal("wrong date specification");
2239159bf17Sjoris dt.tm_year -= 1900;
2249159bf17Sjoris dt.tm_mon -= 1;
2259159bf17Sjoris ent->ce_date = timegm(&dt);
2269159bf17Sjoris ent->ce_tag = NULL;
2279159bf17Sjoris break;
2289159bf17Sjoris case 'T':
229aa3964e7Sjoris ent->ce_tag = fields[5] + 1;
2309159bf17Sjoris break;
2319159bf17Sjoris default:
2329159bf17Sjoris fatal("invalid sticky entry");
2339159bf17Sjoris }
2347f0c79fcSjoris }
2353ad3fb45Sjoris
236d20177feSxsa return (ent);
2376c121f58Sjfb }
238bd5748ebSjfb
2393ad3fb45Sjoris struct cvs_ent *
cvs_ent_get(CVSENTRIES * ep,const char * name)2403ad3fb45Sjoris cvs_ent_get(CVSENTRIES *ep, const char *name)
2413ad3fb45Sjoris {
2423ad3fb45Sjoris struct cvs_ent *ent;
2433ad3fb45Sjoris struct cvs_ent_line *l;
2443ad3fb45Sjoris
2453ad3fb45Sjoris l = ent_get_line(ep, name);
2463ad3fb45Sjoris if (l == NULL)
2473ad3fb45Sjoris return (NULL);
2483ad3fb45Sjoris
2493ad3fb45Sjoris ent = cvs_ent_parse(l->buf);
2503ad3fb45Sjoris return (ent);
2513ad3fb45Sjoris }
2523ad3fb45Sjoris
2533ad3fb45Sjoris void
cvs_ent_close(CVSENTRIES * ep,int writefile)2543ad3fb45Sjoris cvs_ent_close(CVSENTRIES *ep, int writefile)
2553ad3fb45Sjoris {
2563ad3fb45Sjoris FILE *fp;
2573ad3fb45Sjoris struct cvs_ent_line *l;
258d9d194c0Stobias int dflag;
259d9d194c0Stobias
260d9d194c0Stobias dflag = 1;
2617c1a09a6Sjoris cvs_log(LP_TRACE, "cvs_ent_close(%s, %d)", ep->cef_bpath, writefile);
2623ad3fb45Sjoris
2637c1a09a6Sjoris if (cvs_cmdop == CVS_OP_EXPORT)
2647c1a09a6Sjoris writefile = 0;
2657c1a09a6Sjoris
2667c1a09a6Sjoris fp = NULL;
2677c1a09a6Sjoris if (writefile)
2687c1a09a6Sjoris fp = fopen(ep->cef_bpath, "w");
2693ad3fb45Sjoris
2703ad3fb45Sjoris while ((l = TAILQ_FIRST(&(ep->cef_ent))) != NULL) {
2717c1a09a6Sjoris if (fp != NULL) {
272d9d194c0Stobias if (l->buf[0] == 'D')
273d9d194c0Stobias dflag = 0;
274d9d194c0Stobias
2753ad3fb45Sjoris fputs(l->buf, fp);
2763ad3fb45Sjoris fputc('\n', fp);
2773ad3fb45Sjoris }
2783ad3fb45Sjoris
2793ad3fb45Sjoris TAILQ_REMOVE(&(ep->cef_ent), l, entries_list);
280397ddb8aSnicm free(l->buf);
281397ddb8aSnicm free(l);
2823ad3fb45Sjoris }
2833ad3fb45Sjoris
2847c1a09a6Sjoris if (fp != NULL) {
285d9d194c0Stobias if (dflag) {
2863ad3fb45Sjoris fputc('D', fp);
2870cdbab72Spyr fputc('\n', fp);
288d9d194c0Stobias }
2893ad3fb45Sjoris (void)fclose(fp);
2903ad3fb45Sjoris
2913ad3fb45Sjoris if (rename(ep->cef_bpath, ep->cef_path) == -1)
2927d5f2f73Sxsa fatal("cvs_ent_close: rename: `%s'->`%s': %s",
2937d5f2f73Sxsa ep->cef_bpath, ep->cef_path, strerror(errno));
2943ad3fb45Sjoris
2953ad3fb45Sjoris (void)unlink(ep->cef_lpath);
2963ad3fb45Sjoris }
2973ad3fb45Sjoris
298397ddb8aSnicm free(ep->cef_path);
299397ddb8aSnicm free(ep->cef_bpath);
300397ddb8aSnicm free(ep->cef_lpath);
301397ddb8aSnicm free(ep);
3023ad3fb45Sjoris }
3033ad3fb45Sjoris
3043ad3fb45Sjoris void
cvs_ent_add(CVSENTRIES * ep,const char * line)3053ad3fb45Sjoris cvs_ent_add(CVSENTRIES *ep, const char *line)
3063ad3fb45Sjoris {
3073ad3fb45Sjoris FILE *fp;
3083ad3fb45Sjoris struct cvs_ent_line *l;
3093ad3fb45Sjoris struct cvs_ent *ent;
3103ad3fb45Sjoris
3113ad3fb45Sjoris if ((ent = cvs_ent_parse(line)) == NULL)
3123ad3fb45Sjoris fatal("cvs_ent_add: parsing failed '%s'", line);
3133ad3fb45Sjoris
3143ad3fb45Sjoris l = ent_get_line(ep, ent->ce_name);
3153ad3fb45Sjoris if (l != NULL)
3163ad3fb45Sjoris cvs_ent_remove(ep, ent->ce_name);
3173ad3fb45Sjoris
3183ad3fb45Sjoris cvs_ent_free(ent);
3193ad3fb45Sjoris
320d0a063c4Sjoris if (cvs_server_active == 0)
3213ad3fb45Sjoris cvs_log(LP_TRACE, "cvs_ent_add(%s, %s)", ep->cef_path, line);
3223ad3fb45Sjoris
3233ad3fb45Sjoris if ((fp = fopen(ep->cef_lpath, "a")) == NULL)
3247d5f2f73Sxsa fatal("cvs_ent_add: fopen: `%s': %s",
3257d5f2f73Sxsa ep->cef_lpath, strerror(errno));
3263ad3fb45Sjoris
327d2442498Stobias fputs("A ", fp);
3283ad3fb45Sjoris fputs(line, fp);
3293ad3fb45Sjoris fputc('\n', fp);
3303ad3fb45Sjoris
3313ad3fb45Sjoris (void)fclose(fp);
3323ad3fb45Sjoris
333cfff592fSderaadt l = xmalloc(sizeof(*l));
3343ad3fb45Sjoris l->buf = xstrdup(line);
3353ad3fb45Sjoris TAILQ_INSERT_TAIL(&(ep->cef_ent), l, entries_list);
3363ad3fb45Sjoris }
3373ad3fb45Sjoris
3383ad3fb45Sjoris void
cvs_ent_remove(CVSENTRIES * ep,const char * name)3393ad3fb45Sjoris cvs_ent_remove(CVSENTRIES *ep, const char *name)
3403ad3fb45Sjoris {
3413ad3fb45Sjoris FILE *fp;
3423ad3fb45Sjoris struct cvs_ent_line *l;
3433ad3fb45Sjoris
344d0a063c4Sjoris if (cvs_server_active == 0)
3453ad3fb45Sjoris cvs_log(LP_TRACE, "cvs_ent_remove(%s, %s)", ep->cef_path, name);
3463ad3fb45Sjoris
3473ad3fb45Sjoris l = ent_get_line(ep, name);
3483ad3fb45Sjoris if (l == NULL)
3493ad3fb45Sjoris return;
3503ad3fb45Sjoris
3513ad3fb45Sjoris if ((fp = fopen(ep->cef_lpath, "a")) == NULL)
3527d5f2f73Sxsa fatal("cvs_ent_remove: fopen: `%s': %s", ep->cef_lpath,
3537d5f2f73Sxsa strerror(errno));
3543ad3fb45Sjoris
355d2442498Stobias fputs("R ", fp);
3563ad3fb45Sjoris fputs(l->buf, fp);
3573ad3fb45Sjoris fputc('\n', fp);
3583ad3fb45Sjoris
3593ad3fb45Sjoris (void)fclose(fp);
3603ad3fb45Sjoris
3613ad3fb45Sjoris TAILQ_REMOVE(&(ep->cef_ent), l, entries_list);
362397ddb8aSnicm free(l->buf);
363397ddb8aSnicm free(l);
3643ad3fb45Sjoris }
3653ad3fb45Sjoris
366ae83823aSxsa /*
367ae83823aSxsa * cvs_ent_line_str()
368ae83823aSxsa *
369ae83823aSxsa * Build CVS/Entries line.
370ae83823aSxsa *
371ae83823aSxsa */
372ae83823aSxsa void
cvs_ent_line_str(const char * name,char * rev,char * tstamp,char * opts,char * sticky,int isdir,int isremoved,char * buf,size_t len)373ae83823aSxsa cvs_ent_line_str(const char *name, char *rev, char *tstamp, char *opts,
374ae83823aSxsa char *sticky, int isdir, int isremoved, char *buf, size_t len)
375ae83823aSxsa {
376ae83823aSxsa if (isdir == 1) {
377ae83823aSxsa (void)xsnprintf(buf, len, "D/%s////", name);
378ae83823aSxsa return;
379ae83823aSxsa }
380ae83823aSxsa
381ae83823aSxsa (void)xsnprintf(buf, len, "/%s/%s%s/%s/%s/%s",
382ae83823aSxsa name, isremoved == 1 ? "-" : "", rev, tstamp, opts, sticky);
383ae83823aSxsa }
384ae83823aSxsa
385bd5748ebSjfb void
cvs_ent_free(struct cvs_ent * ent)386bd5748ebSjfb cvs_ent_free(struct cvs_ent *ent)
387bd5748ebSjfb {
388*53ce2177Sfcambus free(ent->ce_rev);
389397ddb8aSnicm free(ent->ce_time);
390397ddb8aSnicm free(ent->ce_buf);
391397ddb8aSnicm free(ent);
392bd5748ebSjfb }
393bd5748ebSjfb
3943ad3fb45Sjoris static struct cvs_ent_line *
ent_get_line(CVSENTRIES * ep,const char * name)3953ad3fb45Sjoris ent_get_line(CVSENTRIES *ep, const char *name)
39608bd75e9Sjfb {
3973ad3fb45Sjoris char *p, *s;
3983ad3fb45Sjoris struct cvs_ent_line *l;
39908bd75e9Sjfb
4003ad3fb45Sjoris TAILQ_FOREACH(l, &(ep->cef_ent), entries_list) {
4013ad3fb45Sjoris if (l->buf[0] == 'D')
4023ad3fb45Sjoris p = &(l->buf[2]);
403a8778568Sjoris else
4043ad3fb45Sjoris p = &(l->buf[1]);
4053ad3fb45Sjoris
4063ad3fb45Sjoris if ((s = strchr(p, '/')) == NULL)
4073ad3fb45Sjoris fatal("ent_get_line: bad entry line '%s'", l->buf);
4083ad3fb45Sjoris
4093ad3fb45Sjoris *s = '\0';
4103ad3fb45Sjoris
4113ad3fb45Sjoris if (!strcmp(p, name)) {
4123ad3fb45Sjoris *s = '/';
4133ad3fb45Sjoris return (l);
414a8778568Sjoris }
415a8778568Sjoris
4163ad3fb45Sjoris *s = '/';
41708bd75e9Sjfb }
41808bd75e9Sjfb
4193ad3fb45Sjoris return (NULL);
42008bd75e9Sjfb }
421890ecb5aSxsa
422890ecb5aSxsa void
cvs_parse_tagfile(char * dir,char ** tagp,char ** datep,int * nbp)423890ecb5aSxsa cvs_parse_tagfile(char *dir, char **tagp, char **datep, int *nbp)
424890ecb5aSxsa {
425890ecb5aSxsa FILE *fp;
426e40de241Sxsa int i, linenum;
427890ecb5aSxsa size_t len;
4289159bf17Sjoris struct tm datetm;
429b9fc9a72Sderaadt char linebuf[128], tagpath[PATH_MAX];
430890ecb5aSxsa
431b87788a5Stobias cvs_directory_date = -1;
432b87788a5Stobias
433890ecb5aSxsa if (tagp != NULL)
4343bd1ab07Sjoris *tagp = NULL;
435890ecb5aSxsa
436890ecb5aSxsa if (datep != NULL)
4373bd1ab07Sjoris *datep = NULL;
438890ecb5aSxsa
439890ecb5aSxsa if (nbp != NULL)
440890ecb5aSxsa *nbp = 0;
441890ecb5aSxsa
442b9fc9a72Sderaadt i = snprintf(tagpath, PATH_MAX, "%s/%s", dir, CVS_PATH_TAG);
443b9fc9a72Sderaadt if (i < 0 || i >= PATH_MAX)
444ba7b4b60Sotto return;
445890ecb5aSxsa
446890ecb5aSxsa if ((fp = fopen(tagpath, "r")) == NULL) {
447890ecb5aSxsa if (errno != ENOENT)
448890ecb5aSxsa cvs_log(LP_NOTICE, "failed to open `%s' : %s", tagpath,
449890ecb5aSxsa strerror(errno));
450ba7b4b60Sotto return;
451890ecb5aSxsa }
452890ecb5aSxsa
453890ecb5aSxsa linenum = 0;
454890ecb5aSxsa
455890ecb5aSxsa while (fgets(linebuf, (int)sizeof(linebuf), fp) != NULL) {
456890ecb5aSxsa linenum++;
457890ecb5aSxsa if ((len = strlen(linebuf)) == 0)
458890ecb5aSxsa continue;
459890ecb5aSxsa if (linebuf[len - 1] != '\n') {
460890ecb5aSxsa cvs_log(LP_NOTICE, "line too long in `%s:%d'",
461890ecb5aSxsa tagpath, linenum);
462890ecb5aSxsa break;
463890ecb5aSxsa }
464890ecb5aSxsa linebuf[--len] = '\0';
465890ecb5aSxsa
466890ecb5aSxsa switch (*linebuf) {
467890ecb5aSxsa case 'T':
468890ecb5aSxsa if (tagp != NULL)
469890ecb5aSxsa *tagp = xstrdup(linebuf + 1);
470890ecb5aSxsa break;
471890ecb5aSxsa case 'D':
4729159bf17Sjoris if (sscanf(linebuf + 1, "%d.%d.%d.%d.%d.%d",
4739159bf17Sjoris &datetm.tm_year, &datetm.tm_mon, &datetm.tm_mday,
4749159bf17Sjoris &datetm.tm_hour, &datetm.tm_min, &datetm.tm_sec) !=
4759159bf17Sjoris 6)
4769159bf17Sjoris fatal("wrong date specification");
4779159bf17Sjoris datetm.tm_year -= 1900;
4789159bf17Sjoris datetm.tm_mon -= 1;
4799159bf17Sjoris
480b87788a5Stobias cvs_directory_date = timegm(&datetm);
4819159bf17Sjoris
482890ecb5aSxsa if (datep != NULL)
483890ecb5aSxsa *datep = xstrdup(linebuf + 1);
484890ecb5aSxsa break;
485890ecb5aSxsa case 'N':
486890ecb5aSxsa if (tagp != NULL)
487890ecb5aSxsa *tagp = xstrdup(linebuf + 1);
488890ecb5aSxsa if (nbp != NULL)
489890ecb5aSxsa *nbp = 1;
490890ecb5aSxsa break;
491890ecb5aSxsa default:
492890ecb5aSxsa break;
493890ecb5aSxsa }
494890ecb5aSxsa }
495890ecb5aSxsa if (ferror(fp))
496890ecb5aSxsa cvs_log(LP_NOTICE, "failed to read line from `%s'", tagpath);
497890ecb5aSxsa
498890ecb5aSxsa (void)fclose(fp);
499890ecb5aSxsa }
500890ecb5aSxsa
501890ecb5aSxsa void
cvs_write_tagfile(const char * dir,char * tag,char * date)5022dec954eStobias cvs_write_tagfile(const char *dir, char *tag, char *date)
503890ecb5aSxsa {
504890ecb5aSxsa FILE *fp;
5052dec954eStobias RCSNUM *rev;
506b9fc9a72Sderaadt char tagpath[PATH_MAX];
50751ef6581Sjoris char sticky[CVS_REV_BUFSZ];
5086534056aStobias struct tm datetm;
509e40de241Sxsa int i;
510890ecb5aSxsa
5112dec954eStobias cvs_log(LP_TRACE, "cvs_write_tagfile(%s, %s, %s)", dir,
5122dec954eStobias tag != NULL ? tag : "", date != NULL ? date : "");
5132dec954eStobias
514890ecb5aSxsa if (cvs_noexec == 1)
515890ecb5aSxsa return;
516890ecb5aSxsa
517b9fc9a72Sderaadt i = snprintf(tagpath, PATH_MAX, "%s/%s", dir, CVS_PATH_TAG);
518b9fc9a72Sderaadt if (i < 0 || i >= PATH_MAX)
519ba7b4b60Sotto return;
520890ecb5aSxsa
521b87788a5Stobias if (tag != NULL || cvs_specified_date != -1 ||
522d88ab732Sjoris cvs_directory_date != -1) {
523890ecb5aSxsa if ((fp = fopen(tagpath, "w+")) == NULL) {
524890ecb5aSxsa if (errno != ENOENT) {
525890ecb5aSxsa cvs_log(LP_NOTICE, "failed to open `%s' : %s",
526890ecb5aSxsa tagpath, strerror(errno));
527890ecb5aSxsa }
528ba7b4b60Sotto return;
529890ecb5aSxsa }
5305dd120b0Sjoris
531890ecb5aSxsa if (tag != NULL) {
5322dec954eStobias if ((rev = rcsnum_parse(tag)) != NULL) {
53351ef6581Sjoris (void)xsnprintf(sticky, sizeof(sticky),
53451ef6581Sjoris "N%s", tag);
535*53ce2177Sfcambus free(rev);
53651ef6581Sjoris } else {
53751ef6581Sjoris (void)xsnprintf(sticky, sizeof(sticky),
53851ef6581Sjoris "T%s", tag);
53951ef6581Sjoris }
54051ef6581Sjoris } else {
541b87788a5Stobias if (cvs_specified_date != -1)
5426534056aStobias gmtime_r(&cvs_specified_date, &datetm);
543b87788a5Stobias else
544b87788a5Stobias gmtime_r(&cvs_directory_date, &datetm);
54525d9b074Sxsa (void)strftime(sticky, sizeof(sticky),
5466534056aStobias "D"CVS_DATE_FMT, &datetm);
54751ef6581Sjoris }
548890ecb5aSxsa
54951ef6581Sjoris (void)fprintf(fp, "%s\n", sticky);
550890ecb5aSxsa (void)fclose(fp);
551890ecb5aSxsa }
552890ecb5aSxsa }
553