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

Annotation of src/usr.bin/cvs/entries.c, Revision 1.106

1.106   ! nicm        1: /*     $OpenBSD: entries.c,v 1.105 2015/08/20 22:32:41 deraadt Exp $   */
1.1       jfb         2: /*
1.57      joris       3:  * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
1.1       jfb         4:  *
1.57      joris       5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1       jfb        16:  */
                     17:
1.75      otto       18: #include <errno.h>
1.106   ! nicm       19: #include <stdlib.h>
1.75      otto       20: #include <string.h>
1.83      chl        21: #include <time.h>
1.75      otto       22: #include <unistd.h>
1.1       jfb        23:
1.34      xsa        24: #include "cvs.h"
1.81      joris      25: #include "remote.h"
1.1       jfb        26:
1.42      xsa        27: #define CVS_ENTRIES_NFIELDS    6
                     28: #define CVS_ENTRIES_DELIM      '/'
1.1       jfb        29:
1.57      joris      30: static struct cvs_ent_line *ent_get_line(CVSENTRIES *, const char *);
1.1       jfb        31:
1.98      joris      32: CVSENTRIES *current_list = NULL;
                     33:
1.42      xsa        34: CVSENTRIES *
1.57      joris      35: cvs_ent_open(const char *dir)
1.1       jfb        36: {
1.57      joris      37:        FILE *fp;
                     38:        CVSENTRIES *ep;
1.103     deraadt    39:        char *p, buf[PATH_MAX];
1.1       jfb        40:        struct cvs_ent *ent;
1.57      joris      41:        struct cvs_ent_line *line;
1.36      xsa        42:
1.98      joris      43:        cvs_log(LP_TRACE, "cvs_ent_open(%s)", dir);
1.52      joris      44:
1.73      xsa        45:        (void)xsnprintf(buf, sizeof(buf), "%s/%s", dir, CVS_PATH_ENTRIES);
1.64      xsa        46:
1.98      joris      47:        if (current_list != NULL && !strcmp(current_list->cef_path, buf))
                     48:                return (current_list);
                     49:
                     50:        if (current_list != NULL) {
                     51:                cvs_ent_close(current_list, ENT_SYNC);
                     52:                current_list = NULL;
                     53:        }
                     54:
1.105     deraadt    55:        ep = xcalloc(1, sizeof(*ep));
1.57      joris      56:        ep->cef_path = xstrdup(buf);
1.8       jfb        57:
1.73      xsa        58:        (void)xsnprintf(buf, sizeof(buf), "%s/%s",
                     59:            dir, CVS_PATH_BACKUPENTRIES);
1.64      xsa        60:
1.57      joris      61:        ep->cef_bpath = xstrdup(buf);
1.3       jfb        62:
1.73      xsa        63:        (void)xsnprintf(buf, sizeof(buf), "%s/%s", dir, CVS_PATH_LOGENTRIES);
1.64      xsa        64:
1.57      joris      65:        ep->cef_lpath = xstrdup(buf);
1.1       jfb        66:
1.4       jfb        67:        TAILQ_INIT(&(ep->cef_ent));
1.3       jfb        68:
1.57      joris      69:        if ((fp = fopen(ep->cef_path, "r")) != NULL) {
                     70:                while (fgets(buf, sizeof(buf), fp)) {
1.84      gilles     71:                        buf[strcspn(buf, "\n")] = '\0';
1.57      joris      72:
                     73:                        if (buf[0] == 'D' && buf[1] == '\0')
                     74:                                break;
                     75:
1.105     deraadt    76:                        line = xmalloc(sizeof(*line));
1.57      joris      77:                        line->buf = xstrdup(buf);
                     78:                        TAILQ_INSERT_TAIL(&(ep->cef_ent), line, entries_list);
                     79:                }
1.52      joris      80:
1.25      jfb        81:                (void)fclose(fp);
1.12      jfb        82:        }
1.1       jfb        83:
1.57      joris      84:        if ((fp = fopen(ep->cef_lpath, "r")) != NULL) {
                     85:                while (fgets(buf, sizeof(buf), fp)) {
1.84      gilles     86:                        buf[strcspn(buf, "\n")] = '\0';
1.57      joris      87:
1.87      tobias     88:                        if (strlen(buf) < 2)
                     89:                                fatal("cvs_ent_open: %s: malformed line %s",
                     90:                                    ep->cef_lpath, buf);
                     91:
                     92:                        p = &buf[2];
1.57      joris      93:
                     94:                        if (buf[0] == 'A') {
                     95:                                line = xmalloc(sizeof(*line));
                     96:                                line->buf = xstrdup(p);
                     97:                                TAILQ_INSERT_TAIL(&(ep->cef_ent), line,
                     98:                                    entries_list);
                     99:                        } else if (buf[0] == 'R') {
                    100:                                ent = cvs_ent_parse(p);
                    101:                                line = ent_get_line(ep, ent->ce_name);
1.65      joris     102:                                if (line != NULL) {
1.57      joris     103:                                        TAILQ_REMOVE(&(ep->cef_ent), line,
                    104:                                            entries_list);
1.106   ! nicm      105:                                        free(line->buf);
        !           106:                                        free(line);
1.65      joris     107:                                }
1.57      joris     108:                                cvs_ent_free(ent);
                    109:                        }
                    110:                }
1.4       jfb       111:
1.52      joris     112:                (void)fclose(fp);
                    113:        }
1.12      jfb       114:
1.98      joris     115:        current_list = ep;
1.1       jfb       116:        return (ep);
                    117: }
                    118:
