https://bugs.winehq.org/show_bug.cgi?id=48396
Bug ID: 48396 Summary: 'cmd.exe /c move file1 file2' doesn't respect non-interactive mode, causing prompt for overwrite if destination file exists Product: Wine Version: 5.0-rc3 Hardware: x86-64 OS: Linux Status: NEW Severity: normal Priority: P2 Component: cmd Assignee: wine-bugs@winehq.org Reporter: focht@gmx.net Distribution: ---
Hello folks,
as it says. Noticed this with some scene installers that use batch files to uncompress and concatenate files. At one point the progress stalls and a number of 'cmd.exe' processes just sit around, waiting for input (they are non-interactive). Reason: Wine's cmd.exe 'move' doesn't take non-interactive mode into account when destination file exists.
Cmd's 'copy' works.
--- snip --- $ echo "1" > test1 $ echo "2" > test2
# fails but should work $ wine cmd /c move test1 test2 Overwrite Z:\home\focht\test2? (Yes|No) --- snip ---
Setting 'COPYCMD' environment variable to '/Y' avoids the prompt, but still doesn't overwrite the destination file with original which is another bug. Oh boy, cmd.exe really needs some love. Still so broken after years.
Wine source:
https://source.winehq.org/git/wine.git/blob/HEAD:/programs/cmd/builtins.c#l2...
--- snip --- 2959 void WCMD_move (void) 2960 { 2961 BOOL status; 2962 WIN32_FIND_DATAW fd; 2963 HANDLE hff; 2964 WCHAR input[MAX_PATH]; 2965 WCHAR output[MAX_PATH]; 2966 WCHAR drive[10]; 2967 WCHAR dir[MAX_PATH]; 2968 WCHAR fname[MAX_PATH]; 2969 WCHAR ext[MAX_PATH]; ... 3023 /* If destination exists, prompt unless /Y supplied */ 3024 if (GetFileAttributesW(dest) != INVALID_FILE_ATTRIBUTES) { 3025 BOOL force = FALSE; 3026 WCHAR copycmd[MAXSTRING]; 3027 DWORD len; 3028 3029 /* /-Y has the highest priority, then /Y and finally the COPYCMD env. variable */ 3030 if (wcsstr (quals, parmNoY)) 3031 force = FALSE; 3032 else if (wcsstr (quals, parmY)) 3033 force = TRUE; 3034 else { 3035 static const WCHAR copyCmdW[] = {'C','O','P','Y','C','M','D','\0'}; 3036 len = GetEnvironmentVariableW(copyCmdW, copycmd, ARRAY_SIZE(copycmd)); 3037 force = (len && len < ARRAY_SIZE(copycmd) && !lstrcmpiW(copycmd, parmY)); 3038 } 3039 3040 /* Prompt if overwriting */ 3041 if (!force) { 3042 WCHAR* question; 3043 3044 /* Ask for confirmation */ 3045 question = WCMD_format_string(WCMD_LoadMessage(WCMD_OVERWRITE), dest); 3046 ok = WCMD_ask_confirm(question, FALSE, NULL); 3047 LocalFree(question); 3048 3049 /* So delete the destination prior to the move */ 3050 if (ok) { 3051 if (!DeleteFileW(dest)) { 3052 WCMD_print_error (); 3053 errorlevel = 1; 3054 ok = FALSE; 3055 } 3056 } 3057 } 3058 } ... --- snip ---
While at it you could really refactor/unify the code more. Even basic 'COPYCMD' handling is implemented in different code style (move vs. copy):
https://source.winehq.org/git/wine.git/blob/HEAD:/programs/cmd/builtins.c#l7...
$ wine --version wine-5.0-rc3
Regards