Esempio n. 1
0
static UINT video_data_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *s)
{
	VIDEO_CHANNEL_CALLBACK* callback = (VIDEO_CHANNEL_CALLBACK*) pChannelCallback;
	VIDEO_PLUGIN* video;
	VideoClientContext *context;
	UINT32 cbSize, packetType;
	TSMM_VIDEO_DATA data;

	video = (VIDEO_PLUGIN*) callback->plugin;
	context = (VideoClientContext *)video->wtsPlugin.pInterface;

	if (Stream_GetRemainingLength(s) < 4)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(s, cbSize);
	if (cbSize < 8 || Stream_GetRemainingLength(s) < (cbSize-4))
	{
		WLog_ERR(TAG, "invalid cbSize");
		return ERROR_INVALID_DATA;
	}

	Stream_Read_UINT32(s, packetType);
	if (packetType != TSMM_PACKET_TYPE_VIDEO_DATA)
	{
		WLog_ERR(TAG, "only expecting VIDEO_DATA on the data channel");
		return ERROR_INVALID_DATA;
	}

	if (Stream_GetRemainingLength(s) < 32)
	{
		WLog_ERR(TAG, "not enough bytes for a TSMM_VIDEO_DATA");
		return ERROR_INVALID_DATA;
	}

	Stream_Read_UINT8(s, data.PresentationId);
	Stream_Read_UINT8(s, data.Version);
	Stream_Read_UINT8(s, data.Flags);
	Stream_Seek_UINT8(s); /* reserved */
	Stream_Read_UINT64(s, data.hnsTimestamp);
	Stream_Read_UINT64(s, data.hnsDuration);
	Stream_Read_UINT16(s, data.CurrentPacketIndex);
	Stream_Read_UINT16(s, data.PacketsInSample);
	Stream_Read_UINT32(s, data.SampleNumber);
	Stream_Read_UINT32(s, data.cbSample);
	data.pSample = Stream_Pointer(s);

/*
	WLog_DBG(TAG, "videoData: id:%"PRIu8" version:%"PRIu8" flags:0x%"PRIx8" timestamp=%"PRIu64" duration=%"PRIu64
			" curPacketIndex:%"PRIu16" packetInSample:%"PRIu16" sampleNumber:%"PRIu32" cbSample:%"PRIu32"",
			data.PresentationId, data.Version, data.Flags, data.hnsTimestamp, data.hnsDuration,
			data.CurrentPacketIndex, data.PacketsInSample, data.SampleNumber, data.cbSample);
*/

	return video_VideoData(context, &data);
}
Esempio n. 2
0
int tsmf_ifman_on_sample(TSMF_IFMAN* ifman)
{
	TSMF_PRESENTATION* presentation;
	TSMF_STREAM* stream;
	UINT32 StreamId;
	UINT64 SampleStartTime;
	UINT64 SampleEndTime;
	UINT64 ThrottleDuration;
	UINT32 SampleExtensions;
	UINT32 cbData;

	Stream_Seek(ifman->input, 16);
	Stream_Read_UINT32(ifman->input, StreamId);
	Stream_Seek_UINT32(ifman->input); /* numSample */
	Stream_Read_UINT64(ifman->input, SampleStartTime);
	Stream_Read_UINT64(ifman->input, SampleEndTime);
	Stream_Read_UINT64(ifman->input, ThrottleDuration);
	Stream_Seek_UINT32(ifman->input); /* SampleFlags */
	Stream_Read_UINT32(ifman->input, SampleExtensions);
	Stream_Read_UINT32(ifman->input, cbData);
	
	DEBUG_DVC("MessageId %d StreamId %d SampleStartTime %d SampleEndTime %d "
		"ThrottleDuration %d SampleExtensions %d cbData %d",
		ifman->message_id, StreamId, (int)SampleStartTime, (int)SampleEndTime,
		(int)ThrottleDuration, SampleExtensions, cbData);

	presentation = tsmf_presentation_find_by_id(ifman->presentation_id);

	if (presentation == NULL)
	{
		DEBUG_WARN("unknown presentation id");
		return 1;
	}

	stream = tsmf_stream_find_by_id(presentation, StreamId);

	if (stream == NULL)
	{
		DEBUG_WARN("unknown stream id");
		return 1;
	}

	tsmf_stream_push_sample(stream, ifman->channel_callback,
		ifman->message_id, SampleStartTime, SampleEndTime, ThrottleDuration, SampleExtensions,
		cbData, Stream_Pointer(ifman->input));

	ifman->output_pending = TRUE;

	return 0;
}
Esempio n. 3
0
/* http://msdn.microsoft.com/en-us/library/dd390700.aspx */
static UINT32 tsmf_codec_parse_VIDEOINFOHEADER(TS_AM_MEDIA_TYPE* mediatype, wStream* s)
{
    /*
    typedef struct tagVIDEOINFOHEADER {
      RECT             rcSource;			//16
      RECT             rcTarget;			//16	32
      DWORD            dwBitRate;			//4	36
      DWORD            dwBitErrorRate;		//4	40
      REFERENCE_TIME   AvgTimePerFrame;		//8	48
      BITMAPINFOHEADER bmiHeader;
    } VIDEOINFOHEADER;
    */
    UINT64 AvgTimePerFrame;

    /* VIDEOINFOHEADER.rcSource, RECT(LONG left, LONG top, LONG right, LONG bottom) */
    Stream_Seek_UINT32(s);
    Stream_Seek_UINT32(s);
    Stream_Read_UINT32(s, mediatype->Width);
    Stream_Read_UINT32(s, mediatype->Height);
    /* VIDEOINFOHEADER.rcTarget */
    Stream_Seek(s, 16);
    /* VIDEOINFOHEADER.dwBitRate */
    Stream_Read_UINT32(s, mediatype->BitRate);
    /* VIDEOINFOHEADER.dwBitErrorRate */
    Stream_Seek_UINT32(s);
    /* VIDEOINFOHEADER.AvgTimePerFrame */
    Stream_Read_UINT64(s, AvgTimePerFrame);
    mediatype->SamplesPerSecond.Numerator = 1000000;
    mediatype->SamplesPerSecond.Denominator = (int)(AvgTimePerFrame / 10LL);

    return 48;
}
Esempio n. 4
0
int rdpgfx_recv_surface_to_cache_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
{
	RDPGFX_SURFACE_TO_CACHE_PDU pdu;
	RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
	RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;

	if (Stream_GetRemainingLength(s) < 20)
		return -1;

	Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
	Stream_Read_UINT64(s, pdu.cacheKey); /* cacheKey (8 bytes) */
	Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */
	rdpgfx_read_rect16(s, &(pdu.rectSrc)); /* rectSrc (8 bytes ) */

	WLog_Print(gfx->log, WLOG_DEBUG, "RecvSurfaceToCachePdu: surfaceId: %d cacheKey: 0x%08X cacheSlot: %d "
			"left: %d top: %d right: %d bottom: %d",
			pdu.surfaceId, (int) pdu.cacheKey, pdu.cacheSlot,
			pdu.rectSrc.left, pdu.rectSrc.top,
			pdu.rectSrc.right, pdu.rectSrc.bottom);

	if (context && context->SurfaceToCache)
	{
		context->SurfaceToCache(context, &pdu);
	}

	return 1;
}
Esempio n. 5
0
/**
 * Function description
 *
 * @return 0 on success, otherwise a Win32 error code
 */