1.57      joris     119: struct cvs_ent *
                    120: cvs_ent_parse(const char *entry)
1.1       jfb       121: {
1.57      joris     122:        int i;
1.91      joris     123:        struct tm t, dt;
1.5       jfb       124:        struct cvs_ent *ent;
1.96      tobias    125:        char *fields[CVS_ENTRIES_NFIELDS], *buf, *sp, *dp, *p;
1.5       jfb       126:
1.72      joris     127:        buf = sp = xstrdup(entry);
1.57      joris     128:        i = 0;
                    129:        do {
                    130:                dp = strchr(sp, CVS_ENTRIES_DELIM);
                    131:                if (dp != NULL)
                    132:                        *(dp++) = '\0';
                    133:                fields[i++] = sp;
                    134:                sp = dp;
                    135:        } while (dp != NULL && i < CVS_ENTRIES_NFIELDS);
1.8       jfb       136:
1.57      joris     137:        if (i < CVS_ENTRIES_NFIELDS)
                    138:                fatal("missing fields in entry line '%s'", entry);
1.5       jfb       139:
1.72      joris     140:        ent = xmalloc(sizeof(*ent));
1.57      joris     141:        ent->ce_buf = buf;
1.52      joris     142:
1.57      joris     143:        if (*fields[0] == '\0')
                    144:                ent->ce_type = CVS_ENT_FILE;
                    145:        else if (*fields[0] == 'D')
                    146:                ent->ce_type = CVS_ENT_DIR;
                    147:        else
                    148:                ent->ce_type = CVS_ENT_NONE;
                    149:
                    150:        ent->ce_status = CVS_ENT_REG;
                    151:        ent->ce_name = fields[1];
                    152:        ent->ce_rev = NULL;
1.92      joris     153:        ent->ce_date = -1;
                    154:        ent->ce_tag = NULL;
1.104     stsp      155:        ent->ce_time = NULL;
1.5       jfb       156:
1.57      joris     157:        if (ent->ce_type == CVS_ENT_FILE) {
                    158:                if (*fields[2] == '-') {
                    159:                        ent->ce_status = CVS_ENT_REMOVED;
                    160:                        sp = fields[2] + 1;
1.102     joris     161:                } else if (*fields[2] == CVS_SERVER_QUESTIONABLE) {
                    162:                        sp = NULL;
                    163:                        ent->ce_status = CVS_ENT_UNKNOWN;
1.57      joris     164:                } else {
                    165:                        sp = fields[2];
                    166:                        if (fields[2][0] == '0' && fields[2][1] == '\0')
                    167:                                ent->ce_status = CVS_ENT_ADDED;
                    168:                }
1.1       jfb       169:
1.102     joris     170:                if (sp != NULL) {
                    171:                        if ((ent->ce_rev = rcsnum_parse(sp)) == NULL) {
                    172:                                fatal("failed to parse entry revision '%s'",
                    173:                                    entry);
                    174:                        }
                    175:                }
1.1       jfb       176:
1.72      joris     177:                if (fields[3][0] == '\0' ||
1.102     joris     178:                    strncmp(fields[3], CVS_DATE_DUMMY,
                    179:                    sizeof(CVS_DATE_DUMMY) - 1) == 0 ||
1.57      joris     180:                    strncmp(fields[3], "Initial ", 8) == 0 ||
1.96      tobias    181:                    strcmp(fields[3], "Result of merge") == 0) {
1.57      joris     182:                        ent->ce_mtime = CVS_DATE_DMSEC;
1.81      joris     183:                } else if (cvs_server_active == 1 &&
                    184:                    strncmp(fields[3], CVS_SERVER_UNCHANGED,
                    185:                    strlen(CVS_SERVER_UNCHANGED)) == 0) {
                    186:                        ent->ce_mtime = CVS_SERVER_UPTODATE;
                    187:                } else {
1.96      tobias    188:                        p = fields[3];
                    189:                        if (strncmp(fields[3], "Result of merge+", 16) == 0)
                    190:                                p += 16;
                    191:
1.104     stsp      192:                        ent->ce_time = xstrdup(p);
                    193:
1.78      niallo    194:                        /* Date field can be a '+=' with remote to indicate
                    195:                         * conflict.  In this case do nothing. */
1.96      tobias    196:                        if (strptime(p, "%a %b %d %T %Y", &t) != NULL) {
1.78      niallo    197:                                t.tm_isdst = -1;        /* Figure out DST. */
                    198:                                t.tm_gmtoff = 0;
                    199:                                ent->ce_mtime = mktime(&t);
                    200:                                ent->ce_mtime += t.tm_gmtoff;
                    201:                        }
1.70      joris     202:                }
1.3       jfb       203:        }
1.1       jfb       204:
1.57      joris     205:        ent->ce_conflict = fields[3];
                    206:        if ((dp = strchr(ent->ce_conflict, '+')) != NULL)
                    207:                *dp = '\0';
                    208:        else
                    209:                ent->ce_conflict = NULL;
1.1       jfb       210:
1.57      joris     211:        if (strcmp(fields[4], ""))
                    212:                ent->ce_opts = fields[4];
                    213:        else
                    214:                ent->ce_opts = NULL;
1.8       jfb       215:
1.91      joris     216:        if (strcmp(fields[5], "")) {
1.95      deraadt   217:                switch (*fields[5]) {
1.91      joris     218:                case 'D':
                    219:                        if (sscanf(fields[5] + 1, "%d.%d.%d.%d.%d.%d",
                    220:                            &dt.tm_year, &dt.tm_mon, &dt.tm_mday,
                    221:                            &dt.tm_hour, &dt.tm_min, &dt.tm_sec) != 6)
                    222:                                fatal("wrong date specification");
                    223:                        dt.tm_year -= 1900;
                    224:                        dt.tm_mon -= 1;
                    225:                        ent->ce_date = timegm(&dt);
                    226:                        ent->ce_tag = NULL;
                    227:                        break;
                    228:                case 'T':
                    229:                        ent->ce_tag = fields[5] + 1;
                    230:                        break;
                    231:                default:
                    232:                        fatal("invalid sticky entry");
                    233:                }
1.92      joris     234:        }
1.3       jfb       235:
1.57      joris     236:        return (ent);
1.3       jfb       237: }
                    238:
