Open Files 5.3.0
Multi-Platform Event-Driven Application Framework
test_file.c

This is an example of using files and timers in an threaded application.

/* Copyright (c) 2021 Connected Way, LLC. All rights reserved.
* Use of this source code is governed by a Creative Commons
* Attribution-NoDerivatives 4.0 International license that can be
* found in the LICENSE file.
*/
#include "ofc/config.h"
#include "ofc/types.h"
#include "ofc/handle.h"
#include "ofc/queue.h"
#include "ofc/path.h"
#include "ofc/libc.h"
#include "ofc/time.h"
#include "ofc/thread.h"
#include "ofc/event.h"
#include "ofc/waitset.h"
#include "ofc/console.h"
#include "ofc/process.h"
#if defined(OFC_PERF_STATS)
#include "ofc/perf.h"
#endif
#include "ofc/heap.h"
#include "ofc/file.h"
#define OFC_FS_TEST_INTERVAL 1000
#define OFC_FILE_TEST_COUNT 1
/*
* This application demonstrates the API to the Open File I/O Facility
*
* The Open File I/O Facility is the primary interface fo the
* Open Files SMB Client. Once the SMB client is configured, network
* files are abstracted through this API. Whether files are access over
* the network, or local the the system that the application is running on
* is transparent to the running application. The location of the files
* (whether local or remote) is encoded in the file path. The file name
* can explicitly specify a remote file using a UNC or SMB URL. The file
* name can also specify a local path that is mapped to a UNC or SMB URL.
*/
/*
* Forward declaration of the File System Test Thread
*/
static OFC_DWORD OfcFSTestApp(OFC_PATH *path);
/*
* This test utility will map the destination file location to the device
* 'FS_TEST'. The typical situation would likely have the application
* specifying the path directly and not using a map. In our case, the
* advantage of the map is that we direct the target of the test simply
* by changing the map. The rest of the application remains unchanged.
*
* This test can be used to test the local file system abstraction
* or can be used to test the CIFS file system abstraction. Also,
* by using a loopback address to the CIFS url, we can exercise the
* CIFS Server as well.
*/
/*
* These are various file and directory names. There is nothing special
* about any of these names.
*/
#define FS_TEST_READ TSTR("copy.from")
#define FS_TEST_WRITE TSTR("copy.to")
#define FS_TEST_DELETE TSTR("delete.me")
#define FS_TEST_RENAME TSTR("directory\\rename.me")
#define FS_TEST_RENAMETO TSTR("directory\\new.me")
#define FS_TEST_RENAMETO_ROOT TSTR("new.me")
#define FS_TEST_FLUSH TSTR("flush.me")
#define FS_TEST_DIRECTORY TSTR("directory")
#define FS_TEST_SETEOF TSTR("seteof.txt")
#define FS_TEST_GETEX TSTR("getex.txt")
/*
* Buffering definitions. We test using overlapped asynchronous I/O. This
* implies multi-buffering
*
* The Buffer Size
*/
#define BUFFER_SIZE OFC_MAX_IO
/*
* And the number of buffers
*/
#define NUM_FILE_BUFFERS 10
/*
* Define buffer states.
*/
typedef enum {
BUFFER_STATE_IDLE, /* There is no I/O active */
BUFFER_STATE_READ, /* Data is being read into the buffer */
BUFFER_STATE_WRITE /* Data is being written from the buffer */
} BUFFER_STATE;
/*
* The buffer context
*
* Currently, handles to the overlapped i/o context may be platform
* dependent. Because of this, an overlapped i/o may not be shared
* between files unless it is guaranteed that the files are on the
* same device (using the same type of overlapped context).
*
* Ideally, overlapped I/Os should be platform independent. This will
* require changes to the way overlapped handles are managed.
*/
typedef struct {
OFC_HANDLE readOverlapped; /* The handle to the buffer when reading */
OFC_HANDLE writeOverlapped; /* The handle to the buffer when writing */
OFC_CHAR *data; /* Pointer to the buffer */
BUFFER_STATE state; /* Buffer state */
OFC_LARGE_INTEGER offset; /* Offset in file for I/O */
} OFC_FILE_BUFFER;
/*
* Result of Async I/O
*
* This essentially is a OFC_BOOL with the addition of a PENDING flag
*/
typedef enum {
ASYNC_RESULT_DONE, /* I/O is successful */
ASYNC_RESULT_ERROR, /* I/O was in error */
ASYNC_RESULT_EOF, /* I/O hit EOF */
ASYNC_RESULT_PENDING /* I/O is still pending */
} ASYNC_RESULT;
/*
* Perform an I/O Read
*
* \param wait_set
* The wait set that this I/O and it's overlapped handles will be part of
*
* \param read_file
* Handle of read file
*
* \param buffer
* Pointer to buffer to read into
*
* \param dwLen
* Length of buffer to read
*
* \returns
* OFC_TRUE if success, OFC_FALSE otherwise
*/
static ASYNC_RESULT
AsyncRead(OFC_HANDLE wait_set, OFC_HANDLE read_file,
OFC_FILE_BUFFER *buffer, OFC_DWORD dwLen)
{
ASYNC_RESULT result;
OFC_BOOL status;
/*
* initialize the read buffer using the read file, the read overlapped
* handle and the current read offset
*/
ofc_trace ("Reading 0x%08x\n", OFC_LARGE_INTEGER_LOW(buffer->offset));
OfcSetOverlappedOffset(read_file, buffer->readOverlapped, buffer->offset);
/*
* Set the state to reading
*/
buffer->state = BUFFER_STATE_READ;
/*
* Add the buffer to the wait set
*/
ofc_waitset_add(wait_set, (OFC_HANDLE) buffer, buffer->readOverlapped);
/*
* Issue the read (this will be non blocking)
*/
status = OfcReadFile(read_file, buffer->data, dwLen,
OFC_NULL, buffer->readOverlapped);
/*
* If it completed, the status will be OFC_TRUE. We actually expect
* the status to fail and the last error to be OFC_ERROR_IO_PENDING
*/
if (status == OFC_TRUE)
{
if (*((OFC_ULONG *)(buffer->data)) != buffer->offset)
ofc_printf("got bad buffer in async read 0x%08x, 0x%08x\n",
*((OFC_ULONG *)(buffer->data)), buffer->offset);
result = ASYNC_RESULT_DONE;
}
else
{
OFC_DWORD dwLastError;
/*
* Let's check the last error
*/
dwLastError = OfcGetLastError();
if (dwLastError == OFC_ERROR_IO_PENDING)
{
/*
* This is what we expect, so say the I/O submission succeeded
*/
result = ASYNC_RESULT_PENDING;
}
else
{
if (dwLastError == OFC_ERROR_HANDLE_EOF)
result = ASYNC_RESULT_EOF;
else
result = ASYNC_RESULT_ERROR;
/*
* It's not pending
*/
buffer->state = BUFFER_STATE_IDLE;
ofc_waitset_remove(wait_set, buffer->readOverlapped);
}
}
return (result);
}
/*
* Return the state of the read
*
* \param wait_set
* Wait set that the I/O should be part of
*
* \param read_file
* Handle to the read file
*
* \param buffer
* Pointer to the buffer
*
* \param dwLen
* Number of bytes to read / number of bytes read
*
* \returns
* state of the read
*/
static ASYNC_RESULT AsyncReadResult(OFC_HANDLE wait_set,
OFC_HANDLE read_file,
OFC_FILE_BUFFER *buffer,
OFC_DWORD *dwLen)
{
ASYNC_RESULT result;
OFC_BOOL status;
/*
* Get the overlapped result
*/
status = OfcGetOverlappedResult(read_file, buffer->readOverlapped,
dwLen, OFC_FALSE);
/*
* If the I/O is complete, status will be true and length will be non zero
*/
if (status == OFC_TRUE)
{
if (*dwLen == 0)
{
result = ASYNC_RESULT_EOF;
}
else
{
if (*((OFC_ULONG *)(buffer->data)) != buffer->offset)
{
ofc_printf("got bad buffer in async read result 0x%0x, 0x%0x\n",
*((OFC_ULONG*)(buffer->data)), buffer->offset);
ofc_process_crash("foobar");
}
result = ASYNC_RESULT_DONE;
}
}
else
{
OFC_DWORD dwLastError;
/*
* I/O may still be pending
*/
dwLastError = OfcGetLastError();
if (dwLastError == OFC_ERROR_IO_PENDING)
result = ASYNC_RESULT_PENDING;
else
{
/*
* I/O may also be EOF
*/
if (dwLastError != OFC_ERROR_HANDLE_EOF)
{
ofc_printf("Read Error %d\n", dwLastError);
result = ASYNC_RESULT_ERROR;
}
else
result = ASYNC_RESULT_EOF;
}
}
if (result != ASYNC_RESULT_PENDING)
{
/*
* Finish up the buffer if the I/O is no longer pending
*/
buffer->state = BUFFER_STATE_IDLE;
ofc_waitset_remove(wait_set, buffer->readOverlapped);
}
return (result);
}
/*
* Submit an asynchronous Write
*/
static ASYNC_RESULT AsyncWrite(OFC_HANDLE wait_set, OFC_HANDLE write_file,
OFC_FILE_BUFFER *buffer, OFC_DWORD dwLen)
{
OFC_BOOL status;
ASYNC_RESULT result;
ofc_trace ("Writing 0x%08x\n", OFC_LARGE_INTEGER_LOW(buffer->offset));
OfcSetOverlappedOffset(write_file, buffer->writeOverlapped,
buffer->offset);
buffer->state = BUFFER_STATE_WRITE;
ofc_waitset_add(wait_set, (OFC_HANDLE) buffer, buffer->writeOverlapped);
status = OfcWriteFile(write_file, buffer->data, dwLen, OFC_NULL,
buffer->writeOverlapped);
result = ASYNC_RESULT_DONE;
if (status != OFC_TRUE)
{
OFC_DWORD dwLastError;
dwLastError = OfcGetLastError();
if (dwLastError == OFC_ERROR_IO_PENDING)
result = ASYNC_RESULT_PENDING;
else
{
result = ASYNC_RESULT_ERROR;
buffer->state = BUFFER_STATE_IDLE;
ofc_waitset_remove(wait_set, buffer->writeOverlapped);
}
}
return (result);
}
static ASYNC_RESULT AsyncWriteResult(OFC_HANDLE wait_set,
OFC_HANDLE write_file,
OFC_FILE_BUFFER *buffer,
OFC_DWORD *dwLen)
{
ASYNC_RESULT result;
OFC_BOOL status;
status = OfcGetOverlappedResult(write_file, buffer->writeOverlapped,
dwLen, OFC_FALSE);
if (status == OFC_TRUE)
result = ASYNC_RESULT_DONE;
else
{
OFC_DWORD dwLastError;
dwLastError = OfcGetLastError();
if (dwLastError == OFC_ERROR_IO_PENDING)
result = ASYNC_RESULT_PENDING;
else
{
ofc_printf("Write Error %d\n", dwLastError);
result = ASYNC_RESULT_ERROR;
}
}
if (result != ASYNC_RESULT_PENDING)
{
buffer->state = BUFFER_STATE_IDLE;
ofc_waitset_remove(wait_set, buffer->writeOverlapped);
}
return (result);
}
static OFC_TCHAR *MakeFilename(OFC_CTCHAR *device, OFC_CTCHAR *name)
{
OFC_SIZET devlen;
OFC_SIZET namelen;
OFC_TCHAR *filename;
devlen = ofc_tastrlen (device);
namelen = ofc_tastrlen (name);
filename =
ofc_malloc((devlen + namelen + 2) * sizeof(OFC_TCHAR));
p = filename;
ofc_tastrcpy (p, device);
p += devlen;
if (devlen > 0)
*p++ = TCHAR('/');
ofc_tastrcpy (p, name);
p += namelen;
*p++ = TCHAR_EOS;
return (filename);
}
/*
* Create File Test. This routine will create a file using a blocking
* (sequential) algorithm
*/
/*
* Test File Size. Keep small for AWS. We pay for it
*/
#if 1
#define CREATE_SIZE (64*1024)
#else
#define CREATE_SIZE (64*1024*1024)
#endif
static OFC_BOOL OfcCreateFileTest(OFC_CTCHAR *device)
{
OFC_HANDLE write_file;
OFC_MSTIME start_time;
#if defined(OFC_PERF_STATS)
struct perf_queue *pqueue;
struct perf_rt *prt;
#endif
OFC_BOOL status;
OFC_TCHAR *wfilename;
OFC_BOOL ret;
OFC_INT size;
OFC_BOOL eof;
OFC_INT pending;
OFC_HANDLE buffer_list;
OFC_FILE_BUFFER *buffer;
OFC_HANDLE wait_set;
OFC_DWORD dwLen;
ASYNC_RESULT result;
OFC_HANDLE hEvent;
ret = OFC_TRUE;
/*
* Create the file used for the copy file test.
* This is the read file
*/
wfilename = MakeFilename(device, FS_TEST_READ);
/*
* Get the time for simple performance analysis
*/
status = OFC_TRUE;
start_time = ofc_time_get_now();
#if defined(OFC_PERF_STATS)
pqueue = perf_queue_create(g_measurement, TSTR("App Write"), 0);
prt = perf_rt_create(g_measurement, TSTR("App Create"), 0);
measurement_start(g_measurement);
#endif
/*
* Open up our write file. If it exists, it will be deleted
*/
write_file = OfcCreateFile(wfilename,
if (write_file == OFC_INVALID_HANDLE_VALUE)
{
ofc_printf("Failed to open Copy Destination %A, %s(%d)\n",
wfilename,
ret = OFC_FALSE;
}
else
{
wait_set = ofc_waitset_create();
buffer_list = ofc_queue_create();
eof = OFC_FALSE;
OFC_LARGE_INTEGER_SET(offset, 0, 0);
pending = 0;
/*
* Prime the engine. Priming involves obtaining a buffer
* for each overlapped I/O and initilizing them
*/
#if defined(OFC_PERF_STATS)
perf_rt_start(prt);
#endif
size = 0;
for (i = 0; i < NUM_FILE_BUFFERS && size < CREATE_SIZE && !eof; i++)
{
/*
* Get the buffer descriptor and the data buffer
*/
buffer = ofc_malloc(sizeof(OFC_FILE_BUFFER));
if (buffer == OFC_NULL)
{
ofc_printf("test_file: Failed to alloc buffer context\n");
ret = OFC_FALSE;
}
else
{
buffer->data = ofc_malloc(BUFFER_SIZE);
if (buffer->data == OFC_NULL)
{
ofc_printf("test_file: Failed to allocate "
"memory buffer\n");
ofc_free(buffer);
buffer = OFC_NULL;
ret = OFC_FALSE;
}
else
{
/*
* Initialize the offset to the file
*/
buffer->offset = offset;
/*
* And initialize the overlapped handles
*/
buffer->writeOverlapped = OfcCreateOverlapped(write_file);
if (buffer->writeOverlapped == OFC_HANDLE_NULL)
ofc_process_crash("An Overlapped Handle is NULL");
/*
* Add it to our buffer list
*/
ofc_enqueue(buffer_list, buffer);
dwLen = BUFFER_SIZE;
/*
* Fill in the buffer with an random data
*/
p = (OFC_ULONG *) buffer->data;
for (i = 0; i < (BUFFER_SIZE / sizeof(OFC_ULONG)); i++)
{
*p++ = size;
}
size += BUFFER_SIZE;
/*
* Issue the write (pre increment the pending to
* avoid races
*/
pending++;
#if defined(OFC_PERF_STATS)
perf_request_start(g_measurement, pqueue);
#endif
result = AsyncWrite(wait_set, write_file, buffer, dwLen);
if (result != ASYNC_RESULT_PENDING)
{
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue, 0);
#endif
/*
* discount pending and set eof
*/
pending--;
if (result == ASYNC_RESULT_ERROR)
{
ret = OFC_FALSE;
}
/*
* Set eof either because it really is eof, or we
* want to clean up.
*/
eof = OFC_TRUE;
}
/*
* Prepare for the next buffer
*/
#if defined(OFC_64BIT_INTEGER)
offset += BUFFER_SIZE;
#else
offset.low += BUFFER_SIZE ;
#endif
}
}
}
/*
* Now all our buffers should be busy doing writes. Keep writing
*/
while (pending > 0)
{
/*
* Wait for some buffer to finish (may be a read if we've
* just finished priming, but it may be a write also if
* we've been in this loop a bit
*/
hEvent = ofc_waitset_wait(wait_set);
if (hEvent != OFC_HANDLE_NULL)
{
/*
* We use the app of the event as a pointer to the
* buffer descriptor. Yeah, this isn't really nice but
* the alternative is to add a context to each handle.
* That may be cleaner, but basically unnecessary. If
* we did this kind of thing a lot, I'm all for a
* new property of a handle
*/
buffer = (OFC_FILE_BUFFER *) ofc_handle_get_app(hEvent);
if (buffer->state == BUFFER_STATE_WRITE)
{
/*
* Write, so let's see the result of the read
*/
result = AsyncWriteResult(wait_set, write_file,
buffer, &dwLen);
if (result == ASYNC_RESULT_EOF)
{
pending--;
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue, 0);
#endif
}
else if (result == ASYNC_RESULT_ERROR)
{
pending--;
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue, 0);
#endif
ret = OFC_FALSE;
}
else if (result == ASYNC_RESULT_DONE)
{
/*
* Only report on MB boundaries
*/
pending--;
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue, dwLen);
#endif
#if 0
if (buffer->offset % (1024 * 1024) == 0)
ofc_printf("Wrote %d MB\n",
(buffer->offset / (1024 * 1024)) + 1);
#endif
OFC_LARGE_INTEGER_ASSIGN (buffer->offset, offset);
#if defined(OFC_64BIT_INTEGER)
offset += BUFFER_SIZE;
#else
offset.low += BUFFER_SIZE ;
#endif
/*
* And start a write on the next chunk
*/
if (size < CREATE_SIZE && ret == OFC_TRUE)
{
p = (OFC_ULONG *) buffer->data;
for (i = 0; i < (BUFFER_SIZE / sizeof(OFC_ULONG)); i++)
{
*p++ = size;
}
size += BUFFER_SIZE;
pending++;
#if defined(OFC_PERF_STATS)
perf_request_start(g_measurement, pqueue);
#endif
result = AsyncWrite(wait_set, write_file,
buffer, BUFFER_SIZE);
if (result != ASYNC_RESULT_PENDING)
{
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue, 0);
#endif
}
}
}
}
}
}
#if defined(OFC_PERF_STATS)
perf_rt_stop(prt);
#endif
/*
* The pending count is zero so we've gotten completions
* either due to errors or eof on all of our outstanding
* reads and writes.
*/
for (buffer = ofc_dequeue(buffer_list);
buffer != OFC_NULL;
buffer = ofc_dequeue(buffer_list))
{
/*
* Destroy the overlapped I/O handle for each buffer
*/
OfcDestroyOverlapped(write_file, buffer->writeOverlapped);
/*
* Free the data buffer and the buffer descriptor
*/
ofc_free(buffer->data);
ofc_free(buffer);
}
/*
* Destroy the buffer list
*/
ofc_queue_destroy(buffer_list);
/*
* And destroy the wait list
*/
OfcCloseHandle(write_file);
}
ofc_free(wfilename);
#if defined(OFC_PERF_STATS)
measurement_wait(g_measurement);
measurement_statistics(g_measurement);
perf_rt_destroy(g_measurement, prt);
perf_queue_destroy(g_measurement, pqueue);
#endif
if (ret == OFC_TRUE)
ofc_printf("Create File Test Done, Elapsed Time %dms\n\n",
ofc_time_get_now() - start_time);
else
ofc_printf("Create File Test Failed\n\n");
return (ret);
}
static OFC_BOOL OfcDismountTest(OFC_CTCHAR *device)
{
OFC_BOOL status;
OFC_TCHAR *wfilename;
OFC_BOOL ret;
ret = OFC_TRUE;
/*
* Create the file used for the dismount file test.
*/
wfilename = MakeFilename(device, FS_TEST_READ);
status = OFC_TRUE;
/*
* Dismount the file
*/
OfcDismount(wfilename);
ofc_free(wfilename);
return (ret);
}
static OFC_BOOL OfcCopyFileTest(OFC_CTCHAR *device)
{
OFC_HANDLE read_file;
OFC_HANDLE write_file;
OFC_MSTIME start_time;
OFC_BOOL eof;
OFC_INT pending;
OFC_HANDLE buffer_list;
OFC_FILE_BUFFER *buffer;
OFC_HANDLE wait_set;
OFC_DWORD dwLen;
OFC_BOOL status;
ASYNC_RESULT result;
OFC_HANDLE hEvent;
OFC_TCHAR *rfilename;
OFC_TCHAR *wfilename;
OFC_BOOL ret;
#if defined(OFC_PERF_STATS)
struct perf_queue *pqueue_read;
struct perf_queue *pqueue_write;
struct perf_rt *prt;
#endif
ret = OFC_TRUE;
rfilename = MakeFilename(device, FS_TEST_READ);
wfilename = MakeFilename(device, FS_TEST_WRITE);
/*
* Get the time for simple performance analysis
*/
status = OFC_TRUE;
start_time = ofc_time_get_now();
#if defined(OFC_PERF_STATS)
pqueue_read = perf_queue_create(g_measurement, TSTR("App Read"), 0);
pqueue_write = perf_queue_create(g_measurement, TSTR("App Write"), 0);
prt = perf_rt_create(g_measurement, TSTR("App Copy"), 0);
measurement_start(g_measurement);
#endif
/*
* Open up our read file. This file should
* exist
*/
read_file = OfcCreateFile(rfilename,
if (read_file == OFC_INVALID_HANDLE_VALUE)
{
ofc_printf("Failed to open Copy Source %A, %s(%d)\n",
rfilename,
ret = OFC_FALSE;
}
else
{
/*
* Open up our write file. If it exists, it will be deleted
*/
write_file = OfcCreateFile(wfilename,
0,
if (write_file == OFC_INVALID_HANDLE_VALUE)
{
ofc_printf("Failed to open Copy Destination %A, %s(%d)\n",
wfilename,
ret = OFC_FALSE;
}
else
{
/*
* Now, create a wait set that we will wait for
*/
wait_set = ofc_waitset_create();
/*
* And create our own buffer list that we will manage
*/
buffer_list = ofc_queue_create();
/*
* Set some flags
*/
eof = OFC_FALSE;
OFC_LARGE_INTEGER_SET(offset, 0, 0);
pending = 0;
/*
* Prime the engine. Priming involves obtaining a buffer
* for each overlapped I/O and initilizing them
*/
for (i = 0; i < NUM_FILE_BUFFERS && ret == OFC_TRUE; i++)
{
/*
* Get the buffer descriptor and the data buffer
*/
buffer = ofc_malloc(sizeof(OFC_FILE_BUFFER));
if (buffer == OFC_NULL)
{
ofc_printf("test_file: Failed to alloc buffer context\n");
ret = OFC_FALSE;
}
else
{
buffer->data = ofc_malloc(BUFFER_SIZE);
if (buffer->data == OFC_NULL)
{
ofc_printf("test_file: Failed to allocate "
"memory buffer\n");
ofc_free(buffer);
buffer = OFC_NULL;
ret = OFC_FALSE;
}
else
{
/*
* Initialize the offset to the file
*/
buffer->offset = offset;
/*
* And initialize the overlapped handles
*/
buffer->readOverlapped = OfcCreateOverlapped(read_file);
buffer->writeOverlapped =
OfcCreateOverlapped(write_file);
if (buffer->readOverlapped == OFC_HANDLE_NULL ||
buffer->writeOverlapped == OFC_HANDLE_NULL)
ofc_process_crash("An Overlapped Handle is NULL");
/*
* Add it to our buffer list
*/
ofc_enqueue(buffer_list, buffer);
}
}
}
#if defined(OFC_PERF_STATS)
perf_rt_start(prt);
#endif
if (ret == OFC_TRUE)
{
for (buffer = ofc_queue_first(buffer_list);
buffer != OFC_NULL && !eof;
buffer = ofc_queue_next(buffer_list, buffer))
{
dwLen = BUFFER_SIZE;
/*
* Issue the read (pre increment the pending to
* avoid races
*/
pending++;
#if defined(OFC_PERF_STATS)
perf_request_start(g_measurement, pqueue_read);
#endif
result = AsyncRead(wait_set, read_file, buffer, dwLen);
if (result != ASYNC_RESULT_PENDING)
{
/*
* discount pending and set eof
*/
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue_read, 0);
#endif
pending--;
if (result == ASYNC_RESULT_ERROR)
{
ret = OFC_FALSE;
}
/*
* Set eof either because it really is eof, or we
* want to clean up.
*/
eof = OFC_TRUE;
}
/*
* Prepare for the next buffer
*/
#if defined(OFC_64BIT_INTEGER)
offset += BUFFER_SIZE;
#else
offset.low += BUFFER_SIZE ;
#endif
}
}
/*
* Now all our buffers should be busy doing reads. Keep pumping
* more data to read and service writes
*/
while (pending > 0)
{
/*
* Wait for some buffer to finish (may be a read if we've
* just finished priming, but it may be a write also if
* we've been in this loop a bit
*/
hEvent = ofc_waitset_wait(wait_set);
if (hEvent != OFC_HANDLE_NULL)
{
/*
* We use the app of the event as a pointer to the
* buffer descriptor. Yeah, this isn't really nice but
* the alternative is to add a context to each handle.
* That may be cleaner, but basically unnecessary. If
* we did this kind of thing a lot, I'm all for a
* new property of a handle
*/
buffer = (OFC_FILE_BUFFER *) ofc_handle_get_app(hEvent);
/*
* Now we have both read and write overlapped descriptors
* See what state we're in
*/
if (buffer->state == BUFFER_STATE_READ)
{
/*
* Read, so let's see the result of the read
*/
result = AsyncReadResult(wait_set, read_file,
buffer, &dwLen);
if (result == ASYNC_RESULT_EOF)
{
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue_read, 0);
#endif
}
else if (result == ASYNC_RESULT_ERROR)
{
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue_read, 0);
#endif
ret = OFC_FALSE;
}
else if (result == ASYNC_RESULT_DONE)
{
/*
* When the read is done, let's start up the write
*/
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue_read,
dwLen);
perf_request_start(g_measurement, pqueue_write);
#endif
result = AsyncWrite(wait_set, write_file, buffer,
dwLen);
if (result == ASYNC_RESULT_ERROR)
{
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue_write,
0);
#endif
ret = OFC_FALSE;
}
}
/*
* If the write failed, or we had a read result error
*/
if (result == ASYNC_RESULT_ERROR ||
result == ASYNC_RESULT_EOF ||
(result == ASYNC_RESULT_DONE && status == OFC_FALSE))
{
/*
* The I/O is no longer pending.
*/
pending--;
eof = OFC_TRUE;
}
}
else
{
/*
* The buffer state was write. Let's look at our
* status
*/
result = AsyncWriteResult(wait_set, write_file,
buffer, &dwLen);
/*
* Did it finish
*/
if (result == ASYNC_RESULT_ERROR)
{
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue_write, 0);
#endif
}
else if (result == ASYNC_RESULT_DONE)
{
/*
* The write is finished.
* Let's step the buffer
*/
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue_write,
dwLen);
#endif
/*
* Only report on MB boundaries
*/
#if 0
if (buffer->offset % (1024 * 1024) == 0)
ofc_printf("Copied %d MB\n",
(buffer->offset / (1024 * 1024)) + 1);
#endif
OFC_LARGE_INTEGER_ASSIGN (buffer->offset, offset);
#if defined(OFC_64BIT_INTEGER)
offset += BUFFER_SIZE;
#else
offset.low += BUFFER_SIZE ;
#endif
/*
* And start a read on the next chunk
*/
#if defined(OFC_PERF_STATS)
perf_request_start(g_measurement, pqueue_read);
#endif
result = AsyncRead(wait_set, read_file,
buffer, BUFFER_SIZE);
if (result != ASYNC_RESULT_PENDING)
{
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue_read,
0);
#endif
}
}
if (result != ASYNC_RESULT_PENDING)
{
if (result == ASYNC_RESULT_ERROR)
ret = OFC_FALSE;
eof = OFC_TRUE;
pending--;
}
}
}
}
#if defined(OFC_PERF_STATS)
perf_rt_stop(prt);
#endif
/*
* The pending count is zero so we've gotten completions
* either due to errors or eof on all of our outstanding
* reads and writes.
*/
for (buffer = ofc_dequeue(buffer_list);
buffer != OFC_NULL;
buffer = ofc_dequeue(buffer_list))
{
/*
* Destroy the overlapped I/O handle for each buffer
*/
OfcDestroyOverlapped(read_file, buffer->readOverlapped);
OfcDestroyOverlapped(write_file, buffer->writeOverlapped);
/*
* Free the data buffer and the buffer descriptor
*/
ofc_free(buffer->data);
ofc_free(buffer);
}
/*
* Destroy the buffer list
*/
ofc_queue_destroy(buffer_list);
/*
* And destroy the wait list
*/
/*
* Now close the write file
*/
OfcCloseHandle(write_file);
}
/*
* And close the read file
*/
OfcCloseHandle(read_file);
}
ofc_free(rfilename);
ofc_free(wfilename);
#if defined(OFC_PERF_STATS)
measurement_wait(g_measurement);
measurement_statistics(g_measurement);
perf_rt_destroy(g_measurement, prt);
perf_queue_destroy(g_measurement, pqueue_read);
perf_queue_destroy(g_measurement, pqueue_write);
#endif
if (ret == OFC_TRUE)
ofc_printf("Copy Test Done, Elapsed Time %dms\n\n",
ofc_time_get_now() - start_time);
else
ofc_printf("Copy Test Failed\n\n");
return (ret);
}
static OFC_BOOL OfcReadFileTest(OFC_CTCHAR *device)
{
OFC_HANDLE read_file;
OFC_MSTIME start_time;
OFC_BOOL eof;
OFC_INT pending;
OFC_HANDLE buffer_list;
OFC_FILE_BUFFER *buffer;
OFC_HANDLE wait_set;
OFC_DWORD dwLen;
OFC_BOOL status;
ASYNC_RESULT result;
OFC_HANDLE hEvent;
OFC_TCHAR *rfilename;
OFC_BOOL ret;
#if defined(OFC_PERF_STATS)
struct perf_queue *pqueue;
struct perf_rt *prt;
#endif
ret = OFC_TRUE;
rfilename = MakeFilename(device, FS_TEST_READ);
/*
* Get the time for simple performance analysis
*/
status = OFC_TRUE;
start_time = ofc_time_get_now();
#if defined(OFC_PERF_STATS)
pqueue = perf_queue_create(g_measurement, TSTR("App Read"), 0);
prt = perf_rt_create(g_measurement, TSTR("App Read"), 0);
measurement_start(g_measurement);
#endif
/*
* Open up our read file. This file should
* exist
*/
read_file = OfcCreateFile(rfilename,
if (read_file == OFC_INVALID_HANDLE_VALUE)
{
ofc_printf("Failed to open Copy Source %A, %s(%d)\n",
rfilename,
ret = OFC_FALSE;
}
else
{
/*
* Now, create a wait set that we will wait for
*/
wait_set = ofc_waitset_create();
/*
* And create our own buffer list that we will manage
*/
buffer_list = ofc_queue_create();
/*
* Set some flags
*/
eof = OFC_FALSE;
OFC_LARGE_INTEGER_SET(offset, 0, 0);
pending = 0;
/*
* Prime the engine. Priming involves obtaining a buffer
* for each overlapped I/O and initilizing them
*/
#if defined(OFC_PERF_STATS)
perf_rt_start(prt);
#endif
for (i = 0; i < NUM_FILE_BUFFERS && !eof; i++)
{
/*
* Get the buffer descriptor and the data buffer
*/
buffer = ofc_malloc(sizeof(OFC_FILE_BUFFER));
if (buffer == OFC_NULL)
{
ofc_printf("test_file: Failed to alloc buffer context\n");
ret = OFC_FALSE;
}
else
{
buffer->data = ofc_malloc(BUFFER_SIZE);
if (buffer->data == OFC_NULL)
{
ofc_printf("test_file: Failed to allocate "
"memory buffer\n");
ofc_free(buffer);
buffer = OFC_NULL;
ret = OFC_FALSE;
}
else
{
/*
* Initialize the offset to the file
*/
buffer->offset = offset;
/*
* And initialize the overlapped handles
*/
buffer->readOverlapped = OfcCreateOverlapped(read_file);
if (buffer->readOverlapped == OFC_HANDLE_NULL)
ofc_process_crash("An Overlapped Handle is NULL");
/*
* Add it to our buffer list
*/
ofc_enqueue(buffer_list, buffer);
dwLen = BUFFER_SIZE;
/*
* Issue the read (pre increment the pending to
* avoid races
*/
pending++;
#if defined(OFC_PERF_STATS)
perf_request_start(g_measurement, pqueue);
#endif
result = AsyncRead(wait_set, read_file, buffer, dwLen);
if (result != ASYNC_RESULT_PENDING)
{
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue, 0);
#endif
/*
* discount pending and set eof
*/
pending--;
if (result == ASYNC_RESULT_ERROR)
{
ret = OFC_FALSE;
}
/*
* Set eof either because it really is eof, or we
* want to clean up.
*/
eof = OFC_TRUE;
}
/*
* Prepare for the next buffer
*/
#if defined(OFC_64BIT_INTEGER)
offset += BUFFER_SIZE;
#else
offset.low += BUFFER_SIZE ;
#endif
}
}
}
/*
* Now all our buffers should be busy doing reads. Keep pumping
* more data to read and service writes
*/
while (pending > 0)
{
/*
* Wait for some buffer to finish (may be a read if we've
* just finished priming, but it may be a write also if
* we've been in this loop a bit
*/
hEvent = ofc_waitset_wait(wait_set);
if (hEvent != OFC_HANDLE_NULL)
{
/*
* We use the app of the event as a pointer to the
* buffer descriptor. Yeah, this isn't really nice but
* the alternative is to add a context to each handle.
* That may be cleaner, but basically unnecessary. If
* we did this kind of thing a lot, I'm all for a
* new property of a handle
*/
buffer = (OFC_FILE_BUFFER *) ofc_handle_get_app(hEvent);
if (buffer->state == BUFFER_STATE_READ)
{
/*
* Read, so let's see the result of the read
*/
result = AsyncReadResult(wait_set, read_file,
buffer, &dwLen);
if (result == ASYNC_RESULT_EOF)
{
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue, 0);
#endif
}
else if (result == ASYNC_RESULT_ERROR)
{
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue, 0);
#endif
ret = OFC_FALSE;
}
else if (result == ASYNC_RESULT_DONE)
{
/*
* Only report on MB boundaries
*/
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue, dwLen);
#endif
#if 0
if (buffer->offset % (1024 * 1024) == 0)
ofc_printf("Read %d MB\n",
(buffer->offset / (1024 * 1024)) + 1);
#endif
OFC_LARGE_INTEGER_ASSIGN (buffer->offset, offset);
#if defined(OFC_64BIT_INTEGER)
offset += BUFFER_SIZE;
#else
offset.low += BUFFER_SIZE ;
#endif
/*
* And start a read on the next chunk
*/
#if defined(OFC_PERF_STATS)
perf_request_start(g_measurement, pqueue);
#endif
result = AsyncRead(wait_set, read_file,
buffer, BUFFER_SIZE);
if (result != ASYNC_RESULT_PENDING)
{
#if defined(OFC_PERF_STATS)
perf_request_stop(g_measurement, pqueue, 0);
#endif
}
}
if (result == ASYNC_RESULT_ERROR ||
result == ASYNC_RESULT_EOF ||
(result == ASYNC_RESULT_DONE && status == OFC_FALSE))
{
/*
* The I/O is no longer pending.
*/
pending--;
eof = OFC_TRUE;
}
}
}
}
#if defined(OFC_PERF_STATS)
perf_rt_stop(prt);
#endif
/*
* The pending count is zero so we've gotten completions
* either due to errors or eof on all of our outstanding
* reads and writes.
*/
for (buffer = ofc_dequeue(buffer_list);
buffer != OFC_NULL;
buffer = ofc_dequeue(buffer_list))
{
/*
* Destroy the overlapped I/O handle for each buffer
*/
OfcDestroyOverlapped(read_file, buffer->readOverlapped);
/*
* Free the data buffer and the buffer descriptor
*/
ofc_free(buffer->data);
ofc_free(buffer);
}
/*
* Destroy the buffer list
*/
ofc_queue_destroy(buffer_list);
/*
* And destroy the wait list
*/
/*
* And close the read file
*/
OfcCloseHandle(read_file);
}
ofc_free(rfilename);
#if defined(OFC_PERF_STATS)
measurement_wait(g_measurement);
measurement_statistics(g_measurement);
perf_rt_destroy(g_measurement, prt);
perf_queue_destroy(g_measurement, pqueue);
#endif
if (ret == OFC_TRUE)
ofc_printf("Read Test Done, Elapsed Time %dms\n\n",
ofc_time_get_now() - start_time);
else
ofc_printf("Read Test Failed\n\n");
return (ret);
}
/*
* Delete File Test
*
* \param delete test type
*/
static OFC_BOOL
OfcDeleteTest(OFC_CTCHAR *device)
{
OFC_HANDLE write_file;
OFC_DWORD dwLastError;
OFC_CHAR *buffer;
OFC_SIZET len;
OFC_BOOL status;
OFC_TCHAR *filename;
OFC_DWORD dwBytesWritten;
OFC_BOOL ret;
ret = OFC_TRUE;
filename = MakeFilename(device, FS_TEST_DELETE);
/*
* First we need to create a file to delete
* This also tests us creating and writing to a file without overlap
* i/o
*/
write_file = OfcCreateFile(filename,
if (write_file == OFC_INVALID_HANDLE_VALUE)
{
ofc_printf("Failed to create delete file %A, %s(%d)\n",
filename,
ret = OFC_FALSE;
}
else
{
/*
* Let's write some stuff to the file
*/
buffer = ofc_malloc(BUFFER_SIZE);
len = BUFFER_SIZE;
while (len > 0)
{
len -= ofc_snprintf(buffer + (BUFFER_SIZE - len), len,
"This Text begins at offset %d\n",
BUFFER_SIZE - len);
}
/*
* And write it to the file
*/
status = OfcWriteFile(write_file, buffer, BUFFER_SIZE, &dwBytesWritten,
/*
* Free the buffer
*/
ofc_free(buffer);
if (status != OFC_TRUE)
{
/*
* We failed writing, complain
*/
dwLastError = OfcGetLastError();
ofc_printf("Write to Delete File Failed with %s(%d)\n",
dwLastError);
ret = OFC_FALSE;
}
else
{
/* Close file
*/
status = OfcCloseHandle(write_file);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Close of Delete File Failed with %s(%d)\n",
dwLastError);
ret = OFC_FALSE;
}
else
{
/*
* We've written the file. Now depending on the type
* of delete, delete the file
*/
write_file =
OfcCreateFile(filename,
if (write_file == OFC_INVALID_HANDLE_VALUE)
{
ofc_printf("Failed to create delete on close file %A, "
"%s(%d)\n",
filename,
ret = OFC_FALSE;
}
else
{
/* Close file
*/
status = OfcCloseHandle(write_file);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Close of Delete on close File "
"Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
else
ofc_printf("Delete on Close Test Succeeded\n");
}
}
}
}
ofc_free(filename);
return (ret);
}
/*
* Rename file test
*/
static OFC_BOOL OfcMoveTest(OFC_CTCHAR *device)
{
OFC_HANDLE rename_file;
OFC_DWORD dwLastError;
OFC_CHAR *buffer;
OFC_SIZET len;
OFC_BOOL status;
OFC_TCHAR *filename;
OFC_TCHAR *tofilename;
OFC_DWORD dwBytesWritten;
OFC_BOOL ret;
OFC_TCHAR *dirname;
OFC_HANDLE dirHandle;
/*
* Rename within a directory
*/
ret = OFC_TRUE;
dirname = MakeFilename(device, FS_TEST_DIRECTORY);
status = OfcCreateDirectory(dirname, OFC_NULL);
{
ret = OFC_TRUE;
filename = MakeFilename(device, FS_TEST_RENAME);
tofilename = MakeFilename(device, FS_TEST_RENAMETO);
/*
* First, make sure the destination file is not there
* We don't care about the error. It is probable, file does not exist
*/
OfcDeleteFile(tofilename);
/*
* Now create a file to rename
* Clean up any debris before starting
*/
status = OfcDeleteFile(tofilename);
/*
* First we need to create a file to rename
* This also tests us creating and writing to a file without overlap
* i/o
*/
rename_file = OfcCreateFile(filename,
if (rename_file == OFC_INVALID_HANDLE_VALUE)
{
ofc_printf("Failed to create rename file %A, %s(%d)\n",
filename,
ret = OFC_FALSE;
}
else
{
/*
* Let's write some stuff to the file
*/
buffer = ofc_malloc(BUFFER_SIZE);
len = BUFFER_SIZE;
while (len > 0)
{
len -= ofc_snprintf(buffer + (BUFFER_SIZE - len), len,
"This Text begins at offset %d\n",
BUFFER_SIZE - len);
}
status = OfcWriteFile(rename_file, buffer, BUFFER_SIZE,
&dwBytesWritten, OFC_HANDLE_NULL);
ofc_free(buffer);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Write to Rename File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
else
{
/* Close file
*/
status = OfcCloseHandle(rename_file);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Close of Rename File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
else
{
/*
* Now we can rename the file
*/
status = OfcMoveFile(filename, tofilename);
if (status == OFC_TRUE)
{
/*
* Now we can delete the file
*/
status = OfcDeleteFile(tofilename);
if (status == OFC_TRUE)
ofc_printf("Rename Test Succeeded\n");
else
{
dwLastError = OfcGetLastError();
ofc_printf("Delete Rename File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
}
else
{
dwLastError = OfcGetLastError();
ofc_printf("Rename File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
}
}
}
ofc_free(filename);
ofc_free(tofilename);
#if 0
status = OfcRemoveDirectory(dirname);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Couldn't delete directory, failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
}
#else
dirHandle = OfcCreateFile (dirname,
if (dirHandle == OFC_INVALID_HANDLE_VALUE)
{
ofc_printf("Failed to create delete on close dir %A, "
"%s(%d)\n",
dirname,
ret = OFC_FALSE ;
}
else
{
/* Close file
*/
status = OfcCloseHandle (dirHandle) ;
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError () ;
ofc_printf ("Close of Delete on close dir "
"Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError) ;
ret = OFC_FALSE ;
}
}
#endif
}
else
{
dwLastError = OfcGetLastError();
ofc_printf("Create of Directory Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
ofc_free(dirname);
return (ret);
}
/*
* Rename file test
*/
static OFC_BOOL OfcRenameTest(OFC_CTCHAR *device)
{
OFC_HANDLE rename_file;
OFC_DWORD dwLastError;
OFC_CHAR *buffer;
OFC_SIZET len;
OFC_BOOL status;
OFC_TCHAR *dirname;
OFC_HANDLE dirHandle;
OFC_TCHAR *filename;
OFC_TCHAR *tofilename;
OFC_TCHAR *fulltofilename;
OFC_DWORD dwBytesWritten;
OFC_BOOL ret;
OFC_FILE_RENAME_INFO *rename_info;
OFC_SIZET newlen;
OFC_SIZET rename_info_len;
/*
* Rename within a directory
*/
ret = OFC_TRUE;
dirname = MakeFilename(device, FS_TEST_DIRECTORY);
status = OfcCreateDirectory(dirname, OFC_NULL);
{
filename = MakeFilename(device, FS_TEST_RENAME);
fulltofilename = MakeFilename(device, FS_TEST_RENAMETO);
tofilename = ofc_tastrdup (FS_TEST_RENAMETO_ROOT);
/*
* First we need to create a file to rename
* This also tests us creating and writing to a file without overlap
* i/o
*/
rename_file = OfcCreateFile(filename,
if (rename_file == OFC_INVALID_HANDLE_VALUE)
{
ofc_printf("Failed to create rename file %A, %s(%d)\n",
filename,
ret = OFC_FALSE;
}
else
{
/*
* Let's write some stuff to the file
*/
buffer = ofc_malloc(BUFFER_SIZE);
len = BUFFER_SIZE;
while (len > 0)
{
len -= ofc_snprintf(buffer + (BUFFER_SIZE - len), len,
"This Text begins at offset %d\n",
BUFFER_SIZE - len);
}
status = OfcWriteFile(rename_file, buffer, BUFFER_SIZE, &dwBytesWritten,
ofc_free(buffer);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Write to Rename File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
else
{
/* Close file
*/
status = OfcCloseHandle(rename_file);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Close of Rename File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
else
{
rename_file = OfcCreateFile(filename,
0,
if (rename_file == OFC_INVALID_HANDLE_VALUE)
{
ofc_printf("Failed to create rename file %S, "
"%s(%d)\n",
filename,
ret = OFC_FALSE;
}
else
{
/*
* First delete the to file if it exists
*/
OfcDeleteFile(fulltofilename);
newlen = ofc_tstrlen(tofilename);
rename_info_len = sizeof(OFC_FILE_RENAME_INFO) +
(newlen * sizeof(OFC_WCHAR));
rename_info = ofc_malloc(rename_info_len);
rename_info->ReplaceIfExists = OFC_FALSE;
rename_info->FileNameLength =
(OFC_DWORD) newlen * sizeof(OFC_WCHAR);
ofc_tstrncpy(rename_info->FileName,
tofilename, newlen);
status =
rename_info,
(OFC_DWORD) rename_info_len);
ofc_free(rename_info);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Set File Info on rename File "
"Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
status = OfcCloseHandle(rename_file);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Close of rename File after Rename"
"Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
/*
* Now we can delete the file
*/
status = OfcDeleteFile(fulltofilename);
if (status == OFC_TRUE)
ofc_printf("Rename Test Succeeded\n");
else
{
dwLastError = OfcGetLastError();
ofc_printf("Delete Rename File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
}
}
}
}
ofc_free(filename);
ofc_free(tofilename);
ofc_free(fulltofilename);
#if 0
status = OfcRemoveDirectory(dirname);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Couldn't delete directory, failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
}
#else
dirHandle = OfcCreateFile (dirname,
if (dirHandle == OFC_INVALID_HANDLE_VALUE)
{
ofc_printf ("Failed to create delete on close dir %A, "
"%s(%d)\n",
dirname,
ret = OFC_FALSE ;
}
else
{
/* Close file
*/
status = OfcCloseHandle (dirHandle) ;
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError () ;
ofc_printf ("Close of Delete on close dir "
"Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError) ;
ret = OFC_FALSE ;
}
}
#endif
}
else
{
dwLastError = OfcGetLastError();
ofc_printf("Create of Directory Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
ofc_free(dirname);
return (ret);
}
/*
* Flush file test
*/
static OFC_BOOL OfcFlushTest(OFC_CTCHAR *device)
{
OFC_HANDLE flush_file;
OFC_DWORD dwLastError;
OFC_CHAR *buffer;
OFC_SIZET len;
OFC_BOOL status;
OFC_TCHAR *filename;
OFC_DWORD dwBytesWritten;
OFC_BOOL ret;
ret = OFC_TRUE;
filename = MakeFilename(device, FS_TEST_FLUSH);
/*
* First we need to create a file to flush
* This also tests us creating and writing to a file without overlap
* i/o
*/
flush_file = OfcCreateFile(filename,
if (flush_file == OFC_INVALID_HANDLE_VALUE)
{
ofc_printf("Failed to create flush file %A, %s(%d)\n",
filename,
ret = OFC_FALSE;
}
else
{
/*
* Let's write some stuff to the file
*/
buffer = ofc_malloc(BUFFER_SIZE);
status = OFC_TRUE;
for (i = 0; i < 10 && status == OFC_TRUE; i++)
{
len = ofc_snprintf(buffer, BUFFER_SIZE,
"This is the Text for line %d\n", i);
status = OfcWriteFile(flush_file, buffer, (OFC_DWORD) len, &dwBytesWritten,
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Write to Flush File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
else
{
/*
* Flush the file buffers
*/
status = OfcFlushFileBuffers(flush_file);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Flush to Flush File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
}
}
ofc_free(buffer);
/* Close file
*/
status = OfcCloseHandle(flush_file);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Close of Flush File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
else
{
/*
* Now we can delete the file
*/
status = OfcDeleteFile(filename);
if (status == OFC_TRUE)
ofc_printf("Flush Test Succeeded\n");
else
{
dwLastError = OfcGetLastError();
ofc_printf("Delete of Flush File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
}
}
ofc_free(filename);
return (ret);
}
/*
* Create directory test
*/
static OFC_BOOL OfcCreateDirectoryTest(OFC_CTCHAR *device)
{
OFC_BOOL status;
OFC_DWORD dwLastError;
OFC_TCHAR *filename;
OFC_BOOL ret;
ret = OFC_TRUE;
filename = MakeFilename(device, FS_TEST_DIRECTORY);
status = OfcCreateDirectory(filename, OFC_NULL);
if (status == OFC_TRUE)
ofc_printf("Create Directory Test Succeeded\n");
else
{
dwLastError = OfcGetLastError();
ofc_printf("Create of Directory Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
ofc_free(filename);
return (ret);
}
/*
* Delete Directory Test
*/
static OFC_BOOL OfcDeleteDirectoryTest(OFC_CTCHAR *device)
{
OFC_BOOL status;
OFC_DWORD dwLastError;
OFC_TCHAR *filename;
OFC_BOOL ret;
OFC_HANDLE dirhandle;
ret = OFC_TRUE;
filename = MakeFilename(device, FS_TEST_DIRECTORY);
#if 0
status = OfcRemoveDirectory(filename);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Couldn't delete directory, failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
}
#else
dirhandle = OfcCreateFile (filename,
if (dirhandle == OFC_INVALID_HANDLE_VALUE)
{
ofc_printf ("Failed to create delete on close dir %A, "
"%s(%d)\n",
filename,
ret = OFC_FALSE ;
}
else
{
/* Close file
*/
status = OfcCloseHandle (dirhandle) ;
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError () ;
ofc_printf ("Close of Delete on close dir "
"Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError) ;
ret = OFC_FALSE ;
}
else
ofc_printf ("Delete Directory Test Succeeded\n") ;
}
#endif
ofc_free(filename);
return (ret);
}
static OFC_BOOL OfcSetEOFTest(OFC_CTCHAR *device)
{
OFC_HANDLE seteof_file;
OFC_DWORD dwLastError;
OFC_CHAR *buffer;
OFC_SIZET len;
OFC_BOOL status;
OFC_DWORD pos;
OFC_TCHAR *filename;
OFC_DWORD dwBytesWritten;
OFC_BOOL ret;
ret = OFC_TRUE;
filename = MakeFilename(device, FS_TEST_SETEOF);
/*
* First we need to create a file to play with
* This also tests us creating and writing to a file without overlap
* i/o
*/
seteof_file = OfcCreateFile(filename,
if (seteof_file == OFC_INVALID_HANDLE_VALUE)
{
ofc_printf("Failed to create seteof file %A, %s(%d)\n",
filename,
ret = OFC_FALSE;
}
else
{
/*
* Let's write some stuff to the file
*/
buffer = ofc_malloc(BUFFER_SIZE);
len = BUFFER_SIZE;
while (len > 0)
{
len -= ofc_snprintf(buffer + (BUFFER_SIZE - len), len,
"This Text begins at offset %d\n",
BUFFER_SIZE - len);
}
status = OfcWriteFile(seteof_file, buffer, BUFFER_SIZE, &dwBytesWritten,
ofc_free(buffer);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Write to SetEOF File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
else
{
/* Close file
*/
status = OfcCloseHandle(seteof_file);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Close of SetEOF File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
else
{
/*
* Now we want to open the file for read/write
*/
seteof_file = OfcCreateFile(filename,
if (seteof_file == OFC_INVALID_HANDLE_VALUE)
{
ofc_printf("Failed to open seteof file %A, "
"%s(%d)\n",
filename,
ret = OFC_FALSE;
}
else
{
/*
* So now we want to set the file pointer to say, 2048
*/
pos = OfcSetFilePointer(seteof_file,
BUFFER_SIZE / 2,
dwLastError = OfcGetLastError();
dwLastError != OFC_ERROR_SUCCESS)
{
ofc_printf("SetFilePosition Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
else
{
/*
* Now we want to set eof
*/
status = OfcSetEndOfFile(seteof_file);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Set End Of File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
#if 0
else
{
OFC_FILE_STANDARD_INFO standard_info ;
(seteof_file,
&standard_info,
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError () ;
ofc_printf ("Cannot get end of file position %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError) ;
ret = OFC_FALSE ;
}
else
{
if (standard_info.EndOfFile != BUFFER_SIZE / 2)
{
ofc_printf
("End Of File Doesn't Match. Expected %d, Got %d\n",
BUFFER_SIZE / 2,
(OFC_INT) standard_info.EndOfFile) ;
ret = OFC_FALSE ;
}
}
}
#endif
}
status = OfcCloseHandle(seteof_file);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Close of SetEOF File "
"after pos Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
}
/*
* Now we can delete the file
*/
status = OfcDeleteFile(filename);
if (status == OFC_TRUE)
ofc_printf("SetEOF Test Succeeded\n");
else
{
dwLastError = OfcGetLastError();
ofc_printf("SetEOF Delete File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
}
}
}
ofc_free(filename);
return (ret);
}
/*
* Atrtribute test
*/
static OFC_CHAR *Attr2Str[17] =
{
"RO", /* Read Only */
"HID", /* Hidden */
"SYS", /* System */
"",
"DIR", /* Directory */
"ARV", /* Archive */
"",
"NRM", /* Normal */
"TMP", /* Temporary */
"SPR", /* Sparse */
"",
"CMP", /* Compressed */
"OFF", /* Offline */
"",
"ENC", /* Encrypted */
""
"VIRT", /* Virtual */
};
static OFC_VOID OfcFSPrintFindData(OFC_WIN32_FIND_DATA *find_data)
{
OFC_UINT16 mask;
OFC_CHAR str[100]; /* Guaranteed big enough for all attributes */
OFC_BOOL first;
OFC_WORD fat_date;
OFC_WORD fat_time;
OFC_UINT16 month;
OFC_UINT16 year;
OFC_UINT16 hour;
ofc_printf("File: %A\n", find_data->cFileName);
ofc_printf("Alternate Name: %.14A\n", find_data->cAlternateFileName);
ofc_printf("Attributes: 0x%08x\n", find_data->dwFileAttributes);
mask = 0x0001;
str[0] = '\0';
p = str;
first = OFC_TRUE;
for (i = 0; i < 16; i++, mask <<= 1)
{
if (find_data->dwFileAttributes & mask)
{
if (first)
first = OFC_FALSE;
else
{
ofc_strcpy(p, ", ");
p += 2;
}
ofc_strcpy(p, Attr2Str[i]);
p += ofc_strlen(Attr2Str[i]);
}
}
*p = '\0';
ofc_printf(" %s\n", str);
ofc_file_time_to_dos_date_time(&find_data->ftCreateTime,
&fat_date, &fat_time);
ofc_dos_date_time_to_elements(fat_date, fat_time,
&month, &day, &year, &hour, &min, &sec);
ofc_printf("Create Time: %02d/%02d/%04d %02d:%02d:%02d GMT\n",
month, day, year, hour, min, sec);
ofc_file_time_to_dos_date_time(&find_data->ftLastAccessTime,
&fat_date, &fat_time);
ofc_dos_date_time_to_elements(fat_date, fat_time,
&month, &day, &year, &hour, &min, &sec);
ofc_printf("Last Access Time: %02d/%02d/%04d %02d:%02d:%02d GMT\n",
month, day, year, hour, min, sec);
ofc_file_time_to_dos_date_time(&find_data->ftLastWriteTime,
&fat_date, &fat_time);
ofc_dos_date_time_to_elements(fat_date, fat_time,
&month, &day, &year, &hour, &min, &sec);
ofc_printf("Last Write Time: %02d/%02d/%04d %02d:%02d:%02d GMT\n",
month, day, year, hour, min, sec);
ofc_printf("File Size High: 0x%08x, Low: 0x%08x\n",
find_data->nFileSizeHigh, find_data->nFileSizeLow);
ofc_printf("\n");
}
static OFC_VOID
OfcFSPrintFileAttributeData(OFC_WIN32_FILE_ATTRIBUTE_DATA *file_data)
{
OFC_UINT16 mask;
OFC_CHAR str[100]; /* Guaranteed big enough for all attributes */
OFC_BOOL first;
OFC_WORD fat_date;
OFC_WORD fat_time;
OFC_UINT16 month;
OFC_UINT16 year;
OFC_UINT16 hour;
ofc_printf(" Attributes: 0x%08x\n", file_data->dwFileAttributes);
mask = 0x0001;
str[0] = '\0';
p = str;
first = OFC_TRUE;
for (i = 0; i < 16; i++, mask <<= 1)
{
if (file_data->dwFileAttributes & mask)
{
if (first)
first = OFC_FALSE;
else
{
ofc_strcpy(p, ", ");
p += 2;
}
ofc_strcpy(p, Attr2Str[i]);
p += ofc_strlen(Attr2Str[i]);
}
}
*p = '\0';
ofc_printf(" %s\n", str);
&fat_date, &fat_time);
ofc_dos_date_time_to_elements(fat_date, fat_time,
&month, &day, &year, &hour, &min, &sec);
ofc_printf("Create Time: %02d/%02d/%04d %02d:%02d:%02d GMT\n",
month, day, year, hour, min, sec);
&fat_date, &fat_time);
ofc_dos_date_time_to_elements(fat_date, fat_time,
&month, &day, &year, &hour, &min, &sec);
ofc_printf("Last Access Time: %02d/%02d/%04d %02d:%02d:%02d GMT\n",
month, day, year, hour, min, sec);
&fat_date, &fat_time);
ofc_dos_date_time_to_elements(fat_date, fat_time,
&month, &day, &year, &hour, &min, &sec);
ofc_printf("Last Write Time: %02d/%02d/%04d %02d:%02d:%02d GMT\n",
month, day, year, hour, min, sec);
ofc_printf("File Size High: 0x%08x, Low: 0x%08x\n",
file_data->nFileSizeHigh, file_data->nFileSizeLow);
}
static OFC_BOOL OfcListDirTest(OFC_CTCHAR *device)
{
OFC_HANDLE list_handle;
OFC_BOOL status;
OFC_TCHAR *filename;
OFC_DWORD last_error;
OFC_BOOL retry;
OFC_CHAR username[80];
OFC_CHAR password[80];
OFC_CHAR domain[80];
OFC_TCHAR *tusername;
OFC_TCHAR *tpassword;
OFC_TCHAR *tdomain;
OFC_BOOL ret;
OFC_INT count;
ret = OFC_TRUE;
retry = OFC_TRUE;
list_handle = OFC_INVALID_HANDLE_VALUE;
/*
* The initial credentials in device are anonymous. If that fails,
* prompt for credentials and try again.
*/
count = 0;
while (retry == OFC_TRUE)
{
filename = MakeFilename(device, TSTR("*"));
list_handle = OfcFindFirstFile(filename, &find_data, &more);
if (list_handle != OFC_INVALID_HANDLE_VALUE)
retry = OFC_FALSE;
else
{
last_error = OfcGetLastError();
ofc_printf("Failed to list dir %A, %s(%d)\n",
filename,
ofc_get_error_string(last_error),
last_error);
/*
* LOGON_FAILURE can be returned if authentication failed
* ACCESS_DENIED if authentication succeeded but no access to share
* INVALID_PASSWORD if password different then connection
*/
if (last_error == OFC_ERROR_LOGON_FAILURE ||
last_error == OFC_ERROR_ACCESS_DENIED ||
{
ofc_printf("Please Authenticate\n");
ofc_printf("Username: ");
ofc_read_line(username, 80);
if (ofc_strlen(username) == 0)
retry = OFC_FALSE;
else
{
tusername = ofc_cstr2tastr (username);
ofc_printf("Domain: ");
ofc_read_line(domain, 80);
tdomain = ofc_cstr2tastr (domain);
ofc_printf("Password: ");
ofc_read_password(password, 80);
tpassword = ofc_cstr2tastr (password);
/*
* Now remap the device
*/
ofc_path_update_credentials(filename, tusername,
tpassword, tdomain);
ofc_free(tusername);
ofc_free(tpassword);
ofc_free(tdomain);
}
}
else
{
retry = OFC_FALSE;
ret = OFC_FALSE;
}
}
ofc_free(filename);
}
if (list_handle != OFC_INVALID_HANDLE_VALUE)
{
count++;
OfcFSPrintFindData(&find_data);
status = OFC_TRUE;
while (more && status == OFC_TRUE)
{
status = OfcFindNextFile(list_handle,
&find_data,
&more);
if (status == OFC_TRUE)
{
count++;
OfcFSPrintFindData(&find_data);
}
else
{
last_error = OfcGetLastError();
if (last_error != OFC_ERROR_NO_MORE_FILES)
{
ofc_printf("Failed to Find Next, %s(%d)\n",
ofc_get_error_string(last_error),
last_error);
ret = OFC_FALSE;
}
}
}
OfcFindClose(list_handle);
}
ofc_printf("Total Number of Files in Directory %d\n", count);
return (ret);
}
static OFC_BOOL OfcGetFileAttributesTest(OFC_CTCHAR *device)
{
OFC_HANDLE getex_file;
OFC_DWORD dwLastError;
OFC_CHAR *buffer;
OFC_SIZET len;
OFC_BOOL status;
OFC_TCHAR *filename;
OFC_DWORD dwBytesWritten;
OFC_BOOL ret;
ret = OFC_TRUE;
filename = MakeFilename(device, FS_TEST_GETEX);
/*
* First we need to create a file to play with
*/
getex_file = OfcCreateFile(filename,
if (getex_file == OFC_INVALID_HANDLE_VALUE)
{
ofc_printf("Failed to create getex file %A, %s(%d)\n",
filename,
ret = OFC_FALSE;
}
else
{
/*
* Let's write some stuff to the file
*/
buffer = ofc_malloc(BUFFER_SIZE);
len = BUFFER_SIZE;
while (len > 0)
{
len -= ofc_snprintf(buffer + (BUFFER_SIZE - len), len,
"This Text begins at offset %d\n",
BUFFER_SIZE - len);
}
status = OfcWriteFile(getex_file, buffer, BUFFER_SIZE, &dwBytesWritten,
ofc_free(buffer);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Write to GetEX File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
else
{
/* Close file
*/
status = OfcCloseHandle(getex_file);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("Close of GetEX File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
else
{
status = OfcGetFileAttributesEx(filename,
&fInfo);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("GetEx Get File Info Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
else
{
ofc_printf("Get File Info for %A\n", filename);
OfcFSPrintFileAttributeData(&fInfo);
}
/*
* Now we can delete the file
*/
status = OfcDeleteFile(filename);
if (status != OFC_TRUE)
{
dwLastError = OfcGetLastError();
ofc_printf("GetEx Delete File Failed with %s(%d)\n",
ofc_get_error_string(dwLastError),
dwLastError);
ret = OFC_FALSE;
}
}
}
}
ofc_free(filename);
return (ret);
}
static OFC_BOOL OfcGetDiskFreeSpaceTest(OFC_CTCHAR *device)
{
OFC_DWORD SectorsPerCluster;
OFC_DWORD BytesPerSector;
OFC_DWORD NumberOfFreeClusters;
OFC_DWORD TotalNumberOfClusters;
OFC_BOOL result;
OFC_TCHAR *filename;
OFC_BOOL ret;
ret = OFC_TRUE;
filename = MakeFilename(device, TSTR(":"));
result = OfcGetDiskFreeSpace(filename, &SectorsPerCluster,
&BytesPerSector, &NumberOfFreeClusters,
&TotalNumberOfClusters);
if (result == OFC_FALSE)
{
ofc_printf("Failed to get disk free space on %A, %s(%d)\n",
filename,
ret = OFC_TRUE;
}
else
{
ofc_printf("Free Space On %A\n", filename);
ofc_printf(" Sectors Per Cluster: %d\n", SectorsPerCluster);
ofc_printf(" Bytes Per Sector: %d\n", BytesPerSector);
ofc_printf(" Number of Free Clusters: %d\n", NumberOfFreeClusters);
ofc_printf(" Total Number of Clusters: %d\n", TotalNumberOfClusters);
}
ofc_free(filename);
return (ret);
}
static OFC_BOOL OfcGetVolumeInformationTest(OFC_CTCHAR *device)
{
OFC_TCHAR VolumeNameBuffer[OFC_MAX_PATH + 1];
OFC_DWORD VolumeSerialNumber;
OFC_DWORD MaximumComponentLength;
OFC_DWORD FileSystemFlags;
OFC_TCHAR FileSystemName[OFC_MAX_PATH + 1];
OFC_BOOL result;
OFC_TCHAR *filename;
OFC_BOOL ret;
OFC_TCHAR *root;
ret = OFC_TRUE;
filename = MakeFilename(device, TSTR(":"));
ofc_path_get_root(filename, &root, OFC_NULL);
result = OfcGetVolumeInformation(root,
VolumeNameBuffer,
&VolumeSerialNumber,
&MaximumComponentLength,
&FileSystemFlags,
FileSystemName,
if (result == OFC_FALSE)
{
ofc_printf("Failed to get volume info on %A, %s(%d)\n",
filename,
/*
* Disk Free Space and Volume Information only works on Shares.
* (ie. there is no file name). No, reverse connections are tricky.
* The way we build names for a reverse connection uses the server
* as the gateway and the share as the server. It's not until the
* first directory that we actually specify the share. Unfortunately,
* the SMB protocol only accepts the share id in the request. That
* would imply the server. So getting free space or volume info on
* a server just doesn't make sense. In order to support this through
* a proxy, there needs to be a one to one correspondence between
* client share, proxy share, and server share. This makes proxying
* pretty useless since we could not proxy multiple servers through the
* same proxy. I think this is the only limitation.
*/
ofc_printf("Not supported on reverse connections, "
"see code comment\n");
ret = OFC_TRUE;
}
else
{
ofc_printf("Volume Info for %A\n", filename);
ofc_printf(" Volume Name: %A\n", VolumeNameBuffer);
ofc_printf(" Volume Serial Number: 0x%08x\n", VolumeSerialNumber);
ofc_printf(" Max Component Length: %d\n", MaximumComponentLength);
ofc_printf(" File System Flags: 0x%08x\n", FileSystemFlags);
ofc_printf(" File System Name: %A\n", FileSystemName);
}
ofc_free(filename);
ofc_free(root);
return (ret);
}
struct _test_path
{
OFC_CHAR *description;
OFC_CHAR *username;
OFC_CHAR *password;
OFC_CHAR *domain;
OFC_CHAR *smbserver;
OFC_CHAR *sharefolder;
OFC_CHAR *subdirectory;
OFC_UINT32 expected_error1;
OFC_UINT32 expected_error2;
};
static struct _test_path test_paths[] =
{
/* Test 0, Good case */
{
"Valid Path",
"user", "password", "workgroup",
"tester", "openfiles", "mydir",
},
/* Test 1, SMB server is wrong */
{
"Non-existent SMB Server",
"user", "password", "workgroup",
"bogus", "openfiles", "mydir",
},
/* Test 2, Share folder is wrong */
{
"Non-existent SMB Share",
"user", "password", "workgroup",
"tester", "bogus", "mydir",
},
/* Test 3, Password is wrong */
{
"Bad Passwowrd",
"user", "bogus", "workgroup",
"tester", "openfiles", "mydir",
},
/* Test 4, Subdirectory is wrong */
{
"Non-existent Subdirectory",
"user", "password", "workgroup",
"tester", "openfiles", "bogus",
},
/* Test 5, Share folder doesn't have write permission */
{
"Read-Only Share",
"user", "password", "workgroup",
"tester", "roshare", "mydir",
},
/* Test 6, Subdirectory doesn't have write permission */
{
"Read-Only Subdirectory",
"user", "password", "workgroup",
"tester", "openfiles", "rodir",
},
/* end of list */
{
}
};
static OFC_BOOL OfcBadFileNamesTest(OFC_CTCHAR *device)
{
OFC_BOOL ret;
OFC_BOOL test_status;
OFC_HANDLE hFile;
char uncfilename[OFC_MAX_PATH];
OFC_SIZET filelen;
char *tmpfilename;
OFC_UINT32 lasterror;
ret = OFC_TRUE;
for (i = 0; test_paths[i].description != OFC_NULL; i++)
{
ofc_printf("\n");
ofc_printf("Test %d, %s\n", i, test_paths[i].description);
/*
* method A, Opening Directory
*/
filelen = OFC_MAX_PATH;
tmpfilename = &uncfilename[0];
ofc_path_make_urlA(&tmpfilename, &filelen,
test_paths[i].username,
test_paths[i].password,
test_paths[i].domain,
test_paths[i].smbserver,
test_paths[i].sharefolder,
test_paths[i].subdirectory,
ofc_printf("Writeable Directory Mode\n");
ofc_printf("Testing Write Access to %s\n", uncfilename);
hFile = OfcCreateFileA(uncfilename,
test_status = OFC_TRUE;
{
lasterror = OfcGetLastError();
}
else
{
lasterror = OFC_ERROR_SUCCESS;
}
if (test_paths[i].expected_error1 != lasterror &&
test_paths[i].expected_error2 != lasterror)
{
test_status = OFC_FALSE;
ret = OFC_FALSE;
}
ofc_printf("%s: last error %s(%d), expected error %s(%d) or %s(%d)\n",
test_status == OFC_TRUE ? "SUCCESS" : "FAILURE",
lasterror,
ofc_get_error_string(test_paths[i].expected_error1),
test_paths[i].expected_error1,
ofc_get_error_string(test_paths[i].expected_error2),
test_paths[i].expected_error2);
OfcDismountA(uncfilename);
/*
* method B, Temporary File
*/
filelen = OFC_MAX_PATH;
tmpfilename = &uncfilename[0];
ofc_path_make_urlA(&tmpfilename, &filelen,
test_paths[i].username,
test_paths[i].password,
test_paths[i].domain,
test_paths[i].smbserver,
test_paths[i].sharefolder,
test_paths[i].subdirectory,
"uniquefile");
ofc_printf("Writeable Temporary File Mode\n");
ofc_printf("Testing Write Access to %s\n", uncfilename);
hFile = OfcCreateFileA(uncfilename,
test_status = OFC_TRUE;
{
lasterror = OfcGetLastError();
}
else
{
lasterror = OFC_ERROR_SUCCESS;
}
if (test_paths[i].expected_error1 != lasterror &&
test_paths[i].expected_error2 != lasterror)
{
test_status = OFC_FALSE;
ret = OFC_FALSE;
}
ofc_printf("%s: last error %s(%d), expected error %s(%d) or %s(%d)\n",
test_status == OFC_TRUE ? "SUCCESS" : "FAILURE",
lasterror,
ofc_get_error_string(test_paths[i].expected_error1),
test_paths[i].expected_error1,
ofc_get_error_string(test_paths[i].expected_error2),
test_paths[i].expected_error2);
OfcDismountA(uncfilename);
}
return (ret);
}
/*
* Startup Entry point to the test
*
* \param hScheduler
* The scheduler that this test should create apps within (if any)
* In our case, the file system test does not create any apps.
*/
OFC_INT test_file(OFC_LPCSTR test_root)
{
OFC_DWORD ret;
OFC_TCHAR *device;
OFC_BOOL test_result;
OFC_INT count;
OFC_PATH * test_path;
OFC_HANDLE test_dir;
/*
* If there is a path named "test" in the persistent file, use it
* otherwise use the default that was passed in.
*/
test_path = ofc_path_map_deviceW(TSTR("test"));
if (test_path == OFC_NULL)
device = ofc_cstr2tstr(test_root);
else
{
OFC_SIZET path_size;
OFC_SIZET rem;
OFC_TCHAR *ptr;
rem = 0;
path_size = ofc_path_printW(test_path, OFC_NULL, &rem);
rem = path_size + 1;
device = ofc_malloc(sizeof(OFC_TCHAR) * rem);
ptr = device;
ofc_path_printW(test_path, &ptr, &rem);
/*
* Do not delete the path. It is still mapped
*/
}
ofc_printf("Starting File Test with %S\n\n", device);
/*
* Create the test directory if it doesn't exist
*/
test_result = OfcCreateDirectory(device, OFC_NULL);
if (test_result == OFC_FALSE &&
{
ofc_printf("Failed to Validate Destination %S, %s(%d)\n",
ret = OFC_FALSE;
count = OFC_FILE_TEST_COUNT;
}
else
{
count = 0;
}
while (count != OFC_FILE_TEST_COUNT)
{
test_result = OFC_TRUE;
#if 0
/*
* OfcGetFileAttributesExW on "/" (initially failed with java)
*/
{
OFC_BOOL bret;
ofc_printf("Trying an OfcGetFileAttributesExW on /\n");
&fadFile);
if (bret != OFC_TRUE)
{
ofc_printf ("%s: OfcGetFileAttributesExW failed for %S, %s(%d)\n",
__func__, TSTR("/"),
}
else
ofc_printf("Succeeded\n");
}
#endif
/*
* First, create a random file
*/
#if 1
ofc_printf("Create File Test\n");
if (OfcCreateFileTest(device) == OFC_FALSE)
{
ofc_printf(" *** Create File Test Failed *** \n");
test_result = OFC_FALSE;
}
#endif
#if 0
ofc_printf(" Dismount Test\n");
if (OfcDismountTest(device) == OFC_FALSE)
{
ofc_printf(" *** Dismount Test Failed ***\n");
test_result = OFC_FALSE;
}
/* This may or may not fail. It is posible for the previous test
* to complete (dismount test) before the connection has been
* cleaned up. So, if the connection is up, the API will succeed.
* if the connection has already gone down, then the API will
* fail.
* Either case is good
*/
#if 0
ofc_printf(" Dismount Test with No connection\n");
OfcDismountTest(device);
#else
/* sleep not necessary */
//ofc_sleep(500);
#endif
#endif
#if 1
ofc_printf("Read File Test\n");
if (OfcReadFileTest(device) == OFC_FALSE)
{
ofc_printf(" *** Read File Test Failed *** \n");
test_result = OFC_FALSE;
}
#endif
/*
* Then see if we can copy files
*/
#if 1
ofc_printf("Copy File Test\n");
if (OfcCopyFileTest(device) == OFC_FALSE)
{
ofc_printf(" *** Copy File Test Failed *** \n");
test_result = OFC_FALSE;
}
#endif
#if 1
ofc_printf(" List Directory Test\n");
if (OfcListDirTest(device) == OFC_FALSE)
{
ofc_printf(" *** List Directory Test Failed *** \n");
test_result = OFC_FALSE;
}
#endif
#if 1
ofc_printf(" Delete File Test\n");
if (OfcDeleteTest(device) == OFC_FALSE)
{
ofc_printf(" *** Delete File Test Failed ***\n");
test_result = OFC_FALSE;
}
#endif
/* This one only works in SMBv2, we can update SMBv1 to support
* this style
* Since the API is only supported on SMBv2, we should use the
* move API instead. So, don't enable this approach yet.
*/
#if 0
ofc_printf (" Rename File Test\n") ;
if (OfcRenameTest (device) == OFC_FALSE)
{
ofc_printf (" *** Rename File Test Failed ***\n") ;
ofc_printf (" Failures expected on SMBv1 Systems\n") ;
test_result = OFC_FALSE ;
}
#endif
ofc_printf(" Move File Test\n");
if (OfcMoveTest(device) == OFC_FALSE)
{
ofc_printf(" *** Move File Test Failed ***\n");
test_result = OFC_FALSE;
}
ofc_printf(" Flush File Test\n");
if (OfcFlushTest(device) == OFC_FALSE)
{
ofc_printf(" *** Flush File Test Failed ***\n");
test_result = OFC_FALSE;
}
ofc_printf(" Create Directory Test\n");
if (OfcCreateDirectoryTest(device) == OFC_FALSE)
{
ofc_printf(" *** Create Directory Test Failed ***\n");
test_result = OFC_FALSE;
}
ofc_printf(" Delete Directory Test\n");
if (OfcDeleteDirectoryTest(device) == OFC_FALSE)
{
ofc_printf(" *** Delete Directory Test Failed ***\n");
test_result = OFC_FALSE;
}
ofc_printf(" Set File Pointer and Set EOF Test\n");
if (OfcSetEOFTest(device) == OFC_FALSE)
{
ofc_printf(" *** Set EOF Test Failed ***\n");
test_result = OFC_FALSE;
}
ofc_printf(" Get File Attributes Test\n");
if (OfcGetFileAttributesTest(device) == OFC_FALSE)
{
ofc_printf(" *** Get File Attributes Test Failed ***\n");
test_result = OFC_FALSE;
}
ofc_printf(" Get Disk Free Space Test\n");
if (OfcGetDiskFreeSpaceTest(device) == OFC_FALSE)
{
ofc_printf(" *** Get Disk Free Space Failed ***\n");
test_result = OFC_FALSE;
}
ofc_printf(" Get Volume Information Test\n");
if (OfcGetVolumeInformationTest(device) == OFC_FALSE)
{
ofc_printf(" *** Get Volume Information Failed ***\n");
test_result = OFC_FALSE;
}
if (test_result == OFC_FALSE)
ofc_printf("*** File Test Failed ***\n");
else
ofc_printf("File Test Succeeded\n\n");
count++;
if (count != OFC_FILE_TEST_COUNT)
ofc_sleep(OFC_FS_TEST_INTERVAL);
}
ofc_free(device);
return (0);
}
#define OfcGetDiskFreeSpace
Definition: file.h:2633
@ OFC_FILE_BEGIN
Definition: file.h:1479
@ OFC_ERROR_LOGON_FAILURE
Definition: file.h:1602
@ OFC_ERROR_BAD_NETPATH
Definition: file.h:1540
@ OFC_ERROR_SUCCESS
Definition: file.h:1508
@ OFC_ERROR_INVALID_PASSWORD
Definition: file.h:1548
@ OFC_ERROR_HANDLE_EOF
Definition: file.h:1534
@ OFC_ERROR_NO_MORE_FILES
Definition: file.h:1521
@ OFC_ERROR_FILE_EXISTS
Definition: file.h:1546
@ OFC_ERROR_ALREADY_EXISTS
Definition: file.h:1568
@ OFC_ERROR_ACCESS_DENIED
Definition: file.h:1513
@ OFC_ERROR_PATH_NOT_FOUND
Definition: file.h:1511
@ OFC_ERROR_IO_PENDING
Definition: file.h:1591
@ OFC_ERROR_BAD_NET_NAME
Definition: file.h:1536
@ OFC_ERROR_FILE_NOT_FOUND
Definition: file.h:1510
#define OFC_MAX_PATH
Definition: file.h:119
#define OfcDismount
Definition: file.h:2635
#define OfcCreateDirectory
Definition: file.h:2624
#define OfcGetFileAttributesEx
Definition: file.h:2629
OFC_CORE_LIB OFC_BOOL OfcCloseHandle(OFC_HANDLE hObject)
struct _OFC_FILE_RENAME_INFO OFC_FILE_RENAME_INFO
#define OfcMoveFile
Definition: file.h:2630
@ OfcGetFileExInfoStandard
Definition: file.h:729
@ OfcFileStandardInfo
Definition: file.h:463
@ OfcFileRenameInfo
Definition: file.h:475
#define OfcFindNextFile
Definition: file.h:2628
OFC_CORE_LIB const OFC_CHAR * ofc_get_error_string(OFC_DWORD dwerr)
OFC_CORE_LIB OFC_BOOL OfcDismountA(OFC_LPCSTR lpFileName)
#define OfcGetVolumeInformation
Definition: file.h:2634
OFC_CORE_LIB OFC_DWORD OfcGetLastError(OFC_VOID)
#define OfcRemoveDirectory
Definition: file.h:2626
OFC_CORE_LIB OFC_BOOL OfcSetEndOfFile(OFC_HANDLE hFile)
#define OFC_WIN32_FIND_DATA
Definition: file.h:2639
@ OFC_FILE_SHARE_READ
Definition: file.h:240
@ OFC_FILE_SHARE_DELETE
Definition: file.h:230
@ OFC_FILE_SHARE_NONE
Definition: file.h:225
@ OFC_FILE_SHARE_WRITE
Definition: file.h:235
OFC_CORE_LIB OFC_BOOL OfcGetFileInformationByHandleEx(OFC_HANDLE hFile, OFC_FILE_INFO_BY_HANDLE_CLASS FileInformationClass, OFC_LPVOID lpFileInformation, OFC_DWORD dwBufferSize)
OFC_CORE_LIB OFC_BOOL OfcGetOverlappedResult(OFC_HANDLE hFile, OFC_HANDLE hOverlapped, OFC_LPDWORD lpNumberOfBytesTransferred, OFC_BOOL bWait)
OFC_CORE_LIB OFC_VOID OfcDestroyOverlapped(OFC_HANDLE hFile, OFC_HANDLE hOverlapped)
#define OfcFindFirstFile
Definition: file.h:2627
OFC_CORE_LIB OFC_BOOL OfcReadFile(OFC_HANDLE hFile, OFC_LPVOID lpBuffer, OFC_DWORD nNumberOfBytesToRead, OFC_LPDWORD lpNumberOfBytesRead, OFC_HANDLE hOverlapped)
#define OfcCreateFile
Definition: file.h:2623
OFC_CORE_LIB OFC_BOOL OfcWriteFile(OFC_HANDLE hFile, OFC_LPCVOID lpBuffer, OFC_DWORD nNumberOfBytesToWrite, OFC_LPDWORD lpNumberOfBytesWritten, OFC_HANDLE hOverlapped)
@ OFC_OPEN_EXISTING
Definition: file.h:258
@ OFC_CREATE_NEW
Definition: file.h:250
@ OFC_CREATE_ALWAYS
Definition: file.h:254
OFC_CORE_LIB OFC_BOOL OfcFlushFileBuffers(OFC_HANDLE hFile)
#define OfcDeleteFile
Definition: file.h:2625
OFC_CORE_LIB OFC_HANDLE OfcCreateFileA(OFC_LPCSTR lpFileName, OFC_DWORD dwDesiredAccess, OFC_DWORD dwShareMode, OFC_LPSECURITY_ATTRIBUTES lpSecurityAttributes, OFC_DWORD dwCreationDisposition, OFC_DWORD dwFlagsAndAttributes, OFC_HANDLE hTemplateFile)
OFC_CORE_LIB OFC_VOID OfcSetOverlappedOffset(OFC_HANDLE hFile, OFC_HANDLE hOverlapped, OFC_OFFT offset)
OFC_CORE_LIB OFC_BOOL OfcFindClose(OFC_HANDLE hFindFile)
OFC_CORE_LIB OFC_DWORD OfcSetFilePointer(OFC_HANDLE hFile, OFC_LONG lDistanceToMove, OFC_PLONG lpDistanceToMoveHigh, OFC_DWORD dwMoveMethod)
OFC_CORE_LIB OFC_BOOL OfcGetFileAttributesExW(OFC_LPCTSTR lpFileName, OFC_GET_FILEEX_INFO_LEVELS fInfoLevelId, OFC_LPVOID lpFileInformation)
@ OFC_FILE_ATTRIBUTE_NORMAL
Definition: file.h:298
@ OFC_FILE_ATTRIBUTE_TEMPORARY
Definition: file.h:302
@ OFC_FILE_ATTRIBUTE_DIRECTORY
Definition: file.h:290
@ OFC_FILE_FLAG_DELETE_ON_CLOSE
Definition: file.h:364
@ OFC_FILE_FLAG_OVERLAPPED
Definition: file.h:380
OFC_CORE_LIB OFC_HANDLE OfcCreateOverlapped(OFC_HANDLE hFile)
@ OFC_GENERIC_WRITE
Definition: file.h:211
@ OFC_GENERIC_READ
Definition: file.h:204
@ OFC_FILE_DELETE
Definition: file.h:194
OFC_CORE_LIB OFC_BOOL OfcSetFileInformationByHandle(OFC_HANDLE hFile, OFC_FILE_INFO_BY_HANDLE_CLASS FileInformationClass, OFC_LPVOID lpFileInformation, OFC_DWORD dwBufferSize)
#define OFC_INVALID_SET_FILE_POINTER
Definition: file.h:1502
#define OFC_HANDLE_NULL
Definition: handle.h:64
OFC_CORE_LIB OFC_HANDLE ofc_handle_get_app(OFC_HANDLE hHandle)
OFC_DWORD_PTR OFC_HANDLE
Definition: handle.h:43
#define OFC_INVALID_HANDLE_VALUE
Definition: handle.h:52
OFC_CORE_LIB OFC_VOID ofc_free(OFC_LPVOID mem)
OFC_CORE_LIB OFC_LPVOID ofc_malloc(OFC_SIZET size)
OFC_CORE_LIB OFC_SIZET ofc_path_make_urlA(OFC_LPSTR *filename, OFC_SIZET *rem, OFC_LPCSTR username, OFC_LPCSTR password, OFC_LPCSTR domain, OFC_LPCSTR server, OFC_LPCSTR share, OFC_LPCSTR path, OFC_LPCSTR file)
OFC_CORE_LIB OFC_SIZET ofc_path_printW(OFC_PATH *path, OFC_LPTSTR *filename, OFC_SIZET *rem)
OFC_CORE_LIB OFC_PATH * ofc_path_map_deviceW(OFC_LPCTSTR lpDevice)
#define ofc_path_get_root
Definition: path.h:849
#define ofc_path_update_credentials
Definition: path.h:842
OFC_VOID OFC_PATH
Definition: path.h:122
OFC_CORE_LIB OFC_HANDLE ofc_queue_create(OFC_VOID)
OFC_CORE_LIB OFC_VOID ofc_queue_destroy(OFC_HANDLE qHead)
OFC_CORE_LIB OFC_VOID ofc_enqueue(OFC_HANDLE qHead, OFC_VOID *qElement)
OFC_CORE_LIB OFC_VOID * ofc_queue_next(OFC_HANDLE qHead, OFC_VOID *qElement)
OFC_CORE_LIB OFC_VOID * ofc_dequeue(OFC_HANDLE qHead)
OFC_CORE_LIB OFC_VOID * ofc_queue_first(OFC_HANDLE qHead)
Definition: file.h:895
OFC_WCHAR FileName[1]
Definition: file.h:911
OFC_BOOL ReplaceIfExists
Definition: file.h:899
OFC_HANDLE RootDirectory
Definition: file.h:903
OFC_DWORD FileNameLength
Definition: file.h:907
Definition: file.h:848
OFC_LARGE_INTEGER EndOfFile
Definition: file.h:856
Definition: file.h:690
OFC_DWORD nFileSizeLow
Definition: file.h:714
OFC_FILETIME ftLastAccessTime
Definition: file.h:702
OFC_DWORD dwFileAttributes
Definition: file.h:694
OFC_FILETIME ftLastWriteTime
Definition: file.h:706
OFC_DWORD nFileSizeHigh
Definition: file.h:710
OFC_FILETIME ftCreateTime
Definition: file.h:698
OFC_CORE_LIB OFC_VOID ofc_dos_date_time_to_elements(OFC_WORD FatDate, OFC_WORD FatTime, OFC_UINT16 *month, OFC_UINT16 *day, OFC_UINT16 *year, OFC_UINT16 *hour, OFC_UINT16 *min, OFC_UINT16 *sec)
OFC_CORE_LIB OFC_MSTIME ofc_time_get_now(OFC_VOID)
OFC_CORE_LIB OFC_BOOL ofc_file_time_to_dos_date_time(const OFC_FILETIME *lpFileTime, OFC_WORD *lpFatDate, OFC_WORD *lpFatTime)
@ OFC_FALSE
Definition: types.h:632
@ OFC_TRUE
Definition: types.h:636
#define OFC_LARGE_INTEGER_LOW(x)
Definition: types.h:250
void OFC_VOID
Definition: types.h:159
#define TCHAR_EOS
Definition: types.h:523
unsigned int OFC_UINT32
Definition: types.h:176
#define TCHAR(x)
Definition: types.h:541
OFC_UINT8 OFC_BOOL
Definition: types.h:624
OFC_UINT32 OFC_DWORD
Definition: types.h:430
OFC_WCHAR OFC_TCHAR
Definition: types.h:463
OFC_UINT16 OFC_WORD
Definition: types.h:426
#define OFC_NULL
Definition: types.h:656
unsigned long OFC_ULONG
Definition: types.h:364
char OFC_CHAR
Definition: types.h:143
OFC_INT32 OFC_MSTIME
Definition: types.h:506
OFC_INT64 OFC_LARGE_INTEGER
Definition: types.h:229
const OFC_CHAR * OFC_LPCSTR
Definition: types.h:422
const OFC_WCHAR OFC_CTCHAR
Definition: types.h:467
#define TSTR(x)
Definition: types.h:534
int OFC_INT
Definition: types.h:119
long int OFC_SIZET
Definition: types.h:115
#define OFC_LARGE_INTEGER_SET(x, y, z)
Definition: types.h:283
unsigned short int OFC_UINT16
Definition: types.h:183
#define OFC_LARGE_INTEGER_ASSIGN(x, y)
Definition: types.h:265
OFC_CORE_LIB OFC_VOID ofc_waitset_remove(OFC_HANDLE hSet, OFC_HANDLE hEvent)
OFC_CORE_LIB OFC_HANDLE ofc_waitset_create(OFC_VOID)
OFC_CORE_LIB OFC_VOID ofc_waitset_add(OFC_HANDLE hSet, OFC_HANDLE hApp, OFC_HANDLE hEvent)
OFC_CORE_LIB OFC_VOID ofc_waitset_destroy(OFC_HANDLE handle)
OFC_CORE_LIB OFC_HANDLE ofc_waitset_wait(OFC_HANDLE handle)