Gabriel Ivăncescu schreef op wo 09-09-2020 om 18:30 [+0300]:
On 09/09/2020 15:25, spaarder wrote:
Hello,

I want to contribute to the wonderful Wine project, so I decided to 
start with a simple patch for the CreateSymbolicLinkW WINAP in 
kernelbase.dll .

In my patch I use the system() function, which is in the stdlib library. 
The linker cannot find this library because of the "-nodefautlibs" in 
Makefile.in .
When I remove -nodefaultlibs, all compiles well, but now wineboot (and 
probably a _lot_ of other things) are broken, even if I undo my patch.

Why does removing -nodefaultlibs from wine/dlls/kernelbase/Makefile.in 
break so many things? Has it anything to do with @ cdecl system(str) 
MSVCRT_system?

What would be the "proper" (wine) way to solve this?

Big thanks!

Hans.

Hi Hans,

Unfortunately, CreateSymbolicLinkW is actually complicated. There are 
patches in wine-staging that implement it, so you can take a look there 
and see why that is so (because Windows also has junction points and so 
on). See the ntdll-Junction_Points patchset in wine-staging.

Now for your question about -nodefaultlibs: the wine dlls that have this 
flag are compiled as native Windows .DLL PE files. That means they can't 
use system (unix) functions. kernelbase is one such example: most of the 
functions in kernelbase are done through ntdll.

ntdll is also compiled as PE, but it has a unix library component (to be 
able to use unix libraries or communicate with the wine server). So in 
general, the procedure would be to:

Implement symbolic links via some ntdll API.
Have kernelbase use the ntdll API to implement it.

You can see a 'unix' subdir in the ntdll, which is where the unix 
library is, and it's called through function pointers from the PE module 
(all files at the root of the dir).

Again, the wine-staging patchset might help you in with clues. I'm not 
that familiar with the details myself, so I apologize if I said 
something wrong.

Someone more knowledgeable might clarify it better, if they have the time.

Thank you for your answer Gabriel, it helped me a lot! I looked at the patch in staging, and I noticed it is HUGE and COMPLICATED.
I found a much simpler solution, that is working fine (extensively tested):

================================================begin of patch======================================
diff -Naur wine.orig/dlls/kernelbase/Makefile.in wine.test3/dlls/kernelbase/Makefile.in
--- wine.orig/dlls/kernelbase/Makefile.in 2020-09-06 19:22:23.817571221 +0000
+++ wine.test3/dlls/kernelbase/Makefile.in 2020-09-11 12:37:20.173994185 +0000
@@ -1,6 +1,6 @@
 MODULE    = kernelbase.dll
 IMPORTLIB = kernelbase
-IMPORTS   = uuid ntdll winecrt0
+IMPORTS   = uuid ntdll winecrt0 kernel32
 EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -mno-cygwin -Wl,--image-base,0x7b000000
 
 C_SRCS = \
diff -Naur wine.orig/dlls/kernelbase/file.c wine.test3/dlls/kernelbase/file.c
--- wine.orig/dlls/kernelbase/file.c 2020-09-06 19:22:23.817571221 +0000
+++ wine.test3/dlls/kernelbase/file.c 2020-09-12 10:38:41.844739386 +0000
@@ -920,16 +920,61 @@
     return ret;
 }
 
