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
01932119
Commit
01932119
authored
Feb 06, 2006
by
Mike McCormack
Committed by
Alexandre Julliard
Feb 06, 2006
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
server: Fill in NtNotifyChangeDirectoryFile's buffer with change data.
parent
acb52e52
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
257 additions
and
25 deletions
+257
-25
change.c
dlls/kernel/change.c
+28
-15
directory.c
dlls/ntdll/directory.c
+90
-3
server_protocol.h
include/wine/server_protocol.h
+20
-1
change.c
server/change.c
+87
-5
protocol.def
server/protocol.def
+11
-0
request.h
server/request.h
+2
-0
trace.c
server/trace.c
+19
-1
No files found.
dlls/kernel/change.c
View file @
01932119
...
...
@@ -136,33 +136,46 @@ BOOL WINAPI ReadDirectoryChangesW( HANDLE handle, LPVOID buffer, DWORD len, BOOL
DWORD
filter
,
LPDWORD
returned
,
LPOVERLAPPED
overlapped
,
LPOVERLAPPED_COMPLETION_ROUTINE
completion
)
{
IO_STATUS_BLOCK
io
;
OVERLAPPED
ov
,
*
pov
;
IO_STATUS_BLOCK
*
ios
;
NTSTATUS
status
;
BOOL
ret
=
TRUE
;
HANDLE
event
;
TRACE
(
"%p %p %08lx %d %08lx %p %p %p
\n
"
,
handle
,
buffer
,
len
,
subtree
,
filter
,
returned
,
overlapped
,
completion
);
if
(
overlapped
)
event
=
overlapped
->
hEvent
;
if
(
!
overlapped
)
{
memset
(
&
ov
,
0
,
sizeof
ov
);
ov
.
hEvent
=
CreateEventW
(
NULL
,
0
,
0
,
NULL
);
pov
=
&
ov
;
}
else
event
=
CreateEventW
(
NULL
,
0
,
0
,
NULL
)
;
pov
=
overlapped
;
status
=
NtNotifyChangeDirectoryFile
(
handle
,
event
,
NULL
,
NULL
,
&
io
,
buffer
,
len
,
filter
,
subtree
);
if
(
status
!=
STATUS_PENDING
)
ios
=
(
PIO_STATUS_BLOCK
)
pov
;
ios
->
Status
=
STATUS_PENDING
;
ios
->
Information
=
0
;
status
=
NtNotifyChangeDirectoryFile
(
handle
,
pov
->
hEvent
,
NULL
,
NULL
,
ios
,
buffer
,
len
,
filter
,
subtree
);
if
(
status
==
STATUS_PENDING
)
{
if
(
overlapped
)
return
TRUE
;
WaitForSingleObjectEx
(
ov
.
hEvent
,
INFINITE
,
TRUE
);
CloseHandle
(
ov
.
hEvent
);
if
(
returned
)
*
returned
=
ios
->
Information
;
status
=
ios
->
Status
;
}
if
(
status
!=
STATUS_SUCCESS
)
{
SetLastError
(
RtlNtStatusToDosError
(
status
)
);
ret
=
FALSE
;
}
else
if
(
!
overlapped
)
WaitForSingleObject
(
event
,
INFINITE
);
else
overlapped
->
Internal
=
STATUS_PENDING
;
if
(
!
overlapped
)
CloseHandle
(
event
);
return
ret
;
}
dlls/ntdll/directory.c
View file @
01932119
...
...
@@ -1778,6 +1778,75 @@ done:
return
status
;
}
struct
read_changes_info
{
HANDLE
FileHandle
;
HANDLE
Event
;
PIO_APC_ROUTINE
ApcRoutine
;
PVOID
ApcContext
;
PVOID
Buffer
;
ULONG
BufferSize
;
};
static
void
WINAPI
read_changes_apc
(
void
*
user
,
PIO_STATUS_BLOCK
iosb
,
ULONG
status
)
{
struct
read_changes_info
*
info
=
user
;
char
path
[
PATH_MAX
];
NTSTATUS
ret
=
STATUS_SUCCESS
;
int
len
,
action
;
TRACE
(
"%p %p %p %08lx
\n
"
,
info
,
info
->
ApcContext
,
iosb
,
status
);
/*
* FIXME: race me!
*
* hEvent/hDir is set before the output buffer and iosb is updated.
* Since the thread that called NtNotifyChangeDirectoryFile is usually
* waiting, we'll be safe since we're called in that thread's context.
* If a different thread is waiting on our hEvent/hDir we're going to be
* in trouble...
*/
SERVER_START_REQ
(
read_change
)
{
req
->
handle
=
info
->
FileHandle
;
wine_server_set_reply
(
req
,
path
,
PATH_MAX
);
ret
=
wine_server_call
(
req
);
action
=
reply
->
action
;
len
=
wine_server_reply_size
(
reply
);
}
SERVER_END_REQ
;
if
(
ret
==
STATUS_SUCCESS
&&
info
->
Buffer
&&
(
info
->
BufferSize
>
(
sizeof
(
FILE_NOTIFY_INFORMATION
)
+
len
*
sizeof
(
WCHAR
))))
{
PFILE_NOTIFY_INFORMATION
pfni
;
pfni
=
(
PFILE_NOTIFY_INFORMATION
)
info
->
Buffer
;
len
=
ntdll_umbstowcs
(
0
,
path
,
len
,
pfni
->
FileName
,
info
->
BufferSize
-
sizeof
(
*
pfni
)
);
pfni
->
NextEntryOffset
=
0
;
pfni
->
Action
=
action
;
pfni
->
FileNameLength
=
len
*
sizeof
(
WCHAR
);
pfni
->
FileName
[
len
]
=
0
;
TRACE
(
"action = %ld name = %s
\n
"
,
pfni
->
Action
,
debugstr_w
(
pfni
->
FileName
)
);
len
=
sizeof
(
*
pfni
)
-
sizeof
(
DWORD
)
+
pfni
->
FileNameLength
;
}
else
{
ret
=
STATUS_NOTIFY_ENUM_DIR
;
len
=
0
;
}
iosb
->
u
.
Status
=
ret
;
iosb
->
Information
=
len
;
RtlFreeHeap
(
GetProcessHeap
(),
0
,
info
);
}
#define FILE_NOTIFY_ALL ( \
FILE_NOTIFY_CHANGE_FILE_NAME | \
FILE_NOTIFY_CHANGE_DIR_NAME | \
...
...
@@ -1797,6 +1866,7 @@ NtNotifyChangeDirectoryFile( HANDLE FileHandle, HANDLE Event,
PIO_STATUS_BLOCK
IoStatusBlock
,
PVOID
Buffer
,
ULONG
BufferSize
,
ULONG
CompletionFilter
,
BOOLEAN
WatchTree
)
{
struct
read_changes_info
*
info
;
NTSTATUS
status
;
TRACE
(
"%p %p %p %p %p %p %lu %lu %d
\n
"
,
...
...
@@ -1809,18 +1879,35 @@ NtNotifyChangeDirectoryFile( HANDLE FileHandle, HANDLE Event,
if
(
CompletionFilter
==
0
||
(
CompletionFilter
&
~
FILE_NOTIFY_ALL
))
return
STATUS_INVALID_PARAMETER
;
if
(
ApcRoutine
||
ApcContext
||
Buffer
||
BufferSize
||
WatchTree
)
FIXME
(
"parameters ignored %p %p %p %lu %d
\n
"
,
ApcRoutine
,
ApcContext
,
Buffer
,
BufferSize
,
WatchTree
);
if
(
WatchTree
||
ApcRoutine
)
FIXME
(
"parameters ignored %p %p %d
\n
"
,
ApcRoutine
,
ApcContext
,
WatchTree
);
info
=
RtlAllocateHeap
(
GetProcessHeap
(),
0
,
sizeof
*
info
);
if
(
!
info
)
return
STATUS_NO_MEMORY
;
info
->
FileHandle
=
FileHandle
;
info
->
Event
=
Event
;
info
->
Buffer
=
Buffer
;
info
->
BufferSize
=
BufferSize
;
info
->
ApcRoutine
=
ApcRoutine
;
info
->
ApcContext
=
ApcContext
;
SERVER_START_REQ
(
read_directory_changes
)
{
req
->
handle
=
FileHandle
;
req
->
event
=
Event
;
req
->
filter
=
CompletionFilter
;
req
->
io_apc
=
read_changes_apc
;
req
->
io_sb
=
IoStatusBlock
;
req
->
io_user
=
info
;
status
=
wine_server_call
(
req
);
}
SERVER_END_REQ
;
if
(
status
!=
STATUS_PENDING
)
RtlFreeHeap
(
GetProcessHeap
(),
0
,
info
);
return
status
;
}
include/wine/server_protocol.h
View file @
01932119
...
...
@@ -1401,6 +1401,9 @@ struct read_directory_changes_request
obj_handle_t
handle
;
obj_handle_t
event
;
unsigned
int
filter
;
void
*
io_apc
;
void
*
io_sb
;
void
*
io_user
;
};
struct
read_directory_changes_reply
{
...
...
@@ -1408,6 +1411,19 @@ struct read_directory_changes_reply
};
struct
read_change_request
{
struct
request_header
__header
;
obj_handle_t
handle
;
};
struct
read_change_reply
{
struct
reply_header
__header
;
int
action
;
/* VARARG(name,string); */
};
struct
create_mapping_request
{
...
...
@@ -3768,6 +3784,7 @@ enum request
REQ_move_console_output
,
REQ_send_console_signal
,
REQ_read_directory_changes
,
REQ_read_change
,
REQ_create_mapping
,
REQ_open_mapping
,
REQ_get_mapping_info
,
...
...
@@ -3986,6 +4003,7 @@ union generic_request
struct
move_console_output_request
move_console_output_request
;
struct
send_console_signal_request
send_console_signal_request
;
struct
read_directory_changes_request
read_directory_changes_request
;
struct
read_change_request
read_change_request
;
struct
create_mapping_request
create_mapping_request
;
struct
open_mapping_request
open_mapping_request
;
struct
get_mapping_info_request
get_mapping_info_request
;
...
...
@@ -4202,6 +4220,7 @@ union generic_reply
struct
move_console_output_reply
move_console_output_reply
;
struct
send_console_signal_reply
send_console_signal_reply
;
struct
read_directory_changes_reply
read_directory_changes_reply
;
struct
read_change_reply
read_change_reply
;
struct
create_mapping_reply
create_mapping_reply
;
struct
open_mapping_reply
open_mapping_reply
;
struct
get_mapping_info_reply
get_mapping_info_reply
;
...
...
@@ -4344,6 +4363,6 @@ union generic_reply
struct
query_symlink_reply
query_symlink_reply
;
};
#define SERVER_PROTOCOL_VERSION 22
3
#define SERVER_PROTOCOL_VERSION 22
4
#endif
/* __WINE_WINE_SERVER_PROTOCOL_H */
server/change.c
View file @
01932119
...
...
@@ -126,6 +126,13 @@ static inline int inotify_remove_watch( int fd, int wd )
#endif
struct
change_record
{
struct
list
entry
;
int
action
;
int
len
;
char
name
[
1
];
};
struct
dir
{
struct
object
obj
;
/* object header */
...
...
@@ -137,6 +144,8 @@ struct dir
long
signaled
;
/* the file changed */
struct
fd
*
inotify_fd
;
/* inotify file descriptor */
int
wd
;
/* inotify watch descriptor */
struct
list
change_q
;
/* change readers */
struct
list
change_records
;
/* data for the change */
};
static
struct
fd
*
dir_get_fd
(
struct
object
*
obj
);
...
...
@@ -163,6 +172,7 @@ static const struct object_ops dir_ops =
static
int
dir_get_poll_events
(
struct
fd
*
fd
);
static
int
dir_get_info
(
struct
fd
*
fd
);
static
void
dir_cancel_async
(
struct
fd
*
fd
);
static
const
struct
fd_ops
dir_fd_ops
=
{
...
...
@@ -171,7 +181,7 @@ static const struct fd_ops dir_fd_ops =
no_flush
,
/* flush */
dir_get_info
,
/* get_file_info */
default_fd_queue_async
,
/* queue_async */
d
efault_fd_cancel_async
/* cancel_async */
d
ir_cancel_async
/* cancel_async */
};
static
struct
list
change_list
=
LIST_INIT
(
change_list
);
...
...
@@ -238,6 +248,8 @@ struct object *create_dir_obj( struct fd *fd )
if
(
!
dir
)
return
NULL
;
list_init
(
&
dir
->
change_q
);
list_init
(
&
dir
->
change_records
);
dir
->
event
=
NULL
;
dir
->
filter
=
0
;
dir
->
notified
=
0
;
...
...
@@ -321,8 +333,17 @@ static unsigned int dir_map_access( struct object *obj, unsigned int access )
return
access
&
~
(
GENERIC_READ
|
GENERIC_WRITE
|
GENERIC_EXECUTE
|
GENERIC_ALL
);
}
static
struct
change_record
*
get_first_change_record
(
struct
dir
*
dir
)
{
struct
list
*
ptr
=
list_head
(
&
dir
->
change_records
);
if
(
!
ptr
)
return
NULL
;
list_remove
(
ptr
);
return
LIST_ENTRY
(
ptr
,
struct
change_record
,
entry
);
}
static
void
dir_destroy
(
struct
object
*
obj
)
{
struct
change_record
*
record
;
struct
dir
*
dir
=
(
struct
dir
*
)
obj
;
assert
(
obj
->
ops
==
&
dir_ops
);
...
...
@@ -332,6 +353,9 @@ static void dir_destroy( struct object *obj )
if
(
dir
->
inotify_fd
)
release_object
(
dir
->
inotify_fd
);
async_terminate_queue
(
&
dir
->
change_q
,
STATUS_CANCELLED
);
while
((
record
=
get_first_change_record
(
dir
)))
free
(
record
);
if
(
dir
->
event
)
{
set_event
(
dir
->
event
);
...
...
@@ -356,6 +380,12 @@ static int dir_get_info( struct fd *fd )
return
0
;
}
static
void
dir_cancel_async
(
struct
fd
*
fd
)
{
struct
dir
*
dir
=
(
struct
dir
*
)
get_fd_user
(
fd
);
async_terminate_queue
(
&
dir
->
change_q
,
STATUS_CANCELLED
);
}
#ifdef USE_INOTIFY
...
...
@@ -378,10 +408,32 @@ static int inotify_get_poll_events( struct fd *fd )
return
POLLIN
;
}
static
void
inotify_do_change_notify
(
struct
dir
*
dir
)
static
void
inotify_do_change_notify
(
struct
dir
*
dir
,
struct
inotify_event
*
ie
)
{
dir
->
signaled
++
;
dir_signal_changed
(
dir
);
struct
change_record
*
record
;
record
=
malloc
(
sizeof
(
*
record
)
+
ie
->
len
-
1
)
;
if
(
!
record
)
return
;
if
(
ie
->
mask
&
IN_CREATE
)
record
->
action
=
FILE_ACTION_ADDED
;
else
if
(
ie
->
mask
&
IN_DELETE
)
record
->
action
=
FILE_ACTION_REMOVED
;
else
record
->
action
=
FILE_ACTION_MODIFIED
;
memcpy
(
record
->
name
,
ie
->
name
,
ie
->
len
);
record
->
len
=
strlen
(
ie
->
name
);
list_add_tail
(
&
dir
->
change_records
,
&
record
->
entry
);
if
(
!
list_empty
(
&
dir
->
change_q
))
async_terminate_head
(
&
dir
->
change_q
,
STATUS_ALERTED
);
else
{
dir
->
signaled
++
;
dir_signal_changed
(
dir
);
}
}
static
void
inotify_poll_event
(
struct
fd
*
fd
,
int
event
)
...
...
@@ -404,7 +456,7 @@ static void inotify_poll_event( struct fd *fd, int event )
ie
=
(
struct
inotify_event
*
)
&
buffer
[
ofs
];
if
(
!
ie
->
len
)
break
;
inotify_do_change_notify
(
dir
);
inotify_do_change_notify
(
dir
,
ie
);
ofs
+=
(
sizeof
(
*
ie
)
+
ie
->
len
-
1
);
}
}
...
...
@@ -489,6 +541,11 @@ DECL_HANDLER(read_directory_changes)
if
(
dir
->
event
)
release_object
(
dir
->
event
);
dir
->
event
=
event
;
/* requests don't timeout */
if
(
req
->
io_apc
&&
!
create_async
(
current
,
NULL
,
&
dir
->
change_q
,
req
->
io_apc
,
req
->
io_user
,
req
->
io_sb
))
return
;
/* assign it once */
if
(
!
dir
->
filter
)
{
...
...
@@ -511,3 +568,28 @@ DECL_HANDLER(read_directory_changes)
end
:
release_object
(
dir
);
}
DECL_HANDLER
(
read_change
)
{
struct
change_record
*
record
;
struct
dir
*
dir
;
dir
=
get_dir_obj
(
current
->
process
,
req
->
handle
,
0
);
if
(
!
dir
)
return
;
if
((
record
=
get_first_change_record
(
dir
))
!=
NULL
)
{
reply
->
action
=
record
->
action
;
set_reply_data
(
record
->
name
,
record
->
len
);
free
(
record
);
}
else
set_error
(
STATUS_NO_DATA_DETECTED
);
/* now signal it */
dir
->
signaled
++
;
dir_signal_changed
(
dir
);
release_object
(
dir
);
}
server/protocol.def
View file @
01932119
...
...
@@ -1045,6 +1045,17 @@ enum char_info_mode
obj_handle_t handle; /* handle to the directory */
obj_handle_t event; /* handle to the event */
unsigned int filter; /* notification filter */
void* io_apc; /* APC routine to queue upon end of async */
void* io_sb; /* I/O status block (unique across all async on this handle) */
void* io_user; /* data to pass back to caller */
@END
@REQ(read_change)
obj_handle_t handle;
@REPLY
int action; /* type of change */
VARARG(name,string); /* name of directory entry that changed */
@END
...
...
server/request.h
View file @
01932119
...
...
@@ -181,6 +181,7 @@ DECL_HANDLER(read_console_output);
DECL_HANDLER
(
move_console_output
);
DECL_HANDLER
(
send_console_signal
);
DECL_HANDLER
(
read_directory_changes
);
DECL_HANDLER
(
read_change
);
DECL_HANDLER
(
create_mapping
);
DECL_HANDLER
(
open_mapping
);
DECL_HANDLER
(
get_mapping_info
);
...
...
@@ -398,6 +399,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(
req_handler
)
req_move_console_output
,
(
req_handler
)
req_send_console_signal
,
(
req_handler
)
req_read_directory_changes
,
(
req_handler
)
req_read_change
,
(
req_handler
)
req_create_mapping
,
(
req_handler
)
req_open_mapping
,
(
req_handler
)
req_get_mapping_info
,
...
...
server/trace.c
View file @
01932119
...
...
@@ -1448,7 +1448,22 @@ static void dump_read_directory_changes_request( const struct read_directory_cha
{
fprintf
(
stderr
,
" handle=%p,"
,
req
->
handle
);
fprintf
(
stderr
,
" event=%p,"
,
req
->
event
);
fprintf
(
stderr
,
" filter=%08x"
,
req
->
filter
);
fprintf
(
stderr
,
" filter=%08x,"
,
req
->
filter
);
fprintf
(
stderr
,
" io_apc=%p,"
,
req
->
io_apc
);
fprintf
(
stderr
,
" io_sb=%p,"
,
req
->
io_sb
);
fprintf
(
stderr
,
" io_user=%p"
,
req
->
io_user
);
}
static
void
dump_read_change_request
(
const
struct
read_change_request
*
req
)
{
fprintf
(
stderr
,
" handle=%p"
,
req
->
handle
);
}
static
void
dump_read_change_reply
(
const
struct
read_change_reply
*
req
)
{
fprintf
(
stderr
,
" action=%d,"
,
req
->
action
);
fprintf
(
stderr
,
" name="
);
dump_varargs_string
(
cur_size
);
}
static
void
dump_create_mapping_request
(
const
struct
create_mapping_request
*
req
)
...
...
@@ -3274,6 +3289,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(
dump_func
)
dump_move_console_output_request
,
(
dump_func
)
dump_send_console_signal_request
,
(
dump_func
)
dump_read_directory_changes_request
,
(
dump_func
)
dump_read_change_request
,
(
dump_func
)
dump_create_mapping_request
,
(
dump_func
)
dump_open_mapping_request
,
(
dump_func
)
dump_get_mapping_info_request
,
...
...
@@ -3488,6 +3504,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(
dump_func
)
0
,
(
dump_func
)
0
,
(
dump_func
)
0
,
(
dump_func
)
dump_read_change_reply
,
(
dump_func
)
dump_create_mapping_reply
,
(
dump_func
)
dump_open_mapping_reply
,
(
dump_func
)
dump_get_mapping_info_reply
,
...
...
@@ -3702,6 +3719,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"move_console_output"
,
"send_console_signal"
,
"read_directory_changes"
,
"read_change"
,
"create_mapping"
,
"open_mapping"
,
"get_mapping_info"
,
...
...
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