| /* | |
| * File handling functions | |
| * | |
| * Copyright 1993 Erik Bos | |
| * Copyright 1996, 2004 Alexandre Julliard | |
| * Copyright 2003 Eric Pouech | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| * | |
| */ | |
| #include <errno.h> | |
| #include <stdio.h> | |
| #include <stdarg.h> | |
| #include "winerror.h" | |
| #include "ntstatus.h" | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winnls.h" | |
| #include "winternl.h" | |
| #include "kernel_private.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(file); | |
| #define MAX_PATHNAME_LEN 1024 | |
| static const WCHAR system_dir[] = L"C:\\windows\\system32"; | |
| /*********************************************************************** | |
| * copy_filename_WtoA | |
| * | |
| * copy a file name back to OEM/Ansi, but only if the buffer is large enough | |
| */ | |
| static DWORD copy_filename_WtoA( LPCWSTR nameW, LPSTR buffer, DWORD len ) | |
| { | |
| UNICODE_STRING strW; | |
| DWORD ret; | |
| BOOL is_ansi = AreFileApisANSI(); | |
| RtlInitUnicodeString( &strW, nameW ); | |
| ret = is_ansi ? RtlUnicodeStringToAnsiSize(&strW) : RtlUnicodeStringToOemSize(&strW); | |
| if (buffer && ret <= len) | |
| { | |
| ANSI_STRING str; | |
| str.Buffer = buffer; | |
| str.MaximumLength = min( len, UNICODE_STRING_MAX_CHARS ); | |
| if (is_ansi) | |
| RtlUnicodeStringToAnsiString( &str, &strW, FALSE ); | |
| else | |
| RtlUnicodeStringToOemString( &str, &strW, FALSE ); | |
| ret = str.Length; /* length without terminating 0 */ | |
| } | |
| return ret; | |
| } | |
| /*********************************************************************** | |
| * GetShortPathNameA (KERNEL32.@) | |
| */ | |
| DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, DWORD shortlen ) | |
| { | |
| WCHAR *longpathW; | |
| WCHAR shortpathW[MAX_PATH]; | |
| DWORD ret; | |
| TRACE("%s\n", debugstr_a(longpath)); | |
| if (!(longpathW = FILE_name_AtoW( longpath, FALSE ))) return 0; | |
| ret = GetShortPathNameW(longpathW, shortpathW, MAX_PATH); | |
| if (!ret) return 0; | |
| if (ret > MAX_PATH) | |
| { | |
| SetLastError(ERROR_FILENAME_EXCED_RANGE); | |
| return 0; | |
| } | |
| return copy_filename_WtoA( shortpathW, shortpath, shortlen ); | |
| } | |
| /************************************************************************** | |
| * CopyFileA (KERNEL32.@) | |
| */ | |
| BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists) | |
| { | |
| WCHAR *sourceW, *destW; | |
| BOOL ret; | |
| if (!(sourceW = FILE_name_AtoW( source, FALSE ))) return FALSE; | |
| if (!(destW = FILE_name_AtoW( dest, TRUE ))) return FALSE; | |
| ret = CopyFileW( sourceW, destW, fail_if_exists ); | |
| HeapFree( GetProcessHeap(), 0, destW ); | |
| return ret; | |
| } | |
| /************************************************************************** | |
| * CopyFileExA (KERNEL32.@) | |
| */ | |
| BOOL WINAPI CopyFileExA(LPCSTR sourceFilename, LPCSTR destFilename, | |
| LPPROGRESS_ROUTINE progressRoutine, LPVOID appData, | |
| LPBOOL cancelFlagPointer, DWORD copyFlags) | |
| { | |
| WCHAR *sourceW, *destW; | |
| BOOL ret; | |
| /* can't use the TEB buffer since we may have a callback routine */ | |
| if (!(sourceW = FILE_name_AtoW( sourceFilename, TRUE ))) return FALSE; | |
| if (!(destW = FILE_name_AtoW( destFilename, TRUE ))) | |
| { | |
| HeapFree( GetProcessHeap(), 0, sourceW ); | |
| return FALSE; | |
| } | |
| ret = CopyFileExW(sourceW, destW, progressRoutine, appData, | |
| cancelFlagPointer, copyFlags); | |
| HeapFree( GetProcessHeap(), 0, sourceW ); | |
| HeapFree( GetProcessHeap(), 0, destW ); | |
| return ret; | |
| } | |
| /************************************************************************** | |
| * MoveFileTransactedA (KERNEL32.@) | |
| */ | |
| BOOL WINAPI MoveFileTransactedA(const char *source, const char *dest, LPPROGRESS_ROUTINE progress, void *data, DWORD flags, HANDLE handle) | |
| { | |
| FIXME("(%s, %s, %p, %p, %ld, %p) semi-stub\n", debugstr_a(source), debugstr_a(dest), progress, data, flags, handle); | |
| return MoveFileWithProgressA(source, dest, progress, data, flags); | |
| } | |
| /************************************************************************** | |
| * MoveFileTransactedW (KERNEL32.@) | |
| */ | |
| BOOL WINAPI MoveFileTransactedW(const WCHAR *source, const WCHAR *dest, LPPROGRESS_ROUTINE progress, void *data, DWORD flags, HANDLE handle) | |
| { | |
| FIXME("(%s, %s, %p, %p, %ld, %p) semi-stub\n", debugstr_w(source), debugstr_w(dest), progress, data, flags, handle); | |
| return MoveFileWithProgressW(source, dest, progress, data, flags); | |
| } | |
| /************************************************************************* | |
| * CreateFileTransactedA (KERNEL32.@) | |
| */ | |
| HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileTransactedA( LPCSTR name, DWORD access, DWORD sharing, | |
| LPSECURITY_ATTRIBUTES sa, DWORD creation, | |
| DWORD attributes, HANDLE template, | |
| HANDLE transaction, PUSHORT version, | |
| PVOID param ) | |
| { | |
| FIXME("(%s %lx %lx %p %lx %lx %p %p %p %p): semi-stub\n", debugstr_a(name), access, sharing, sa, | |
| creation, attributes, template, transaction, version, param); | |
| return CreateFileA(name, access, sharing, sa, creation, attributes, template); | |
| } | |
| /************************************************************************* | |
| * CreateFileTransactedW (KERNEL32.@) | |
| */ | |
| HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileTransactedW( LPCWSTR name, DWORD access, DWORD sharing, | |
| LPSECURITY_ATTRIBUTES sa, DWORD creation, | |
| DWORD attributes, HANDLE template, HANDLE transaction, | |
| PUSHORT version, PVOID param ) | |
| { | |
| FIXME("(%s %lx %lx %p %lx %lx %p %p %p %p): semi-stub\n", debugstr_w(name), access, sharing, sa, | |
| creation, attributes, template, transaction, version, param); | |
| return CreateFileW(name, access, sharing, sa, creation, attributes, template); | |
| } | |
| /*********************************************************************** | |
| * CreateDirectoryTransactedA (KERNEL32.@) | |
| */ | |
| BOOL WINAPI DECLSPEC_HOTPATCH CreateDirectoryTransactedA(LPCSTR template, LPCSTR path, LPSECURITY_ATTRIBUTES sa, HANDLE transaction) | |
| { | |
| FIXME("(%s %s %p %p): semi-stub\n", debugstr_a(template), debugstr_a(path), sa, transaction); | |
| return CreateDirectoryExA(template, path, sa); | |
| } | |
| /*********************************************************************** | |
| * CreateDirectoryTransactedW (KERNEL32.@) | |
| */ | |
| BOOL WINAPI DECLSPEC_HOTPATCH CreateDirectoryTransactedW(LPCWSTR template, LPCWSTR path, LPSECURITY_ATTRIBUTES sa, HANDLE transaction) | |
| { | |
| FIXME("(%s %s %p %p): semi-stub\n", debugstr_w(template), debugstr_w(path), sa, transaction); | |
| return CreateDirectoryExW(template, path, sa); | |
| } | |
| /*********************************************************************** | |
| * DeleteFileTransactedA (KERNEL32.@) | |
| */ | |
| BOOL WINAPI DECLSPEC_HOTPATCH DeleteFileTransactedA(LPCSTR path, HANDLE transaction) | |
| { | |
| FIXME("(%s %p): semi-stub\n", debugstr_a(path), transaction); | |
| return DeleteFileA(path); | |
| } | |
| /*********************************************************************** | |
| * DeleteFileTransactedW (KERNEL32.@) | |
| */ | |
| BOOL WINAPI DECLSPEC_HOTPATCH DeleteFileTransactedW(LPCWSTR path, HANDLE transaction) | |
| { | |
| FIXME("(%s %p): semi-stub\n", debugstr_w(path), transaction); | |
| return DeleteFileW(path); | |
| } | |
| /****************************************************************************** | |
| * FindFirstFileTransactedA (KERNEL32.@) | |
| */ | |
| HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileTransactedA( LPCSTR filename, FINDEX_INFO_LEVELS level, | |
| LPVOID data, FINDEX_SEARCH_OPS search_op, | |
| LPVOID filter, DWORD flags, HANDLE transaction ) | |
| { | |
| FIXME("(%s %d %p %d %p %lx %p): semi-stub\n", debugstr_a(filename), level, data, search_op, filter, flags, transaction); | |
| return FindFirstFileExA(filename, level, data, search_op, filter, flags); | |
| } | |
| /****************************************************************************** | |
| * FindFirstFileTransactedW (KERNEL32.@) | |
| */ | |
| HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileTransactedW( LPCWSTR filename, FINDEX_INFO_LEVELS level, | |
| LPVOID data, FINDEX_SEARCH_OPS search_op, | |
| LPVOID filter, DWORD flags, HANDLE transaction ) | |
| { | |
| FIXME("(%s %d %p %d %p %lx %p): semi-stub\n", debugstr_w(filename), level, data, search_op, filter, flags, transaction); | |
| return FindFirstFileExW(filename, level, data, search_op, filter, flags); | |
| } | |
| /************************************************************************** | |
| * GetFileAttributesTransactedA (KERNEL32.@) | |
| */ | |
| DWORD WINAPI DECLSPEC_HOTPATCH GetFileAttributesTransactedA(LPCSTR name, GET_FILEEX_INFO_LEVELS level, void *ptr, HANDLE transaction) | |
| { | |
| FIXME("(%s %p): semi-stub\n", debugstr_a(name), transaction); | |
| return GetFileAttributesExA(name, level, ptr); | |
| } | |
| /************************************************************************** | |
| * GetFileAttributesTransactedW (KERNEL32.@) | |
| */ | |
| DWORD WINAPI DECLSPEC_HOTPATCH GetFileAttributesTransactedW(LPCWSTR name, GET_FILEEX_INFO_LEVELS level, void *ptr, HANDLE transaction) | |
| { | |
| FIXME("(%s %p): semi-stub\n", debugstr_w(name), transaction); | |
| return GetFileAttributesExW(name, level, ptr); | |
| } | |
| /*********************************************************************** | |
| * RemoveDirectoryTransactedA (KERNEL32.@) | |
| */ | |
| BOOL WINAPI DECLSPEC_HOTPATCH RemoveDirectoryTransactedA(LPCSTR path, HANDLE transaction) | |
| { | |
| FIXME("(%s %p): semi-stub\n", debugstr_a(path), transaction); | |
| return RemoveDirectoryA(path); | |
| } | |
| /*********************************************************************** | |
| * RemoveDirectoryTransactedW (KERNEL32.@) | |
| */ | |
| BOOL WINAPI DECLSPEC_HOTPATCH RemoveDirectoryTransactedW(LPCWSTR path, HANDLE transaction) | |
| { | |
| FIXME("(%s %p): semi-stub\n", debugstr_w(path), transaction); | |
| return RemoveDirectoryW(path); | |
| } | |
| /************************************************************************** | |
| * MoveFileWithProgressA (KERNEL32.@) | |
| */ | |
| BOOL WINAPI MoveFileWithProgressA( LPCSTR source, LPCSTR dest, | |
| LPPROGRESS_ROUTINE fnProgress, | |
| LPVOID param, DWORD flag ) | |
| { | |
| WCHAR *sourceW, *destW; | |
| BOOL ret; | |
| if (!(sourceW = FILE_name_AtoW( source, FALSE ))) return FALSE; | |
| if (dest) | |
| { | |
| if (!(destW = FILE_name_AtoW( dest, TRUE ))) return FALSE; | |
| } | |
| else | |
| destW = NULL; | |
| ret = MoveFileWithProgressW( sourceW, destW, fnProgress, param, flag ); | |
| HeapFree( GetProcessHeap(), 0, destW ); | |
| return ret; | |
| } | |
| /************************************************************************** | |
| * MoveFileExA (KERNEL32.@) | |
| */ | |
| BOOL WINAPI MoveFileExA( LPCSTR source, LPCSTR dest, DWORD flag ) | |
| { | |
| return MoveFileWithProgressA( source, dest, NULL, NULL, flag ); | |
| } | |
| /************************************************************************** | |
| * MoveFileW (KERNEL32.@) | |
| * | |
| * Move file or directory | |
| */ | |
| BOOL WINAPI MoveFileW( LPCWSTR source, LPCWSTR dest ) | |
| { | |
| return MoveFileExW( source, dest, MOVEFILE_COPY_ALLOWED ); | |
| } | |
| /************************************************************************** | |
| * MoveFileA (KERNEL32.@) | |
| */ | |
| BOOL WINAPI MoveFileA( LPCSTR source, LPCSTR dest ) | |
| { | |
| return MoveFileExA( source, dest, MOVEFILE_COPY_ALLOWED ); | |
| } | |
| /*********************************************************************** | |
| * CreateDirectoryExA (KERNEL32.@) | |
| */ | |
| BOOL WINAPI CreateDirectoryExA( LPCSTR template, LPCSTR path, LPSECURITY_ATTRIBUTES sa ) | |
| { | |
| WCHAR *pathW, *templateW = NULL; | |
| BOOL ret; | |
| if (!(pathW = FILE_name_AtoW( path, FALSE ))) return FALSE; | |
| if (template && !(templateW = FILE_name_AtoW( template, TRUE ))) return FALSE; | |
| ret = CreateDirectoryExW( templateW, pathW, sa ); | |
| HeapFree( GetProcessHeap(), 0, templateW ); | |
| return ret; | |
| } | |
| /*********************************************************************** | |
| * GetSystemDirectoryW (KERNEL32.@) | |
| * | |
| * See comment for GetWindowsDirectoryA. | |
| */ | |
| UINT WINAPI GetSystemDirectoryW( LPWSTR path, UINT count ) | |
| { | |
| UINT len = ARRAY_SIZE(system_dir); | |
| if (path && count >= len) | |
| { | |
| lstrcpyW( path, system_dir ); | |
| len--; | |
| } | |
| return len; | |
| } | |
| /*********************************************************************** | |
| * GetSystemDirectoryA (KERNEL32.@) | |
| * | |
| * See comment for GetWindowsDirectoryA. | |
| */ | |
| UINT WINAPI GetSystemDirectoryA( LPSTR path, UINT count ) | |
| { | |
| return copy_filename_WtoA( system_dir, path, count ); | |
| } | |
| /*********************************************************************** | |
| * wine_get_unix_file_name (KERNEL32.@) Not a Windows API | |
| * | |
| * Return the full Unix file name for a given path. | |
| * Returned buffer must be freed by caller. | |
| */ | |
| char * CDECL wine_get_unix_file_name( LPCWSTR dosW ) | |
| { | |
| UNICODE_STRING nt_name; | |
| OBJECT_ATTRIBUTES attr; | |
| IO_STATUS_BLOCK io; | |
| HANDLE handle; | |
| NTSTATUS status; | |
| ULONG size = 256, lenW = 0; | |
| WCHAR *file = NULL; | |
| char *p, *buffer = NULL; | |
| WINE_FILE_UNIX_NAME_INFORMATION *info = NULL; | |
| if (!RtlDosPathNameToNtPathName_U( dosW, &nt_name, NULL, NULL )) return NULL; | |
| InitializeObjectAttributes( &attr, &nt_name, 0, 0, NULL ); | |
| status = NtOpenFile( &handle, GENERIC_READ, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE, | |
| FILE_SYNCHRONOUS_IO_NONALERT ); | |
| if (status) | |
| { | |
| ULONG i = nt_name.Length / sizeof(WCHAR); | |
| while (i && nt_name.Buffer[i - 1] != '\\') i--; | |
| file = nt_name.Buffer + i; | |
| lenW = nt_name.Length / sizeof(WCHAR) - i; | |
| while (i && nt_name.Buffer[i - 1] == '\\') i--; | |
| if (i == 6 && nt_name.Buffer[i - 1] == ':') i++; /* keep backslash after drive */ | |
| if (i > 5) | |
| { | |
| nt_name.Length = i * sizeof(WCHAR); | |
| status = NtOpenFile( &handle, GENERIC_READ, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE, | |
| FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ); | |
| } | |
| } | |
| if (!set_ntstatus( status )) goto failed; | |
| for (;;) | |
| { | |
| if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, size ))) goto failed; | |
| status = NtQueryInformationFile( handle, &io, info, size, WineFileUnixNameInformation ); | |
| if (status == STATUS_BUFFER_OVERFLOW) | |
| { | |
| size = offsetof( WINE_FILE_UNIX_NAME_INFORMATION, Name[info->Length] ); | |
| RtlFreeHeap( GetProcessHeap(), 0, info ); | |
| continue; | |
| } | |
| if (status) goto failed; | |
| if (file) | |
| { | |
| ULONG lenA = WideCharToMultiByte( CP_UNIXCP, 0, file, lenW, NULL, 0, NULL, NULL ); | |
| if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, info->Length + lenA + 2 ))) goto failed; | |
| memcpy( buffer, info->Name, info->Length ); | |
| p = buffer + info->Length; | |
| if (lenA) | |
| { | |
| *p++ = '/'; | |
| p += WideCharToMultiByte( CP_UNIXCP, 0, file, lenW, p, lenA, NULL, NULL ); | |
| } | |
| *p = 0; | |
| RtlFreeHeap( GetProcessHeap(), 0, info ); | |
| } | |
| else | |
| { | |
| ULONG lenA = info->Length; | |
| buffer = (char *)info; | |
| memmove( buffer, info->Name, lenA ); | |
| if (lenA > 1 && nt_name.Buffer[nt_name.Length/sizeof(WCHAR) - 1] == '\\') buffer[lenA++] = '/'; | |
| buffer[lenA] = 0; | |
| } | |
| break; | |
| } | |
| CloseHandle( handle ); | |
| RtlFreeUnicodeString( &nt_name ); | |
| return buffer; | |
| failed: | |
| RtlFreeHeap( GetProcessHeap(), 0, info ); | |
| RtlFreeUnicodeString( &nt_name ); | |
| return NULL; | |
| } | |
| /*********************************************************************** | |
| * wine_get_dos_file_name (KERNEL32.@) Not a Windows API | |
| * | |
| * Return the full DOS file name for a given Unix path. | |
| * Returned buffer must be freed by caller. | |
| */ | |
| WCHAR * CDECL wine_get_dos_file_name( LPCSTR str ) | |
| { | |
| UNICODE_STRING nt_name; | |
| OBJECT_ATTRIBUTES attr; | |
| IO_STATUS_BLOCK io; | |
| NTSTATUS status; | |
| HANDLE handle = 0; | |
| WCHAR *buffer = NULL, *nt_str = NULL; | |
| ULONG i, res, len = strlen(str) + 1; | |
| if (str[0] != '/') /* relative path name */ | |
| { | |
| if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL; | |
| MultiByteToWideChar( CP_UNIXCP, 0, str, len, buffer, len ); | |
| status = RtlDosPathNameToNtPathName_U_WithStatus( buffer, &nt_name, NULL, NULL ); | |
| if (!set_ntstatus( status )) goto failed; | |
| buffer = nt_name.Buffer; | |
| } | |
| else | |
| { | |
| if (!(nt_str = RtlAllocateHeap( GetProcessHeap(), 0, (len + 8) * sizeof(WCHAR) ))) return NULL; | |
| wcscpy( nt_str, L"\\??\\unix" ); | |
| MultiByteToWideChar( CP_UNIXCP, 0, str, len, nt_str + 8, len ); | |
| for (WCHAR *p = nt_str; *p; p++) if (*p == '/') *p = '\\'; | |
| RtlInitUnicodeString( &nt_name, nt_str ); | |
| InitializeObjectAttributes( &attr, &nt_name, 0, 0, NULL ); | |
| for (i = nt_name.Length / sizeof(WCHAR); i > 9 && nt_name.Buffer[i - 1] == '\\'; i--) | |
| nt_name.Length -= sizeof(WCHAR); | |
| status = NtOpenFile( &handle, GENERIC_READ, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE, | |
| FILE_SYNCHRONOUS_IO_NONALERT ); | |
| while (status) | |
| { | |
| i = nt_name.Length / sizeof(WCHAR); | |
| while (i && nt_name.Buffer[i - 1] != '\\') i--; | |
| while (i && nt_name.Buffer[i - 1] == '\\') i--; | |
| if (i <= 9) break; | |
| nt_name.Length = i * sizeof(WCHAR); | |
| status = NtOpenFile( &handle, GENERIC_READ, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE, | |
| FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ); | |
| } | |
| if (!set_ntstatus( status )) goto failed; | |
| if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, (len + 8) * sizeof(WCHAR) ))) goto failed; | |
| res = GetFinalPathNameByHandleW( handle, buffer, len + 8, VOLUME_NAME_DOS ); | |
| if (!res || res > len + 8) goto failed; | |
| if (buffer[res - 1] == '\\' && nt_name.Buffer[nt_name.Length / sizeof(WCHAR)] == '\\') res--; | |
| wcscpy( buffer + res, nt_name.Buffer + nt_name.Length / sizeof(WCHAR) ); | |
| NtClose( handle ); | |
| RtlFreeHeap( GetProcessHeap(), 0, nt_str ); | |
| } | |
| if (buffer[5] == ':') | |
| { | |
| /* get rid of the \??\ prefix */ | |
| /* FIXME: should implement RtlNtPathNameToDosPathName and use that instead */ | |
| memmove( buffer, buffer + 4, (wcslen(buffer + 4) + 1) * sizeof(WCHAR) ); | |
| } | |
| else buffer[1] = '\\'; | |
| return buffer; | |
| failed: | |
| if (handle) NtClose( handle ); | |
| RtlFreeHeap( GetProcessHeap(), 0, buffer ); | |
| RtlFreeHeap( GetProcessHeap(), 0, nt_str ); | |
| return NULL; | |
| } | |
| /************************************************************************* | |
| * CreateSymbolicLinkA (KERNEL32.@) | |
| */ | |
| BOOLEAN WINAPI CreateSymbolicLinkA(LPCSTR link, LPCSTR target, DWORD flags) | |
| { | |
| WCHAR *linkW, *targetW; | |
| BOOL ret; | |
| if (!(linkW = FILE_name_AtoW( link, FALSE ))) return FALSE; | |
| if (!(targetW = FILE_name_AtoW( target, TRUE ))) return FALSE; | |
| ret = CreateSymbolicLinkW( linkW, targetW, flags ); | |
| HeapFree( GetProcessHeap(), 0, targetW ); | |
| return ret; | |
| } | |
| /************************************************************************* | |
| * CreateHardLinkTransactedA (KERNEL32.@) | |
| */ | |
| BOOL WINAPI CreateHardLinkTransactedA(LPCSTR link, LPCSTR target, LPSECURITY_ATTRIBUTES sa, HANDLE transaction) | |
| { | |
| FIXME("(%s %s %p %p): stub\n", debugstr_a(link), debugstr_a(target), sa, transaction); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return FALSE; | |
| } | |
| /************************************************************************* | |
| * CreateHardLinkTransactedW (KERNEL32.@) | |
| */ | |
| BOOL WINAPI CreateHardLinkTransactedW(LPCWSTR link, LPCWSTR target, LPSECURITY_ATTRIBUTES sa, HANDLE transaction) | |
| { | |
| FIXME("(%s %s %p %p): stub\n", debugstr_w(link), debugstr_w(target), sa, transaction); | |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | |
| return FALSE; | |
| } | |
| /************************************************************************* | |
| * CheckNameLegalDOS8Dot3A (KERNEL32.@) | |
| */ | |
| BOOL WINAPI CheckNameLegalDOS8Dot3A(const char *name, char *oemname, DWORD oemname_len, | |
| BOOL *contains_spaces, BOOL *is_legal) | |
| { | |
| WCHAR *nameW; | |
| TRACE("(%s %p %lu %p %p)\n", name, oemname, | |
| oemname_len, contains_spaces, is_legal); | |
| if (!name || !is_legal) | |
| return FALSE; | |
| if (!(nameW = FILE_name_AtoW( name, FALSE ))) return FALSE; | |
| return CheckNameLegalDOS8Dot3W( nameW, oemname, oemname_len, contains_spaces, is_legal ); | |
| } | |
| /************************************************************************* | |
| * CheckNameLegalDOS8Dot3W (KERNEL32.@) | |
| */ | |
| BOOL WINAPI CheckNameLegalDOS8Dot3W(const WCHAR *name, char *oemname, DWORD oemname_len, | |
| BOOL *contains_spaces_ret, BOOL *is_legal) | |
| { | |
| OEM_STRING oem_str; | |
| UNICODE_STRING nameW; | |
| BOOLEAN contains_spaces; | |
| TRACE("(%s %p %lu %p %p)\n", wine_dbgstr_w(name), oemname, | |
| oemname_len, contains_spaces_ret, is_legal); | |
| if (!name || !is_legal) | |
| return FALSE; | |
| RtlInitUnicodeString( &nameW, name ); | |
| if (oemname) { | |
| oem_str.Length = oemname_len; | |
| oem_str.MaximumLength = oemname_len; | |
| oem_str.Buffer = oemname; | |
| } | |
| *is_legal = RtlIsNameLegalDOS8Dot3( &nameW, oemname ? &oem_str : NULL, &contains_spaces ); | |
| if (contains_spaces_ret) *contains_spaces_ret = contains_spaces; | |
| return TRUE; | |
| } | |
| /************************************************************************* | |
| * SetSearchPathMode (KERNEL32.@) | |
| */ | |
| BOOL WINAPI SetSearchPathMode( DWORD flags ) | |
| { | |
| return set_ntstatus( RtlSetSearchPathMode( flags )); | |
| } |