static UINT serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
{
	UINT32 Length;
	UINT64 Offset;
	BYTE* buffer = NULL;
	DWORD nbRead = 0;

	if (Stream_GetRemainingLength(irp->input) < 32)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
	Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
	Stream_Seek(irp->input, 20); /* Padding (20 bytes) */

	buffer = (BYTE*)calloc(Length, sizeof(BYTE));
	if (buffer == NULL)
	{
		irp->IoStatus = STATUS_NO_MEMORY;
		goto error_handle;
	}

	/* MS-RDPESP 3.2.5.1.4: If the Offset field is not set to 0, the value MUST be ignored
	 * assert(Offset == 0);
	 */
	WLog_Print(serial->log, WLOG_DEBUG, "reading %"PRIu32" bytes from %s", Length,
	           serial->device.name);

	/* FIXME: CommReadFile to be replaced by ReadFile */
	if (CommReadFile(serial->hComm, buffer, Length, &nbRead, NULL))
	{
		irp->IoStatus = STATUS_SUCCESS;
	}
	else
	{
		WLog_Print(serial->log, WLOG_DEBUG,
		           "read failure to %s, nbRead=%"PRIu32", last-error: 0x%08"PRIX32"", serial->device.name,
		           nbRead, GetLastError());
		irp->IoStatus = _GetLastErrorToIoStatus(serial);
	}

	WLog_Print(serial->log, WLOG_DEBUG, "%"PRIu32" bytes read from %s", nbRead,
	           serial->device.name);
error_handle:
	Stream_Write_UINT32(irp->output, nbRead); /* Length (4 bytes) */

	if (nbRead > 0)
	{
		if (!Stream_EnsureRemainingCapacity(irp->output, nbRead))
		{
			WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
			free(buffer);
			return CHANNEL_RC_NO_MEMORY;
		}

		Stream_Write(irp->output, buffer, nbRead); /* ReadData */
	}

	free(buffer);
	return CHANNEL_RC_OK;
}
void guac_rdpdr_fs_process_set_end_of_file_info(guac_rdpdr_device* device,
        wStream* input_stream, int file_id, int completion_id, int length) {

    int result;
    UINT64 size;
    wStream* output_stream;

    /* Read new size */
    Stream_Read_UINT64(input_stream, size); /* AllocationSize */

    GUAC_RDP_DEBUG(2, "[file_id=%i] size=%" PRIu64, file_id, (uint64_t) size);

    /* Truncate file */
    result = guac_rdp_fs_truncate((guac_rdp_fs*) device->data, file_id, size);
    if (result < 0)
        output_stream = guac_rdpdr_new_io_completion(device,
                completion_id, guac_rdp_fs_get_status(result), 4);
    else
        output_stream = guac_rdpdr_new_io_completion(device,
                completion_id, STATUS_SUCCESS, 4);

    Stream_Write_UINT32(output_stream, length);
    svc_plugin_send((rdpSvcPlugin*) device->rdpdr, output_stream);

}
Esempio n. 7
0
/**
 * Function description
 *
 * @return 0 on success, otherwise a Win32 error code
 */
static UINT rdpgfx_recv_map_surface_to_window_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
        wStream* s)
{
	RDPGFX_MAP_SURFACE_TO_WINDOW_PDU pdu;
	RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
	RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
	UINT error = CHANNEL_RC_OK;

	if (Stream_GetRemainingLength(s) < 18)
	{
		WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
		return ERROR_INVALID_DATA;
	}

	Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
	Stream_Read_UINT64(s, pdu.windowId); /* windowId (8 bytes) */
	Stream_Read_UINT32(s, pdu.mappedWidth); /* mappedWidth (4 bytes) */
	Stream_Read_UINT32(s, pdu.mappedHeight); /* mappedHeight (4 bytes) */
	WLog_Print(gfx->log, WLOG_DEBUG,
	         "RecvMapSurfaceToWindowPdu: surfaceId: %"PRIu16" windowId: 0x%016"PRIX64" mappedWidth: %"PRIu32" mappedHeight: %"PRIu32"",
	         pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight);

	if (context && context->MapSurfaceToWindow)
	{
		IFCALLRET(context->MapSurfaceToWindow, error, context, &pdu);

		if (error)
			WLog_Print(gfx->log, WLOG_ERROR, "context->MapSurfaceToWindow failed with error %"PRIu32"", error);
	}

	return error;
}
Esempio n. 8
0
/**
 * Function description
 *
 * @return 0 on success, otherwise a Win32 error code
 */
