ntdll: Move the Unix to NT file name conversion support to the Unix library.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
f6bfb4ce00
commit
7e9ccbe68f
|
@ -48,97 +48,6 @@ static const WCHAR UncPfxW[] = {'U','N','C','\\',0};
|
||||||
|
|
||||||
#define IS_SEPARATOR(ch) ((ch) == '\\' || (ch) == '/')
|
#define IS_SEPARATOR(ch) ((ch) == '\\' || (ch) == '/')
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* remove_last_componentA
|
|
||||||
*
|
|
||||||
* Remove the last component of the path. Helper for find_drive_rootA.
|
|
||||||
*/
|
|
||||||
static inline unsigned int remove_last_componentA( const char *path, unsigned int len )
|
|
||||||
{
|
|
||||||
int level = 0;
|
|
||||||
|
|
||||||
while (level < 1)
|
|
||||||
{
|
|
||||||
/* find start of the last path component */
|
|
||||||
unsigned int prev = len;
|
|
||||||
if (prev <= 1) break; /* reached root */
|
|
||||||
while (prev > 1 && path[prev - 1] != '/') prev--;
|
|
||||||
/* does removing it take us up a level? */
|
|
||||||
if (len - prev != 1 || path[prev] != '.') /* not '.' */
|
|
||||||
{
|
|
||||||
if (len - prev == 2 && path[prev] == '.' && path[prev+1] == '.') /* is it '..'? */
|
|
||||||
level--;
|
|
||||||
else
|
|
||||||
level++;
|
|
||||||
}
|
|
||||||
/* strip off trailing slashes */
|
|
||||||
while (prev > 1 && path[prev - 1] == '/') prev--;
|
|
||||||
len = prev;
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* find_drive_rootA
|
|
||||||
*
|
|
||||||
* Find a drive for which the root matches the beginning of the given path.
|
|
||||||
* This can be used to translate a Unix path into a drive + DOS path.
|
|
||||||
* Return value is the drive, or -1 on error. On success, ppath is modified
|
|
||||||
* to point to the beginning of the DOS path.
|
|
||||||
*/
|
|
||||||
static NTSTATUS find_drive_rootA( LPCSTR *ppath, unsigned int len, int *drive_ret )
|
|
||||||
{
|
|
||||||
/* Starting with the full path, check if the device and inode match any of
|
|
||||||
* the wine 'drives'. If not then remove the last path component and try
|
|
||||||
* again. If the last component was a '..' then skip a normal component
|
|
||||||
* since it's a directory that's ascended back out of.
|
|
||||||
*/
|
|
||||||
int drive;
|
|
||||||
char *buffer;
|
|
||||||
const char *path = *ppath;
|
|
||||||
struct stat st;
|
|
||||||
struct drive_info info[MAX_DOS_DRIVES];
|
|
||||||
|
|
||||||
/* get device and inode of all drives */
|
|
||||||
if (!DIR_get_drives_info( info )) return STATUS_OBJECT_PATH_NOT_FOUND;
|
|
||||||
|
|
||||||
/* strip off trailing slashes */
|
|
||||||
while (len > 1 && path[len - 1] == '/') len--;
|
|
||||||
|
|
||||||
/* make a copy of the path */
|
|
||||||
if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, len + 1 ))) return STATUS_NO_MEMORY;
|
|
||||||
memcpy( buffer, path, len );
|
|
||||||
buffer[len] = 0;
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
if (!stat( buffer, &st ) && S_ISDIR( st.st_mode ))
|
|
||||||
{
|
|
||||||
/* Find the drive */
|
|
||||||
for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
|
|
||||||
{
|
|
||||||
if ((info[drive].dev == st.st_dev) && (info[drive].ino == st.st_ino))
|
|
||||||
{
|
|
||||||
if (len == 1) len = 0; /* preserve root slash in returned path */
|
|
||||||
TRACE( "%s -> drive %c:, root=%s, name=%s\n",
|
|
||||||
debugstr_a(path), 'A' + drive, debugstr_a(buffer), debugstr_a(path + len));
|
|
||||||
*ppath += len;
|
|
||||||
*drive_ret = drive;
|
|
||||||
RtlFreeHeap( GetProcessHeap(), 0, buffer );
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (len <= 1) break; /* reached root */
|
|
||||||
len = remove_last_componentA( buffer, len );
|
|
||||||
buffer[len] = 0;
|
|
||||||
}
|
|
||||||
RtlFreeHeap( GetProcessHeap(), 0, buffer );
|
|
||||||
return STATUS_OBJECT_PATH_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* remove_last_componentW
|
* remove_last_componentW
|
||||||
*
|
*
|
||||||
|
@ -1069,86 +978,32 @@ NTSTATUS WINAPI RtlSetCurrentDirectory_U(const UNICODE_STRING* dir)
|
||||||
*/
|
*/
|
||||||
NTSTATUS CDECL wine_unix_to_nt_file_name( const ANSI_STRING *name, UNICODE_STRING *nt )
|
NTSTATUS CDECL wine_unix_to_nt_file_name( const ANSI_STRING *name, UNICODE_STRING *nt )
|
||||||
{
|
{
|
||||||
static const WCHAR prefixW[] = {'\\','?','?','\\','A',':','\\'};
|
|
||||||
static const WCHAR unix_prefixW[] = {'\\','?','?','\\','u','n','i','x'};
|
|
||||||
unsigned int lenW, lenA = name->Length;
|
unsigned int lenW, lenA = name->Length;
|
||||||
const char *path = name->Buffer;
|
const char *path = name->Buffer;
|
||||||
char *cwd;
|
|
||||||
WCHAR *p;
|
|
||||||
NTSTATUS status;
|
|
||||||
int drive;
|
|
||||||
|
|
||||||
if (!lenA || path[0] != '/')
|
if (!lenA) return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if (path[0] != '/') /* relative path name */
|
||||||
{
|
{
|
||||||
char *newcwd, *end;
|
WCHAR *tmp;
|
||||||
size_t size;
|
|
||||||
|
|
||||||
if ((status = DIR_get_unix_cwd( &cwd )) != STATUS_SUCCESS) return status;
|
path++;
|
||||||
|
lenA--;
|
||||||
size = strlen(cwd) + lenA + 1;
|
if (!(tmp = RtlAllocateHeap( GetProcessHeap(), 0, (lenA + 1) * sizeof(WCHAR) )))
|
||||||
if (!(newcwd = RtlReAllocateHeap( GetProcessHeap(), 0, cwd, size )))
|
return STATUS_NO_MEMORY;
|
||||||
|
lenW = ntdll_umbstowcs( path, lenA, tmp, lenA );
|
||||||
|
tmp[lenW] = 0;
|
||||||
|
lenW = RtlGetFullPathName_U( tmp, 0, NULL, NULL );
|
||||||
|
if (!lenW || !(nt->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, lenW )))
|
||||||
{
|
{
|
||||||
status = STATUS_NO_MEMORY;
|
RtlFreeHeap( GetProcessHeap(), 0, tmp );
|
||||||
goto done;
|
return STATUS_NO_MEMORY;
|
||||||
}
|
}
|
||||||
cwd = newcwd;
|
lenW = RtlGetFullPathName_U( tmp, lenW, nt->Buffer, NULL );
|
||||||
end = cwd + strlen(cwd);
|
nt->Length = lenW;
|
||||||
if (end > cwd && end[-1] != '/') *end++ = '/';
|
nt->MaximumLength = lenW + sizeof(WCHAR);
|
||||||
memcpy( end, path, lenA );
|
RtlFreeHeap( GetProcessHeap(), 0, tmp );
|
||||||
lenA += end - cwd;
|
return STATUS_SUCCESS;
|
||||||
path = cwd;
|
|
||||||
|
|
||||||
status = find_drive_rootA( &path, lenA, &drive );
|
|
||||||
lenA -= (path - cwd);
|
|
||||||
}
|
}
|
||||||
else
|
return unix_funcs->unix_to_nt_file_name( name, nt );
|
||||||
{
|
|
||||||
cwd = NULL;
|
|
||||||
status = find_drive_rootA( &path, lenA, &drive );
|
|
||||||
lenA -= (path - name->Buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
{
|
|
||||||
if (status == STATUS_OBJECT_PATH_NOT_FOUND)
|
|
||||||
{
|
|
||||||
nt->Buffer = RtlAllocateHeap( GetProcessHeap(), 0,
|
|
||||||
(lenA + 1) * sizeof(WCHAR) + sizeof(unix_prefixW) );
|
|
||||||
if (nt->Buffer == NULL)
|
|
||||||
{
|
|
||||||
status = STATUS_NO_MEMORY;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
memcpy( nt->Buffer, unix_prefixW, sizeof(unix_prefixW) );
|
|
||||||
lenW = ARRAY_SIZE( unix_prefixW );
|
|
||||||
lenW += ntdll_umbstowcs( path, lenA, nt->Buffer + lenW, lenA );
|
|
||||||
nt->Buffer[lenW] = 0;
|
|
||||||
nt->Length = lenW * sizeof(WCHAR);
|
|
||||||
nt->MaximumLength = nt->Length + sizeof(WCHAR);
|
|
||||||
for (p = nt->Buffer + ARRAY_SIZE( unix_prefixW ); *p; p++) if (*p == '/') *p = '\\';
|
|
||||||
status = STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
while (lenA && path[0] == '/') { lenA--; path++; }
|
|
||||||
|
|
||||||
if (!(nt->Buffer = RtlAllocateHeap( GetProcessHeap(), 0,
|
|
||||||
(lenA + 1) * sizeof(WCHAR) + sizeof(prefixW) )))
|
|
||||||
{
|
|
||||||
status = STATUS_NO_MEMORY;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy( nt->Buffer, prefixW, sizeof(prefixW) );
|
|
||||||
nt->Buffer[4] += drive;
|
|
||||||
lenW = ARRAY_SIZE( prefixW );
|
|
||||||
lenW += ntdll_umbstowcs( path, lenA, nt->Buffer + lenW, lenA );
|
|
||||||
nt->Buffer[lenW] = 0;
|
|
||||||
nt->Length = lenW * sizeof(WCHAR);
|
|
||||||
nt->MaximumLength = nt->Length + sizeof(WCHAR);
|
|
||||||
for (p = nt->Buffer + ARRAY_SIZE( prefixW ); *p; p++) if (*p == '/') *p = '\\';
|
|
||||||
|
|
||||||
done:
|
|
||||||
RtlFreeHeap( GetProcessHeap(), 0, cwd );
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1803,7 +1803,7 @@ static NTSTATUS fill_name_info( const ANSI_STRING *unix_name, FILE_NAME_INFORMAT
|
||||||
UNICODE_STRING nt_name;
|
UNICODE_STRING nt_name;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
|
||||||
if (!(status = wine_unix_to_nt_file_name( unix_name, &nt_name )))
|
if (!(status = unix_to_nt_file_name( unix_name, &nt_name )))
|
||||||
{
|
{
|
||||||
const WCHAR *ptr = nt_name.Buffer;
|
const WCHAR *ptr = nt_name.Buffer;
|
||||||
const WCHAR *end = ptr + (nt_name.Length / sizeof(WCHAR));
|
const WCHAR *end = ptr + (nt_name.Length / sizeof(WCHAR));
|
||||||
|
@ -2894,6 +2894,97 @@ static inline int get_dos_prefix_len( const UNICODE_STRING *name )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* remove_last_componentA
|
||||||
|
*
|
||||||
|
* Remove the last component of the path. Helper for find_drive_rootA.
|
||||||
|
*/
|
||||||
|
static inline unsigned int remove_last_componentA( const char *path, unsigned int len )
|
||||||
|
{
|
||||||
|
int level = 0;
|
||||||
|
|
||||||
|
while (level < 1)
|
||||||
|
{
|
||||||
|
/* find start of the last path component */
|
||||||
|
unsigned int prev = len;
|
||||||
|
if (prev <= 1) break; /* reached root */
|
||||||
|
while (prev > 1 && path[prev - 1] != '/') prev--;
|
||||||
|
/* does removing it take us up a level? */
|
||||||
|
if (len - prev != 1 || path[prev] != '.') /* not '.' */
|
||||||
|
{
|
||||||
|
if (len - prev == 2 && path[prev] == '.' && path[prev+1] == '.') /* is it '..'? */
|
||||||
|
level--;
|
||||||
|
else
|
||||||
|
level++;
|
||||||
|
}
|
||||||
|
/* strip off trailing slashes */
|
||||||
|
while (prev > 1 && path[prev - 1] == '/') prev--;
|
||||||
|
len = prev;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* find_drive_rootA
|
||||||
|
*
|
||||||
|
* Find a drive for which the root matches the beginning of the given path.
|
||||||
|
* This can be used to translate a Unix path into a drive + DOS path.
|
||||||
|
* Return value is the drive, or -1 on error. On success, ppath is modified
|
||||||
|
* to point to the beginning of the DOS path.
|
||||||
|
*/
|
||||||
|
static NTSTATUS find_drive_rootA( LPCSTR *ppath, unsigned int len, int *drive_ret )
|
||||||
|
{
|
||||||
|
/* Starting with the full path, check if the device and inode match any of
|
||||||
|
* the wine 'drives'. If not then remove the last path component and try
|
||||||
|
* again. If the last component was a '..' then skip a normal component
|
||||||
|
* since it's a directory that's ascended back out of.
|
||||||
|
*/
|
||||||
|
int drive;
|
||||||
|
char *buffer;
|
||||||
|
const char *path = *ppath;
|
||||||
|
struct stat st;
|
||||||
|
struct file_identity info[MAX_DOS_DRIVES];
|
||||||
|
|
||||||
|
/* get device and inode of all drives */
|
||||||
|
if (!get_drives_info( info )) return STATUS_OBJECT_PATH_NOT_FOUND;
|
||||||
|
|
||||||
|
/* strip off trailing slashes */
|
||||||
|
while (len > 1 && path[len - 1] == '/') len--;
|
||||||
|
|
||||||
|
/* make a copy of the path */
|
||||||
|
if (!(buffer = malloc( len + 1 ))) return STATUS_NO_MEMORY;
|
||||||
|
memcpy( buffer, path, len );
|
||||||
|
buffer[len] = 0;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (!stat( buffer, &st ) && S_ISDIR( st.st_mode ))
|
||||||
|
{
|
||||||
|
/* Find the drive */
|
||||||
|
for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
|
||||||
|
{
|
||||||
|
if ((info[drive].dev == st.st_dev) && (info[drive].ino == st.st_ino))
|
||||||
|
{
|
||||||
|
if (len == 1) len = 0; /* preserve root slash in returned path */
|
||||||
|
TRACE( "%s -> drive %c:, root=%s, name=%s\n",
|
||||||
|
debugstr_a(path), 'A' + drive, debugstr_a(buffer), debugstr_a(path + len));
|
||||||
|
*ppath += len;
|
||||||
|
*drive_ret = drive;
|
||||||
|
free( buffer );
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (len <= 1) break; /* reached root */
|
||||||
|
len = remove_last_componentA( buffer, len );
|
||||||
|
buffer[len] = 0;
|
||||||
|
}
|
||||||
|
free( buffer );
|
||||||
|
return STATUS_OBJECT_PATH_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* find_file_id
|
* find_file_id
|
||||||
*
|
*
|
||||||
|
@ -3331,6 +3422,44 @@ NTSTATUS CDECL nt_to_unix_file_name( const UNICODE_STRING *nameW, ANSI_STRING *u
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* unix_to_nt_file_name
|
||||||
|
*/
|
||||||
|
NTSTATUS CDECL unix_to_nt_file_name( const ANSI_STRING *name, UNICODE_STRING *nt )
|
||||||
|
{
|
||||||
|
static const WCHAR unix_prefixW[] = {'\\','?','?','\\','u','n','i','x',0};
|
||||||
|
WCHAR dos_prefixW[] = {'\\','?','?','\\','A',':','\\',0};
|
||||||
|
const WCHAR *prefix = unix_prefixW;
|
||||||
|
unsigned int lenW, lenA = name->Length;
|
||||||
|
const char *path = name->Buffer;
|
||||||
|
NTSTATUS status;
|
||||||
|
WCHAR *p;
|
||||||
|
int drive;
|
||||||
|
|
||||||
|
status = find_drive_rootA( &path, lenA, &drive );
|
||||||
|
lenA -= (path - name->Buffer);
|
||||||
|
|
||||||
|
if (status == STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
while (lenA && path[0] == '/') { lenA--; path++; }
|
||||||
|
dos_prefixW[4] += drive;
|
||||||
|
prefix = dos_prefixW;
|
||||||
|
}
|
||||||
|
else if (status != STATUS_OBJECT_PATH_NOT_FOUND) return status;
|
||||||
|
|
||||||
|
lenW = wcslen( prefix );
|
||||||
|
if (!(nt->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, (lenA + lenW + 1) * sizeof(WCHAR) )))
|
||||||
|
return STATUS_NO_MEMORY;
|
||||||
|
memcpy( nt->Buffer, prefix, lenW * sizeof(WCHAR) );
|
||||||
|
lenW += ntdll_umbstowcs( path, lenA, nt->Buffer + lenW, lenA );
|
||||||
|
nt->Buffer[lenW] = 0;
|
||||||
|
nt->Length = lenW * sizeof(WCHAR);
|
||||||
|
nt->MaximumLength = nt->Length + sizeof(WCHAR);
|
||||||
|
for (p = nt->Buffer; *p; p++) if (*p == '/') *p = '\\';
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* unmount_device
|
* unmount_device
|
||||||
*
|
*
|
||||||
|
|
|
@ -961,6 +961,7 @@ static struct unix_funcs unix_funcs =
|
||||||
server_release_fd,
|
server_release_fd,
|
||||||
server_init_process_done,
|
server_init_process_done,
|
||||||
nt_to_unix_file_name,
|
nt_to_unix_file_name,
|
||||||
|
unix_to_nt_file_name,
|
||||||
set_show_dot_files,
|
set_show_dot_files,
|
||||||
__wine_dbg_get_channel_flags,
|
__wine_dbg_get_channel_flags,
|
||||||
__wine_dbg_strdup,
|
__wine_dbg_strdup,
|
||||||
|
|
|
@ -114,6 +114,7 @@ extern NTSTATUS CDECL exec_process( const UNICODE_STRING *cmdline, const pe_imag
|
||||||
|
|
||||||
extern NTSTATUS CDECL nt_to_unix_file_name( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret,
|
extern NTSTATUS CDECL nt_to_unix_file_name( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret,
|
||||||
UINT disposition, BOOLEAN check_case ) DECLSPEC_HIDDEN;
|
UINT disposition, BOOLEAN check_case ) DECLSPEC_HIDDEN;
|
||||||
|
extern NTSTATUS CDECL unix_to_nt_file_name( const ANSI_STRING *name, UNICODE_STRING *nt ) DECLSPEC_HIDDEN;
|
||||||
extern void CDECL set_show_dot_files( BOOL enable ) DECLSPEC_HIDDEN;
|
extern void CDECL set_show_dot_files( BOOL enable ) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
extern const char *data_dir DECLSPEC_HIDDEN;
|
extern const char *data_dir DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -28,7 +28,7 @@ struct ldt_copy;
|
||||||
struct msghdr;
|
struct msghdr;
|
||||||
|
|
||||||
/* increment this when you change the function table */
|
/* increment this when you change the function table */
|
||||||
#define NTDLL_UNIXLIB_VERSION 50
|
#define NTDLL_UNIXLIB_VERSION 51
|
||||||
|
|
||||||
struct unix_funcs
|
struct unix_funcs
|
||||||
{
|
{
|
||||||
|
@ -302,6 +302,7 @@ struct unix_funcs
|
||||||
/* file functions */
|
/* file functions */
|
||||||
NTSTATUS (CDECL *nt_to_unix_file_name)( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret,
|
NTSTATUS (CDECL *nt_to_unix_file_name)( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret,
|
||||||
UINT disposition, BOOLEAN check_case );
|
UINT disposition, BOOLEAN check_case );
|
||||||
|
NTSTATUS (CDECL *unix_to_nt_file_name)( const ANSI_STRING *name, UNICODE_STRING *nt );
|
||||||
void (CDECL *set_show_dot_files)( BOOL enable );
|
void (CDECL *set_show_dot_files)( BOOL enable );
|
||||||
|
|
||||||
/* debugging functions */
|
/* debugging functions */
|
||||||
|
|
Loading…
Reference in New Issue