Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
c3e2013b
Commit
c3e2013b
authored
Jun 13, 2020
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ntdll: Move the get/set file information functions to the Unix library.
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
07248fc5
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1012 additions
and
967 deletions
+1012
-967
file.c
dlls/ntdll/file.c
+2
-949
loader.c
dlls/ntdll/loader.c
+0
-4
ntdll_misc.h
dlls/ntdll/ntdll_misc.h
+0
-1
file.c
dlls/ntdll/unix/file.c
+1003
-3
loader.c
dlls/ntdll/unix/loader.c
+2
-2
unix_private.h
dlls/ntdll/unix/unix_private.h
+0
-3
unixlib.h
dlls/ntdll/unixlib.h
+5
-5
No files found.
dlls/ntdll/file.c
View file @
c3e2013b
...
...
@@ -112,82 +112,9 @@
WINE_DEFAULT_DEBUG_CHANNEL
(
ntdll
);
mode_t
FILE_umask
=
0
;
#define SECSPERDAY 86400
#define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
#define FILE_WRITE_TO_END_OF_FILE ((LONGLONG)-1)
#define FILE_USE_FILE_POINTER_POSITION ((LONGLONG)-2)
/* fetch the attributes of a file */
static
inline
ULONG
get_file_attributes
(
const
struct
stat
*
st
)
{
ULONG
attr
;
if
(
S_ISDIR
(
st
->
st_mode
))
attr
=
FILE_ATTRIBUTE_DIRECTORY
;
else
attr
=
FILE_ATTRIBUTE_ARCHIVE
;
if
(
!
(
st
->
st_mode
&
(
S_IWUSR
|
S_IWGRP
|
S_IWOTH
)))
attr
|=
FILE_ATTRIBUTE_READONLY
;
return
attr
;
}
static
BOOL
fd_is_mount_point
(
int
fd
,
const
struct
stat
*
st
)
{
struct
stat
parent
;
return
S_ISDIR
(
st
->
st_mode
)
&&
!
fstatat
(
fd
,
".."
,
&
parent
,
0
)
&&
(
parent
.
st_dev
!=
st
->
st_dev
||
parent
.
st_ino
==
st
->
st_ino
);
}
/* get the stat info and file attributes for a file (by file descriptor) */
int
fd_get_file_info
(
int
fd
,
unsigned
int
options
,
struct
stat
*
st
,
ULONG
*
attr
)
{
int
ret
;
*
attr
=
0
;
ret
=
fstat
(
fd
,
st
);
if
(
ret
==
-
1
)
return
ret
;
*
attr
|=
get_file_attributes
(
st
);
/* consider mount points to be reparse points (IO_REPARSE_TAG_MOUNT_POINT) */
if
((
options
&
FILE_OPEN_REPARSE_POINT
)
&&
fd_is_mount_point
(
fd
,
st
))
*
attr
|=
FILE_ATTRIBUTE_REPARSE_POINT
;
return
ret
;
}
static
int
get_file_info
(
const
char
*
path
,
struct
stat
*
st
,
ULONG
*
attr
)
{
char
*
parent_path
;
int
ret
;
*
attr
=
0
;
ret
=
lstat
(
path
,
st
);
if
(
ret
==
-
1
)
return
ret
;
if
(
S_ISLNK
(
st
->
st_mode
))
{
ret
=
stat
(
path
,
st
);
if
(
ret
==
-
1
)
return
ret
;
/* is a symbolic link and a directory, consider these "reparse points" */
if
(
S_ISDIR
(
st
->
st_mode
))
*
attr
|=
FILE_ATTRIBUTE_REPARSE_POINT
;
}
else
if
(
S_ISDIR
(
st
->
st_mode
)
&&
(
parent_path
=
RtlAllocateHeap
(
GetProcessHeap
(),
0
,
strlen
(
path
)
+
4
)))
{
struct
stat
parent_st
;
/* consider mount points to be reparse points (IO_REPARSE_TAG_MOUNT_POINT) */
strcpy
(
parent_path
,
path
);
strcat
(
parent_path
,
"/.."
);
if
(
!
stat
(
parent_path
,
&
parent_st
)
&&
(
st
->
st_dev
!=
parent_st
.
st_dev
||
st
->
st_ino
==
parent_st
.
st_ino
))
*
attr
|=
FILE_ATTRIBUTE_REPARSE_POINT
;
RtlFreeHeap
(
GetProcessHeap
(),
0
,
parent_path
);
}
*
attr
|=
get_file_attributes
(
st
);
return
ret
;
}
/**************************************************************************
* NtOpenFile [NTDLL.@]
...
...
@@ -1802,244 +1729,6 @@ NTSTATUS WINAPI NtSetVolumeInformationFile(
return
0
;
}
#if defined(__ANDROID__) && !defined(HAVE_FUTIMENS)
static
int
futimens
(
int
fd
,
const
struct
timespec
spec
[
2
]
)
{
return
syscall
(
__NR_utimensat
,
fd
,
NULL
,
spec
,
0
);
}
#define HAVE_FUTIMENS
#endif
/* __ANDROID__ */
#ifndef UTIME_OMIT
#define UTIME_OMIT ((1 << 30) - 2)
#endif
static
BOOL
set_file_times_precise
(
int
fd
,
const
LARGE_INTEGER
*
mtime
,
const
LARGE_INTEGER
*
atime
,
NTSTATUS
*
status
)
{
#ifdef HAVE_FUTIMENS
struct
timespec
tv
[
2
];
tv
[
0
].
tv_sec
=
tv
[
1
].
tv_sec
=
0
;
tv
[
0
].
tv_nsec
=
tv
[
1
].
tv_nsec
=
UTIME_OMIT
;
if
(
atime
->
QuadPart
)
{
tv
[
0
].
tv_sec
=
atime
->
QuadPart
/
10000000
-
SECS_1601_TO_1970
;
tv
[
0
].
tv_nsec
=
(
atime
->
QuadPart
%
10000000
)
*
100
;
}
if
(
mtime
->
QuadPart
)
{
tv
[
1
].
tv_sec
=
mtime
->
QuadPart
/
10000000
-
SECS_1601_TO_1970
;
tv
[
1
].
tv_nsec
=
(
mtime
->
QuadPart
%
10000000
)
*
100
;
}
#ifdef __APPLE__
if
(
!&
futimens
)
return
FALSE
;
#endif
if
(
futimens
(
fd
,
tv
)
==
-
1
)
*
status
=
FILE_GetNtStatus
();
else
*
status
=
STATUS_SUCCESS
;
return
TRUE
;
#else
return
FALSE
;
#endif
}
static
NTSTATUS
set_file_times
(
int
fd
,
const
LARGE_INTEGER
*
mtime
,
const
LARGE_INTEGER
*
atime
)
{
NTSTATUS
status
=
STATUS_SUCCESS
;
#if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT)
struct
timeval
tv
[
2
];
struct
stat
st
;
#endif
if
(
set_file_times_precise
(
fd
,
mtime
,
atime
,
&
status
))
return
status
;
#if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT)
if
(
!
atime
->
QuadPart
||
!
mtime
->
QuadPart
)
{
tv
[
0
].
tv_sec
=
tv
[
0
].
tv_usec
=
0
;
tv
[
1
].
tv_sec
=
tv
[
1
].
tv_usec
=
0
;
if
(
!
fstat
(
fd
,
&
st
))
{
tv
[
0
].
tv_sec
=
st
.
st_atime
;
tv
[
1
].
tv_sec
=
st
.
st_mtime
;
#ifdef HAVE_STRUCT_STAT_ST_ATIM
tv
[
0
].
tv_usec
=
st
.
st_atim
.
tv_nsec
/
1000
;
#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
tv
[
0
].
tv_usec
=
st
.
st_atimespec
.
tv_nsec
/
1000
;
#endif
#ifdef HAVE_STRUCT_STAT_ST_MTIM
tv
[
1
].
tv_usec
=
st
.
st_mtim
.
tv_nsec
/
1000
;
#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
tv
[
1
].
tv_usec
=
st
.
st_mtimespec
.
tv_nsec
/
1000
;
#endif
}
}
if
(
atime
->
QuadPart
)
{
tv
[
0
].
tv_sec
=
atime
->
QuadPart
/
10000000
-
SECS_1601_TO_1970
;
tv
[
0
].
tv_usec
=
(
atime
->
QuadPart
%
10000000
)
/
10
;
}
if
(
mtime
->
QuadPart
)
{
tv
[
1
].
tv_sec
=
mtime
->
QuadPart
/
10000000
-
SECS_1601_TO_1970
;
tv
[
1
].
tv_usec
=
(
mtime
->
QuadPart
%
10000000
)
/
10
;
}
#ifdef HAVE_FUTIMES
if
(
futimes
(
fd
,
tv
)
==
-
1
)
status
=
FILE_GetNtStatus
();
#elif defined(HAVE_FUTIMESAT)
if
(
futimesat
(
fd
,
NULL
,
tv
)
==
-
1
)
status
=
FILE_GetNtStatus
();
#endif
#else
/* HAVE_FUTIMES || HAVE_FUTIMESAT */
FIXME
(
"setting file times not supported
\n
"
);
status
=
STATUS_NOT_IMPLEMENTED
;
#endif
return
status
;
}
static
inline
void
get_file_times
(
const
struct
stat
*
st
,
LARGE_INTEGER
*
mtime
,
LARGE_INTEGER
*
ctime
,
LARGE_INTEGER
*
atime
,
LARGE_INTEGER
*
creation
)
{
RtlSecondsSince1970ToTime
(
st
->
st_mtime
,
mtime
);
RtlSecondsSince1970ToTime
(
st
->
st_ctime
,
ctime
);
RtlSecondsSince1970ToTime
(
st
->
st_atime
,
atime
);
#ifdef HAVE_STRUCT_STAT_ST_MTIM
mtime
->
QuadPart
+=
st
->
st_mtim
.
tv_nsec
/
100
;
#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
mtime
->
QuadPart
+=
st
->
st_mtimespec
.
tv_nsec
/
100
;
#endif
#ifdef HAVE_STRUCT_STAT_ST_CTIM
ctime
->
QuadPart
+=
st
->
st_ctim
.
tv_nsec
/
100
;
#elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
ctime
->
QuadPart
+=
st
->
st_ctimespec
.
tv_nsec
/
100
;
#endif
#ifdef HAVE_STRUCT_STAT_ST_ATIM
atime
->
QuadPart
+=
st
->
st_atim
.
tv_nsec
/
100
;
#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
atime
->
QuadPart
+=
st
->
st_atimespec
.
tv_nsec
/
100
;
#endif
#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
RtlSecondsSince1970ToTime
(
st
->
st_birthtime
,
creation
);
#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIM
creation
->
QuadPart
+=
st
->
st_birthtim
.
tv_nsec
/
100
;
#elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
creation
->
QuadPart
+=
st
->
st_birthtimespec
.
tv_nsec
/
100
;
#endif
#elif defined(HAVE_STRUCT_STAT___ST_BIRTHTIME)
RtlSecondsSince1970ToTime
(
st
->
__st_birthtime
,
creation
);
#ifdef HAVE_STRUCT_STAT___ST_BIRTHTIM
creation
->
QuadPart
+=
st
->
__st_birthtim
.
tv_nsec
/
100
;
#endif
#else
*
creation
=
*
mtime
;
#endif
}
/* fill in the file information that depends on the stat and attribute info */
NTSTATUS
fill_file_info
(
const
struct
stat
*
st
,
ULONG
attr
,
void
*
ptr
,
FILE_INFORMATION_CLASS
class
)
{
switch
(
class
)
{
case
FileBasicInformation
:
{
FILE_BASIC_INFORMATION
*
info
=
ptr
;
get_file_times
(
st
,
&
info
->
LastWriteTime
,
&
info
->
ChangeTime
,
&
info
->
LastAccessTime
,
&
info
->
CreationTime
);
info
->
FileAttributes
=
attr
;
}
break
;
case
FileStandardInformation
:
{
FILE_STANDARD_INFORMATION
*
info
=
ptr
;
if
((
info
->
Directory
=
S_ISDIR
(
st
->
st_mode
)))
{
info
->
AllocationSize
.
QuadPart
=
0
;
info
->
EndOfFile
.
QuadPart
=
0
;
info
->
NumberOfLinks
=
1
;
}
else
{
info
->
AllocationSize
.
QuadPart
=
(
ULONGLONG
)
st
->
st_blocks
*
512
;
info
->
EndOfFile
.
QuadPart
=
st
->
st_size
;
info
->
NumberOfLinks
=
st
->
st_nlink
;
}
}
break
;
case
FileInternalInformation
:
{
FILE_INTERNAL_INFORMATION
*
info
=
ptr
;
info
->
IndexNumber
.
QuadPart
=
st
->
st_ino
;
}
break
;
case
FileEndOfFileInformation
:
{
FILE_END_OF_FILE_INFORMATION
*
info
=
ptr
;
info
->
EndOfFile
.
QuadPart
=
S_ISDIR
(
st
->
st_mode
)
?
0
:
st
->
st_size
;
}
break
;
case
FileAllInformation
:
{
FILE_ALL_INFORMATION
*
info
=
ptr
;
fill_file_info
(
st
,
attr
,
&
info
->
BasicInformation
,
FileBasicInformation
);
fill_file_info
(
st
,
attr
,
&
info
->
StandardInformation
,
FileStandardInformation
);
fill_file_info
(
st
,
attr
,
&
info
->
InternalInformation
,
FileInternalInformation
);
}
break
;
/* all directory structures start with the FileDirectoryInformation layout */
case
FileBothDirectoryInformation
:
case
FileFullDirectoryInformation
:
case
FileDirectoryInformation
:
{
FILE_DIRECTORY_INFORMATION
*
info
=
ptr
;
get_file_times
(
st
,
&
info
->
LastWriteTime
,
&
info
->
ChangeTime
,
&
info
->
LastAccessTime
,
&
info
->
CreationTime
);
if
(
S_ISDIR
(
st
->
st_mode
))
{
info
->
AllocationSize
.
QuadPart
=
0
;
info
->
EndOfFile
.
QuadPart
=
0
;
}
else
{
info
->
AllocationSize
.
QuadPart
=
(
ULONGLONG
)
st
->
st_blocks
*
512
;
info
->
EndOfFile
.
QuadPart
=
st
->
st_size
;
}
info
->
FileAttributes
=
attr
;
}
break
;
case
FileIdFullDirectoryInformation
:
{
FILE_ID_FULL_DIRECTORY_INFORMATION
*
info
=
ptr
;
info
->
FileId
.
QuadPart
=
st
->
st_ino
;
fill_file_info
(
st
,
attr
,
info
,
FileDirectoryInformation
);
}
break
;
case
FileIdBothDirectoryInformation
:
{
FILE_ID_BOTH_DIRECTORY_INFORMATION
*
info
=
ptr
;
info
->
FileId
.
QuadPart
=
st
->
st_ino
;
fill_file_info
(
st
,
attr
,
info
,
FileDirectoryInformation
);
}
break
;
case
FileIdGlobalTxDirectoryInformation
:
{
FILE_ID_GLOBAL_TX_DIR_INFORMATION
*
info
=
ptr
;
info
->
FileId
.
QuadPart
=
st
->
st_ino
;
fill_file_info
(
st
,
attr
,
info
,
FileDirectoryInformation
);
}
break
;
default:
return
STATUS_INVALID_INFO_CLASS
;
}
return
STATUS_SUCCESS
;
}
NTSTATUS
server_get_unix_name
(
HANDLE
handle
,
ANSI_STRING
*
unix_name
)
{
data_size_t
size
=
1024
;
...
...
@@ -2074,51 +1763,6 @@ NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name )
return
ret
;
}
static
NTSTATUS
fill_name_info
(
const
ANSI_STRING
*
unix_name
,
FILE_NAME_INFORMATION
*
info
,
LONG
*
name_len
)
{
UNICODE_STRING
nt_name
;
NTSTATUS
status
;
if
(
!
(
status
=
wine_unix_to_nt_file_name
(
unix_name
,
&
nt_name
)))
{
const
WCHAR
*
ptr
=
nt_name
.
Buffer
;
const
WCHAR
*
end
=
ptr
+
(
nt_name
.
Length
/
sizeof
(
WCHAR
));
/* Skip the volume mount point. */
while
(
ptr
!=
end
&&
*
ptr
==
'\\'
)
++
ptr
;
while
(
ptr
!=
end
&&
*
ptr
!=
'\\'
)
++
ptr
;
while
(
ptr
!=
end
&&
*
ptr
==
'\\'
)
++
ptr
;
while
(
ptr
!=
end
&&
*
ptr
!=
'\\'
)
++
ptr
;
info
->
FileNameLength
=
(
end
-
ptr
)
*
sizeof
(
WCHAR
);
if
(
*
name_len
<
info
->
FileNameLength
)
status
=
STATUS_BUFFER_OVERFLOW
;
else
*
name_len
=
info
->
FileNameLength
;
memcpy
(
info
->
FileName
,
ptr
,
*
name_len
);
RtlFreeUnicodeString
(
&
nt_name
);
}
return
status
;
}
static
NTSTATUS
server_get_file_info
(
HANDLE
handle
,
IO_STATUS_BLOCK
*
io
,
void
*
buffer
,
ULONG
length
,
FILE_INFORMATION_CLASS
info_class
)
{
SERVER_START_REQ
(
get_file_info
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
info_class
=
info_class
;
wine_server_set_reply
(
req
,
buffer
,
length
);
io
->
u
.
Status
=
wine_server_call
(
req
);
io
->
Information
=
wine_server_reply_size
(
reply
);
}
SERVER_END_REQ
;
if
(
io
->
u
.
Status
==
STATUS_NOT_IMPLEMENTED
)
FIXME
(
"Unsupported info class %x
\n
"
,
info_class
);
return
io
->
u
.
Status
;
}
/* Find a DOS device which can act as the root of "path".
* Similar to find_drive_root(), but returns -1 instead of crossing volumes. */
static
int
find_dos_device
(
const
char
*
path
)
...
...
@@ -2260,288 +1904,7 @@ static struct mountmgr_unix_drive *get_mountmgr_fs_info( HANDLE handle, int fd )
NTSTATUS
WINAPI
NtQueryInformationFile
(
HANDLE
hFile
,
PIO_STATUS_BLOCK
io
,
PVOID
ptr
,
LONG
len
,
FILE_INFORMATION_CLASS
class
)
{
static
const
size_t
info_sizes
[]
=
{
0
,
sizeof
(
FILE_DIRECTORY_INFORMATION
),
/* FileDirectoryInformation */
sizeof
(
FILE_FULL_DIRECTORY_INFORMATION
),
/* FileFullDirectoryInformation */
sizeof
(
FILE_BOTH_DIRECTORY_INFORMATION
),
/* FileBothDirectoryInformation */
sizeof
(
FILE_BASIC_INFORMATION
),
/* FileBasicInformation */
sizeof
(
FILE_STANDARD_INFORMATION
),
/* FileStandardInformation */
sizeof
(
FILE_INTERNAL_INFORMATION
),
/* FileInternalInformation */
sizeof
(
FILE_EA_INFORMATION
),
/* FileEaInformation */
0
,
/* FileAccessInformation */
sizeof
(
FILE_NAME_INFORMATION
),
/* FileNameInformation */
sizeof
(
FILE_RENAME_INFORMATION
)
-
sizeof
(
WCHAR
),
/* FileRenameInformation */
0
,
/* FileLinkInformation */
sizeof
(
FILE_NAMES_INFORMATION
)
-
sizeof
(
WCHAR
),
/* FileNamesInformation */
sizeof
(
FILE_DISPOSITION_INFORMATION
),
/* FileDispositionInformation */
sizeof
(
FILE_POSITION_INFORMATION
),
/* FilePositionInformation */
sizeof
(
FILE_FULL_EA_INFORMATION
),
/* FileFullEaInformation */
0
,
/* FileModeInformation */
sizeof
(
FILE_ALIGNMENT_INFORMATION
),
/* FileAlignmentInformation */
sizeof
(
FILE_ALL_INFORMATION
),
/* FileAllInformation */
sizeof
(
FILE_ALLOCATION_INFORMATION
),
/* FileAllocationInformation */
sizeof
(
FILE_END_OF_FILE_INFORMATION
),
/* FileEndOfFileInformation */
0
,
/* FileAlternateNameInformation */
sizeof
(
FILE_STREAM_INFORMATION
)
-
sizeof
(
WCHAR
),
/* FileStreamInformation */
sizeof
(
FILE_PIPE_INFORMATION
),
/* FilePipeInformation */
sizeof
(
FILE_PIPE_LOCAL_INFORMATION
),
/* FilePipeLocalInformation */
0
,
/* FilePipeRemoteInformation */
sizeof
(
FILE_MAILSLOT_QUERY_INFORMATION
),
/* FileMailslotQueryInformation */
0
,
/* FileMailslotSetInformation */
0
,
/* FileCompressionInformation */
0
,
/* FileObjectIdInformation */
0
,
/* FileCompletionInformation */
0
,
/* FileMoveClusterInformation */
0
,
/* FileQuotaInformation */
0
,
/* FileReparsePointInformation */
sizeof
(
FILE_NETWORK_OPEN_INFORMATION
),
/* FileNetworkOpenInformation */
sizeof
(
FILE_ATTRIBUTE_TAG_INFORMATION
),
/* FileAttributeTagInformation */
0
,
/* FileTrackingInformation */
0
,
/* FileIdBothDirectoryInformation */
0
,
/* FileIdFullDirectoryInformation */
0
,
/* FileValidDataLengthInformation */
0
,
/* FileShortNameInformation */
0
,
/* FileIoCompletionNotificationInformation, */
0
,
/* FileIoStatusBlockRangeInformation */
0
,
/* FileIoPriorityHintInformation */
0
,
/* FileSfioReserveInformation */
0
,
/* FileSfioVolumeInformation */
0
,
/* FileHardLinkInformation */
0
,
/* FileProcessIdsUsingFileInformation */
0
,
/* FileNormalizedNameInformation */
0
,
/* FileNetworkPhysicalNameInformation */
0
,
/* FileIdGlobalTxDirectoryInformation */
0
,
/* FileIsRemoteDeviceInformation */
0
,
/* FileAttributeCacheInformation */
0
,
/* FileNumaNodeInformation */
0
,
/* FileStandardLinkInformation */
0
,
/* FileRemoteProtocolInformation */
0
,
/* FileRenameInformationBypassAccessCheck */
0
,
/* FileLinkInformationBypassAccessCheck */
0
,
/* FileVolumeNameInformation */
sizeof
(
FILE_ID_INFORMATION
),
/* FileIdInformation */
0
,
/* FileIdExtdDirectoryInformation */
0
,
/* FileReplaceCompletionInformation */
0
,
/* FileHardLinkFullIdInformation */
0
,
/* FileIdExtdBothDirectoryInformation */
};
struct
stat
st
;
int
fd
,
needs_close
=
FALSE
;
ULONG
attr
;
unsigned
int
options
;
TRACE
(
"(%p,%p,%p,0x%08x,0x%08x)
\n
"
,
hFile
,
io
,
ptr
,
len
,
class
);
io
->
Information
=
0
;
if
(
class
<=
0
||
class
>=
FileMaximumInformation
)
return
io
->
u
.
Status
=
STATUS_INVALID_INFO_CLASS
;
if
(
!
info_sizes
[
class
])
return
server_get_file_info
(
hFile
,
io
,
ptr
,
len
,
class
);
if
(
len
<
info_sizes
[
class
])
return
io
->
u
.
Status
=
STATUS_INFO_LENGTH_MISMATCH
;
if
((
io
->
u
.
Status
=
unix_funcs
->
server_get_unix_fd
(
hFile
,
0
,
&
fd
,
&
needs_close
,
NULL
,
&
options
)))
{
if
(
io
->
u
.
Status
!=
STATUS_BAD_DEVICE_TYPE
)
return
io
->
u
.
Status
;
return
server_get_file_info
(
hFile
,
io
,
ptr
,
len
,
class
);
}
switch
(
class
)
{
case
FileBasicInformation
:
if
(
fd_get_file_info
(
fd
,
options
,
&
st
,
&
attr
)
==
-
1
)
io
->
u
.
Status
=
FILE_GetNtStatus
();
else
if
(
!
S_ISREG
(
st
.
st_mode
)
&&
!
S_ISDIR
(
st
.
st_mode
))
io
->
u
.
Status
=
STATUS_INVALID_INFO_CLASS
;
else
fill_file_info
(
&
st
,
attr
,
ptr
,
class
);
break
;
case
FileStandardInformation
:
{
FILE_STANDARD_INFORMATION
*
info
=
ptr
;
if
(
fd_get_file_info
(
fd
,
options
,
&
st
,
&
attr
)
==
-
1
)
io
->
u
.
Status
=
FILE_GetNtStatus
();
else
{
fill_file_info
(
&
st
,
attr
,
info
,
class
);
info
->
DeletePending
=
FALSE
;
/* FIXME */
}
}
break
;
case
FilePositionInformation
:
{
FILE_POSITION_INFORMATION
*
info
=
ptr
;
off_t
res
=
lseek
(
fd
,
0
,
SEEK_CUR
);
if
(
res
==
(
off_t
)
-
1
)
io
->
u
.
Status
=
FILE_GetNtStatus
();
else
info
->
CurrentByteOffset
.
QuadPart
=
res
;
}
break
;
case
FileInternalInformation
:
if
(
fd_get_file_info
(
fd
,
options
,
&
st
,
&
attr
)
==
-
1
)
io
->
u
.
Status
=
FILE_GetNtStatus
();
else
fill_file_info
(
&
st
,
attr
,
ptr
,
class
);
break
;
case
FileEaInformation
:
{
FILE_EA_INFORMATION
*
info
=
ptr
;
info
->
EaSize
=
0
;
}
break
;
case
FileEndOfFileInformation
:
if
(
fd_get_file_info
(
fd
,
options
,
&
st
,
&
attr
)
==
-
1
)
io
->
u
.
Status
=
FILE_GetNtStatus
();
else
fill_file_info
(
&
st
,
attr
,
ptr
,
class
);
break
;
case
FileAllInformation
:
{
FILE_ALL_INFORMATION
*
info
=
ptr
;
ANSI_STRING
unix_name
;
if
(
fd_get_file_info
(
fd
,
options
,
&
st
,
&
attr
)
==
-
1
)
io
->
u
.
Status
=
FILE_GetNtStatus
();
else
if
(
!
S_ISREG
(
st
.
st_mode
)
&&
!
S_ISDIR
(
st
.
st_mode
))
io
->
u
.
Status
=
STATUS_INVALID_INFO_CLASS
;
else
if
(
!
(
io
->
u
.
Status
=
server_get_unix_name
(
hFile
,
&
unix_name
)))
{
LONG
name_len
=
len
-
FIELD_OFFSET
(
FILE_ALL_INFORMATION
,
NameInformation
.
FileName
);
fill_file_info
(
&
st
,
attr
,
info
,
FileAllInformation
);
info
->
StandardInformation
.
DeletePending
=
FALSE
;
/* FIXME */
info
->
EaInformation
.
EaSize
=
0
;
info
->
AccessInformation
.
AccessFlags
=
0
;
/* FIXME */
info
->
PositionInformation
.
CurrentByteOffset
.
QuadPart
=
lseek
(
fd
,
0
,
SEEK_CUR
);
info
->
ModeInformation
.
Mode
=
0
;
/* FIXME */
info
->
AlignmentInformation
.
AlignmentRequirement
=
1
;
/* FIXME */
io
->
u
.
Status
=
fill_name_info
(
&
unix_name
,
&
info
->
NameInformation
,
&
name_len
);
RtlFreeAnsiString
(
&
unix_name
);
io
->
Information
=
FIELD_OFFSET
(
FILE_ALL_INFORMATION
,
NameInformation
.
FileName
)
+
name_len
;
}
}
break
;
case
FileMailslotQueryInformation
:
{
FILE_MAILSLOT_QUERY_INFORMATION
*
info
=
ptr
;
SERVER_START_REQ
(
set_mailslot_info
)
{
req
->
handle
=
wine_server_obj_handle
(
hFile
);
req
->
flags
=
0
;
io
->
u
.
Status
=
wine_server_call
(
req
);
if
(
io
->
u
.
Status
==
STATUS_SUCCESS
)
{
info
->
MaximumMessageSize
=
reply
->
max_msgsize
;
info
->
MailslotQuota
=
0
;
info
->
NextMessageSize
=
0
;
info
->
MessagesAvailable
=
0
;
info
->
ReadTimeout
.
QuadPart
=
reply
->
read_timeout
;
}
}
SERVER_END_REQ
;
if
(
!
io
->
u
.
Status
)
{
char
*
tmpbuf
;
ULONG
size
=
info
->
MaximumMessageSize
?
info
->
MaximumMessageSize
:
0x10000
;
if
(
size
>
0x10000
)
size
=
0x10000
;
if
((
tmpbuf
=
RtlAllocateHeap
(
GetProcessHeap
(),
0
,
size
)))
{
if
(
!
unix_funcs
->
server_get_unix_fd
(
hFile
,
FILE_READ_DATA
,
&
fd
,
&
needs_close
,
NULL
,
NULL
))
{
int
res
=
recv
(
fd
,
tmpbuf
,
size
,
MSG_PEEK
);
info
->
MessagesAvailable
=
(
res
>
0
);
info
->
NextMessageSize
=
(
res
>=
0
)
?
res
:
MAILSLOT_NO_MESSAGE
;
if
(
needs_close
)
close
(
fd
);
}
RtlFreeHeap
(
GetProcessHeap
(),
0
,
tmpbuf
);
}
}
}
break
;
case
FileNameInformation
:
{
FILE_NAME_INFORMATION
*
info
=
ptr
;
ANSI_STRING
unix_name
;
if
(
!
(
io
->
u
.
Status
=
server_get_unix_name
(
hFile
,
&
unix_name
)))
{
LONG
name_len
=
len
-
FIELD_OFFSET
(
FILE_NAME_INFORMATION
,
FileName
);
io
->
u
.
Status
=
fill_name_info
(
&
unix_name
,
info
,
&
name_len
);
RtlFreeAnsiString
(
&
unix_name
);
io
->
Information
=
FIELD_OFFSET
(
FILE_NAME_INFORMATION
,
FileName
)
+
name_len
;
}
}
break
;
case
FileNetworkOpenInformation
:
{
FILE_NETWORK_OPEN_INFORMATION
*
info
=
ptr
;
ANSI_STRING
unix_name
;
if
(
!
(
io
->
u
.
Status
=
server_get_unix_name
(
hFile
,
&
unix_name
)))
{
ULONG
attributes
;
struct
stat
st
;
if
(
get_file_info
(
unix_name
.
Buffer
,
&
st
,
&
attributes
)
==
-
1
)
io
->
u
.
Status
=
FILE_GetNtStatus
();
else
if
(
!
S_ISREG
(
st
.
st_mode
)
&&
!
S_ISDIR
(
st
.
st_mode
))
io
->
u
.
Status
=
STATUS_INVALID_INFO_CLASS
;
else
{
FILE_BASIC_INFORMATION
basic
;
FILE_STANDARD_INFORMATION
std
;
fill_file_info
(
&
st
,
attributes
,
&
basic
,
FileBasicInformation
);
fill_file_info
(
&
st
,
attributes
,
&
std
,
FileStandardInformation
);
info
->
CreationTime
=
basic
.
CreationTime
;
info
->
LastAccessTime
=
basic
.
LastAccessTime
;
info
->
LastWriteTime
=
basic
.
LastWriteTime
;
info
->
ChangeTime
=
basic
.
ChangeTime
;
info
->
AllocationSize
=
std
.
AllocationSize
;
info
->
EndOfFile
=
std
.
EndOfFile
;
info
->
FileAttributes
=
basic
.
FileAttributes
;
}
RtlFreeAnsiString
(
&
unix_name
);
}
}
break
;
case
FileIdInformation
:
if
(
fd_get_file_info
(
fd
,
options
,
&
st
,
&
attr
)
==
-
1
)
io
->
u
.
Status
=
FILE_GetNtStatus
();
else
{
struct
mountmgr_unix_drive
*
drive
;
FILE_ID_INFORMATION
*
info
=
ptr
;
info
->
VolumeSerialNumber
=
0
;
if
((
drive
=
get_mountmgr_fs_info
(
hFile
,
fd
)))
{
info
->
VolumeSerialNumber
=
drive
->
serial
;
RtlFreeHeap
(
GetProcessHeap
(),
0
,
drive
);
}
memset
(
&
info
->
FileId
,
0
,
sizeof
(
info
->
FileId
)
);
*
(
ULONGLONG
*
)
&
info
->
FileId
=
st
.
st_ino
;
}
break
;
case
FileAttributeTagInformation
:
if
(
fd_get_file_info
(
fd
,
options
,
&
st
,
&
attr
)
==
-
1
)
io
->
u
.
Status
=
FILE_GetNtStatus
();
else
{
FILE_ATTRIBUTE_TAG_INFORMATION
*
info
=
ptr
;
info
->
FileAttributes
=
attr
;
info
->
ReparseTag
=
0
;
/* FIXME */
if
((
options
&
FILE_OPEN_REPARSE_POINT
)
&&
fd_is_mount_point
(
fd
,
&
st
))
info
->
ReparseTag
=
IO_REPARSE_TAG_MOUNT_POINT
;
}
break
;
default:
FIXME
(
"Unsupported class (%d)
\n
"
,
class
);
io
->
u
.
Status
=
STATUS_NOT_IMPLEMENTED
;
break
;
}
if
(
needs_close
)
close
(
fd
);
if
(
io
->
u
.
Status
==
STATUS_SUCCESS
&&
!
io
->
Information
)
io
->
Information
=
info_sizes
[
class
];
return
io
->
u
.
Status
;
return
unix_funcs
->
NtQueryInformationFile
(
hFile
,
io
,
ptr
,
len
,
class
);
}
/******************************************************************************
...
...
@@ -2564,317 +1927,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
NTSTATUS
WINAPI
NtSetInformationFile
(
HANDLE
handle
,
PIO_STATUS_BLOCK
io
,
PVOID
ptr
,
ULONG
len
,
FILE_INFORMATION_CLASS
class
)
{
int
fd
,
needs_close
;
TRACE
(
"(%p,%p,%p,0x%08x,0x%08x)
\n
"
,
handle
,
io
,
ptr
,
len
,
class
);
io
->
u
.
Status
=
STATUS_SUCCESS
;
switch
(
class
)
{
case
FileBasicInformation
:
if
(
len
>=
sizeof
(
FILE_BASIC_INFORMATION
))
{
struct
stat
st
;
const
FILE_BASIC_INFORMATION
*
info
=
ptr
;
LARGE_INTEGER
mtime
,
atime
;
if
((
io
->
u
.
Status
=
unix_funcs
->
server_get_unix_fd
(
handle
,
0
,
&
fd
,
&
needs_close
,
NULL
,
NULL
)))
return
io
->
u
.
Status
;
mtime
.
QuadPart
=
info
->
LastWriteTime
.
QuadPart
==
-
1
?
0
:
info
->
LastWriteTime
.
QuadPart
;
atime
.
QuadPart
=
info
->
LastAccessTime
.
QuadPart
==
-
1
?
0
:
info
->
LastAccessTime
.
QuadPart
;
if
(
atime
.
QuadPart
||
mtime
.
QuadPart
)
io
->
u
.
Status
=
set_file_times
(
fd
,
&
mtime
,
&
atime
);
if
(
io
->
u
.
Status
==
STATUS_SUCCESS
&&
info
->
FileAttributes
)
{
if
(
fstat
(
fd
,
&
st
)
==
-
1
)
io
->
u
.
Status
=
FILE_GetNtStatus
();
else
{
if
(
info
->
FileAttributes
&
FILE_ATTRIBUTE_READONLY
)
{
if
(
S_ISDIR
(
st
.
st_mode
))
WARN
(
"FILE_ATTRIBUTE_READONLY ignored for directory.
\n
"
);
else
st
.
st_mode
&=
~
0222
;
/* clear write permission bits */
}
else
{
/* add write permission only where we already have read permission */
st
.
st_mode
|=
(
0600
|
((
st
.
st_mode
&
044
)
>>
1
))
&
(
~
FILE_umask
);
}
if
(
fchmod
(
fd
,
st
.
st_mode
)
==
-
1
)
io
->
u
.
Status
=
FILE_GetNtStatus
();
}
}
if
(
needs_close
)
close
(
fd
);
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
case
FilePositionInformation
:
if
(
len
>=
sizeof
(
FILE_POSITION_INFORMATION
))
{
const
FILE_POSITION_INFORMATION
*
info
=
ptr
;
if
((
io
->
u
.
Status
=
unix_funcs
->
server_get_unix_fd
(
handle
,
0
,
&
fd
,
&
needs_close
,
NULL
,
NULL
)))
return
io
->
u
.
Status
;
if
(
lseek
(
fd
,
info
->
CurrentByteOffset
.
QuadPart
,
SEEK_SET
)
==
(
off_t
)
-
1
)
io
->
u
.
Status
=
FILE_GetNtStatus
();
if
(
needs_close
)
close
(
fd
);
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
case
FileEndOfFileInformation
:
if
(
len
>=
sizeof
(
FILE_END_OF_FILE_INFORMATION
))
{
struct
stat
st
;
const
FILE_END_OF_FILE_INFORMATION
*
info
=
ptr
;
if
((
io
->
u
.
Status
=
unix_funcs
->
server_get_unix_fd
(
handle
,
0
,
&
fd
,
&
needs_close
,
NULL
,
NULL
)))
return
io
->
u
.
Status
;
/* first try normal truncate */
if
(
ftruncate
(
fd
,
(
off_t
)
info
->
EndOfFile
.
QuadPart
)
!=
-
1
)
break
;
/* now check for the need to extend the file */
if
(
fstat
(
fd
,
&
st
)
!=
-
1
&&
(
off_t
)
info
->
EndOfFile
.
QuadPart
>
st
.
st_size
)
{
static
const
char
zero
;
/* extend the file one byte beyond the requested size and then truncate it */
/* this should work around ftruncate implementations that can't extend files */
if
(
pwrite
(
fd
,
&
zero
,
1
,
(
off_t
)
info
->
EndOfFile
.
QuadPart
)
!=
-
1
&&
ftruncate
(
fd
,
(
off_t
)
info
->
EndOfFile
.
QuadPart
)
!=
-
1
)
break
;
}
io
->
u
.
Status
=
FILE_GetNtStatus
();
if
(
needs_close
)
close
(
fd
);
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
case
FilePipeInformation
:
if
(
len
>=
sizeof
(
FILE_PIPE_INFORMATION
))
{
FILE_PIPE_INFORMATION
*
info
=
ptr
;
if
((
info
->
CompletionMode
|
info
->
ReadMode
)
&
~
1
)
{
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER
;
break
;
}
SERVER_START_REQ
(
set_named_pipe_info
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
flags
=
(
info
->
CompletionMode
?
NAMED_PIPE_NONBLOCKING_MODE
:
0
)
|
(
info
->
ReadMode
?
NAMED_PIPE_MESSAGE_STREAM_READ
:
0
);
io
->
u
.
Status
=
wine_server_call
(
req
);
}
SERVER_END_REQ
;
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
case
FileMailslotSetInformation
:
{
FILE_MAILSLOT_SET_INFORMATION
*
info
=
ptr
;
SERVER_START_REQ
(
set_mailslot_info
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
flags
=
MAILSLOT_SET_READ_TIMEOUT
;
req
->
read_timeout
=
info
->
ReadTimeout
.
QuadPart
;
io
->
u
.
Status
=
wine_server_call
(
req
);
}
SERVER_END_REQ
;
}
break
;
case
FileCompletionInformation
:
if
(
len
>=
sizeof
(
FILE_COMPLETION_INFORMATION
))
{
FILE_COMPLETION_INFORMATION
*
info
=
ptr
;
SERVER_START_REQ
(
set_completion_info
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
chandle
=
wine_server_obj_handle
(
info
->
CompletionPort
);
req
->
ckey
=
info
->
CompletionKey
;
io
->
u
.
Status
=
wine_server_call
(
req
);
}
SERVER_END_REQ
;
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
case
FileIoCompletionNotificationInformation
:
if
(
len
>=
sizeof
(
FILE_IO_COMPLETION_NOTIFICATION_INFORMATION
))
{
FILE_IO_COMPLETION_NOTIFICATION_INFORMATION
*
info
=
ptr
;
if
(
info
->
Flags
&
FILE_SKIP_SET_USER_EVENT_ON_FAST_IO
)
FIXME
(
"FILE_SKIP_SET_USER_EVENT_ON_FAST_IO not supported
\n
"
);
SERVER_START_REQ
(
set_fd_completion_mode
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
flags
=
info
->
Flags
;
io
->
u
.
Status
=
wine_server_call
(
req
);
}
SERVER_END_REQ
;
}
else
io
->
u
.
Status
=
STATUS_INFO_LENGTH_MISMATCH
;
break
;
case
FileIoPriorityHintInformation
:
if
(
len
>=
sizeof
(
FILE_IO_PRIORITY_HINT_INFO
))
{
FILE_IO_PRIORITY_HINT_INFO
*
info
=
ptr
;
if
(
info
->
PriorityHint
<
MaximumIoPriorityHintType
)
TRACE
(
"ignoring FileIoPriorityHintInformation %u
\n
"
,
info
->
PriorityHint
);
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER
;
}
else
io
->
u
.
Status
=
STATUS_INFO_LENGTH_MISMATCH
;
break
;
case
FileAllInformation
:
io
->
u
.
Status
=
STATUS_INVALID_INFO_CLASS
;
break
;
case
FileValidDataLengthInformation
:
if
(
len
>=
sizeof
(
FILE_VALID_DATA_LENGTH_INFORMATION
))
{
struct
stat
st
;
const
FILE_VALID_DATA_LENGTH_INFORMATION
*
info
=
ptr
;
if
((
io
->
u
.
Status
=
unix_funcs
->
server_get_unix_fd
(
handle
,
FILE_WRITE_DATA
,
&
fd
,
&
needs_close
,
NULL
,
NULL
)))
return
io
->
u
.
Status
;
if
(
fstat
(
fd
,
&
st
)
==
-
1
)
io
->
u
.
Status
=
FILE_GetNtStatus
();
else
if
(
info
->
ValidDataLength
.
QuadPart
<=
0
||
(
off_t
)
info
->
ValidDataLength
.
QuadPart
>
st
.
st_size
)
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER
;
else
{
#ifdef HAVE_FALLOCATE
if
(
fallocate
(
fd
,
0
,
0
,
(
off_t
)
info
->
ValidDataLength
.
QuadPart
)
==
-
1
)
{
NTSTATUS
status
=
FILE_GetNtStatus
();
if
(
status
==
STATUS_NOT_SUPPORTED
)
WARN
(
"fallocate not supported on this filesystem
\n
"
);
else
io
->
u
.
Status
=
status
;
}
#else
FIXME
(
"setting valid data length not supported
\n
"
);
#endif
}
if
(
needs_close
)
close
(
fd
);
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
case
FileDispositionInformation
:
if
(
len
>=
sizeof
(
FILE_DISPOSITION_INFORMATION
))
{
FILE_DISPOSITION_INFORMATION
*
info
=
ptr
;
SERVER_START_REQ
(
set_fd_disp_info
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
unlink
=
info
->
DoDeleteFile
;
io
->
u
.
Status
=
wine_server_call
(
req
);
}
SERVER_END_REQ
;
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
case
FileRenameInformation
:
if
(
len
>=
sizeof
(
FILE_RENAME_INFORMATION
))
{
FILE_RENAME_INFORMATION
*
info
=
ptr
;
UNICODE_STRING
name_str
;
OBJECT_ATTRIBUTES
attr
;
ANSI_STRING
unix_name
;
name_str
.
Buffer
=
info
->
FileName
;
name_str
.
Length
=
info
->
FileNameLength
;
name_str
.
MaximumLength
=
info
->
FileNameLength
+
sizeof
(
WCHAR
);
attr
.
Length
=
sizeof
(
attr
);
attr
.
ObjectName
=
&
name_str
;
attr
.
RootDirectory
=
info
->
RootDirectory
;
attr
.
Attributes
=
OBJ_CASE_INSENSITIVE
;
io
->
u
.
Status
=
unix_funcs
->
nt_to_unix_file_name_attr
(
&
attr
,
&
unix_name
,
FILE_OPEN_IF
);
if
(
io
->
u
.
Status
!=
STATUS_SUCCESS
&&
io
->
u
.
Status
!=
STATUS_NO_SUCH_FILE
)
break
;
SERVER_START_REQ
(
set_fd_name_info
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
rootdir
=
wine_server_obj_handle
(
attr
.
RootDirectory
);
req
->
link
=
FALSE
;
req
->
replace
=
info
->
ReplaceIfExists
;
wine_server_add_data
(
req
,
unix_name
.
Buffer
,
unix_name
.
Length
);
io
->
u
.
Status
=
wine_server_call
(
req
);
}
SERVER_END_REQ
;
RtlFreeAnsiString
(
&
unix_name
);
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
case
FileLinkInformation
:
if
(
len
>=
sizeof
(
FILE_LINK_INFORMATION
))
{
FILE_LINK_INFORMATION
*
info
=
ptr
;
UNICODE_STRING
name_str
;
OBJECT_ATTRIBUTES
attr
;
ANSI_STRING
unix_name
;
name_str
.
Buffer
=
info
->
FileName
;
name_str
.
Length
=
info
->
FileNameLength
;
name_str
.
MaximumLength
=
info
->
FileNameLength
+
sizeof
(
WCHAR
);
attr
.
Length
=
sizeof
(
attr
);
attr
.
ObjectName
=
&
name_str
;
attr
.
RootDirectory
=
info
->
RootDirectory
;
attr
.
Attributes
=
OBJ_CASE_INSENSITIVE
;
io
->
u
.
Status
=
unix_funcs
->
nt_to_unix_file_name_attr
(
&
attr
,
&
unix_name
,
FILE_OPEN_IF
);
if
(
io
->
u
.
Status
!=
STATUS_SUCCESS
&&
io
->
u
.
Status
!=
STATUS_NO_SUCH_FILE
)
break
;
SERVER_START_REQ
(
set_fd_name_info
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
rootdir
=
wine_server_obj_handle
(
attr
.
RootDirectory
);
req
->
link
=
TRUE
;
req
->
replace
=
info
->
ReplaceIfExists
;
wine_server_add_data
(
req
,
unix_name
.
Buffer
,
unix_name
.
Length
);
io
->
u
.
Status
=
wine_server_call
(
req
);
}
SERVER_END_REQ
;
RtlFreeAnsiString
(
&
unix_name
);
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
default:
FIXME
(
"Unsupported class (%d)
\n
"
,
class
);
io
->
u
.
Status
=
STATUS_NOT_IMPLEMENTED
;
break
;
}
io
->
Information
=
0
;
return
io
->
u
.
Status
;
return
unix_funcs
->
NtSetInformationFile
(
handle
,
io
,
ptr
,
len
,
class
);
}
...
...
dlls/ntdll/loader.c
View file @
c3e2013b
...
...
@@ -4384,10 +4384,6 @@ void __wine_process_init(void)
init_user_process_params
(
info_size
);
params
=
peb
->
ProcessParameters
;
/* retrieve current umask */
FILE_umask
=
umask
(
0777
);
umask
(
FILE_umask
);
load_global_options
();
version_init
();
...
...
dlls/ntdll/ntdll_misc.h
View file @
c3e2013b
...
...
@@ -203,7 +203,6 @@ static inline int get_unix_exit_code( NTSTATUS status )
return
status
;
}
extern
mode_t
FILE_umask
DECLSPEC_HIDDEN
;
extern
SYSTEM_CPU_INFORMATION
cpu_info
DECLSPEC_HIDDEN
;
#define HASH_STRING_ALGORITHM_DEFAULT 0
...
...
dlls/ntdll/unix/file.c
View file @
c3e2013b
...
...
@@ -46,6 +46,12 @@
#ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifdef HAVE_SYS_ATTR_H
#include <sys/attr.h>
#endif
...
...
@@ -103,8 +109,12 @@
#define NONAMELESSUNION
#include "windef.h"
#include "winnt.h"
#include "winioctl.h"
#include "winternl.h"
#include "ddk/ntddk.h"
#include "ddk/wdm.h"
#define WINE_MOUNTMGR_EXTENSIONS
#include "ddk/mountmgr.h"
#include "wine/server.h"
#include "wine/list.h"
#include "wine/debug.h"
...
...
@@ -213,6 +223,7 @@ static struct dir_data **dir_data_cache;
static
unsigned
int
dir_data_cache_size
;
static
BOOL
show_dot_files
;
static
mode_t
start_umask
;
/* at some point we may want to allow Winelib apps to set this */
static
const
BOOL
is_case_sensitive
=
FALSE
;
...
...
@@ -1446,6 +1457,30 @@ static inline ULONG get_file_attributes( const struct stat *st )
}
static
BOOL
fd_is_mount_point
(
int
fd
,
const
struct
stat
*
st
)
{
struct
stat
parent
;
return
S_ISDIR
(
st
->
st_mode
)
&&
!
fstatat
(
fd
,
".."
,
&
parent
,
0
)
&&
(
parent
.
st_dev
!=
st
->
st_dev
||
parent
.
st_ino
==
st
->
st_ino
);
}
/* get the stat info and file attributes for a file (by file descriptor) */
static
int
fd_get_file_info
(
int
fd
,
unsigned
int
options
,
struct
stat
*
st
,
ULONG
*
attr
)
{
int
ret
;
*
attr
=
0
;
ret
=
fstat
(
fd
,
st
);
if
(
ret
==
-
1
)
return
ret
;
*
attr
|=
get_file_attributes
(
st
);
/* consider mount points to be reparse points (IO_REPARSE_TAG_MOUNT_POINT) */
if
((
options
&
FILE_OPEN_REPARSE_POINT
)
&&
fd_is_mount_point
(
fd
,
st
))
*
attr
|=
FILE_ATTRIBUTE_REPARSE_POINT
;
return
ret
;
}
/* get the stat info and file attributes for a file (by name) */
static
int
get_file_info
(
const
char
*
path
,
struct
stat
*
st
,
ULONG
*
attr
)
{
...
...
@@ -1480,6 +1515,105 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr )
}
#if defined(__ANDROID__) && !defined(HAVE_FUTIMENS)
static
int
futimens
(
int
fd
,
const
struct
timespec
spec
[
2
]
)
{
return
syscall
(
__NR_utimensat
,
fd
,
NULL
,
spec
,
0
);
}
#define HAVE_FUTIMENS
#endif
/* __ANDROID__ */
#ifndef UTIME_OMIT
#define UTIME_OMIT ((1 << 30) - 2)
#endif
static
BOOL
set_file_times_precise
(
int
fd
,
const
LARGE_INTEGER
*
mtime
,
const
LARGE_INTEGER
*
atime
,
NTSTATUS
*
status
)
{
#ifdef HAVE_FUTIMENS
struct
timespec
tv
[
2
];
tv
[
0
].
tv_sec
=
tv
[
1
].
tv_sec
=
0
;
tv
[
0
].
tv_nsec
=
tv
[
1
].
tv_nsec
=
UTIME_OMIT
;
if
(
atime
->
QuadPart
)
{
tv
[
0
].
tv_sec
=
atime
->
QuadPart
/
10000000
-
SECS_1601_TO_1970
;
tv
[
0
].
tv_nsec
=
(
atime
->
QuadPart
%
10000000
)
*
100
;
}
if
(
mtime
->
QuadPart
)
{
tv
[
1
].
tv_sec
=
mtime
->
QuadPart
/
10000000
-
SECS_1601_TO_1970
;
tv
[
1
].
tv_nsec
=
(
mtime
->
QuadPart
%
10000000
)
*
100
;
}
#ifdef __APPLE__
if
(
!&
futimens
)
return
FALSE
;
#endif
if
(
futimens
(
fd
,
tv
)
==
-
1
)
*
status
=
errno_to_status
(
errno
);
else
*
status
=
STATUS_SUCCESS
;
return
TRUE
;
#else
return
FALSE
;
#endif
}
static
NTSTATUS
set_file_times
(
int
fd
,
const
LARGE_INTEGER
*
mtime
,
const
LARGE_INTEGER
*
atime
)
{
NTSTATUS
status
=
STATUS_SUCCESS
;
#if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT)
struct
timeval
tv
[
2
];
struct
stat
st
;
#endif
if
(
set_file_times_precise
(
fd
,
mtime
,
atime
,
&
status
))
return
status
;
#if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT)
if
(
!
atime
->
QuadPart
||
!
mtime
->
QuadPart
)
{
tv
[
0
].
tv_sec
=
tv
[
0
].
tv_usec
=
0
;
tv
[
1
].
tv_sec
=
tv
[
1
].
tv_usec
=
0
;
if
(
!
fstat
(
fd
,
&
st
))
{
tv
[
0
].
tv_sec
=
st
.
st_atime
;
tv
[
1
].
tv_sec
=
st
.
st_mtime
;
#ifdef HAVE_STRUCT_STAT_ST_ATIM
tv
[
0
].
tv_usec
=
st
.
st_atim
.
tv_nsec
/
1000
;
#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
tv
[
0
].
tv_usec
=
st
.
st_atimespec
.
tv_nsec
/
1000
;
#endif
#ifdef HAVE_STRUCT_STAT_ST_MTIM
tv
[
1
].
tv_usec
=
st
.
st_mtim
.
tv_nsec
/
1000
;
#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
tv
[
1
].
tv_usec
=
st
.
st_mtimespec
.
tv_nsec
/
1000
;
#endif
}
}
if
(
atime
->
QuadPart
)
{
tv
[
0
].
tv_sec
=
atime
->
QuadPart
/
10000000
-
SECS_1601_TO_1970
;
tv
[
0
].
tv_usec
=
(
atime
->
QuadPart
%
10000000
)
/
10
;
}
if
(
mtime
->
QuadPart
)
{
tv
[
1
].
tv_sec
=
mtime
->
QuadPart
/
10000000
-
SECS_1601_TO_1970
;
tv
[
1
].
tv_usec
=
(
mtime
->
QuadPart
%
10000000
)
/
10
;
}
#ifdef HAVE_FUTIMES
if
(
futimes
(
fd
,
tv
)
==
-
1
)
status
=
errno_to_status
(
errno
);
#elif defined(HAVE_FUTIMESAT)
if
(
futimesat
(
fd
,
NULL
,
tv
)
==
-
1
)
status
=
FILE_GetNtStatus
();
#endif
#else
/* HAVE_FUTIMES || HAVE_FUTIMESAT */
FIXME
(
"setting file times not supported
\n
"
);
status
=
STATUS_NOT_IMPLEMENTED
;
#endif
return
status
;
}
static
inline
void
get_file_times
(
const
struct
stat
*
st
,
LARGE_INTEGER
*
mtime
,
LARGE_INTEGER
*
ctime
,
LARGE_INTEGER
*
atime
,
LARGE_INTEGER
*
creation
)
{
...
...
@@ -1623,6 +1757,258 @@ static NTSTATUS fill_file_info( const struct stat *st, ULONG attr, void *ptr,
}
static
NTSTATUS
server_get_unix_name
(
HANDLE
handle
,
ANSI_STRING
*
unix_name
)
{
data_size_t
size
=
1024
;
NTSTATUS
ret
;
char
*
name
;
for
(;;)
{
name
=
RtlAllocateHeap
(
GetProcessHeap
(),
0
,
size
+
1
);
if
(
!
name
)
return
STATUS_NO_MEMORY
;
unix_name
->
MaximumLength
=
size
+
1
;
SERVER_START_REQ
(
get_handle_unix_name
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
wine_server_set_reply
(
req
,
name
,
size
);
ret
=
wine_server_call
(
req
);
size
=
reply
->
name_len
;
}
SERVER_END_REQ
;
if
(
!
ret
)
{
name
[
size
]
=
0
;
unix_name
->
Buffer
=
name
;
unix_name
->
Length
=
size
;
break
;
}
RtlFreeHeap
(
GetProcessHeap
(),
0
,
name
);
if
(
ret
!=
STATUS_BUFFER_OVERFLOW
)
break
;
}
return
ret
;
}
static
NTSTATUS
fill_name_info
(
const
ANSI_STRING
*
unix_name
,
FILE_NAME_INFORMATION
*
info
,
LONG
*
name_len
)
{
UNICODE_STRING
nt_name
;
NTSTATUS
status
;
if
(
!
(
status
=
wine_unix_to_nt_file_name
(
unix_name
,
&
nt_name
)))
{
const
WCHAR
*
ptr
=
nt_name
.
Buffer
;
const
WCHAR
*
end
=
ptr
+
(
nt_name
.
Length
/
sizeof
(
WCHAR
));
/* Skip the volume mount point. */
while
(
ptr
!=
end
&&
*
ptr
==
'\\'
)
++
ptr
;
while
(
ptr
!=
end
&&
*
ptr
!=
'\\'
)
++
ptr
;
while
(
ptr
!=
end
&&
*
ptr
==
'\\'
)
++
ptr
;
while
(
ptr
!=
end
&&
*
ptr
!=
'\\'
)
++
ptr
;
info
->
FileNameLength
=
(
end
-
ptr
)
*
sizeof
(
WCHAR
);
if
(
*
name_len
<
info
->
FileNameLength
)
status
=
STATUS_BUFFER_OVERFLOW
;
else
*
name_len
=
info
->
FileNameLength
;
memcpy
(
info
->
FileName
,
ptr
,
*
name_len
);
RtlFreeUnicodeString
(
&
nt_name
);
}
return
status
;
}
static
NTSTATUS
server_get_file_info
(
HANDLE
handle
,
IO_STATUS_BLOCK
*
io
,
void
*
buffer
,
ULONG
length
,
FILE_INFORMATION_CLASS
info_class
)
{
SERVER_START_REQ
(
get_file_info
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
info_class
=
info_class
;
wine_server_set_reply
(
req
,
buffer
,
length
);
io
->
u
.
Status
=
wine_server_call
(
req
);
io
->
Information
=
wine_server_reply_size
(
reply
);
}
SERVER_END_REQ
;
if
(
io
->
u
.
Status
==
STATUS_NOT_IMPLEMENTED
)
FIXME
(
"Unsupported info class %x
\n
"
,
info_class
);
return
io
->
u
.
Status
;
}
/* retrieve device/inode number for all the drives */
static
unsigned
int
get_drives_info
(
struct
file_identity
info
[
MAX_DOS_DRIVES
]
)
{
static
struct
file_identity
cache
[
MAX_DOS_DRIVES
];
static
time_t
last_update
;
static
unsigned
int
nb_drives
;
unsigned
int
ret
;
time_t
now
=
time
(
NULL
);
RtlEnterCriticalSection
(
&
dir_section
);
if
(
now
!=
last_update
)
{
char
*
buffer
,
*
p
;
struct
stat
st
;
unsigned
int
i
;
if
((
buffer
=
RtlAllocateHeap
(
GetProcessHeap
(),
0
,
strlen
(
config_dir
)
+
sizeof
(
"/dosdevices/a:"
)
)))
{
strcpy
(
buffer
,
config_dir
);
strcat
(
buffer
,
"/dosdevices/a:"
);
p
=
buffer
+
strlen
(
buffer
)
-
2
;
for
(
i
=
nb_drives
=
0
;
i
<
MAX_DOS_DRIVES
;
i
++
)
{
*
p
=
'a'
+
i
;
if
(
!
stat
(
buffer
,
&
st
))
{
cache
[
i
].
dev
=
st
.
st_dev
;
cache
[
i
].
ino
=
st
.
st_ino
;
nb_drives
++
;
}
else
{
cache
[
i
].
dev
=
0
;
cache
[
i
].
ino
=
0
;
}
}
RtlFreeHeap
(
GetProcessHeap
(),
0
,
buffer
);
}
last_update
=
now
;
}
memcpy
(
info
,
cache
,
sizeof
(
cache
)
);
ret
=
nb_drives
;
RtlLeaveCriticalSection
(
&
dir_section
);
return
ret
;
}
/* Find a DOS device which can act as the root of "path".
* Similar to find_drive_root(), but returns -1 instead of crossing volumes. */
static
int
find_dos_device
(
const
char
*
path
)
{
int
len
=
strlen
(
path
);
int
drive
;
char
*
buffer
;
struct
stat
st
;
struct
file_identity
info
[
MAX_DOS_DRIVES
];
dev_t
dev_id
;
if
(
!
get_drives_info
(
info
))
return
-
1
;
if
(
stat
(
path
,
&
st
)
<
0
)
return
-
1
;
dev_id
=
st
.
st_dev
;
/* 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
-
1
;
memcpy
(
buffer
,
path
,
len
);
buffer
[
len
]
=
0
;
for
(;;)
{
if
(
!
stat
(
buffer
,
&
st
)
&&
S_ISDIR
(
st
.
st_mode
))
{
if
(
st
.
st_dev
!=
dev_id
)
break
;
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
));
RtlFreeHeap
(
GetProcessHeap
(),
0
,
buffer
);
return
drive
;
}
}
}
if
(
len
<=
1
)
break
;
/* reached root */
while
(
path
[
len
-
1
]
!=
'/'
)
len
--
;
while
(
path
[
len
-
1
]
==
'/'
)
len
--
;
buffer
[
len
]
=
0
;
}
RtlFreeHeap
(
GetProcessHeap
(),
0
,
buffer
);
return
-
1
;
}
static
struct
mountmgr_unix_drive
*
get_mountmgr_fs_info
(
HANDLE
handle
,
int
fd
)
{
struct
mountmgr_unix_drive
*
drive
;
OBJECT_ATTRIBUTES
attr
;
UNICODE_STRING
string
;
ANSI_STRING
unix_name
;
IO_STATUS_BLOCK
io
;
HANDLE
mountmgr
;
NTSTATUS
status
;
int
letter
;
if
(
server_get_unix_name
(
handle
,
&
unix_name
))
return
NULL
;
letter
=
find_dos_device
(
unix_name
.
Buffer
);
RtlFreeAnsiString
(
&
unix_name
);
if
(
!
(
drive
=
RtlAllocateHeap
(
GetProcessHeap
(),
0
,
1024
)))
return
NULL
;
if
(
letter
==
-
1
)
{
struct
stat
st
;
if
(
fstat
(
fd
,
&
st
)
==
-
1
)
{
RtlFreeHeap
(
GetProcessHeap
(),
0
,
drive
);
return
NULL
;
}
drive
->
unix_dev
=
st
.
st_dev
;
drive
->
letter
=
0
;
}
else
drive
->
letter
=
'a'
+
letter
;
RtlInitUnicodeString
(
&
string
,
MOUNTMGR_DEVICE_NAME
);
InitializeObjectAttributes
(
&
attr
,
&
string
,
0
,
NULL
,
NULL
);
if
(
NtOpenFile
(
&
mountmgr
,
GENERIC_READ
|
SYNCHRONIZE
,
&
attr
,
&
io
,
FILE_SHARE_READ
|
FILE_SHARE_WRITE
,
FILE_SYNCHRONOUS_IO_NONALERT
))
{
RtlFreeHeap
(
GetProcessHeap
(),
0
,
drive
);
return
NULL
;
}
status
=
NtDeviceIoControlFile
(
mountmgr
,
NULL
,
NULL
,
NULL
,
&
io
,
IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
,
drive
,
sizeof
(
*
drive
),
drive
,
1024
);
if
(
status
==
STATUS_BUFFER_OVERFLOW
)
{
if
(
!
(
drive
=
RtlReAllocateHeap
(
GetProcessHeap
(),
0
,
drive
,
drive
->
size
)))
{
RtlFreeHeap
(
GetProcessHeap
(),
0
,
drive
);
NtClose
(
mountmgr
);
return
NULL
;
}
status
=
NtDeviceIoControlFile
(
mountmgr
,
NULL
,
NULL
,
NULL
,
&
io
,
IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
,
drive
,
sizeof
(
*
drive
),
drive
,
drive
->
size
);
}
NtClose
(
mountmgr
);
if
(
status
)
{
WARN
(
"failed to retrieve filesystem type from mountmgr, status %#x
\n
"
,
status
);
RtlFreeHeap
(
GetProcessHeap
(),
0
,
drive
);
return
NULL
;
}
return
drive
;
}
/***********************************************************************
* get_dir_data_entry
*
...
...
@@ -2399,6 +2785,9 @@ void init_files(void)
#ifdef linux
ignore_file
(
"/sys"
);
#endif
/* retrieve initial umask */
start_umask
=
umask
(
0777
);
umask
(
start_umask
);
}
...
...
@@ -2558,7 +2947,7 @@ static NTSTATUS find_file_id( ANSI_STRING *unix_name, ULONGLONG file_id, dev_t d
*
* Lookup a file from its file id instead of its name.
*/
NTSTATUS
CDECL
file_id_to_unix_file_name
(
const
OBJECT_ATTRIBUTES
*
attr
,
ANSI_STRING
*
unix_name
)
static
NTSTATUS
file_id_to_unix_file_name
(
const
OBJECT_ATTRIBUTES
*
attr
,
ANSI_STRING
*
unix_name
)
{
enum
server_fd_type
type
;
int
old_cwd
,
root_fd
,
needs_close
;
...
...
@@ -2748,8 +3137,8 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
/******************************************************************************
* nt_to_unix_file_name_attr
*/
NTSTATUS
CDECL
nt_to_unix_file_name_attr
(
const
OBJECT_ATTRIBUTES
*
attr
,
ANSI_STRING
*
unix_name_ret
,
UINT
disposition
)
static
NTSTATUS
nt_to_unix_file_name_attr
(
const
OBJECT_ATTRIBUTES
*
attr
,
ANSI_STRING
*
unix_name_ret
,
UINT
disposition
)
{
static
const
WCHAR
invalid_charsW
[]
=
{
INVALID_NT_CHARS
,
0
};
enum
server_fd_type
type
;
...
...
@@ -3282,3 +3671,614 @@ NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC
else
WARN
(
"%s not found (%x)
\n
"
,
debugstr_us
(
attr
->
ObjectName
),
status
);
return
status
;
}
/******************************************************************************
* NtQueryInformationFile (NTDLL.@)
*/
NTSTATUS
WINAPI
NtQueryInformationFile
(
HANDLE
handle
,
IO_STATUS_BLOCK
*
io
,
void
*
ptr
,
LONG
len
,
FILE_INFORMATION_CLASS
class
)
{
static
const
size_t
info_sizes
[]
=
{
0
,
sizeof
(
FILE_DIRECTORY_INFORMATION
),
/* FileDirectoryInformation */
sizeof
(
FILE_FULL_DIRECTORY_INFORMATION
),
/* FileFullDirectoryInformation */
sizeof
(
FILE_BOTH_DIRECTORY_INFORMATION
),
/* FileBothDirectoryInformation */
sizeof
(
FILE_BASIC_INFORMATION
),
/* FileBasicInformation */
sizeof
(
FILE_STANDARD_INFORMATION
),
/* FileStandardInformation */
sizeof
(
FILE_INTERNAL_INFORMATION
),
/* FileInternalInformation */
sizeof
(
FILE_EA_INFORMATION
),
/* FileEaInformation */
0
,
/* FileAccessInformation */
sizeof
(
FILE_NAME_INFORMATION
),
/* FileNameInformation */
sizeof
(
FILE_RENAME_INFORMATION
)
-
sizeof
(
WCHAR
),
/* FileRenameInformation */
0
,
/* FileLinkInformation */
sizeof
(
FILE_NAMES_INFORMATION
)
-
sizeof
(
WCHAR
),
/* FileNamesInformation */
sizeof
(
FILE_DISPOSITION_INFORMATION
),
/* FileDispositionInformation */
sizeof
(
FILE_POSITION_INFORMATION
),
/* FilePositionInformation */
sizeof
(
FILE_FULL_EA_INFORMATION
),
/* FileFullEaInformation */
0
,
/* FileModeInformation */
sizeof
(
FILE_ALIGNMENT_INFORMATION
),
/* FileAlignmentInformation */
sizeof
(
FILE_ALL_INFORMATION
),
/* FileAllInformation */
sizeof
(
FILE_ALLOCATION_INFORMATION
),
/* FileAllocationInformation */
sizeof
(
FILE_END_OF_FILE_INFORMATION
),
/* FileEndOfFileInformation */
0
,
/* FileAlternateNameInformation */
sizeof
(
FILE_STREAM_INFORMATION
)
-
sizeof
(
WCHAR
),
/* FileStreamInformation */
sizeof
(
FILE_PIPE_INFORMATION
),
/* FilePipeInformation */
sizeof
(
FILE_PIPE_LOCAL_INFORMATION
),
/* FilePipeLocalInformation */
0
,
/* FilePipeRemoteInformation */
sizeof
(
FILE_MAILSLOT_QUERY_INFORMATION
),
/* FileMailslotQueryInformation */
0
,
/* FileMailslotSetInformation */
0
,
/* FileCompressionInformation */
0
,
/* FileObjectIdInformation */
0
,
/* FileCompletionInformation */
0
,
/* FileMoveClusterInformation */
0
,
/* FileQuotaInformation */
0
,
/* FileReparsePointInformation */
sizeof
(
FILE_NETWORK_OPEN_INFORMATION
),
/* FileNetworkOpenInformation */
sizeof
(
FILE_ATTRIBUTE_TAG_INFORMATION
),
/* FileAttributeTagInformation */
0
,
/* FileTrackingInformation */
0
,
/* FileIdBothDirectoryInformation */
0
,
/* FileIdFullDirectoryInformation */
0
,
/* FileValidDataLengthInformation */
0
,
/* FileShortNameInformation */
0
,
/* FileIoCompletionNotificationInformation, */
0
,
/* FileIoStatusBlockRangeInformation */
0
,
/* FileIoPriorityHintInformation */
0
,
/* FileSfioReserveInformation */
0
,
/* FileSfioVolumeInformation */
0
,
/* FileHardLinkInformation */
0
,
/* FileProcessIdsUsingFileInformation */
0
,
/* FileNormalizedNameInformation */
0
,
/* FileNetworkPhysicalNameInformation */
0
,
/* FileIdGlobalTxDirectoryInformation */
0
,
/* FileIsRemoteDeviceInformation */
0
,
/* FileAttributeCacheInformation */
0
,
/* FileNumaNodeInformation */
0
,
/* FileStandardLinkInformation */
0
,
/* FileRemoteProtocolInformation */
0
,
/* FileRenameInformationBypassAccessCheck */
0
,
/* FileLinkInformationBypassAccessCheck */
0
,
/* FileVolumeNameInformation */
sizeof
(
FILE_ID_INFORMATION
),
/* FileIdInformation */
0
,
/* FileIdExtdDirectoryInformation */
0
,
/* FileReplaceCompletionInformation */
0
,
/* FileHardLinkFullIdInformation */
0
,
/* FileIdExtdBothDirectoryInformation */
};
struct
stat
st
;
int
fd
,
needs_close
=
FALSE
;
ULONG
attr
;
unsigned
int
options
;
TRACE
(
"(%p,%p,%p,0x%08x,0x%08x)
\n
"
,
handle
,
io
,
ptr
,
len
,
class
);
io
->
Information
=
0
;
if
(
class
<=
0
||
class
>=
FileMaximumInformation
)
return
io
->
u
.
Status
=
STATUS_INVALID_INFO_CLASS
;
if
(
!
info_sizes
[
class
])
return
server_get_file_info
(
handle
,
io
,
ptr
,
len
,
class
);
if
(
len
<
info_sizes
[
class
])
return
io
->
u
.
Status
=
STATUS_INFO_LENGTH_MISMATCH
;
if
((
io
->
u
.
Status
=
server_get_unix_fd
(
handle
,
0
,
&
fd
,
&
needs_close
,
NULL
,
&
options
)))
{
if
(
io
->
u
.
Status
!=
STATUS_BAD_DEVICE_TYPE
)
return
io
->
u
.
Status
;
return
server_get_file_info
(
handle
,
io
,
ptr
,
len
,
class
);
}
switch
(
class
)
{
case
FileBasicInformation
:
if
(
fd_get_file_info
(
fd
,
options
,
&
st
,
&
attr
)
==
-
1
)
io
->
u
.
Status
=
errno_to_status
(
errno
);
else
if
(
!
S_ISREG
(
st
.
st_mode
)
&&
!
S_ISDIR
(
st
.
st_mode
))
io
->
u
.
Status
=
STATUS_INVALID_INFO_CLASS
;
else
fill_file_info
(
&
st
,
attr
,
ptr
,
class
);
break
;
case
FileStandardInformation
:
{
FILE_STANDARD_INFORMATION
*
info
=
ptr
;
if
(
fd_get_file_info
(
fd
,
options
,
&
st
,
&
attr
)
==
-
1
)
io
->
u
.
Status
=
errno_to_status
(
errno
);
else
{
fill_file_info
(
&
st
,
attr
,
info
,
class
);
info
->
DeletePending
=
FALSE
;
/* FIXME */
}
}
break
;
case
FilePositionInformation
:
{
FILE_POSITION_INFORMATION
*
info
=
ptr
;
off_t
res
=
lseek
(
fd
,
0
,
SEEK_CUR
);
if
(
res
==
(
off_t
)
-
1
)
io
->
u
.
Status
=
errno_to_status
(
errno
);
else
info
->
CurrentByteOffset
.
QuadPart
=
res
;
}
break
;
case
FileInternalInformation
:
if
(
fd_get_file_info
(
fd
,
options
,
&
st
,
&
attr
)
==
-
1
)
io
->
u
.
Status
=
errno_to_status
(
errno
);
else
fill_file_info
(
&
st
,
attr
,
ptr
,
class
);
break
;
case
FileEaInformation
:
{
FILE_EA_INFORMATION
*
info
=
ptr
;
info
->
EaSize
=
0
;
}
break
;
case
FileEndOfFileInformation
:
if
(
fd_get_file_info
(
fd
,
options
,
&
st
,
&
attr
)
==
-
1
)
io
->
u
.
Status
=
errno_to_status
(
errno
);
else
fill_file_info
(
&
st
,
attr
,
ptr
,
class
);
break
;
case
FileAllInformation
:
{
FILE_ALL_INFORMATION
*
info
=
ptr
;
ANSI_STRING
unix_name
;
if
(
fd_get_file_info
(
fd
,
options
,
&
st
,
&
attr
)
==
-
1
)
io
->
u
.
Status
=
errno_to_status
(
errno
);
else
if
(
!
S_ISREG
(
st
.
st_mode
)
&&
!
S_ISDIR
(
st
.
st_mode
))
io
->
u
.
Status
=
STATUS_INVALID_INFO_CLASS
;
else
if
(
!
(
io
->
u
.
Status
=
server_get_unix_name
(
handle
,
&
unix_name
)))
{
LONG
name_len
=
len
-
FIELD_OFFSET
(
FILE_ALL_INFORMATION
,
NameInformation
.
FileName
);
fill_file_info
(
&
st
,
attr
,
info
,
FileAllInformation
);
info
->
StandardInformation
.
DeletePending
=
FALSE
;
/* FIXME */
info
->
EaInformation
.
EaSize
=
0
;
info
->
AccessInformation
.
AccessFlags
=
0
;
/* FIXME */
info
->
PositionInformation
.
CurrentByteOffset
.
QuadPart
=
lseek
(
fd
,
0
,
SEEK_CUR
);
info
->
ModeInformation
.
Mode
=
0
;
/* FIXME */
info
->
AlignmentInformation
.
AlignmentRequirement
=
1
;
/* FIXME */
io
->
u
.
Status
=
fill_name_info
(
&
unix_name
,
&
info
->
NameInformation
,
&
name_len
);
RtlFreeAnsiString
(
&
unix_name
);
io
->
Information
=
FIELD_OFFSET
(
FILE_ALL_INFORMATION
,
NameInformation
.
FileName
)
+
name_len
;
}
}
break
;
case
FileMailslotQueryInformation
:
{
FILE_MAILSLOT_QUERY_INFORMATION
*
info
=
ptr
;
SERVER_START_REQ
(
set_mailslot_info
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
flags
=
0
;
io
->
u
.
Status
=
wine_server_call
(
req
);
if
(
io
->
u
.
Status
==
STATUS_SUCCESS
)
{
info
->
MaximumMessageSize
=
reply
->
max_msgsize
;
info
->
MailslotQuota
=
0
;
info
->
NextMessageSize
=
0
;
info
->
MessagesAvailable
=
0
;
info
->
ReadTimeout
.
QuadPart
=
reply
->
read_timeout
;
}
}
SERVER_END_REQ
;
if
(
!
io
->
u
.
Status
)
{
char
*
tmpbuf
;
ULONG
size
=
info
->
MaximumMessageSize
?
info
->
MaximumMessageSize
:
0x10000
;
if
(
size
>
0x10000
)
size
=
0x10000
;
if
((
tmpbuf
=
RtlAllocateHeap
(
GetProcessHeap
(),
0
,
size
)))
{
if
(
!
server_get_unix_fd
(
handle
,
FILE_READ_DATA
,
&
fd
,
&
needs_close
,
NULL
,
NULL
))
{
int
res
=
recv
(
fd
,
tmpbuf
,
size
,
MSG_PEEK
);
info
->
MessagesAvailable
=
(
res
>
0
);
info
->
NextMessageSize
=
(
res
>=
0
)
?
res
:
MAILSLOT_NO_MESSAGE
;
if
(
needs_close
)
close
(
fd
);
}
RtlFreeHeap
(
GetProcessHeap
(),
0
,
tmpbuf
);
}
}
}
break
;
case
FileNameInformation
:
{
FILE_NAME_INFORMATION
*
info
=
ptr
;
ANSI_STRING
unix_name
;
if
(
!
(
io
->
u
.
Status
=
server_get_unix_name
(
handle
,
&
unix_name
)))
{
LONG
name_len
=
len
-
FIELD_OFFSET
(
FILE_NAME_INFORMATION
,
FileName
);
io
->
u
.
Status
=
fill_name_info
(
&
unix_name
,
info
,
&
name_len
);
RtlFreeAnsiString
(
&
unix_name
);
io
->
Information
=
FIELD_OFFSET
(
FILE_NAME_INFORMATION
,
FileName
)
+
name_len
;
}
}
break
;
case
FileNetworkOpenInformation
:
{
FILE_NETWORK_OPEN_INFORMATION
*
info
=
ptr
;
ANSI_STRING
unix_name
;
if
(
!
(
io
->
u
.
Status
=
server_get_unix_name
(
handle
,
&
unix_name
)))
{
ULONG
attributes
;
struct
stat
st
;
if
(
get_file_info
(
unix_name
.
Buffer
,
&
st
,
&
attributes
)
==
-
1
)
io
->
u
.
Status
=
errno_to_status
(
errno
);
else
if
(
!
S_ISREG
(
st
.
st_mode
)
&&
!
S_ISDIR
(
st
.
st_mode
))
io
->
u
.
Status
=
STATUS_INVALID_INFO_CLASS
;
else
{
FILE_BASIC_INFORMATION
basic
;
FILE_STANDARD_INFORMATION
std
;
fill_file_info
(
&
st
,
attributes
,
&
basic
,
FileBasicInformation
);
fill_file_info
(
&
st
,
attributes
,
&
std
,
FileStandardInformation
);
info
->
CreationTime
=
basic
.
CreationTime
;
info
->
LastAccessTime
=
basic
.
LastAccessTime
;
info
->
LastWriteTime
=
basic
.
LastWriteTime
;
info
->
ChangeTime
=
basic
.
ChangeTime
;
info
->
AllocationSize
=
std
.
AllocationSize
;
info
->
EndOfFile
=
std
.
EndOfFile
;
info
->
FileAttributes
=
basic
.
FileAttributes
;
}
RtlFreeAnsiString
(
&
unix_name
);
}
}
break
;
case
FileIdInformation
:
if
(
fd_get_file_info
(
fd
,
options
,
&
st
,
&
attr
)
==
-
1
)
io
->
u
.
Status
=
errno_to_status
(
errno
);
else
{
struct
mountmgr_unix_drive
*
drive
;
FILE_ID_INFORMATION
*
info
=
ptr
;
info
->
VolumeSerialNumber
=
0
;
if
((
drive
=
get_mountmgr_fs_info
(
handle
,
fd
)))
{
info
->
VolumeSerialNumber
=
drive
->
serial
;
RtlFreeHeap
(
GetProcessHeap
(),
0
,
drive
);
}
memset
(
&
info
->
FileId
,
0
,
sizeof
(
info
->
FileId
)
);
*
(
ULONGLONG
*
)
&
info
->
FileId
=
st
.
st_ino
;
}
break
;
case
FileAttributeTagInformation
:
if
(
fd_get_file_info
(
fd
,
options
,
&
st
,
&
attr
)
==
-
1
)
io
->
u
.
Status
=
errno_to_status
(
errno
);
else
{
FILE_ATTRIBUTE_TAG_INFORMATION
*
info
=
ptr
;
info
->
FileAttributes
=
attr
;
info
->
ReparseTag
=
0
;
/* FIXME */
if
((
options
&
FILE_OPEN_REPARSE_POINT
)
&&
fd_is_mount_point
(
fd
,
&
st
))
info
->
ReparseTag
=
IO_REPARSE_TAG_MOUNT_POINT
;
}
break
;
default:
FIXME
(
"Unsupported class (%d)
\n
"
,
class
);
io
->
u
.
Status
=
STATUS_NOT_IMPLEMENTED
;
break
;
}
if
(
needs_close
)
close
(
fd
);
if
(
io
->
u
.
Status
==
STATUS_SUCCESS
&&
!
io
->
Information
)
io
->
Information
=
info_sizes
[
class
];
return
io
->
u
.
Status
;
}
/******************************************************************************
* NtSetInformationFile (NTDLL.@)
*/
NTSTATUS
WINAPI
NtSetInformationFile
(
HANDLE
handle
,
IO_STATUS_BLOCK
*
io
,
void
*
ptr
,
ULONG
len
,
FILE_INFORMATION_CLASS
class
)
{
int
fd
,
needs_close
;
TRACE
(
"(%p,%p,%p,0x%08x,0x%08x)
\n
"
,
handle
,
io
,
ptr
,
len
,
class
);
io
->
u
.
Status
=
STATUS_SUCCESS
;
switch
(
class
)
{
case
FileBasicInformation
:
if
(
len
>=
sizeof
(
FILE_BASIC_INFORMATION
))
{
struct
stat
st
;
const
FILE_BASIC_INFORMATION
*
info
=
ptr
;
LARGE_INTEGER
mtime
,
atime
;
if
((
io
->
u
.
Status
=
server_get_unix_fd
(
handle
,
0
,
&
fd
,
&
needs_close
,
NULL
,
NULL
)))
return
io
->
u
.
Status
;
mtime
.
QuadPart
=
info
->
LastWriteTime
.
QuadPart
==
-
1
?
0
:
info
->
LastWriteTime
.
QuadPart
;
atime
.
QuadPart
=
info
->
LastAccessTime
.
QuadPart
==
-
1
?
0
:
info
->
LastAccessTime
.
QuadPart
;
if
(
atime
.
QuadPart
||
mtime
.
QuadPart
)
io
->
u
.
Status
=
set_file_times
(
fd
,
&
mtime
,
&
atime
);
if
(
io
->
u
.
Status
==
STATUS_SUCCESS
&&
info
->
FileAttributes
)
{
if
(
fstat
(
fd
,
&
st
)
==
-
1
)
io
->
u
.
Status
=
errno_to_status
(
errno
);
else
{
if
(
info
->
FileAttributes
&
FILE_ATTRIBUTE_READONLY
)
{
if
(
S_ISDIR
(
st
.
st_mode
))
WARN
(
"FILE_ATTRIBUTE_READONLY ignored for directory.
\n
"
);
else
st
.
st_mode
&=
~
0222
;
/* clear write permission bits */
}
else
{
/* add write permission only where we already have read permission */
st
.
st_mode
|=
(
0600
|
((
st
.
st_mode
&
044
)
>>
1
))
&
(
~
start_umask
);
}
if
(
fchmod
(
fd
,
st
.
st_mode
)
==
-
1
)
io
->
u
.
Status
=
errno_to_status
(
errno
);
}
}
if
(
needs_close
)
close
(
fd
);
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
case
FilePositionInformation
:
if
(
len
>=
sizeof
(
FILE_POSITION_INFORMATION
))
{
const
FILE_POSITION_INFORMATION
*
info
=
ptr
;
if
((
io
->
u
.
Status
=
server_get_unix_fd
(
handle
,
0
,
&
fd
,
&
needs_close
,
NULL
,
NULL
)))
return
io
->
u
.
Status
;
if
(
lseek
(
fd
,
info
->
CurrentByteOffset
.
QuadPart
,
SEEK_SET
)
==
(
off_t
)
-
1
)
io
->
u
.
Status
=
errno_to_status
(
errno
);
if
(
needs_close
)
close
(
fd
);
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
case
FileEndOfFileInformation
:
if
(
len
>=
sizeof
(
FILE_END_OF_FILE_INFORMATION
))
{
struct
stat
st
;
const
FILE_END_OF_FILE_INFORMATION
*
info
=
ptr
;
if
((
io
->
u
.
Status
=
server_get_unix_fd
(
handle
,
0
,
&
fd
,
&
needs_close
,
NULL
,
NULL
)))
return
io
->
u
.
Status
;
/* first try normal truncate */
if
(
ftruncate
(
fd
,
(
off_t
)
info
->
EndOfFile
.
QuadPart
)
!=
-
1
)
break
;
/* now check for the need to extend the file */
if
(
fstat
(
fd
,
&
st
)
!=
-
1
&&
(
off_t
)
info
->
EndOfFile
.
QuadPart
>
st
.
st_size
)
{
static
const
char
zero
;
/* extend the file one byte beyond the requested size and then truncate it */
/* this should work around ftruncate implementations that can't extend files */
if
(
pwrite
(
fd
,
&
zero
,
1
,
(
off_t
)
info
->
EndOfFile
.
QuadPart
)
!=
-
1
&&
ftruncate
(
fd
,
(
off_t
)
info
->
EndOfFile
.
QuadPart
)
!=
-
1
)
break
;
}
io
->
u
.
Status
=
errno_to_status
(
errno
);
if
(
needs_close
)
close
(
fd
);
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
case
FilePipeInformation
:
if
(
len
>=
sizeof
(
FILE_PIPE_INFORMATION
))
{
FILE_PIPE_INFORMATION
*
info
=
ptr
;
if
((
info
->
CompletionMode
|
info
->
ReadMode
)
&
~
1
)
{
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER
;
break
;
}
SERVER_START_REQ
(
set_named_pipe_info
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
flags
=
(
info
->
CompletionMode
?
NAMED_PIPE_NONBLOCKING_MODE
:
0
)
|
(
info
->
ReadMode
?
NAMED_PIPE_MESSAGE_STREAM_READ
:
0
);
io
->
u
.
Status
=
wine_server_call
(
req
);
}
SERVER_END_REQ
;
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
case
FileMailslotSetInformation
:
{
FILE_MAILSLOT_SET_INFORMATION
*
info
=
ptr
;
SERVER_START_REQ
(
set_mailslot_info
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
flags
=
MAILSLOT_SET_READ_TIMEOUT
;
req
->
read_timeout
=
info
->
ReadTimeout
.
QuadPart
;
io
->
u
.
Status
=
wine_server_call
(
req
);
}
SERVER_END_REQ
;
}
break
;
case
FileCompletionInformation
:
if
(
len
>=
sizeof
(
FILE_COMPLETION_INFORMATION
))
{
FILE_COMPLETION_INFORMATION
*
info
=
ptr
;
SERVER_START_REQ
(
set_completion_info
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
chandle
=
wine_server_obj_handle
(
info
->
CompletionPort
);
req
->
ckey
=
info
->
CompletionKey
;
io
->
u
.
Status
=
wine_server_call
(
req
);
}
SERVER_END_REQ
;
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
case
FileIoCompletionNotificationInformation
:
if
(
len
>=
sizeof
(
FILE_IO_COMPLETION_NOTIFICATION_INFORMATION
))
{
FILE_IO_COMPLETION_NOTIFICATION_INFORMATION
*
info
=
ptr
;
if
(
info
->
Flags
&
FILE_SKIP_SET_USER_EVENT_ON_FAST_IO
)
FIXME
(
"FILE_SKIP_SET_USER_EVENT_ON_FAST_IO not supported
\n
"
);
SERVER_START_REQ
(
set_fd_completion_mode
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
flags
=
info
->
Flags
;
io
->
u
.
Status
=
wine_server_call
(
req
);
}
SERVER_END_REQ
;
}
else
io
->
u
.
Status
=
STATUS_INFO_LENGTH_MISMATCH
;
break
;
case
FileIoPriorityHintInformation
:
if
(
len
>=
sizeof
(
FILE_IO_PRIORITY_HINT_INFO
))
{
FILE_IO_PRIORITY_HINT_INFO
*
info
=
ptr
;
if
(
info
->
PriorityHint
<
MaximumIoPriorityHintType
)
TRACE
(
"ignoring FileIoPriorityHintInformation %u
\n
"
,
info
->
PriorityHint
);
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER
;
}
else
io
->
u
.
Status
=
STATUS_INFO_LENGTH_MISMATCH
;
break
;
case
FileAllInformation
:
io
->
u
.
Status
=
STATUS_INVALID_INFO_CLASS
;
break
;
case
FileValidDataLengthInformation
:
if
(
len
>=
sizeof
(
FILE_VALID_DATA_LENGTH_INFORMATION
))
{
struct
stat
st
;
const
FILE_VALID_DATA_LENGTH_INFORMATION
*
info
=
ptr
;
if
((
io
->
u
.
Status
=
server_get_unix_fd
(
handle
,
FILE_WRITE_DATA
,
&
fd
,
&
needs_close
,
NULL
,
NULL
)))
return
io
->
u
.
Status
;
if
(
fstat
(
fd
,
&
st
)
==
-
1
)
io
->
u
.
Status
=
errno_to_status
(
errno
);
else
if
(
info
->
ValidDataLength
.
QuadPart
<=
0
||
(
off_t
)
info
->
ValidDataLength
.
QuadPart
>
st
.
st_size
)
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER
;
else
{
#ifdef HAVE_FALLOCATE
if
(
fallocate
(
fd
,
0
,
0
,
(
off_t
)
info
->
ValidDataLength
.
QuadPart
)
==
-
1
)
{
NTSTATUS
status
=
errno_to_status
(
errno
);
if
(
status
==
STATUS_NOT_SUPPORTED
)
WARN
(
"fallocate not supported on this filesystem
\n
"
);
else
io
->
u
.
Status
=
status
;
}
#else
FIXME
(
"setting valid data length not supported
\n
"
);
#endif
}
if
(
needs_close
)
close
(
fd
);
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
case
FileDispositionInformation
:
if
(
len
>=
sizeof
(
FILE_DISPOSITION_INFORMATION
))
{
FILE_DISPOSITION_INFORMATION
*
info
=
ptr
;
SERVER_START_REQ
(
set_fd_disp_info
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
unlink
=
info
->
DoDeleteFile
;
io
->
u
.
Status
=
wine_server_call
(
req
);
}
SERVER_END_REQ
;
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
case
FileRenameInformation
:
if
(
len
>=
sizeof
(
FILE_RENAME_INFORMATION
))
{
FILE_RENAME_INFORMATION
*
info
=
ptr
;
UNICODE_STRING
name_str
;
OBJECT_ATTRIBUTES
attr
;
ANSI_STRING
unix_name
;
name_str
.
Buffer
=
info
->
FileName
;
name_str
.
Length
=
info
->
FileNameLength
;
name_str
.
MaximumLength
=
info
->
FileNameLength
+
sizeof
(
WCHAR
);
attr
.
Length
=
sizeof
(
attr
);
attr
.
ObjectName
=
&
name_str
;
attr
.
RootDirectory
=
info
->
RootDirectory
;
attr
.
Attributes
=
OBJ_CASE_INSENSITIVE
;
io
->
u
.
Status
=
nt_to_unix_file_name_attr
(
&
attr
,
&
unix_name
,
FILE_OPEN_IF
);
if
(
io
->
u
.
Status
!=
STATUS_SUCCESS
&&
io
->
u
.
Status
!=
STATUS_NO_SUCH_FILE
)
break
;
SERVER_START_REQ
(
set_fd_name_info
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
rootdir
=
wine_server_obj_handle
(
attr
.
RootDirectory
);
req
->
link
=
FALSE
;
req
->
replace
=
info
->
ReplaceIfExists
;
wine_server_add_data
(
req
,
unix_name
.
Buffer
,
unix_name
.
Length
);
io
->
u
.
Status
=
wine_server_call
(
req
);
}
SERVER_END_REQ
;
RtlFreeAnsiString
(
&
unix_name
);
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
case
FileLinkInformation
:
if
(
len
>=
sizeof
(
FILE_LINK_INFORMATION
))
{
FILE_LINK_INFORMATION
*
info
=
ptr
;
UNICODE_STRING
name_str
;
OBJECT_ATTRIBUTES
attr
;
ANSI_STRING
unix_name
;
name_str
.
Buffer
=
info
->
FileName
;
name_str
.
Length
=
info
->
FileNameLength
;
name_str
.
MaximumLength
=
info
->
FileNameLength
+
sizeof
(
WCHAR
);
attr
.
Length
=
sizeof
(
attr
);
attr
.
ObjectName
=
&
name_str
;
attr
.
RootDirectory
=
info
->
RootDirectory
;
attr
.
Attributes
=
OBJ_CASE_INSENSITIVE
;
io
->
u
.
Status
=
nt_to_unix_file_name_attr
(
&
attr
,
&
unix_name
,
FILE_OPEN_IF
);
if
(
io
->
u
.
Status
!=
STATUS_SUCCESS
&&
io
->
u
.
Status
!=
STATUS_NO_SUCH_FILE
)
break
;
SERVER_START_REQ
(
set_fd_name_info
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
rootdir
=
wine_server_obj_handle
(
attr
.
RootDirectory
);
req
->
link
=
TRUE
;
req
->
replace
=
info
->
ReplaceIfExists
;
wine_server_add_data
(
req
,
unix_name
.
Buffer
,
unix_name
.
Length
);
io
->
u
.
Status
=
wine_server_call
(
req
);
}
SERVER_END_REQ
;
RtlFreeAnsiString
(
&
unix_name
);
}
else
io
->
u
.
Status
=
STATUS_INVALID_PARAMETER_3
;
break
;
default:
FIXME
(
"Unsupported class (%d)
\n
"
,
class
);
io
->
u
.
Status
=
STATUS_NOT_IMPLEMENTED
;
break
;
}
io
->
Information
=
0
;
return
io
->
u
.
Status
;
}
dlls/ntdll/unix/loader.c
View file @
c3e2013b
...
...
@@ -864,6 +864,7 @@ static struct unix_funcs unix_funcs =
NtQueryDirectoryFile
,
NtQueryEvent
,
NtQueryFullAttributesFile
,
NtQueryInformationFile
,
NtQueryInformationJobObject
,
NtQueryIoCompletion
,
NtQueryMutant
,
...
...
@@ -886,6 +887,7 @@ static struct unix_funcs unix_funcs =
NtResumeThread
,
NtSetContextThread
,
NtSetEvent
,
NtSetInformationFile
,
NtSetInformationJobObject
,
NtSetIoCompletion
,
NtSetLdtEntries
,
...
...
@@ -955,8 +957,6 @@ static struct unix_funcs unix_funcs =
server_handle_to_fd
,
server_release_fd
,
server_init_process_done
,
file_id_to_unix_file_name
,
nt_to_unix_file_name_attr
,
nt_to_unix_file_name
,
unmount_device
,
set_show_dot_files
,
...
...
dlls/ntdll/unix/unix_private.h
View file @
c3e2013b
...
...
@@ -120,9 +120,6 @@ extern NTSTATUS CDECL exec_process( const UNICODE_STRING *cmdline, const pe_imag
extern
NTSTATUS
CDECL
fork_and_exec
(
const
char
*
unix_name
,
const
char
*
unix_dir
,
const
RTL_USER_PROCESS_PARAMETERS
*
params
)
DECLSPEC_HIDDEN
;
extern
NTSTATUS
CDECL
file_id_to_unix_file_name
(
const
OBJECT_ATTRIBUTES
*
attr
,
ANSI_STRING
*
unix_name
)
DECLSPEC_HIDDEN
;
extern
NTSTATUS
CDECL
nt_to_unix_file_name_attr
(
const
OBJECT_ATTRIBUTES
*
attr
,
ANSI_STRING
*
unix_name_ret
,
UINT
disposition
)
DECLSPEC_HIDDEN
;
extern
NTSTATUS
CDECL
nt_to_unix_file_name
(
const
UNICODE_STRING
*
nameW
,
ANSI_STRING
*
unix_name_ret
,
UINT
disposition
,
BOOLEAN
check_case
)
DECLSPEC_HIDDEN
;
extern
NTSTATUS
CDECL
unmount_device
(
HANDLE
handle
)
DECLSPEC_HIDDEN
;
...
...
dlls/ntdll/unixlib.h
View file @
c3e2013b
...
...
@@ -28,7 +28,7 @@ struct ldt_copy;
struct
msghdr
;
/* increment this when you change the function table */
#define NTDLL_UNIXLIB_VERSION 4
5
#define NTDLL_UNIXLIB_VERSION 4
6
struct
unix_funcs
{
...
...
@@ -129,6 +129,8 @@ struct unix_funcs
void
*
info
,
ULONG
len
,
ULONG
*
ret_len
);
NTSTATUS
(
WINAPI
*
NtQueryFullAttributesFile
)(
const
OBJECT_ATTRIBUTES
*
attr
,
FILE_NETWORK_OPEN_INFORMATION
*
info
);
NTSTATUS
(
WINAPI
*
NtQueryInformationFile
)(
HANDLE
hFile
,
IO_STATUS_BLOCK
*
io
,
void
*
ptr
,
LONG
len
,
FILE_INFORMATION_CLASS
class
);
NTSTATUS
(
WINAPI
*
NtQueryInformationJobObject
)(
HANDLE
handle
,
JOBOBJECTINFOCLASS
class
,
void
*
info
,
ULONG
len
,
ULONG
*
ret_len
);
NTSTATUS
(
WINAPI
*
NtQueryIoCompletion
)(
HANDLE
handle
,
IO_COMPLETION_INFORMATION_CLASS
class
,
...
...
@@ -165,6 +167,8 @@ struct unix_funcs
NTSTATUS
(
WINAPI
*
NtResumeThread
)(
HANDLE
handle
,
ULONG
*
count
);
NTSTATUS
(
WINAPI
*
NtSetContextThread
)(
HANDLE
handle
,
const
CONTEXT
*
context
);
NTSTATUS
(
WINAPI
*
NtSetEvent
)(
HANDLE
handle
,
LONG
*
prev_state
);
NTSTATUS
(
WINAPI
*
NtSetInformationFile
)(
HANDLE
handle
,
IO_STATUS_BLOCK
*
io
,
void
*
ptr
,
ULONG
len
,
FILE_INFORMATION_CLASS
class
);
NTSTATUS
(
WINAPI
*
NtSetInformationJobObject
)(
HANDLE
handle
,
JOBOBJECTINFOCLASS
class
,
void
*
info
,
ULONG
len
);
NTSTATUS
(
WINAPI
*
NtSetIoCompletion
)(
HANDLE
handle
,
ULONG_PTR
key
,
ULONG_PTR
value
,
...
...
@@ -273,10 +277,6 @@ struct unix_funcs
void
(
CDECL
*
server_init_process_done
)(
void
*
relay
);
/* file functions */
NTSTATUS
(
CDECL
*
file_id_to_unix_file_name
)(
const
OBJECT_ATTRIBUTES
*
attr
,
ANSI_STRING
*
unix_name
);
NTSTATUS
(
CDECL
*
nt_to_unix_file_name_attr
)(
const
OBJECT_ATTRIBUTES
*
attr
,
ANSI_STRING
*
unix_name_ret
,
UINT
disposition
);
NTSTATUS
(
CDECL
*
nt_to_unix_file_name
)(
const
UNICODE_STRING
*
nameW
,
ANSI_STRING
*
unix_name_ret
,
UINT
disposition
,
BOOLEAN
check_case
);
NTSTATUS
(
CDECL
*
unmount_device
)(
HANDLE
handle
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment