#include "win32_compat.h"
#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
#ifdef HAVE_NET_IF_H
#include <net/if.h>
#endif
#include <sys/ioctl.h>
#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#include "libnfs-private.h"
struct sync_cb_data {
- int is_finished;
- int status;
- uint64_t offset;
- void *return_data;
- int return_int;
+ int is_finished;
+ int status;
+ uint64_t offset;
+ void *return_data;
+ int return_int;
+ const char *call;
};
cb_data->status = status;
if (status < 0) {
- nfs_set_error(nfs, "pread call failed with \"%s\"", (char *)data);
+ nfs_set_error(nfs, "%s call failed with \"%s\"", cb_data->call, (char *)data);
return;
}
cb_data.is_finished = 0;
cb_data.return_data = buffer;
+ cb_data.call = "pread";
if (nfs_pread_async(nfs, nfsfh, offset, count, pread_cb, &cb_data) != 0) {
nfs_set_error(nfs, "nfs_pread_async failed");
*/
int nfs_read(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buffer)
{
- return nfs_pread(nfs, nfsfh, nfs_get_current_offset(nfsfh), count, buffer);
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+ cb_data.return_data = buffer;
+ cb_data.call = "read";
+
+ if (nfs_read_async(nfs, nfsfh, count, pread_cb, &cb_data) != 0) {
+ nfs_set_error(nfs, "nfs_read_async failed");
+ return -1;
+ }
+
+ wait_for_nfs_reply(nfs, &cb_data);
+
+ return cb_data.status;
}
/*
cb_data->is_finished = 1;
cb_data->status = status;
- if (status < 0) {
- nfs_set_error(nfs, "pwrite call failed with \"%s\"", (char *)data);
- return;
- }
+ if (status < 0)
+ nfs_set_error(nfs, "%s call failed with \"%s\"", cb_data->call, (char *)data);
}
int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf)
struct sync_cb_data cb_data;
cb_data.is_finished = 0;
+ cb_data.call = "pwrite";
if (nfs_pwrite_async(nfs, nfsfh, offset, count, buf, pwrite_cb, &cb_data) != 0) {
nfs_set_error(nfs, "nfs_pwrite_async failed");
*/
int nfs_write(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf)
{
- return nfs_pwrite(nfs, nfsfh, nfs_get_current_offset(nfsfh), count, buf);
+ struct sync_cb_data cb_data;
+
+ cb_data.is_finished = 0;
+ cb_data.call = "write";
+
+ if (nfs_write_async(nfs, nfsfh, count, buf, pwrite_cb, &cb_data) != 0) {
+ nfs_set_error(nfs, "nfs_write_async failed");
+ return -1;
+ }
+
+ wait_for_nfs_reply(nfs, &cb_data);
+
+ return cb_data.status;
}
}
}
-int nfs_lseek(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, int whence, uint64_t *current_offset)
+int nfs_lseek(struct nfs_context *nfs, struct nfsfh *nfsfh, int64_t offset, int whence, uint64_t *current_offset)
{
struct sync_cb_data cb_data;
free(srv);
srv = next;
}
-}
+}
struct nfs_list_data {
int status;
srv_data->status = -1;
return;
}
-
+
/* check for dupes */
for (srvr = srv_data->srvrs; srvr; srvr = srvr->next) {
if (!strcmp(hostdd, srvr->addr)) {
srvr = malloc(sizeof(struct nfs_server_list));
if (srvr == NULL) {
- rpc_set_error(rpc, "Malloc failed when allocating server structure");
+ rpc_set_error(rpc, "Malloc failed when allocating server structure");
srv_data->status = -1;
return;
}
assert(rpc->magic == RPC_CONTEXT_MAGIC);
- for(i = 0; i < numIfs; i++)
+ for(i = 0; i < numIfs; i++)
{
SOCKADDR *pAddress;
char bcdd[16];
if(pAddress->sa_family != AF_INET)
continue;
-
+
nFlags = InterfaceList[i].iiFlags;
- if (!(nFlags & IFF_UP))
+ if (!(nFlags & IFF_UP))
{
continue;
}
- if (nFlags & IFF_LOOPBACK)
+ if (nFlags & IFF_LOOPBACK)
{
continue;
}
- if (!(nFlags & IFF_BROADCAST))
+ if (!(nFlags & IFF_BROADCAST))
{
continue;
}
- if (getnameinfo(pAddress, sizeof(struct sockaddr_in), &bcdd[0], sizeof(bcdd), NULL, 0, NI_NUMERICHOST) < 0)
+ if (getnameinfo(pAddress, sizeof(struct sockaddr_in), &bcdd[0], sizeof(bcdd), NULL, 0, NI_NUMERICHOST) < 0)
{
continue;
}
- if (rpc_set_udp_destination(rpc, bcdd, 111, 1) < 0)
+ if (rpc_set_udp_destination(rpc, bcdd, 111, 1) < 0)
{
return -1;
}
- if (rpc_pmap2_callit_async(rpc, MOUNT_PROGRAM, 2, 0, NULL, 0, callit_cb, data) < 0)
+ if (rpc_pmap2_callit_async(rpc, MOUNT_PROGRAM, 2, 0, NULL, 0, callit_cb, data) < 0)
{
return -1;
}
int nNumInterfaces = 0;
rpc = rpc_init_udp_context();
- if (rpc == NULL)
+ if (rpc == NULL)
{
return NULL;
}
- if (rpc_bind_udp(rpc, "0.0.0.0", 0) < 0)
+ if (rpc_bind_udp(rpc, "0.0.0.0", 0) < 0)
{
rpc_destroy_context(rpc);
return NULL;
}
- if (WSAIoctl(rpc_get_fd(rpc), SIO_GET_INTERFACE_LIST, 0, 0, &InterfaceList, sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR)
+ if (WSAIoctl(rpc_get_fd(rpc), SIO_GET_INTERFACE_LIST, 0, 0, &InterfaceList, sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR)
{
return NULL;
}
nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO);
- for (loop=0; loop<3; loop++)
+ for (loop=0; loop<3; loop++)
{
- if (send_nfsd_probes(rpc, InterfaceList, nNumInterfaces, &data) != 0)
+ if (send_nfsd_probes(rpc, InterfaceList, nNumInterfaces, &data) != 0)
{
rpc_destroy_context(rpc);
return NULL;
}
win32_gettimeofday(&tv_start, NULL);
- for(;;)
+ for(;;)
{
int mpt;
- (tv_current.tv_sec *1000 + tv_current.tv_usec / 1000)
+ (tv_start.tv_sec *1000 + tv_start.tv_usec / 1000);
- if (poll(&pfd, 1, mpt) < 0)
+ if (poll(&pfd, 1, mpt) < 0)
{
free_nfs_srvr_list(data.srvrs);
rpc_destroy_context(rpc);
return NULL;
}
- if (pfd.revents == 0)
+ if (pfd.revents == 0)
{
break;
}
-
- if (rpc_service(rpc, pfd.revents) < 0)
+
+ if (rpc_service(rpc, pfd.revents) < 0)
{
break;
}
rpc_destroy_context(rpc);
- if (data.status != 0)
+ if (data.status != 0)
{
free_nfs_srvr_list(data.srvrs);
return NULL;
while(ifc.ifc_len > (size - sizeof(struct ifreq))) {
size *= 2;
- free(ifc.ifc_buf);
+ free(ifc.ifc_buf);
ifc.ifc_len = size;
ifc.ifc_buf = malloc(size);
memset(ifc.ifc_buf, 0, size);
if (ioctl(rpc_get_fd(rpc), SIOCGIFCONF, (caddr_t)&ifc) < 0) {
rpc_destroy_context(rpc);
- free(ifc.ifc_buf);
+ free(ifc.ifc_buf);
return NULL;
}
- }
+ }
for (loop=0; loop<3; loop++) {
if (send_nfsd_probes(rpc, &ifc, &data) != 0) {
rpc_destroy_context(rpc);
- free(ifc.ifc_buf);
+ free(ifc.ifc_buf);
return NULL;
}
if (pfd.revents == 0) {
break;
}
-
+
if (rpc_service(rpc, pfd.revents) < 0) {
break;
}
}
}
- free(ifc.ifc_buf);
+ free(ifc.ifc_buf);
rpc_destroy_context(rpc);
if (data.status != 0) {
struct nfs_cb_data *data;
uint64_t offset;
uint64_t count;
+ int update_pos;
};
static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb_data *data, struct nfs_fh3 *fh);
if (res->status != NFS3_OK) {
rpc_set_error(nfs->rpc, "NFS: Read failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
data->error = 1;
- } else {
+ } else {
+ uint64_t count = res->READ3res_u.resok.count;
+
+ if (mdata->update_pos)
+ data->nfsfh->offset += count;
+
/* if we have more than one call or we have received a short read we need a reassembly buffer */
- if (data->num_calls || (res->READ3res_u.resok.count < mdata->count && !res->READ3res_u.resok.eof)) {
+ if (data->num_calls || (count < mdata->count && !res->READ3res_u.resok.eof)) {
if (data->buffer == NULL) {
data->buffer = malloc(data->request_size);
if (data->buffer == NULL) {
}
}
}
- if (res->READ3res_u.resok.count > 0) {
- if (res->READ3res_u.resok.count <= mdata->count) {
+ if (count > 0) {
+ if (count <= mdata->count) {
/* copy data into reassembly buffer if we have one */
if (data->buffer != NULL) {
- memcpy(&data->buffer[mdata->offset - data->start_offset], res->READ3res_u.resok.data.data_val, res->READ3res_u.resok.count);
+ memcpy(&data->buffer[mdata->offset - data->start_offset], res->READ3res_u.resok.data.data_val, count);
}
- if (data->max_offset < mdata->offset + res->READ3res_u.resok.count) {
- data->max_offset = mdata->offset + res->READ3res_u.resok.count;
+ if (data->max_offset < mdata->offset + count) {
+ data->max_offset = mdata->offset + count;
}
} else {
rpc_set_error(nfs->rpc, "NFS: Read overflow. Server has sent more data than requested!");
}
}
/* check if we have received a short read */
- if (res->READ3res_u.resok.count < mdata->count && !res->READ3res_u.resok.eof) {
- if (res->READ3res_u.resok.count == 0) {
+ if (count < mdata->count && !res->READ3res_u.resok.eof) {
+ if (count == 0) {
rpc_set_error(nfs->rpc, "NFS: Read failed. No bytes read and not at EOF!");
data->error = 1;
} else {
/* reissue reminder of this read request */
READ3args args;
- mdata->offset += res->READ3res_u.resok.count;
- mdata->count -= res->READ3res_u.resok.count;
+ mdata->offset += count;
+ mdata->count -= count;
nfs_fill_READ3args(&args, data->nfsfh, mdata->offset, mdata->count);
if (rpc_nfs3_read_async(nfs->rpc, nfs_pread_mcb, &args, mdata) == 0) {
data->num_calls++;
return;
}
- data->nfsfh->offset = data->max_offset;
if (data->buffer) {
data->cb(data->max_offset - data->start_offset, nfs, data->buffer, data->private_data);
} else {
free_nfs_cb_data(data);
}
-int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, nfs_cb cb, void *private_data)
+static int nfs_pread_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, nfs_cb cb, void *private_data, int update_pos)
{
struct nfs_cb_data *data;
data->nfsfh = nfsfh;
data->request_size = count;
- nfsfh->offset = offset;
-
assert(data->num_calls == 0);
/* chop requests into chunks of at most READMAX bytes if necessary.
mdata->data = data;
mdata->offset = offset;
mdata->count = readcount;
+ mdata->update_pos = update_pos;
nfs_fill_READ3args(&args, nfsfh, offset, readcount);
return 0;
}
+int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, nfs_cb cb, void *private_data)
+{
+ return nfs_pread_async_internal(nfs, nfsfh, offset, count, cb, private_data, 0);
+}
+
/*
* Async read()
*/
int nfs_read_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, nfs_cb cb, void *private_data)
{
- return nfs_pread_async(nfs, nfsfh, nfsfh->offset, count, cb, private_data);
+ return nfs_pread_async_internal(nfs, nfsfh, nfsfh->offset, count, cb, private_data, 1);
}
rpc_set_error(nfs->rpc, "NFS: Write failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
data->error = 1;
} else {
- if (res->WRITE3res_u.resok.count < mdata->count) {
- if (res->WRITE3res_u.resok.count == 0) {
+ uint64_t count = res->WRITE3res_u.resok.count;
+
+ if (mdata->update_pos)
+ data->nfsfh->offset += count;
+
+ if (count < mdata->count) {
+ if (count == 0) {
rpc_set_error(nfs->rpc, "NFS: Write failed. No bytes written!");
data->error = 1;
} else {
/* reissue reminder of this write request */
WRITE3args args;
- mdata->offset += res->WRITE3res_u.resok.count;
- mdata->count -= res->WRITE3res_u.resok.count;
+ mdata->offset += count;
+ mdata->count -= count;
+
nfs_fill_WRITE3args(&args, data->nfsfh, mdata->offset, mdata->count,
&data->usrbuf[mdata->offset - data->start_offset]);
if (rpc_nfs3_write_async(nfs->rpc, nfs_pwrite_mcb, &args, mdata) == 0) {
}
}
}
- if (res->WRITE3res_u.resok.count > 0) {
- if (data->max_offset < mdata->offset + res->WRITE3res_u.resok.count) {
- data->max_offset = mdata->offset + res->WRITE3res_u.resok.count;
+ if (count > 0) {
+ if (data->max_offset < mdata->offset + count) {
+ data->max_offset = mdata->offset + count;
}
}
}
return;
}
- data->nfsfh->offset = data->max_offset;
data->cb(data->max_offset - data->start_offset, nfs, NULL, data->private_data);
free_nfs_cb_data(data);
}
-int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf, nfs_cb cb, void *private_data)
+static int nfs_pwrite_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf, nfs_cb cb, void *private_data, int update_pos)
{
struct nfs_cb_data *data;
data->nfsfh = nfsfh;
data->usrbuf = buf;
- nfsfh->offset = offset;
-
/* hello, clang-analyzer */
assert(data->num_calls == 0);
mdata->data = data;
mdata->offset = offset;
mdata->count = writecount;
+ mdata->update_pos = update_pos;
nfs_fill_WRITE3args(&args, nfsfh, offset, writecount, &buf[offset - data->start_offset]);
return 0;
}
+int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf, nfs_cb cb, void *private_data)
+{
+ return nfs_pwrite_async_internal(nfs, nfsfh, offset, count, buf, cb, private_data, 0);
+}
+
/*
* Async write()
*/
int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf, nfs_cb cb, void *private_data)
{
- return nfs_pwrite_async(nfs, nfsfh, nfsfh->offset, count, buf, cb, private_data);
+ return nfs_pwrite_async_internal(nfs, nfsfh, nfsfh->offset, count, buf, cb, private_data, 1);
}
struct lseek_cb_data {
struct nfs_context *nfs;
struct nfsfh *nfsfh;
- uint64_t offset;
+ int64_t offset;
nfs_cb cb;
void *private_data;
};
GETATTR3res *res;
struct lseek_cb_data *data = private_data;
struct nfs_context *nfs = data->nfs;
+ uint64_t size = 0;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
return;
}
- data->nfsfh->offset = data->offset + res->GETATTR3res_u.resok.obj_attributes.size;
- data->cb(0, nfs, &data->nfsfh->offset, data->private_data);
+ size = res->GETATTR3res_u.resok.obj_attributes.size;
+
+ if (data->offset < 0 &&
+ (uint64_t)(-data->offset) > size) {
+ data->cb(-EINVAL, nfs, &data->nfsfh->offset, data->private_data);
+ } else {
+ data->nfsfh->offset = data->offset + size;
+ data->cb(0, nfs, &data->nfsfh->offset, data->private_data);
+ }
+
free(data);
}
-int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, int whence, nfs_cb cb, void *private_data)
+int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int64_t offset, int whence, nfs_cb cb, void *private_data)
{
struct lseek_cb_data *data;
struct GETATTR3args args;
if (whence == SEEK_SET) {
- nfsfh->offset = offset;
- cb(0, nfs, &nfsfh->offset, private_data);
+ if (offset < 0) {
+ cb(-EINVAL, nfs, &nfsfh->offset, private_data);
+ } else {
+ nfsfh->offset = offset;
+ cb(0, nfs, &nfsfh->offset, private_data);
+ }
return 0;
}
if (whence == SEEK_CUR) {
- nfsfh->offset += offset;
- cb(0, nfs, &nfsfh->offset, private_data);
+ if (offset < 0 &&
+ nfsfh->offset < (uint64_t)(-offset)) {
+ cb(-EINVAL, nfs, &nfsfh->offset, private_data);
+ } else {
+ nfsfh->offset += offset;
+ cb(0, nfs, &nfsfh->offset, private_data);
+ }
return 0;
}