static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp)
{
	DRIVE_FILE* file;
	UINT32 Length;
	UINT64 Offset;
	Stream_Read_UINT32(irp->input, Length);
	Stream_Read_UINT64(irp->input, Offset);
	Stream_Seek(irp->input, 20); /* Padding */
	file = drive_get_file_by_id(drive, irp->FileId);

	if (!file)
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		Length = 0;
	}
	else if (!drive_file_seek(file, Offset))
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		Length = 0;
	}
	else if (!drive_file_write(file, Stream_Pointer(irp->input), Length))
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		Length = 0;
	}

	Stream_Write_UINT32(irp->output, Length);
	Stream_Write_UINT8(irp->output, 0); /* Padding */
	return irp->Complete(irp);
}
Esempio n. 9
0
/**
 * Function description
 *
 * @return 0 on success, otherwise a Win32 error code
 */
static UINT printer_process_irp_write(PRINTER_DEVICE* printer_dev, IRP* irp)
{
	UINT32 Length;
	UINT64 Offset;
	rdpPrintJob* printjob = NULL;
	UINT error = CHANNEL_RC_OK;
	Stream_Read_UINT32(irp->input, Length);
	Stream_Read_UINT64(irp->input, Offset);
	Stream_Seek(irp->input, 20); /* Padding */

	if (printer_dev->printer)
		printjob = printer_dev->printer->FindPrintJob(printer_dev->printer,
		           irp->FileId);

	if (!printjob)
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		Length = 0;
	}
	else
	{
		error = printjob->Write(printjob, Stream_Pointer(irp->input), Length);
	}

	if (error)
	{
		WLog_ERR(TAG, "printjob->Write failed with error %lu!", error);
		return error;
	}

	Stream_Write_UINT32(irp->output, Length);
	Stream_Write_UINT8(irp->output, 0); /* Padding */
	return irp->Complete(irp);
}
Esempio n. 10
0
/**
 * Function description
 *
 * @return 0 on success, otherwise a Win32 error code
 */
static UINT parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
{
	UINT32 len;
	UINT32 Length;
	UINT64 Offset;
	ssize_t status;

	Stream_Read_UINT32(irp->input, Length);
	Stream_Read_UINT64(irp->input, Offset);
	Stream_Seek(irp->input, 20); /* Padding */

	len = Length;

	while (len > 0)
	{
		status = write(parallel->file, Stream_Pointer(irp->input), len);

		if (status < 0)
		{
			irp->IoStatus = STATUS_UNSUCCESSFUL;
			Length = 0;
			break;
		}

		Stream_Seek(irp->input, status);
		len -= status;
	}

	Stream_Write_UINT32(irp->output, Length);
	Stream_Write_UINT8(irp->output, 0); /* Padding */

	return irp->Complete(irp);
}
Esempio n. 11
0
/**
 * Function description
 *
 * @return 0 on success, otherwise a Win32 error code
 */
static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context,
        wStream* s)
{
	UINT16 index;
	RDPGFX_CACHE_IMPORT_OFFER_PDU pdu;
	RDPGFX_CACHE_ENTRY_METADATA* cacheEntries;
	UINT error = CHANNEL_RC_OK;

	if (Stream_GetRemainingLength(s) < 2)
	{
		WLog_ERR(TAG, "not enough data!");
		return ERROR_INVALID_DATA;
	}

	/* cacheEntriesCount (2 bytes) */
	Stream_Read_UINT16(s, pdu.cacheEntriesCount);

	if (pdu.cacheEntriesCount <= 0)
	{
		/* According to the latest spec, capsSetCount <= 3 */
		WLog_ERR(TAG, "Invalid cacheEntriesCount: %u", pdu.cacheEntriesCount);
		return ERROR_INVALID_DATA;
	}

	if (Stream_GetRemainingLength(s) < (pdu.cacheEntriesCount * 12))
	{
		WLog_ERR(TAG, "not enough data!");
		return ERROR_INVALID_DATA;
	}

	pdu.cacheEntries = (RDPGFX_CACHE_ENTRY_METADATA*)
	                   calloc(pdu.cacheEntriesCount,
	                          sizeof(RDPGFX_CACHE_ENTRY_METADATA));

	if (!pdu.cacheEntries)
	{
		WLog_ERR(TAG, "calloc failed!");
		return CHANNEL_RC_NO_MEMORY;
	}

	for (index = 0; index < pdu.cacheEntriesCount; index++)
	{
		cacheEntries = &(pdu.cacheEntries[index]);
		Stream_Read_UINT64(s, cacheEntries->cacheKey); /* cacheKey (8 bytes) */
		/* bitmapLength (4 bytes) */
		Stream_Read_UINT32(s, cacheEntries->bitmapLength);
	}

	if (context)
	{
		IFCALLRET(context->CacheImportOffer, error, context, &pdu);

		if (error)
			WLog_ERR(TAG, "context->CacheImportOffer failed with error %u",
			         error);
	}

	free(pdu.cacheEntries);
	return error;
}
Esempio n. 12
0
static UINT video_read_tsmm_presentation_req(VideoClientContext *context, wStream *s)
{
	TSMM_PRESENTATION_REQUEST req;

	if (Stream_GetRemainingLength(s) < 60)
	{
		WLog_ERR(TAG, "not enough bytes for a TSMM_PRESENTATION_REQUEST");
		return ERROR_INVALID_DATA;
	}

	Stream_Read_UINT8(s, req.PresentationId);
	Stream_Read_UINT8(s, req.Version);
	Stream_Read_UINT8(s, req.Command);
	Stream_Read_UINT8(s, req.FrameRate); /* FrameRate - reserved and ignored */

	Stream_Seek_UINT16(s); /* AverageBitrateKbps reserved and ignored */
	Stream_Seek_UINT16(s); /* reserved */

	Stream_Read_UINT32(s, req.SourceWidth);
	Stream_Read_UINT32(s, req.SourceHeight);
	Stream_Read_UINT32(s, req.ScaledWidth);
	Stream_Read_UINT32(s, req.ScaledHeight);
	Stream_Read_UINT64(s, req.hnsTimestampOffset);
	Stream_Read_UINT64(s, req.GeometryMappingId);
	Stream_Read(s, req.VideoSubtypeId, 16);

	Stream_Read_UINT32(s, req.cbExtra);

	if (Stream_GetRemainingLength(s) < req.cbExtra)
	{
		WLog_ERR(TAG, "not enough bytes for cbExtra of TSMM_PRESENTATION_REQUEST");
		return ERROR_INVALID_DATA;
	}

	req.pExtraData = Stream_Pointer(s);

	WLog_DBG(TAG, "presentationReq: id:%"PRIu8" version:%"PRIu8" command:%s srcWidth/srcHeight=%"PRIu32"x%"PRIu32
			" scaled Width/Height=%"PRIu32"x%"PRIu32" timestamp=%"PRIu64" mappingId=%"PRIx64"",
			req.PresentationId, req.Version, video_command_name(req.Command),
			req.SourceWidth, req.SourceHeight, req.ScaledWidth, req.ScaledHeight,
			req.hnsTimestampOffset, req.GeometryMappingId);

	return video_PresentationRequest(context, &req);
}
Esempio n. 13
0
/**
 * Function description
 *
 * @return 0 on success, otherwise a Win32 error code
 */
