[ros-diffs] [weiden] 27667: - Fix caching of directory queries, FindFirstFile(Ex) should no longer return garbage occasionally - These changes re-introduce the problem with searches for fake DOS devices that I claimed to have fixed in r27634

weiden at svn.reactos.org weiden at svn.reactos.org
Sun Jul 15 00:29:42 CEST 2007


Author: weiden
Date: Sun Jul 15 02:29:42 2007
New Revision: 27667

URL: http://svn.reactos.org/svn/reactos?rev=27667&view=rev
Log:
- Fix caching of directory queries, FindFirstFile(Ex) should no longer return garbage occasionally
- These changes re-introduce the problem with searches for fake DOS devices that I claimed to have fixed in r27634

Modified:
    trunk/reactos/dll/win32/kernel32/file/find.c

Modified: trunk/reactos/dll/win32/kernel32/file/find.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/file/find.c?rev=27667&r1=27666&r2=27667&view=diff
==============================================================================
--- trunk/reactos/dll/win32/kernel32/file/find.c (original)
+++ trunk/reactos/dll/win32/kernel32/file/find.c Sun Jul 15 02:29:42 2007
@@ -19,15 +19,19 @@
 
 /* TYPES ********************************************************************/
 
-#define FIND_DATA_SIZE	(16*1024)
+#define FIND_DATA_SIZE	0x4000
 
 #define FIND_DEVICE_HANDLE ((HANDLE)0x1)
 
 typedef struct _KERNEL32_FIND_FILE_DATA
 {
    HANDLE DirectoryHandle;
+   RTL_CRITICAL_SECTION Lock;
+   PFILE_BOTH_DIR_INFORMATION pFileInfo;
    BOOLEAN DirectoryOnly;
-   PFILE_BOTH_DIR_INFORMATION pFileInfo;
+   BOOLEAN HasMoreData;
+   BOOLEAN HasData;
+   BOOLEAN LockInitialized;
 } KERNEL32_FIND_FILE_DATA, *PKERNEL32_FIND_FILE_DATA;
 
 typedef struct _KERNEL32_FIND_STREAM_DATA
@@ -51,7 +55,7 @@
 
 /* FUNCTIONS ****************************************************************/
 
-HANDLE
+static HANDLE
 InternalCopyDeviceFindDataW(LPWIN32_FIND_DATAW lpFindFileData,
                             LPCWSTR lpFileName,
                             ULONG DeviceNameInfo)
@@ -72,7 +76,7 @@
     return FIND_DEVICE_HANDLE;
 }
 
-HANDLE
+static HANDLE
 InternalCopyDeviceFindDataA(LPWIN32_FIND_DATAA lpFindFileData,
                             PUNICODE_STRING FileName,
                             ULONG DeviceNameInfo)
@@ -90,10 +94,6 @@
         RtlUnicodeStringToAnsiString (&BufferA, &DeviceName, FALSE);
     else
         RtlUnicodeStringToOemString (&BufferA, &DeviceName, FALSE);
-
-    /* NOTE: Free the string before we try to write the results to the caller,
-             this way we prevent a memory leak in case of a fault... */
-    RtlFreeUnicodeString(FileName);
 
     /* Return the data */
     RtlZeroMemory(lpFindFileData,
@@ -106,7 +106,7 @@
     return FIND_DEVICE_HANDLE;
 }
 
-VOID
+static VOID
 InternalCopyFindDataW(LPWIN32_FIND_DATAW            lpFindFileData,
                       PFILE_BOTH_DIR_INFORMATION    lpFileInfo)
 {
@@ -131,7 +131,7 @@
     lpFindFileData->cAlternateFileName[lpFileInfo->ShortNameLength / sizeof(WCHAR)] = 0;
 }
 