-
+extern int system2(char * cmd);
 /*************************************************************************
  * CreateSymbolicLinkW   (kernelbase.@)
  */
 BOOLEAN WINAPI /* DECLSPEC_HOTPATCH */ CreateSymbolicLinkW( LPCWSTR link, LPCWSTR target, DWORD flags )
 {
-    FIXME( "(%s %s %d): stub\n", debugstr_w(link), debugstr_w(target), flags );
-    return TRUE;
-}
+    if (flags != 2) {
+        //flags=0: target is a file
+        //flags=1: link target is a directory
+        //flags=2: allow creation of symbolic links when the process is not elevated. Developer Mode must first be enabled on the machine before this option will function.
+        int ret = -2;
+        char *link_unix = NULL;
+        char *target_unix = NULL;
+        //works for macOS, BSD and linux:
+        static const char ln[] = "ln -s '";
+        //max path length in windows is 260 char, +7 for ln command, 
+        //+3 for quoted space between link and target, +1 for quote at end
+        char cmd[531];
+        link_unix=wine_get_unix_file_name(link);
+        target_unix=wine_get_unix_file_name(target);
+        strcpy( cmd, ln );
+        strcat( cmd, target_unix );
+        strcat( cmd, "' '");
+        strcat( cmd, link_unix );
+        strcat( cmd, "'");
+        //FIXME( "(%s): DINGO\n", cmd);
+        ret = system2( cmd );
 
+        if (!link_unix)
+            free(link_unix);
+        if (!target_unix)
+            free(target_unix);
+
+        switch(ret) {
+            //return code in WINDOWS: success = non-zero = TRUE
+            //return code of system: -1 = error in system call, other codes are from exit code of called program: 0 = success, others are errors
+            case 0:
+                //success
+                return TRUE;
+            case -2:
+                SetLastError( ERROR_INSUFFICIENT_BUFFER );
+                break;
+            case -1:
+                SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+                break;
+            default:
+                SetLastError(ERROR_INVALID_PARAMETER);
+        }
+    }
+    else {
+        FIXME( "(%s %s %s %d): stub\n", "Developer mode not supported.", debugstr_w(link), debugstr_w(target), flags );
+        return TRUE;
+    }
+    return FALSE;
+}
 
 /***********************************************************************
  * DeleteFileA   (kernelbase.@)
diff -Naur wine.orig/dlls/ntdll/ntdll.spec wine.test3/dlls/ntdll/ntdll.spec
--- wine.orig/dlls/ntdll/ntdll.spec 2020-09-06 19:22:23.977570502 +0000
+++ wine.test3/dlls/ntdll/ntdll.spec 2020-09-11 12:37:20.177993944 +0000
@@ -1554,6 +1554,7 @@
 @ cdecl strstr(str str)
 @ cdecl strtol(str ptr long)
 @ cdecl strtoul(str ptr long)
+@ cdecl system2(str)
 @ varargs swprintf(ptr wstr) NTDLL_swprintf
 @ varargs swprintf_s(ptr long wstr)
 @ cdecl tan(double)
diff -Naur wine.orig/dlls/ntdll/path.c wine.test3/dlls/ntdll/path.c
--- wine.orig/dlls/ntdll/path.c 2020-09-06 19:22:23.977570502 +0000
+++ wine.test3/dlls/ntdll/path.c 2020-09-11 12:37:20.177993944 +0000
@@ -134,6 +134,13 @@
     return 0;
 }
 
+//int WINAPI system2(char* cmd)
+int CDECL system2(char* cmd)
+{
+    int ret = unix_funcs->system3(cmd);
+    return ret;
+}
+
 /**************************************************************************
  *                 RtlDosPathNameToNtPathName_U_WithStatus    [NTDLL.@]
  *
diff -Naur wine.orig/dlls/ntdll/unix/file.c wine.test3/dlls/ntdll/unix/file.c
--- wine.orig/dlls/ntdll/unix/file.c 2020-09-06 19:22:23.989570448 +0000
+++ wine.test3/dlls/ntdll/unix/file.c 2020-09-11 13:15:43.337430667 +0000
@@ -3492,6 +3492,10 @@
     show_dot_files = enable;
 }
 
+int CDECL system3( char * cmd )
+{
+    return system( cmd );
+}
 
 /******************************************************************************
  *              open_unix_file
diff -Naur wine.orig/dlls/ntdll/unix/loader.c wine.test3/dlls/ntdll/unix/loader.c
--- wine.orig/dlls/ntdll/unix/loader.c 2020-09-06 19:22:23.993570430 +0000
+++ wine.test3/dlls/ntdll/unix/loader.c 2020-09-11 12:37:10.382585289 +0000
@@ -1409,6 +1409,7 @@
     get_locales,
     virtual_release_address_space,
     set_show_dot_files,
+    system3,
     load_so_dll,
     load_builtin_dll,
     unload_builtin_dll,
diff -Naur wine.orig/dlls/ntdll/unix/unix_private.h wine.test3/dlls/ntdll/unix/unix_private.h
--- wine.orig/dlls/ntdll/unix/unix_private.h 2020-09-06 19:22:23.993570430 +0000
+++ wine.test3/dlls/ntdll/unix/unix_private.h 2020-09-11 12:37:20.177993944 +0000
@@ -109,6 +109,7 @@
 extern void CDECL get_initial_directory( UNICODE_STRING *dir ) DECLSPEC_HIDDEN;
 extern void CDECL get_initial_console( HANDLE *handle, HANDLE *std_in, HANDLE *std_out, HANDLE *std_err ) DECLSPEC_HIDDEN;
 extern USHORT * CDECL get_unix_codepage_data(void) DECLSPEC_HIDDEN;
+extern int CDECL system3(char *cmd) DECLSPEC_HIDDEN;
 extern void CDECL get_locales( WCHAR *sys, WCHAR *user ) DECLSPEC_HIDDEN;
 extern void CDECL virtual_release_address_space(void) DECLSPEC_HIDDEN;
 
diff -Naur wine.orig/dlls/ntdll/unixlib.h wine.test3/dlls/ntdll/unixlib.h
--- wine.orig/dlls/ntdll/unixlib.h 2020-09-06 19:22:23.993570430 +0000
+++ wine.test3/dlls/ntdll/unixlib.h 2020-09-11 12:37:20.177993944 +0000
@@ -27,7 +27,7 @@
 struct _DISPATCHER_CONTEXT;
 
 /* increment this when you change the function table */
-#define NTDLL_UNIXLIB_VERSION 104
+#define NTDLL_UNIXLIB_VERSION 105
 
 struct unix_funcs
 {
@@ -83,6 +83,7 @@
 
     /* file functions */
     void          (CDECL *set_show_dot_files)( BOOL enable );
+    int           (CDECL *system3)(char *cmd);
 
     /* loader functions */
     NTSTATUS      (CDECL *load_so_dll)( UNICODE_STRING *nt_name, void **module );

================================================end of patch======================================

I realise this is not upto the goal of "translating winapi calls to posix calls", but this way I could keep my code much more compact and 
much more readable than the CreateSymbolicLinkW patch that is in wine-staging; I copied the use of the "system" userland call from the umount 
routines, so it is not a new thing to the wine code.

Please give me your comments and guidelines on if and how this patch could make it into the master branch.

Thank you!

Hans.