static UINT drive_process_irp_read(DRIVE_DEVICE* drive, IRP* irp)
{
	DRIVE_FILE* file;
	UINT32 Length;
	UINT64 Offset;
	BYTE* buffer = NULL;
	Stream_Read_UINT32(irp->input, Length);
	Stream_Read_UINT64(irp->input, Offset);
	file = drive_get_file_by_id(drive, irp->FileId);

	if (!file)
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		Length = 0;
	}
	else if (!drive_file_seek(file, Offset))
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		Length = 0;
	}
	else
	{
		buffer = (BYTE*) malloc(Length);

		if (!buffer)
		{
			WLog_ERR(TAG, "malloc failed!");
			return CHANNEL_RC_OK;
		}

		if (!drive_file_read(file, buffer, &Length))
		{
			irp->IoStatus = STATUS_UNSUCCESSFUL;
			free(buffer);
			buffer = NULL;
			Length = 0;
		}
	}

	Stream_Write_UINT32(irp->output, Length);

	if (Length > 0)
	{
		if (!Stream_EnsureRemainingCapacity(irp->output, (int) Length))
		{
			WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
			return ERROR_INTERNAL_ERROR;
		}

		Stream_Write(irp->output, buffer, Length);
	}

	free(buffer);
	return irp->Complete(irp);
}
Esempio n. 14
0
static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
{
	SERIAL_TTY* tty;
	UINT32 Length;
	UINT64 Offset;
	BYTE* buffer = NULL;

	Stream_Read_UINT32(irp->input, Length);
	Stream_Read_UINT64(irp->input, Offset);

	DEBUG_SVC("length %u offset %llu", Length, Offset);

	tty = serial->tty;

	if (tty == NULL)
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		Length = 0;

		DEBUG_WARN("tty not valid.");
	}
	else
	{
		buffer = (BYTE*) malloc(Length);

		if (!serial_tty_read(tty, buffer, &Length))
		{
			irp->IoStatus = STATUS_UNSUCCESSFUL;
			free(buffer);
			buffer = NULL;
			Length = 0;

			DEBUG_WARN("read %s(%d) failed.", serial->path, tty->id);
		}
		else
		{
			DEBUG_SVC("read %llu-%llu from %d", Offset, Offset + Length, tty->id);
		}
	}

	Stream_Write_UINT32(irp->output, Length);

	if (Length > 0)
	{
		Stream_EnsureRemainingCapacity(irp->output, Length);
		Stream_Write(irp->output, buffer, Length);
	}

	free(buffer);

	irp->Complete(irp);
}
Esempio n. 15
0
static void drive_process_irp_read(DRIVE_DEVICE* drive, IRP* irp)
{
	DRIVE_FILE* file;
	UINT32 Length;
	UINT64 Offset;
	BYTE* buffer = NULL;

	Stream_Read_UINT32(irp->input, Length);
	Stream_Read_UINT64(irp->input, Offset);

	file = drive_get_file_by_id(drive, irp->FileId);

	if (!file)
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		Length = 0;
	}
	else if (!drive_file_seek(file, Offset))
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		Length = 0;
	}
	else
	{
		buffer = (BYTE*) malloc(Length);

		if (!drive_file_read(file, buffer, &Length))
		{
			irp->IoStatus = STATUS_UNSUCCESSFUL;
			free(buffer);
			buffer = NULL;
			Length = 0;
		}
		else
		{

		}
	}

	Stream_Write_UINT32(irp->output, Length);

	if (Length > 0)
	{
		Stream_EnsureRemainingCapacity(irp->output, (int) Length);
		Stream_Write(irp->output, buffer, Length);
	}

	free(buffer);

	irp->Complete(irp);
}
Esempio n. 16
0
void guac_rdpdr_fs_process_read(guac_rdpdr_device* device,
        wStream* input_stream, int file_id, int completion_id) {

    UINT32 length;
    UINT64 offset;
    char* buffer;
    int bytes_read;

    wStream* output_stream;

    /* Read packet */
    Stream_Read_UINT32(input_stream, length);
    Stream_Read_UINT64(input_stream, offset);

    guac_client_log(device->rdpdr->client, GUAC_LOG_DEBUG,
            "%s: [file_id=%i] length=%i, offset=%" PRIu64,
             __func__, file_id, length, (uint64_t) offset);

    /* Ensure buffer size does not exceed a safe maximum */
    if (length > GUAC_RDP_MAX_READ_BUFFER)
        length = GUAC_RDP_MAX_READ_BUFFER;

    /* Allocate buffer */
    buffer = malloc(length);

    /* Attempt read */
    bytes_read = guac_rdp_fs_read((guac_rdp_fs*) device->data, file_id, offset,
            buffer, length);

    /* If error, return invalid parameter */
    if (bytes_read < 0) {
        output_stream = guac_rdpdr_new_io_completion(device, completion_id,
                guac_rdp_fs_get_status(bytes_read), 4);
        Stream_Write_UINT32(output_stream, 0); /* Length */
    }

    /* Otherwise, send bytes read */
    else {
        output_stream = guac_rdpdr_new_io_completion(device, completion_id,
                STATUS_SUCCESS, 4+bytes_read);
        Stream_Write_UINT32(output_stream, bytes_read);  /* Length */
        Stream_Write(output_stream, buffer, bytes_read); /* ReadData */
    }

    svc_plugin_send((rdpSvcPlugin*) device->rdpdr, output_stream);
    free(buffer);

}
Esempio n. 17
0
/**
 * Function description
 *
 * @return 0 on success, otherwise a Win32 error code
 */
