コード例 #1
0
TEST(UNISTD_TEST, lockf_partial_with_child) {
  constexpr off64_t file_size = 32*1024LL;

  TemporaryFile tf;
  ASSERT_EQ(0, ftruncate(tf.fd, file_size));

  // Lock the first half of the file.
  ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
  ASSERT_EQ(0, lockf64(tf.fd, F_LOCK, file_size/2));

  // Fork a child process.
  pid_t pid = fork();
  ASSERT_NE(-1, pid);
  if (pid == 0) {
    // Check that the child can lock the other half.
    ASSERT_EQ(file_size/2, lseek64(tf.fd, file_size/2, SEEK_SET));
    ASSERT_EQ(0, lockf64(tf.fd, F_TLOCK, file_size/2));
    // Check that the child cannot lock the first half.
    ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
    ASSERT_EQ(-1, lockf64(tf.fd, F_TEST, file_size/2));
    ASSERT_EQ(EACCES, errno);
    // Check also that it reports itself as locked.
    ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
    ASSERT_EQ(-1, lockf64(tf.fd, F_TEST, file_size/2));
    ASSERT_EQ(EACCES, errno);
    _exit(0);
  }
  AssertChildExited(pid, 0);

  // The second half was locked by the child, but the lock disappeared
  // when the process exited, so check it can be locked now.
  ASSERT_EQ(file_size/2, lseek64(tf.fd, file_size/2, SEEK_SET));
  ASSERT_EQ(0, lockf64(tf.fd, F_TLOCK, file_size/2));
}
コード例 #2
0
TEST(UNISTD_TEST, lockf_with_child) {
  constexpr off64_t file_size = 32*1024LL;

  TemporaryFile tf;
  ASSERT_EQ(0, ftruncate(tf.fd, file_size));

  // Lock everything.
  ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
  ASSERT_EQ(0, lockf64(tf.fd, F_LOCK, file_size));

  // Fork a child process
  pid_t pid = fork();
  ASSERT_NE(-1, pid);
  if (pid == 0) {
    // Check that the child cannot lock the file.
    ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
    ASSERT_EQ(-1, lockf64(tf.fd, F_TLOCK, file_size));
    ASSERT_EQ(EAGAIN, errno);
    // Check also that it reports itself as locked.
    ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
    ASSERT_EQ(-1, lockf64(tf.fd, F_TEST, file_size));
    ASSERT_EQ(EACCES, errno);
    _exit(0);
  }
  AssertChildExited(pid, 0);
}
コード例 #3
0
TEST(UNISTD_TEST, lockf_negative) {
  constexpr off64_t file_size = 32*1024LL;

  TemporaryFile tf;
  ASSERT_EQ(0, ftruncate(tf.fd, file_size));

  // Lock everything, but specifying the range in reverse.
  ASSERT_EQ(file_size, lseek64(tf.fd, file_size, SEEK_SET));
  ASSERT_EQ(0, lockf64(tf.fd, F_LOCK, -file_size));

  // Check that it's locked.
  ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
  ASSERT_EQ(0, lockf64(tf.fd, F_TEST, file_size));
}
コード例 #4
0
ファイル: xbase64.cpp プロジェクト: utech/UtechLib
xbShort xbXBase::LockFile( int fn, xbShort LockType, xbOffT lockLen )
{
  xbShort cmd, rc;
  xbShort tries = 0;
  
/* convert cross platform xbase lock type to unix lock type */  
  if( LockType == XB_UNLOCK ) 
    cmd = F_ULOCK;
  else if( LockType == XB_LOCK || LockType == XB_LOCK_HOLD )
    cmd = F_TLOCK;
  else
    return XB_INVALID_LOCK_OPTION;

/* do the actual lock */
  do{     
    #ifdef _LARGEFILE64_SOURCE
      rc = lockf64( fn, cmd, lockLen );
    #else
      rc = lockf( fn, cmd, lockLen );
    #endif
    if( rc == -1 && errno != EINTR ){    
      tries++; 
      sleep(1);
    }
  } while( rc == -1 && tries < GetLockRetryCount());
    
  if( rc )
    return XB_LOCK_FAILED;
    
  return XB_NO_ERROR;
}
コード例 #5
0
TEST(UNISTD_TEST, lockf_zero) {
  constexpr off64_t file_size = 32*1024LL;

  TemporaryFile tf;
  ASSERT_EQ(0, ftruncate(tf.fd, file_size));

  // Lock everything by specifying a size of 0 (meaning "to the end, even if it changes").
  ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
  ASSERT_EQ(0, lockf64(tf.fd, F_LOCK, 0));

  // Check that it's locked.
  ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
  ASSERT_EQ(0, lockf64(tf.fd, F_TEST, file_size));

  // Move the end.
  ASSERT_EQ(0, ftruncate(tf.fd, 2*file_size));

  // Check that the new section is locked too.
  ASSERT_EQ(file_size, lseek64(tf.fd, file_size, SEEK_SET));
  ASSERT_EQ(0, lockf64(tf.fd, F_TEST, 2*file_size));
}
コード例 #6
0
TEST(UNISTD_TEST, lockf_smoke) {
  constexpr off64_t file_size = 32*1024LL;

  TemporaryFile tf;
  ASSERT_EQ(0, ftruncate(tf.fd, file_size));

  // Lock everything.
  ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
  ASSERT_EQ(0, lockf64(tf.fd, F_LOCK, file_size));

  // Try-lock everything, this should succeed too.
  ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
  ASSERT_EQ(0, lockf64(tf.fd, F_TLOCK, file_size));

  // Check status.
  ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
  ASSERT_EQ(0, lockf64(tf.fd, F_TEST, file_size));

  // Unlock file.
  ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
  ASSERT_EQ(0, lockf64(tf.fd, F_ULOCK, file_size));
}
コード例 #7
0
void
open_archive (struct locarhandle *ah, bool readonly)
{
  struct stat64 st;
  struct stat64 st2;
  int fd;
  struct locarhead head;
  int retry = 0;
  size_t prefix_len = output_prefix ? strlen (output_prefix) : 0;
  char archivefname[prefix_len + sizeof (ARCHIVE_NAME)];

  if (output_prefix)
    memcpy (archivefname, output_prefix, prefix_len);
  strcpy (archivefname + prefix_len, ARCHIVE_NAME);

  while (1)
    {
      /* Open the archive.  We must have exclusive write access.  */
      fd = open64 (archivefname, readonly ? O_RDONLY : O_RDWR);
      if (fd == -1)
	{
	  /* Maybe the file does not yet exist.  */
	  if (errno == ENOENT)
	    {
	      if (readonly)
		{
		  static const struct locarhead nullhead =
		    {
		      .namehash_used = 0,
		      .namehash_offset = 0,
		      .namehash_size = 0
		    };

		  ah->addr = (void *) &nullhead;
		  ah->fd = -1;
		}
	      else
		create_archive (archivefname, ah);

	      return;
	    }
	  else
	    error (EXIT_FAILURE, errno, _("cannot open locale archive \"%s\""),
		   archivefname);
	}

      if (fstat64 (fd, &st) < 0)
	error (EXIT_FAILURE, errno, _("cannot stat locale archive \"%s\""),
	       archivefname);

      if (!readonly && lockf64 (fd, F_LOCK, sizeof (struct locarhead)) == -1)
	{
	  close (fd);

	  if (retry++ < max_locarchive_open_retry)
	    {
	      struct timespec req;

	      /* Wait for a bit.  */
	      req.tv_sec = 0;
	      req.tv_nsec = 1000000 * (random () % 500 + 1);
	      (void) nanosleep (&req, NULL);

	      continue;
	    }

	  error (EXIT_FAILURE, errno, _("cannot lock locale archive \"%s\""),
		 archivefname);
	}

      /* One more check.  Maybe another process replaced the archive file
	 with a new, larger one since we opened the file.  */
      if (stat64 (archivefname, &st2) == -1
	  || st.st_dev != st2.st_dev
	  || st.st_ino != st2.st_ino)
	{
	  (void) lockf64 (fd, F_ULOCK, sizeof (struct locarhead));
	  close (fd);
	  continue;
	}

      /* Leave the loop.  */
      break;
    }
コード例 #8
0
static void
enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
{
  struct stat64 st;
  int fd;
  struct locarhead newhead;
  size_t total;
  void *p;
  unsigned int cnt, loccnt;
  struct namehashent *oldnamehashtab;
  struct locrecent *oldlocrectab;
  struct locarhandle new_ah;
  struct oldlocrecent *oldlocrecarray;
  size_t prefix_len = output_prefix ? strlen (output_prefix) : 0;
  char archivefname[prefix_len + sizeof (ARCHIVE_NAME)];
  char fname[prefix_len + sizeof (ARCHIVE_NAME) + sizeof (".XXXXXX") - 1];

  if (output_prefix)
    memcpy (archivefname, output_prefix, prefix_len);
  strcpy (archivefname + prefix_len, ARCHIVE_NAME);
  strcpy (stpcpy (fname, archivefname), ".XXXXXX");

  /* Not all of the old file has to be mapped.  Change this now this
     we will have to access the whole content.  */
  if (fstat64 (ah->fd, &st) != 0)
  enomap:
    error (EXIT_FAILURE, errno, _("cannot map locale archive file"));

  if (st.st_size < ah->reserved)
    ah->addr = mmap64 (ah->addr, st.st_size, PROT_READ | PROT_WRITE,
		       MAP_SHARED | MAP_FIXED, ah->fd, 0);
  else
    {
      munmap (ah->addr, ah->reserved);
      ah->addr = mmap64 (NULL, st.st_size, PROT_READ | PROT_WRITE,
			 MAP_SHARED, ah->fd, 0);
      ah->reserved = st.st_size;
      head = ah->addr;
    }
  if (ah->addr == MAP_FAILED)
    goto enomap;
  ah->mmaped = st.st_size;

  /* Create a temporary file in the correct directory.  */
  fd = mkstemp (fname);
  if (fd == -1)
    error (EXIT_FAILURE, errno, _("cannot create temporary file"));

  /* Copy the existing head information.  */
  newhead = *head;

  /* Create the new archive header.  The sizes of the various tables
     should be double from what is currently used.  */
  newhead.namehash_size = MAX (next_prime (2 * newhead.namehash_used),
			       newhead.namehash_size);
  if (verbose)
    printf ("name: size: %u, used: %d, new: size: %u\n",
	    head->namehash_size, head->namehash_used, newhead.namehash_size);

  newhead.string_offset = (newhead.namehash_offset
			   + (newhead.namehash_size
			      * sizeof (struct namehashent)));
  /* Keep the string table size aligned to 4 bytes, so that
     all the struct { uint32_t } types following are happy.  */
  newhead.string_size = MAX ((2 * newhead.string_used + 3) & -4,
			     newhead.string_size);

  newhead.locrectab_offset = newhead.string_offset + newhead.string_size;
  newhead.locrectab_size = MAX (2 * newhead.locrectab_used,
				newhead.locrectab_size);

  newhead.sumhash_offset = (newhead.locrectab_offset
			    + (newhead.locrectab_size
			       * sizeof (struct locrecent)));
  newhead.sumhash_size = MAX (next_prime (2 * newhead.sumhash_used),
			      newhead.sumhash_size);

  total = (newhead.sumhash_offset
	   + newhead.sumhash_size * sizeof (struct sumhashent));

  /* The new file is empty now.  */
  newhead.namehash_used = 0;
  newhead.string_used = 0;
  newhead.locrectab_used = 0;
  newhead.sumhash_used = 0;

  /* Write out the header and create room for the other data structures.  */
  if (TEMP_FAILURE_RETRY (write (fd, &newhead, sizeof (newhead)))
      != sizeof (newhead))
    {
      int errval = errno;
      unlink (fname);
      error (EXIT_FAILURE, errval, _("cannot initialize archive file"));
    }

  if (ftruncate64 (fd, total) != 0)
    {
      int errval = errno;
      unlink (fname);
      error (EXIT_FAILURE, errval, _("cannot resize archive file"));
    }

  /* To prepare for enlargements of the mmaped area reserve some
     address space.  */
  size_t reserved = RESERVE_MMAP_SIZE;
  int xflags = 0;
  if (total < reserved
      && ((p = mmap64 (NULL, reserved, PROT_NONE, MAP_PRIVATE | MAP_ANON,
		       -1, 0)) != MAP_FAILED))
    xflags = MAP_FIXED;
  else
    {
      p = NULL;
      reserved = total;
    }

  /* Map the header and all the administration data structures.  */
  p = mmap64 (p, total, PROT_READ | PROT_WRITE, MAP_SHARED | xflags, fd, 0);
  if (p == MAP_FAILED)
    {
      int errval = errno;
      unlink (fname);
      error (EXIT_FAILURE, errval, _("cannot map archive header"));
    }

  /* Lock the new file.  */
  if (lockf64 (fd, F_LOCK, total) != 0)
    {
      int errval = errno;
      unlink (fname);
      error (EXIT_FAILURE, errval, _("cannot lock new archive"));
    }

  new_ah.mmaped = total;
  new_ah.addr = p;
  new_ah.fd = fd;
  new_ah.reserved = reserved;

  /* Walk through the hash name hash table to find out what data is
     still referenced and transfer it into the new file.  */
  oldnamehashtab = (struct namehashent *) ((char *) ah->addr
					   + head->namehash_offset);
  oldlocrectab = (struct locrecent *) ((char *) ah->addr
				       + head->locrectab_offset);

  /* Sort the old locrec table in order of data position.  */
  oldlocrecarray = alloca (sizeof (*oldlocrecarray) * head->namehash_size);
  for (cnt = 0, loccnt = 0; cnt < head->namehash_size; ++cnt)
    if (oldnamehashtab[cnt].locrec_offset != 0)
      {
	oldlocrecarray[loccnt].cnt = cnt;
	oldlocrecarray[loccnt++].locrec
	  = (struct locrecent *) ((char *) ah->addr
				  + oldnamehashtab[cnt].locrec_offset);
      }
  qsort (oldlocrecarray, loccnt, sizeof (struct oldlocrecent),
	 oldlocrecentcmp);

  uint32_t last_locrec_offset = 0;
  for (cnt = 0; cnt < loccnt; ++cnt)
    {
      /* Insert this entry in the new hash table.  */
      locale_data_t old_data;
      unsigned int idx;
      struct locrecent *oldlocrec = oldlocrecarray[cnt].locrec;

      for (idx = 0; idx < __LC_LAST; ++idx)
	if (idx != LC_ALL)
	  {
	    old_data[idx].size = oldlocrec->record[idx].len;
	    old_data[idx].addr
	      = ((char *) ah->addr + oldlocrec->record[idx].offset);

	    __md5_buffer (old_data[idx].addr, old_data[idx].size,
			  old_data[idx].sum);
	  }

      if (cnt > 0 && oldlocrecarray[cnt - 1].locrec == oldlocrec)
	{
	  const char *oldname
	    = ((char *) ah->addr
	       + oldnamehashtab[oldlocrecarray[cnt - 1].cnt].name_offset);

	  add_alias (&new_ah,
		     ((char *) ah->addr
		      + oldnamehashtab[oldlocrecarray[cnt].cnt].name_offset),
		     0, oldname, &last_locrec_offset);
	  continue;
	}

      last_locrec_offset =
	add_locale (&new_ah,
		    ((char *) ah->addr
		     + oldnamehashtab[oldlocrecarray[cnt].cnt].name_offset),
		    old_data, 0);
      if (last_locrec_offset == 0)
	error (EXIT_FAILURE, 0, _("cannot extend locale archive file"));
    }

  /* Make the file globally readable.  */
  if (fchmod (fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) == -1)
    {
      int errval = errno;
      unlink (fname);
      error (EXIT_FAILURE, errval,
	     _("cannot change mode of resized locale archive"));
    }

  /* Rename the new file.  */
  if (rename (fname, archivefname) != 0)
    {
      int errval = errno;
      unlink (fname);
      error (EXIT_FAILURE, errval, _("cannot rename new archive"));
    }

  /* Close the old file.  */
  close_archive (ah);

  /* Add the information for the new one.  */
  *ah = new_ah;
}