-VOID
+static VOID
 InternalCopyFindDataA(LPWIN32_FIND_DATAA            lpFindFileData,
                       PFILE_BOTH_DIR_INFORMATION    lpFileInfo)
 {
@@ -189,23 +189,23 @@
 BOOL
 STDCALL
 InternalFindNextFile (
-	HANDLE	hFindFile,
-        PUNICODE_STRING SearchPattern
-	)
-{
-	PKERNEL32_FIND_DATA_HEADER IHeader;
-	PKERNEL32_FIND_FILE_DATA IData;
-	IO_STATUS_BLOCK IoStatusBlock;
-	NTSTATUS Status;
-
-	DPRINT("InternalFindNextFile(%lx)\n", hFindFile);
-
-    if (hFindFile == FIND_DEVICE_HANDLE)
-    {
-        SetLastError (ERROR_NO_MORE_FILES);
-        return FALSE;
-    }
-
+    HANDLE	hFindFile,
+    PUNICODE_STRING SearchPattern,
+    PVOID lpFindFileData,
+    BOOL bUnicode
+    )
+{
+    PKERNEL32_FIND_DATA_HEADER IHeader;
+    PKERNEL32_FIND_FILE_DATA IData;
+    IO_STATUS_BLOCK IoStatusBlock;
+    BOOLEAN Locked = FALSE;
+    PFILE_BOTH_DIR_INFORMATION Buffer, FoundFile = NULL;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    DPRINT("InternalFindNextFile(%lx, %wZ)\n", hFindFile, SearchPattern);
+
+    if (hFindFile != FIND_DEVICE_HANDLE)
+    {
         IHeader = (PKERNEL32_FIND_DATA_HEADER)hFindFile;
         if (hFindFile == NULL || hFindFile == INVALID_HANDLE_VALUE ||
             IHeader->Type != FileFind)
@@ -215,41 +215,119 @@
         }
 
         IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
-
-        while (1)
-        {
-            if (IData->pFileInfo->NextEntryOffset != 0)
-	    {
-	        IData->pFileInfo = (PVOID)((ULONG_PTR)IData->pFileInfo + IData->pFileInfo->NextEntryOffset);
+        Buffer = (PFILE_BOTH_DIR_INFORMATION)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA));
+
+        if (SearchPattern == NULL)
+        {
+            RtlEnterCriticalSection(&IData->Lock);
+            Locked = TRUE;
+        }
+
+        do
+        {
+            if (IData->HasData)
+            {
+                if (!IData->DirectoryOnly || (IData->pFileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+                {
+                    FoundFile = IData->pFileInfo;
+                }
+
+                if (IData->pFileInfo->NextEntryOffset != 0)
+                {
+                    ULONG_PTR BufferEnd;
+
+                    IData->pFileInfo = (PFILE_BOTH_DIR_INFORMATION)((ULONG_PTR)IData->pFileInfo + IData->pFileInfo->NextEntryOffset);
+
+                    /* Be paranoid and make sure that the next entry is completely there */
+                    BufferEnd = (ULONG_PTR)Buffer + FIND_DATA_SIZE;
+                    if (BufferEnd < (ULONG_PTR)IData->pFileInfo ||
+                        BufferEnd < (ULONG_PTR)&IData->pFileInfo->FileNameLength + sizeof(IData->pFileInfo->FileNameLength) ||
+                        BufferEnd <= (ULONG_PTR)&IData->pFileInfo->FileName[IData->pFileInfo->FileNameLength])
+                    {
+                        goto NeedMoreData;
+                    }
+                }
+                else
+                {
+NeedMoreData:
+                    IData->HasData = FALSE;
+
+                    if (!IData->HasMoreData)
+                        break;
+                }
             }
             else
             {
-                IData->pFileInfo = (PVOID)((ULONG_PTR)IData + sizeof(KERNEL32_FIND_FILE_DATA));
-	        IData->pFileInfo->FileIndex = 0;
-	        Status = NtQueryDirectoryFile (IData->DirectoryHandle,
-	                                       NULL,
+                IData->pFileInfo = Buffer;
+                IData->pFileInfo->NextEntryOffset = 0;
+                Status = NtQueryDirectoryFile (IData->DirectoryHandle,
+                                               NULL,
                                                NULL,
                                                NULL,
                                                &IoStatusBlock,
                                                (PVOID)IData->pFileInfo,
                                                FIND_DATA_SIZE,
                                                FileBothDirectoryInformation,
-                                               SearchPattern ? TRUE : FALSE,
+                                               FALSE,
                                                SearchPattern,
-                                               SearchPattern ? TRUE : FALSE);
+                                               SearchPattern != NULL);
+
+                if (Status == STATUS_BUFFER_OVERFLOW)
+                {
+                    IData->HasMoreData = TRUE;
+                    Status = STATUS_SUCCESS;
+                }
+                else
+                {
+                    if (!NT_SUCCESS(Status))
+                        break;
+
+                    IData->HasMoreData = FALSE;
+                }
+
+                IData->HasData = TRUE;
                 SearchPattern = NULL;
-                if (!NT_SUCCESS(Status))
+            }
+
+        } while (FoundFile == NULL);
+
+        if (FoundFile != NULL)
+        {
+            _SEH_TRY
+            {
+                if (bUnicode)
                 {
-                    SetLastErrorByStatus (Status);
-                    return FALSE;
-	        }
+                    InternalCopyFindDataW(lpFindFileData,
+                                          FoundFile);
+                }
+                else
+                {
+                    InternalCopyFindDataA(lpFindFileData,
+                                          FoundFile);
+                }
             }
-            if (!IData->DirectoryOnly || IData->pFileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+            _SEH_HANDLE
             {
-	        DPRINT("Found %.*S\n",IData->pFileInfo->FileNameLength/sizeof(WCHAR), IData->pFileInfo->FileName);
-	        return TRUE;
             }
+            _SEH_END;
         }
+
+        if (Locked)
+            RtlLeaveCriticalSection(&IData->Lock);
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        SetLastErrorByStatus (Status);
+        return FALSE;
+    }
+    else if (FoundFile == NULL)
+    {
+        SetLastError (ERROR_NO_MORE_FILES);
+        return FALSE;
+    }
+
+    return TRUE;
 }
 
 
@@ -261,7 +339,8 @@
 InternalFindFirstFile (
     LPCWSTR	lpFileName,
     BOOLEAN DirectoryOnly,
-    PULONG DeviceNameInfo
+    PVOID lpFindFileData,
+    BOOL bUnicode
 	)
 {
 	OBJECT_ATTRIBUTES ObjectAttributes;
@@ -274,12 +353,12 @@
 	BOOLEAN RemovedSlash = FALSE;
 	BOOL bResult;
 	CURDIR DirInfo;
-    HANDLE hDirectory = NULL;
+	ULONG DeviceNameInfo;
+	HANDLE hDirectory = NULL;
 
 	DPRINT("FindFirstFileW(lpFileName %S)\n",
 	       lpFileName);
 
-	*DeviceNameInfo = 0;
 	RtlZeroMemory(&PathFileName,
 	              sizeof(PathFileName));
 	RtlInitUnicodeString(&FileName,
@@ -329,8 +408,8 @@
 
 	/* Remove a trailing backslash from the path, unless it's a DOS drive directly */
 	if (NtPathU.Length > 3 * sizeof(WCHAR) &&
-	    NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 2] != L':' &&
-	    NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 1] != L'\\')
+	    NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 1] == L'\\' &&
+	    NtPathU.Buffer[(NtPathU.Length / sizeof(WCHAR)) - 2] != L':')
 	{
 	    NtPathU.Length -= sizeof(WCHAR);
 	    RemovedSlash = TRUE;
@@ -348,11 +427,11 @@
 	                            NULL);
 
 	Status = NtOpenFile (&hDirectory,
-	                     FILE_LIST_DIRECTORY,
+	                     FILE_LIST_DIRECTORY | SYNCHRONIZE,
 	                     &ObjectAttributes,
 	                     &IoStatusBlock,
 	                     FILE_SHARE_READ|FILE_SHARE_WRITE,
-	                     FILE_DIRECTORY_FILE);
+	                     FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
 
 	if (!NT_SUCCESS(Status) && RemovedSlash)
 	{
@@ -360,25 +439,38 @@
 	    NtPathU.Length -= sizeof(WCHAR);
 
 	    Status = NtOpenFile (&hDirectory,
-	                         FILE_LIST_DIRECTORY,
+	                         FILE_LIST_DIRECTORY | SYNCHRONIZE,
 	                         &ObjectAttributes,
 	                         &IoStatusBlock,
 	                         FILE_SHARE_READ|FILE_SHARE_WRITE,
-	                         FILE_DIRECTORY_FILE);
-
-	    NtPathU.Length -= sizeof(WCHAR);
+	                         FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
 	}
 
 	if (!NT_SUCCESS(Status))
 	{
-	    RtlFreeHeap (hProcessHeap,
-	                 0,
-	                 NtPathBuffer);
+	   RtlFreeHeap (hProcessHeap,
+	                0,
+	                NtPathBuffer);
 
 	   /* See if the application tries to look for a DOS device */
-	   *DeviceNameInfo = RtlIsDosDeviceName_U((PWSTR)((ULONG_PTR)lpFileName));
-	   if (*DeviceNameInfo != 0)
+	   DeviceNameInfo = RtlIsDosDeviceName_U((PWSTR)((ULONG_PTR)lpFileName));
+	   if (DeviceNameInfo != 0)
+	   {
+	       if (bUnicode)
+	       {
+	           InternalCopyDeviceFindDataW(lpFindFileData,
+	                                       lpFileName,
+	                                       DeviceNameInfo);
+	       }
+	       else
+	       {
+	           InternalCopyDeviceFindDataA(lpFindFileData,
+	                                       &FileName,
+	                                       DeviceNameInfo);
+	       }
+
 	       return FIND_DEVICE_HANDLE;
+	   }
 
 	   SetLastErrorByStatus (Status);
 	   return(NULL);
@@ -413,6 +505,7 @@
 	IHeader->Type = FileFind;
 	IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
 	IData->DirectoryHandle = hDirectory;
+	IData->HasMoreData = TRUE;
 
 	/* change pattern: "*.*" --> "*" */
 	if (PathFileName.Length == 6 &&
@@ -427,7 +520,10 @@
 	IData->pFileInfo->FileIndex = 0;
 	IData->DirectoryOnly = DirectoryOnly;
 
-	bResult = InternalFindNextFile((HANDLE)IHeader, &PathFileName);
+	bResult = InternalFindNextFile((HANDLE)IHeader,
+	                               &PathFileName,
+	                               lpFindFileData,
+	                               bUnicode);
 
 	RtlFreeHeap (hProcessHeap,
 	             0,
@@ -438,6 +534,9 @@
 	    FindClose((HANDLE)IHeader);
 	    return NULL;
 	}
+
+	RtlInitializeCriticalSection(&IData->Lock);
+	IData->LockInitialized = TRUE;
 
 	return (HANDLE)IHeader;
 }
@@ -453,52 +552,12 @@
 	LPWIN32_FIND_DATAA	lpFindFileData
 	)
 {
-	PKERNEL32_FIND_DATA_HEADER IHeader;
-	PKERNEL32_FIND_FILE_DATA IData;
-	UNICODE_STRING FileNameU;
-	ANSI_STRING FileName;
-	ULONG DeviceNameInfo;
-
-	RtlInitAnsiString (&FileName,
-	                   (LPSTR)lpFileName);
-
-	/* convert ansi (or oem) string to unicode */
-	if (bIsFileApiAnsi)
-		RtlAnsiStringToUnicodeString (&FileNameU,
-		                              &FileName,
-		                              TRUE);
-	else
-		RtlOemStringToUnicodeString (&FileNameU,
-		                             &FileName,
-		                             TRUE);
-
-	IHeader = InternalFindFirstFile (FileNameU.Buffer, FALSE, &DeviceNameInfo);
-
-	if (IHeader == NULL)
-	{
-		RtlFreeUnicodeString (&FileNameU);
-		DPRINT("Failing request\n");
-		return INVALID_HANDLE_VALUE;
-	}
-
-	if ((HANDLE)IHeader == FIND_DEVICE_HANDLE)
-	{
-		/* NOTE: FileNameU will be freed in InternalCopyDeviceFindDataA */
-		return InternalCopyDeviceFindDataA(lpFindFileData, &FileNameU, DeviceNameInfo);
-	}
-
-	RtlFreeUnicodeString (&FileNameU);
-
-	IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
-
-	DPRINT("IData->pFileInfo->FileNameLength %d\n",
-	       IData->pFileInfo->FileNameLength);
-
-	/* copy data into WIN32_FIND_DATA structure */
-        InternalCopyFindDataA(lpFindFileData, IData->pFileInfo);
-
-
-	return (HANDLE)IHeader;
+	return FindFirstFileExA (lpFileName,
+	                         FindExInfoStandard,
+	                         (LPVOID)lpFindFileData,
+	                         FindExSearchNameMatch,
+	                         NULL,
+	                         0);
 }
 
 
