Mike McCormack : server:
Distinguish between a directory and a file changing in
Alexandre Julliard
julliard at wine.codeweavers.com
Mon Feb 20 05:41:35 CST 2006
Module: wine
Branch: refs/heads/master
Commit: a2813f7c2ef879fee94948eb4f935448e2f48152
URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=a2813f7c2ef879fee94948eb4f935448e2f48152
Author: Mike McCormack <mike at codeweavers.com>
Date: Mon Feb 20 12:28:46 2006 +0100
server: Distinguish between a directory and a file changing in
ReadDirectoryChangesW.
Add a test for it.
---
dlls/kernel/tests/change.c | 80 ++++++++++++++++++++++++++++++++++++++++++++
server/change.c | 67 +++++++++++++++++++++++++++++++------
2 files changed, 136 insertions(+), 11 deletions(-)
diff --git a/dlls/kernel/tests/change.c b/dlls/kernel/tests/change.c
index 3c8e245..dfdaa9e 100644
--- a/dlls/kernel/tests/change.c
+++ b/dlls/kernel/tests/change.c
@@ -560,6 +560,85 @@ static void test_readdirectorychanges_nu
ok( r == TRUE, "failed to remove directory\n");
}
+static void test_readdirectorychanges_filedir(void)
+{
+ NTSTATUS r;
+ HANDLE hdir, hfile;
+ char buffer[0x1000];
+ DWORD fflags, filter = 0;
+ OVERLAPPED ov;
+ WCHAR path[MAX_PATH], subdir[MAX_PATH], file[MAX_PATH];
+ static const WCHAR szBoo[] = { '\\','b','o','o',0 };
+ static const WCHAR szHoo[] = { '\\','h','o','o',0 };
+ static const WCHAR szFoo[] = { '\\','f','o','o',0 };
+ PFILE_NOTIFY_INFORMATION pfni;
+
+ r = GetTempPathW( MAX_PATH, path );
+ ok( r != 0, "temp path failed\n");
+ if (!r)
+ return;
+
+ lstrcatW( path, szBoo );
+ lstrcpyW( subdir, path );
+ lstrcatW( subdir, szHoo );
+
+ lstrcpyW( file, path );
+ lstrcatW( file, szFoo );
+
+ DeleteFileW( file );
+ RemoveDirectoryW( subdir );
+ RemoveDirectoryW( path );
+
+ r = CreateDirectoryW(path, NULL);
+ ok( r == TRUE, "failed to create directory\n");
+
+ fflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED;
+ hdir = CreateFileW(path, GENERIC_READ|SYNCHRONIZE|FILE_LIST_DIRECTORY,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, fflags, NULL);
+ ok( hdir != INVALID_HANDLE_VALUE, "failed to open directory\n");
+
+ ov.hEvent = CreateEvent( NULL, 0, 0, NULL );
+
+ filter = FILE_NOTIFY_CHANGE_FILE_NAME;
+
+ r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,TRUE,filter,NULL,&ov,NULL);
+ ok(r==TRUE, "should return true\n");
+
+ r = WaitForSingleObject( ov.hEvent, 10 );
+ ok( r == WAIT_TIMEOUT, "should timeout\n" );
+
+ r = CreateDirectoryW( subdir, NULL );
+ ok( r == TRUE, "failed to create directory\n");
+
+ hfile = CreateFileW( file, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
+ ok( hfile != INVALID_HANDLE_VALUE, "failed to create file\n");
+ ok( CloseHandle(hfile), "failed toc lose file\n");
+
+ r = WaitForSingleObject( ov.hEvent, INFINITE );
+ ok( r == WAIT_OBJECT_0, "event should be ready\n" );
+
+ ok( ov.Internal == STATUS_SUCCESS, "ov.Internal wrong\n");
+ ok( ov.InternalHigh == 0x12, "ov.InternalHigh wrong\n");
+
+ pfni = (PFILE_NOTIFY_INFORMATION) buffer;
+ ok( pfni->NextEntryOffset == 0, "offset wrong\n" );
+ ok( pfni->Action == FILE_ACTION_ADDED, "action wrong\n" );
+ ok( pfni->FileNameLength == 6, "len wrong\n" );
+ ok( !memcmp(pfni->FileName,&szFoo[1],6), "name wrong\n" );
+
+ r = DeleteFileW( file );
+ ok( r == TRUE, "failed to delete file\n");
+
+ r = RemoveDirectoryW( subdir );
+ ok( r == TRUE, "failed to remove directory\n");
+
+ CloseHandle(hdir);
+
+ r = RemoveDirectoryW( path );
+ ok( r == TRUE, "failed to remove directory\n");
+}
+
START_TEST(change)
{
HMODULE hkernel32 = GetModuleHandle("kernel32");
@@ -570,4 +649,5 @@ START_TEST(change)
test_ffcn();
test_readdirectorychanges();
test_readdirectorychanges_null();
+ test_readdirectorychanges_filedir();
}
diff --git a/server/change.c b/server/change.c
index aa8e0cb..d0de942 100644
--- a/server/change.c
+++ b/server/change.c
@@ -485,24 +485,20 @@ static int inotify_get_poll_events( stru
return POLLIN;
}
-static void inotify_do_change_notify( struct dir *dir, struct inotify_event *ie )
+static void inotify_do_change_notify( struct dir *dir, unsigned int action,
+ const char *relpath )
{
struct change_record *record;
if (dir->want_data)
{
- size_t len = strlen(ie->name);
+ size_t len = strlen(relpath);
record = malloc( offsetof(struct change_record, name[len]) );
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, len );
+ record->action = action;
+ memcpy( record->name, relpath, len );
record->len = len;
list_add_tail( &dir->change_records, &record->entry );
@@ -535,11 +531,39 @@ static unsigned int filter_from_event( s
return filter;
}
+static int inode_entry_is_dir( struct inode *inode, const char *name )
+{
+ /* distinguish a created file from a directory */
+ char *path;
+ struct list *head;
+ struct stat st;
+ int unix_fd, r;
+
+ head = list_head( &inode->dirs );
+ if (!head)
+ return -1;
+
+ path = malloc( strlen(name) + 32 );
+ if (!path)
+ return -1;
+
+ unix_fd = get_unix_fd( LIST_ENTRY( head, struct dir, in_entry )->fd );
+ sprintf( path, "/proc/self/fd/%u/%s", unix_fd, name );
+ r = stat( path, &st );
+ free( path );
+ if (-1 == r)
+ return -1;
+
+ if (S_ISDIR(st.st_mode))
+ return 1;
+ return 0;
+}
+
static void inotify_notify_all( struct inotify_event *ie )
{
+ unsigned int filter, action;
struct inode *inode;
struct dir *dir;
- unsigned int filter;
inode = inode_from_wd( ie->wd );
if (!inode)
@@ -549,10 +573,31 @@ static void inotify_notify_all( struct i
}
filter = filter_from_event( ie );
+
+ if (ie->mask & IN_CREATE)
+ {
+ switch (inode_entry_is_dir( inode, ie->name ))
+ {
+ case 1:
+ filter &= ~FILE_NOTIFY_CHANGE_FILE_NAME;
+ break;
+ case 0:
+ filter &= ~FILE_NOTIFY_CHANGE_DIR_NAME;
+ break;
+ default:
+ break;
+ /* Maybe the file disappeared before we could check it? */
+ }
+ action = FILE_ACTION_ADDED;
+ }
+ else if (ie->mask & IN_DELETE)
+ action = FILE_ACTION_REMOVED;
+ else
+ action = FILE_ACTION_MODIFIED;
LIST_FOR_EACH_ENTRY( dir, &inode->dirs, struct dir, in_entry )
if (filter & dir->filter)
- inotify_do_change_notify( dir, ie );
+ inotify_do_change_notify( dir, action, ie->name );
}
static void inotify_poll_event( struct fd *fd, int event )
More information about the wine-cvs
mailing list