static UINT parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp)
{
	UINT32 Length;
	UINT64 Offset;
	ssize_t status;
	BYTE* buffer = NULL;

	Stream_Read_UINT32(irp->input, Length);
	Stream_Read_UINT64(irp->input, Offset);

	buffer = (BYTE*) malloc(Length);
	if (!buffer)
	{
		WLog_ERR(TAG, "malloc failed!");
		return CHANNEL_RC_NO_MEMORY;
	}

	status = read(parallel->file, buffer, Length);

	if (status < 0)
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		free(buffer);
		buffer = NULL;
		Length = 0;
	}
	else
	{

	}

	Stream_Write_UINT32(irp->output, Length);

	if (Length > 0)
	{
		if (!Stream_EnsureRemainingCapacity(irp->output, Length))
		{
			WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
			free(buffer);
			return CHANNEL_RC_NO_MEMORY;
		}
		Stream_Write(irp->output, buffer, Length);
	}

	free(buffer);

	return irp->Complete(irp);
}
Esempio n. 18
0
static UINT serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
{
	UINT32 Length;
	UINT64 Offset;
	DWORD nbWritten = 0;

	if (Stream_GetRemainingLength(irp->input) < 32)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
	Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
	Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
	/* MS-RDPESP 3.2.5.1.5: The Offset field is ignored
	 * assert(Offset == 0);
	 *
	 * Using a serial printer, noticed though this field could be
	 * set.
	 */
	WLog_Print(serial->log, WLOG_DEBUG, "writing %"PRIu32" bytes to %s", Length,
	           serial->device.name);

	/* FIXME: CommWriteFile to be replaced by WriteFile */
	if (CommWriteFile(serial->hComm, Stream_Pointer(irp->input), Length, &nbWritten,
	                  NULL))
	{
		irp->IoStatus = STATUS_SUCCESS;
	}
	else
	{
		WLog_Print(serial->log, WLOG_DEBUG,
		           "write failure to %s, nbWritten=%"PRIu32", last-error: 0x%08"PRIX32"", serial->device.name,
		           nbWritten, GetLastError());
		irp->IoStatus = _GetLastErrorToIoStatus(serial);
	}

	WLog_Print(serial->log, WLOG_DEBUG, "%"PRIu32" bytes written to %s", nbWritten,
	           serial->device.name);
	Stream_Write_UINT32(irp->output, nbWritten); /* Length (4 bytes) */
	Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */

	return CHANNEL_RC_OK;
}
Esempio n. 19
0
/**
 * Function description
 *
 * @return 0 on success, otherwise a Win32 error code
 */
