(root)/
tar-1.35/
gnu/
lseek.c
       1  /* An lseek() function that detects pipes.
       2     Copyright (C) 2007, 2009-2023 Free Software Foundation, Inc.
       3  
       4     This file is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU Lesser General Public License as
       6     published by the Free Software Foundation; either version 2.1 of the
       7     License, or (at your option) any later version.
       8  
       9     This file is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #include <config.h>
      18  
      19  /* Specification.  */
      20  #include <unistd.h>
      21  
      22  #if defined _WIN32 && ! defined __CYGWIN__
      23  /* Windows platforms.  */
      24  /* Get GetFileType.  */
      25  # include <windows.h>
      26  /* Get _get_osfhandle.  */
      27  # if GNULIB_MSVC_NOTHROW
      28  #  include "msvc-nothrow.h"
      29  # else
      30  #  include <io.h>
      31  # endif
      32  #else
      33  # include <sys/stat.h>
      34  #endif
      35  #include <errno.h>
      36  
      37  #undef lseek
      38  
      39  off_t
      40  rpl_lseek (int fd, off_t offset, int whence)
      41  {
      42  #if defined _WIN32 && ! defined __CYGWIN__
      43    /* mingw lseek mistakenly succeeds on pipes, sockets, and terminals.  */
      44    HANDLE h = (HANDLE) _get_osfhandle (fd);
      45    if (h == INVALID_HANDLE_VALUE)
      46      {
      47        errno = EBADF;
      48        return -1;
      49      }
      50    if (GetFileType (h) != FILE_TYPE_DISK)
      51      {
      52        errno = ESPIPE;
      53        return -1;
      54      }
      55  #elif defined __APPLE__ && defined __MACH__ && defined SEEK_DATA
      56    if (whence == SEEK_DATA)
      57      {
      58        /* If OFFSET points to data, macOS lseek+SEEK_DATA returns the
      59           start S of the first data region that begins *after* OFFSET,
      60           where the region from OFFSET to S consists of possibly-empty
      61           data followed by a possibly-empty hole.  To work around this
      62           portability glitch, check whether OFFSET is within data by
      63           using lseek+SEEK_HOLE, and if so return to OFFSET by using
      64           lseek+SEEK_SET.  Also, contrary to the macOS documentation,
      65           lseek+SEEK_HOLE can fail with ENXIO if there are no holes on
      66           or after OFFSET.  What a mess!  */
      67        off_t next_hole = lseek (fd, offset, SEEK_HOLE);
      68        if (next_hole < 0)
      69          return errno == ENXIO ? offset : next_hole;
      70        if (next_hole != offset)
      71          whence = SEEK_SET;
      72      }
      73  #else
      74    /* BeOS lseek mistakenly succeeds on pipes...  */
      75    struct stat statbuf;
      76    if (fstat (fd, &statbuf) < 0)
      77      return -1;
      78    if (!S_ISREG (statbuf.st_mode))
      79      {
      80        errno = ESPIPE;
      81        return -1;
      82      }
      83  #endif
      84  #if _GL_WINDOWS_64_BIT_OFF_T || (defined __MINGW32__ && defined _FILE_OFFSET_BITS && (_FILE_OFFSET_BITS == 64))
      85    return _lseeki64 (fd, offset, whence);
      86  #else
      87    return lseek (fd, offset, whence);
      88  #endif
      89  }