1.57      joris     239: struct cvs_ent *
                    240: cvs_ent_get(CVSENTRIES *ep, const char *name)
1.3       jfb       241: {
                    242:        struct cvs_ent *ent;
1.57      joris     243:        struct cvs_ent_line *l;
1.3       jfb       244:
1.57      joris     245:        l = ent_get_line(ep, name);
                    246:        if (l == NULL)
                    247:                return (NULL);
1.3       jfb       248:
1.57      joris     249:        ent = cvs_ent_parse(l->buf);
                    250:        return (ent);
1.1       jfb       251: }
                    252:
1.57      joris     253: void
                    254: cvs_ent_close(CVSENTRIES *ep, int writefile)
1.9       jfb       255: {
1.57      joris     256:        FILE *fp;
                    257:        struct cvs_ent_line *l;
1.85      tobias    258:        int dflag;
                    259:
                    260:        dflag = 1;
1.98      joris     261:        cvs_log(LP_TRACE, "cvs_ent_close(%s, %d)", ep->cef_bpath, writefile);
1.44      xsa       262:
1.98      joris     263:        if (cvs_cmdop == CVS_OP_EXPORT)
                    264:                writefile = 0;
                    265:
                    266:        fp = NULL;
                    267:        if (writefile)
                    268:                fp = fopen(ep->cef_bpath, "w");
1.16      jfb       269:
1.57      joris     270:        while ((l = TAILQ_FIRST(&(ep->cef_ent))) != NULL) {
1.98      joris     271:                if (fp != NULL) {
1.85      tobias    272:                        if (l->buf[0] == 'D')
                    273:                                dflag = 0;
                    274:
1.57      joris     275:                        fputs(l->buf, fp);
                    276:                        fputc('\n', fp);
1.51      joris     277:                }
1.57      joris     278:
                    279:                TAILQ_REMOVE(&(ep->cef_ent), l, entries_list);
1.106   ! nicm      280:                free(l->buf);
        !           281:                free(l);
1.22      jfb       282:        }
1.9       jfb       283:
1.98      joris     284:        if (fp != NULL) {
1.85      tobias    285:                if (dflag) {
                    286:                        fputc('D', fp);
                    287:                        fputc('\n', fp);
                    288:                }
1.57      joris     289:                (void)fclose(fp);
                    290:
                    291:                if (rename(ep->cef_bpath, ep->cef_path) == -1)
1.63      xsa       292:                        fatal("cvs_ent_close: rename: `%s'->`%s': %s",
                    293:                            ep->cef_bpath, ep->cef_path, strerror(errno));
1.57      joris     294:
                    295:                (void)unlink(ep->cef_lpath);
                    296:        }
1.9       jfb       297:
1.106   ! nicm      298:        free(ep->cef_path);
        !           299:        free(ep->cef_bpath);
        !           300:        free(ep->cef_lpath);
        !           301:        free(ep);
1.9       jfb       302: }
                    303:
