Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/flock.cc')
-rw-r--r--winsup/cygwin/flock.cc291
1 files changed, 254 insertions, 37 deletions
diff --git a/winsup/cygwin/flock.cc b/winsup/cygwin/flock.cc
index 0a2ff9ea2..c9d7eb6ea 100644
--- a/winsup/cygwin/flock.cc
+++ b/winsup/cygwin/flock.cc
@@ -1,6 +1,6 @@
/* flock.cc. NT specific implementation of advisory file locking.
- Copyright 2003, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc.
+ Copyright 2003, 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc.
This file is part of Cygwin.
@@ -170,7 +170,7 @@ allow_others_to_sync ()
MAX_PROCESS_SD_SIZE, &len);
if (!NT_SUCCESS (status))
{
- debug_printf ("NtQuerySecurityObject: %p", status);
+ debug_printf ("NtQuerySecurityObject: %y", status);
return;
}
/* Create a valid dacl pointer and set its size to be as big as
@@ -197,14 +197,14 @@ allow_others_to_sync ()
well_known_world_sid);
if (!NT_SUCCESS (status))
{
- debug_printf ("RtlAddAccessAllowedAce: %p", status);
+ debug_printf ("RtlAddAccessAllowedAce: %y", status);
return;
}
/* Set the size of the DACL correctly. */
status = RtlFirstFreeAce (dacl, &ace);
if (!NT_SUCCESS (status))
{
- debug_printf ("RtlFirstFreeAce: %p", status);
+ debug_printf ("RtlFirstFreeAce: %y", status);
return;
}
dacl->AclSize = (char *) ace - (char *) dacl;
@@ -212,7 +212,7 @@ allow_others_to_sync ()
status = NtSetSecurityObject (NtCurrentProcess (), DACL_SECURITY_INFORMATION, sd);
if (!NT_SUCCESS (status))
{
- debug_printf ("NtSetSecurityObject: %p", status);
+ debug_printf ("NtSetSecurityObject: %y", status);
return;
}
done = true;
@@ -228,7 +228,7 @@ get_obj_handle_count (HANDLE h)
status = NtQueryObject (h, ObjectBasicInformation, &obi, sizeof obi, NULL);
if (!NT_SUCCESS (status))
- debug_printf ("NtQueryObject: %p\n", status);
+ debug_printf ("NtQueryObject: %y", status);
else
hdl_cnt = obi.HandleCount;
return hdl_cnt;
@@ -248,9 +248,9 @@ class lockf_t
public:
uint16_t lf_flags; /* Semantics: F_POSIX, F_FLOCK, F_WAIT */
uint16_t lf_type; /* Lock type: F_RDLCK, F_WRLCK */
- _off64_t lf_start; /* Byte # of the start of the lock */
- _off64_t lf_end; /* Byte # of the end of the lock (-1=EOF) */
- int64_t lf_id; /* Cygwin PID for POSIX locks, a unique id per
+ off_t lf_start; /* Byte # of the start of the lock */
+ off_t lf_end; /* Byte # of the end of the lock (-1=EOF) */
+ int64_t lf_id; /* Cygwin PID for POSIX locks, a unique id per
file table entry for BSD flock locks. */
DWORD lf_wid; /* Win PID of the resource holding the lock */
uint16_t lf_ver; /* Version number of the lock. If a released
@@ -268,7 +268,7 @@ class lockf_t
lf_next (NULL), lf_obj (NULL)
{}
lockf_t (class inode_t *node, class lockf_t **head,
- short flags, short type, _off64_t start, _off64_t end,
+ short flags, short type, off_t start, off_t end,
long long id, DWORD wid, uint16_t ver)
: lf_flags (flags), lf_type (type), lf_start (start), lf_end (end),
lf_id (id), lf_wid (wid), lf_ver (ver), lf_head (head), lf_inode (node),
@@ -308,8 +308,8 @@ class inode_t
lockf_t *i_lockf; /* List of locks of this process. */
lockf_t *i_all_lf; /* Temp list of all locks for this file. */
- __dev32_t i_dev; /* Device ID */
- __ino64_t i_ino; /* inode number */
+ dev_t i_dev; /* Device ID */
+ ino_t i_ino; /* inode number */
private:
HANDLE i_dir;
@@ -317,7 +317,7 @@ class inode_t
uint32_t i_cnt; /* # of threads referencing this instance. */
public:
- inode_t (__dev32_t dev, __ino64_t ino);
+ inode_t (dev_t dev, ino_t ino);
~inode_t ();
void *operator new (size_t size)
@@ -325,7 +325,7 @@ class inode_t
void operator delete (void *p)
{ cfree (p); }
- static inode_t *get (__dev32_t dev, __ino64_t ino,
+ static inode_t *get (dev_t dev, ino_t ino,
bool create_if_missing, bool lock);
void LOCK () { WaitForSingleObject (i_mtx, INFINITE); }
@@ -482,7 +482,7 @@ fixup_lockf_after_exec ()
file. The file is specified by the device and inode_t number. If inode_t
doesn't exist, create it. */
inode_t *
-inode_t::get (__dev32_t dev, __ino64_t ino, bool create_if_missing, bool lock)
+inode_t::get (dev_t dev, ino_t ino, bool create_if_missing, bool lock)
{
inode_t *node;
@@ -504,7 +504,7 @@ inode_t::get (__dev32_t dev, __ino64_t ino, bool create_if_missing, bool lock)
return node;
}
-inode_t::inode_t (__dev32_t dev, __ino64_t ino)
+inode_t::inode_t (dev_t dev, ino_t ino)
: i_lockf (NULL), i_all_lf (NULL), i_dev (dev), i_ino (ino), i_cnt (0L)
{
HANDLE parent_dir;
@@ -522,14 +522,14 @@ inode_t::inode_t (__dev32_t dev, __ino64_t ino)
parent_dir, everyone_sd (FLOCK_INODE_DIR_ACCESS));
status = NtCreateDirectoryObject (&i_dir, FLOCK_INODE_DIR_ACCESS, &attr);
if (!NT_SUCCESS (status))
- api_fatal ("NtCreateDirectoryObject(inode): %p", status);
+ api_fatal ("NtCreateDirectoryObject(inode): %y", status);
/* Create a mutex object in the file specific dir, which is used for
access synchronization on the dir and its objects. */
InitializeObjectAttributes (&attr, &ro_u_mtx, OBJ_INHERIT | OBJ_OPENIF, i_dir,
everyone_sd (CYG_MUTANT_ACCESS));
status = NtCreateMutant (&i_mtx, CYG_MUTANT_ACCESS, &attr, FALSE);
if (!NT_SUCCESS (status))
- api_fatal ("NtCreateMutant(inode): %p", status);
+ api_fatal ("NtCreateMutant(inode): %y", status);
}
/* Enumerate all lock event objects for this file and create a lockf_t
@@ -554,10 +554,10 @@ lockf_t::from_obj_name (inode_t *node, lockf_t **head, const wchar_t *name)
lf_type = wcstol (endptr + 1, &endptr, 16);
if ((lf_type != F_RDLCK && lf_type != F_WRLCK) || !endptr || *endptr != L'-')
return false;
- lf_start = (_off64_t) wcstoull (endptr + 1, &endptr, 16);
+ lf_start = (off_t) wcstoull (endptr + 1, &endptr, 16);
if (lf_start < 0 || !endptr || *endptr != L'-')
return false;
- lf_end = (_off64_t) wcstoull (endptr + 1, &endptr, 16);
+ lf_end = (off_t) wcstoull (endptr + 1, &endptr, 16);
if (lf_end < -1LL
|| (lf_end > 0 && lf_end < lf_start)
|| !endptr || *endptr != L'-')
@@ -640,8 +640,8 @@ create_lock_in_parent (PVOID param)
OBJECT_NAME_INFORMATION *ntfn;
NTSTATUS status;
wchar_t *lockname, *inodename, *endptr;
- __dev32_t dev;
- __ino64_t ino;
+ dev_t dev;
+ ino_t ino;
inode_t *node;
lockf_t newlock, *lock;
int cnt;
@@ -753,7 +753,7 @@ lockf_t::create_lock_obj ()
if (!NT_SUCCESS (status))
{
if (status != STATUS_OBJECT_NAME_COLLISION)
- api_fatal ("NtCreateEvent(lock): %p", status);
+ api_fatal ("NtCreateEvent(lock): %y", status);
/* If we get a STATUS_OBJECT_NAME_COLLISION, the event still exists
because some other process is waiting for it in lf_setlock.
If so, check the event's signal state. If we can't open it, it
@@ -764,7 +764,7 @@ lockf_t::create_lock_obj ()
if (open_lock_obj ())
{
if (!IsEventSignalled (lf_obj))
- api_fatal ("NtCreateEvent(lock): %p", status);
+ api_fatal ("NtCreateEvent(lock): %y", status);
close_lock_obj ();
/* Increment the lf_ver field until we have no collision. */
++lf_ver;
@@ -910,15 +910,25 @@ static int maxlockdepth = MAXDEPTH;
static int lf_clearlock (lockf_t *, lockf_t **, HANDLE);
static int lf_findoverlap (lockf_t *, lockf_t *, int, lockf_t ***, lockf_t **);
static lockf_t *lf_getblock (lockf_t *, inode_t *node);
-static int lf_getlock (lockf_t *, inode_t *, struct __flock64 *);
+static int lf_getlock (lockf_t *, inode_t *, struct flock *);
static int lf_setlock (lockf_t *, inode_t *, lockf_t **, HANDLE);
static void lf_split (lockf_t *, lockf_t *, lockf_t **);
static void lf_wakelock (lockf_t *, HANDLE);
+/* This is the fcntl advisory lock implementation. For the implementation
+ of mandatory locks using the Windows mandatory locking functions, see the
+ fhandler_disk_file::mand_lock method at the end of this file. */
int
-fhandler_disk_file::lock (int a_op, struct __flock64 *fl)
+fhandler_base::lock (int, struct flock *)
{
- _off64_t start, end, oadd;
+ set_errno (EINVAL);
+ return -1;
+}
+
+int
+fhandler_disk_file::lock (int a_op, struct flock *fl)
+{
+ off_t start, end, oadd;
int error = 0;
short a_flags = fl->l_type & (F_POSIX | F_FLOCK);
@@ -1499,7 +1509,7 @@ lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl)
* and if so return its process identifier.
*/
static int
-lf_getlock (lockf_t *lock, inode_t *node, struct __flock64 *fl)
+lf_getlock (lockf_t *lock, inode_t *node, struct flock *fl)
{
lockf_t *block;
tmp_pathbuf tp;
@@ -1577,7 +1587,7 @@ static int
lf_findoverlap (lockf_t *lf, lockf_t *lock, int type, lockf_t ***prev,
lockf_t **overlap)
{
- _off64_t start, end;
+ off_t start, end;
*overlap = lf;
if (lf == NOLOCKF)
@@ -1716,7 +1726,7 @@ flock (int fd, int operation)
{
int res = -1;
int cmd;
- struct __flock64 fl = { 0, SEEK_SET, 0, 0, 0 };
+ struct flock fl = { 0, SEEK_SET, 0, 0, 0 };
myfault efault;
if (efault.faulted (EFAULT))
@@ -1730,19 +1740,22 @@ flock (int fd, int operation)
switch (operation & (~LOCK_NB))
{
case LOCK_EX:
- fl.l_type = F_WRLCK | F_FLOCK;
+ fl.l_type = F_WRLCK;
break;
case LOCK_SH:
- fl.l_type = F_RDLCK | F_FLOCK;
+ fl.l_type = F_RDLCK;
break;
case LOCK_UN:
- fl.l_type = F_UNLCK | F_FLOCK;
+ fl.l_type = F_UNLCK;
break;
default:
set_errno (EINVAL);
goto done;
}
- res = cfd->lock (cmd, &fl);
+ if (!cfd->mandatory_locking ())
+ fl.l_type |= F_FLOCK;
+ res = cfd->mandatory_locking () ? cfd->mand_lock (cmd, &fl)
+ : cfd->lock (cmd, &fl);
if ((res == -1) && ((get_errno () == EAGAIN) || (get_errno () == EACCES)))
set_errno (EWOULDBLOCK);
done:
@@ -1751,11 +1764,11 @@ done:
}
extern "C" int
-lockf (int filedes, int function, _off64_t size)
+lockf (int filedes, int function, off_t size)
{
int res = -1;
int cmd;
- struct __flock64 fl;
+ struct flock fl;
pthread_testcancel ();
@@ -1800,8 +1813,212 @@ lockf (int filedes, int function, _off64_t size)
goto done;
/* NOTREACHED */
}
- res = cfd->lock (cmd, &fl);
+ res = cfd->mandatory_locking () ? cfd->mand_lock (cmd, &fl)
+ : cfd->lock (cmd, &fl);
done:
syscall_printf ("%R = lockf(%d, %d, %D)", res, filedes, function, size);
return res;
}
+
+/* This is the fcntl lock implementation for mandatory locks using the
+ Windows mandatory locking functions. For the UNIX-like advisory locking
+ implementation see the fhandler_disk_file::lock method earlier in this
+ file. */
+struct lock_parms {
+ HANDLE h;
+ PIO_STATUS_BLOCK pio;
+ PLARGE_INTEGER poff;
+ PLARGE_INTEGER plen;
+ BOOL type;
+ NTSTATUS status;
+};
+
+static DWORD WINAPI
+blocking_lock_thr (LPVOID param)
+{
+ struct lock_parms *lp = (struct lock_parms *) param;
+ lp->status = NtLockFile (lp->h, NULL, NULL, NULL, lp->pio, lp->poff,
+ lp->plen, 0, FALSE, lp->type);
+ return 0;
+}
+
+int
+fhandler_base::mand_lock (int, struct flock *)
+{
+ set_errno (EINVAL);
+ return -1;
+}
+
+int
+fhandler_disk_file::mand_lock (int a_op, struct flock *fl)
+{
+ NTSTATUS status;
+ IO_STATUS_BLOCK io;
+ FILE_POSITION_INFORMATION fpi;
+ FILE_STANDARD_INFORMATION fsi;
+ off_t startpos;
+ LARGE_INTEGER offset;
+ LARGE_INTEGER length;
+
+ /* Calculate where to start from, then adjust this by fl->l_start. */
+ switch (fl->l_whence)
+ {
+ case SEEK_SET:
+ startpos = 0;
+ break;
+ case SEEK_CUR:
+ status = NtQueryInformationFile (get_handle (), &io, &fpi, sizeof fpi,
+ FilePositionInformation);
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ return -1;
+ }
+ startpos = fpi.CurrentByteOffset.QuadPart;
+ break;
+ case SEEK_END:
+ status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi,
+ FileStandardInformation);
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ return -1;
+ }
+ startpos = fsi.EndOfFile.QuadPart;
+ break;
+ default:
+ set_errno (EINVAL);
+ return -1;
+ }
+ /* Adjust start and length until they make sense. */
+ offset.QuadPart = startpos + fl->l_start;
+ if (fl->l_len < 0)
+ {
+ offset.QuadPart -= fl->l_len;
+ length.QuadPart = -fl->l_len;
+ }
+ else
+ length.QuadPart = fl->l_len;
+ if (offset.QuadPart < 0)
+ {
+ length.QuadPart -= -offset.QuadPart;
+ if (length.QuadPart <= 0)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ offset.QuadPart = 0;
+ }
+ /* Special case if len == 0. For POSIX this means lock to the end of
+ the entire file, even when file grows later. */
+ if (length.QuadPart == 0)
+ length.QuadPart = UINT64_MAX;
+ /* Action! */
+ if (fl->l_type == F_UNLCK)
+ {
+ status = NtUnlockFile (get_handle (), &io, &offset, &length, 0);
+ if (status == STATUS_RANGE_NOT_LOCKED) /* Not an error */
+ status = STATUS_SUCCESS;
+ }
+ else if (a_op == F_SETLKW)
+ {
+ /* We open file handles synchronously. To allow asynchronous operation
+ the file locking functions require a file handle opened in asynchronous
+ mode. Since Windows locks are per-process/per-file object, we can't
+ open another handle asynchrously and lock/unlock using that handle:
+ The original file handle would not have placed the lock and would be
+ restricted by the lock like any other file handle.
+ So, what we do here is to start a thread which calls the potentially
+ blocking NtLockFile call. Then we wait for thread completion in an
+ interruptible fashion. */
+ OBJECT_ATTRIBUTES attr;
+ HANDLE evt;
+ struct lock_parms lp = { get_handle (), &io, &offset, &length,
+ fl->l_type == F_WRLCK, 0 };
+ cygthread *thr = NULL;
+
+ InitializeObjectAttributes (&attr, NULL, 0, NULL, NULL);
+ status = NtCreateEvent (&evt, EVENT_ALL_ACCESS, &attr,
+ NotificationEvent, FALSE);
+ if (evt)
+ thr = new cygthread (blocking_lock_thr, &lp, "blk_lock", evt);
+ if (!thr)
+ {
+ /* Thread creation failed. Fall back to blocking lock call. */
+ if (evt)
+ NtClose (evt);
+ status = NtLockFile (get_handle (), NULL, NULL, NULL, &io, &offset,
+ &length, 0, FALSE, fl->l_type == F_WRLCK);
+ }
+ else
+ {
+ /* F_SETLKW and lock cannot be established. Wait until the lock can
+ be established, or a signal request arrived. We deliberately
+ don't handle thread cancel requests here. */
+ DWORD wait_res = cygwait (evt, INFINITE, cw_sig | cw_sig_eintr);
+ NtClose (evt);
+ switch (wait_res)
+ {
+ case WAIT_OBJECT_0:
+ /* Fetch completion status. */
+ status = lp.status;
+ thr->detach ();
+ break;
+ default:
+ /* Signal arrived. */
+ /* Starting with Vista, CancelSynchronousIo works, and we wait
+ for the thread to exit. lp.status will be either
+ STATUS_SUCCESS, or STATUS_CANCELLED. We only call
+ NtUnlockFile in the first case.
+ Prior to Vista, CancelSynchronousIo doesn't exist, so we
+ terminated the thread and always call NtUnlockFile since
+ lp.status was 0 to begin with. */
+ if (CancelSynchronousIo (thr->thread_handle ()))
+ thr->detach ();
+ else
+ thr->terminate_thread ();
+ if (NT_SUCCESS (lp.status))
+ NtUnlockFile (get_handle (), &io, &offset, &length, 0);
+ /* Per SUSv4: If a signal is received while fcntl is waiting,
+ fcntl shall be interrupted. Upon return from the signal
+ handler, fcntl shall return -1 with errno set to EINTR,
+ and the lock operation shall not be done. */
+ _my_tls.call_signal_handler ();
+ set_errno (EINTR);
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ status = NtLockFile (get_handle (), NULL, NULL, NULL, &io, &offset,
+ &length, 0, TRUE, fl->l_type == F_WRLCK);
+ if (a_op == F_GETLK)
+ {
+ /* This is non-atomic, but there's no other way on Windows to detect
+ if another lock is blocking our lock, other than trying to place
+ the lock, and then having to unlock it again. */
+ if (NT_SUCCESS (status))
+ {
+ NtUnlockFile (get_handle (), &io, &offset, &length, 0);
+ fl->l_type = F_UNLCK;
+ }
+ else
+ {
+ /* FAKE! FAKE! FAKE! */
+ fl->l_type = F_WRLCK;
+ fl->l_whence = SEEK_SET;
+ fl->l_start = offset.QuadPart;
+ fl->l_len = length.QuadPart;
+ fl->l_pid = (pid_t) -1;
+ }
+ status = STATUS_SUCCESS;
+ }
+ }
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ return -1;
+ }
+ return 0;
+}