@@ -511,23 +570,10 @@
 	HANDLE hFindFile,
 	LPWIN32_FIND_DATAA lpFindFileData)
 {
-	PKERNEL32_FIND_FILE_DATA IData;
-
-	if (!InternalFindNextFile (hFindFile, NULL))
-	{
-		DPRINT("InternalFindNextFile() failed\n");
-		return FALSE;
-	}
-
-	IData = (PKERNEL32_FIND_FILE_DATA)((PKERNEL32_FIND_DATA_HEADER)hFindFile + 1);
-
-	DPRINT("IData->pFileInfo->FileNameLength %d\n",
-	       IData->pFileInfo->FileNameLength);
-
-	/* copy data into WIN32_FIND_DATA structure */
-        InternalCopyFindDataA(lpFindFileData, IData->pFileInfo);
-
-	return TRUE;
+	return InternalFindNextFile (hFindFile,
+	                             NULL,
+	                             lpFindFileData,
+	                             FALSE);
 }
 
 
@@ -561,6 +607,8 @@
 		{
 			PKERNEL32_FIND_FILE_DATA IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
 			CloseHandle (IData->DirectoryHandle);
+			if (IData->LockInitialized)
+				RtlDeleteCriticalSection(&IData->Lock);
 			break;
 		}
 