1.57      joris     304: void
                    305: cvs_ent_add(CVSENTRIES *ep, const char *line)
1.1       jfb       306: {
1.57      joris     307:        FILE *fp;
                    308:        struct cvs_ent_line *l;
1.39      xsa       309:        struct cvs_ent *ent;
1.1       jfb       310:
1.57      joris     311:        if ((ent = cvs_ent_parse(line)) == NULL)
                    312:                fatal("cvs_ent_add: parsing failed '%s'", line);
1.1       jfb       313:
1.57      joris     314:        l = ent_get_line(ep, ent->ce_name);
                    315:        if (l != NULL)
                    316:                cvs_ent_remove(ep, ent->ce_name);
1.1       jfb       317:
1.57      joris     318:        cvs_ent_free(ent);
1.1       jfb       319:
1.61      joris     320:        if (cvs_server_active == 0)
                    321:                cvs_log(LP_TRACE, "cvs_ent_add(%s, %s)", ep->cef_path, line);
1.1       jfb       322:
1.57      joris     323:        if ((fp = fopen(ep->cef_lpath, "a")) == NULL)
1.63      xsa       324:                fatal("cvs_ent_add: fopen: `%s': %s",
                    325:                    ep->cef_lpath, strerror(errno));
1.1       jfb       326:
1.87      tobias    327:        fputs("A ", fp);
1.57      joris     328:        fputs(line, fp);
                    329:        fputc('\n', fp);
1.1       jfb       330:
1.57      joris     331:        (void)fclose(fp);
1.10      jfb       332:
1.105     deraadt   333:        l = xmalloc(sizeof(*l));
1.57      joris     334:        l->buf = xstrdup(line);
                    335:        TAILQ_INSERT_TAIL(&(ep->cef_ent), l, entries_list);
                    336: }
