Blame channels/drive/client/drive_file.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * File System Virtual Channel
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 * Copyright 2010-2011 Vic Lee
Packit 1fb8d4
 * Copyright 2012 Gerald Richter
Packit 1fb8d4
 * Copyright 2015 Thincast Technologies GmbH
Packit 1fb8d4
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
Packit 1fb8d4
 * Copyright 2016 Inuvika Inc.
Packit 1fb8d4
 * Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
Packit 1fb8d4
 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
Packit 1fb8d4
 * Copyright 2017 Thincast Technologies GmbH
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <errno.h>
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
#include <time.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/wtypes.h>
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/path.h>
Packit 1fb8d4
#include <winpr/file.h>
Packit 1fb8d4
#include <winpr/stream.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/channels/rdpdr.h>
Packit 1fb8d4
Packit 1fb8d4
#include "drive_file.h"
Packit 1fb8d4
Packit 1fb8d4
#ifdef WITH_DEBUG_RDPDR
Packit 1fb8d4
#define DEBUG_WSTR(msg, wstr) do { LPSTR lpstr; ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &lpstr, 0, NULL, NULL); WLog_DBG(TAG, msg, lpstr); free(lpstr); } while (0)
Packit 1fb8d4
#else
Packit 1fb8d4
#define DEBUG_WSTR(msg, wstr) do { } while (0)
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
static void drive_file_fix_path(WCHAR* path)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t i;
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	length = (int) _wcslen(path);
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < length; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (path[i] == L'\\')
Packit 1fb8d4
			path[i] = L'/';
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#ifdef WIN32
Packit 1fb8d4
Packit 1fb8d4
	if ((length == 3) && (path[1] == L':') && (path[2] == L'/'))
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
#else
Packit 1fb8d4
Packit 1fb8d4
	if ((length == 1) && (path[0] == L'/'))
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
	if ((length > 0) && (path[length - 1] == L'/'))
Packit 1fb8d4
		path[length - 1] = L'\0';
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static WCHAR* drive_file_combine_fullpath(const WCHAR* base_path, const WCHAR* path,
Packit 1fb8d4
        UINT32 PathLength)
Packit 1fb8d4
{
Packit 1fb8d4
	WCHAR* fullpath;
Packit 1fb8d4
	UINT32 base_path_length;
Packit 1fb8d4
Packit 1fb8d4
	if (!base_path || !path)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	base_path_length = _wcslen(base_path) * 2;
Packit 1fb8d4
	fullpath = (WCHAR*)calloc(1, base_path_length + PathLength + sizeof(WCHAR));
Packit 1fb8d4
Packit 1fb8d4
	if (!fullpath)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "malloc failed!");
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	CopyMemory(fullpath, base_path, base_path_length);
Packit 1fb8d4
	CopyMemory((char*)fullpath + base_path_length, path, PathLength);
Packit 1fb8d4
	drive_file_fix_path(fullpath);
Packit 1fb8d4
	return fullpath;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL drive_file_remove_dir(const WCHAR* path)