@@ -595,13 +643,12 @@
 	LPWIN32_FIND_DATAW	lpFindFileData
 	)
 {
-
-        return FindFirstFileExW (lpFileName,
-                                 FindExInfoStandard,
-                                 (LPVOID)lpFindFileData,
-                                 FindExSearchNameMatch,
-                                 NULL,
-                                 0);
+    return FindFirstFileExW (lpFileName,
+                             FindExInfoStandard,
+                             (LPVOID)lpFindFileData,
+                             FindExSearchNameMatch,
+                             NULL,
+                             0);
 }
 
 /*
@@ -614,20 +661,10 @@
 	LPWIN32_FIND_DATAW	lpFindFileData
 	)
 {
-	PKERNEL32_FIND_FILE_DATA IData;
-
-	if (!InternalFindNextFile(hFindFile, NULL))
-	{
-		DPRINT("Failing request\n");
-		return FALSE;
-	}
-
-	IData = (PKERNEL32_FIND_FILE_DATA)((PKERNEL32_FIND_DATA_HEADER)hFindFile + 1);
-
-	/* copy data into WIN32_FIND_DATA structure */
-        InternalCopyFindDataW(lpFindFileData, IData->pFileInfo);
-
-	return TRUE;
+	return InternalFindNextFile (hFindFile,
+	                             NULL,
+	                             lpFindFileData,
+	                             TRUE);
 }
 
 