1.10      jfb       337:
1.57      joris     338: void
                    339: cvs_ent_remove(CVSENTRIES *ep, const char *name)
                    340: {
                    341:        FILE *fp;
                    342:        struct cvs_ent_line *l;
1.1       jfb       343:
1.61      joris     344:        if (cvs_server_active == 0)
                    345:                cvs_log(LP_TRACE, "cvs_ent_remove(%s, %s)", ep->cef_path, name);
1.1       jfb       346:
1.57      joris     347:        l = ent_get_line(ep, name);
                    348:        if (l == NULL)
                    349:                return;
1.1       jfb       350:
1.57      joris     351:        if ((fp = fopen(ep->cef_lpath, "a")) == NULL)
1.63      xsa       352:                fatal("cvs_ent_remove: fopen: `%s': %s", ep->cef_lpath,
                    353:                    strerror(errno));
1.38      joris     354:
1.87      tobias    355:        fputs("R ", fp);
1.57      joris     356:        fputs(l->buf, fp);
                    357:        fputc('\n', fp);
1.24      jfb       358:
1.57      joris     359:        (void)fclose(fp);
1.24      jfb       360:
1.57      joris     361:        TAILQ_REMOVE(&(ep->cef_ent), l, entries_list);
1.106   ! nicm      362:        free(l->buf);
        !           363:        free(l);
1.90      xsa       364: }
                    365:
                    366: /*
                    367:  * cvs_ent_line_str()
                    368:  *
                    369:  * Build CVS/Entries line.
                    370:  *
                    371:  */
                    372: void
                    373: cvs_ent_line_str(const char *name, char *rev, char *tstamp, char *opts,
                    374:     char *sticky, int isdir, int isremoved, char *buf, size_t len)
                    375: {
                    376:        if (isdir == 1) {
                    377:                (void)xsnprintf(buf, len, "D/%s////", name);
                    378:                return;
                    379:        }
                    380:
                    381:        (void)xsnprintf(buf, len, "/%s/%s%s/%s/%s/%s",
                    382:            name, isremoved == 1 ? "-" : "", rev, tstamp, opts, sticky);
1.5       jfb       383: }
                    384:
                    385: void
                    386: cvs_ent_free(struct cvs_ent *ent)
                    387: {
                    388:        if (ent->ce_rev != NULL)
                    389:                rcsnum_free(ent->ce_rev);
1.106   ! nicm      390:        free(ent->ce_time);
        !           391:        free(ent->ce_buf);
        !           392:        free(ent);
1.5       jfb       393: }
1.8       jfb       394:
1.57      joris     395: static struct cvs_ent_line *
                    396: ent_get_line(CVSENTRIES *ep, const char *name)
1.8       jfb       397: {
1.57      joris     398:        char *p, *s;
                    399:        struct cvs_ent_line *l;
1.8       jfb       400:
1.57      joris     401:        TAILQ_FOREACH(l, &(ep->cef_ent), entries_list) {
                    402:                if (l->buf[0] == 'D')
                    403:                        p = &(l->buf[2]);
                    404:                else
                    405:                        p = &(l->buf[1]);
                    406:
                    407:                if ((s = strchr(p, '/')) == NULL)
                    408:                        fatal("ent_get_line: bad entry line '%s'", l->buf);
                    409:
                    410:                *s = '\0';
                    411:
                    412:                if (!strcmp(p, name)) {
                    413:                        *s = '/';
                    414:                        return (l);
1.15      jfb       415:                }
1.8       jfb       416:
1.57      joris     417:                *s = '/';
1.8       jfb       418:        }
                    419:
1.57      joris     420:        return (NULL);
1.59      xsa       421: }
                    422:
                    423: void
                    424: cvs_parse_tagfile(char *dir, char **tagp, char **datep, int *nbp)
                    425: {
                    426:        FILE *fp;
1.73      xsa       427:        int i, linenum;
1.59      xsa       428:        size_t len;
1.91      joris     429:        struct tm datetm;
1.103     deraadt   430:        char linebuf[128], tagpath[PATH_MAX];
1.59      xsa       431:
1.99      tobias    432:        cvs_directory_date = -1;
                    433:
1.59      xsa       434:        if (tagp != NULL)
1.60      joris     435:                *tagp = NULL;
1.59      xsa       436:
                    437:        if (datep != NULL)
1.60      joris     438:                *datep = NULL;
1.59      xsa       439:
                    440:        if (nbp != NULL)
                    441:                *nbp = 0;
                    442:
1.103     deraadt   443:        i = snprintf(tagpath, PATH_MAX, "%s/%s", dir, CVS_PATH_TAG);
                    444:        if (i < 0 || i >= PATH_MAX)
1.69      otto      445:                return;
1.59      xsa       446:
                    447:        if ((fp = fopen(tagpath, "r")) == NULL) {
                    448:                if (errno != ENOENT)
                    449:                        cvs_log(LP_NOTICE, "failed to open `%s' : %s", tagpath,
                    450:                            strerror(errno));
1.69      otto      451:                return;
1.59      xsa       452:         }
                    453:
                    454:        linenum = 0;
                    455:
                    456:        while (fgets(linebuf, (int)sizeof(linebuf), fp) != NULL) {
                    457:                linenum++;
                    458:                if ((len = strlen(linebuf)) == 0)
                    459:                        continue;
                    460:                if (linebuf[len - 1] != '\n') {
                    461:                        cvs_log(LP_NOTICE, "line too long in `%s:%d'",
                    462:                            tagpath, linenum);
                    463:                        break;
                    464:                }
                    465:                linebuf[--len] = '\0';
                    466:
                    467:                switch (*linebuf) {
                    468:                case 'T':
                    469:                        if (tagp != NULL)
                    470:                                *tagp = xstrdup(linebuf + 1);
                    471:                        break;
                    472:                case 'D':
1.91      joris     473:                        if (sscanf(linebuf + 1, "%d.%d.%d.%d.%d.%d",
                    474:                            &datetm.tm_year, &datetm.tm_mon, &datetm.tm_mday,
                    475:                            &datetm.tm_hour, &datetm.tm_min, &datetm.tm_sec) !=
                    476:                            6)
                    477:                                fatal("wrong date specification");
                    478:                        datetm.tm_year -= 1900;
                    479:                        datetm.tm_mon -= 1;
                    480:
1.99      tobias    481:                        cvs_directory_date = timegm(&datetm);
1.91      joris     482:
1.59      xsa       483:                        if (datep != NULL)
                    484:                                *datep = xstrdup(linebuf + 1);
                    485:                        break;
                    486:                case 'N':
                    487:                        if (tagp != NULL)
                    488:                                *tagp = xstrdup(linebuf + 1);
                    489:                        if (nbp != NULL)
                    490:                                *nbp = 1;
                    491:                        break;
                    492:                default:
                    493:                        break;
                    494:                }
                    495:        }
                    496:        if (ferror(fp))
                    497:                cvs_log(LP_NOTICE, "failed to read line from `%s'", tagpath);
                    498:
                    499:        (void)fclose(fp);
                    500: }
                    501:
                    502: void