static UINT rdpgfx_recv_surface_to_cache_pdu(RDPGFX_CHANNEL_CALLBACK* callback,
        wStream* s)
{
	RDPGFX_SURFACE_TO_CACHE_PDU pdu;
	RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
	RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
	UINT error;

	if (Stream_GetRemainingLength(s) < 20)
	{
		WLog_Print(gfx->log, WLOG_ERROR, "not enough data!");
		return ERROR_INVALID_DATA;
	}

	Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
	Stream_Read_UINT64(s, pdu.cacheKey); /* cacheKey (8 bytes) */
	Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */

	if ((error = rdpgfx_read_rect16(s, &(pdu.rectSrc)))) /* rectSrc (8 bytes ) */
	{
		WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_rect16 failed with error %"PRIu32"!", error);
		return error;
	}

	WLog_Print(gfx->log, WLOG_DEBUG,
	         "RecvSurfaceToCachePdu: surfaceId: %"PRIu16" cacheKey: 0x%016"PRIX64" cacheSlot: %"PRIu16" "
	         "left: %"PRIu16" top: %"PRIu16" right: %"PRIu16" bottom: %"PRIu16"",
	         pdu.surfaceId, pdu.cacheKey, pdu.cacheSlot,
	         pdu.rectSrc.left, pdu.rectSrc.top,
	         pdu.rectSrc.right, pdu.rectSrc.bottom);

	if (context)
	{
		IFCALLRET(context->SurfaceToCache, error, context, &pdu);

		if (error)
			WLog_Print(gfx->log, WLOG_ERROR, "context->SurfaceToCache failed with error %"PRIu32"", error);
	}

	return error;
}
Esempio n. 20
0
void guac_rdpdr_fs_process_write(guac_rdpdr_device* device,
        wStream* input_stream, int file_id, int completion_id) {

    UINT32 length;
    UINT64 offset;
    int bytes_written;

    wStream* output_stream;

    /* Read packet */
    Stream_Read_UINT32(input_stream, length);
    Stream_Read_UINT64(input_stream, offset);
    Stream_Seek(input_stream, 20); /* Padding */

    guac_client_log(device->rdpdr->client, GUAC_LOG_DEBUG,
            "%s: [file_id=%i] length=%i, offset=%" PRIu64,
             __func__, file_id, length, (uint64_t) offset);

    /* Attempt write */
    bytes_written = guac_rdp_fs_write((guac_rdp_fs*) device->data, file_id,
            offset, Stream_Pointer(input_stream), length);

    /* If error, return invalid parameter */
    if (bytes_written < 0) {
        output_stream = guac_rdpdr_new_io_completion(device, completion_id,
                guac_rdp_fs_get_status(bytes_written), 5);
        Stream_Write_UINT32(output_stream, 0); /* Length */
        Stream_Write_UINT8(output_stream, 0);  /* Padding */
    }

    /* Otherwise, send success */
    else {
        output_stream = guac_rdpdr_new_io_completion(device, completion_id,
                STATUS_SUCCESS, 5);
        Stream_Write_UINT32(output_stream, bytes_written); /* Length */
        Stream_Write_UINT8(output_stream, 0);              /* Padding */
    }

    svc_plugin_send((rdpSvcPlugin*) device->rdpdr, output_stream);

}
Esempio n. 21
0
static void parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp)
{
	UINT32 Length;
	UINT64 Offset;
	ssize_t status;
	BYTE* buffer = NULL;

	Stream_Read_UINT32(irp->input, Length);
	Stream_Read_UINT64(irp->input, Offset);

	buffer = (BYTE*) malloc(Length);

	status = read(parallel->file, buffer, Length);

	if (status < 0)
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		free(buffer);
		buffer = NULL;
		Length = 0;

		DEBUG_WARN("read %s(%d) failed", parallel->path, parallel->id);
	}
	else
	{
		DEBUG_SVC("read %llu-%llu from %d", Offset, Offset + Length, parallel->id);
	}

	Stream_Write_UINT32(irp->output, Length);

	if (Length > 0)
	{
		Stream_EnsureRemainingCapacity(irp->output, Length);
		Stream_Write(irp->output, buffer, Length);
	}

	free(buffer);

	irp->Complete(irp);
}
Esempio n. 22
0
/* http://msdn.microsoft.com/en-us/library/dd407326.aspx */
static UINT32 tsmf_codec_parse_VIDEOINFOHEADER2(TS_AM_MEDIA_TYPE* mediatype, wStream* s)
{
	UINT64 AvgTimePerFrame;
	/* VIDEOINFOHEADER2.rcSource, RECT(LONG left, LONG top, LONG right, LONG bottom) */
	Stream_Seek_UINT32(s);
	Stream_Seek_UINT32(s);
	Stream_Read_UINT32(s, mediatype->Width);
	Stream_Read_UINT32(s, mediatype->Height);
	/* VIDEOINFOHEADER2.rcTarget */
	Stream_Seek(s, 16);
	/* VIDEOINFOHEADER2.dwBitRate */
	Stream_Read_UINT32(s, mediatype->BitRate);
	/* VIDEOINFOHEADER2.dwBitErrorRate */
	Stream_Seek_UINT32(s);
	/* VIDEOINFOHEADER2.AvgTimePerFrame */
	Stream_Read_UINT64(s, AvgTimePerFrame);
	mediatype->SamplesPerSecond.Numerator = 1000000;
	mediatype->SamplesPerSecond.Denominator = (int)(AvgTimePerFrame / 10LL);
	/* Remaining fields before bmiHeader */
	Stream_Seek(s, 24);
	return 72;
}
Esempio n. 23
0
static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
{
	SERIAL_TTY* tty;
	UINT32 Length;
	UINT64 Offset;

	Stream_Read_UINT32(irp->input, Length);
	Stream_Read_UINT64(irp->input, Offset);
	Stream_Seek(irp->input, 20); /* Padding */

	DEBUG_SVC("length %u offset %llu", Length, Offset);

	tty = serial->tty;

	if (tty == NULL)
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		Length = 0;

		DEBUG_WARN("tty not valid.");
	}
	else if (!serial_tty_write(tty, Stream_Pointer(irp->input), Length))
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		Length = 0;

		DEBUG_WARN("write %s(%d) failed.", serial->path, tty->id);
	}
	else
	{
		DEBUG_SVC("write %llu-%llu to %s(%d).", Offset, Offset + Length, serial->path, tty->id);
	}

	Stream_Write_UINT32(irp->output, Length);
	Stream_Write_UINT8(irp->output, 0); /* Padding */

	irp->Complete(irp);
}
Esempio n. 24
0
static void parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
{
	UINT32 len;
	UINT32 Length;
	UINT64 Offset;
	ssize_t status;

	Stream_Read_UINT32(irp->input, Length);
	Stream_Read_UINT64(irp->input, Offset);
	Stream_Seek(irp->input, 20); /* Padding */

	DEBUG_SVC("Length %u Offset %llu", Length, Offset);

	len = Length;

	while (len > 0)
	{
		status = write(parallel->file, Stream_Pointer(irp->input), len);

		if (status < 0)
		{
			irp->IoStatus = STATUS_UNSUCCESSFUL;
			Length = 0;

			DEBUG_WARN("write %s(%d) failed.", parallel->path, parallel->id);
			break;
		}

		Stream_Seek(irp->input, status);
		len -= status;
	}

	Stream_Write_UINT32(irp->output, Length);
	Stream_Write_UINT8(irp->output, 0); /* Padding */

	irp->Complete(irp);
}
Esempio n. 25
0
int rdpgfx_recv_map_surface_to_window_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
{
	RDPGFX_MAP_SURFACE_TO_WINDOW_PDU pdu;
	RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
	RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;

	if (Stream_GetRemainingLength(s) < 18)
		return -1;

	Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */
	Stream_Read_UINT64(s, pdu.windowId); /* windowId (8 bytes) */
	Stream_Read_UINT32(s, pdu.mappedWidth); /* mappedWidth (4 bytes) */
	Stream_Read_UINT32(s, pdu.mappedHeight); /* mappedHeight (4 bytes) */

	WLog_Print(gfx->log, WLOG_DEBUG, "RecvMapSurfaceToWindowPdu: surfaceId: %d windowId: 0x%04X mappedWidth: %d mappedHeight: %d",
			pdu.surfaceId, (int) pdu.windowId, pdu.mappedWidth, pdu.mappedHeight);

	if (context && context->MapSurfaceToWindow)
	{
		context->MapSurfaceToWindow(context, &pdu);
	}

	return 1;
}
Esempio n. 26
0
/**
 * Function description
 *
 * @return 0 on success, otherwise a Win32 error code
 */