@@ -643,15 +680,14 @@
                   LPVOID                lpSearchFilter,
                   DWORD                 dwAdditionalFlags)
 {
-    PKERNEL32_FIND_DATA_HEADER IHeader;
-    PKERNEL32_FIND_FILE_DATA IData;
-    ULONG DeviceNameInfo;
+    HANDLE Handle;
 
     if (fInfoLevelId != FindExInfoStandard)
     {
         SetLastError(ERROR_INVALID_PARAMETER);
         return INVALID_HANDLE_VALUE;
     }
+
     if (fSearchOp == FindExSearchNameMatch || fSearchOp == FindExSearchLimitToDirectories)
     {
         if (lpSearchFilter)
@@ -660,23 +696,19 @@
             return INVALID_HANDLE_VALUE;
         }
 
-        IHeader = InternalFindFirstFile (lpFileName, fSearchOp == FindExSearchLimitToDirectories ? TRUE : FALSE, &DeviceNameInfo);
-        if (IHeader == NULL)
+        Handle = InternalFindFirstFile (lpFileName,
+                                        fSearchOp == FindExSearchLimitToDirectories,
+                                        lpFindFileData,
+                                        TRUE);
+        if (Handle == NULL)
         {
             DPRINT("Failing request\n");
             return INVALID_HANDLE_VALUE;
         }
 
-        if ((HANDLE)IHeader == FIND_DEVICE_HANDLE)
-            return InternalCopyDeviceFindDataW((LPWIN32_FIND_DATAW)lpFindFileData, lpFileName, DeviceNameInfo);
-
-        IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
-
-        /* copy data into WIN32_FIND_DATA structure */
-        InternalCopyFindDataW((LPWIN32_FIND_DATAW)lpFindFileData, IData->pFileInfo);
-
-	return (HANDLE)IHeader;
-    }
+        return Handle;
+    }
+
     SetLastError(ERROR_INVALID_PARAMETER);
     return INVALID_HANDLE_VALUE;
 }
