Пример #1
0
time_t
ar_member_date (const char *name)
{
  char *arname;
  char *memname;
  long int val;

  ar_parse_name (name, &arname, &memname);

  /* Make sure we know the modtime of the archive itself because we are
     likely to be called just before commands to remake a member are run,
     and they will change the archive itself.

     But we must be careful not to enter_file the archive itself if it does
     not exist, because pattern_search assumes that files found in the data
     base exist or can be made.  */
  {
    struct file *arfile;
    arfile = lookup_file (arname);
    if (arfile == 0 && file_exists_p (arname))
      arfile = enter_file (strcache_add (arname));

    if (arfile != 0)
      (void) f_mtime (arfile, 0);
  }

  val = ar_scan (arname, ar_member_date_1, memname);

  free (arname);

  return (val <= 0 ? (time_t) -1 : (time_t) val);
}
Пример #2
0
int
ar_touch (const char *name)
{
  char *arname, *memname;
  int val;

  ar_parse_name (name, &arname, &memname);

  /* Make sure we know the modtime of the archive itself before we
     touch the member, since this will change the archive modtime.  */
  {
    struct file *arfile;
    arfile = enter_file (strcache_add (arname));
    f_mtime (arfile, 0);
  }

  val = 1;
  switch (ar_member_touch (arname, memname))
    {
    case -1:
      error (NILF, _("touch: Archive `%s' does not exist"), arname);
      break;
    case -2:
      error (NILF, _("touch: `%s' is not a valid archive"), arname);
      break;
    case -3:
      perror_with_name ("touch: ", arname);
      break;
    case 1:
      error (NILF,
             _("touch: Member `%s' does not exist in `%s'"), memname, arname);
      break;
    case 0:
      val = 0;
      break;
    default:
      error (NILF,
             _("touch: Bad return code from ar_member_touch on `%s'"), name);
    }

  free (arname);

  return val;
}
Пример #3
0
void
notice_finished_file (struct file *file)
{
  struct dep *d;
  int ran = file->command_state == cs_running;
  int touched = 0;

  file->command_state = cs_finished;
  file->updated = 1;

  if (touch_flag
      /* The update status will be:
		-1	if this target was not remade;
		0	if 0 or more commands (+ or ${MAKE}) were run and won;
		1	if some commands were run and lost.
	 We touch the target if it has commands which either were not run
	 or won when they ran (i.e. status is 0).  */
      && file->update_status == 0)
    {
      if (file->cmds != 0 && file->cmds->any_recurse)
	{
	  /* If all the command lines were recursive,
	     we don't want to do the touching.  */
	  unsigned int i;
	  for (i = 0; i < file->cmds->ncommand_lines; ++i)
	    if (!(file->cmds->lines_flags[i] & COMMANDS_RECURSE))
	      goto have_nonrecursing;
	}
      else
	{
	have_nonrecursing:
	  if (file->phony)
	    file->update_status = 0;
          /* According to POSIX, -t doesn't affect targets with no cmds.  */
	  else if (file->cmds != 0)
            {
              /* Should set file's modification date and do nothing else.  */
              file->update_status = touch_file (file);

              /* Pretend we ran a real touch command, to suppress the
                 "'foo' is up to date" message.  */
              commands_started++;

              /* Request for the timestamp to be updated (and distributed
                 to the double-colon entries). Simply setting ran=1 would
                 almost have done the trick, but messes up with the also_make
                 updating logic below.  */
              touched = 1;
            }
	}
    }

  if (file->mtime_before_update == UNKNOWN_MTIME)
    file->mtime_before_update = file->last_mtime;

  if ((ran && !file->phony) || touched)
    {
      int i = 0;

      /* If -n, -t, or -q and all the commands are recursive, we ran them so
         really check the target's mtime again.  Otherwise, assume the target
         would have been updated. */

      if ((question_flag || just_print_flag || touch_flag) && file->cmds)
        {
          for (i = file->cmds->ncommand_lines; i > 0; --i)
            if (! (file->cmds->lines_flags[i-1] & COMMANDS_RECURSE))
              break;
        }

      /* If there were no commands at all, it's always new. */

      else if (file->is_target && file->cmds == 0)
	i = 1;

      file->last_mtime = i == 0 ? UNKNOWN_MTIME : NEW_MTIME;
    }

  if (file->double_colon)
    {
      /* If this is a double colon rule and it is the last one to be
         updated, propagate the change of modification time to all the
         double-colon entries for this file.

         We do it on the last update because it is important to handle
         individual entries as separate rules with separate timestamps
         while they are treated as targets and then as one rule with the
         unified timestamp when they are considered as a prerequisite
         of some target.  */

      struct file *f;
      FILE_TIMESTAMP max_mtime = file->last_mtime;

      /* Check that all rules were updated and at the same time find
         the max timestamp.  We assume UNKNOWN_MTIME is newer then
         any other value.  */
      for (f = file->double_colon; f != 0 && f->updated; f = f->prev)
        if (max_mtime != UNKNOWN_MTIME
            && (f->last_mtime == UNKNOWN_MTIME || f->last_mtime > max_mtime))
          max_mtime = f->last_mtime;

      if (f == 0)
        for (f = file->double_colon; f != 0; f = f->prev)
          f->last_mtime = max_mtime;
    }

  if (ran && file->update_status != -1)
    /* We actually tried to update FILE, which has
       updated its also_make's as well (if it worked).
       If it didn't work, it wouldn't work again for them.
       So mark them as updated with the same status.  */
    for (d = file->also_make; d != 0; d = d->next)
      {
	d->file->command_state = cs_finished;
	d->file->updated = 1;
	d->file->update_status = file->update_status;

	if (ran && !d->file->phony)
	  /* Fetch the new modification time.
	     We do this instead of just invalidating the cached time
	     so that a vpath_search can happen.  Otherwise, it would
	     never be done because the target is already updated.  */
	  f_mtime (d->file, 0);
      }
  else if (file->update_status == -1)
    /* Nothing was done for FILE, but it needed nothing done.
       So mark it now as "succeeded".  */
    file->update_status = 0;
}
Пример #4
0
FILE_TIMESTAMP
f_mtime (struct file *file, int search)
{
  FILE_TIMESTAMP mtime;

  /* File's mtime is not known; must get it from the system.  */

#ifndef	NO_ARCHIVES
  if (ar_name (file->name))
    {
      /* This file is an archive-member reference.  */

      char *arname, *memname;
      struct file *arfile;
      time_t member_date;

      /* Find the archive's name.  */
      ar_parse_name (file->name, &arname, &memname);

      /* Find the modification time of the archive itself.
	 Also allow for its name to be changed via VPATH search.  */
      arfile = lookup_file (arname);
      if (arfile == 0)
        arfile = enter_file (strcache_add (arname));
      mtime = f_mtime (arfile, search);
      check_renamed (arfile);
      if (search && strcmp (arfile->hname, arname))
	{
	  /* The archive's name has changed.
	     Change the archive-member reference accordingly.  */

          char *name;
	  unsigned int arlen, memlen;

	  arlen = strlen (arfile->hname);
	  memlen = strlen (memname);

	  name = xmalloc (arlen + 1 + memlen + 2);
	  memcpy (name, arfile->hname, arlen);
	  name[arlen] = '(';
	  memcpy (name + arlen + 1, memname, memlen);
	  name[arlen + 1 + memlen] = ')';
	  name[arlen + 1 + memlen + 1] = '\0';

          /* If the archive was found with GPATH, make the change permanent;
             otherwise defer it until later.  */
          if (arfile->name == arfile->hname)
            rename_file (file, name);
          else
            rehash_file (file, name);
          check_renamed (file);
	}

      free (arname);

      file->low_resolution_time = 1;

      if (mtime == NONEXISTENT_MTIME)
	/* The archive doesn't exist, so its members don't exist either.  */
	return NONEXISTENT_MTIME;

      member_date = ar_member_date (file->hname);
      mtime = (member_date == (time_t) -1
               ? NONEXISTENT_MTIME
               : file_timestamp_cons (file->hname, member_date, 0));
    }
  else
#endif
    {
      mtime = name_mtime (file->name);

      if (mtime == NONEXISTENT_MTIME && search && !file->ignore_vpath)
	{
	  /* If name_mtime failed, search VPATH.  */
	  const char *name = vpath_search (file->name, &mtime, NULL, NULL);
	  if (name
	      /* Last resort, is it a library (-lxxx)?  */
	      || (file->name[0] == '-' && file->name[1] == 'l'
		  && (name = library_search (file->name, &mtime)) != 0))
	    {
	      if (mtime != UNKNOWN_MTIME)
		/* vpath_search and library_search store UNKNOWN_MTIME
		   if they didn't need to do a stat call for their work.  */
		file->last_mtime = mtime;

              /* If we found it in VPATH, see if it's in GPATH too; if so,
                 change the name right now; if not, defer until after the
                 dependencies are updated. */
              if (gpath_search (name, strlen(name) - strlen(file->name) - 1))
                {
                  rename_file (file, name);
                  check_renamed (file);
                  return file_mtime (file);
                }

	      rehash_file (file, name);
	      check_renamed (file);
              /* If the result of a vpath search is -o or -W, preserve it.
                 Otherwise, find the mtime of the resulting file.  */
              if (mtime != OLD_MTIME && mtime != NEW_MTIME)
                mtime = name_mtime (name);
	    }
	}
    }

  /* Files can have bogus timestamps that nothing newly made will be
     "newer" than.  Updating their dependents could just result in loops.
     So notify the user of the anomaly with a warning.

     We only need to do this once, for now. */

  if (!clock_skew_detected
      && mtime != NONEXISTENT_MTIME && mtime != NEW_MTIME
      && !file->updated)
    {
      static FILE_TIMESTAMP adjusted_now;

      FILE_TIMESTAMP adjusted_mtime = mtime;

#if defined(WINDOWS32) || defined(__MSDOS__)
      /* Experimentation has shown that FAT filesystems can set file times
         up to 3 seconds into the future!  Play it safe.  */

#define FAT_ADJ_OFFSET  (FILE_TIMESTAMP) 3

      FILE_TIMESTAMP adjustment = FAT_ADJ_OFFSET << FILE_TIMESTAMP_LO_BITS;
      if (ORDINARY_MTIME_MIN + adjustment <= adjusted_mtime)
        adjusted_mtime -= adjustment;
#elif defined(__EMX__)
      /* FAT filesystems round time to the nearest even second!
         Allow for any file (NTFS or FAT) to perhaps suffer from this
         brain damage.  */
      FILE_TIMESTAMP adjustment = (((FILE_TIMESTAMP_S (adjusted_mtime) & 1) == 0
                     && FILE_TIMESTAMP_NS (adjusted_mtime) == 0)
                    ? (FILE_TIMESTAMP) 1 << FILE_TIMESTAMP_LO_BITS
                    : 0);
#endif

      /* If the file's time appears to be in the future, update our
         concept of the present and try once more.  */
      if (adjusted_now < adjusted_mtime)
        {
          int resolution;
          FILE_TIMESTAMP now = file_timestamp_now (&resolution);
          adjusted_now = now + (resolution - 1);
          if (adjusted_now < adjusted_mtime)
            {
#ifdef NO_FLOAT
              error (NILF, _("Warning: File '%s' has modification time in the future"),
                     file->name);
#else
              double from_now =
                (FILE_TIMESTAMP_S (mtime) - FILE_TIMESTAMP_S (now)
                 + ((FILE_TIMESTAMP_NS (mtime) - FILE_TIMESTAMP_NS (now))
                    / 1e9));
              char from_now_string[100];

              if (from_now >= 99 && from_now <= ULONG_MAX)
                sprintf (from_now_string, "%lu", (unsigned long) from_now);
              else
                sprintf (from_now_string, "%.2g", from_now);
              error (NILF, _("Warning: File '%s' has modification time %s s in the future"),
                     file->name, from_now_string);
#endif
              clock_skew_detected = 1;
            }
        }
    }

  /* Store the mtime into all the entries for this file.  */
  if (file->double_colon)
    file = file->double_colon;

  do
    {
      /* If this file is not implicit but it is intermediate then it was
	 made so by the .INTERMEDIATE target.  If this file has never
	 been built by us but was found now, it existed before make
	 started.  So, turn off the intermediate bit so make doesn't
	 delete it, since it didn't create it.  */
      if (mtime != NONEXISTENT_MTIME && file->command_state == cs_not_started
	  && file->command_state == cs_not_started
	  && !file->tried_implicit && file->intermediate)
	file->intermediate = 0;

      file->last_mtime = mtime;
      file = file->prev;
    }
  while (file != 0);

  return mtime;
}