Packit 1fb8d4
{
Packit 1fb8d4
	WIN32_FIND_DATAW findFileData;
Packit 1fb8d4
	BOOL ret = TRUE;
Packit 1fb8d4
	INT len;
Packit 1fb8d4
	HANDLE dir;
Packit 1fb8d4
	WCHAR* fullpath;
Packit 1fb8d4
	WCHAR* path_slash;
Packit 1fb8d4
	UINT32 base_path_length;
Packit 1fb8d4
Packit 1fb8d4
	if (!path)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	base_path_length = _wcslen(path) * 2;
Packit 1fb8d4
	path_slash = (WCHAR*)calloc(1, base_path_length + sizeof(WCHAR) * 3);
Packit 1fb8d4
Packit 1fb8d4
	if (!path_slash)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "malloc failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	CopyMemory(path_slash, path, base_path_length);
Packit 1fb8d4
	path_slash[base_path_length / 2] = L'/';
Packit 1fb8d4
	path_slash[base_path_length / 2 + 1] = L'*';
Packit 1fb8d4
	DEBUG_WSTR("Search in %s", path_slash);
Packit 1fb8d4
	dir = FindFirstFileW(path_slash, &findFileData);
Packit 1fb8d4
	path_slash[base_path_length / 2 + 1] = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (dir == INVALID_HANDLE_VALUE)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(path_slash);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	do
Packit 1fb8d4
	{
Packit 1fb8d4
		len = _wcslen(findFileData.cFileName);
Packit 1fb8d4
Packit 1fb8d4
		if ((len == 1 && findFileData.cFileName[0] == L'.') || (len == 2 &&
Packit 1fb8d4
		        findFileData.cFileName[0] == L'.' && findFileData.cFileName[1] == L'.'))
Packit 1fb8d4
		{
Packit 1fb8d4
			continue;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		fullpath = drive_file_combine_fullpath(path_slash, findFileData.cFileName, len * 2);
Packit 1fb8d4
		DEBUG_WSTR("Delete %s", fullpath);
Packit 1fb8d4
Packit 1fb8d4
		if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
Packit 1fb8d4
		{
Packit 1fb8d4
			ret = drive_file_remove_dir(fullpath);
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			ret = DeleteFileW(fullpath);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		free(fullpath);
Packit 1fb8d4
Packit 1fb8d4
		if (!ret)
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
	while (ret && FindNextFileW(dir, &findFileData) != 0);
Packit 1fb8d4
Packit 1fb8d4
	FindClose(dir);
Packit 1fb8d4
Packit 1fb8d4
	if (ret)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!RemoveDirectoryW(path))
Packit 1fb8d4
		{
Packit 1fb8d4
			ret = FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(path_slash);
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL drive_file_set_fullpath(DRIVE_FILE* file, WCHAR* fullpath)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!file || !fullpath)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	free(file->fullpath);
Packit 1fb8d4
	file->fullpath = fullpath;
Packit 1fb8d4
	file->filename = _wcsrchr(file->fullpath, L'/');
Packit 1fb8d4
Packit 1fb8d4
	if (file->filename == NULL)
Packit 1fb8d4
		file->filename = file->fullpath;
Packit 1fb8d4
	else
Packit 1fb8d4
		file->filename += 1;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL drive_file_init(DRIVE_FILE* file)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT CreateDisposition = 0;
Packit 1fb8d4
	DWORD dwAttr = GetFileAttributesW(file->fullpath);
Packit 1fb8d4
Packit 1fb8d4
	if (dwAttr != INVALID_FILE_ATTRIBUTES)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* The file exists */
Packit 1fb8d4
		file->is_dir = (dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0;
Packit 1fb8d4
Packit 1fb8d4
		if (file->is_dir)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (file->CreateDisposition == FILE_CREATE)
Packit 1fb8d4
			{
Packit 1fb8d4
				SetLastError(ERROR_ALREADY_EXISTS);
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (file->CreateOptions & FILE_NON_DIRECTORY_FILE)
Packit 1fb8d4
			{
Packit 1fb8d4
				SetLastError(ERROR_ACCESS_DENIED);
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			return TRUE;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			if (file->CreateOptions & FILE_DIRECTORY_FILE)
Packit 1fb8d4
			{
Packit 1fb8d4
				SetLastError(ERROR_DIRECTORY);
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		file->is_dir = ((file->CreateOptions & FILE_DIRECTORY_FILE) ? TRUE : FALSE);
Packit 1fb8d4
Packit 1fb8d4
		if (file->is_dir)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* Should only create the directory if the disposition allows for it */
Packit 1fb8d4
			if ((file->CreateDisposition == FILE_OPEN_IF) || (file->CreateDisposition == FILE_CREATE))
Packit 1fb8d4
			{
Packit 1fb8d4
				if (CreateDirectoryW(file->fullpath, NULL) != 0)
Packit 1fb8d4
				{
Packit 1fb8d4
					return TRUE;
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			SetLastError(ERROR_FILE_NOT_FOUND);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (file->file_handle == INVALID_HANDLE_VALUE)
Packit 1fb8d4
	{
Packit 1fb8d4
		switch (file->CreateDisposition)
Packit 1fb8d4
		{
Packit 1fb8d4
			case FILE_SUPERSEDE: /* If the file already exists, replace it with the given file. If it does not, create the given file. */
Packit 1fb8d4
				CreateDisposition = CREATE_ALWAYS;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case FILE_OPEN: /* If the file already exists, open it instead of creating a new file. If it does not, fail the request and do not create a new file. */
Packit 1fb8d4
				CreateDisposition = OPEN_EXISTING;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case FILE_CREATE: /* If the file already exists, fail the request and do not create or open the given file. If it does not, create the given file. */
Packit 1fb8d4
				CreateDisposition = CREATE_NEW;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case FILE_OPEN_IF: /* If the file already exists, open it. If it does not, create the given file. */
Packit 1fb8d4
				CreateDisposition = OPEN_ALWAYS;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case FILE_OVERWRITE: /* If the file already exists, open it and overwrite it. If it does not, fail the request. */
Packit 1fb8d4
				CreateDisposition = TRUNCATE_EXISTING;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case FILE_OVERWRITE_IF: /* If the file already exists, open it and overwrite it. If it does not, create the given file. */
Packit 1fb8d4
				CreateDisposition = CREATE_ALWAYS;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			default:
Packit 1fb8d4
				break;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
#ifndef WIN32
Packit 1fb8d4
		file->SharedAccess = 0;
Packit 1fb8d4
#endif
Packit 1fb8d4
		file->file_handle = CreateFileW(file->fullpath, file->DesiredAccess,
Packit 1fb8d4
		                                file->SharedAccess, NULL, CreateDisposition,
Packit 1fb8d4
		                                file->FileAttributes, NULL);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (file->file_handle == INVALID_HANDLE_VALUE)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* Get the error message, if any. */
Packit 1fb8d4
		DWORD errorMessageID = GetLastError();
Packit 1fb8d4
Packit 1fb8d4
		if (errorMessageID != 0)
Packit 1fb8d4
		{
Packit 1fb8d4
#ifdef WIN32
Packit 1fb8d4
			LPSTR messageBuffer = NULL;
Packit 1fb8d4
			size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
Packit 1fb8d4
			                             FORMAT_MESSAGE_IGNORE_INSERTS,
Packit 1fb8d4
			                             NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
Packit 1fb8d4
			WLog_ERR(TAG, "Error in drive_file_init: %s %s", messageBuffer, file->fullpath);
Packit 1fb8d4
			/* Free the buffer. */
Packit 1fb8d4
			LocalFree(messageBuffer);
Packit 1fb8d4
#endif
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return file->file_handle != INVALID_HANDLE_VALUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathLength, UINT32 id,
Packit 1fb8d4
                           UINT32 DesiredAccess, UINT32 CreateDisposition,
Packit 1fb8d4
                           UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess)
Packit 1fb8d4
{
Packit 1fb8d4
	DRIVE_FILE* file;
Packit 1fb8d4
Packit 1fb8d4
	if (!base_path || !path)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	file = (DRIVE_FILE*) calloc(1, sizeof(DRIVE_FILE));
Packit 1fb8d4
Packit 1fb8d4
	if (!file)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "calloc failed!");
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	file->file_handle = INVALID_HANDLE_VALUE;
Packit 1fb8d4
	file->find_handle = INVALID_HANDLE_VALUE;
Packit 1fb8d4
	file->id = id;
Packit 1fb8d4
	file->basepath = (WCHAR*) base_path;
Packit 1fb8d4
	file->FileAttributes = FileAttributes;
Packit 1fb8d4
	file->DesiredAccess = DesiredAccess;
Packit 1fb8d4
	file->CreateDisposition = CreateDisposition;
Packit 1fb8d4
	file->CreateOptions = CreateOptions;
Packit 1fb8d4
	file->SharedAccess = SharedAccess;
Packit 1fb8d4
	drive_file_set_fullpath(file, drive_file_combine_fullpath(base_path, path, PathLength));
Packit 1fb8d4
Packit 1fb8d4
	if (!drive_file_init(file))
Packit 1fb8d4
	{
Packit 1fb8d4
		drive_file_free(file);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return file;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL drive_file_free(DRIVE_FILE* file)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL rc = FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!file)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (file->file_handle != INVALID_HANDLE_VALUE)
Packit 1fb8d4
	{
Packit 1fb8d4
		CloseHandle(file->file_handle);
Packit 1fb8d4
		file->file_handle = INVALID_HANDLE_VALUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (file->find_handle != INVALID_HANDLE_VALUE)
Packit 1fb8d4
	{
Packit 1fb8d4
		FindClose(file->find_handle);
Packit 1fb8d4
		file->find_handle = INVALID_HANDLE_VALUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (file->delete_pending)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (file->is_dir)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!drive_file_remove_dir(file->fullpath))
Packit 1fb8d4
				goto fail;
Packit 1fb8d4
		}
Packit 1fb8d4
		else if (!DeleteFileW(file->fullpath))
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	rc = TRUE;
Packit 1fb8d4
fail:
Packit 1fb8d4
	DEBUG_WSTR("Free %s", file->fullpath);
Packit 1fb8d4
	free(file->fullpath);
Packit 1fb8d4
	free(file);
Packit 1fb8d4
	return rc;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL drive_file_seek(DRIVE_FILE* file, UINT64 Offset)
Packit 1fb8d4
{
Packit 1fb8d4
	LARGE_INTEGER loffset;
Packit 1fb8d4
Packit 1fb8d4
	if (!file)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	loffset.QuadPart = Offset;
Packit 1fb8d4
	return SetFilePointerEx(file->file_handle, loffset, NULL, FILE_BEGIN);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL drive_file_read(DRIVE_FILE* file, BYTE* buffer, UINT32* Length)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 read;
Packit 1fb8d4
Packit 1fb8d4
	if (!file || !buffer || !Length)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	DEBUG_WSTR("Read file %s", file->fullpath);
Packit 1fb8d4
Packit 1fb8d4
	if (ReadFile(file->file_handle, buffer, *Length, &read, NULL))
Packit 1fb8d4
	{
Packit 1fb8d4
		*Length = read;
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL drive_file_write(DRIVE_FILE* file, BYTE* buffer, UINT32 Length)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 written;
Packit 1fb8d4
Packit 1fb8d4
	if (!file || !buffer)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	DEBUG_WSTR("Write file %s", file->fullpath);
Packit 1fb8d4
Packit 1fb8d4
	while (Length > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!WriteFile(file->file_handle, buffer, Length, &written, NULL))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		Length -= written;
Packit 1fb8d4
		buffer += written;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, wStream* output)
Packit 1fb8d4
{
Packit 1fb8d4
	WIN32_FILE_ATTRIBUTE_DATA fileAttributes;
Packit 1fb8d4
	DEBUG_WSTR("FindFirstFile %s", file->fullpath);
Packit 1fb8d4
Packit 1fb8d4
	if (!file || !output)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!GetFileAttributesExW(file->fullpath, GetFileExInfoStandard, &fileAttributes))
Packit 1fb8d4
		goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
	switch (FsInformationClass)
Packit 1fb8d4
	{
Packit 1fb8d4
		case FileBasicInformation:
Packit 1fb8d4
Packit 1fb8d4
			/* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
Packit 1fb8d4
			if (!Stream_EnsureRemainingCapacity(output, 4 + 36))
Packit 1fb8d4
				goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
			Stream_Write_UINT32(output, 36); /* Length */
Packit 1fb8d4
			Stream_Write_UINT32(output, fileAttributes.ftCreationTime.dwLowDateTime); /* CreationTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, fileAttributes.ftCreationTime.dwHighDateTime); /* CreationTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, fileAttributes.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, fileAttributes.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, fileAttributes.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, fileAttributes.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, fileAttributes.ftLastWriteTime.dwLowDateTime); /* ChangeTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, fileAttributes.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, fileAttributes.dwFileAttributes); /* FileAttributes */
Packit 1fb8d4
			/* Reserved(4), MUST NOT be added! */
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case FileStandardInformation:
Packit 1fb8d4
Packit 1fb8d4
			/*  http://msdn.microsoft.com/en-us/library/cc232088.aspx */
Packit 1fb8d4
			if (!Stream_EnsureRemainingCapacity(output, 4 + 22))
Packit 1fb8d4
				goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
			Stream_Write_UINT32(output, 22); /* Length */
Packit 1fb8d4
			Stream_Write_UINT32(output, fileAttributes.nFileSizeLow); /* AllocationSize */
Packit 1fb8d4
			Stream_Write_UINT32(output, fileAttributes.nFileSizeHigh); /* AllocationSize */
Packit 1fb8d4
			Stream_Write_UINT32(output, fileAttributes.nFileSizeLow); /* EndOfFile */
Packit 1fb8d4
			Stream_Write_UINT32(output, fileAttributes.nFileSizeHigh); /* EndOfFile */
Packit 1fb8d4
			Stream_Write_UINT32(output, 0); /* NumberOfLinks */
Packit 1fb8d4
			Stream_Write_UINT8(output, file->delete_pending ? 1 : 0); /* DeletePending */
Packit 1fb8d4
			Stream_Write_UINT8(output, fileAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? TRUE :
Packit 1fb8d4
			                   FALSE); /* Directory */
Packit 1fb8d4
			/* Reserved(2), MUST NOT be added! */
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case FileAttributeTagInformation:
Packit 1fb8d4
Packit 1fb8d4
			/* http://msdn.microsoft.com/en-us/library/cc232093.aspx */
Packit 1fb8d4
			if (!Stream_EnsureRemainingCapacity(output, 4 + 8))
Packit 1fb8d4
				goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
			Stream_Write_UINT32(output, 8); /* Length */
Packit 1fb8d4
			Stream_Write_UINT32(output, fileAttributes.dwFileAttributes); /* FileAttributes */
Packit 1fb8d4
			Stream_Write_UINT32(output, 0); /* ReparseTag */
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			/* Unhandled FsInformationClass */
Packit 1fb8d4
			goto out_fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
out_fail:
Packit 1fb8d4
	Stream_Write_UINT32(output, 0); /* Length */
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length,
Packit 1fb8d4
                                wStream* input)
Packit 1fb8d4
{
Packit 1fb8d4
	INT64 size;
Packit 1fb8d4
	WCHAR* fullpath;
Packit 1fb8d4
	ULARGE_INTEGER liCreationTime;
Packit 1fb8d4
	ULARGE_INTEGER liLastAccessTime;
Packit 1fb8d4
	ULARGE_INTEGER liLastWriteTime;
Packit 1fb8d4
	ULARGE_INTEGER liChangeTime;
Packit 1fb8d4
	FILETIME ftCreationTime;
Packit 1fb8d4
	FILETIME ftLastAccessTime;
Packit 1fb8d4
	FILETIME ftLastWriteTime;
Packit 1fb8d4
	FILETIME* pftCreationTime = NULL;
Packit 1fb8d4
	FILETIME* pftLastAccessTime = NULL;
Packit 1fb8d4
	FILETIME* pftLastWriteTime = NULL;
Packit 1fb8d4
	UINT32 FileAttributes;
Packit 1fb8d4
	UINT32 FileNameLength;
Packit 1fb8d4
	LARGE_INTEGER liSize;
Packit 1fb8d4
	UINT8 delete_pending;
Packit 1fb8d4
	UINT8 ReplaceIfExists;
Packit 1fb8d4
	DWORD attr;
Packit 1fb8d4
Packit 1fb8d4
	if (!file || !input)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	switch (FsInformationClass)
Packit 1fb8d4
	{
Packit 1fb8d4
		case FileBasicInformation:
Packit 1fb8d4
			if (Stream_GetRemainingLength(input) < 36)
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			/* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
Packit 1fb8d4
			Stream_Read_UINT64(input, liCreationTime.QuadPart);
Packit 1fb8d4
			Stream_Read_UINT64(input, liLastAccessTime.QuadPart);
Packit 1fb8d4
			Stream_Read_UINT64(input, liLastWriteTime.QuadPart);
Packit 1fb8d4
			Stream_Read_UINT64(input, liChangeTime.QuadPart);
Packit 1fb8d4
			Stream_Read_UINT32(input, FileAttributes);
Packit 1fb8d4
Packit 1fb8d4
			if (!PathFileExistsW(file->fullpath))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			if (file->file_handle == INVALID_HANDLE_VALUE)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "Unable to set file time %s (%"PRId32")", file->fullpath, GetLastError());
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (liCreationTime.QuadPart != 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				ftCreationTime.dwHighDateTime = liCreationTime.HighPart;
Packit 1fb8d4
				ftCreationTime.dwLowDateTime = liCreationTime.LowPart;
Packit 1fb8d4
				pftCreationTime = &ftCreationTime;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (liLastAccessTime.QuadPart != 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				ftLastAccessTime.dwHighDateTime = liLastAccessTime.HighPart;
Packit 1fb8d4
				ftLastAccessTime.dwLowDateTime = liLastAccessTime.LowPart;
Packit 1fb8d4
				pftLastAccessTime = &ftLastAccessTime;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (liLastWriteTime.QuadPart != 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				ftLastWriteTime.dwHighDateTime = liLastWriteTime.HighPart;
Packit 1fb8d4
				ftLastWriteTime.dwLowDateTime = liLastWriteTime.LowPart;
Packit 1fb8d4
				pftLastWriteTime = &ftLastWriteTime;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (liChangeTime.QuadPart != 0 && liChangeTime.QuadPart > liLastWriteTime.QuadPart)
Packit 1fb8d4
			{
Packit 1fb8d4
				ftLastWriteTime.dwHighDateTime = liChangeTime.HighPart;
Packit 1fb8d4
				ftLastWriteTime.dwLowDateTime = liChangeTime.LowPart;
Packit 1fb8d4
				pftLastWriteTime = &ftLastWriteTime;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			DEBUG_WSTR("SetFileTime %s", file->fullpath);
Packit 1fb8d4
Packit 1fb8d4
			if (!SetFileTime(file->file_handle, pftCreationTime, pftLastAccessTime, pftLastWriteTime))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "Unable to set file time to %s", file->fullpath);
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			SetFileAttributesW(file->fullpath, FileAttributes);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case FileEndOfFileInformation:
Packit 1fb8d4
Packit 1fb8d4
		/* http://msdn.microsoft.com/en-us/library/cc232067.aspx */
Packit 1fb8d4
		case FileAllocationInformation:
Packit 1fb8d4
			if (Stream_GetRemainingLength(input) < 8)
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			/* http://msdn.microsoft.com/en-us/library/cc232076.aspx */
Packit 1fb8d4
			Stream_Read_INT64(input, size);
Packit 1fb8d4
Packit 1fb8d4
			if (file->file_handle == INVALID_HANDLE_VALUE)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "Unable to truncate %s to %"PRId64" (%"PRId32")", file->fullpath, size,
Packit 1fb8d4
				         GetLastError());
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (!SetFilePointerEx(file->file_handle, liSize, NULL, FILE_BEGIN))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "Unable to truncate %s to %d (%"PRId32")", file->fullpath, size, GetLastError());
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			DEBUG_WSTR("Truncate %s", file->fullpath);
Packit 1fb8d4
Packit 1fb8d4
			if (SetEndOfFile(file->file_handle) == 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "Unable to truncate %s to %d (%"PRId32")", file->fullpath, size, GetLastError());
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case FileDispositionInformation:
Packit 1fb8d4
Packit 1fb8d4
			/* http://msdn.microsoft.com/en-us/library/cc232098.aspx */
Packit 1fb8d4
			/* http://msdn.microsoft.com/en-us/library/cc241371.aspx */
Packit 1fb8d4
			if (file->is_dir && !PathIsDirectoryEmptyW(file->fullpath))
Packit 1fb8d4
				break; /* TODO: SetLastError ??? */
Packit 1fb8d4
Packit 1fb8d4
			if (Length)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (Stream_GetRemainingLength(input) < 1)
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
Packit 1fb8d4
				Stream_Read_UINT8(input, delete_pending);
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
				delete_pending = 1;
Packit 1fb8d4
Packit 1fb8d4
			if (delete_pending)
Packit 1fb8d4
			{
Packit 1fb8d4
				DEBUG_WSTR("SetDeletePending %s", file->fullpath);
Packit 1fb8d4
				attr = GetFileAttributesW(file->fullpath);
Packit 1fb8d4
Packit 1fb8d4
				if (attr & FILE_ATTRIBUTE_READONLY)
Packit 1fb8d4
				{
Packit 1fb8d4
					SetLastError(ERROR_ACCESS_DENIED);
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			file->delete_pending = delete_pending;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case FileRenameInformation:
Packit 1fb8d4
			if (Stream_GetRemainingLength(input) < 6)
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			/* http://msdn.microsoft.com/en-us/library/cc232085.aspx */
Packit 1fb8d4
			Stream_Read_UINT8(input, ReplaceIfExists);
Packit 1fb8d4
			Stream_Seek_UINT8(input); /* RootDirectory */
Packit 1fb8d4
			Stream_Read_UINT32(input, FileNameLength);
Packit 1fb8d4
Packit 1fb8d4
			if (Stream_GetRemainingLength(input) < FileNameLength)
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			fullpath = drive_file_combine_fullpath(file->basepath, (WCHAR*)Stream_Pointer(input),
Packit 1fb8d4
			                                       FileNameLength);
Packit 1fb8d4
Packit 1fb8d4
			if (!fullpath)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "drive_file_combine_fullpath failed!");
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
#ifdef _WIN32
Packit 1fb8d4
Packit 1fb8d4
			if (file->file_handle != INVALID_HANDLE_VALUE)
Packit 1fb8d4
			{
Packit 1fb8d4
				CloseHandle(file->file_handle);
Packit 1fb8d4
				file->file_handle = INVALID_HANDLE_VALUE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
			DEBUG_WSTR("MoveFileExW %s", file->fullpath);
Packit 1fb8d4
Packit 1fb8d4
			if (MoveFileExW(file->fullpath, fullpath,
Packit 1fb8d4
			                MOVEFILE_COPY_ALLOWED | (ReplaceIfExists ? MOVEFILE_REPLACE_EXISTING : 0)))
Packit 1fb8d4
			{
Packit 1fb8d4
				if (!drive_file_set_fullpath(file, fullpath))
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				free(fullpath);
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
#ifdef _WIN32
Packit 1fb8d4
			drive_file_init(file);
Packit 1fb8d4
#endif
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery,
Packit 1fb8d4
                                const WCHAR* path, UINT32 PathLength, wStream* output)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	WCHAR* ent_path;
Packit 1fb8d4
Packit 1fb8d4
	if (!file || !path || !output)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (InitialQuery != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* release search handle */
Packit 1fb8d4
		if (file->find_handle != INVALID_HANDLE_VALUE)
Packit 1fb8d4
			FindClose(file->find_handle);
Packit 1fb8d4
Packit 1fb8d4
		ent_path = drive_file_combine_fullpath(file->basepath, path, PathLength);
Packit 1fb8d4
		/* open new search handle and retrieve the first entry */
Packit 1fb8d4
		file->find_handle = FindFirstFileW(ent_path, &file->find_data);
Packit 1fb8d4
		free(ent_path);
Packit 1fb8d4
Packit 1fb8d4
		if (file->find_handle == INVALID_HANDLE_VALUE)
Packit 1fb8d4
			goto out_fail;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (!FindNextFileW(file->find_handle, &file->find_data))
Packit 1fb8d4
		goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
	length = _wcslen(file->find_data.cFileName) * 2;
Packit 1fb8d4
Packit 1fb8d4
	switch (FsInformationClass)
Packit 1fb8d4
	{
Packit 1fb8d4
		case FileDirectoryInformation:
Packit 1fb8d4
Packit 1fb8d4
			/* http://msdn.microsoft.com/en-us/library/cc232097.aspx */
Packit 1fb8d4
			if (!Stream_EnsureRemainingCapacity(output, 4 + 64 + length))
Packit 1fb8d4
				goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
			Stream_Write_UINT32(output, 64 + length); /* Length */
Packit 1fb8d4
			Stream_Write_UINT32(output, 0); /* NextEntryOffset */
Packit 1fb8d4
			Stream_Write_UINT32(output, 0); /* FileIndex */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* EndOfFile */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* EndOfFile */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */
Packit 1fb8d4
			Stream_Write_UINT32(output, length); /* FileNameLength */
Packit 1fb8d4
			Stream_Write(output, file->find_data.cFileName, length);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case FileFullDirectoryInformation:
Packit 1fb8d4
Packit 1fb8d4
			/* http://msdn.microsoft.com/en-us/library/cc232068.aspx */
Packit 1fb8d4
			if (!Stream_EnsureRemainingCapacity(output, 4 + 68 + length))
Packit 1fb8d4
				goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
			Stream_Write_UINT32(output, 68 + length); /* Length */
Packit 1fb8d4
			Stream_Write_UINT32(output, 0); /* NextEntryOffset */
Packit 1fb8d4
			Stream_Write_UINT32(output, 0); /* FileIndex */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* EndOfFile */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* EndOfFile */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */
Packit 1fb8d4
			Stream_Write_UINT32(output, length); /* FileNameLength */
Packit 1fb8d4
			Stream_Write_UINT32(output, 0); /* EaSize */
Packit 1fb8d4
			Stream_Write(output, file->find_data.cFileName, length);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case FileBothDirectoryInformation:
Packit 1fb8d4
Packit 1fb8d4
			/* http://msdn.microsoft.com/en-us/library/cc232095.aspx */
Packit 1fb8d4
			if (!Stream_EnsureRemainingCapacity(output, 4 + 93 + length))
Packit 1fb8d4
				goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
			Stream_Write_UINT32(output, 93 + length); /* Length */
Packit 1fb8d4
			Stream_Write_UINT32(output, 0); /* NextEntryOffset */
Packit 1fb8d4
			Stream_Write_UINT32(output, 0); /* FileIndex */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* EndOfFile */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* EndOfFile */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */
Packit 1fb8d4
			Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */
Packit 1fb8d4
			Stream_Write_UINT32(output, length); /* FileNameLength */
Packit 1fb8d4
			Stream_Write_UINT32(output, 0); /* EaSize */
Packit 1fb8d4
			Stream_Write_UINT8(output, 0); /* ShortNameLength */
Packit 1fb8d4
			/* Reserved(1), MUST NOT be added! */
Packit 1fb8d4
			Stream_Zero(output, 24); /* ShortName */
Packit 1fb8d4
			Stream_Write(output, file->find_data.cFileName, length);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case FileNamesInformation:
Packit 1fb8d4
Packit 1fb8d4
			/* http://msdn.microsoft.com/en-us/library/cc232077.aspx */
Packit 1fb8d4
			if (!Stream_EnsureRemainingCapacity(output, 4 + 12 + length))
Packit 1fb8d4
				goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
			Stream_Write_UINT32(output, 12 + length); /* Length */
Packit 1fb8d4
			Stream_Write_UINT32(output, 0); /* NextEntryOffset */
Packit 1fb8d4
			Stream_Write_UINT32(output, 0); /* FileIndex */
Packit 1fb8d4
			Stream_Write_UINT32(output, length); /* FileNameLength */
Packit 1fb8d4
			Stream_Write(output, file->find_data.cFileName, length);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			/* Unhandled FsInformationClass */
Packit 1fb8d4
			goto out_fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
out_fail:
Packit 1fb8d4
	Stream_Write_UINT32(output, 0); /* Length */
Packit 1fb8d4
	Stream_Write_UINT8(output, 0); /* Padding */
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}