@@ -695,11 +727,9 @@
 	DWORD			dwAdditionalFlags
 	)
 {
-    PKERNEL32_FIND_DATA_HEADER IHeader;
-    PKERNEL32_FIND_FILE_DATA IData;
     UNICODE_STRING FileNameU;
     ANSI_STRING FileNameA;
-    ULONG DeviceNameInfo;
+    HANDLE Handle;
 
     if (fInfoLevelId != FindExInfoStandard)
     {
@@ -713,39 +743,31 @@
             SetLastError(ERROR_INVALID_PARAMETER);
             return INVALID_HANDLE_VALUE;
         }
-	
+
         RtlInitAnsiString (&FileNameA, (LPSTR)lpFileName);
 
-	/* convert ansi (or oem) string to unicode */
-	if (bIsFileApiAnsi)
+        /* convert ansi (or oem) string to unicode */
+        if (bIsFileApiAnsi)
             RtlAnsiStringToUnicodeString (&FileNameU, &FileNameA, TRUE);
-	else
+        else
             RtlOemStringToUnicodeString (&FileNameU, &FileNameA, TRUE);
 
-	IHeader = InternalFindFirstFile (FileNameU.Buffer, FALSE, &DeviceNameInfo);
-
-	if (IHeader == NULL)
-	{
-		RtlFreeUnicodeString (&FileNameU);
-		DPRINT("Failing request\n");
-		return INVALID_HANDLE_VALUE;
-	}
-
-	if ((HANDLE)IHeader == FIND_DEVICE_HANDLE)
-	{
-		/* NOTE: FileNameU will be freed in InternalCopyDeviceFindDataA */
-		return InternalCopyDeviceFindDataA(lpFindFileData, &FileNameU, DeviceNameInfo);
-	}
-
-	RtlFreeUnicodeString (&FileNameU);
-
-        IData = (PKERNEL32_FIND_FILE_DATA)(IHeader + 1);
-
-	/* copy data into WIN32_FIND_DATA structure */
-        InternalCopyFindDataA(lpFindFileData, IData->pFileInfo);
-
-        return (HANDLE)IHeader;
-    }
+        Handle = InternalFindFirstFile (FileNameU.Buffer,
+                                        fSearchOp == FindExSearchLimitToDirectories,
+                                        lpFindFileData,
+                                        FALSE);
+
+        RtlFreeUnicodeString (&FileNameU);
+
+        if (Handle == NULL)
+        {
+            DPRINT("Failing request\n");
+            return INVALID_HANDLE_VALUE;
+        }
+
+        return Handle;
+    }
+
     SetLastError(ERROR_INVALID_PARAMETER);
     return INVALID_HANDLE_VALUE;
 }




More information about the Ros-diffs mailing list