"Fossies" - the Fresh Open Source Software Archive

Member "cvs-1.11.23/src/vers_ts.c" (7 May 2008, 12153 Bytes) of package /linux/misc/old/cvs-1.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "vers_ts.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
    3  *
    4  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
    5  *                                  and others.
    6  *
    7  * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
    8  * Portions Copyright (C) 1989-1992, Brian Berliner
    9  * 
   10  * You may distribute under the terms of the GNU General Public License as
   11  * specified in the README file that comes with the CVS source distribution.
   12  */
   13 
   14 #include "cvs.h"
   15 
   16 #ifdef SERVER_SUPPORT
   17 static void time_stamp_server PROTO((const char *, Vers_TS *, Entnode *));
   18 #endif
   19 
   20 
   21 
   22 /* Fill in and return a Vers_TS structure for the file FINFO.  TAG and
   23    DATE are from the command line.  */
   24 
   25 Vers_TS *
   26 Version_TS (finfo, options, tag, date, force_tag_match, set_time)
   27     struct file_info *finfo;
   28 
   29     /* Keyword expansion options, I think generally from the command
   30        line.  Can be either NULL or "" to indicate none are specified
   31        here.  */
   32     char *options;
   33     char *tag;
   34     char *date;
   35     int force_tag_match;
   36     int set_time;
   37 {
   38     Node *p;
   39     RCSNode *rcsdata;
   40     Vers_TS *vers_ts;
   41     struct stickydirtag *sdtp;
   42     Entnode *entdata;
   43     char *rcsexpand = NULL;
   44 
   45 #ifdef UTIME_EXPECTS_WRITABLE
   46     int change_it_back = 0;
   47 #endif
   48 
   49     /* get a new Vers_TS struct */
   50     vers_ts = (Vers_TS *) xmalloc (sizeof (Vers_TS));
   51     memset ((char *) vers_ts, 0, sizeof (*vers_ts));
   52 
   53     /*
   54      * look up the entries file entry and fill in the version and timestamp
   55      * if entries is NULL, there is no entries file so don't bother trying to
   56      * look it up (used by checkout -P)
   57      */
   58     if (finfo->entries == NULL)
   59     {
   60     sdtp = NULL;
   61     p = NULL;
   62     }
   63     else
   64     {
   65     p = findnode_fn (finfo->entries, finfo->file);
   66     sdtp = finfo->entries->list->data; /* list-private */
   67     }
   68 
   69     entdata = NULL;
   70     if (p != NULL)
   71     {
   72     entdata = p->data;
   73 
   74     if (entdata->type == ENT_SUBDIR)
   75     {
   76         /* According to cvs.texinfo, the various fields in the Entries
   77            file for a directory (other than the name) do not have a
   78            defined meaning.  We need to pass them along without getting
   79            confused based on what is in them.  Therefore we make sure
   80            not to set vn_user and the like from Entries, add.c and
   81            perhaps other code will expect these fields to be NULL for
   82            a directory.  */
   83         vers_ts->entdata = entdata;
   84     }
   85     else
   86 #ifdef SERVER_SUPPORT
   87     /* An entries line with "D" in the timestamp indicates that the
   88        client sent Is-modified without sending Entry.  So we want to
   89        use the entries line for the sole purpose of telling
   90        time_stamp_server what is up; we don't want the rest of CVS
   91        to think there is an entries line.  */
   92     if (strcmp (entdata->timestamp, "D") != 0)
   93 #endif
   94     {
   95         vers_ts->vn_user = xstrdup (entdata->version);
   96         vers_ts->ts_rcs = xstrdup (entdata->timestamp);
   97         vers_ts->ts_conflict = xstrdup (entdata->conflict);
   98         if (!(tag || date) && !(sdtp && sdtp->aflag))
   99         {
  100         vers_ts->tag = xstrdup (entdata->tag);
  101         vers_ts->date = xstrdup (entdata->date);
  102         }
  103         vers_ts->entdata = entdata;
  104     }
  105     /* Even if we don't have an "entries line" as such
  106        (vers_ts->entdata), we want to pick up options which could
  107        have been from a Kopt protocol request.  */
  108     if (!options || *options == '\0')
  109     {
  110         if (!(sdtp && sdtp->aflag))
  111         vers_ts->options = xstrdup (entdata->options);
  112     }
  113     }
  114 
  115     /* Always look up the RCS keyword mode when we have an RCS archive.  It
  116      * will either be needed as a default or to avoid allowing the -k options
  117      * specified on the command line from overriding binary mode (-kb).
  118      */
  119     if (finfo->rcs != NULL)
  120     rcsexpand = RCS_getexpand (finfo->rcs);
  121 
  122     /*
  123      * -k options specified on the command line override (and overwrite)
  124      * options stored in the entries file and default options from the RCS
  125      * archive, except for binary mode (-kb).
  126      */
  127     if (options && *options != '\0')
  128     {
  129     if (vers_ts->options != NULL)
  130         free (vers_ts->options);
  131     if (rcsexpand != NULL && strcmp (rcsexpand, "b") == 0)
  132         vers_ts->options = xstrdup ("-kb");
  133     else
  134         vers_ts->options = xstrdup (options);
  135     }
  136     else if ((!vers_ts->options || *vers_ts->options == '\0')
  137              && rcsexpand != NULL)
  138     {
  139     /* If no keyword expansion was specified on command line,
  140        use whatever was in the rcs file (if there is one).  This
  141        is how we, if we are the server, tell the client whether
  142        a file is binary.  */
  143     if (vers_ts->options != NULL)
  144         free (vers_ts->options);
  145     vers_ts->options = xmalloc (strlen (rcsexpand) + 3);
  146     strcpy (vers_ts->options, "-k");
  147     strcat (vers_ts->options, rcsexpand);
  148     }
  149     if (!vers_ts->options)
  150     vers_ts->options = xstrdup ("");
  151 
  152     /*
  153      * if tags were specified on the command line, they override what is in
  154      * the Entries file
  155      */
  156     if (tag || date)
  157     {
  158     vers_ts->tag = xstrdup (tag);
  159     vers_ts->date = xstrdup (date);
  160     }
  161     else if (!vers_ts->entdata && (sdtp && sdtp->aflag == 0))
  162     {
  163     if (!vers_ts->tag)
  164     {
  165         vers_ts->tag = xstrdup (sdtp->tag);
  166         vers_ts->nonbranch = sdtp->nonbranch;
  167     }
  168     if (!vers_ts->date)
  169         vers_ts->date = xstrdup (sdtp->date);
  170     }
  171 
  172     /* Now look up the info on the source controlled file */
  173     if (finfo->rcs != NULL)
  174     {
  175     rcsdata = finfo->rcs;
  176     rcsdata->refcount++;
  177     }
  178     else if (finfo->repository != NULL)
  179     rcsdata = RCS_parse (finfo->file, finfo->repository);
  180     else
  181     rcsdata = NULL;
  182 
  183     if (rcsdata != NULL)
  184     {
  185     /* squirrel away the rcsdata pointer for others */
  186     vers_ts->srcfile = rcsdata;
  187 
  188     if (vers_ts->tag && strcmp (vers_ts->tag, TAG_BASE) == 0)
  189     {
  190         vers_ts->vn_rcs = xstrdup (vers_ts->vn_user);
  191         vers_ts->vn_tag = xstrdup (vers_ts->vn_user);
  192     }
  193     else
  194     {
  195         int simple;
  196 
  197         vers_ts->vn_rcs = RCS_getversion (rcsdata, vers_ts->tag,
  198                           vers_ts->date, force_tag_match,
  199                           &simple);
  200         if (vers_ts->vn_rcs == NULL)
  201         vers_ts->vn_tag = NULL;
  202         else if (simple)
  203         vers_ts->vn_tag = xstrdup (vers_ts->tag);
  204         else
  205         vers_ts->vn_tag = xstrdup (vers_ts->vn_rcs);
  206     }
  207 
  208     /*
  209      * If the source control file exists and has the requested revision,
  210      * get the Date the revision was checked in.  If "user" exists, set
  211      * its mtime.
  212      */
  213     if (set_time && vers_ts->vn_rcs != NULL)
  214     {
  215 #ifdef SERVER_SUPPORT
  216         if (server_active)
  217         server_modtime (finfo, vers_ts);
  218         else
  219 #endif
  220         {
  221         struct utimbuf t;
  222 
  223         memset (&t, 0, sizeof (t));
  224         t.modtime = RCS_getrevtime (rcsdata, vers_ts->vn_rcs, 0, 0);
  225         if (t.modtime != (time_t) -1)
  226         {
  227             (void) time (&t.actime);
  228 
  229 #ifdef UTIME_EXPECTS_WRITABLE
  230             if (!iswritable (finfo->file))
  231             {
  232             xchmod (finfo->file, 1);
  233             change_it_back = 1;
  234             }
  235 #endif  /* UTIME_EXPECTS_WRITABLE  */
  236 
  237             /* This used to need to ignore existence_errors
  238                (for cases like where update.c now clears
  239                set_time if noexec, but didn't used to).  I
  240                think maybe now it doesn't (server_modtime does
  241                not like those kinds of cases).  */
  242             (void) CVS_UTIME (finfo->file, &t);
  243 
  244 #ifdef UTIME_EXPECTS_WRITABLE
  245             if (change_it_back)
  246             {
  247             xchmod (finfo->file, 0);
  248             change_it_back = 0;
  249             }
  250 #endif  /*  UTIME_EXPECTS_WRITABLE  */
  251         }
  252         }
  253     }
  254     }
  255 
  256     /* get user file time-stamp in ts_user */
  257     if (finfo->entries != (List *) NULL)
  258     {
  259 #ifdef SERVER_SUPPORT
  260     if (server_active)
  261         time_stamp_server (finfo->file, vers_ts, entdata);
  262     else
  263 #endif
  264         vers_ts->ts_user = time_stamp (finfo->file);
  265     }
  266 
  267     return (vers_ts);
  268 }
  269 
  270 #ifdef SERVER_SUPPORT
  271 
  272 /* Set VERS_TS->TS_USER to time stamp for FILE.  */
  273 
  274 /* Separate these out to keep the logic below clearer.  */
  275 #define mark_lost(V)        ((V)->ts_user = 0)
  276 #define mark_unchanged(V)   ((V)->ts_user = xstrdup ((V)->ts_rcs))
  277 
  278 static void
  279 time_stamp_server (file, vers_ts, entdata)
  280     const char *file;
  281     Vers_TS *vers_ts;
  282     Entnode *entdata;
  283 {
  284     struct stat sb;
  285     char *cp;
  286 
  287     if (CVS_LSTAT (file, &sb) < 0)
  288     {
  289     if (! existence_error (errno))
  290         error (1, errno, "cannot stat temp file");
  291 
  292     /* Missing file means lost or unmodified; check entries
  293        file to see which.
  294 
  295        XXX FIXME - If there's no entries file line, we
  296        wouldn't be getting the file at all, so consider it
  297        lost.  I don't know that that's right, but it's not
  298        clear to me that either choice is.  Besides, would we
  299        have an RCS string in that case anyways?  */
  300     if (entdata == NULL)
  301         mark_lost (vers_ts);
  302     else if (entdata->timestamp
  303          && entdata->timestamp[0] == '=')
  304         mark_unchanged (vers_ts);
  305     else if (entdata->conflict
  306          && entdata->conflict[0] == '=')
  307     {
  308         /* These just need matching content.  Might as well minimize it.  */
  309         vers_ts->ts_user = xstrdup ("");
  310         vers_ts->ts_conflict = xstrdup ("");
  311     }
  312     else if (entdata->timestamp
  313          && (entdata->timestamp[0] == 'M'
  314              || entdata->timestamp[0] == 'D')
  315          && entdata->timestamp[1] == '\0')
  316         vers_ts->ts_user = xstrdup ("Is-modified");
  317     else
  318         mark_lost (vers_ts);
  319     }
  320     else if (sb.st_mtime == 0)
  321     {
  322     /* We shouldn't reach this case any more!  */
  323     abort ();
  324     }
  325     else
  326     {
  327         struct tm *tm_p;
  328 
  329     vers_ts->ts_user = xmalloc (25);
  330     /* We want to use the same timestamp format as is stored in the
  331        st_mtime.  For unix (and NT I think) this *must* be universal
  332        time (UT), so that files don't appear to be modified merely
  333        because the timezone has changed.  For VMS, or hopefully other
  334        systems where gmtime returns NULL, the modification time is
  335        stored in local time, and therefore it is not possible to cause
  336        st_mtime to be out of sync by changing the timezone.  */
  337     tm_p = gmtime (&sb.st_mtime);
  338     cp = tm_p ? asctime (tm_p) : ctime (&sb.st_mtime);
  339     cp[24] = 0;
  340     /* Fix non-standard format.  */
  341     if (cp[8] == '0') cp[8] = ' ';
  342     (void) strcpy (vers_ts->ts_user, cp);
  343 #ifdef DEBUG_TIMESTAMPS
  344     printf("sb.st_mtime = %llu, 0x%llX, %s\n", 
  345             sb.st_mtime, sb.st_mtime, cp);
  346 #endif
  347     }
  348 }
  349 
  350 #endif /* SERVER_SUPPORT */
  351 /*
  352  * Gets the time-stamp for the file "file" and returns it in space it
  353  * allocates
  354  */
  355 char *
  356 time_stamp (file)
  357     const char *file;
  358 {
  359     struct stat sb;
  360     char *cp;
  361     char *ts = NULL;
  362     time_t mtime = 0L;
  363 
  364     if (!CVS_LSTAT (file, &sb))
  365     {
  366     mtime = sb.st_mtime;
  367     }
  368     else if (! existence_error (errno))
  369     error (0, errno, "cannot lstat %s", file);
  370 
  371     /* If it's a symlink, return whichever is the newest mtime of
  372        the link and its target, for safety.
  373     */
  374     if (!CVS_STAT (file, &sb))
  375     {
  376         if (mtime < sb.st_mtime)
  377         mtime = sb.st_mtime;
  378     }
  379     else if (! existence_error (errno))
  380     error (0, errno, "cannot stat %s", file);
  381 
  382     if (mtime)
  383     {
  384     struct tm *tm_p;
  385     ts = xmalloc (25);
  386     /* We want to use the same timestamp format as is stored in the
  387        st_mtime.  For unix (and NT I think) this *must* be universal
  388        time (UT), so that files don't appear to be modified merely
  389        because the timezone has changed.  For VMS, or hopefully other
  390        systems where gmtime returns NULL, the modification time is
  391        stored in local time, and therefore it is not possible to cause
  392        st_mtime to be out of sync by changing the timezone.  */
  393     tm_p = gmtime (&mtime);
  394     cp = tm_p ? asctime (tm_p) : ctime (&mtime);
  395     cp[24] = 0;
  396     /* Fix non-standard format.  */
  397     if (cp[8] == '0') cp[8] = ' ';
  398     (void) strcpy (ts, cp);
  399 #ifdef DEBUG_TIMESTAMPS
  400     printf("sb.st_mtime = %llu, 0x%llX, %s\n",
  401         sb.st_mtime, sb.st_mtime, cp);
  402 #endif
  403     }
  404 
  405     return (ts);
  406 }
  407 
  408 /*
  409  * free up a Vers_TS struct
  410  */
  411 void
  412 freevers_ts (versp)
  413     Vers_TS **versp;
  414 {
  415     if ((*versp)->srcfile)
  416     freercsnode (&((*versp)->srcfile));
  417     if ((*versp)->vn_user)
  418     free ((*versp)->vn_user);
  419     if ((*versp)->vn_rcs)
  420     free ((*versp)->vn_rcs);
  421     if ((*versp)->vn_tag)
  422     free ((*versp)->vn_tag);
  423     if ((*versp)->ts_user)
  424     free ((*versp)->ts_user);
  425     if ((*versp)->ts_rcs)
  426     free ((*versp)->ts_rcs);
  427     if ((*versp)->options)
  428     free ((*versp)->options);
  429     if ((*versp)->tag)
  430     free ((*versp)->tag);
  431     if ((*versp)->date)
  432     free ((*versp)->date);
  433     if ((*versp)->ts_conflict)
  434     free ((*versp)->ts_conflict);
  435     free ((char *) *versp);
  436     *versp = (Vers_TS *) NULL;
  437 }