[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.91

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