From 1f1b6cb0a78dcd89299ce22abc96171d1288e074 Mon Sep 17 00:00:00 2001 From: Arne Redlich Date: Mon, 31 Mar 2014 21:23:48 +0200 Subject: [PATCH] nfs_lseek{,_async}: allow negative offsets and guard against file positions < 0 Signed-off-by: Arne Redlich --- include/nfsc/libnfs.h | 4 +-- lib/libnfs-sync.c | 58 +++++++++++++++++++++---------------------- lib/libnfs.c | 34 +++++++++++++++++++------ 3 files changed, 57 insertions(+), 39 deletions(-) diff --git a/include/nfsc/libnfs.h b/include/nfsc/libnfs.h index 406fcdf..55f0280 100644 --- a/include/nfsc/libnfs.h +++ b/include/nfsc/libnfs.h @@ -504,14 +504,14 @@ EXTERN int nfs_write(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t coun * -errno : An error occured. * data is the error string. */ -EXTERN int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, int whence, nfs_cb cb, void *private_data); +EXTERN int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int64_t offset, int whence, nfs_cb cb, void *private_data); /* * Sync lseek() * Function returns * >=0 : numer of bytes read. * -errno : An error occured. */ -EXTERN int nfs_lseek(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, int whence, uint64_t *current_offset); +EXTERN int nfs_lseek(struct nfs_context *nfs, struct nfsfh *nfsfh, int64_t offset, int whence, uint64_t *current_offset); /* diff --git a/lib/libnfs-sync.c b/lib/libnfs-sync.c index e539a45..83d7086 100644 --- a/lib/libnfs-sync.c +++ b/lib/libnfs-sync.c @@ -813,7 +813,7 @@ static void lseek_cb(int status, struct nfs_context *nfs, void *data, void *priv } } -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; @@ -1328,7 +1328,7 @@ void free_nfs_srvr_list(struct nfs_server_list *srv) free(srv); srv = next; } -} +} struct nfs_list_data { int status; @@ -1364,7 +1364,7 @@ void callit_cb(struct rpc_context *rpc, int status, void *data _U_, void *privat srv_data->status = -1; return; } - + /* check for dupes */ for (srvr = srv_data->srvrs; srvr; srvr = srvr->next) { if (!strcmp(hostdd, srvr->addr)) { @@ -1374,7 +1374,7 @@ void callit_cb(struct rpc_context *rpc, int status, void *data _U_, void *privat 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; } @@ -1399,7 +1399,7 @@ static int send_nfsd_probes(struct rpc_context *rpc, INTERFACE_INFO *InterfaceLi assert(rpc->magic == RPC_CONTEXT_MAGIC); - for(i = 0; i < numIfs; i++) + for(i = 0; i < numIfs; i++) { SOCKADDR *pAddress; char bcdd[16]; @@ -1409,35 +1409,35 @@ static int send_nfsd_probes(struct rpc_context *rpc, INTERFACE_INFO *InterfaceLi 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; } @@ -1457,34 +1457,34 @@ struct nfs_server_list *nfs_find_local_servers(void) 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; @@ -1496,18 +1496,18 @@ struct nfs_server_list *nfs_find_local_servers(void) - (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; } @@ -1516,7 +1516,7 @@ struct nfs_server_list *nfs_find_local_servers(void) rpc_destroy_context(rpc); - if (data.status != 0) + if (data.status != 0) { free_nfs_srvr_list(data.srvrs); return NULL; @@ -1607,21 +1607,21 @@ struct nfs_server_list *nfs_find_local_servers(void) 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; } @@ -1645,14 +1645,14 @@ struct nfs_server_list *nfs_find_local_servers(void) 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) { diff --git a/lib/libnfs.c b/lib/libnfs.c index 9053ab1..5ea3280 100644 --- a/lib/libnfs.c +++ b/lib/libnfs.c @@ -3034,7 +3034,7 @@ void nfs_getcwd(struct nfs_context *nfs, const char **cwd) struct lseek_cb_data { struct nfs_context *nfs; struct nfsfh *nfsfh; - uint64_t offset; + int64_t offset; nfs_cb cb; void *private_data; }; @@ -3044,6 +3044,7 @@ static void nfs_lseek_1_cb(struct rpc_context *rpc, int status, void *command_da 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); @@ -3066,24 +3067,41 @@ static void nfs_lseek_1_cb(struct rpc_context *rpc, int status, void *command_da 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; } -- 2.34.1