UINT tsmf_ifman_on_sample(TSMF_IFMAN* ifman)
{
	TSMF_PRESENTATION* presentation;
	TSMF_STREAM* stream;
	UINT32 StreamId;
	UINT64 SampleStartTime;
	UINT64 SampleEndTime;
	UINT64 ThrottleDuration;
	UINT32 SampleExtensions;
	UINT32 cbData;
    UINT error;

	if (Stream_GetRemainingLength(ifman->input) < 60)
		return ERROR_INVALID_DATA;
	Stream_Seek(ifman->input, 16);
	Stream_Read_UINT32(ifman->input, StreamId);
	Stream_Seek_UINT32(ifman->input); /* numSample */
	Stream_Read_UINT64(ifman->input, SampleStartTime);
	Stream_Read_UINT64(ifman->input, SampleEndTime);
	Stream_Read_UINT64(ifman->input, ThrottleDuration);
	Stream_Seek_UINT32(ifman->input); /* SampleFlags */
	Stream_Read_UINT32(ifman->input, SampleExtensions);
	Stream_Read_UINT32(ifman->input, cbData);

	if (Stream_GetRemainingLength(ifman->input) < cbData)
		return ERROR_INVALID_DATA;

	DEBUG_TSMF("MessageId %d StreamId %d SampleStartTime %lu SampleEndTime %lu "
			   "ThrottleDuration %d SampleExtensions %d cbData %d",
			   ifman->message_id, StreamId, SampleStartTime, SampleEndTime,
			   (int)ThrottleDuration, SampleExtensions, cbData);

	presentation = tsmf_presentation_find_by_id(ifman->presentation_id);

	if (!presentation)
	{
		WLog_ERR(TAG, "unknown presentation id");
		return ERROR_NOT_FOUND;
	}

	stream = tsmf_stream_find_by_id(presentation, StreamId);

	if (!stream)
	{
		WLog_ERR(TAG, "unknown stream id");
		return ERROR_NOT_FOUND;
	}

	if (!tsmf_stream_push_sample(stream, ifman->channel_callback,
			ifman->message_id, SampleStartTime, SampleEndTime,
			ThrottleDuration, SampleExtensions, cbData, Stream_Pointer(ifman->input)))
	{
		WLog_ERR(TAG, "unable to push sample");
		return ERROR_OUTOFMEMORY;
	}

	if ((error = tsmf_presentation_sync(presentation)))
    {
        WLog_ERR(TAG, "tsmf_presentation_sync failed with error %lu", error);
        return error;
    }
	ifman->output_pending = TRUE;

	return CHANNEL_RC_OK;
}
Esempio n. 27
0
BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input)
{
	char* s = NULL;
        mode_t m;
	UINT64 size;
	int status;
	char* fullpath;
	struct STAT st;
	struct timeval tv[2];
	UINT64 LastWriteTime;
	UINT32 FileAttributes;
	UINT32 FileNameLength;

	m = 0;

	switch (FsInformationClass)
	{
		case FileBasicInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
			Stream_Seek_UINT64(input); /* CreationTime */
			Stream_Seek_UINT64(input); /* LastAccessTime */
			Stream_Read_UINT64(input, LastWriteTime);
			Stream_Seek_UINT64(input); /* ChangeTime */
			Stream_Read_UINT32(input, FileAttributes);

			if (FSTAT(file->fd, &st) != 0)
				return FALSE;

			tv[0].tv_sec = st.st_atime;
			tv[0].tv_usec = 0;
			tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime);
			tv[1].tv_usec = 0;
#ifndef WIN32
/* TODO on win32 */                        
#ifdef ANDROID
			utimes(file->fullpath, tv);
#else
			futimes(file->fd, tv);
#endif

			if (FileAttributes > 0)
			{
				m = st.st_mode;
				if ((FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
					m |= S_IWUSR;
				else
					m &= ~S_IWUSR;
				if (m != st.st_mode)
					fchmod(file->fd, m);
			}
#endif
                        break;

		case FileEndOfFileInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232067.aspx */
		case FileAllocationInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232076.aspx */
			Stream_Read_UINT64(input, size);
			if (ftruncate(file->fd, size) != 0)
				return FALSE;
			break;

		case FileDispositionInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232098.aspx */
			/* http://msdn.microsoft.com/en-us/library/cc241371.aspx */
			if (Length)
				Stream_Read_UINT8(input, file->delete_pending);
			else
				file->delete_pending = 1;
			if (file->delete_pending && file->is_dir)
			{
				/* mstsc causes this to FAIL if the directory is not empty,
				 * and that's what the server is expecting.  If we wait for
				 * the close to flag a failure, cut and paste of a folder
				 * will lose the folder's contents.
				 */
				int status;
				status = rmdir(file->fullpath);
				if (status == 0)
				{
					/* Put it back so the normal pending delete will work. */
					mkdir(file->fullpath, 0755);
				}
				else
				{
					return FALSE;
				}
			}
			break;

		case FileRenameInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232085.aspx */
			Stream_Seek_UINT8(input); /* ReplaceIfExists */
			Stream_Seek_UINT8(input); /* RootDirectory */
			Stream_Read_UINT32(input, FileNameLength);

			status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(input),
					FileNameLength / 2, &s, 0, NULL, NULL);

			if (status < 1)
				s = (char*) calloc(1, 1);

			fullpath = drive_file_combine_fullpath(file->basepath, s);
			free(s);

			/* TODO rename does not work on win32 */
                        if (rename(file->fullpath, fullpath) == 0)
			{
				DEBUG_SVC("renamed %s to %s", file->fullpath, fullpath);
				drive_file_set_fullpath(file, fullpath);
			}
			else
			{
				DEBUG_WARN("rename %s to %s failed, errno = %d", file->fullpath, fullpath, errno);
				free(fullpath);
				return FALSE;
			}

			break;

		default:
			DEBUG_WARN("invalid FsInformationClass %d", FsInformationClass);
			return FALSE;
	}

	return TRUE;
}
Esempio n. 28
0
BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input)
{
	char* s = NULL;
	mode_t m;
	UINT64 size;
	int status;
	char* fullpath;
	struct STAT st;
#if defined(__linux__) && !defined(ANDROID) || defined(sun)
	struct timespec tv[2];
#else
	struct timeval tv[2];
#endif
	UINT64 LastWriteTime;
	UINT32 FileAttributes;
	UINT32 FileNameLength;

	m = 0;

	switch (FsInformationClass)
	{
		case FileBasicInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
			Stream_Seek_UINT64(input); /* CreationTime */
			Stream_Seek_UINT64(input); /* LastAccessTime */
			Stream_Read_UINT64(input, LastWriteTime);
			Stream_Seek_UINT64(input); /* ChangeTime */
			Stream_Read_UINT32(input, FileAttributes);

			if (FSTAT(file->fd, &st) != 0)
				return FALSE;

			tv[0].tv_sec = st.st_atime;
			tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime);
#ifndef WIN32
			/* TODO on win32 */
#ifdef ANDROID
			tv[0].tv_usec = 0;
			tv[1].tv_usec = 0;
			utimes(file->fullpath, tv);
#elif defined (__linux__) || defined (sun)
			tv[0].tv_nsec = 0;
			tv[1].tv_nsec = 0;			
			futimens(file->fd, tv);
#else
			tv[0].tv_usec = 0;
			tv[1].tv_usec = 0;
			futimes(file->fd, tv);
#endif

			if (FileAttributes > 0)
			{
				m = st.st_mode;
				if ((FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
					m |= S_IWUSR;
				else
					m &= ~S_IWUSR;
				if (m != st.st_mode)
					fchmod(file->fd, st.st_mode);
			}
#endif
			break;

		case FileEndOfFileInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232067.aspx */
		case FileAllocationInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232076.aspx */
			Stream_Read_UINT64(input, size);
#ifndef _WIN32
			if (ftruncate(file->fd, size) != 0)
				return FALSE;
#endif
			break;

		case FileDispositionInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232098.aspx */
			/* http://msdn.microsoft.com/en-us/library/cc241371.aspx */
			if (file->is_dir && !dir_empty(file->fullpath))
				break;

			if (Length)
				Stream_Read_UINT8(input, file->delete_pending);
			else
				file->delete_pending = 1;
			break;

		case FileRenameInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232085.aspx */
			Stream_Seek_UINT8(input); /* ReplaceIfExists */
			Stream_Seek_UINT8(input); /* RootDirectory */
			Stream_Read_UINT32(input, FileNameLength);

			status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(input),
					FileNameLength / 2, &s, 0, NULL, NULL);

			if (status < 1)
				if (!(s = (char*) calloc(1, 1)))
				{
					WLog_ERR(TAG, "calloc failed!");
					return FALSE;
				}

			fullpath = drive_file_combine_fullpath(file->basepath, s);
			if (!fullpath)
			{
				WLog_ERR(TAG, "drive_file_combine_fullpath failed!");
				free (s);
				return FALSE;
			}
			free(s);

#ifdef _WIN32
			if (file->fd)
				close(file->fd);
#endif
			if (rename(file->fullpath, fullpath) == 0)
			{
				drive_file_set_fullpath(file, fullpath);
#ifdef _WIN32
				file->fd = OPEN(fullpath, O_RDWR | O_BINARY);
#endif
			}
			else
			{
				free(fullpath);
				return FALSE;
			}

			break;

		default:
			return FALSE;
	}

	return TRUE;
}