root/maint/gnulib/lib/flock.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. file_size
  2. do_lock
  3. do_unlock
  4. flock
  5. flock

   1 /* Emulate flock on platforms that lack it, primarily Windows and MinGW.
   2 
   3    This is derived from sqlite3 sources.
   4    https://www.sqlite.org/src/finfo?name=src/os_win.c
   5    https://www.sqlite.org/copyright.html
   6 
   7    Written by Richard W.M. Jones <rjones.at.redhat.com>
   8 
   9    Copyright (C) 2008-2021 Free Software Foundation, Inc.
  10 
  11    This library is free software; you can redistribute it and/or
  12    modify it under the terms of the GNU Lesser General Public
  13    License as published by the Free Software Foundation; either
  14    version 2.1 of the License, or (at your option) any later version.
  15 
  16    This library is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19    Lesser General Public License for more details.
  20 
  21    You should have received a copy of the GNU Lesser General Public License
  22    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  23 
  24 #include <config.h>
  25 #include <sys/file.h>
  26 
  27 #if defined _WIN32 && ! defined __CYGWIN__
  28 
  29 /* LockFileEx */
  30 # define WIN32_LEAN_AND_MEAN
  31 # include <windows.h>
  32 
  33 # include <errno.h>
  34 
  35 /* _get_osfhandle */
  36 # if GNULIB_MSVC_NOTHROW
  37 #  include "msvc-nothrow.h"
  38 # else
  39 #  include <io.h>
  40 # endif
  41 
  42 /* Determine the current size of a file.  Because the other braindead
  43  * APIs we'll call need lower/upper 32 bit pairs, keep the file size
  44  * like that too.
  45  */
  46 static BOOL
  47 file_size (HANDLE h, DWORD * lower, DWORD * upper)
     /* [previous][next][first][last][top][bottom][index][help] */
  48 {
  49   *lower = GetFileSize (h, upper);
  50   return 1;
  51 }
  52 
  53 /* LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. */
  54 # ifndef LOCKFILE_FAIL_IMMEDIATELY
  55 #  define LOCKFILE_FAIL_IMMEDIATELY 1
  56 # endif
  57 
  58 /* Acquire a lock. */
  59 static BOOL
  60 do_lock (HANDLE h, int non_blocking, int exclusive)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62   BOOL res;
  63   DWORD size_lower, size_upper;
  64   OVERLAPPED ovlp;
  65   int flags = 0;
  66 
  67   /* We're going to lock the whole file, so get the file size. */
  68   res = file_size (h, &size_lower, &size_upper);
  69   if (!res)
  70     return 0;
  71 
  72   /* Start offset is 0, and also zero the remaining members of this struct. */
  73   memset (&ovlp, 0, sizeof ovlp);
  74 
  75   if (non_blocking)
  76     flags |= LOCKFILE_FAIL_IMMEDIATELY;
  77   if (exclusive)
  78     flags |= LOCKFILE_EXCLUSIVE_LOCK;
  79 
  80   return LockFileEx (h, flags, 0, size_lower, size_upper, &ovlp);
  81 }
  82 
  83 /* Unlock reader or exclusive lock. */
  84 static BOOL
  85 do_unlock (HANDLE h)
     /* [previous][next][first][last][top][bottom][index][help] */
  86 {
  87   int res;
  88   DWORD size_lower, size_upper;
  89 
  90   res = file_size (h, &size_lower, &size_upper);
  91   if (!res)
  92     return 0;
  93 
  94   return UnlockFile (h, 0, 0, size_lower, size_upper);
  95 }
  96 
  97 /* Now our BSD-like flock operation. */
  98 int
  99 flock (int fd, int operation)
     /* [previous][next][first][last][top][bottom][index][help] */
 100 {
 101   HANDLE h = (HANDLE) _get_osfhandle (fd);
 102   DWORD res;
 103   int non_blocking;
 104 
 105   if (h == INVALID_HANDLE_VALUE)
 106     {
 107       errno = EBADF;
 108       return -1;
 109     }
 110 
 111   non_blocking = operation & LOCK_NB;
 112   operation &= ~LOCK_NB;
 113 
 114   switch (operation)
 115     {
 116     case LOCK_SH:
 117       res = do_lock (h, non_blocking, 0);
 118       break;
 119     case LOCK_EX:
 120       res = do_lock (h, non_blocking, 1);
 121       break;
 122     case LOCK_UN:
 123       res = do_unlock (h);
 124       break;
 125     default:
 126       errno = EINVAL;
 127       return -1;
 128     }
 129 
 130   /* Map Windows errors into Unix errnos.  As usual MSDN fails to
 131    * document the permissible error codes.
 132    */
 133   if (!res)
 134     {
 135       DWORD err = GetLastError ();
 136       switch (err)
 137         {
 138           /* This means someone else is holding a lock. */
 139         case ERROR_LOCK_VIOLATION:
 140           errno = EAGAIN;
 141           break;
 142 
 143           /* Out of memory. */
 144         case ERROR_NOT_ENOUGH_MEMORY:
 145           errno = ENOMEM;
 146           break;
 147 
 148         case ERROR_BAD_COMMAND:
 149           errno = EINVAL;
 150           break;
 151 
 152           /* Unlikely to be other errors, but at least don't lose the
 153            * error code.
 154            */
 155         default:
 156           errno = err;
 157         }
 158 
 159       return -1;
 160     }
 161 
 162   return 0;
 163 }
 164 
 165 #else /* !Windows */
 166 
 167 # ifdef HAVE_STRUCT_FLOCK_L_TYPE
 168 /* We know how to implement flock in terms of fcntl. */
 169 
 170 #  include <fcntl.h>
 171 
 172 #  ifdef HAVE_UNISTD_H
 173 #   include <unistd.h>
 174 #  endif
 175 
 176 #  include <errno.h>
 177 #  include <string.h>
 178 
 179 int
 180 flock (int fd, int operation)
     /* [previous][next][first][last][top][bottom][index][help] */
 181 {
 182   int cmd, r;
 183   struct flock fl;
 184 
 185   if (operation & LOCK_NB)
 186     cmd = F_SETLK;
 187   else
 188     cmd = F_SETLKW;
 189   operation &= ~LOCK_NB;
 190 
 191   memset (&fl, 0, sizeof fl);
 192   fl.l_whence = SEEK_SET;
 193   /* l_start & l_len are 0, which as a special case means "whole file". */
 194 
 195   switch (operation)
 196     {
 197     case LOCK_SH:
 198       fl.l_type = F_RDLCK;
 199       break;
 200     case LOCK_EX:
 201       fl.l_type = F_WRLCK;
 202       break;
 203     case LOCK_UN:
 204       fl.l_type = F_UNLCK;
 205       break;
 206     default:
 207       errno = EINVAL;
 208       return -1;
 209     }
 210 
 211   r = fcntl (fd, cmd, &fl);
 212   if (r == -1 && errno == EACCES)
 213     errno = EAGAIN;
 214 
 215   return r;
 216 }
 217 
 218 # else /* !HAVE_STRUCT_FLOCK_L_TYPE */
 219 
 220 #  error "This platform lacks flock function, and Gnulib doesn't provide a replacement. This is a bug in Gnulib."
 221 
 222 # endif /* !HAVE_STRUCT_FLOCK_L_TYPE */
 223 
 224 #endif /* !Windows */

/* [previous][next][first][last][top][bottom][index][help] */