1.88      tobias    503: cvs_write_tagfile(const char *dir, char *tag, char *date)
1.59      xsa       504: {
                    505:        FILE *fp;
1.88      tobias    506:        RCSNUM *rev;
1.103     deraadt   507:        char tagpath[PATH_MAX];
1.82      joris     508:        char sticky[CVS_REV_BUFSZ];
1.97      tobias    509:        struct tm datetm;
1.73      xsa       510:        int i;
1.59      xsa       511:
1.88      tobias    512:        cvs_log(LP_TRACE, "cvs_write_tagfile(%s, %s, %s)", dir,
                    513:            tag != NULL ? tag : "", date != NULL ? date : "");
                    514:
1.59      xsa       515:        if (cvs_noexec == 1)
                    516:                return;
                    517:
1.103     deraadt   518:        i = snprintf(tagpath, PATH_MAX, "%s/%s", dir, CVS_PATH_TAG);
                    519:        if (i < 0 || i >= PATH_MAX)
1.69      otto      520:                return;
1.59      xsa       521:
1.99      tobias    522:        if (tag != NULL || cvs_specified_date != -1 ||
1.100     joris     523:            cvs_directory_date != -1) {
1.59      xsa       524:                if ((fp = fopen(tagpath, "w+")) == NULL) {
                    525:                        if (errno != ENOENT) {
                    526:                                cvs_log(LP_NOTICE, "failed to open `%s' : %s",
                    527:                                    tagpath, strerror(errno));
                    528:                        }
1.69      otto      529:                        return;
1.59      xsa       530:                }
1.79      joris     531:
1.59      xsa       532:                if (tag != NULL) {
1.88      tobias    533:                        if ((rev = rcsnum_parse(tag)) != NULL) {
1.82      joris     534:                                (void)xsnprintf(sticky, sizeof(sticky),
                    535:                                    "N%s", tag);
1.88      tobias    536:                                rcsnum_free(rev);
1.82      joris     537:                        } else {
                    538:                                (void)xsnprintf(sticky, sizeof(sticky),
                    539:                                    "T%s", tag);
                    540:                        }
                    541:                } else {
1.99      tobias    542:                        if (cvs_specified_date != -1)
                    543:                                gmtime_r(&cvs_specified_date, &datetm);
                    544:                        else
                    545:                                gmtime_r(&cvs_directory_date, &datetm);
1.94      xsa       546:                        (void)strftime(sticky, sizeof(sticky),
1.97      tobias    547:                            "D"CVS_DATE_FMT, &datetm);
1.82      joris     548:                }
1.59      xsa       549:
1.82      joris     550:                (void)fprintf(fp, "%s\n", sticky);
1.59      xsa       551:                (void)fclose(fp);
                    552:        }
1.1       jfb       553: }