mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-01-18 12:29:32 +08:00
* ntdll.h: Add descriptive comments to special Rtl functions.
(STATUS_OBJECT_PATH_NOT_FOUND): Define. (STATUS_BUFFER_OVERFLOW): Define. (FILE_SUPERSEDED): Define. (FILE_OPENED): Define. (FILE_CREATED): Define. (FILE_OVERWRITTEN): Define. (FILE_EXISTS): Define. (FILE_DOES_NOT_EXIST): Define. (PIO_APC_ROUTINE): Typedef. (NtFsControlFile): Fix parameter types to use PIO_APC_ROUTINE. (NtWriteFile): Declare. (RtlInt64ToHexUnicodeString): Declare. * strfuncs.cc: Include ntdll.h. (RtlInt64ToHexUnicodeString): New function. * syscalls.cc (try_to_bin): Rewrite using native NT functions. Only try to create recycle bin after unsuccessfully trying to move file. Also try to create special files in recycle bin so that Windows Explorer isn't unnecessarily stampeded.
This commit is contained in:
parent
847e89f8e1
commit
61c44b72d4
@ -1,3 +1,25 @@
|
||||
2007-08-12 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* ntdll.h: Add descriptive comments to special Rtl functions.
|
||||
(STATUS_OBJECT_PATH_NOT_FOUND): Define.
|
||||
(STATUS_BUFFER_OVERFLOW): Define.
|
||||
(FILE_SUPERSEDED): Define.
|
||||
(FILE_OPENED): Define.
|
||||
(FILE_CREATED): Define.
|
||||
(FILE_OVERWRITTEN): Define.
|
||||
(FILE_EXISTS): Define.
|
||||
(FILE_DOES_NOT_EXIST): Define.
|
||||
(PIO_APC_ROUTINE): Typedef.
|
||||
(NtFsControlFile): Fix parameter types to use PIO_APC_ROUTINE.
|
||||
(NtWriteFile): Declare.
|
||||
(RtlInt64ToHexUnicodeString): Declare.
|
||||
* strfuncs.cc: Include ntdll.h.
|
||||
(RtlInt64ToHexUnicodeString): New function.
|
||||
* syscalls.cc (try_to_bin): Rewrite using native NT functions.
|
||||
Only try to create recycle bin after unsuccessfully trying to move
|
||||
file. Also try to create special files in recycle bin so that Windows
|
||||
Explorer isn't unnecessarily stampeded.
|
||||
|
||||
2007-08-10 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* path.cc (fillout_mntent): Fix calculation of unicode buffer size.
|
||||
|
@ -20,6 +20,7 @@
|
||||
#define STATUS_ACCESS_DENIED ((NTSTATUS) 0xc0000022)
|
||||
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xc0000023)
|
||||
#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xc0000034)
|
||||
#define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS) 0xc000003A)
|
||||
#define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xc0000043)
|
||||
#define STATUS_DELETE_PENDING ((NTSTATUS) 0xc0000056)
|
||||
#define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xc00000a1)
|
||||
@ -27,6 +28,7 @@
|
||||
#define STATUS_DIRECTORY_NOT_EMPTY ((NTSTATUS) 0xc0000101)
|
||||
#define STATUS_NOT_ALL_ASSIGNED ((NTSTATUS) 0x00000106)
|
||||
#define STATUS_INVALID_LEVEL ((NTSTATUS) 0xc0000148)
|
||||
#define STATUS_BUFFER_OVERFLOW ((NTSTATUS) 0x80000005)
|
||||
#define STATUS_NO_MORE_FILES ((NTSTATUS) 0x80000006)
|
||||
#define PDI_MODULES 0x01
|
||||
#define PDI_HEAPS 0x04
|
||||
@ -41,6 +43,13 @@
|
||||
#define WSLE_PAGE_SHARE_COUNT_MASK 0x0E0
|
||||
#define WSLE_PAGE_SHAREABLE 0x100
|
||||
|
||||
#define FILE_SUPERSEDED 0
|
||||
#define FILE_OPENED 1
|
||||
#define FILE_CREATED 2
|
||||
#define FILE_OVERWRITTEN 3
|
||||
#define FILE_EXISTS 4
|
||||
#define FILE_DOES_NOT_EXIST 5
|
||||
|
||||
/* Device Characteristics. */
|
||||
#define FILE_REMOVABLE_MEDIA 0x00000001
|
||||
#define FILE_READ_ONLY_DEVICE 0x00000002
|
||||
@ -736,6 +745,8 @@ typedef struct _FILE_FULL_EA_INFORMATION
|
||||
CHAR EaName[1];
|
||||
} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;
|
||||
|
||||
typedef VOID NTAPI (*PIO_APC_ROUTINE)(PVOID, PIO_STATUS_BLOCK, ULONG);
|
||||
|
||||
/* Function declarations for ntdll.dll. These don't appear in any
|
||||
standard Win32 header. */
|
||||
extern "C"
|
||||
@ -753,7 +764,7 @@ extern "C"
|
||||
PTOKEN_GROUPS, PTOKEN_PRIVILEGES, PTOKEN_OWNER,
|
||||
PTOKEN_PRIMARY_GROUP, PTOKEN_DEFAULT_DACL,
|
||||
PTOKEN_SOURCE);
|
||||
NTSTATUS NTAPI NtFsControlFile (HANDLE, HANDLE, PVOID, PVOID,
|
||||
NTSTATUS NTAPI NtFsControlFile (HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID,
|
||||
PIO_STATUS_BLOCK, ULONG, PVOID, ULONG,
|
||||
PVOID, ULONG);
|
||||
NTSTATUS NTAPI NtLockVirtualMemory (HANDLE, PVOID *, ULONG *, ULONG);
|
||||
@ -799,6 +810,9 @@ extern "C"
|
||||
PSECURITY_DESCRIPTOR);
|
||||
NTSTATUS NTAPI NtUnlockVirtualMemory (HANDLE, PVOID *, ULONG *, ULONG);
|
||||
NTSTATUS NTAPI NtUnmapViewOfSection (HANDLE, PVOID);
|
||||
NTSTATUS NTAPI NtWriteFile (HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID,
|
||||
PIO_STATUS_BLOCK, PVOID, ULONG, PLARGE_INTEGER,
|
||||
PULONG);
|
||||
NTSTATUS NTAPI RtlAppendUnicodeToString (PUNICODE_STRING, PCWSTR);
|
||||
NTSTATUS NTAPI RtlAppendUnicodeStringToString (PUNICODE_STRING,
|
||||
PUNICODE_STRING);
|
||||
@ -830,8 +844,11 @@ extern "C"
|
||||
BOOLEAN);
|
||||
|
||||
/* A few Rtl functions are either actually macros, or they just don't
|
||||
exist even though they would be a big help. We implement them here
|
||||
as inline functions. */
|
||||
exist even though they would be a big help. We implement them here,
|
||||
partly as inline functions. */
|
||||
|
||||
/* RtlInitEmptyUnicodeString is defined as a macro in wdm.h, but that file
|
||||
is missing entirely in w32api. */
|
||||
inline
|
||||
VOID NTAPI RtlInitEmptyUnicodeString(PUNICODE_STRING dest, PCWSTR buf,
|
||||
USHORT len)
|
||||
@ -840,6 +857,11 @@ extern "C"
|
||||
dest->MaximumLength = len;
|
||||
dest->Buffer = (PWSTR) buf;
|
||||
}
|
||||
/* Like RtlInitEmptyUnicodeString, but initialize Length to len, too.
|
||||
This is for instance useful when creating a UNICODE_STRING from an
|
||||
NtQueryInformationFile info buffer, where the length of the filename
|
||||
is known, but you can't rely on the string being 0-terminated.
|
||||
If you know it's 0-terminated, just use RtlInitUnicodeString(). */
|
||||
inline
|
||||
VOID NTAPI RtlInitCountedUnicodeString (PUNICODE_STRING dest, PCWSTR buf,
|
||||
USHORT len)
|
||||
@ -847,20 +869,29 @@ extern "C"
|
||||
dest->Length = dest->MaximumLength = len;
|
||||
dest->Buffer = (PWSTR) buf;
|
||||
}
|
||||
/* Split path into dirname and basename part. This function does not
|
||||
copy anything! It just initializes the dirname and basename
|
||||
UNICODE_STRINGs so that their Buffer members point to the right spot
|
||||
into path's Buffer, and the Length (and MaximumLength) members are set
|
||||
to match the dirname part and the basename part.
|
||||
Note that dirname's Length is set so that it also includes the trailing
|
||||
backslash. If you don't need it, just subtract sizeof(WCHAR) from
|
||||
dirname.Length. */
|
||||
inline
|
||||
VOID NTAPI RtlSplitUnicodePath (PUNICODE_STRING path, PUNICODE_STRING dir,
|
||||
PUNICODE_STRING file)
|
||||
VOID NTAPI RtlSplitUnicodePath (PUNICODE_STRING path, PUNICODE_STRING dirname,
|
||||
PUNICODE_STRING basename)
|
||||
{
|
||||
USHORT len = path->Length / sizeof (WCHAR);
|
||||
while (len > 0 && path->Buffer[--len] != L'\\')
|
||||
;
|
||||
++len;
|
||||
if (dir)
|
||||
RtlInitCountedUnicodeString (dir, path->Buffer, len * sizeof (WCHAR));
|
||||
if (file)
|
||||
RtlInitCountedUnicodeString (file, &path->Buffer[len],
|
||||
if (dirname)
|
||||
RtlInitCountedUnicodeString (dirname, path->Buffer, len * sizeof (WCHAR));
|
||||
if (basename)
|
||||
RtlInitCountedUnicodeString (basename, &path->Buffer[len],
|
||||
path->Length - len * sizeof (WCHAR));
|
||||
}
|
||||
/* Check if prefix is a prefix of path. */
|
||||
inline
|
||||
BOOLEAN NTAPI RtlEqualUnicodePathPrefix (PUNICODE_STRING path, PCWSTR prefix,
|
||||
BOOLEAN caseinsensitive)
|
||||
@ -873,6 +904,7 @@ extern "C"
|
||||
? pref.Length : path->Length);
|
||||
return RtlEqualUnicodeString (&p, &pref, caseinsensitive);
|
||||
}
|
||||
/* Check if sufffix is a sufffix of path. */
|
||||
inline
|
||||
BOOL NTAPI RtlEqualUnicodePathSuffix (PUNICODE_STRING path, PCWSTR suffix,
|
||||
BOOLEAN caseinsensitive)
|
||||
@ -888,4 +920,12 @@ extern "C"
|
||||
RtlInitCountedUnicodeString (&p, path->Buffer, path->Length);
|
||||
return RtlEqualUnicodeString (&p, &suf, caseinsensitive);
|
||||
}
|
||||
/* Implemented in strfuncs.cc. Create a Hex UNICODE_STRING from a given
|
||||
64 bit integer value. If append is TRUE, append the hex string,
|
||||
otherwise overwrite dest. Returns either STAUTUS_SUCCESS, or
|
||||
STATUS_BUFFER_OVERFLOW, if the unicode buffer is too small (hasn't
|
||||
room for 16 WCHARs). */
|
||||
NTSTATUS NTAPI RtlInt64ToHexUnicodeString (ULONGLONG value,
|
||||
PUNICODE_STRING dest,
|
||||
BOOLEAN append);
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ details. */
|
||||
#include "winsup.h"
|
||||
#include <winbase.h>
|
||||
#include <winnls.h>
|
||||
#include <ntdll.h>
|
||||
|
||||
codepage_type current_codepage = ansi_cp;
|
||||
|
||||
@ -41,3 +42,23 @@ sys_mbstowcs (WCHAR *tgt, const char *src, int len)
|
||||
int res = MultiByteToWideChar (get_cp (), 0, src, -1, tgt, len);
|
||||
return res;
|
||||
}
|
||||
|
||||
static WCHAR hex_wchars[] = L"0123456789abcdef";
|
||||
|
||||
NTSTATUS NTAPI
|
||||
RtlInt64ToHexUnicodeString (ULONGLONG value, PUNICODE_STRING dest,
|
||||
BOOLEAN append)
|
||||
{
|
||||
USHORT len = append ? dest->Length : 0;
|
||||
if (dest->MaximumLength - len < 16 * (int) sizeof (WCHAR))
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
PWCHAR end = (PWCHAR) ((PBYTE) dest->Buffer + len);
|
||||
register PWCHAR p = end + 16;
|
||||
while (p-- > end)
|
||||
{
|
||||
*p = hex_wchars[value & 0xf];
|
||||
value >>= 4;
|
||||
}
|
||||
dest->Length += 16 * sizeof (WCHAR);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -139,94 +139,231 @@ dup2 (int oldfd, int newfd)
|
||||
return cygheap->fdtab.dup2 (oldfd, newfd);
|
||||
}
|
||||
|
||||
static char desktop_ini[] =
|
||||
"[.ShellClassInfo]\r\nCLSID={645FF040-5081-101B-9F08-00AA002F954E}\r\n";
|
||||
static BYTE info2[] =
|
||||
{
|
||||
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static void
|
||||
try_to_bin (path_conv &win32_path, HANDLE h)
|
||||
{
|
||||
NTSTATUS status;
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
IO_STATUS_BLOCK io;
|
||||
char recycler[CYG_MAX_PATH + 20];
|
||||
HANDLE rootdir = NULL, recyclerdir = NULL;
|
||||
USHORT recycler_base_len = 0, recycler_user_len = 0;
|
||||
UNICODE_STRING root, recycler, fname;
|
||||
WCHAR recyclerbuf[NAME_MAX + 1]; /* Enough for recycler + SID + filename */
|
||||
PFILE_NAME_INFORMATION pfni;
|
||||
PFILE_INTERNAL_INFORMATION pfii;
|
||||
PFILE_RENAME_INFORMATION pfri;
|
||||
BYTE infobuf[sizeof (FILE_NAME_INFORMATION ) + 32767 * sizeof (WCHAR)];
|
||||
|
||||
rootdir (win32_path, recycler);
|
||||
char *c = recycler + strlen (recycler);
|
||||
if (wincap.has_recycle_dot_bin ())
|
||||
pfni = (PFILE_NAME_INFORMATION) infobuf;
|
||||
status = NtQueryInformationFile (h, &io, pfni, sizeof infobuf,
|
||||
FileNameInformation);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
strcpy (c, "$Recycle.Bin"); /* NTFS and FAT since Vista */
|
||||
c += 12;
|
||||
}
|
||||
else if (win32_path.fs_is_ntfs ())
|
||||
{
|
||||
strcpy (c, "RECYCLER"); /* NTFS up to 2K3 */
|
||||
c += 8;
|
||||
}
|
||||
else if (win32_path.fs_is_fat ())
|
||||
{
|
||||
strcpy (c, "Recycled"); /* FAT up to 2K3 */
|
||||
c += 8;
|
||||
debug_printf ("NtQueryInformationFile (FileNameInformation) failed, %08x",
|
||||
status);
|
||||
goto out;
|
||||
}
|
||||
/* The filename could change, the parent dir not. So we split both paths
|
||||
and take the prefix. However, there are two special cases:
|
||||
- The handle refers to the root dir of the volume.
|
||||
- The handle refers to the recycler or a subdir.
|
||||
Both cases are handled by just returning and not even trying to move
|
||||
them into the recycler. */
|
||||
if (pfni->FileNameLength == 2) /* root dir. */
|
||||
goto out;
|
||||
/* Initialize recycler path. */
|
||||
RtlInitEmptyUnicodeString (&recycler, recyclerbuf, sizeof recyclerbuf);
|
||||
if (wincap.has_recycle_dot_bin ()) /* NTFS and FAT since Vista */
|
||||
RtlAppendUnicodeToString (&recycler, L"\\$Recycle.Bin\\");
|
||||
else if (win32_path.fs_is_ntfs ()) /* NTFS up to 2K3 */
|
||||
RtlAppendUnicodeToString (&recycler, L"\\RECYCLER\\");
|
||||
else if (win32_path.fs_is_fat ()) /* FAT up to 2K3 */
|
||||
RtlAppendUnicodeToString (&recycler, L"\\Recycled\\");
|
||||
else
|
||||
return;
|
||||
goto out;
|
||||
/* Is the file a subdir of the recycler? */
|
||||
RtlInitCountedUnicodeString(&fname, pfni->FileName, pfni->FileNameLength);
|
||||
if (RtlEqualUnicodePathPrefix (&fname, recycler.Buffer, TRUE))
|
||||
goto out;
|
||||
/* Is fname the recycler? Temporarily hide trailing backslash. */
|
||||
recycler.Length -= sizeof (WCHAR);
|
||||
if (RtlEqualUnicodeString (&fname, &recycler, TRUE))
|
||||
goto out;
|
||||
|
||||
/* Yes, we can really do that. Typically the recycle bin is created
|
||||
by the first user actually using the bin. The permissions are the
|
||||
default permissions propagated from the root directory. */
|
||||
if (GetFileAttributes (recycler) == INVALID_FILE_ATTRIBUTES)
|
||||
/* Create root dir path from file name information. */
|
||||
RtlSplitUnicodePath (&fname, &fname, NULL);
|
||||
RtlSplitUnicodePath (win32_path.get_nt_native_path (), &root, NULL);
|
||||
root.Length -= fname.Length - sizeof (WCHAR);
|
||||
|
||||
/* Open root directory. */
|
||||
InitializeObjectAttributes (&attr, &root, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
||||
status = NtOpenFile (&rootdir, FILE_TRAVERSE, &attr, &io,
|
||||
FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
if (!CreateDirectory (recycler, NULL))
|
||||
{
|
||||
debug_printf ("Can't create folder %s, %E", recycler);
|
||||
return;
|
||||
}
|
||||
SetFileAttributes (recycler,
|
||||
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
|
||||
debug_printf ("NtOpenFile (%S) failed, %08x", &root, status);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Up to Windows 2003 Server, the default settings for the top level recycle
|
||||
bin are so that everybody has the right to create files in it. Starting
|
||||
with Vista, users are by default not allowed to create files in that
|
||||
directory, only subdirectories. Too bad, but that requires to move
|
||||
files to the user's own recycler subdir. Instead of adding yet another
|
||||
special case, we just move the stuff to the user's recycler, especially
|
||||
since only shared files are moved at all. */
|
||||
/* Strip leading backslash */
|
||||
++recycler.Buffer;
|
||||
recycler.Length -= sizeof (WCHAR);
|
||||
/* Store length of recycler base dir, should it be necessary to create it. */
|
||||
recycler_base_len = recycler.Length;
|
||||
/* On NTFS the recycler dir contains user specific subdirs, which are the
|
||||
actual recycle bins per user. The name if this dir is the string
|
||||
representation of the user SID. */
|
||||
if (win32_path.fs_is_ntfs ())
|
||||
{
|
||||
*c++ = '\\';
|
||||
cygheap->user.get_windows_id (c);
|
||||
while (*c)
|
||||
++c;
|
||||
if (GetFileAttributes (recycler) == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
if (!CreateDirectory (recycler,
|
||||
sec_user ((PSECURITY_ATTRIBUTES) alloca (1024),
|
||||
cygheap->user.sid ())))
|
||||
{
|
||||
debug_printf ("Can't create folder %s, %E", recycler);
|
||||
return;
|
||||
}
|
||||
SetFileAttributes (recycler,
|
||||
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
|
||||
}
|
||||
UNICODE_STRING sid;
|
||||
WCHAR sidbuf[128];
|
||||
/* Unhide trailing backslash. */
|
||||
recycler.Length += sizeof (WCHAR);
|
||||
RtlInitEmptyUnicodeString (&sid, sidbuf, sizeof sidbuf);
|
||||
/* In contrast to what MSDN claims, this function is already available
|
||||
since NT4. */
|
||||
RtlConvertSidToUnicodeString (&sid, cygheap->user.sid (), FALSE);
|
||||
RtlAppendUnicodeStringToString (&recycler, &sid);
|
||||
recycler_user_len = recycler.Length;
|
||||
}
|
||||
|
||||
/* Create hopefully unique filename. */
|
||||
__small_sprintf (c, "\\cyg%016X", hash_path_name (myself->uid,
|
||||
win32_path.get_win32 ()));
|
||||
c += 20;
|
||||
|
||||
/* Length of the WCHAR path in bytes. */
|
||||
ULONG len = 2 * (c - recycler);
|
||||
/* Choose size big enough to fit a local native NT path into it. */
|
||||
ULONG size = sizeof (FILE_RENAME_INFORMATION) + len + 10;
|
||||
PFILE_RENAME_INFORMATION pfri = (PFILE_RENAME_INFORMATION) alloca (size);
|
||||
|
||||
RtlAppendUnicodeToString (&recycler, L"\\cyg");
|
||||
pfii = (PFILE_INTERNAL_INFORMATION) infobuf;
|
||||
status = NtQueryInformationFile (h, &io, pfii, sizeof infobuf,
|
||||
FileInternalInformation);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
debug_printf ("NtQueryInformationFile (FileInternalInformation) failed, "
|
||||
"%08x", status);
|
||||
goto out;
|
||||
}
|
||||
RtlInt64ToHexUnicodeString (pfii->FileId.QuadPart, &recycler, TRUE);
|
||||
/* Shoot. */
|
||||
pfri = (PFILE_RENAME_INFORMATION) infobuf;
|
||||
pfri->ReplaceIfExists = TRUE;
|
||||
pfri->RootDirectory = NULL;
|
||||
UNICODE_STRING uname = { 0, len + 10, pfri->FileName };
|
||||
get_nt_native_path (recycler, uname);
|
||||
pfri->FileNameLength = uname.Length;
|
||||
status = NtSetInformationFile (h, &io, pfri, size, FileRenameInformation);
|
||||
pfri->RootDirectory = rootdir;
|
||||
pfri->FileNameLength = recycler.Length;
|
||||
memcpy (pfri->FileName, recycler.Buffer, recycler.Length);
|
||||
status = NtSetInformationFile (h, &io, pfri, sizeof infobuf,
|
||||
FileRenameInformation);
|
||||
if (status == STATUS_OBJECT_PATH_NOT_FOUND)
|
||||
{
|
||||
/* Ok, so the recycler and/or the recycler/SID directory don't exist.
|
||||
First reopen root dir with permission to create subdirs. */
|
||||
NtClose (rootdir);
|
||||
status = NtOpenFile (&rootdir, FILE_ADD_SUBDIRECTORY, &attr, &io,
|
||||
FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
debug_printf ("NtOpenFile (%S) failed, %08x", &recycler, status);
|
||||
goto out;
|
||||
}
|
||||
/* Then check if recycler exists by opening and potentially creating it.
|
||||
Yes, we can really do that. Typically the recycle bin is created
|
||||
by the first user actually using the bin. The permissions are the
|
||||
default permissions propagated from the root directory. */
|
||||
InitializeObjectAttributes (&attr, &recycler, OBJ_CASE_INSENSITIVE,
|
||||
rootdir, NULL);
|
||||
recycler.Length = recycler_base_len;
|
||||
status = NtCreateFile (&recyclerdir,
|
||||
READ_CONTROL
|
||||
| (win32_path.fs_is_ntfs () ? 0 : FILE_ADD_FILE),
|
||||
&attr, &io, NULL,
|
||||
FILE_ATTRIBUTE_DIRECTORY
|
||||
| FILE_ATTRIBUTE_SYSTEM
|
||||
| FILE_ATTRIBUTE_HIDDEN,
|
||||
FILE_SHARE_VALID_FLAGS, FILE_OPEN_IF,
|
||||
FILE_DIRECTORY_FILE, NULL, 0);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
debug_printf ("NtCreateFile (%S) failed, %08x", &recycler, status);
|
||||
goto out;
|
||||
}
|
||||
/* Next, if necessary, check if the recycler/SID dir exists and
|
||||
create it if not. */
|
||||
if (win32_path.fs_is_ntfs ())
|
||||
{
|
||||
NtClose (recyclerdir);
|
||||
recycler.Length = recycler_user_len;
|
||||
status = NtCreateFile (&recyclerdir, READ_CONTROL | FILE_ADD_FILE,
|
||||
&attr, &io, NULL, FILE_ATTRIBUTE_DIRECTORY
|
||||
| FILE_ATTRIBUTE_SYSTEM
|
||||
| FILE_ATTRIBUTE_HIDDEN,
|
||||
FILE_SHARE_VALID_FLAGS, FILE_OPEN_IF,
|
||||
FILE_DIRECTORY_FILE, NULL, 0);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
debug_printf ("NtCreateFile (%S) failed, %08x",
|
||||
&recycler, status);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* The desktop.ini and INFO2 (pre-Vista) files are expected by
|
||||
Windows Explorer. Otherwise, the created bin is treated as
|
||||
corrupted */
|
||||
if (io.Information == FILE_CREATED)
|
||||
{
|
||||
HANDLE fh;
|
||||
RtlInitUnicodeString (&fname, L"desktop.ini");
|
||||
InitializeObjectAttributes (&attr, &fname, OBJ_CASE_INSENSITIVE,
|
||||
recyclerdir, NULL);
|
||||
status = NtCreateFile (&fh, FILE_GENERIC_WRITE, &attr, &io, NULL,
|
||||
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
|
||||
FILE_SHARE_VALID_FLAGS, FILE_CREATE,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT
|
||||
| FILE_NON_DIRECTORY_FILE, NULL, 0);
|
||||
if (!NT_SUCCESS (status))
|
||||
debug_printf ("NtCreateFile (%S) failed, %08x", &recycler, status);
|
||||
else
|
||||
{
|
||||
status = NtWriteFile (fh, NULL, NULL, NULL, &io, desktop_ini,
|
||||
sizeof desktop_ini - 1, NULL, NULL);
|
||||
if (!NT_SUCCESS (status))
|
||||
debug_printf ("NtWriteFile (%S) failed, %08x", &fname, status);
|
||||
NtClose (fh);
|
||||
}
|
||||
if (!wincap.has_recycle_dot_bin ()) /* No INFO2 file since Vista */
|
||||
{
|
||||
RtlInitUnicodeString (&fname, L"INFO2");
|
||||
status = NtCreateFile (&fh, FILE_GENERIC_WRITE, &attr, &io, NULL,
|
||||
FILE_ATTRIBUTE_ARCHIVE
|
||||
| FILE_ATTRIBUTE_HIDDEN,
|
||||
FILE_SHARE_VALID_FLAGS, FILE_CREATE,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT
|
||||
| FILE_NON_DIRECTORY_FILE, NULL, 0);
|
||||
if (!NT_SUCCESS (status))
|
||||
debug_printf ("NtCreateFile (%S) failed, %08x",
|
||||
&recycler, status);
|
||||
else
|
||||
{
|
||||
status = NtWriteFile (fh, NULL, NULL, NULL, &io, info2,
|
||||
sizeof info2, NULL, NULL);
|
||||
if (!NT_SUCCESS (status))
|
||||
debug_printf ("NtWriteFile (%S) failed, %08x",
|
||||
&fname, status);
|
||||
NtClose (fh);
|
||||
}
|
||||
}
|
||||
}
|
||||
NtClose (recyclerdir);
|
||||
/* Shoot again. */
|
||||
status = NtSetInformationFile (h, &io, pfri, sizeof infobuf,
|
||||
FileRenameInformation);
|
||||
}
|
||||
if (!NT_SUCCESS (status))
|
||||
debug_printf ("Move %s to %s failed, status = %p", win32_path.get_win32 (),
|
||||
recycler, status);
|
||||
out:
|
||||
if (rootdir)
|
||||
NtClose (rootdir);
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
|
Loading…
x
Reference in New Issue
Block a user