MoveFileEx now enters the files in the registry when the boot delay
flag is set.
diff --git a/files/file.c b/files/file.c
index ebdb576..19a0173 100644
--- a/files/file.c
+++ b/files/file.c
@@ -2117,6 +2117,99 @@
}
+/***********************************************************************
+ * FILE_AddBootRenameEntry
+ *
+ * Adds an entry to the registry that is loaded when windows boots and
+ * checks if there are some files to be removed or renamed/moved.
+ * <fn1> has to be valid and <fn2> may be NULL. If both pointers are
+ * non-NULL then the file is moved, otherwise it is deleted. The
+ * entry of the registrykey is always appended with two zero
+ * terminated strings. If <fn2> is NULL then the second entry is
+ * simply a single 0-byte. Otherwise the second filename goes
+ * there. The entries are prepended with \??\ before the path and the
+ * second filename gets also a '!' as the first character if
+ * MOVEFILE_REPLACE_EXISTING is set. After the final string another
+ * 0-byte follows to indicate the end of the strings.
+ * i.e.:
+ * \??\D:\test\file1[0]
+ * !\??\D:\test\file1_renamed[0]
+ * \??\D:\Test|delete[0]
+ * [0] <- file is to be deleted, second string empty
+ * \??\D:\test\file2[0]
+ * !\??\D:\test\file2_renamed[0]
+ * [0] <- indicates end of strings
+ *
+ * or:
+ * \??\D:\test\file1[0]
+ * !\??\D:\test\file1_renamed[0]
+ * \??\D:\Test|delete[0]
+ * [0] <- file is to be deleted, second string empty
+ * [0] <- indicates end of strings
+ *
+ */
+static BOOL FILE_AddBootRenameEntry( const char *fn1, const char *fn2, DWORD flags )
+{
+ static const char PreString[] = "\\??\\";
+ static const char ValueName[] = "PendingFileRenameOperations";
+
+ BOOL rc = FALSE;
+ HKEY Reboot = 0;
+ DWORD Type, len1, len2, l;
+ DWORD DataSize = 0;
+ BYTE *Buffer = NULL;
+
+ if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
+ &Reboot) != ERROR_SUCCESS)
+ {
+ WARN("Error creating key for reboot managment [%s]\n",
+ "SYSTEM\\CurrentControlSet\\Control\\Session Manager");
+ return FALSE;
+ }
+
+ l = strlen(PreString);
+ len1 = strlen(fn1) + l + 1;
+ if (fn2)
+ {
+ len2 = strlen(fn2) + l + 1;
+ if (flags & MOVEFILE_REPLACE_EXISTING) len2++; /* Plus 1 because of the leading '!' */
+ }
+ else len2 = 1; /* minimum is the 0 byte for the empty second string */
+
+ /* First we check if the key exists and if so how many bytes it already contains. */
+ if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, NULL, &DataSize) == ERROR_SUCCESS)
+ {
+ if (Type != REG_MULTI_SZ) goto Quit;
+ if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + 1 ))) goto Quit;
+ if (RegQueryValueExA(Reboot, ValueName, NULL, &Type, Buffer, &DataSize) != ERROR_SUCCESS)
+ goto Quit;
+ if (DataSize) DataSize--; /* remove terminating null (will be added back later) */
+ }
+ else
+ {
+ if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, len1 + len2 + 1 ))) goto Quit;
+ DataSize = 0;
+ }
+ sprintf( Buffer + DataSize, "%s%s", PreString, fn1 );
+ DataSize += len1;
+ if (fn2)
+ {
+ sprintf( Buffer + DataSize, "%s%s%s",
+ (flags & MOVEFILE_REPLACE_EXISTING) ? "!" : "", PreString, fn2 );
+ DataSize += len2;
+ }
+ else Buffer[DataSize++] = 0;
+
+ Buffer[DataSize++] = 0; /* add final null */
+ rc = !RegSetValueExA( Reboot, ValueName, 0, REG_MULTI_SZ, Buffer, DataSize );
+
+ Quit:
+ if (Reboot) RegCloseKey(Reboot);
+ if (Buffer) HeapFree( GetProcessHeap(), 0, Buffer );
+ return(rc);
+}
+
+
/**************************************************************************
* MoveFileExA (KERNEL32.@)
*/
@@ -2126,26 +2219,57 @@
TRACE("(%s,%s,%04lx)\n", fn1, fn2, flag);
+ /* FIXME: <Gerhard W. Gruber>sparhawk@gmx.at
+ In case of W9x and lesser this function should return 120 (ERROR_CALL_NOT_IMPLEMENTED)
+ to be really compatible. Most programs wont have any problems though. In case
+ you encounter one, this is what you should return here. I don't know what's up
+ with NT 3.5. Is this function available there or not?
+ Does anybody really care about 3.5? :)
+ */
+
+ /* Filename1 has to be always set to a valid path. Filename2 may be NULL
+ if the source file has to be deleted.
+ */
if (!fn1) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
- if (!DOSFS_GetFullName( fn1, TRUE, &full_name1 )) return FALSE;
+ /* This function has to be run through in order to process the name properly.
+ If the BOOTDELAY flag is set, the file doesn't need to exist though. At least
+ that is the behaviour on NT 4.0. The operation accepts the filenames as
+ they are given but it can't reply with a reasonable returncode. Success
+ means in that case success for entering the values into the registry.
+ */
+ if(!DOSFS_GetFullName( fn1, TRUE, &full_name1 ))
+ {
+ if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
+ return FALSE;
+ }
if (fn2) /* !fn2 means delete fn1 */
{
- if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
+ if (DOSFS_GetFullName( fn2, TRUE, &full_name2 ))
{
- /* target exists, check if we may overwrite */
- if (!(flag & MOVEFILE_REPLACE_EXISTING))
+ if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
{
- /* FIXME: Use right error code */
- SetLastError( ERROR_ACCESS_DENIED );
- return FALSE;
+ /* target exists, check if we may overwrite */
+ if (!(flag & MOVEFILE_REPLACE_EXISTING))
+ {
+ /* FIXME: Use right error code */
+ SetLastError( ERROR_ACCESS_DENIED );
+ return FALSE;
+ }
}
}
- else if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 )) return FALSE;
+ else
+ {
+ if (!DOSFS_GetFullName( fn2, FALSE, &full_name2 ))
+ {
+ if(!(flag & MOVEFILE_DELAY_UNTIL_REBOOT))
+ return FALSE;
+ }
+ }
/* Source name and target path are valid */
@@ -2156,8 +2280,8 @@
when exiting... What about using on_exit(2)
*/
FIXME("Please move existing file '%s' to file '%s' when Wine has finished\n",
- full_name1.long_name, full_name2.long_name);
- return TRUE;
+ fn1, fn2);
+ return FILE_AddBootRenameEntry( fn1, fn2, flag );
}
if (full_name1.drive != full_name2.drive)
@@ -2204,9 +2328,8 @@
Perhaps we should queue these command and execute it
when exiting... What about using on_exit(2)
*/
- FIXME("Please delete file '%s' when Wine has finished\n",
- full_name1.long_name);
- return TRUE;
+ FIXME("Please delete file '%s' when Wine has finished\n", fn1);
+ return FILE_AddBootRenameEntry( fn1, NULL, flag );
}
if (unlink( full_name1.long_name ) == -1)