Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
ce613493
Commit
ce613493
authored
Mar 18, 2003
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implemented file locking functions (partly based on my old Corel
patch). Added a few regression tests.
parent
6fb02776
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
559 additions
and
269 deletions
+559
-269
file.c
dlls/kernel/tests/file.c
+74
-0
file.c
files/file.c
+70
-237
winbase.h
include/winbase.h
+2
-0
server_protocol.h
include/wine/server_protocol.h
+5
-1
fd.c
server/fd.c
+373
-11
file.c
server/file.c
+8
-18
file.h
server/file.h
+4
-0
list.h
server/list.h
+6
-0
process.c
server/process.c
+1
-0
process.h
server/process.h
+1
-0
protocol.def
server/protocol.def
+5
-0
trace.c
server/trace.c
+10
-2
No files found.
dlls/kernel/tests/file.c
View file @
ce613493
...
...
@@ -674,6 +674,79 @@ void test_offset_in_overlapped_structure(void)
ok
(
DeleteFileA
(
temp_fname
),
"DeleteFileA error %ld
\n
"
,
GetLastError
());
}
static
void
test_LockFile
(
void
)
{
HANDLE
handle
;
DWORD
written
;
OVERLAPPED
overlapped
;
handle
=
CreateFileA
(
filename
,
GENERIC_READ
|
GENERIC_WRITE
,
FILE_SHARE_READ
|
FILE_SHARE_WRITE
,
NULL
,
CREATE_ALWAYS
,
0
,
0
);
if
(
handle
==
INVALID_HANDLE_VALUE
)
{
ok
(
0
,
"couldn't create file
\"
%s
\"
(err=%ld)"
,
filename
,
GetLastError
());
return
;
}
ok
(
WriteFile
(
handle
,
sillytext
,
strlen
(
sillytext
),
&
written
,
NULL
),
"write failed"
);
ok
(
LockFile
(
handle
,
0
,
0
,
0
,
0
),
"LockFile failed"
);
ok
(
UnlockFile
(
handle
,
0
,
0
,
0
,
0
),
"UnlockFile failed"
);
ok
(
!
UnlockFile
(
handle
,
0
,
0
,
0
,
0
),
"UnlockFile succeeded"
);
ok
(
LockFile
(
handle
,
10
,
0
,
20
,
0
),
"LockFile 10,20 failed"
);
/* overlapping locks must fail */
ok
(
!
LockFile
(
handle
,
12
,
0
,
10
,
0
),
"LockFile 12,10 succeeded"
);
ok
(
!
LockFile
(
handle
,
5
,
0
,
6
,
0
),
"LockFile 5,6 succeeded"
);
/* non-overlapping locks must succeed */
ok
(
LockFile
(
handle
,
5
,
0
,
5
,
0
),
"LockFile 5,5 failed"
);
ok
(
!
UnlockFile
(
handle
,
10
,
0
,
10
,
0
),
"UnlockFile 10,10 succeeded"
);
ok
(
UnlockFile
(
handle
,
10
,
0
,
20
,
0
),
"UnlockFile 10,20 failed"
);
ok
(
!
UnlockFile
(
handle
,
10
,
0
,
20
,
0
),
"UnlockFile 10,20 again succeeded"
);
ok
(
UnlockFile
(
handle
,
5
,
0
,
5
,
0
),
"UnlockFile 5,5 failed"
);
overlapped
.
Offset
=
100
;
overlapped
.
OffsetHigh
=
0
;
overlapped
.
hEvent
=
0
;
ok
(
LockFileEx
(
handle
,
0
,
0
,
100
,
0
,
&
overlapped
),
"LockFileEx 100,100 failed"
);
/* overlapping shared locks are OK */
overlapped
.
Offset
=
150
;
ok
(
LockFileEx
(
handle
,
0
,
0
,
100
,
0
,
&
overlapped
),
"LockFileEx 150,100 failed"
);
/* but exclusive is not */
ok
(
!
LockFileEx
(
handle
,
LOCKFILE_EXCLUSIVE_LOCK
|
LOCKFILE_FAIL_IMMEDIATELY
,
0
,
50
,
0
,
&
overlapped
),
"LockFileEx exclusive 150,50 succeeded"
);
ok
(
UnlockFileEx
(
handle
,
0
,
100
,
0
,
&
overlapped
),
"UnlockFileEx 150,100 failed"
);
ok
(
!
UnlockFileEx
(
handle
,
0
,
100
,
0
,
&
overlapped
),
"UnlockFileEx 150,100 again succeeded"
);
overlapped
.
Offset
=
100
;
ok
(
UnlockFileEx
(
handle
,
0
,
100
,
0
,
&
overlapped
),
"UnlockFileEx 100,100 failed"
);
ok
(
!
UnlockFileEx
(
handle
,
0
,
100
,
0
,
&
overlapped
),
"UnlockFileEx 100,100 again succeeded"
);
ok
(
LockFile
(
handle
,
0
,
0x10000000
,
0
,
0xf0000000
),
"LockFile failed"
);
ok
(
!
LockFile
(
handle
,
~
0
,
~
0
,
1
,
0
),
"LockFile ~0,1 succeeded"
);
ok
(
!
LockFile
(
handle
,
0
,
0x20000000
,
20
,
0
),
"LockFile 0x20000000,20 succeeded"
);
ok
(
UnlockFile
(
handle
,
0
,
0x10000000
,
0
,
0xf0000000
),
"UnlockFile failed"
);
/* wrap-around lock should not do anything */
/* (but still succeeds on NT4 so we don't check result) */
LockFile
(
handle
,
0
,
0x10000000
,
0
,
0xf0000001
);
ok
(
LockFile
(
handle
,
~
0
,
~
0
,
1
,
0
),
"LockFile ~0,1 failed"
);
ok
(
UnlockFile
(
handle
,
~
0
,
~
0
,
1
,
0
),
"Unlockfile ~0,1 failed"
);
/* zero-byte lock */
ok
(
LockFile
(
handle
,
100
,
0
,
0
,
0
),
"LockFile 100,0 failed"
);
ok
(
!
LockFile
(
handle
,
98
,
0
,
4
,
0
),
"LockFile 98,4 succeeded"
);
ok
(
LockFile
(
handle
,
90
,
0
,
10
,
0
),
"LockFile 90,10 failed"
);
ok
(
LockFile
(
handle
,
100
,
0
,
10
,
0
),
"LockFile 100,10 failed"
);
ok
(
UnlockFile
(
handle
,
90
,
0
,
10
,
0
),
"UnlockFile 90,10 failed"
);
ok
(
UnlockFile
(
handle
,
100
,
0
,
10
,
0
),
"UnlockFile 100,10 failed"
);
ok
(
UnlockFile
(
handle
,
100
,
0
,
0
,
0
),
"UnlockFile 100,0 failed"
);
CloseHandle
(
handle
);
DeleteFileA
(
filename
);
}
START_TEST
(
file
)
{
test__hread
(
);
...
...
@@ -690,5 +763,6 @@ START_TEST(file)
test_CreateFileW
();
test_DeleteFileA
();
test_DeleteFileW
();
test_LockFile
();
test_offset_in_overlapped_structure
();
}
files/file.c
View file @
ce613493
...
...
@@ -2995,20 +2995,22 @@ BOOL WINAPI SetFileTime( HANDLE hFile,
/**************************************************************************
* LockFile (KERNEL32.@)
*/
BOOL
WINAPI
LockFile
(
HANDLE
hFile
,
DWORD
dwFileOffsetLow
,
DWORD
dwFileOffsetH
igh
,
DWORD
nNumberOfBytesToLockLow
,
DWORD
nNumberOfBytesToLockH
igh
)
BOOL
WINAPI
LockFile
(
HANDLE
hFile
,
DWORD
offset_low
,
DWORD
offset_h
igh
,
DWORD
count_low
,
DWORD
count_h
igh
)
{
BOOL
ret
;
FIXME
(
"not implemented in server
\n
"
);
TRACE
(
"%p %lx%08lx %lx%08lx
\n
"
,
hFile
,
offset_high
,
offset_low
,
count_high
,
count_low
);
SERVER_START_REQ
(
lock_file
)
{
req
->
handle
=
hFile
;
req
->
offset_low
=
dwFileOffsetLow
;
req
->
offset_high
=
dwFileOffsetHigh
;
req
->
count_low
=
nNumberOfBytesToLockLow
;
req
->
count_high
=
nNumberOfBytesToLockHigh
;
req
->
offset_low
=
offset_low
;
req
->
offset_high
=
offset_high
;
req
->
count_low
=
count_low
;
req
->
count_high
=
count_high
;
req
->
shared
=
FALSE
;
req
->
wait
=
FALSE
;
ret
=
!
wine_server_call_err
(
req
);
}
SERVER_END_REQ
;
...
...
@@ -3028,41 +3030,76 @@ BOOL WINAPI LockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHig
* Per Microsoft docs, the third parameter (reserved) must be set to 0.
*/
BOOL
WINAPI
LockFileEx
(
HANDLE
hFile
,
DWORD
flags
,
DWORD
reserved
,
DWORD
nNumberOfBytesToLockLow
,
DWORD
nNumberOfBytesToLockHigh
,
LPOVERLAPPED
pOverlapped
)
{
FIXME
(
"hFile=%p,flags=%ld,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.
\n
"
,
hFile
,
flags
,
reserved
,
nNumberOfBytesToLockLow
,
nNumberOfBytesToLockHigh
,
pOverlapped
);
if
(
reserved
==
0
)
SetLastError
(
ERROR_CALL_NOT_IMPLEMENTED
);
else
DWORD
count_low
,
DWORD
count_high
,
LPOVERLAPPED
overlapped
)
{
NTSTATUS
err
;
BOOL
async
;
HANDLE
handle
;
if
(
reserved
)
{
ERR
(
"reserved == %ld: Supposed to be 0??
\n
"
,
reserved
);
SetLastError
(
ERROR_INVALID_PARAMETER
)
;
SetLastError
(
ERROR_INVALID_PARAMETER
);
return
FALSE
;
}
return
FALSE
;
TRACE
(
"%p %lx%08lx %lx%08lx flags %lx
\n
"
,
hFile
,
overlapped
->
OffsetHigh
,
overlapped
->
Offset
,
count_high
,
count_low
,
flags
);
for
(;;)
{
SERVER_START_REQ
(
lock_file
)
{
req
->
handle
=
hFile
;
req
->
offset_low
=
overlapped
->
Offset
;
req
->
offset_high
=
overlapped
->
OffsetHigh
;
req
->
count_low
=
count_low
;
req
->
count_high
=
count_high
;
req
->
shared
=
!
(
flags
&
LOCKFILE_EXCLUSIVE_LOCK
);
req
->
wait
=
!
(
flags
&
LOCKFILE_FAIL_IMMEDIATELY
);
err
=
wine_server_call
(
req
);
handle
=
reply
->
handle
;
async
=
reply
->
overlapped
;
}
SERVER_END_REQ
;
if
(
err
!=
STATUS_PENDING
)
{
if
(
err
)
SetLastError
(
RtlNtStatusToDosError
(
err
)
);
return
!
err
;
}
if
(
async
)
{
FIXME
(
"Async I/O lock wait not implemented, might deadlock
\n
"
);
if
(
handle
)
CloseHandle
(
handle
);
SetLastError
(
ERROR_IO_PENDING
);
return
FALSE
;
}
if
(
handle
)
{
WaitForSingleObject
(
handle
,
INFINITE
);
CloseHandle
(
handle
);
}
else
Sleep
(
100
);
/* Unix lock conflict, sleep a bit and retry */
}
}
/**************************************************************************
* UnlockFile (KERNEL32.@)
*/
BOOL
WINAPI
UnlockFile
(
HANDLE
hFile
,
DWORD
dwFileOffsetLow
,
DWORD
dwFileOffsetH
igh
,
DWORD
nNumberOfBytesToUnlockLow
,
DWORD
nNumberOfBytesToUnlockH
igh
)
BOOL
WINAPI
UnlockFile
(
HANDLE
hFile
,
DWORD
offset_low
,
DWORD
offset_h
igh
,
DWORD
count_low
,
DWORD
count_h
igh
)
{
BOOL
ret
;
FIXME
(
"not implemented in server
\n
"
);
TRACE
(
"%p %lx%08lx %lx%08lx
\n
"
,
hFile
,
offset_high
,
offset_low
,
count_high
,
count_low
);
SERVER_START_REQ
(
unlock_file
)
{
req
->
handle
=
hFile
;
req
->
offset_low
=
dwFileOffsetL
ow
;
req
->
offset_high
=
dwFileOffsetH
igh
;
req
->
count_low
=
nNumberOfBytesToUnlockL
ow
;
req
->
count_high
=
nNumberOfBytesToUnlockH
igh
;
req
->
offset_low
=
offset_l
ow
;
req
->
offset_high
=
offset_h
igh
;
req
->
count_low
=
count_l
ow
;
req
->
count_high
=
count_h
igh
;
ret
=
!
wine_server_call_err
(
req
);
}
SERVER_END_REQ
;
...
...
@@ -3073,223 +3110,19 @@ BOOL WINAPI UnlockFile( HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetH
/**************************************************************************
* UnlockFileEx (KERNEL32.@)
*/
BOOL
WINAPI
UnlockFileEx
(
HANDLE
hFile
,
DWORD
dwReserved
,
DWORD
nNumberOfBytesToUnlockLow
,
DWORD
nNumberOfBytesToUnlockHigh
,
LPOVERLAPPED
lpOverlapped
)
{
FIXME
(
"hFile=%p,reserved=%ld,lowbytes=%ld,highbytes=%ld,overlapped=%p: stub.
\n
"
,
hFile
,
dwReserved
,
nNumberOfBytesToUnlockLow
,
nNumberOfBytesToUnlockHigh
,
lpOverlapped
);
if
(
dwReserved
==
0
)
SetLastError
(
ERROR_CALL_NOT_IMPLEMENTED
);
else
{
ERR
(
"reserved == %ld: Supposed to be 0??
\n
"
,
dwReserved
);
SetLastError
(
ERROR_INVALID_PARAMETER
);
}
return
FALSE
;
}
#if 0
struct DOS_FILE_LOCK {
struct DOS_FILE_LOCK * next;
DWORD base;
DWORD len;
DWORD processId;
FILE_OBJECT * dos_file;
/* char * unix_name;*/
};
typedef struct DOS_FILE_LOCK DOS_FILE_LOCK;
static DOS_FILE_LOCK *locks = NULL;
static void DOS_RemoveFileLocks(FILE_OBJECT *file);
/* Locks need to be mirrored because unix file locking is based
* on the pid. Inside of wine there can be multiple WINE processes
* that share the same unix pid.
* Read's and writes should check these locks also - not sure
* how critical that is at this point (FIXME).
*/
static BOOL DOS_AddLock(FILE_OBJECT *file, struct flock *f)
BOOL
WINAPI
UnlockFileEx
(
HANDLE
hFile
,
DWORD
reserved
,
DWORD
count_low
,
DWORD
count_high
,
LPOVERLAPPED
overlapped
)
{
DOS_FILE_LOCK *curr;
DWORD processId;
processId = GetCurrentProcessId();
/* check if lock overlaps a current lock for the same file */
#if 0
for (curr = locks; curr; curr = curr->next) {
if (strcmp(curr->unix_name, file->unix_name) == 0) {
if ((f->l_start == curr->base) && (f->l_len == curr->len))
return TRUE;/* region is identic */
if ((f->l_start < (curr->base + curr->len)) &&
((f->l_start + f->l_len) > curr->base)) {
/* region overlaps */
return FALSE;
}
}
}
#endif
curr = HeapAlloc( GetProcessHeap(), 0, sizeof(DOS_FILE_LOCK) );
curr->processId = GetCurrentProcessId();
curr->base = f->l_start;
curr->len = f->l_len;
/* curr->unix_name = HEAP_strdupA( GetProcessHeap(), 0, file->unix_name);*/
curr->next = locks;
curr->dos_file = file;
locks = curr;
return TRUE;
}
static void DOS_RemoveFileLocks(FILE_OBJECT *file)
{
DWORD processId;
DOS_FILE_LOCK **curr;
DOS_FILE_LOCK *rem;
processId = GetCurrentProcessId();
curr = &locks;
while (*curr) {
if ((*curr)->dos_file == file) {
rem = *curr;
*curr = (*curr)->next;
/* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
HeapFree( GetProcessHeap(), 0, rem );
}
else
curr = &(*curr)->next;
}
}
static BOOL DOS_RemoveLock(FILE_OBJECT *file, struct flock *f)
{
DWORD processId;
DOS_FILE_LOCK **curr;
DOS_FILE_LOCK *rem;
processId = GetCurrentProcessId();
for (curr = &locks; *curr; curr = &(*curr)->next) {
if ((*curr)->processId == processId &&
(*curr)->dos_file == file &&
(*curr)->base == f->l_start &&
(*curr)->len == f->l_len) {
/* this is the same lock */
rem = *curr;
*curr = (*curr)->next;
/* HeapFree( GetProcessHeap(), 0, rem->unix_name );*/
HeapFree( GetProcessHeap(), 0, rem );
return TRUE;
}
}
/* no matching lock found */
return FALSE;
}
/**************************************************************************
* LockFile (KERNEL32.@)
*/
BOOL WINAPI LockFile(
HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
DWORD nNumberOfBytesToLockLow,DWORD nNumberOfBytesToLockHigh )
{
struct flock f;
FILE_OBJECT *file;
TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
hFile, dwFileOffsetLow, dwFileOffsetHigh,
nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
if (dwFileOffsetHigh || nNumberOfBytesToLockHigh) {
FIXME("Unimplemented bytes > 32bits\n");
return FALSE;
}
f.l_start = dwFileOffsetLow;
f.l_len = nNumberOfBytesToLockLow;
f.l_whence = SEEK_SET;
f.l_pid = 0;
f.l_type = F_WRLCK;
if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
/* shadow locks internally */
if (!DOS_AddLock(file, &f)) {
SetLastError( ERROR_LOCK_VIOLATION );
return FALSE;
}
/* FIXME: Unix locking commented out for now, doesn't work with Excel */
#ifdef USE_UNIX_LOCKS
if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
if (errno == EACCES || errno == EAGAIN) {
SetLastError( ERROR_LOCK_VIOLATION );
}
else {
FILE_SetDosError();
if
(
reserved
)
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
return
FALSE
;
}
/* remove our internal copy of the lock */
DOS_RemoveLock(file, &f);
return FALSE;
}
#endif
return TRUE;
return
UnlockFile
(
hFile
,
overlapped
->
Offset
,
overlapped
->
OffsetHigh
,
count_low
,
count_high
);
}
/**************************************************************************
* UnlockFile (KERNEL32.@)
*/
BOOL WINAPI UnlockFile(
HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
DWORD nNumberOfBytesToUnlockLow,DWORD nNumberOfBytesToUnlockHigh )
{
FILE_OBJECT *file;
struct flock f;
TRACE("handle %d offsetlow=%ld offsethigh=%ld nbyteslow=%ld nbyteshigh=%ld\n",
hFile, dwFileOffsetLow, dwFileOffsetHigh,
nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
if (dwFileOffsetHigh || nNumberOfBytesToUnlockHigh) {
WARN("Unimplemented bytes > 32bits\n");
return FALSE;
}
f.l_start = dwFileOffsetLow;
f.l_len = nNumberOfBytesToUnlockLow;
f.l_whence = SEEK_SET;
f.l_pid = 0;
f.l_type = F_UNLCK;
if (!(file = FILE_GetFile(hFile,0,NULL))) return FALSE;
DOS_RemoveLock(file, &f); /* ok if fails - may be another wine */
/* FIXME: Unix locking commented out for now, doesn't work with Excel */
#ifdef USE_UNIX_LOCKS
if (fcntl(file->unix_handle, F_SETLK, &f) == -1) {
FILE_SetDosError();
return FALSE;
}
#endif
return TRUE;
}
#endif
/**************************************************************************
* GetFileAttributesExW (KERNEL32.@)
*/
BOOL
WINAPI
GetFileAttributesExW
(
...
...
include/winbase.h
View file @
ce613493
...
...
@@ -293,6 +293,8 @@ typedef struct _PROCESS_HEAP_ENTRY
#define INVALID_SET_FILE_POINTER ((DWORD)-1)
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#define LOCKFILE_FAIL_IMMEDIATELY 1
#define LOCKFILE_EXCLUSIVE_LOCK 2
#define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF)
...
...
include/wine/server_protocol.h
View file @
ce613493
...
...
@@ -899,10 +899,14 @@ struct lock_file_request
unsigned
int
offset_high
;
unsigned
int
count_low
;
unsigned
int
count_high
;
int
shared
;
int
wait
;
};
struct
lock_file_reply
{
struct
reply_header
__header
;
obj_handle_t
handle
;
int
overlapped
;
};
...
...
@@ -3551,6 +3555,6 @@ union generic_reply
struct
get_next_hook_reply
get_next_hook_reply
;
};
#define SERVER_PROTOCOL_VERSION
99
#define SERVER_PROTOCOL_VERSION
100
#endif
/* __WINE_WINE_SERVER_PROTOCOL_H */
server/fd.c
View file @
ce613493
/*
* Server-side file descriptor management
*
* Copyright (C) 2003 Alexandre Julliard
* Copyright (C) 200
0, 200
3 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
...
...
@@ -22,7 +22,9 @@
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
...
...
@@ -42,6 +44,11 @@
#include "request.h"
#include "console.h"
/* Because of the stupid Posix locking semantics, we need to keep
* track of all file descriptors referencing a given file, and not
* close a single one until all the locks are gone (sigh).
*/
/* file descriptor object */
/* closed_fd is used to keep track of the unix fd belonging to a closed fd object */
...
...
@@ -59,6 +66,7 @@ struct fd
struct
list
inode_entry
;
/* entry in inode fd list */
struct
closed_fd
*
closed
;
/* structure to store the unix fd at destroy time */
struct
object
*
user
;
/* object using this file descriptor */
struct
list
locks
;
/* list of locks on this fd */
int
unix_fd
;
/* unix file descriptor */
int
poll_index
;
/* index of fd in poll array */
};
...
...
@@ -88,6 +96,7 @@ struct inode
dev_t
dev
;
/* device number */
ino_t
ino
;
/* inode number */
struct
list
open
;
/* list of open file descriptors */
struct
list
locks
;
/* list of file locks */
struct
closed_fd
*
closed
;
/* list of file descriptors to close at destroy time */
};
...
...
@@ -106,6 +115,42 @@ static const struct object_ops inode_ops =
inode_destroy
/* destroy */
};
/* file lock object */
struct
file_lock
{
struct
object
obj
;
/* object header */
struct
fd
*
fd
;
/* fd owning this lock */
struct
list
fd_entry
;
/* entry in list of locks on a given fd */
struct
list
inode_entry
;
/* entry in inode list of locks */
int
shared
;
/* shared lock? */
file_pos_t
start
;
/* locked region is interval [start;end) */
file_pos_t
end
;
struct
process
*
process
;
/* process owning this lock */
struct
list
proc_entry
;
/* entry in list of locks owned by the process */
};
static
void
file_lock_dump
(
struct
object
*
obj
,
int
verbose
);
static
int
file_lock_signaled
(
struct
object
*
obj
,
struct
thread
*
thread
);
static
const
struct
object_ops
file_lock_ops
=
{
sizeof
(
struct
file_lock
),
/* size */
file_lock_dump
,
/* dump */
add_queue
,
/* add_queue */
remove_queue
,
/* remove_queue */
file_lock_signaled
,
/* signaled */
no_satisfied
,
/* satisfied */
no_get_fd
,
/* get_fd */
no_destroy
/* destroy */
};
#define OFF_T_MAX (~((file_pos_t)1 << (8*sizeof(off_t)-1)))
#define FILE_POS_T_MAX (~(file_pos_t)0)
static
file_pos_t
max_unix_offset
=
OFF_T_MAX
;
#define DUMP_LONG_LONG(val) do { \
if (sizeof(val) > sizeof(unsigned long) && (val) > ~0UL) \
fprintf( stderr, "%lx%08lx", (unsigned long)((val) >> 32), (unsigned long)(val) ); \
...
...
@@ -368,6 +413,18 @@ void main_loop(void)
static
struct
list
inode_hash
[
HASH_SIZE
];
/* close all pending file descriptors in the closed list */
static
void
inode_close_pending
(
struct
inode
*
inode
)
{
while
(
inode
->
closed
)
{
struct
closed_fd
*
fd
=
inode
->
closed
;
inode
->
closed
=
fd
->
next
;
close
(
fd
->
fd
);
free
(
fd
);
}
}
static
void
inode_dump
(
struct
object
*
obj
,
int
verbose
)
{
...
...
@@ -383,16 +440,11 @@ static void inode_destroy( struct object *obj )
{
struct
inode
*
inode
=
(
struct
inode
*
)
obj
;
assert
(
!
list_head
(
&
inode
->
open
)
);
assert
(
list_empty
(
&
inode
->
open
)
);
assert
(
list_empty
(
&
inode
->
locks
)
);
list_remove
(
&
inode
->
entry
);
while
(
inode
->
closed
)
{
struct
closed_fd
*
fd
=
inode
->
closed
;
inode
->
closed
=
fd
->
next
;
close
(
fd
->
fd
);
free
(
fd
);
}
inode_close_pending
(
inode
);
}
/* retrieve the inode object for a given fd, creating it if needed */
...
...
@@ -421,6 +473,7 @@ static struct inode *get_inode( dev_t dev, ino_t ino )
inode
->
ino
=
ino
;
inode
->
closed
=
NULL
;
list_init
(
&
inode
->
open
);
list_init
(
&
inode
->
locks
);
list_add_head
(
&
inode_hash
[
hash
],
&
inode
->
entry
);
}
return
inode
;
...
...
@@ -429,8 +482,315 @@ static struct inode *get_inode( dev_t dev, ino_t ino )
/* add fd to the indoe list of file descriptors to close */
static
void
inode_add_closed_fd
(
struct
inode
*
inode
,
struct
closed_fd
*
fd
)
{
fd
->
next
=
inode
->
closed
;
inode
->
closed
=
fd
;
if
(
!
list_empty
(
&
inode
->
locks
))
{
fd
->
next
=
inode
->
closed
;
inode
->
closed
=
fd
;
}
else
/* no locks on this inode, we can close the fd right away */
{
close
(
fd
->
fd
);
free
(
fd
);
}
}
/****************************************************************/
/* file lock functions */
static
void
file_lock_dump
(
struct
object
*
obj
,
int
verbose
)
{
struct
file_lock
*
lock
=
(
struct
file_lock
*
)
obj
;
fprintf
(
stderr
,
"Lock %s fd=%p proc=%p start="
,
lock
->
shared
?
"shared"
:
"excl"
,
lock
->
fd
,
lock
->
process
);
DUMP_LONG_LONG
(
lock
->
start
);
fprintf
(
stderr
,
" end="
);
DUMP_LONG_LONG
(
lock
->
end
);
fprintf
(
stderr
,
"
\n
"
);
}
static
int
file_lock_signaled
(
struct
object
*
obj
,
struct
thread
*
thread
)
{
struct
file_lock
*
lock
=
(
struct
file_lock
*
)
obj
;
/* lock is signaled if it has lost its owner */
return
!
lock
->
process
;
}
/* set (or remove) a Unix lock if possible for the given range */
static
int
set_unix_lock
(
const
struct
fd
*
fd
,
file_pos_t
start
,
file_pos_t
end
,
int
type
)
{
struct
flock
fl
;
for
(;;)
{
if
(
start
==
end
)
return
1
;
/* can't set zero-byte lock */
if
(
start
>
max_unix_offset
)
return
1
;
/* ignore it */
fl
.
l_type
=
type
;
fl
.
l_whence
=
SEEK_SET
;
fl
.
l_start
=
start
;
if
(
!
end
||
end
>
max_unix_offset
)
fl
.
l_len
=
0
;
else
fl
.
l_len
=
end
-
start
;
if
(
fcntl
(
fd
->
unix_fd
,
F_SETLK
,
&
fl
)
!=
-
1
)
return
1
;
switch
(
errno
)
{
case
EACCES
:
case
EAGAIN
:
set_error
(
STATUS_FILE_LOCK_CONFLICT
);
return
0
;
case
EOVERFLOW
:
/* this can happen if off_t is 64-bit but the kernel only supports 32-bit */
/* in that case we shrink the limit and retry */
if
(
max_unix_offset
>
INT_MAX
)
{
max_unix_offset
=
INT_MAX
;
break
;
/* retry */
}
/* fall through */
default:
file_set_error
();
return
0
;
}
}
}
/* check if interval [start;end) overlaps the lock */
inline
static
int
lock_overlaps
(
struct
file_lock
*
lock
,
file_pos_t
start
,
file_pos_t
end
)
{
if
(
lock
->
end
&&
start
>=
lock
->
end
)
return
0
;
if
(
end
&&
lock
->
start
>=
end
)
return
0
;
return
1
;
}
/* remove Unix locks for all bytes in the specified area that are no longer locked */
static
void
remove_unix_locks
(
const
struct
fd
*
fd
,
file_pos_t
start
,
file_pos_t
end
)
{
struct
hole
{
struct
hole
*
next
;
struct
hole
*
prev
;
file_pos_t
start
;
file_pos_t
end
;
}
*
first
,
*
cur
,
*
next
,
*
buffer
;
struct
list
*
ptr
;
int
count
=
0
;
if
(
!
fd
->
inode
)
return
;
if
(
start
==
end
||
start
>
max_unix_offset
)
return
;
if
(
!
end
||
end
>
max_unix_offset
)
end
=
max_unix_offset
+
1
;
/* count the number of locks overlapping the specified area */
LIST_FOR_EACH
(
ptr
,
&
fd
->
inode
->
locks
)
{
struct
file_lock
*
lock
=
LIST_ENTRY
(
ptr
,
struct
file_lock
,
inode_entry
);
if
(
lock
->
start
==
lock
->
end
)
continue
;
if
(
lock_overlaps
(
lock
,
start
,
end
))
count
++
;
}
if
(
!
count
)
/* no locks at all, we can unlock everything */
{
set_unix_lock
(
fd
,
start
,
end
,
F_UNLCK
);
return
;
}
/* allocate space for the list of holes */
/* max. number of holes is number of locks + 1 */
if
(
!
(
buffer
=
malloc
(
sizeof
(
*
buffer
)
*
(
count
+
1
)
)))
return
;
first
=
buffer
;
first
->
next
=
NULL
;
first
->
prev
=
NULL
;
first
->
start
=
start
;
first
->
end
=
end
;
next
=
first
+
1
;
/* build a sorted list of unlocked holes in the specified area */
LIST_FOR_EACH
(
ptr
,
&
fd
->
inode
->
locks
)
{
struct
file_lock
*
lock
=
LIST_ENTRY
(
ptr
,
struct
file_lock
,
inode_entry
);
if
(
lock
->
start
==
lock
->
end
)
continue
;
if
(
!
lock_overlaps
(
lock
,
start
,
end
))
continue
;
/* go through all the holes touched by this lock */
for
(
cur
=
first
;
cur
;
cur
=
cur
->
next
)
{
if
(
cur
->
end
<=
lock
->
start
)
continue
;
/* hole is before start of lock */
if
(
lock
->
end
&&
cur
->
start
>=
lock
->
end
)
break
;
/* hole is after end of lock */
/* now we know that lock is overlapping hole */
if
(
cur
->
start
>=
lock
->
start
)
/* lock starts before hole, shrink from start */
{
cur
->
start
=
lock
->
end
;
if
(
cur
->
start
&&
cur
->
start
<
cur
->
end
)
break
;
/* done with this lock */
/* now hole is empty, remove it */
if
(
cur
->
next
)
cur
->
next
->
prev
=
cur
->
prev
;
if
(
cur
->
prev
)
cur
->
prev
->
next
=
cur
->
next
;
else
if
(
!
(
first
=
cur
->
next
))
goto
done
;
/* no more holes at all */
}
else
if
(
!
lock
->
end
||
cur
->
end
<=
lock
->
end
)
/* lock larger than hole, shrink from end */
{
cur
->
end
=
lock
->
start
;
assert
(
cur
->
start
<
cur
->
end
);
}
else
/* lock is in the middle of hole, split hole in two */
{
next
->
prev
=
cur
;
next
->
next
=
cur
->
next
;
cur
->
next
=
next
;
next
->
start
=
lock
->
end
;
next
->
end
=
cur
->
end
;
cur
->
end
=
lock
->
start
;
assert
(
next
->
start
<
next
->
end
);
assert
(
cur
->
end
<
next
->
start
);
next
++
;
break
;
/* done with this lock */
}
}
}
/* clear Unix locks for all the holes */
for
(
cur
=
first
;
cur
;
cur
=
cur
->
next
)
set_unix_lock
(
fd
,
cur
->
start
,
cur
->
end
,
F_UNLCK
);
done:
free
(
buffer
);
}
/* create a new lock on a fd */
static
struct
file_lock
*
add_lock
(
struct
fd
*
fd
,
int
shared
,
file_pos_t
start
,
file_pos_t
end
)
{
struct
file_lock
*
lock
;
if
(
!
fd
->
inode
)
/* not a regular file */
{
set_error
(
STATUS_INVALID_HANDLE
);
return
NULL
;
}
if
(
!
(
lock
=
alloc_object
(
&
file_lock_ops
)))
return
NULL
;
lock
->
shared
=
shared
;
lock
->
start
=
start
;
lock
->
end
=
end
;
lock
->
fd
=
fd
;
lock
->
process
=
current
->
process
;
/* now try to set a Unix lock */
if
(
!
set_unix_lock
(
lock
->
fd
,
lock
->
start
,
lock
->
end
,
lock
->
shared
?
F_RDLCK
:
F_WRLCK
))
{
release_object
(
lock
);
return
NULL
;
}
list_add_head
(
&
fd
->
locks
,
&
lock
->
fd_entry
);
list_add_head
(
&
fd
->
inode
->
locks
,
&
lock
->
inode_entry
);
list_add_head
(
&
lock
->
process
->
locks
,
&
lock
->
proc_entry
);
return
lock
;
}
/* remove an existing lock */
static
void
remove_lock
(
struct
file_lock
*
lock
,
int
remove_unix
)
{
struct
inode
*
inode
=
lock
->
fd
->
inode
;
list_remove
(
&
lock
->
fd_entry
);
list_remove
(
&
lock
->
inode_entry
);
list_remove
(
&
lock
->
proc_entry
);
if
(
remove_unix
)
remove_unix_locks
(
lock
->
fd
,
lock
->
start
,
lock
->
end
);
if
(
list_empty
(
&
inode
->
locks
))
inode_close_pending
(
inode
);
lock
->
process
=
NULL
;
wake_up
(
&
lock
->
obj
,
0
);
release_object
(
lock
);
}
/* remove all locks owned by a given process */
void
remove_process_locks
(
struct
process
*
process
)
{
struct
list
*
ptr
;
while
((
ptr
=
list_head
(
&
process
->
locks
)))
{
struct
file_lock
*
lock
=
LIST_ENTRY
(
ptr
,
struct
file_lock
,
proc_entry
);
remove_lock
(
lock
,
1
);
/* this removes it from the list */
}
}
/* remove all locks on a given fd */
static
void
remove_fd_locks
(
struct
fd
*
fd
)
{
file_pos_t
start
=
FILE_POS_T_MAX
,
end
=
0
;
struct
list
*
ptr
;
while
((
ptr
=
list_head
(
&
fd
->
locks
)))
{
struct
file_lock
*
lock
=
LIST_ENTRY
(
ptr
,
struct
file_lock
,
fd_entry
);
if
(
lock
->
start
<
start
)
start
=
lock
->
start
;
if
(
!
lock
->
end
||
lock
->
end
>
end
)
end
=
lock
->
end
-
1
;
remove_lock
(
lock
,
0
);
}
if
(
start
<
end
)
remove_unix_locks
(
fd
,
start
,
end
+
1
);
}
/* add a lock on an fd */
/* returns handle to wait on */
obj_handle_t
lock_fd
(
struct
fd
*
fd
,
file_pos_t
start
,
file_pos_t
count
,
int
shared
,
int
wait
)
{
struct
list
*
ptr
;
file_pos_t
end
=
start
+
count
;
/* don't allow wrapping locks */
if
(
end
&&
end
<
start
)
{
set_error
(
STATUS_INVALID_PARAMETER
);
return
0
;
}
/* check if another lock on that file overlaps the area */
LIST_FOR_EACH
(
ptr
,
&
fd
->
inode
->
locks
)
{
struct
file_lock
*
lock
=
LIST_ENTRY
(
ptr
,
struct
file_lock
,
inode_entry
);
if
(
!
lock_overlaps
(
lock
,
start
,
end
))
continue
;
if
(
lock
->
shared
&&
shared
)
continue
;
/* found one */
if
(
!
wait
)
{
set_error
(
STATUS_FILE_LOCK_CONFLICT
);
return
0
;
}
set_error
(
STATUS_PENDING
);
return
alloc_handle
(
current
->
process
,
lock
,
SYNCHRONIZE
,
0
);
}
/* not found, add it */
if
(
add_lock
(
fd
,
shared
,
start
,
end
))
return
0
;
if
(
get_error
()
==
STATUS_FILE_LOCK_CONFLICT
)
{
/* Unix lock conflict -> tell client to wait and retry */
if
(
wait
)
set_error
(
STATUS_PENDING
);
}
return
0
;
}
/* remove a lock on an fd */
void
unlock_fd
(
struct
fd
*
fd
,
file_pos_t
start
,
file_pos_t
count
)
{
struct
list
*
ptr
;
file_pos_t
end
=
start
+
count
;
/* find an existing lock with the exact same parameters */
LIST_FOR_EACH
(
ptr
,
&
fd
->
locks
)
{
struct
file_lock
*
lock
=
LIST_ENTRY
(
ptr
,
struct
file_lock
,
fd_entry
);
if
((
lock
->
start
==
start
)
&&
(
lock
->
end
==
end
))
{
remove_lock
(
lock
,
1
);
return
;
}
}
set_error
(
STATUS_FILE_LOCK_CONFLICT
);
}
...
...
@@ -447,6 +807,7 @@ static void fd_destroy( struct object *obj )
{
struct
fd
*
fd
=
(
struct
fd
*
)
obj
;
remove_fd_locks
(
fd
);
list_remove
(
&
fd
->
inode_entry
);
if
(
fd
->
poll_index
!=
-
1
)
remove_poll_user
(
fd
,
fd
->
poll_index
);
if
(
fd
->
inode
)
...
...
@@ -492,6 +853,7 @@ struct fd *alloc_fd( const struct fd_ops *fd_user_ops, struct object *user )
fd
->
unix_fd
=
-
1
;
fd
->
poll_index
=
-
1
;
list_init
(
&
fd
->
inode_entry
);
list_init
(
&
fd
->
locks
);
if
((
fd
->
poll_index
=
add_poll_user
(
fd
))
==
-
1
)
{
...
...
server/file.c
View file @
ce613493
...
...
@@ -453,6 +453,7 @@ void file_set_error(void)
case
ESPIPE
:
set_error
(
0xc0010000
|
ERROR_SEEK
/* FIXME */
);
break
;
case
ENOTEMPTY
:
set_error
(
STATUS_DIRECTORY_NOT_EMPTY
);
break
;
case
EIO
:
set_error
(
STATUS_ACCESS_VIOLATION
);
break
;
case
EOVERFLOW
:
set_error
(
STATUS_INVALID_PARAMETER
);
break
;
default:
perror
(
"file_set_error"
);
set_error
(
ERROR_UNKNOWN
/* FIXME */
);
break
;
}
}
...
...
@@ -581,20 +582,6 @@ static int set_file_time( obj_handle_t handle, time_t access_time, time_t write_
return
0
;
}
static
int
file_lock
(
struct
file
*
file
,
int
offset_high
,
int
offset_low
,
int
count_high
,
int
count_low
)
{
/* FIXME: implement this */
return
1
;
}
static
int
file_unlock
(
struct
file
*
file
,
int
offset_high
,
int
offset_low
,
int
count_high
,
int
count_low
)
{
/* FIXME: implement this */
return
1
;
}
/* create a file */
DECL_HANDLER
(
create_file
)
{
...
...
@@ -661,11 +648,13 @@ DECL_HANDLER(set_file_time)
DECL_HANDLER
(
lock_file
)
{
struct
file
*
file
;
file_pos_t
offset
=
((
file_pos_t
)
req
->
offset_high
<<
32
)
|
req
->
offset_low
;
file_pos_t
count
=
((
file_pos_t
)
req
->
count_high
<<
32
)
|
req
->
count_low
;
if
((
file
=
get_file_obj
(
current
->
process
,
req
->
handle
,
0
)))
{
file_lock
(
file
,
req
->
offset_high
,
req
->
offset_low
,
req
->
count_high
,
req
->
count_low
)
;
reply
->
handle
=
lock_fd
(
file
->
fd
,
offset
,
count
,
req
->
shared
,
req
->
wait
);
reply
->
overlapped
=
(
file
->
flags
&
FILE_FLAG_OVERLAPPED
)
!=
0
;
release_object
(
file
);
}
}
...
...
@@ -674,11 +663,12 @@ DECL_HANDLER(lock_file)
DECL_HANDLER
(
unlock_file
)
{
struct
file
*
file
;
file_pos_t
offset
=
((
file_pos_t
)
req
->
offset_high
<<
32
)
|
req
->
offset_low
;
file_pos_t
count
=
((
file_pos_t
)
req
->
count_high
<<
32
)
|
req
->
count_low
;
if
((
file
=
get_file_obj
(
current
->
process
,
req
->
handle
,
0
)))
{
file_unlock
(
file
,
req
->
offset_high
,
req
->
offset_low
,
req
->
count_high
,
req
->
count_low
);
unlock_fd
(
file
->
fd
,
offset
,
count
);
release_object
(
file
);
}
}
server/file.h
View file @
ce613493
...
...
@@ -25,6 +25,8 @@
struct
fd
;
typedef
unsigned
__int64
file_pos_t
;
/* operations valid on file descriptor objects */
struct
fd_ops
{
...
...
@@ -51,6 +53,8 @@ extern int get_unix_fd( struct fd *fd );
extern
void
fd_poll_event
(
struct
fd
*
fd
,
int
event
);
extern
int
check_fd_events
(
struct
fd
*
fd
,
int
events
);
extern
void
set_fd_events
(
struct
fd
*
fd
,
int
events
);
extern
obj_handle_t
lock_fd
(
struct
fd
*
fd
,
file_pos_t
offset
,
file_pos_t
count
,
int
shared
,
int
wait
);
extern
void
unlock_fd
(
struct
fd
*
fd
,
file_pos_t
offset
,
file_pos_t
count
);
extern
int
default_fd_add_queue
(
struct
object
*
obj
,
struct
wait_queue_entry
*
entry
);
extern
void
default_fd_remove_queue
(
struct
object
*
obj
,
struct
wait_queue_entry
*
entry
);
...
...
server/list.h
View file @
ce613493
...
...
@@ -80,6 +80,12 @@ inline static struct list *list_tail( struct list *list )
return
list_prev
(
list
,
list
);
}
/* check if a list is empty */
inline
static
int
list_empty
(
struct
list
*
list
)
{
return
list
->
next
==
list
;
}
/* initialize a list */
inline
static
void
list_init
(
struct
list
*
list
)
{
...
...
server/process.c
View file @
ce613493
...
...
@@ -296,6 +296,7 @@ struct thread *create_process( int fd )
process
->
exe
.
namelen
=
0
;
process
->
exe
.
filename
=
NULL
;
process
->
group_id
=
0
;
list_init
(
&
process
->
locks
);
gettimeofday
(
&
process
->
start_time
,
NULL
);
if
((
process
->
next
=
first_process
)
!=
NULL
)
process
->
next
->
prev
=
process
;
...
...
server/process.h
View file @
ce613493
...
...
@@ -67,6 +67,7 @@ struct process
int
affinity
;
/* process affinity mask */
int
suspend
;
/* global process suspend count */
int
create_flags
;
/* process creation flags */
struct
list
locks
;
/* list of file locks owned by the process */
struct
console_input
*
console
;
/* console input */
enum
startup_state
startup_state
;
/* startup state */
struct
startup_info
*
startup_info
;
/* startup info while init is in progress */
...
...
server/protocol.def
View file @
ce613493
...
...
@@ -681,6 +681,11 @@ enum fd_type
unsigned int offset_high; /* offset of start of lock */
unsigned int count_low; /* count of bytes to lock */
unsigned int count_high; /* count of bytes to lock */
int shared; /* shared or exclusive lock? */
int wait; /* do we want to wait? */
@REPLY
obj_handle_t handle; /* handle to wait on */
int overlapped; /* is it an overlapped I/O handle? */
@END
...
...
server/trace.c
View file @
ce613493
...
...
@@ -889,7 +889,15 @@ static void dump_lock_file_request( const struct lock_file_request *req )
fprintf
(
stderr
,
" offset_low=%08x,"
,
req
->
offset_low
);
fprintf
(
stderr
,
" offset_high=%08x,"
,
req
->
offset_high
);
fprintf
(
stderr
,
" count_low=%08x,"
,
req
->
count_low
);
fprintf
(
stderr
,
" count_high=%08x"
,
req
->
count_high
);
fprintf
(
stderr
,
" count_high=%08x,"
,
req
->
count_high
);
fprintf
(
stderr
,
" shared=%d,"
,
req
->
shared
);
fprintf
(
stderr
,
" wait=%d"
,
req
->
wait
);
}
static
void
dump_lock_file_reply
(
const
struct
lock_file_reply
*
req
)
{
fprintf
(
stderr
,
" handle=%p,"
,
req
->
handle
);
fprintf
(
stderr
,
" overlapped=%d"
,
req
->
overlapped
);
}
static
void
dump_unlock_file_request
(
const
struct
unlock_file_request
*
req
)
...
...
@@ -2632,7 +2640,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(
dump_func
)
0
,
(
dump_func
)
0
,
(
dump_func
)
dump_get_file_info_reply
,
(
dump_func
)
0
,
(
dump_func
)
dump_lock_file_reply
,
(
dump_func
)
0
,
(
dump_func
)
dump_create_pipe_reply
,
(
dump_func
)
dump_create_socket_reply
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment