2011-02-06 07:45:09 +03:00
/*
Copyright ( C ) 2010 by Ronnie Sahlberg < ronniesahlberg @ gmail . com >
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public License
along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
/*
* High level api to nfs filesystems
*/
2013-04-14 21:11:48 +04:00
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
2013-04-14 21:32:01 +04:00
# ifdef AROS
# include "aros_compat.h"
2013-04-14 21:11:48 +04:00
# endif
2011-09-01 23:35:54 +04:00
# ifdef WIN32
# include "win32_compat.h"
2013-05-29 04:54:12 +04:00
# endif
# ifdef HAVE_UTIME_H
2013-04-11 07:28:40 +04:00
# include <utime.h>
2013-05-29 04:54:12 +04:00
# endif
2013-04-11 07:28:40 +04:00
# ifdef ANDROID
2012-11-28 21:04:05 +04:00
# define statvfs statfs
2013-04-14 21:32:01 +04:00
# endif
2011-09-01 23:35:54 +04:00
# define _GNU_SOURCE
2011-08-28 13:43:33 +04:00
2013-04-14 21:32:01 +04:00
# ifdef HAVE_UNISTD_H
# include <unistd.h>
# endif
# ifdef HAVE_SYS_VFS_H
# include <sys/vfs.h>
# endif
# ifdef HAVE_SYS_STATVFS_H
# include <sys/statvfs.h>
# endif
2013-05-29 04:38:37 +04:00
# ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
# endif
2013-05-29 04:54:12 +04:00
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
2011-02-06 07:45:09 +03:00
# include <stdio.h>
2011-06-19 03:38:20 +04:00
# include <stdarg.h>
2011-02-06 07:45:09 +03:00
# include <stdlib.h>
# include <string.h>
2012-11-24 20:18:54 +04:00
# include <assert.h>
2011-02-06 07:45:09 +03:00
# include <errno.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
2012-07-04 10:53:12 +04:00
# include "libnfs-zdr.h"
2014-06-08 22:22:06 +04:00
# include "slist.h"
2011-02-06 07:45:09 +03:00
# include "libnfs.h"
# include "libnfs-raw.h"
# include "libnfs-raw-mount.h"
# include "libnfs-raw-nfs.h"
2014-03-17 04:48:35 +04:00
# include "libnfs-raw-portmap.h"
2011-06-19 03:38:20 +04:00
# include "libnfs-private.h"
2014-06-30 01:42:28 +04:00
# define MAX_DIR_CACHE 128
2014-06-08 22:22:06 +04:00
2011-06-19 03:38:20 +04:00
struct nfsdir {
2014-06-08 22:22:06 +04:00
struct nfs_fh3 fh ;
fattr3 attr ;
struct nfsdir * next ;
2011-06-19 03:38:20 +04:00
struct nfsdirent * entries ;
struct nfsdirent * current ;
} ;
2011-02-06 07:45:09 +03:00
2014-06-23 18:31:32 +04:00
struct nfs_readahead {
uint64_t fh_offset ;
uint64_t last_offset ;
uint64_t buf_offset ;
uint64_t buf_count ;
time_t buf_ts ;
void * buf ;
uint32_t cur_ra ;
} ;
2011-02-06 07:45:09 +03:00
struct nfsfh {
struct nfs_fh3 fh ;
int is_sync ;
2014-04-18 20:32:01 +04:00
int is_append ;
2011-11-27 07:49:08 +04:00
uint64_t offset ;
2014-06-23 18:31:32 +04:00
struct nfs_readahead ra ;
2011-02-06 07:45:09 +03:00
} ;
2011-06-19 03:38:20 +04:00
struct nfs_context {
struct rpc_context * rpc ;
char * server ;
char * export ;
struct nfs_fh3 rootfh ;
2011-11-27 07:49:08 +04:00
uint64_t readmax ;
uint64_t writemax ;
2014-01-28 08:54:14 +04:00
char * cwd ;
2014-06-08 22:22:06 +04:00
struct nfsdir * dircache ;
2011-02-06 07:45:09 +03:00
} ;
void nfs_free_nfsdir ( struct nfsdir * nfsdir )
{
while ( nfsdir - > entries ) {
struct nfsdirent * dirent = nfsdir - > entries - > next ;
if ( nfsdir - > entries - > name ! = NULL ) {
free ( nfsdir - > entries - > name ) ;
}
free ( nfsdir - > entries ) ;
nfsdir - > entries = dirent ;
}
2014-06-08 22:22:06 +04:00
free ( nfsdir - > fh . data . data_val ) ;
2011-02-06 07:45:09 +03:00
free ( nfsdir ) ;
}
2014-06-08 22:22:06 +04:00
static void nfs_dircache_add ( struct nfs_context * nfs , struct nfsdir * nfsdir )
{
int i ;
LIBNFS_LIST_ADD ( & nfs - > dircache , nfsdir ) ;
for ( nfsdir = nfs - > dircache , i = 0 ; nfsdir ; nfsdir = nfsdir - > next , i + + ) {
if ( i > MAX_DIR_CACHE ) {
LIBNFS_LIST_REMOVE ( & nfs - > dircache , nfsdir ) ;
nfs_free_nfsdir ( nfsdir ) ;
break ;
}
}
}
static struct nfsdir * nfs_dircache_find ( struct nfs_context * nfs , struct nfs_fh3 * fh )
{
struct nfsdir * nfsdir ;
for ( nfsdir = nfs - > dircache ; nfsdir ; nfsdir = nfsdir - > next ) {
if ( nfsdir - > fh . data . data_len = = fh - > data . data_len & &
! memcmp ( nfsdir - > fh . data . data_val , fh - > data . data_val , fh - > data . data_len ) ) {
LIBNFS_LIST_REMOVE ( & nfs - > dircache , nfsdir ) ;
return nfsdir ;
}
}
return NULL ;
}
2011-02-06 07:45:09 +03:00
struct nfs_cb_data ;
2014-06-08 20:45:22 +04:00
typedef int ( * continue_func ) ( struct nfs_context * nfs , fattr3 * attr ,
struct nfs_cb_data * data ) ;
2011-02-06 07:45:09 +03:00
struct nfs_cb_data {
struct nfs_context * nfs ;
struct nfsfh * nfsfh ;
char * saved_path , * path ;
nfs_cb cb ;
void * private_data ;
continue_func continue_cb ;
void * continue_data ;
void ( * free_continue_data ) ( void * ) ;
int continue_int ;
struct nfs_fh3 fh ;
2011-06-19 02:43:28 +04:00
/* for multi-read/write calls. */
int error ;
int cancel ;
2014-03-16 23:15:48 +04:00
int oom ;
2011-06-19 02:43:28 +04:00
int num_calls ;
2014-06-23 18:31:32 +04:00
uint64_t offset , count , max_offset , org_offset , org_count ;
2011-06-19 02:43:28 +04:00
char * buffer ;
2014-03-15 19:22:03 +04:00
char * usrbuf ;
2011-06-19 02:43:28 +04:00
} ;
struct nfs_mcb_data {
struct nfs_cb_data * data ;
2011-11-27 07:49:08 +04:00
uint64_t offset ;
uint64_t count ;
2014-04-01 01:40:26 +04:00
int update_pos ;
2011-02-06 07:45:09 +03:00
} ;
2014-06-08 20:45:22 +04:00
static int nfs_lookup_path_async_internal ( struct nfs_context * nfs , fattr3 * attr , struct nfs_cb_data * data , struct nfs_fh3 * fh ) ;
2011-02-06 07:45:09 +03:00
2012-07-05 04:23:19 +04:00
void nfs_set_auth ( struct nfs_context * nfs , struct AUTH * auth )
2011-02-06 07:45:09 +03:00
{
2011-08-28 13:25:20 +04:00
rpc_set_auth ( nfs - > rpc , auth ) ;
2011-02-06 07:45:09 +03:00
}
int nfs_get_fd ( struct nfs_context * nfs )
{
return rpc_get_fd ( nfs - > rpc ) ;
}
2011-09-11 15:32:48 +04:00
int nfs_queue_length ( struct nfs_context * nfs )
{
return rpc_queue_length ( nfs - > rpc ) ;
}
2011-02-06 07:45:09 +03:00
int nfs_which_events ( struct nfs_context * nfs )
{
return rpc_which_events ( nfs - > rpc ) ;
}
int nfs_service ( struct nfs_context * nfs , int revents )
{
return rpc_service ( nfs - > rpc , revents ) ;
}
char * nfs_get_error ( struct nfs_context * nfs )
{
return rpc_get_error ( nfs - > rpc ) ;
} ;
2013-12-26 21:08:26 +04:00
static int nfs_set_context_args ( struct nfs_context * nfs , char * arg , char * val )
2013-12-26 04:57:52 +04:00
{
2014-06-23 18:31:32 +04:00
if ( ! strcmp ( arg , " tcp-syncnt " ) ) {
2013-12-26 21:08:26 +04:00
rpc_set_tcp_syncnt ( nfs_get_rpc_context ( nfs ) , atoi ( val ) ) ;
2014-06-23 18:31:32 +04:00
} else if ( ! strcmp ( arg , " uid " ) ) {
2013-12-26 21:08:26 +04:00
rpc_set_uid ( nfs_get_rpc_context ( nfs ) , atoi ( val ) ) ;
2014-06-23 18:31:32 +04:00
} else if ( ! strcmp ( arg , " gid " ) ) {
2013-12-26 21:08:26 +04:00
rpc_set_gid ( nfs_get_rpc_context ( nfs ) , atoi ( val ) ) ;
2014-06-23 18:31:32 +04:00
} else if ( ! strcmp ( arg , " readahaed " ) ) {
rpc_set_readahead ( nfs_get_rpc_context ( nfs ) , atoi ( val ) ) ;
2013-12-26 04:57:52 +04:00
}
return 0 ;
}
2013-12-23 17:50:09 +04:00
static struct nfs_url * nfs_parse_url ( struct nfs_context * nfs , const char * url , int dir , int incomplete )
2013-12-23 17:03:00 +04:00
{
struct nfs_url * urls ;
char * strp , * flagsp , * strp2 ;
if ( strncmp ( url , " nfs:// " , 6 ) ) {
rpc_set_error ( nfs - > rpc , " Invalid URL specified " ) ;
return NULL ;
}
urls = malloc ( sizeof ( struct nfs_url ) ) ;
if ( urls = = NULL ) {
rpc_set_error ( nfs - > rpc , " Out of memory " ) ;
return NULL ;
}
2013-12-26 15:48:21 +04:00
memset ( urls , 0x00 , sizeof ( struct nfs_url ) ) ;
2013-12-23 17:03:00 +04:00
urls - > server = strdup ( url + 6 ) ;
if ( urls - > server = = NULL ) {
nfs_destroy_url ( urls ) ;
rpc_set_error ( nfs - > rpc , " Out of memory " ) ;
return NULL ;
}
if ( urls - > server [ 0 ] = = ' / ' | | urls - > server [ 0 ] = = ' \0 ' | |
urls - > server [ 0 ] = = ' ? ' ) {
if ( incomplete ) {
flagsp = strchr ( urls - > server , ' ? ' ) ;
goto flags ;
}
nfs_destroy_url ( urls ) ;
rpc_set_error ( nfs - > rpc , " Invalid server string " ) ;
return NULL ;
}
strp = strchr ( urls - > server , ' / ' ) ;
if ( strp = = NULL ) {
if ( incomplete ) {
flagsp = strchr ( urls - > server , ' ? ' ) ;
goto flags ;
}
nfs_destroy_url ( urls ) ;
rpc_set_error ( nfs - > rpc , " Incomplete or invalid URL specified. " ) ;
return NULL ;
}
urls - > path = strdup ( strp ) ;
if ( urls - > path = = NULL ) {
nfs_destroy_url ( urls ) ;
rpc_set_error ( nfs - > rpc , " Out of memory " ) ;
return NULL ;
}
* strp = 0 ;
if ( dir ) {
flagsp = strchr ( urls - > path , ' ? ' ) ;
goto flags ;
}
strp = strrchr ( urls - > path , ' / ' ) ;
if ( strp = = NULL ) {
if ( incomplete ) {
flagsp = strchr ( urls - > path , ' ? ' ) ;
goto flags ;
}
nfs_destroy_url ( urls ) ;
rpc_set_error ( nfs - > rpc , " Incomplete or invalid URL specified. " ) ;
return NULL ;
}
urls - > file = strdup ( strp ) ;
if ( urls - > path = = NULL ) {
nfs_destroy_url ( urls ) ;
rpc_set_error ( nfs - > rpc , " Out of memory " ) ;
return NULL ;
}
* strp = 0 ;
flagsp = strchr ( urls - > file , ' ? ' ) ;
flags :
if ( flagsp ) {
* flagsp = 0 ;
}
if ( urls - > file & & ! strlen ( urls - > file ) ) {
free ( urls - > file ) ;
urls - > file = NULL ;
if ( ! incomplete ) {
nfs_destroy_url ( urls ) ;
rpc_set_error ( nfs - > rpc , " Incomplete or invalid URL specified. " ) ;
return NULL ;
}
}
while ( flagsp ! = NULL & & * ( flagsp + 1 ) ! = 0 ) {
strp = flagsp + 1 ;
flagsp = strchr ( strp , ' & ' ) ;
if ( flagsp ) {
* flagsp = 0 ;
}
strp2 = strchr ( strp , ' = ' ) ;
if ( strp2 ) {
* strp2 = 0 ;
strp2 + + ;
2013-12-26 21:08:26 +04:00
nfs_set_context_args ( nfs , strp , strp2 ) ;
2013-12-23 17:03:00 +04:00
}
}
2013-12-26 13:43:15 +04:00
if ( urls - > server & & strlen ( urls - > server ) < = 1 ) {
free ( urls - > server ) ;
urls - > server = NULL ;
}
2013-12-23 17:03:00 +04:00
return urls ;
}
struct nfs_url * nfs_parse_url_full ( struct nfs_context * nfs , const char * url )
{
return nfs_parse_url ( nfs , url , 0 , 0 ) ;
}
struct nfs_url * nfs_parse_url_dir ( struct nfs_context * nfs , const char * url )
{
return nfs_parse_url ( nfs , url , 1 , 0 ) ;
}
struct nfs_url * nfs_parse_url_incomplete ( struct nfs_context * nfs , const char * url )
{
return nfs_parse_url ( nfs , url , 0 , 1 ) ;
}
void nfs_destroy_url ( struct nfs_url * url )
{
if ( url ) {
free ( url - > server ) ;
free ( url - > path ) ;
free ( url - > file ) ;
}
free ( url ) ;
}
2011-02-06 07:45:09 +03:00
struct nfs_context * nfs_init_context ( void )
{
struct nfs_context * nfs ;
nfs = malloc ( sizeof ( struct nfs_context ) ) ;
if ( nfs = = NULL ) {
return NULL ;
}
2014-01-28 08:54:14 +04:00
memset ( nfs , 0 , sizeof ( struct nfs_context ) ) ;
2011-02-06 07:45:09 +03:00
nfs - > rpc = rpc_init_context ( ) ;
if ( nfs - > rpc = = NULL ) {
free ( nfs ) ;
return NULL ;
}
2014-01-28 08:54:14 +04:00
nfs - > cwd = strdup ( " / " ) ;
2011-07-31 04:59:46 +04:00
2011-02-06 07:45:09 +03:00
return nfs ;
}
void nfs_destroy_context ( struct nfs_context * nfs )
{
rpc_destroy_context ( nfs - > rpc ) ;
nfs - > rpc = NULL ;
if ( nfs - > server ) {
free ( nfs - > server ) ;
nfs - > server = NULL ;
}
if ( nfs - > export ) {
free ( nfs - > export ) ;
nfs - > export = NULL ;
}
2014-01-28 08:54:14 +04:00
if ( nfs - > cwd ) {
free ( nfs - > cwd ) ;
nfs - > cwd = NULL ;
}
2011-02-06 07:45:09 +03:00
if ( nfs - > rootfh . data . data_val ! = NULL ) {
free ( nfs - > rootfh . data . data_val ) ;
nfs - > rootfh . data . data_val = NULL ;
}
2014-06-08 22:22:06 +04:00
while ( nfs - > dircache ) {
struct nfsdir * nfsdir = nfs - > dircache ;
LIBNFS_LIST_REMOVE ( & nfs - > dircache , nfsdir ) ;
nfs_free_nfsdir ( nfsdir ) ;
}
2011-02-06 07:45:09 +03:00
free ( nfs ) ;
}
2013-10-27 00:16:09 +04:00
struct rpc_cb_data {
char * server ;
uint32_t program ;
uint32_t version ;
rpc_cb cb ;
void * private_data ;
2014-01-01 04:11:11 +04:00
} ;
2013-10-27 00:16:09 +04:00
void free_rpc_cb_data ( struct rpc_cb_data * data )
{
free ( data - > server ) ;
data - > server = NULL ;
free ( data ) ;
}
2014-03-17 02:00:19 +04:00
static void rpc_connect_program_5_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
{
struct rpc_cb_data * data = private_data ;
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
/* Dont want any more callbacks even if the socket is closed */
rpc - > connect_cb = NULL ;
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( rpc , status , command_data , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( rpc , status , " Command was cancelled " , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
data - > cb ( rpc , status , NULL , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
}
2013-10-27 00:16:09 +04:00
static void rpc_connect_program_4_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
{
struct rpc_cb_data * data = private_data ;
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
/* Dont want any more callbacks even if the socket is closed */
rpc - > connect_cb = NULL ;
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( rpc , status , command_data , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( rpc , status , " Command was cancelled " , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
2014-03-17 02:00:19 +04:00
switch ( data - > program ) {
case MOUNT_PROGRAM :
if ( rpc_mount3_null_async ( rpc , rpc_connect_program_5_cb ,
data ) ! = 0 ) {
data - > cb ( rpc , status , command_data , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
return ;
case NFS_PROGRAM :
if ( rpc_nfs3_null_async ( rpc , rpc_connect_program_5_cb ,
data ) ! = 0 ) {
data - > cb ( rpc , status , command_data , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
return ;
}
2013-10-27 00:16:09 +04:00
data - > cb ( rpc , status , NULL , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
}
static void rpc_connect_program_3_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
{
struct rpc_cb_data * data = private_data ;
2014-03-18 08:29:32 +04:00
struct pmap3_string_result * gar ;
2014-03-17 04:48:35 +04:00
uint32_t rpc_port = 0 ;
unsigned char * ptr ;
2013-10-27 00:16:09 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2014-02-14 01:36:54 +04:00
if ( status = = RPC_STATUS_ERROR ) {
2013-10-27 00:16:09 +04:00
data - > cb ( rpc , status , command_data , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( rpc , status , " Command was cancelled " , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
2014-03-17 04:48:35 +04:00
switch ( rpc - > s . ss_family ) {
case AF_INET :
rpc_port = * ( uint32_t * ) command_data ;
break ;
case AF_INET6 :
/* ouch. portmapper and ipv6 are not great */
gar = command_data ;
if ( gar - > addr = = NULL ) {
break ;
}
ptr = strrchr ( gar - > addr , ' . ' ) ;
if ( ptr = = NULL ) {
break ;
}
rpc_port = atoi ( ptr + 1 ) ;
* ptr = 0 ;
ptr = strrchr ( gar - > addr , ' . ' ) ;
if ( ptr = = NULL ) {
break ;
}
rpc_port + = 256 * atoi ( ptr + 1 ) ;
break ;
}
2013-10-27 00:16:09 +04:00
if ( rpc_port = = 0 ) {
rpc_set_error ( rpc , " RPC error. Program is not available on %s " , data - > server ) ;
data - > cb ( rpc , RPC_STATUS_ERROR , rpc_get_error ( rpc ) , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
rpc_disconnect ( rpc , " normal disconnect " ) ;
if ( rpc_connect_async ( rpc , data - > server , rpc_port , rpc_connect_program_4_cb , data ) ! = 0 ) {
data - > cb ( rpc , status , command_data , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
}
static void rpc_connect_program_2_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
{
struct rpc_cb_data * data = private_data ;
2014-03-17 04:48:35 +04:00
struct pmap3_mapping map ;
2013-10-27 00:16:09 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( rpc , status , command_data , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( rpc , status , " Command was cancelled " , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
2014-03-17 04:48:35 +04:00
switch ( rpc - > s . ss_family ) {
case AF_INET :
if ( rpc_pmap2_getport_async ( rpc , data - > program , data - > version , IPPROTO_TCP , rpc_connect_program_3_cb , private_data ) ! = 0 ) {
data - > cb ( rpc , status , command_data , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
break ;
case AF_INET6 :
map . prog = data - > program ;
map . vers = data - > version ;
map . netid = " " ;
map . addr = " " ;
map . owner = " " ;
if ( rpc_pmap3_getaddr_async ( rpc , & map , rpc_connect_program_3_cb , private_data ) ! = 0 ) {
data - > cb ( rpc , status , command_data , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
break ;
2013-10-27 00:16:09 +04:00
}
}
static void rpc_connect_program_1_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
{
struct rpc_cb_data * data = private_data ;
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
/* Dont want any more callbacks even if the socket is closed */
rpc - > connect_cb = NULL ;
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( rpc , status , command_data , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( rpc , status , " Command was cancelled " , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
2014-03-17 04:48:35 +04:00
switch ( rpc - > s . ss_family ) {
case AF_INET :
if ( rpc_pmap2_null_async ( rpc , rpc_connect_program_2_cb , data ) ! = 0 ) {
data - > cb ( rpc , status , command_data , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
break ;
case AF_INET6 :
if ( rpc_pmap3_null_async ( rpc , rpc_connect_program_2_cb , data ) ! = 0 ) {
data - > cb ( rpc , status , command_data , data - > private_data ) ;
free_rpc_cb_data ( data ) ;
return ;
}
break ;
2013-10-27 00:16:09 +04:00
}
}
2014-03-17 02:00:19 +04:00
int rpc_connect_program_async ( struct rpc_context * rpc , const char * server , int program , int version , rpc_cb cb , void * private_data )
2013-10-27 00:16:09 +04:00
{
struct rpc_cb_data * data ;
data = malloc ( sizeof ( struct rpc_cb_data ) ) ;
if ( data = = NULL ) {
return - 1 ;
}
memset ( data , 0 , sizeof ( struct rpc_cb_data ) ) ;
data - > server = strdup ( server ) ;
data - > program = program ;
data - > version = version ;
data - > cb = cb ;
data - > private_data = private_data ;
if ( rpc_connect_async ( rpc , server , 111 , rpc_connect_program_1_cb , data ) ! = 0 ) {
rpc_set_error ( rpc , " Failed to start connection " ) ;
free_rpc_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
2014-02-18 02:34:18 +04:00
static void free_nfs_cb_data ( struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
if ( data - > continue_data ! = NULL ) {
2014-02-18 02:29:07 +04:00
assert ( data - > free_continue_data ) ;
2011-02-06 07:45:09 +03:00
data - > free_continue_data ( data - > continue_data ) ;
}
2014-02-18 02:34:18 +04:00
free ( data - > saved_path ) ;
free ( data - > fh . data . data_val ) ;
free ( data - > buffer ) ;
2011-06-19 02:43:28 +04:00
2011-02-06 07:45:09 +03:00
free ( data ) ;
}
2014-07-20 11:07:46 +04:00
static void free_nfsfh ( struct nfsfh * nfsfh )
{
if ( nfsfh - > fh . data . data_val ! = NULL ) {
free ( nfsfh - > fh . data . data_val ) ;
nfsfh - > fh . data . data_val = NULL ;
}
free ( nfsfh - > ra . buf ) ;
free ( nfsfh ) ;
}
2011-02-06 07:45:09 +03:00
2012-11-24 20:18:54 +04:00
static void nfs_mount_10_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
data - > cb ( 0 , nfs , NULL , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2011-05-31 18:08:29 +04:00
static void nfs_mount_9_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
2011-05-31 18:08:29 +04:00
FSINFO3res * res = command_data ;
2013-12-24 23:16:21 +04:00
struct GETATTR3args args ;
2011-02-06 07:45:09 +03:00
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
2011-05-31 18:08:29 +04:00
nfs - > readmax = res - > FSINFO3res_u . resok . rtmax ;
nfs - > writemax = res - > FSINFO3res_u . resok . wtmax ;
2011-02-06 07:45:09 +03:00
2013-12-24 23:16:21 +04:00
memset ( & args , 0 , sizeof ( GETATTR3args ) ) ;
2014-01-01 04:11:11 +04:00
args . object = nfs - > rootfh ;
2013-12-24 23:16:21 +04:00
if ( rpc_nfs3_getattr_async ( rpc , nfs_mount_10_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
data - > cb ( - ENOMEM , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
}
2011-05-31 18:08:29 +04:00
static void nfs_mount_8_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
{
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
2014-01-01 03:06:25 +04:00
struct FSINFO3args args ;
2011-05-31 18:08:29 +04:00
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-05-31 18:08:29 +04:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
2014-07-19 14:32:40 +04:00
/* NFS TCP connections we want to autoreconnect after sessions are torn down (due to inactivity or error) */
rpc_set_autoreconnect ( rpc ) ;
2014-01-01 03:06:25 +04:00
args . fsroot = nfs - > rootfh ;
if ( rpc_nfs3_fsinfo_async ( rpc , nfs_mount_9_cb , & args , data ) ! = 0 ) {
2011-05-31 18:08:29 +04:00
data - > cb ( - ENOMEM , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
}
2011-02-06 07:45:09 +03:00
static void nfs_mount_6_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
{
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
mountres3 * res ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > fhs_status ! = MNT3_OK ) {
rpc_set_error ( rpc , " RPC error: Mount failed with error %s(%d) %s(%d) " , mountstat3_to_str ( res - > fhs_status ) , res - > fhs_status , strerror ( - mountstat3_to_errno ( res - > fhs_status ) ) , - mountstat3_to_errno ( res - > fhs_status ) ) ;
data - > cb ( mountstat3_to_errno ( res - > fhs_status ) , nfs , rpc_get_error ( rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
nfs - > rootfh . data . data_len = res - > mountres3_u . mountinfo . fhandle . fhandle3_len ;
nfs - > rootfh . data . data_val = malloc ( nfs - > rootfh . data . data_len ) ;
if ( nfs - > rootfh . data . data_val = = NULL ) {
rpc_set_error ( rpc , " Out of memory. Could not allocate memory to store root filehandle " ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
memcpy ( nfs - > rootfh . data . data_val , res - > mountres3_u . mountinfo . fhandle . fhandle3_val , nfs - > rootfh . data . data_len ) ;
rpc_disconnect ( rpc , " normal disconnect " ) ;
2014-03-17 02:00:19 +04:00
if ( rpc_connect_program_async ( nfs - > rpc , nfs - > server , NFS_PROGRAM , NFS_V3 , nfs_mount_8_cb , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
data - > cb ( - ENOMEM , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
}
static void nfs_mount_5_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
{
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
2013-12-26 21:11:05 +04:00
if ( rpc_mount3_mnt_async ( rpc , nfs_mount_6_cb , nfs - > export , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
data - > cb ( - ENOMEM , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
}
/*
* Async call for mounting an nfs share and geting the root filehandle
*/
int nfs_mount_async ( struct nfs_context * nfs , const char * server , const char * export , nfs_cb cb , void * private_data )
{
struct nfs_cb_data * data ;
2011-07-31 04:46:34 +04:00
char * new_server , * new_export ;
2011-02-06 07:45:09 +03:00
data = malloc ( sizeof ( struct nfs_cb_data ) ) ;
if ( data = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " out of memory. failed to allocate memory for nfs mount data " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
2011-09-03 08:11:22 +04:00
memset ( data , 0 , sizeof ( struct nfs_cb_data ) ) ;
2011-07-31 04:46:34 +04:00
new_server = strdup ( server ) ;
new_export = strdup ( export ) ;
if ( nfs - > server ! = NULL ) {
free ( nfs - > server ) ;
}
nfs - > server = new_server ;
if ( nfs - > export ! = NULL ) {
free ( nfs - > export ) ;
}
nfs - > export = new_export ;
2011-02-06 07:45:09 +03:00
data - > nfs = nfs ;
data - > cb = cb ;
data - > private_data = private_data ;
2014-03-17 02:00:19 +04:00
if ( rpc_connect_program_async ( nfs - > rpc , server , MOUNT_PROGRAM , MOUNT_V3 , nfs_mount_5_cb , data ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Failed to start connection " ) ;
2011-02-06 07:45:09 +03:00
free_nfs_cb_data ( data ) ;
2011-06-19 03:03:04 +04:00
return - 1 ;
2011-02-06 07:45:09 +03:00
}
return 0 ;
}
/*
* Functions to first look up a path , component by component , and then finally call a specific function once
* the filehandle for the final component is found .
*/
2012-11-24 20:18:54 +04:00
static void nfs_lookup_path_1_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
LOOKUP3res * res ;
2014-06-08 20:45:22 +04:00
fattr3 * attr ;
2011-02-06 07:45:09 +03:00
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: Lookup of %s failed with %s(%d) " , data - > saved_path , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
2014-06-08 20:45:22 +04:00
attr = res - > LOOKUP3res_u . resok . obj_attributes . attributes_follow ?
& res - > LOOKUP3res_u . resok . obj_attributes . post_op_attr_u . attributes :
NULL ;
/* This function will always invoke the callback and cleanup
* for failures . So no need to check the return value .
*/
nfs_lookup_path_async_internal ( nfs , attr , data , & res - > LOOKUP3res_u . resok . object ) ;
2011-02-06 07:45:09 +03:00
}
2014-06-08 20:45:22 +04:00
static int nfs_lookup_path_async_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data , struct nfs_fh3 * fh )
2011-02-06 07:45:09 +03:00
{
2014-01-28 08:54:14 +04:00
char * path , * slash ;
2013-12-24 23:16:21 +04:00
LOOKUP3args args ;
2011-02-06 07:45:09 +03:00
while ( * data - > path = = ' / ' ) {
data - > path + + ;
}
path = data - > path ;
2014-01-28 08:54:14 +04:00
slash = strchr ( path , ' / ' ) ;
if ( slash ! = NULL ) {
/* Clear slash so that path is a zero terminated string for
* the current path component . Set it back to ' / ' again later
* when we are finished referencing this component so that
* data - > saved_path will still point to the full
* normalized path .
*/
* slash = 0 ;
data - > path = slash + 1 ;
2011-02-06 07:45:09 +03:00
} else {
while ( * data - > path ! = 0 ) {
data - > path + + ;
}
}
if ( * path = = 0 ) {
data - > fh . data . data_len = fh - > data . data_len ;
data - > fh . data . data_val = malloc ( data - > fh . data . data_len ) ;
if ( data - > fh . data . data_val = = NULL ) {
rpc_set_error ( nfs - > rpc , " Out of memory: Failed to allocate fh for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
memcpy ( data - > fh . data . data_val , fh - > data . data_val , data - > fh . data . data_len ) ;
2014-01-28 08:54:14 +04:00
if ( slash ! = NULL ) {
* slash = ' / ' ;
}
2014-06-08 20:45:22 +04:00
data - > continue_cb ( nfs , attr , data ) ;
2011-02-06 07:45:09 +03:00
return 0 ;
}
2013-12-24 23:16:21 +04:00
memset ( & args , 0 , sizeof ( LOOKUP3args ) ) ;
2014-01-01 04:11:11 +04:00
args . what . dir = * fh ;
args . what . name = path ;
2013-12-24 23:16:21 +04:00
if ( rpc_nfs3_lookup_async ( nfs - > rpc , nfs_lookup_path_1_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send lookup call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
2014-01-28 08:54:14 +04:00
if ( slash ! = NULL ) {
* slash = ' / ' ;
}
return 0 ;
}
static int nfs_normalize_path ( struct nfs_context * nfs , char * path )
{
char * str ;
int len ;
/* // -> / */
2014-02-14 01:36:54 +04:00
while ( ( str = strstr ( path , " // " ) ) ) {
2014-01-28 08:54:14 +04:00
while ( * str ) {
* str = * ( str + 1 ) ;
str + + ;
}
}
/* /./ -> / */
2014-02-14 01:36:54 +04:00
while ( ( str = strstr ( path , " /./ " ) ) ) {
2014-01-28 08:54:14 +04:00
while ( * ( str + 1 ) ) {
* str = * ( str + 2 ) ;
str + + ;
}
}
/* ^/../ -> error */
if ( ! strncmp ( path , " /../ " , 4 ) ) {
rpc_set_error ( nfs - > rpc ,
" Absolute path starts with '/../' "
" during normalization " ) ;
return - 1 ;
}
/* ^[^/] -> error */
if ( path [ 0 ] ! = ' / ' ) {
rpc_set_error ( nfs - > rpc ,
" Absolute path does not start with '/' " ) ;
return - 1 ;
}
/* /string/../ -> / */
2014-02-14 01:36:54 +04:00
while ( ( str = strstr ( path , " /../ " ) ) ) {
2014-01-28 08:54:14 +04:00
char * tmp ;
if ( ! strncmp ( path , " /../ " , 4 ) ) {
rpc_set_error ( nfs - > rpc ,
" Absolute path starts with '/../' "
" during normalization " ) ;
return - 1 ;
}
tmp = str - 1 ;
while ( * tmp ! = ' / ' ) {
tmp - - ;
}
str + = 3 ;
while ( ( * ( tmp + + ) = * ( str + + ) ) ! = ' \0 ' )
;
}
/* /$ -> \0 */
len = strlen ( path ) ;
2014-03-10 00:55:42 +04:00
if ( len > 1 ) {
2014-01-28 08:54:14 +04:00
if ( path [ len - 1 ] = = ' / ' ) {
path [ len - 1 ] = ' \0 ' ;
len - - ;
}
}
if ( path [ 0 ] = = ' \0 ' ) {
rpc_set_error ( nfs - > rpc ,
" Absolute path became '' "
" during normalization " ) ;
return - 1 ;
}
/* /.$ -> \0 */
if ( len > = 2 ) {
if ( ! strcmp ( & path [ len - 2 ] , " /. " ) ) {
path [ len - 2 ] = ' \0 ' ;
len - = 2 ;
}
}
/* ^/..$ -> error */
if ( ! strcmp ( path , " /.. " ) ) {
rpc_set_error ( nfs - > rpc ,
" Absolute path is '/..' "
" during normalization " ) ;
return - 1 ;
}
/* /string/..$ -> / */
if ( len > = 3 ) {
if ( ! strcmp ( & path [ len - 3 ] , " /.. " ) ) {
char * tmp = & path [ len - 3 ] ;
while ( * - - tmp ! = ' / ' )
;
2014-02-14 01:36:54 +04:00
* tmp = ' \0 ' ;
2014-01-28 08:54:14 +04:00
}
}
2011-02-06 07:45:09 +03:00
return 0 ;
}
2014-06-08 20:45:22 +04:00
static void nfs_lookup_path_getattr_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
{
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
GETATTR3res * res ;
fattr3 * attr ;
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: GETATTR of %s failed with %s(%d) " , data - > saved_path , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
attr = & res - > GETATTR3res_u . resok . obj_attributes ;
/* This function will always invoke the callback and cleanup
* for failures . So no need to check the return value .
*/
nfs_lookup_path_async_internal ( nfs , attr , data , & nfs - > rootfh ) ;
}
2011-02-06 07:45:09 +03:00
static int nfs_lookuppath_async ( struct nfs_context * nfs , const char * path , nfs_cb cb , void * private_data , continue_func continue_cb , void * continue_data , void ( * free_continue_data ) ( void * ) , int continue_int )
{
struct nfs_cb_data * data ;
2014-06-08 20:45:22 +04:00
struct GETATTR3args args ;
2011-02-06 07:45:09 +03:00
2014-01-28 08:54:14 +04:00
if ( path [ 0 ] = = ' \0 ' ) {
2014-02-01 20:03:12 +04:00
path = " . " ;
2011-02-06 07:45:09 +03:00
}
data = malloc ( sizeof ( struct nfs_cb_data ) ) ;
if ( data = = NULL ) {
2014-01-28 08:54:14 +04:00
rpc_set_error ( nfs - > rpc , " out of memory: failed to allocate "
" nfs_cb_data structure " ) ;
2014-02-18 02:06:32 +04:00
if ( free_continue_data )
free_continue_data ( continue_data ) ;
2011-06-19 03:03:04 +04:00
return - 1 ;
2011-02-06 07:45:09 +03:00
}
2011-09-03 08:11:22 +04:00
memset ( data , 0 , sizeof ( struct nfs_cb_data ) ) ;
2011-02-06 07:45:09 +03:00
data - > nfs = nfs ;
data - > cb = cb ;
data - > continue_cb = continue_cb ;
data - > continue_data = continue_data ;
data - > free_continue_data = free_continue_data ;
data - > continue_int = continue_int ;
data - > private_data = private_data ;
2014-01-28 08:54:14 +04:00
if ( path [ 0 ] = = ' / ' ) {
data - > saved_path = strdup ( path ) ;
} else {
data - > saved_path = malloc ( strlen ( path ) + strlen ( nfs - > cwd ) + 2 ) ;
if ( data - > saved_path = = NULL ) {
rpc_set_error ( nfs - > rpc , " out of memory: failed to "
" malloc path string " ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
sprintf ( data - > saved_path , " %s/%s " , nfs - > cwd , path ) ;
}
2011-02-06 07:45:09 +03:00
if ( data - > saved_path = = NULL ) {
rpc_set_error ( nfs - > rpc , " out of memory: failed to copy path string " ) ;
free_nfs_cb_data ( data ) ;
2011-06-19 03:03:04 +04:00
return - 1 ;
2011-02-06 07:45:09 +03:00
}
2014-01-28 08:54:14 +04:00
if ( nfs_normalize_path ( nfs , data - > saved_path ) ! = 0 ) {
free_nfs_cb_data ( data ) ;
return - 1 ;
}
2011-02-06 07:45:09 +03:00
data - > path = data - > saved_path ;
2014-06-08 20:45:22 +04:00
if ( data - > path [ 0 ] ) {
/* This function will always invoke the callback and cleanup
* for failures . So no need to check the return value .
*/
nfs_lookup_path_async_internal ( nfs , NULL , data , & nfs - > rootfh ) ;
2011-02-06 07:45:09 +03:00
return 0 ;
}
2014-06-08 20:45:22 +04:00
/* We have a request for "", so just perform a GETATTR3 so we can
* return the attributes to the caller .
*/
memset ( & args , 0 , sizeof ( GETATTR3args ) ) ;
args . object = nfs - > rootfh ;
if ( rpc_nfs3_getattr_async ( nfs - > rpc , nfs_lookup_path_getattr_cb , & args , data ) ! = 0 ) {
free_nfs_cb_data ( data ) ;
return - 1 ;
}
2011-02-06 07:45:09 +03:00
return 0 ;
}
/*
* Async stat ( )
*/
2012-11-24 20:18:54 +04:00
static void nfs_stat_1_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
GETATTR3res * res ;
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
2014-01-12 17:42:56 +04:00
# ifdef WIN32
struct __stat64 st ;
# else
2011-02-06 07:45:09 +03:00
struct stat st ;
2014-01-12 17:42:56 +04:00
# endif
2011-02-06 07:45:09 +03:00
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: GETATTR of %s failed with %s(%d) " , data - > saved_path , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
st . st_dev = - 1 ;
st . st_ino = res - > GETATTR3res_u . resok . obj_attributes . fileid ;
st . st_mode = res - > GETATTR3res_u . resok . obj_attributes . mode ;
2011-06-19 19:02:48 +04:00
if ( res - > GETATTR3res_u . resok . obj_attributes . type = = NF3DIR ) {
st . st_mode | = S_IFDIR ;
}
2011-12-05 06:54:21 +04:00
if ( res - > GETATTR3res_u . resok . obj_attributes . type = = NF3REG ) {
st . st_mode | = S_IFREG ;
}
2011-02-06 07:45:09 +03:00
st . st_nlink = res - > GETATTR3res_u . resok . obj_attributes . nlink ;
st . st_uid = res - > GETATTR3res_u . resok . obj_attributes . uid ;
st . st_gid = res - > GETATTR3res_u . resok . obj_attributes . gid ;
st . st_rdev = 0 ;
st . st_size = res - > GETATTR3res_u . resok . obj_attributes . size ;
2011-09-01 23:35:54 +04:00
# ifndef WIN32
2014-06-23 18:31:32 +04:00
st . st_blksize = NFS_BLKSIZE ;
st . st_blocks = res - > GETATTR3res_u . resok . obj_attributes . size / NFS_BLKSIZE ;
2014-02-14 01:36:54 +04:00
# endif //WIN32
2011-02-06 07:45:09 +03:00
st . st_atime = res - > GETATTR3res_u . resok . obj_attributes . atime . seconds ;
st . st_mtime = res - > GETATTR3res_u . resok . obj_attributes . mtime . seconds ;
st . st_ctime = res - > GETATTR3res_u . resok . obj_attributes . ctime . seconds ;
data - > cb ( 0 , nfs , & st , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-06-08 20:45:22 +04:00
static int nfs_stat_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
2013-12-24 23:16:21 +04:00
struct GETATTR3args args ;
memset ( & args , 0 , sizeof ( GETATTR3args ) ) ;
2014-01-01 04:11:11 +04:00
args . object = data - > fh ;
2013-12-24 23:16:21 +04:00
if ( rpc_nfs3_getattr_async ( nfs - > rpc , nfs_stat_1_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send STAT GETATTR call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
int nfs_stat_async ( struct nfs_context * nfs , const char * path , nfs_cb cb , void * private_data )
{
if ( nfs_lookuppath_async ( nfs , path , cb , private_data , nfs_stat_continue_internal , NULL , NULL , 0 ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
return 0 ;
}
2014-03-05 07:40:05 +04:00
/*
* Async nfs_stat64 ( )
*/
static void nfs_stat64_1_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
{
GETATTR3res * res ;
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
struct nfs_stat_64 st ;
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: GETATTR of %s failed with %s(%d) " , data - > saved_path , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
st . nfs_dev = - 1 ;
st . nfs_ino = res - > GETATTR3res_u . resok . obj_attributes . fileid ;
st . nfs_mode = res - > GETATTR3res_u . resok . obj_attributes . mode ;
if ( res - > GETATTR3res_u . resok . obj_attributes . type = = NF3DIR ) {
st . nfs_mode | = S_IFDIR ;
}
if ( res - > GETATTR3res_u . resok . obj_attributes . type = = NF3REG ) {
st . nfs_mode | = S_IFREG ;
}
st . nfs_nlink = res - > GETATTR3res_u . resok . obj_attributes . nlink ;
st . nfs_uid = res - > GETATTR3res_u . resok . obj_attributes . uid ;
st . nfs_gid = res - > GETATTR3res_u . resok . obj_attributes . gid ;
st . nfs_rdev = 0 ;
st . nfs_size = res - > GETATTR3res_u . resok . obj_attributes . size ;
st . nfs_atime = res - > GETATTR3res_u . resok . obj_attributes . atime . seconds ;
st . nfs_mtime = res - > GETATTR3res_u . resok . obj_attributes . mtime . seconds ;
st . nfs_ctime = res - > GETATTR3res_u . resok . obj_attributes . ctime . seconds ;
data - > cb ( 0 , nfs , & st , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-06-08 20:45:22 +04:00
static int nfs_stat64_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2014-03-05 07:40:05 +04:00
{
struct GETATTR3args args ;
memset ( & args , 0 , sizeof ( GETATTR3args ) ) ;
args . object = data - > fh ;
if ( rpc_nfs3_getattr_async ( nfs - > rpc , nfs_stat64_1_cb , & args , data ) ! = 0 ) {
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send STAT GETATTR call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
int nfs_stat64_async ( struct nfs_context * nfs , const char * path , nfs_cb cb , void * private_data )
{
if ( nfs_lookuppath_async ( nfs , path , cb , private_data , nfs_stat64_continue_internal , NULL , NULL , 0 ) ! = 0 ) {
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
return - 1 ;
}
return 0 ;
}
2011-02-06 07:45:09 +03:00
/*
* Async open ( )
*/
2014-02-03 00:16:07 +04:00
static void nfs_open_trunc_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
{
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
2014-02-03 05:39:04 +04:00
struct nfsfh * nfsfh ;
2014-02-03 00:16:07 +04:00
SETATTR3res * res ;
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: Setattr failed with %s(%d) " , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
2014-02-03 05:39:04 +04:00
nfsfh = malloc ( sizeof ( struct nfsfh ) ) ;
if ( nfsfh = = NULL ) {
rpc_set_error ( nfs - > rpc , " NFS: Failed to allocate nfsfh structure " ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
memset ( nfsfh , 0 , sizeof ( struct nfsfh ) ) ;
if ( data - > continue_int & O_SYNC ) {
nfsfh - > is_sync = 1 ;
}
2014-04-18 20:32:01 +04:00
if ( data - > continue_int & O_APPEND ) {
nfsfh - > is_append = 1 ;
}
2014-02-03 05:39:04 +04:00
/* steal the filehandle */
nfsfh - > fh = data - > fh ;
data - > fh . data . data_val = NULL ;
data - > cb ( 0 , nfs , nfsfh , data - > private_data ) ;
2014-02-03 00:16:07 +04:00
free_nfs_cb_data ( data ) ;
}
2012-11-24 20:18:54 +04:00
static void nfs_open_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
ACCESS3res * res ;
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
struct nfsfh * nfsfh ;
unsigned int nfsmode = 0 ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: ACCESS of %s failed with %s(%d) " , data - > saved_path , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( data - > continue_int & O_WRONLY ) {
nfsmode | = ACCESS3_MODIFY ;
}
if ( data - > continue_int & O_RDWR ) {
nfsmode | = ACCESS3_READ | ACCESS3_MODIFY ;
}
if ( ! ( data - > continue_int & ( O_WRONLY | O_RDWR ) ) ) {
nfsmode | = ACCESS3_READ ;
}
if ( res - > ACCESS3res_u . resok . access ! = nfsmode ) {
rpc_set_error ( nfs - > rpc , " NFS: ACCESS denied. Required access %c%c%c. Allowed access %c%c%c " ,
nfsmode & ACCESS3_READ ? ' r ' : ' - ' ,
nfsmode & ACCESS3_MODIFY ? ' w ' : ' - ' ,
nfsmode & ACCESS3_EXECUTE ? ' x ' : ' - ' ,
res - > ACCESS3res_u . resok . access & ACCESS3_READ ? ' r ' : ' - ' ,
res - > ACCESS3res_u . resok . access & ACCESS3_MODIFY ? ' w ' : ' - ' ,
res - > ACCESS3res_u . resok . access & ACCESS3_EXECUTE ? ' x ' : ' - ' ) ;
data - > cb ( - EACCES , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
2014-02-03 00:16:07 +04:00
/* Try to truncate it if we were requested to */
if ( ( data - > continue_int & O_TRUNC ) & &
( data - > continue_int & ( O_RDWR | O_WRONLY ) ) ) {
SETATTR3args args ;
memset ( & args , 0 , sizeof ( SETATTR3args ) ) ;
2014-02-03 05:39:04 +04:00
args . object = data - > fh ;
2014-02-03 00:16:07 +04:00
args . new_attributes . size . set_it = 1 ;
args . new_attributes . size . set_size3_u . size = 0 ;
if ( rpc_nfs3_setattr_async ( nfs - > rpc , nfs_open_trunc_cb , & args ,
data ) ! = 0 ) {
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send "
" SETATTR call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) ,
data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
return ;
}
2014-02-03 05:39:04 +04:00
nfsfh = malloc ( sizeof ( struct nfsfh ) ) ;
if ( nfsfh = = NULL ) {
rpc_set_error ( nfs - > rpc , " NFS: Failed to allocate nfsfh structure " ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
memset ( nfsfh , 0 , sizeof ( struct nfsfh ) ) ;
if ( data - > continue_int & O_SYNC ) {
nfsfh - > is_sync = 1 ;
}
2014-04-18 20:32:01 +04:00
if ( data - > continue_int & O_APPEND ) {
nfsfh - > is_append = 1 ;
}
2014-02-03 05:39:04 +04:00
/* steal the filehandle */
nfsfh - > fh = data - > fh ;
data - > fh . data . data_val = NULL ;
2011-02-06 07:45:09 +03:00
data - > cb ( 0 , nfs , nfsfh , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-06-08 20:45:22 +04:00
static int nfs_open_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
int nfsmode = 0 ;
2013-12-24 23:16:21 +04:00
ACCESS3args args ;
2011-02-06 07:45:09 +03:00
if ( data - > continue_int & O_WRONLY ) {
nfsmode | = ACCESS3_MODIFY ;
}
if ( data - > continue_int & O_RDWR ) {
nfsmode | = ACCESS3_READ | ACCESS3_MODIFY ;
}
if ( ! ( data - > continue_int & ( O_WRONLY | O_RDWR ) ) ) {
nfsmode | = ACCESS3_READ ;
}
2013-12-24 23:16:21 +04:00
memset ( & args , 0 , sizeof ( ACCESS3args ) ) ;
2014-01-01 04:11:11 +04:00
args . object = data - > fh ;
2013-12-24 23:16:21 +04:00
args . access = nfsmode ;
if ( rpc_nfs3_access_async ( nfs - > rpc , nfs_open_cb , & args , data ) ! = 0 ) {
2014-02-03 00:16:07 +04:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send OPEN ACCESS "
" call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) ,
data - > private_data ) ;
2011-02-06 07:45:09 +03:00
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
2014-02-02 23:41:22 +04:00
int nfs_open_async ( struct nfs_context * nfs , const char * path , int flags , nfs_cb cb , void * private_data )
2011-02-06 07:45:09 +03:00
{
2014-02-02 23:41:22 +04:00
if ( nfs_lookuppath_async ( nfs , path , cb , private_data , nfs_open_continue_internal , NULL , NULL , flags ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
return - 1 ;
2011-02-06 07:45:09 +03:00
}
return 0 ;
}
2014-01-28 08:54:14 +04:00
/*
* Async chdir ( )
*/
2014-06-08 20:45:22 +04:00
static int nfs_chdir_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2014-01-28 08:54:14 +04:00
{
/* steal saved_path */
free ( nfs - > cwd ) ;
nfs - > cwd = data - > saved_path ;
data - > saved_path = NULL ;
2011-02-06 07:45:09 +03:00
2014-01-28 08:54:14 +04:00
data - > cb ( 0 , nfs , NULL , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return 0 ;
}
int nfs_chdir_async ( struct nfs_context * nfs , const char * path , nfs_cb cb , void * private_data )
{
if ( nfs_lookuppath_async ( nfs , path , cb , private_data , nfs_chdir_continue_internal , NULL , NULL , 0 ) ! = 0 ) {
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
return - 1 ;
}
return 0 ;
}
2011-02-06 07:45:09 +03:00
/*
* Async pread ( )
*/
2014-03-15 20:05:44 +04:00
static void nfs_fill_READ3args ( READ3args * args , struct nfsfh * fh , uint64_t offset , uint64_t count )
{
memset ( args , 0 , sizeof ( READ3args ) ) ;
args - > file = fh - > fh ;
args - > offset = offset ;
args - > count = count ;
}
2012-11-24 20:18:54 +04:00
static void nfs_pread_mcb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-06-19 02:43:28 +04:00
{
struct nfs_mcb_data * mdata = private_data ;
struct nfs_cb_data * data = mdata - > data ;
struct nfs_context * nfs = data - > nfs ;
READ3res * res ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-06-19 02:43:28 +04:00
data - > num_calls - - ;
if ( status = = RPC_STATUS_ERROR ) {
/* flag the failure but do not invoke callback until we have received all responses */
data - > error = 1 ;
}
if ( status = = RPC_STATUS_CANCEL ) {
/* flag the cancellation but do not invoke callback until we have received all responses */
data - > cancel = 1 ;
}
if ( status = = RPC_STATUS_SUCCESS ) {
res = command_data ;
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 ;
2014-04-01 01:40:26 +04:00
} else {
uint64_t count = res - > READ3res_u . resok . count ;
if ( mdata - > update_pos )
data - > nfsfh - > offset + = count ;
2014-03-16 23:15:48 +04:00
/* if we have more than one call or we have received a short read we need a reassembly buffer */
2014-04-01 01:40:26 +04:00
if ( data - > num_calls | | ( count < mdata - > count & & ! res - > READ3res_u . resok . eof ) ) {
2014-03-16 23:15:48 +04:00
if ( data - > buffer = = NULL ) {
2014-06-23 18:31:32 +04:00
data - > buffer = malloc ( data - > count ) ;
2014-03-16 23:15:48 +04:00
if ( data - > buffer = = NULL ) {
2014-06-23 18:31:32 +04:00
rpc_set_error ( nfs - > rpc , " Out-Of-Memory: Failed to allocate reassembly buffer for %d bytes " , ( int ) data - > count ) ;
2014-03-16 23:15:48 +04:00
data - > oom = 1 ;
}
}
}
2014-04-01 01:40:26 +04:00
if ( count > 0 ) {
if ( count < = mdata - > count ) {
2014-03-16 23:15:48 +04:00
/* copy data into reassembly buffer if we have one */
if ( data - > buffer ! = NULL ) {
2014-06-23 18:31:32 +04:00
memcpy ( & data - > buffer [ mdata - > offset - data - > offset ] , res - > READ3res_u . resok . data . data_val , count ) ;
2014-03-16 23:15:48 +04:00
}
2014-04-01 01:40:26 +04:00
if ( data - > max_offset < mdata - > offset + count ) {
data - > max_offset = mdata - > offset + count ;
2014-03-15 17:20:29 +04:00
}
} else {
rpc_set_error ( nfs - > rpc , " NFS: Read overflow. Server has sent more data than requested! " ) ;
data - > error = 1 ;
2011-06-21 00:07:29 +04:00
}
2011-06-19 02:43:28 +04:00
}
2014-03-16 23:15:48 +04:00
/* check if we have received a short read */
2014-04-01 01:40:26 +04:00
if ( count < mdata - > count & & ! res - > READ3res_u . resok . eof ) {
if ( count = = 0 ) {
2014-03-16 23:15:48 +04:00
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 ;
2014-04-01 01:40:26 +04:00
mdata - > offset + = count ;
mdata - > count - = count ;
2014-03-16 23:15:48 +04:00
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 ;
} else {
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send READ call for %s " , data - > path ) ;
2014-03-15 20:11:27 +04:00
data - > oom = 1 ;
2014-03-16 23:15:48 +04:00
}
}
}
2011-06-19 02:43:28 +04:00
}
}
2014-03-16 23:15:48 +04:00
free ( mdata ) ;
2011-06-19 02:43:28 +04:00
if ( data - > num_calls > 0 ) {
/* still waiting for more replies */
return ;
}
2014-03-16 23:15:48 +04:00
if ( data - > oom ! = 0 ) {
data - > cb ( - ENOMEM , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
2011-06-19 02:43:28 +04:00
if ( data - > error ! = 0 ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( data - > cancel ! = 0 ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
2014-03-16 23:15:48 +04:00
if ( data - > buffer ) {
2014-06-23 18:31:32 +04:00
if ( data - > max_offset > data - > org_offset + data - > org_count ) {
data - > max_offset = data - > org_offset + data - > org_count ;
}
data - > cb ( data - > max_offset - data - > org_offset , nfs , data - > buffer + ( data - > org_offset - data - > offset ) , data - > private_data ) ;
2014-03-16 23:15:48 +04:00
} else {
data - > cb ( res - > READ3res_u . resok . count , nfs , res - > READ3res_u . resok . data . data_val , data - > private_data ) ;
}
2011-06-25 06:23:52 +04:00
2014-06-23 18:31:32 +04:00
data - > nfsfh - > ra . fh_offset = data - > max_offset ;
if ( data - > nfsfh - > ra . cur_ra ) {
free ( data - > nfsfh - > ra . buf ) ;
data - > nfsfh - > ra . buf = data - > buffer ;
data - > nfsfh - > ra . buf_offset = data - > offset ;
data - > nfsfh - > ra . buf_count = data - > count ;
data - > nfsfh - > ra . buf_ts = time ( NULL ) ;
data - > buffer = NULL ;
}
2011-06-19 02:43:28 +04:00
free_nfs_cb_data ( data ) ;
}
2014-06-23 18:31:32 +04:00
static void nfs_ra_invalidate ( struct nfsfh * nfsfh ) {
free ( nfsfh - > ra . buf ) ;
nfsfh - > ra . buf = NULL ;
nfsfh - > ra . buf_offset = 0 ;
nfsfh - > ra . buf_count = 0 ;
nfsfh - > ra . buf_ts = time ( NULL ) ;
nfsfh - > ra . cur_ra = NFS_BLKSIZE ;
}
2014-04-01 01:40:26 +04:00
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 )
2011-02-06 07:45:09 +03:00
{
struct nfs_cb_data * data ;
data = malloc ( sizeof ( struct nfs_cb_data ) ) ;
if ( data = = NULL ) {
rpc_set_error ( nfs - > rpc , " out of memory: failed to allocate nfs_cb_data structure " ) ;
return - 1 ;
}
2011-09-03 08:11:22 +04:00
memset ( data , 0 , sizeof ( struct nfs_cb_data ) ) ;
2011-02-06 07:45:09 +03:00
data - > nfs = nfs ;
data - > cb = cb ;
data - > private_data = private_data ;
data - > nfsfh = nfsfh ;
2014-06-23 18:31:32 +04:00
data - > org_offset = offset ;
data - > org_count = count ;
2011-02-06 07:45:09 +03:00
2014-02-18 23:56:24 +04:00
assert ( data - > num_calls = = 0 ) ;
2014-06-23 18:31:32 +04:00
if ( nfs - > rpc - > readahead & & time ( NULL ) - nfsfh - > ra . buf_ts > NFS_RA_TIMEOUT ) {
/* readahead cache timeout */
nfs_ra_invalidate ( nfsfh ) ;
}
if ( nfs - > rpc - > readahead ) {
if ( offset > = nfsfh - > ra . last_offset & &
offset - NFS_BLKSIZE < = nfsfh - > ra . fh_offset + nfsfh - > ra . cur_ra ) {
if ( nfs - > rpc - > readahead > nfsfh - > ra . cur_ra ) {
nfsfh - > ra . cur_ra < < = 1 ;
}
} else {
nfsfh - > ra . cur_ra = NFS_BLKSIZE ;
}
nfsfh - > ra . last_offset = offset ;
if ( nfsfh - > ra . buf_offset < = offset & &
nfsfh - > ra . buf_offset + nfsfh - > ra . buf_count > = offset + count ) {
/* serve request completely from cache */
data - > buffer = malloc ( count ) ;
if ( data - > buffer = = NULL ) {
free_nfs_cb_data ( data ) ;
return - ENOMEM ;
}
memcpy ( data - > buffer , nfsfh - > ra . buf + ( offset - nfsfh - > ra . buf_offset ) , count ) ;
data - > cb ( count , nfs , data - > buffer , data - > private_data ) ;
nfsfh - > ra . fh_offset = offset + count ;
free_nfs_cb_data ( data ) ;
return 0 ;
}
/* align start offset to blocksize */
count + = offset & ( NFS_BLKSIZE - 1 ) ;
offset & = ~ ( NFS_BLKSIZE - 1 ) ;
/* align end offset to blocksize and add readahead */
count + = nfsfh - > ra . cur_ra - 1 ;
count & = ~ ( NFS_BLKSIZE - 1 ) ;
data - > buffer = malloc ( count ) ;
if ( data - > buffer = = NULL ) {
free_nfs_cb_data ( data ) ;
return - ENOMEM ;
}
data - > offset = offset ;
data - > count = count ;
if ( nfsfh - > ra . buf_count & & nfsfh - > ra . buf_offset < = offset & &
nfsfh - > ra . buf_offset + nfsfh - > ra . buf_count > = offset ) {
/* serve request partially from cache */
size_t overlap = ( nfsfh - > ra . buf_offset + nfsfh - > ra . buf_count ) - offset ;
if ( overlap > count ) count = overlap ;
memcpy ( data - > buffer , nfsfh - > ra . buf + ( offset - nfsfh - > ra . buf_offset ) , overlap ) ;
offset + = overlap ;
count - = overlap ;
}
} else {
data - > offset = offset ;
data - > count = count ;
}
data - > max_offset = offset ;
2014-03-18 23:08:33 +04:00
/* chop requests into chunks of at most READMAX bytes if necessary.
2013-10-23 23:43:24 +04:00
* we send all reads in parallel so that performance is still good .
2011-06-19 02:43:28 +04:00
*/
2014-03-16 23:15:48 +04:00
do {
2011-11-27 07:49:08 +04:00
uint64_t readcount = count ;
2011-06-19 02:43:28 +04:00
struct nfs_mcb_data * mdata ;
2013-12-24 23:16:21 +04:00
READ3args args ;
2011-06-19 02:43:28 +04:00
if ( readcount > nfs_get_readmax ( nfs ) ) {
readcount = nfs_get_readmax ( nfs ) ;
}
mdata = malloc ( sizeof ( struct nfs_mcb_data ) ) ;
if ( mdata = = NULL ) {
rpc_set_error ( nfs - > rpc , " out of memory: failed to allocate nfs_mcb_data structure " ) ;
2014-03-15 20:11:27 +04:00
if ( data - > num_calls = = 0 ) {
2014-02-18 23:56:24 +04:00
free_nfs_cb_data ( data ) ;
2014-03-15 20:11:27 +04:00
return - 1 ;
}
data - > oom = 1 ;
2014-03-18 23:08:33 +04:00
break ;
2011-06-19 02:43:28 +04:00
}
2011-09-03 08:11:22 +04:00
memset ( mdata , 0 , sizeof ( struct nfs_mcb_data ) ) ;
2011-06-19 02:43:28 +04:00
mdata - > data = data ;
mdata - > offset = offset ;
mdata - > count = readcount ;
2014-04-01 01:40:26 +04:00
mdata - > update_pos = update_pos ;
2013-12-24 23:16:21 +04:00
2014-03-15 20:05:44 +04:00
nfs_fill_READ3args ( & args , nfsfh , offset , readcount ) ;
2013-12-24 23:16:21 +04:00
if ( rpc_nfs3_read_async ( nfs - > rpc , nfs_pread_mcb , & args , mdata ) ! = 0 ) {
2011-06-19 02:43:28 +04:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send READ call for %s " , data - > path ) ;
free ( mdata ) ;
2014-03-15 20:11:27 +04:00
if ( data - > num_calls = = 0 ) {
2014-02-18 23:56:24 +04:00
free_nfs_cb_data ( data ) ;
2014-03-15 20:11:27 +04:00
return - 1 ;
}
data - > oom = 1 ;
2014-03-18 23:08:33 +04:00
break ;
2011-06-19 02:43:28 +04:00
}
count - = readcount ;
offset + = readcount ;
data - > num_calls + + ;
2014-03-16 23:15:48 +04:00
} while ( count > 0 ) ;
2011-06-19 02:43:28 +04:00
return 0 ;
2011-02-06 07:45:09 +03:00
}
2014-04-01 01:40:26 +04:00
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 ) ;
}
2011-02-06 07:45:09 +03:00
/*
* Async read ( )
*/
2011-11-27 07:49:08 +04:00
int nfs_read_async ( struct nfs_context * nfs , struct nfsfh * nfsfh , uint64_t count , nfs_cb cb , void * private_data )
2011-02-06 07:45:09 +03:00
{
2014-04-01 01:40:26 +04:00
return nfs_pread_async_internal ( nfs , nfsfh , nfsfh - > offset , count , cb , private_data , 1 ) ;
2011-02-06 07:45:09 +03:00
}
/*
* Async pwrite ( )
*/
2014-03-15 20:05:44 +04:00
static void nfs_fill_WRITE3args ( WRITE3args * args , struct nfsfh * fh , uint64_t offset , uint64_t count ,
void * buf )
{
memset ( args , 0 , sizeof ( WRITE3args ) ) ;
args - > file = fh - > fh ;
args - > offset = offset ;
args - > count = count ;
2014-04-18 20:32:01 +04:00
args - > stable = fh - > is_sync ? FILE_SYNC : UNSTABLE ;
2014-03-15 20:05:44 +04:00
args - > data . data_len = count ;
args - > data . data_val = buf ;
}
2012-11-24 20:18:54 +04:00
static void nfs_pwrite_mcb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-09-11 16:13:28 +04:00
{
struct nfs_mcb_data * mdata = private_data ;
struct nfs_cb_data * data = mdata - > data ;
struct nfs_context * nfs = data - > nfs ;
WRITE3res * res ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-09-11 16:13:28 +04:00
data - > num_calls - - ;
if ( status = = RPC_STATUS_ERROR ) {
/* flag the failure but do not invoke callback until we have received all responses */
data - > error = 1 ;
}
if ( status = = RPC_STATUS_CANCEL ) {
/* flag the cancellation but do not invoke callback until we have received all responses */
data - > cancel = 1 ;
}
if ( status = = RPC_STATUS_SUCCESS ) {
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
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 {
2014-04-01 01:40:26 +04:00
uint64_t count = res - > WRITE3res_u . resok . count ;
if ( mdata - > update_pos )
data - > nfsfh - > offset + = count ;
if ( count < mdata - > count ) {
if ( count = = 0 ) {
2014-03-15 19:22:03 +04:00
rpc_set_error ( nfs - > rpc , " NFS: Write failed. No bytes written! " ) ;
data - > error = 1 ;
} else {
/* reissue reminder of this write request */
WRITE3args args ;
2014-04-01 01:40:26 +04:00
mdata - > offset + = count ;
mdata - > count - = count ;
2014-03-15 19:22:03 +04:00
nfs_fill_WRITE3args ( & args , data - > nfsfh , mdata - > offset , mdata - > count ,
2014-06-23 18:31:32 +04:00
& data - > usrbuf [ mdata - > offset - data - > offset ] ) ;
2014-03-15 19:22:03 +04:00
if ( rpc_nfs3_write_async ( nfs - > rpc , nfs_pwrite_mcb , & args , mdata ) = = 0 ) {
data - > num_calls + + ;
return ;
} else {
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send WRITE call for %s " , data - > path ) ;
2014-03-15 20:11:27 +04:00
data - > oom = 1 ;
2014-03-15 19:22:03 +04:00
}
}
}
2014-04-01 01:40:26 +04:00
if ( count > 0 ) {
if ( data - > max_offset < mdata - > offset + count ) {
data - > max_offset = mdata - > offset + count ;
2011-09-11 16:13:28 +04:00
}
}
}
}
2014-03-15 19:22:03 +04:00
free ( mdata ) ;
2011-09-11 16:13:28 +04:00
if ( data - > num_calls > 0 ) {
/* still waiting for more replies */
return ;
}
2014-03-15 20:11:27 +04:00
if ( data - > oom ! = 0 ) {
data - > cb ( - ENOMEM , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
2011-09-11 16:13:28 +04:00
if ( data - > error ! = 0 ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( data - > cancel ! = 0 ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
2014-06-23 18:31:32 +04:00
data - > cb ( data - > max_offset - data - > offset , nfs , NULL , data - > private_data ) ;
2011-09-11 16:13:28 +04:00
free_nfs_cb_data ( data ) ;
}
2014-04-01 01:40:26 +04:00
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 )
2011-02-06 07:45:09 +03:00
{
struct nfs_cb_data * data ;
data = malloc ( sizeof ( struct nfs_cb_data ) ) ;
if ( data = = NULL ) {
rpc_set_error ( nfs - > rpc , " out of memory: failed to allocate nfs_cb_data structure " ) ;
return - 1 ;
}
2011-09-03 08:11:22 +04:00
memset ( data , 0 , sizeof ( struct nfs_cb_data ) ) ;
2011-02-06 07:45:09 +03:00
data - > nfs = nfs ;
data - > cb = cb ;
data - > private_data = private_data ;
data - > nfsfh = nfsfh ;
2014-03-15 19:22:03 +04:00
data - > usrbuf = buf ;
2011-02-06 07:45:09 +03:00
2014-02-18 23:51:36 +04:00
/* hello, clang-analyzer */
assert ( data - > num_calls = = 0 ) ;
2014-03-18 23:08:33 +04:00
/* chop requests into chunks of at most WRITEMAX bytes if necessary.
2013-10-23 23:43:24 +04:00
* we send all writes in parallel so that performance is still good .
2011-09-11 16:13:28 +04:00
*/
data - > max_offset = offset ;
2014-06-23 18:31:32 +04:00
data - > offset = offset ;
2011-09-11 16:13:28 +04:00
2014-03-15 19:22:03 +04:00
do {
2011-11-27 07:49:08 +04:00
uint64_t writecount = count ;
2011-09-11 16:13:28 +04:00
struct nfs_mcb_data * mdata ;
2013-12-24 23:16:21 +04:00
WRITE3args args ;
2011-09-11 16:13:28 +04:00
if ( writecount > nfs_get_writemax ( nfs ) ) {
writecount = nfs_get_writemax ( nfs ) ;
}
mdata = malloc ( sizeof ( struct nfs_mcb_data ) ) ;
if ( mdata = = NULL ) {
rpc_set_error ( nfs - > rpc , " out of memory: failed to allocate nfs_mcb_data structure " ) ;
2014-03-15 20:11:27 +04:00
if ( data - > num_calls = = 0 ) {
2014-02-18 23:51:36 +04:00
free_nfs_cb_data ( data ) ;
2014-03-15 20:11:27 +04:00
return - 1 ;
}
data - > oom = 1 ;
2014-03-18 23:08:33 +04:00
break ;
2011-09-11 16:13:28 +04:00
}
memset ( mdata , 0 , sizeof ( struct nfs_mcb_data ) ) ;
mdata - > data = data ;
mdata - > offset = offset ;
mdata - > count = writecount ;
2014-04-01 01:40:26 +04:00
mdata - > update_pos = update_pos ;
2011-09-11 16:13:28 +04:00
2014-06-23 18:31:32 +04:00
nfs_fill_WRITE3args ( & args , nfsfh , offset , writecount , & buf [ offset - data - > offset ] ) ;
2013-12-24 23:16:21 +04:00
if ( rpc_nfs3_write_async ( nfs - > rpc , nfs_pwrite_mcb , & args , mdata ) ! = 0 ) {
2011-09-11 16:13:28 +04:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send WRITE call for %s " , data - > path ) ;
free ( mdata ) ;
2014-03-15 20:11:27 +04:00
if ( data - > num_calls = = 0 ) {
2014-02-18 23:51:36 +04:00
free_nfs_cb_data ( data ) ;
2014-03-15 20:11:27 +04:00
return - 1 ;
}
data - > oom = 1 ;
2014-03-18 23:08:33 +04:00
break ;
2011-09-11 16:13:28 +04:00
}
count - = writecount ;
offset + = writecount ;
data - > num_calls + + ;
2014-03-15 19:22:03 +04:00
} while ( count > 0 ) ;
2011-09-11 16:13:28 +04:00
2011-02-06 07:45:09 +03:00
return 0 ;
}
2014-04-01 01:40:26 +04:00
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 ) ;
}
2011-02-06 07:45:09 +03:00
/*
* Async write ( )
*/
2014-04-18 20:32:01 +04:00
static void nfs_write_append_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
{
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
GETATTR3res * res ;
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: GETATTR failed with %s(%d) " , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( nfs_pwrite_async_internal ( nfs , data - > nfsfh , res - > GETATTR3res_u . resok . obj_attributes . size , data - > count , data - > usrbuf , data - > cb , data - > private_data , 1 ) ! = 0 ) {
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
free_nfs_cb_data ( data ) ;
}
2011-11-27 07:49:08 +04:00
int nfs_write_async ( struct nfs_context * nfs , struct nfsfh * nfsfh , uint64_t count , char * buf , nfs_cb cb , void * private_data )
2011-02-06 07:45:09 +03:00
{
2014-06-23 18:31:32 +04:00
nfs_ra_invalidate ( nfsfh ) ;
2014-04-18 20:32:01 +04:00
if ( nfsfh - > is_append ) {
struct GETATTR3args args ;
struct nfs_cb_data * data ;
data = malloc ( sizeof ( struct nfs_cb_data ) ) ;
if ( data = = NULL ) {
rpc_set_error ( nfs - > rpc , " out of memory: failed to allocate nfs_cb_data structure " ) ;
return - 1 ;
}
memset ( data , 0 , sizeof ( struct nfs_cb_data ) ) ;
data - > nfs = nfs ;
data - > cb = cb ;
data - > private_data = private_data ;
data - > nfsfh = nfsfh ;
data - > usrbuf = buf ;
data - > count = count ;
memset ( & args , 0 , sizeof ( GETATTR3args ) ) ;
args . object = nfsfh - > fh ;
if ( rpc_nfs3_getattr_async ( nfs - > rpc , nfs_write_append_cb , & args , data ) ! = 0 ) {
rpc_set_error ( nfs - > rpc , " out of memory: failed to send GETATTR " ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
2014-04-01 01:40:26 +04:00
return nfs_pwrite_async_internal ( nfs , nfsfh , nfsfh - > offset , count , buf , cb , private_data , 1 ) ;
2011-02-06 07:45:09 +03:00
}
/*
* close
*/
2014-02-14 01:36:54 +04:00
2011-02-06 07:45:09 +03:00
int nfs_close_async ( struct nfs_context * nfs , struct nfsfh * nfsfh , nfs_cb cb , void * private_data )
{
2014-07-20 11:07:46 +04:00
free_nfsfh ( nfsfh ) ;
2011-02-06 07:45:09 +03:00
cb ( 0 , nfs , NULL , private_data ) ;
return 0 ;
} ;
/*
* Async fstat ( )
*/
int nfs_fstat_async ( struct nfs_context * nfs , struct nfsfh * nfsfh , nfs_cb cb , void * private_data )
{
struct nfs_cb_data * data ;
2013-12-24 23:16:21 +04:00
struct GETATTR3args args ;
2011-02-06 07:45:09 +03:00
data = malloc ( sizeof ( struct nfs_cb_data ) ) ;
if ( data = = NULL ) {
rpc_set_error ( nfs - > rpc , " out of memory: failed to allocate nfs_cb_data structure " ) ;
return - 1 ;
}
2011-09-03 08:11:22 +04:00
memset ( data , 0 , sizeof ( struct nfs_cb_data ) ) ;
2011-02-06 07:45:09 +03:00
data - > nfs = nfs ;
data - > cb = cb ;
data - > private_data = private_data ;
2013-12-24 23:16:21 +04:00
memset ( & args , 0 , sizeof ( GETATTR3args ) ) ;
2014-01-01 04:11:11 +04:00
args . object = nfsfh - > fh ;
2013-12-24 23:16:21 +04:00
if ( rpc_nfs3_getattr_async ( nfs - > rpc , nfs_stat_1_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send STAT GETATTR call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
/*
* Async fsync ( )
*/
2012-11-24 20:18:54 +04:00
static void nfs_fsync_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
COMMIT3res * res ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: Commit failed with %s(%d) " , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
data - > cb ( 0 , nfs , NULL , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
int nfs_fsync_async ( struct nfs_context * nfs , struct nfsfh * nfsfh , nfs_cb cb , void * private_data )
{
struct nfs_cb_data * data ;
2014-01-01 03:16:02 +04:00
struct COMMIT3args args ;
2011-02-06 07:45:09 +03:00
data = malloc ( sizeof ( struct nfs_cb_data ) ) ;
if ( data = = NULL ) {
rpc_set_error ( nfs - > rpc , " out of memory: failed to allocate nfs_cb_data structure " ) ;
return - 1 ;
}
2011-09-03 08:11:22 +04:00
memset ( data , 0 , sizeof ( struct nfs_cb_data ) ) ;
2011-02-06 07:45:09 +03:00
data - > nfs = nfs ;
data - > cb = cb ;
data - > private_data = private_data ;
2014-01-01 03:16:02 +04:00
args . file = nfsfh - > fh ;
args . offset = 0 ;
args . count = 0 ;
if ( rpc_nfs3_commit_async ( nfs - > rpc , nfs_fsync_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send COMMIT call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
/*
* Async ftruncate ( )
*/
2012-11-24 20:18:54 +04:00
static void nfs_ftruncate_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
SETATTR3res * res ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: Setattr failed with %s(%d) " , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
data - > cb ( 0 , nfs , NULL , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2011-11-27 07:49:08 +04:00
int nfs_ftruncate_async ( struct nfs_context * nfs , struct nfsfh * nfsfh , uint64_t length , nfs_cb cb , void * private_data )
2011-02-06 07:45:09 +03:00
{
struct nfs_cb_data * data ;
SETATTR3args args ;
data = malloc ( sizeof ( struct nfs_cb_data ) ) ;
if ( data = = NULL ) {
rpc_set_error ( nfs - > rpc , " out of memory: failed to allocate nfs_cb_data structure " ) ;
return - 1 ;
}
2011-09-03 08:11:22 +04:00
memset ( data , 0 , sizeof ( struct nfs_cb_data ) ) ;
2011-02-06 07:45:09 +03:00
data - > nfs = nfs ;
data - > cb = cb ;
data - > private_data = private_data ;
2011-09-03 08:11:22 +04:00
memset ( & args , 0 , sizeof ( SETATTR3args ) ) ;
2014-01-01 04:11:11 +04:00
args . object = nfsfh - > fh ;
2011-02-06 07:45:09 +03:00
args . new_attributes . size . set_it = 1 ;
args . new_attributes . size . set_size3_u . size = length ;
2014-01-01 03:12:32 +04:00
if ( rpc_nfs3_setattr_async ( nfs - > rpc , nfs_ftruncate_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send SETATTR call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
/*
* Async truncate ( )
*/
2014-06-08 20:45:22 +04:00
static int nfs_truncate_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
2011-11-27 07:49:08 +04:00
uint64_t offset = data - > continue_int ;
2011-02-06 07:45:09 +03:00
struct nfsfh nfsfh ;
2014-01-01 04:11:11 +04:00
nfsfh . fh = data - > fh ;
2011-02-06 07:45:09 +03:00
if ( nfs_ftruncate_async ( nfs , & nfsfh , offset , data - > cb , data - > private_data ) ! = 0 ) {
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send SETATTR call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
free_nfs_cb_data ( data ) ;
return 0 ;
}
2011-11-27 07:49:08 +04:00
int nfs_truncate_async ( struct nfs_context * nfs , const char * path , uint64_t length , nfs_cb cb , void * private_data )
2011-02-06 07:45:09 +03:00
{
2011-11-27 07:49:08 +04:00
uint64_t offset ;
2011-02-06 07:45:09 +03:00
offset = length ;
if ( nfs_lookuppath_async ( nfs , path , cb , private_data , nfs_truncate_continue_internal , NULL , NULL , offset ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
return - 1 ;
2011-02-06 07:45:09 +03:00
}
return 0 ;
}
/*
* Async mkdir ( )
*/
2012-11-24 20:18:54 +04:00
static void nfs_mkdir_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
MKDIR3res * res ;
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
char * str = data - > continue_data ;
2014-02-14 01:36:54 +04:00
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
str = & str [ strlen ( str ) + 1 ] ;
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: MKDIR of %s/%s failed with %s(%d) " , data - > saved_path , str , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
data - > cb ( 0 , nfs , NULL , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-06-08 20:45:22 +04:00
static int nfs_mkdir_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
char * str = data - > continue_data ;
2012-01-12 09:02:32 +04:00
MKDIR3args args ;
2011-02-06 07:45:09 +03:00
str = & str [ strlen ( str ) + 1 ] ;
2012-01-12 09:02:32 +04:00
memset ( & args , 0 , sizeof ( MKDIR3args ) ) ;
2014-01-01 04:11:11 +04:00
args . where . dir = data - > fh ;
2012-01-12 09:02:32 +04:00
args . where . name = str ;
args . attributes . mode . set_it = 1 ;
args . attributes . mode . set_mode3_u . mode = 0755 ;
2014-01-01 03:17:16 +04:00
if ( rpc_nfs3_mkdir_async ( nfs - > rpc , nfs_mkdir_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send MKDIR call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
int nfs_mkdir_async ( struct nfs_context * nfs , const char * path , nfs_cb cb , void * private_data )
{
char * new_path ;
char * ptr ;
new_path = strdup ( path ) ;
if ( new_path = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate mode buffer for path " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
2011-08-28 13:27:23 +04:00
ptr = strrchr ( new_path , ' / ' ) ;
2011-02-06 07:45:09 +03:00
if ( ptr = = NULL ) {
2014-02-18 03:19:23 +04:00
free ( new_path ) ;
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Invalid path %s " , path ) ;
return - 1 ;
2011-02-06 07:45:09 +03:00
}
* ptr = 0 ;
/* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
if ( nfs_lookuppath_async ( nfs , new_path , cb , private_data , nfs_mkdir_continue_internal , new_path , free , 0 ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path component " ) ;
return - 1 ;
2011-02-06 07:45:09 +03:00
}
return 0 ;
}
/*
* Async rmdir ( )
*/
2012-11-24 20:18:54 +04:00
static void nfs_rmdir_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
RMDIR3res * res ;
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
char * str = data - > continue_data ;
2014-02-14 01:36:54 +04:00
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
str = & str [ strlen ( str ) + 1 ] ;
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: RMDIR of %s/%s failed with %s(%d) " , data - > saved_path , str , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
data - > cb ( 0 , nfs , NULL , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-06-08 20:45:22 +04:00
static int nfs_rmdir_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
char * str = data - > continue_data ;
2014-01-01 03:20:28 +04:00
RMDIR3args args ;
2011-02-06 07:45:09 +03:00
str = & str [ strlen ( str ) + 1 ] ;
2014-01-01 03:20:28 +04:00
args . object . dir = data - > fh ;
args . object . name = str ;
if ( rpc_nfs3_rmdir_async ( nfs - > rpc , nfs_rmdir_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send RMDIR call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
int nfs_rmdir_async ( struct nfs_context * nfs , const char * path , nfs_cb cb , void * private_data )
{
char * new_path ;
char * ptr ;
new_path = strdup ( path ) ;
if ( new_path = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate mode buffer for path " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
2011-08-28 13:27:23 +04:00
ptr = strrchr ( new_path , ' / ' ) ;
2011-02-06 07:45:09 +03:00
if ( ptr = = NULL ) {
2014-02-18 03:20:59 +04:00
free ( new_path ) ;
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Invalid path %s " , path ) ;
return - 1 ;
2011-02-06 07:45:09 +03:00
}
* ptr = 0 ;
/* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
if ( nfs_lookuppath_async ( nfs , new_path , cb , private_data , nfs_rmdir_continue_internal , new_path , free , 0 ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
return - 1 ;
2011-02-06 07:45:09 +03:00
}
return 0 ;
}
/*
* Async creat ( )
*/
2014-07-18 01:31:23 +04:00
struct create_cb_data {
char * path ;
int flags ;
int mode ;
} ;
static void free_create_cb_data ( void * ptr )
{
struct create_cb_data * data = ptr ;
free ( data - > path ) ;
free ( data ) ;
}
2014-07-20 11:07:46 +04:00
static void nfs_create_trunc_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
{
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
struct nfsfh * nfsfh ;
SETATTR3res * res ;
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
free_nfsfh ( nfsfh ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
free_nfsfh ( nfsfh ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: Setattr failed with %s(%d) " , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
free_nfsfh ( nfsfh ) ;
return ;
}
data - > cb ( 0 , nfs , data - > nfsfh , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2012-11-24 20:18:54 +04:00
static void nfs_create_2_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
LOOKUP3res * res ;
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
struct nfsfh * nfsfh ;
2014-07-18 01:31:23 +04:00
struct create_cb_data * cb_data = data - > continue_data ;
char * str = cb_data - > path ;
2011-02-06 07:45:09 +03:00
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
str = & str [ strlen ( str ) + 1 ] ;
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: CREATE of %s/%s failed with %s(%d) " , data - > saved_path , str , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
return ;
}
nfsfh = malloc ( sizeof ( struct nfsfh ) ) ;
if ( nfsfh = = NULL ) {
rpc_set_error ( nfs - > rpc , " NFS: Failed to allocate nfsfh structure " ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
2011-09-03 08:11:22 +04:00
memset ( nfsfh , 0 , sizeof ( struct nfsfh ) ) ;
2011-02-06 07:45:09 +03:00
2014-07-18 01:31:23 +04:00
if ( cb_data - > flags & O_SYNC ) {
nfsfh - > is_sync = 1 ;
}
if ( cb_data - > flags & O_APPEND ) {
nfsfh - > is_append = 1 ;
}
2013-04-16 08:37:03 +04:00
/* copy the filehandle */
nfsfh - > fh . data . data_len = res - > LOOKUP3res_u . resok . object . data . data_len ;
nfsfh - > fh . data . data_val = malloc ( nfsfh - > fh . data . data_len ) ;
2014-07-20 11:13:45 +04:00
if ( nfsfh - > fh . data . data_val = = NULL ) {
rpc_set_error ( nfs - > rpc , " Out of memory: Failed to allocate fh structure " ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
free ( nfsfh ) ;
return - 1 ;
}
2013-04-16 08:37:03 +04:00
memcpy ( nfsfh - > fh . data . data_val , res - > LOOKUP3res_u . resok . object . data . data_val , nfsfh - > fh . data . data_len ) ;
2011-02-06 07:45:09 +03:00
2014-07-20 11:07:46 +04:00
/* Try to truncate it if we were requested to */
if ( cb_data - > flags & O_TRUNC ) {
SETATTR3args args ;
data - > nfsfh = nfsfh ;
memset ( & args , 0 , sizeof ( SETATTR3args ) ) ;
args . object = nfsfh - > fh ;
args . new_attributes . size . set_it = 1 ;
args . new_attributes . size . set_size3_u . size = 0 ;
if ( rpc_nfs3_setattr_async ( nfs - > rpc , nfs_create_trunc_cb ,
& args , data ) ! = 0 ) {
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send "
" SETATTR call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) ,
data - > private_data ) ;
free_nfs_cb_data ( data ) ;
free_nfsfh ( nfsfh ) ;
return ;
}
return ;
}
2011-02-06 07:45:09 +03:00
data - > cb ( 0 , nfs , nfsfh , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-07-18 01:31:23 +04:00
static void nfs_create_1_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
CREATE3res * res ;
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
2014-07-18 01:31:23 +04:00
struct create_cb_data * cb_data = data - > continue_data ;
char * str = cb_data - > path ;
2013-12-24 23:16:21 +04:00
LOOKUP3args args ;
2011-02-06 07:45:09 +03:00
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
str = & str [ strlen ( str ) + 1 ] ;
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: CREATE of %s/%s failed with %s(%d) " , data - > saved_path , str , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
2013-12-17 14:50:00 +04:00
free_nfs_cb_data ( data ) ;
2011-02-06 07:45:09 +03:00
return ;
}
2013-12-24 23:16:21 +04:00
memset ( & args , 0 , sizeof ( LOOKUP3args ) ) ;
2014-01-01 04:11:11 +04:00
args . what . dir = data - > fh ;
args . what . name = str ;
2013-12-24 23:16:21 +04:00
if ( rpc_nfs3_lookup_async ( nfs - > rpc , nfs_create_2_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send lookup call for %s/%s " , data - > saved_path , str ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
return ;
}
2014-07-18 01:31:23 +04:00
static int nfs_create_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
2014-07-18 01:31:23 +04:00
struct create_cb_data * cb_data = data - > continue_data ;
char * str = cb_data - > path ;
2012-01-12 08:31:49 +04:00
CREATE3args args ;
2011-02-06 07:45:09 +03:00
str = & str [ strlen ( str ) + 1 ] ;
2012-01-12 08:31:49 +04:00
memset ( & args , 0 , sizeof ( CREATE3args ) ) ;
2014-01-01 04:11:11 +04:00
args . where . dir = data - > fh ;
2012-01-12 08:31:49 +04:00
args . where . name = str ;
2014-07-18 01:31:23 +04:00
args . how . mode = ( cb_data - > flags & O_EXCL ) ? GUARDED : UNCHECKED ;
2012-01-12 08:31:49 +04:00
args . how . createhow3_u . obj_attributes . mode . set_it = 1 ;
2014-07-18 01:31:23 +04:00
args . how . createhow3_u . obj_attributes . mode . set_mode3_u . mode = cb_data - > mode ;
2012-01-12 08:31:49 +04:00
2014-07-18 01:31:23 +04:00
if ( rpc_nfs3_create_async ( nfs - > rpc , nfs_create_1_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send CREATE call for %s/%s " , data - > path , str ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
2014-07-18 01:31:23 +04:00
int nfs_create_async ( struct nfs_context * nfs , const char * path , int flags , int mode , nfs_cb cb , void * private_data )
2011-02-06 07:45:09 +03:00
{
2014-07-18 01:31:23 +04:00
struct create_cb_data * cb_data ;
2011-02-06 07:45:09 +03:00
char * ptr ;
2014-07-18 01:31:23 +04:00
cb_data = malloc ( sizeof ( struct create_cb_data ) ) ;
if ( cb_data = = NULL ) {
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate mode buffer for cb data " ) ;
return - 1 ;
}
cb_data - > path = strdup ( path ) ;
if ( cb_data - > path = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate mode buffer for path " ) ;
2014-07-18 01:31:23 +04:00
free ( cb_data ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
2014-07-18 01:31:23 +04:00
ptr = strrchr ( cb_data - > path , ' / ' ) ;
2011-02-06 07:45:09 +03:00
if ( ptr = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Invalid path %s " , path ) ;
2014-07-18 01:31:23 +04:00
free_create_cb_data ( cb_data ) ;
2011-06-19 03:03:04 +04:00
return - 1 ;
2011-02-06 07:45:09 +03:00
}
* ptr = 0 ;
2014-07-18 01:31:23 +04:00
cb_data - > flags = flags ;
cb_data - > mode = mode ;
2013-04-16 07:42:44 +04:00
/* new_path now points to the parent directory, and beyond the nul terminator is the new directory to create */
2014-07-18 01:31:23 +04:00
if ( nfs_lookuppath_async ( nfs , cb_data - > path , cb , private_data , nfs_create_continue_internal , cb_data , free_create_cb_data , 0 ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
return - 1 ;
2011-02-06 07:45:09 +03:00
}
return 0 ;
}
2014-07-18 01:31:23 +04:00
int nfs_creat_async ( struct nfs_context * nfs , const char * path , int mode , nfs_cb cb , void * private_data )
{
return nfs_create_async ( nfs , path , 0 , mode , cb , private_data ) ;
}
2011-02-06 07:45:09 +03:00
/*
* Async unlink ( )
*/
2012-11-24 20:18:54 +04:00
static void nfs_unlink_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
REMOVE3res * res ;
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
char * str = data - > continue_data ;
2014-02-14 01:36:54 +04:00
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
str = & str [ strlen ( str ) + 1 ] ;
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: REMOVE of %s/%s failed with %s(%d) " , data - > saved_path , str , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
data - > cb ( 0 , nfs , NULL , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-06-08 20:45:22 +04:00
static int nfs_unlink_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
char * str = data - > continue_data ;
2014-01-01 03:23:44 +04:00
struct REMOVE3args args ;
2011-02-06 07:45:09 +03:00
str = & str [ strlen ( str ) + 1 ] ;
2014-01-01 03:23:44 +04:00
args . object . dir = data - > fh ;
args . object . name = str ;
if ( rpc_nfs3_remove_async ( nfs - > rpc , nfs_unlink_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send REMOVE call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
int nfs_unlink_async ( struct nfs_context * nfs , const char * path , nfs_cb cb , void * private_data )
{
char * new_path ;
char * ptr ;
new_path = strdup ( path ) ;
if ( new_path = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate mode buffer for path " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
2011-08-28 13:27:23 +04:00
ptr = strrchr ( new_path , ' / ' ) ;
2011-02-06 07:45:09 +03:00
if ( ptr = = NULL ) {
2014-02-18 03:22:45 +04:00
free ( new_path ) ;
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Invalid path %s " , path ) ;
return - 1 ;
2011-02-06 07:45:09 +03:00
}
* ptr = 0 ;
/* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
if ( nfs_lookuppath_async ( nfs , new_path , cb , private_data , nfs_unlink_continue_internal , new_path , free , 0 ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
return - 1 ;
2011-02-06 07:45:09 +03:00
}
return 0 ;
}
2011-11-27 07:08:24 +04:00
/*
* Async mknod ( )
*/
struct mknod_cb_data {
char * path ;
int mode ;
int major ;
int minor ;
} ;
static void free_mknod_cb_data ( void * ptr )
{
struct mknod_cb_data * data = ptr ;
free ( data - > path ) ;
free ( data ) ;
}
2012-11-24 20:18:54 +04:00
static void nfs_mknod_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-11-27 07:08:24 +04:00
{
MKNOD3res * res ;
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
char * str = data - > continue_data ;
2014-02-14 01:36:54 +04:00
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-11-27 07:08:24 +04:00
str = & str [ strlen ( str ) + 1 ] ;
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: MKNOD of %s/%s failed with %s(%d) " , data - > saved_path , str , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
data - > cb ( 0 , nfs , NULL , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-06-08 20:45:22 +04:00
static int nfs_mknod_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-11-27 07:08:24 +04:00
{
struct mknod_cb_data * cb_data = data - > continue_data ;
char * str = cb_data - > path ;
2014-01-01 03:33:36 +04:00
MKNOD3args args ;
2014-02-14 01:36:54 +04:00
2011-11-27 07:08:24 +04:00
str = & str [ strlen ( str ) + 1 ] ;
2014-01-01 03:33:36 +04:00
args . where . dir = data - > fh ;
args . where . name = str ;
switch ( cb_data - > mode & S_IFMT ) {
case S_IFCHR :
args . what . type = NF3CHR ;
args . what . mknoddata3_u . chr_device . dev_attributes . mode . set_it = 1 ;
args . what . mknoddata3_u . chr_device . dev_attributes . mode . set_mode3_u . mode = cb_data - > mode & ( S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH ) ;
args . what . mknoddata3_u . chr_device . spec . specdata1 = cb_data - > major ;
args . what . mknoddata3_u . chr_device . spec . specdata2 = cb_data - > minor ;
break ;
case S_IFBLK :
args . what . type = NF3BLK ;
args . what . mknoddata3_u . blk_device . dev_attributes . mode . set_it = 1 ;
args . what . mknoddata3_u . blk_device . dev_attributes . mode . set_mode3_u . mode = cb_data - > mode & ( S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH ) ;
args . what . mknoddata3_u . blk_device . spec . specdata1 = cb_data - > major ;
args . what . mknoddata3_u . blk_device . spec . specdata2 = cb_data - > minor ;
case S_IFSOCK :
args . what . type = NF3SOCK ;
args . what . mknoddata3_u . sock_attributes . mode . set_it = 1 ;
args . what . mknoddata3_u . sock_attributes . mode . set_mode3_u . mode = cb_data - > mode & ( S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH ) ;
break ;
case S_IFIFO :
args . what . type = NF3FIFO ;
args . what . mknoddata3_u . pipe_attributes . mode . set_it = 1 ;
args . what . mknoddata3_u . pipe_attributes . mode . set_mode3_u . mode = cb_data - > mode & ( S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH ) ;
break ;
default :
rpc_set_error ( nfs - > rpc , " Invalid file type for NFS3/MKNOD call " ) ;
data - > cb ( - EINVAL , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
if ( rpc_nfs3_mknod_async ( nfs - > rpc , nfs_mknod_cb , & args , data ) ! = 0 ) {
2011-11-27 07:08:24 +04:00
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
int nfs_mknod_async ( struct nfs_context * nfs , const char * path , int mode , int dev , nfs_cb cb , void * private_data )
{
char * ptr ;
struct mknod_cb_data * cb_data ;
cb_data = malloc ( sizeof ( struct mknod_cb_data ) ) ;
if ( cb_data = = NULL ) {
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate mode buffer for cb data " ) ;
return - 1 ;
}
cb_data - > path = strdup ( path ) ;
if ( cb_data - > path = = NULL ) {
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate mode buffer for path " ) ;
2014-02-14 01:36:54 +04:00
free ( cb_data ) ;
2011-11-27 07:08:24 +04:00
return - 1 ;
}
ptr = strrchr ( cb_data - > path , ' / ' ) ;
if ( ptr = = NULL ) {
rpc_set_error ( nfs - > rpc , " Invalid path %s " , path ) ;
2014-02-18 02:09:31 +04:00
free_mknod_cb_data ( cb_data ) ;
2011-11-27 07:08:24 +04:00
return - 1 ;
}
* ptr = 0 ;
cb_data - > mode = mode ;
cb_data - > major = major ( dev ) ;
cb_data - > minor = minor ( dev ) ;
/* data->path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
if ( nfs_lookuppath_async ( nfs , cb_data - > path , cb , private_data , nfs_mknod_continue_internal , cb_data , free_mknod_cb_data , 0 ) ! = 0 ) {
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
return - 1 ;
}
return 0 ;
}
2011-02-06 07:45:09 +03:00
/*
* Async opendir ( )
*/
2011-10-03 03:55:42 +04:00
/* ReadDirPlus Emulation Callback data */
struct rdpe_cb_data {
int getattrcount ;
int status ;
struct nfs_cb_data * data ;
} ;
/* ReadDirPlus Emulation LOOKUP Callback data */
struct rdpe_lookup_cb_data {
struct rdpe_cb_data * rdpe_cb_data ;
struct nfsdirent * nfsdirent ;
} ;
/* Workaround for servers lacking READDIRPLUS, use READDIR instead and a GETATTR-loop */
2012-11-24 20:18:54 +04:00
static void nfs_opendir3_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
2011-10-03 03:55:42 +04:00
LOOKUP3res * res = command_data ;
struct rdpe_lookup_cb_data * rdpe_lookup_cb_data = private_data ;
struct rdpe_cb_data * rdpe_cb_data = rdpe_lookup_cb_data - > rdpe_cb_data ;
struct nfs_cb_data * data = rdpe_cb_data - > data ;
struct nfsdir * nfsdir = data - > continue_data ;
struct nfs_context * nfs = data - > nfs ;
struct nfsdirent * nfsdirent = rdpe_lookup_cb_data - > nfsdirent ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-10-03 03:55:42 +04:00
free ( rdpe_lookup_cb_data ) ;
rdpe_cb_data - > getattrcount - - ;
if ( status = = RPC_STATUS_ERROR ) {
2014-03-13 17:30:31 +04:00
rpc_set_error ( nfs - > rpc , " LOOKUP during READDIRPLUS emulation "
" failed with RPC_STATUS_ERROR " ) ;
2011-10-03 03:55:42 +04:00
rdpe_cb_data - > status = RPC_STATUS_ERROR ;
}
if ( status = = RPC_STATUS_CANCEL ) {
2014-03-13 17:30:31 +04:00
rpc_set_error ( nfs - > rpc , " LOOKUP during READDIRPLUS emulation "
" failed with RPC_STATUS_CANCEL " ) ;
2011-10-03 03:55:42 +04:00
rdpe_cb_data - > status = RPC_STATUS_CANCEL ;
}
if ( status = = RPC_STATUS_SUCCESS & & res - > status = = NFS3_OK ) {
if ( res - > LOOKUP3res_u . resok . obj_attributes . attributes_follow ) {
fattr3 * attributes = & res - > LOOKUP3res_u . resok . obj_attributes . post_op_attr_u . attributes ;
nfsdirent - > type = attributes - > type ;
nfsdirent - > mode = attributes - > mode ;
nfsdirent - > size = attributes - > size ;
nfsdirent - > atime . tv_sec = attributes - > atime . seconds ;
nfsdirent - > atime . tv_usec = attributes - > atime . nseconds / 1000 ;
nfsdirent - > mtime . tv_sec = attributes - > mtime . seconds ;
nfsdirent - > mtime . tv_usec = attributes - > mtime . nseconds / 1000 ;
nfsdirent - > ctime . tv_sec = attributes - > ctime . seconds ;
nfsdirent - > ctime . tv_usec = attributes - > ctime . nseconds / 1000 ;
2014-01-01 04:25:01 +04:00
nfsdirent - > uid = attributes - > uid ;
nfsdirent - > gid = attributes - > gid ;
2014-06-08 22:40:35 +04:00
nfsdirent - > nlink = attributes - > nlink ;
2011-10-03 03:55:42 +04:00
}
}
if ( rdpe_cb_data - > getattrcount = = 0 ) {
if ( rdpe_cb_data - > status ! = RPC_STATUS_SUCCESS ) {
2014-03-13 17:30:31 +04:00
rpc_set_error ( nfs - > rpc , " READDIRPLUS emulation "
" failed: %s " , rpc_get_error ( rpc ) ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) ,
data - > private_data ) ;
2011-10-03 03:55:42 +04:00
nfs_free_nfsdir ( nfsdir ) ;
} else {
data - > cb ( 0 , nfs , nfsdir , data - > private_data ) ;
}
free ( rdpe_cb_data ) ;
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
}
}
2012-11-24 20:18:54 +04:00
static void nfs_opendir2_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-10-03 03:55:42 +04:00
{
READDIR3res * res = command_data ;
2011-02-06 07:45:09 +03:00
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
2011-08-28 13:30:10 +04:00
struct nfsdir * nfsdir = data - > continue_data ;
2011-10-03 03:55:42 +04:00
struct nfsdirent * nfsdirent ;
struct entry3 * entry ;
2014-01-13 18:36:38 +04:00
uint64_t cookie = 0 ;
2011-10-03 03:55:42 +04:00
struct rdpe_cb_data * rdpe_cb_data ;
2014-02-14 01:36:54 +04:00
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
nfs_free_nfsdir ( nfsdir ) ;
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
return ;
}
2011-10-03 03:55:42 +04:00
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
nfs_free_nfsdir ( nfsdir ) ;
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: READDIR of %s failed with %s(%d) " , data - > saved_path , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
nfs_free_nfsdir ( nfsdir ) ;
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
return ;
2011-10-03 03:55:42 +04:00
}
entry = res - > READDIR3res_u . resok . reply . entries ;
while ( entry ! = NULL ) {
nfsdirent = malloc ( sizeof ( struct nfsdirent ) ) ;
if ( nfsdirent = = NULL ) {
data - > cb ( - ENOMEM , nfs , " Failed to allocate dirent " , data - > private_data ) ;
nfs_free_nfsdir ( nfsdir ) ;
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
return ;
}
memset ( nfsdirent , 0 , sizeof ( struct nfsdirent ) ) ;
nfsdirent - > name = strdup ( entry - > name ) ;
if ( nfsdirent - > name = = NULL ) {
data - > cb ( - ENOMEM , nfs , " Failed to allocate dirent->name " , data - > private_data ) ;
2014-02-18 02:42:42 +04:00
free ( nfsdirent ) ;
2011-10-03 03:55:42 +04:00
nfs_free_nfsdir ( nfsdir ) ;
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
return ;
}
nfsdirent - > inode = entry - > fileid ;
nfsdirent - > next = nfsdir - > entries ;
nfsdir - > entries = nfsdirent ;
cookie = entry - > cookie ;
entry = entry - > nextentry ;
}
if ( res - > READDIR3res_u . resok . reply . eof = = 0 ) {
2014-01-01 03:53:40 +04:00
READDIR3args args ;
args . dir = data - > fh ;
args . cookie = cookie ;
2014-01-01 04:11:11 +04:00
memcpy ( & args . cookieverf , res - > READDIR3res_u . resok . cookieverf , sizeof ( cookieverf3 ) ) ;
2014-01-01 03:53:40 +04:00
args . count = 8192 ;
if ( rpc_nfs3_readdir_async ( nfs - > rpc , nfs_opendir2_cb , & args , data ) ! = 0 ) {
2011-10-03 03:55:42 +04:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send READDIR call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
nfs_free_nfsdir ( nfsdir ) ;
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
return ;
}
return ;
}
2014-06-08 22:22:06 +04:00
if ( res - > READDIR3res_u . resok . dir_attributes . attributes_follow )
nfsdir - > attr = res - > READDIR3res_u . resok . dir_attributes . post_op_attr_u . attributes ;
2011-10-03 03:55:42 +04:00
/* steal the dirhandle */
nfsdir - > current = nfsdir - > entries ;
2014-02-19 00:07:46 +04:00
if ( nfsdir - > entries ) {
rdpe_cb_data = malloc ( sizeof ( struct rdpe_cb_data ) ) ;
rdpe_cb_data - > getattrcount = 0 ;
rdpe_cb_data - > status = RPC_STATUS_SUCCESS ;
rdpe_cb_data - > data = data ;
for ( nfsdirent = nfsdir - > entries ; nfsdirent ; nfsdirent = nfsdirent - > next ) {
struct rdpe_lookup_cb_data * rdpe_lookup_cb_data ;
LOOKUP3args args ;
rdpe_lookup_cb_data = malloc ( sizeof ( struct rdpe_lookup_cb_data ) ) ;
rdpe_lookup_cb_data - > rdpe_cb_data = rdpe_cb_data ;
rdpe_lookup_cb_data - > nfsdirent = nfsdirent ;
memset ( & args , 0 , sizeof ( LOOKUP3args ) ) ;
args . what . dir = data - > fh ;
args . what . name = nfsdirent - > name ;
if ( rpc_nfs3_lookup_async ( nfs - > rpc , nfs_opendir3_cb , & args , rdpe_lookup_cb_data ) ! = 0 ) {
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send READDIR LOOKUP call " ) ;
/* if we have already commands in flight, we cant just stop, we have to wait for the
* commands in flight to complete
*/
if ( rdpe_cb_data - > getattrcount > 0 ) {
nfs_free_nfsdir ( nfsdir ) ;
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
rdpe_cb_data - > status = RPC_STATUS_ERROR ;
free ( rdpe_lookup_cb_data ) ;
return ;
}
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
2014-02-18 02:42:42 +04:00
nfs_free_nfsdir ( nfsdir ) ;
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
2011-10-03 03:55:42 +04:00
free ( rdpe_lookup_cb_data ) ;
2014-02-19 00:07:46 +04:00
free ( rdpe_cb_data ) ;
2011-10-03 03:55:42 +04:00
return ;
}
2014-02-19 00:07:46 +04:00
rdpe_cb_data - > getattrcount + + ;
2011-10-03 03:55:42 +04:00
}
}
}
2012-11-24 20:18:54 +04:00
static void nfs_opendir_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-10-03 03:55:42 +04:00
{
READDIRPLUS3res * res = command_data ;
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
struct nfsdir * nfsdir = data - > continue_data ;
struct entryplus3 * entry ;
2014-01-13 18:36:38 +04:00
uint64_t cookie = 0 ;
2014-02-14 01:36:54 +04:00
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-10-03 03:55:42 +04:00
if ( status = = RPC_STATUS_ERROR | | ( status = = RPC_STATUS_SUCCESS & & res - > status = = NFS3ERR_NOTSUPP ) ) {
2014-01-01 03:53:40 +04:00
READDIR3args args ;
args . dir = data - > fh ;
args . cookie = cookie ;
2014-01-01 04:11:11 +04:00
memset ( & args . cookieverf , 0 , sizeof ( cookieverf3 ) ) ;
2014-01-01 03:53:40 +04:00
args . count = 8192 ;
2011-10-03 03:55:42 +04:00
2014-01-01 03:53:40 +04:00
if ( rpc_nfs3_readdir_async ( nfs - > rpc , nfs_opendir2_cb , & args , data ) ! = 0 ) {
2011-10-03 03:55:42 +04:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send READDIR call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
nfs_free_nfsdir ( nfsdir ) ;
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
return ;
}
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
nfs_free_nfsdir ( nfsdir ) ;
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: READDIRPLUS of %s failed with %s(%d) " , data - > saved_path , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
nfs_free_nfsdir ( nfsdir ) ;
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
return ;
2011-02-06 07:45:09 +03:00
}
2011-09-02 14:27:01 +04:00
entry = res - > READDIRPLUS3res_u . resok . reply . entries ;
2011-02-06 07:45:09 +03:00
while ( entry ! = NULL ) {
struct nfsdirent * nfsdirent ;
nfsdirent = malloc ( sizeof ( struct nfsdirent ) ) ;
if ( nfsdirent = = NULL ) {
data - > cb ( - ENOMEM , nfs , " Failed to allocate dirent " , data - > private_data ) ;
nfs_free_nfsdir ( nfsdir ) ;
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
return ;
}
2011-09-03 08:11:22 +04:00
memset ( nfsdirent , 0 , sizeof ( struct nfsdirent ) ) ;
2011-02-06 07:45:09 +03:00
nfsdirent - > name = strdup ( entry - > name ) ;
if ( nfsdirent - > name = = NULL ) {
data - > cb ( - ENOMEM , nfs , " Failed to allocate dirent->name " , data - > private_data ) ;
2014-02-18 01:44:47 +04:00
free ( nfsdirent ) ;
2011-02-06 07:45:09 +03:00
nfs_free_nfsdir ( nfsdir ) ;
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
return ;
}
nfsdirent - > inode = entry - > fileid ;
2011-09-02 14:45:30 +04:00
if ( entry - > name_attributes . attributes_follow ) {
nfsdirent - > type = entry - > name_attributes . post_op_attr_u . attributes . type ;
nfsdirent - > mode = entry - > name_attributes . post_op_attr_u . attributes . mode ;
nfsdirent - > size = entry - > name_attributes . post_op_attr_u . attributes . size ;
nfsdirent - > atime . tv_sec = entry - > name_attributes . post_op_attr_u . attributes . atime . seconds ;
nfsdirent - > atime . tv_usec = entry - > name_attributes . post_op_attr_u . attributes . atime . nseconds / 1000 ;
nfsdirent - > mtime . tv_sec = entry - > name_attributes . post_op_attr_u . attributes . mtime . seconds ;
nfsdirent - > mtime . tv_usec = entry - > name_attributes . post_op_attr_u . attributes . mtime . nseconds / 1000 ;
nfsdirent - > ctime . tv_sec = entry - > name_attributes . post_op_attr_u . attributes . ctime . seconds ;
nfsdirent - > ctime . tv_usec = entry - > name_attributes . post_op_attr_u . attributes . ctime . nseconds / 1000 ;
2014-01-01 04:25:01 +04:00
nfsdirent - > uid = entry - > name_attributes . post_op_attr_u . attributes . uid ;
nfsdirent - > gid = entry - > name_attributes . post_op_attr_u . attributes . gid ;
2014-06-08 22:40:35 +04:00
nfsdirent - > nlink = entry - > name_attributes . post_op_attr_u . attributes . nlink ;
2011-09-02 14:45:30 +04:00
}
2011-02-06 07:45:09 +03:00
nfsdirent - > next = nfsdir - > entries ;
nfsdir - > entries = nfsdirent ;
cookie = entry - > cookie ;
entry = entry - > nextentry ;
}
2011-09-02 14:27:01 +04:00
if ( res - > READDIRPLUS3res_u . resok . reply . eof = = 0 ) {
2014-01-01 03:58:59 +04:00
READDIRPLUS3args args ;
args . dir = data - > fh ;
args . cookie = cookie ;
memcpy ( & args . cookieverf , res - > READDIRPLUS3res_u . resok . cookieverf , sizeof ( cookieverf3 ) ) ;
args . dircount = 8192 ;
args . maxcount = 8192 ;
if ( rpc_nfs3_readdirplus_async ( nfs - > rpc , nfs_opendir_cb , & args , data ) ! = 0 ) {
2011-09-02 14:27:01 +04:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send READDIRPLUS call for %s " , data - > path ) ;
2011-02-06 07:45:09 +03:00
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
nfs_free_nfsdir ( nfsdir ) ;
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
return ;
}
return ;
}
2014-06-08 22:22:06 +04:00
if ( res - > READDIRPLUS3res_u . resok . dir_attributes . attributes_follow )
nfsdir - > attr = res - > READDIRPLUS3res_u . resok . dir_attributes . post_op_attr_u . attributes ;
2011-02-06 07:45:09 +03:00
/* steal the dirhandle */
data - > continue_data = NULL ;
nfsdir - > current = nfsdir - > entries ;
data - > cb ( 0 , nfs , nfsdir , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-06-08 20:45:22 +04:00
static int nfs_opendir_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
2014-01-01 03:58:59 +04:00
READDIRPLUS3args args ;
2014-06-08 22:22:06 +04:00
struct nfsdir * nfsdir = data - > continue_data ; ;
struct nfsdir * cached ;
cached = nfs_dircache_find ( nfs , & data - > fh ) ;
if ( cached ) {
if ( attr & & attr - > mtime . seconds = = cached - > attr . mtime . seconds ) {
cached - > current = cached - > entries ;
data - > cb ( 0 , nfs , cached , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return 0 ;
} else {
/* cache must be stale */
nfs_free_nfsdir ( cached ) ;
}
}
nfsdir - > fh . data . data_len = data - > fh . data . data_len ;
nfsdir - > fh . data . data_val = malloc ( nfsdir - > fh . data . data_len ) ;
if ( nfsdir - > fh . data . data_val = = NULL ) {
rpc_set_error ( nfs - > rpc , " OOM when allocating fh for nfsdir " ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
memcpy ( nfsdir - > fh . data . data_val , data - > fh . data . data_val , data - > fh . data . data_len ) ;
2011-02-06 07:45:09 +03:00
2014-01-01 03:58:59 +04:00
args . dir = data - > fh ;
args . cookie = 0 ;
memset ( & args . cookieverf , 0 , sizeof ( cookieverf3 ) ) ;
args . dircount = 8192 ;
args . maxcount = 8192 ;
if ( rpc_nfs3_readdirplus_async ( nfs - > rpc , nfs_opendir_cb , & args , data ) ! = 0 ) {
2011-09-02 14:27:01 +04:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send READDIRPLUS call for %s " , data - > path ) ;
2011-02-06 07:45:09 +03:00
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
int nfs_opendir_async ( struct nfs_context * nfs , const char * path , nfs_cb cb , void * private_data )
{
struct nfsdir * nfsdir ;
nfsdir = malloc ( sizeof ( struct nfsdir ) ) ;
if ( nfsdir = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " failed to allocate buffer for nfsdir " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
2011-09-03 08:11:22 +04:00
memset ( nfsdir , 0 , sizeof ( struct nfsdir ) ) ;
2011-02-06 07:45:09 +03:00
if ( nfs_lookuppath_async ( nfs , path , cb , private_data , nfs_opendir_continue_internal , nfsdir , free , 0 ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
return - 1 ;
2011-02-06 07:45:09 +03:00
}
return 0 ;
}
struct nfsdirent * nfs_readdir ( struct nfs_context * nfs _U_ , struct nfsdir * nfsdir )
{
struct nfsdirent * nfsdirent = nfsdir - > current ;
if ( nfsdir - > current ! = NULL ) {
nfsdir - > current = nfsdir - > current - > next ;
}
return nfsdirent ;
}
2014-01-28 08:54:14 +04:00
/*
* closedir ( )
*/
2014-06-08 22:22:06 +04:00
void nfs_closedir ( struct nfs_context * nfs , struct nfsdir * nfsdir )
2011-02-06 07:45:09 +03:00
{
2014-06-08 22:22:06 +04:00
nfs_dircache_add ( nfs , nfsdir ) ;
2011-02-06 07:45:09 +03:00
}
2014-01-28 08:54:14 +04:00
/*
* getcwd ( )
*/
void nfs_getcwd ( struct nfs_context * nfs , const char * * cwd )
{
if ( cwd ) {
* cwd = nfs - > cwd ;
}
}
2011-02-06 07:45:09 +03:00
/*
* Async lseek ( )
*/
struct lseek_cb_data {
struct nfs_context * nfs ;
struct nfsfh * nfsfh ;
2014-03-31 23:23:48 +04:00
int64_t offset ;
2011-02-06 07:45:09 +03:00
nfs_cb cb ;
void * private_data ;
} ;
2012-11-24 20:18:54 +04:00
static void nfs_lseek_1_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
GETATTR3res * res ;
struct lseek_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
2014-03-31 23:23:48 +04:00
uint64_t size = 0 ;
2011-02-06 07:45:09 +03:00
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: GETATTR failed with %s(%d) " , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free ( data ) ;
return ;
}
2014-03-31 23:23:48 +04:00
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 ) ;
}
2011-02-06 07:45:09 +03:00
free ( data ) ;
}
2014-03-31 23:23:48 +04:00
int nfs_lseek_async ( struct nfs_context * nfs , struct nfsfh * nfsfh , int64_t offset , int whence , nfs_cb cb , void * private_data )
2011-02-06 07:45:09 +03:00
{
struct lseek_cb_data * data ;
2013-12-24 23:16:21 +04:00
struct GETATTR3args args ;
2011-02-06 07:45:09 +03:00
if ( whence = = SEEK_SET ) {
2014-03-31 23:23:48 +04:00
if ( offset < 0 ) {
cb ( - EINVAL , nfs , & nfsfh - > offset , private_data ) ;
} else {
nfsfh - > offset = offset ;
cb ( 0 , nfs , & nfsfh - > offset , private_data ) ;
}
2011-02-06 07:45:09 +03:00
return 0 ;
}
if ( whence = = SEEK_CUR ) {
2014-03-31 23:23:48 +04:00
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 ) ;
}
2011-02-06 07:45:09 +03:00
return 0 ;
}
data = malloc ( sizeof ( struct lseek_cb_data ) ) ;
if ( data = = NULL ) {
rpc_set_error ( nfs - > rpc , " Out Of Memory: Failed to malloc lseek cb data " ) ;
return - 1 ;
}
data - > nfs = nfs ;
data - > nfsfh = nfsfh ;
data - > offset = offset ;
data - > cb = cb ;
data - > private_data = private_data ;
2013-12-24 23:16:21 +04:00
memset ( & args , 0 , sizeof ( GETATTR3args ) ) ;
2014-01-01 04:11:11 +04:00
args . object = nfsfh - > fh ;
2013-12-24 23:16:21 +04:00
if ( rpc_nfs3_getattr_async ( nfs - > rpc , nfs_lseek_1_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send LSEEK GETATTR call " ) ;
free ( data ) ;
2011-06-19 03:03:04 +04:00
return - 1 ;
2011-02-06 07:45:09 +03:00
}
return 0 ;
}
/*
* Async statvfs ( )
*/
2012-11-24 20:18:54 +04:00
static void nfs_statvfs_1_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
FSSTAT3res * res ;
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
struct statvfs svfs ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: FSSTAT of %s failed with %s(%d) " , data - > saved_path , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
2014-06-23 18:31:32 +04:00
svfs . f_bsize = NFS_BLKSIZE ;
svfs . f_frsize = NFS_BLKSIZE ;
svfs . f_blocks = res - > FSSTAT3res_u . resok . tbytes / NFS_BLKSIZE ;
svfs . f_bfree = res - > FSSTAT3res_u . resok . fbytes / NFS_BLKSIZE ;
svfs . f_bavail = res - > FSSTAT3res_u . resok . abytes / NFS_BLKSIZE ;
2011-02-06 07:45:09 +03:00
svfs . f_files = res - > FSSTAT3res_u . resok . tfiles ;
svfs . f_ffree = res - > FSSTAT3res_u . resok . ffiles ;
2012-11-28 21:04:05 +04:00
# if !defined(ANDROID)
2011-02-06 07:45:09 +03:00
svfs . f_favail = res - > FSSTAT3res_u . resok . afiles ;
svfs . f_fsid = 0 ;
svfs . f_flag = 0 ;
svfs . f_namemax = 256 ;
2012-11-28 21:04:05 +04:00
# endif
2011-02-06 07:45:09 +03:00
data - > cb ( 0 , nfs , & svfs , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-06-08 20:45:22 +04:00
static int nfs_statvfs_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
2014-01-01 03:08:11 +04:00
FSSTAT3args args ;
args . fsroot = data - > fh ;
if ( rpc_nfs3_fsstat_async ( nfs - > rpc , nfs_statvfs_1_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send FSSTAT call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
int nfs_statvfs_async ( struct nfs_context * nfs , const char * path , nfs_cb cb , void * private_data )
{
if ( nfs_lookuppath_async ( nfs , path , cb , private_data , nfs_statvfs_continue_internal , NULL , NULL , 0 ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
return 0 ;
}
/*
* Async readlink ( )
*/
2012-11-24 20:18:54 +04:00
static void nfs_readlink_1_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
READLINK3res * res ;
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: READLINK of %s failed with %s(%d) " , data - > saved_path , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
2014-02-14 01:36:54 +04:00
2011-02-06 07:45:09 +03:00
data - > cb ( 0 , nfs , res - > READLINK3res_u . resok . data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-06-08 20:45:22 +04:00
static int nfs_readlink_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
2012-01-14 01:11:09 +04:00
READLINK3args args ;
2014-01-01 04:11:11 +04:00
args . symlink = data - > fh ;
2012-01-14 01:11:09 +04:00
2014-01-01 03:46:32 +04:00
if ( rpc_nfs3_readlink_async ( nfs - > rpc , nfs_readlink_1_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send READLINK call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
int nfs_readlink_async ( struct nfs_context * nfs , const char * path , nfs_cb cb , void * private_data )
{
if ( nfs_lookuppath_async ( nfs , path , cb , private_data , nfs_readlink_continue_internal , NULL , NULL , 0 ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
return 0 ;
}
/*
* Async chmod ( )
*/
2012-11-24 20:18:54 +04:00
static void nfs_chmod_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
SETATTR3res * res ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: SETATTR failed with %s(%d) " , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
data - > cb ( 0 , nfs , NULL , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-06-08 20:45:22 +04:00
static int nfs_chmod_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
SETATTR3args args ;
2011-09-03 08:11:22 +04:00
memset ( & args , 0 , sizeof ( SETATTR3args ) ) ;
2014-01-01 04:11:11 +04:00
args . object = data - > fh ;
2011-02-06 07:45:09 +03:00
args . new_attributes . mode . set_it = 1 ;
args . new_attributes . mode . set_mode3_u . mode = data - > continue_int ;
2014-01-01 03:12:32 +04:00
if ( rpc_nfs3_setattr_async ( nfs - > rpc , nfs_chmod_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send SETATTR call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
int nfs_chmod_async ( struct nfs_context * nfs , const char * path , int mode , nfs_cb cb , void * private_data )
{
if ( nfs_lookuppath_async ( nfs , path , cb , private_data , nfs_chmod_continue_internal , NULL , NULL , mode ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
return 0 ;
}
/*
* Async fchmod ( )
*/
int nfs_fchmod_async ( struct nfs_context * nfs , struct nfsfh * nfsfh , int mode , nfs_cb cb , void * private_data )
{
struct nfs_cb_data * data ;
data = malloc ( sizeof ( struct nfs_cb_data ) ) ;
if ( data = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " out of memory. failed to allocate memory for nfs mount data " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
2011-09-03 08:11:22 +04:00
memset ( data , 0 , sizeof ( struct nfs_cb_data ) ) ;
2011-02-06 07:45:09 +03:00
data - > nfs = nfs ;
data - > cb = cb ;
data - > private_data = private_data ;
data - > continue_int = mode ;
data - > fh . data . data_len = nfsfh - > fh . data . data_len ;
data - > fh . data . data_val = malloc ( data - > fh . data . data_len ) ;
if ( data - > fh . data . data_val = = NULL ) {
rpc_set_error ( nfs - > rpc , " Out of memory: Failed to allocate fh " ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
memcpy ( data - > fh . data . data_val , nfsfh - > fh . data . data_val , data - > fh . data . data_len ) ;
2014-06-08 20:45:22 +04:00
if ( nfs_chmod_continue_internal ( nfs , NULL , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
return - 1 ;
}
return 0 ;
}
/*
* Async chown ( )
*/
2012-11-24 20:18:54 +04:00
static void nfs_chown_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
SETATTR3res * res ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: SETATTR failed with %s(%d) " , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
data - > cb ( 0 , nfs , NULL , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
struct nfs_chown_data {
uid_t uid ;
gid_t gid ;
} ;
2014-06-08 20:45:22 +04:00
static int nfs_chown_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
SETATTR3args args ;
struct nfs_chown_data * chown_data = data - > continue_data ;
2011-09-03 08:11:22 +04:00
memset ( & args , 0 , sizeof ( SETATTR3args ) ) ;
2014-01-01 04:11:11 +04:00
args . object = data - > fh ;
2011-02-06 07:45:09 +03:00
if ( chown_data - > uid ! = ( uid_t ) - 1 ) {
args . new_attributes . uid . set_it = 1 ;
args . new_attributes . uid . set_uid3_u . uid = chown_data - > uid ;
}
if ( chown_data - > gid ! = ( gid_t ) - 1 ) {
args . new_attributes . gid . set_it = 1 ;
args . new_attributes . gid . set_gid3_u . gid = chown_data - > gid ;
}
2014-01-01 03:12:32 +04:00
if ( rpc_nfs3_setattr_async ( nfs - > rpc , nfs_chown_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send SETATTR call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
int nfs_chown_async ( struct nfs_context * nfs , const char * path , int uid , int gid , nfs_cb cb , void * private_data )
{
struct nfs_chown_data * chown_data ;
chown_data = malloc ( sizeof ( struct nfs_chown_data ) ) ;
if ( chown_data = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Failed to allocate memory for chown data structure " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
chown_data - > uid = uid ;
chown_data - > gid = gid ;
if ( nfs_lookuppath_async ( nfs , path , cb , private_data , nfs_chown_continue_internal , chown_data , free , 0 ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
return 0 ;
}
/*
* Async fchown ( )
*/
int nfs_fchown_async ( struct nfs_context * nfs , struct nfsfh * nfsfh , int uid , int gid , nfs_cb cb , void * private_data )
{
struct nfs_cb_data * data ;
struct nfs_chown_data * chown_data ;
chown_data = malloc ( sizeof ( struct nfs_chown_data ) ) ;
if ( chown_data = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Failed to allocate memory for chown data structure " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
chown_data - > uid = uid ;
chown_data - > gid = gid ;
data = malloc ( sizeof ( struct nfs_cb_data ) ) ;
if ( data = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " out of memory. failed to allocate memory for fchown data " ) ;
2014-02-18 02:17:15 +04:00
free ( chown_data ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
2011-09-03 08:11:22 +04:00
memset ( data , 0 , sizeof ( struct nfs_cb_data ) ) ;
2011-02-06 07:45:09 +03:00
data - > nfs = nfs ;
data - > cb = cb ;
data - > private_data = private_data ;
data - > continue_data = chown_data ;
2014-02-18 02:22:02 +04:00
data - > free_continue_data = free ;
2011-02-06 07:45:09 +03:00
data - > fh . data . data_len = nfsfh - > fh . data . data_len ;
data - > fh . data . data_val = malloc ( data - > fh . data . data_len ) ;
if ( data - > fh . data . data_val = = NULL ) {
rpc_set_error ( nfs - > rpc , " Out of memory: Failed to allocate fh " ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
memcpy ( data - > fh . data . data_val , nfsfh - > fh . data . data_val , data - > fh . data . data_len ) ;
2014-06-08 20:45:22 +04:00
if ( nfs_chown_continue_internal ( nfs , NULL , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
return - 1 ;
}
return 0 ;
}
/*
* Async utimes ( )
*/
2012-11-24 20:18:54 +04:00
static void nfs_utimes_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
SETATTR3res * res ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: SETATTR failed with %s(%d) " , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
data - > cb ( 0 , nfs , NULL , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-06-08 20:45:22 +04:00
static int nfs_utimes_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
SETATTR3args args ;
struct timeval * utimes_data = data - > continue_data ;
2011-09-03 08:11:22 +04:00
memset ( & args , 0 , sizeof ( SETATTR3args ) ) ;
2014-01-01 04:11:11 +04:00
args . object = data - > fh ;
2011-02-06 07:45:09 +03:00
if ( utimes_data ! = NULL ) {
args . new_attributes . atime . set_it = SET_TO_CLIENT_TIME ;
args . new_attributes . atime . set_atime_u . atime . seconds = utimes_data [ 0 ] . tv_sec ;
args . new_attributes . atime . set_atime_u . atime . nseconds = utimes_data [ 0 ] . tv_usec * 1000 ;
args . new_attributes . mtime . set_it = SET_TO_CLIENT_TIME ;
args . new_attributes . mtime . set_mtime_u . mtime . seconds = utimes_data [ 1 ] . tv_sec ;
args . new_attributes . mtime . set_mtime_u . mtime . nseconds = utimes_data [ 1 ] . tv_usec * 1000 ;
} else {
args . new_attributes . atime . set_it = SET_TO_SERVER_TIME ;
args . new_attributes . mtime . set_it = SET_TO_SERVER_TIME ;
}
2014-01-01 03:12:32 +04:00
if ( rpc_nfs3_setattr_async ( nfs - > rpc , nfs_utimes_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send SETATTR call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
int nfs_utimes_async ( struct nfs_context * nfs , const char * path , struct timeval * times , nfs_cb cb , void * private_data )
{
struct timeval * new_times = NULL ;
if ( times ! = NULL ) {
new_times = malloc ( sizeof ( struct timeval ) * 2 ) ;
if ( new_times = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Failed to allocate memory for timeval structure " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
memcpy ( new_times , times , sizeof ( struct timeval ) * 2 ) ;
}
if ( nfs_lookuppath_async ( nfs , path , cb , private_data , nfs_utimes_continue_internal , new_times , free , 0 ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
return 0 ;
}
/*
* Async utime ( )
*/
int nfs_utime_async ( struct nfs_context * nfs , const char * path , struct utimbuf * times , nfs_cb cb , void * private_data )
{
struct timeval * new_times = NULL ;
if ( times ! = NULL ) {
new_times = malloc ( sizeof ( struct timeval ) * 2 ) ;
if ( new_times = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Failed to allocate memory for timeval structure " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
new_times [ 0 ] . tv_sec = times - > actime ;
new_times [ 0 ] . tv_usec = 0 ;
new_times [ 1 ] . tv_sec = times - > modtime ;
new_times [ 1 ] . tv_usec = 0 ;
}
if ( nfs_lookuppath_async ( nfs , path , cb , private_data , nfs_utimes_continue_internal , new_times , free , 0 ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
return 0 ;
}
/*
* Async access ( )
*/
2012-11-24 20:18:54 +04:00
static void nfs_access_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
ACCESS3res * res ;
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
unsigned int nfsmode = 0 ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: ACCESS of %s failed with %s(%d) " , data - > saved_path , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( data - > continue_int & R_OK ) {
nfsmode | = ACCESS3_READ ;
}
if ( data - > continue_int & W_OK ) {
nfsmode | = ACCESS3_MODIFY ;
}
if ( data - > continue_int & X_OK ) {
nfsmode | = ACCESS3_EXECUTE ;
}
if ( res - > ACCESS3res_u . resok . access ! = nfsmode ) {
rpc_set_error ( nfs - > rpc , " NFS: ACCESS denied. Required access %c%c%c. Allowed access %c%c%c " ,
nfsmode & ACCESS3_READ ? ' r ' : ' - ' ,
nfsmode & ACCESS3_MODIFY ? ' w ' : ' - ' ,
nfsmode & ACCESS3_EXECUTE ? ' x ' : ' - ' ,
res - > ACCESS3res_u . resok . access & ACCESS3_READ ? ' r ' : ' - ' ,
res - > ACCESS3res_u . resok . access & ACCESS3_MODIFY ? ' w ' : ' - ' ,
res - > ACCESS3res_u . resok . access & ACCESS3_EXECUTE ? ' x ' : ' - ' ) ;
data - > cb ( - EACCES , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
data - > cb ( 0 , nfs , NULL , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-06-08 20:45:22 +04:00
static int nfs_access_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
int nfsmode = 0 ;
2013-12-24 23:16:21 +04:00
ACCESS3args args ;
2011-02-06 07:45:09 +03:00
if ( data - > continue_int & R_OK ) {
nfsmode | = ACCESS3_READ ;
}
if ( data - > continue_int & W_OK ) {
nfsmode | = ACCESS3_MODIFY ;
}
if ( data - > continue_int & X_OK ) {
nfsmode | = ACCESS3_EXECUTE ;
}
2013-12-24 23:16:21 +04:00
memset ( & args , 0 , sizeof ( ACCESS3args ) ) ;
2014-01-01 04:11:11 +04:00
args . object = data - > fh ;
2013-12-24 23:16:21 +04:00
args . access = nfsmode ;
if ( rpc_nfs3_access_async ( nfs - > rpc , nfs_access_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send OPEN ACCESS call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
int nfs_access_async ( struct nfs_context * nfs , const char * path , int mode , nfs_cb cb , void * private_data )
{
if ( nfs_lookuppath_async ( nfs , path , cb , private_data , nfs_access_continue_internal , NULL , NULL , mode ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
return - 1 ;
2011-02-06 07:45:09 +03:00
}
return 0 ;
}
/*
* Async symlink ( )
*/
struct nfs_symlink_data {
char * oldpath ;
char * newpathparent ;
char * newpathobject ;
} ;
static void free_nfs_symlink_data ( void * mem )
{
struct nfs_symlink_data * data = mem ;
if ( data - > oldpath ! = NULL ) {
free ( data - > oldpath ) ;
}
if ( data - > newpathparent ! = NULL ) {
free ( data - > newpathparent ) ;
}
if ( data - > newpathobject ! = NULL ) {
free ( data - > newpathobject ) ;
}
free ( data ) ;
}
2012-11-24 20:18:54 +04:00
static void nfs_symlink_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
SYMLINK3res * res ;
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
struct nfs_symlink_data * symlink_data = data - > continue_data ;
2014-02-14 01:36:54 +04:00
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: SYMLINK %s/%s -> %s failed with %s(%d) " , symlink_data - > newpathparent , symlink_data - > newpathobject , symlink_data - > oldpath , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
data - > cb ( 0 , nfs , NULL , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-06-08 20:45:22 +04:00
static int nfs_symlink_continue_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
struct nfs_symlink_data * symlink_data = data - > continue_data ;
2014-01-01 03:44:15 +04:00
SYMLINK3args args ;
2011-02-06 07:45:09 +03:00
2014-01-01 03:44:15 +04:00
memset ( & args , 0 , sizeof ( SYMLINK3args ) ) ;
2014-01-01 04:11:11 +04:00
args . where . dir = data - > fh ;
2014-01-01 03:44:15 +04:00
args . where . name = symlink_data - > newpathobject ;
args . symlink . symlink_attributes . mode . set_it = 1 ;
args . symlink . symlink_attributes . mode . set_mode3_u . mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH ;
args . symlink . symlink_data = symlink_data - > oldpath ;
2012-01-14 01:18:19 +04:00
2014-01-01 03:44:15 +04:00
if ( rpc_nfs3_symlink_async ( nfs - > rpc , nfs_symlink_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send SYMLINK call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
int nfs_symlink_async ( struct nfs_context * nfs , const char * oldpath , const char * newpath , nfs_cb cb , void * private_data )
{
char * ptr ;
struct nfs_symlink_data * symlink_data ;
symlink_data = malloc ( sizeof ( struct nfs_symlink_data ) ) ;
if ( symlink_data = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate buffer for symlink data " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
2011-09-03 08:11:22 +04:00
memset ( symlink_data , 0 , sizeof ( struct nfs_symlink_data ) ) ;
2011-02-06 07:45:09 +03:00
symlink_data - > oldpath = strdup ( oldpath ) ;
if ( symlink_data - > oldpath = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate buffer for oldpath " ) ;
2011-02-06 07:45:09 +03:00
free_nfs_symlink_data ( symlink_data ) ;
2011-06-19 03:03:04 +04:00
return - 1 ;
2011-02-06 07:45:09 +03:00
}
symlink_data - > newpathparent = strdup ( newpath ) ;
if ( symlink_data - > newpathparent = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate mode buffer for new path " ) ;
2011-02-06 07:45:09 +03:00
free_nfs_symlink_data ( symlink_data ) ;
2011-06-19 03:03:04 +04:00
return - 1 ;
2011-02-06 07:45:09 +03:00
}
2011-08-28 13:27:23 +04:00
ptr = strrchr ( symlink_data - > newpathparent , ' / ' ) ;
2011-02-06 07:45:09 +03:00
if ( ptr = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Invalid path %s " , oldpath ) ;
2011-02-06 07:45:09 +03:00
free_nfs_symlink_data ( symlink_data ) ;
2011-06-19 03:03:04 +04:00
return - 1 ;
2011-02-06 07:45:09 +03:00
}
* ptr = 0 ;
ptr + + ;
symlink_data - > newpathobject = strdup ( ptr ) ;
if ( symlink_data - > newpathobject = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate mode buffer for new path " ) ;
2011-02-06 07:45:09 +03:00
free_nfs_symlink_data ( symlink_data ) ;
2011-06-19 03:03:04 +04:00
return - 1 ;
2011-02-06 07:45:09 +03:00
}
if ( nfs_lookuppath_async ( nfs , symlink_data - > newpathparent , cb , private_data , nfs_symlink_continue_internal , symlink_data , free_nfs_symlink_data , 0 ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
return - 1 ;
2011-02-06 07:45:09 +03:00
}
return 0 ;
}
/*
* Async rename ( )
*/
struct nfs_rename_data {
char * oldpath ;
char * oldobject ;
struct nfs_fh3 olddir ;
char * newpath ;
char * newobject ;
struct nfs_fh3 newdir ;
} ;
static void free_nfs_rename_data ( void * mem )
{
struct nfs_rename_data * data = mem ;
if ( data - > oldpath ! = NULL ) {
free ( data - > oldpath ) ;
}
if ( data - > olddir . data . data_val ! = NULL ) {
free ( data - > olddir . data . data_val ) ;
}
if ( data - > newpath ! = NULL ) {
free ( data - > newpath ) ;
}
if ( data - > newdir . data . data_val ! = NULL ) {
free ( data - > newdir . data . data_val ) ;
}
free ( data ) ;
}
2012-11-24 20:18:54 +04:00
static void nfs_rename_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
RENAME3res * res ;
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
struct nfs_rename_data * rename_data = data - > continue_data ;
2014-02-14 01:36:54 +04:00
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: RENAME %s/%s -> %s/%s failed with %s(%d) " , rename_data - > oldpath , rename_data - > oldobject , rename_data - > newpath , rename_data - > newobject , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
data - > cb ( 0 , nfs , NULL , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-06-08 20:45:22 +04:00
static int nfs_rename_continue_2_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
struct nfs_rename_data * rename_data = data - > continue_data ;
2014-01-01 03:37:40 +04:00
RENAME3args args ;
2011-02-06 07:45:09 +03:00
/* steal the filehandle */
2014-01-01 04:11:11 +04:00
rename_data - > newdir = data - > fh ;
2011-02-06 07:45:09 +03:00
data - > fh . data . data_val = NULL ;
2014-01-01 03:37:40 +04:00
args . from . dir = rename_data - > olddir ;
args . from . name = rename_data - > oldobject ;
args . to . dir = rename_data - > newdir ;
args . to . name = rename_data - > newobject ;
if ( rpc_nfs3_rename_async ( nfs - > rpc , nfs_rename_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send RENAME call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
2014-06-08 20:45:22 +04:00
static int nfs_rename_continue_1_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
struct nfs_rename_data * rename_data = data - > continue_data ;
2014-02-18 03:32:10 +04:00
char * newpath = strdup ( rename_data - > newpath ) ;
if ( ! newpath ) {
rpc_set_error ( nfs - > rpc , " Out of memory. Could not allocate memory to store target path for rename " ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
2011-02-06 07:45:09 +03:00
/* steal the filehandle */
2014-01-01 04:11:11 +04:00
rename_data - > olddir = data - > fh ;
2011-02-06 07:45:09 +03:00
data - > fh . data . data_val = NULL ;
if ( nfs_lookuppath_async ( nfs , rename_data - > newpath , data - > cb , data - > private_data , nfs_rename_continue_2_internal , rename_data , free_nfs_rename_data , 0 ) ! = 0 ) {
2014-02-18 03:32:10 +04:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send LOOKUP call for %s " , newpath ) ;
2011-02-06 07:45:09 +03:00
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
2014-02-18 03:32:10 +04:00
free ( newpath ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
2014-02-18 03:32:10 +04:00
free ( newpath ) ;
2011-02-06 07:45:09 +03:00
return 0 ;
}
int nfs_rename_async ( struct nfs_context * nfs , const char * oldpath , const char * newpath , nfs_cb cb , void * private_data )
{
char * ptr ;
struct nfs_rename_data * rename_data ;
rename_data = malloc ( sizeof ( struct nfs_rename_data ) ) ;
if ( rename_data = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate buffer for rename data " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
2011-09-03 08:11:22 +04:00
memset ( rename_data , 0 , sizeof ( struct nfs_rename_data ) ) ;
2011-02-06 07:45:09 +03:00
rename_data - > oldpath = strdup ( oldpath ) ;
if ( rename_data - > oldpath = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate buffer for oldpath " ) ;
2011-02-06 07:45:09 +03:00
free_nfs_rename_data ( rename_data ) ;
2011-06-19 03:03:04 +04:00
return - 1 ;
2011-02-06 07:45:09 +03:00
}
2011-08-28 13:27:23 +04:00
ptr = strrchr ( rename_data - > oldpath , ' / ' ) ;
2011-02-06 07:45:09 +03:00
if ( ptr = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Invalid path %s " , oldpath ) ;
2011-02-06 07:45:09 +03:00
free_nfs_rename_data ( rename_data ) ;
2011-06-19 03:03:04 +04:00
return - 1 ;
2011-02-06 07:45:09 +03:00
}
* ptr = 0 ;
ptr + + ;
rename_data - > oldobject = ptr ;
rename_data - > newpath = strdup ( newpath ) ;
if ( rename_data - > newpath = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate buffer for newpath " ) ;
2011-02-06 07:45:09 +03:00
free_nfs_rename_data ( rename_data ) ;
2011-06-19 03:03:04 +04:00
return - 1 ;
2011-02-06 07:45:09 +03:00
}
2011-08-28 13:27:23 +04:00
ptr = strrchr ( rename_data - > newpath , ' / ' ) ;
2011-02-06 07:45:09 +03:00
if ( ptr = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Invalid path %s " , newpath ) ;
2011-02-06 07:45:09 +03:00
free_nfs_rename_data ( rename_data ) ;
2011-06-19 03:03:04 +04:00
return - 1 ;
2011-02-06 07:45:09 +03:00
}
* ptr = 0 ;
ptr + + ;
rename_data - > newobject = ptr ;
if ( nfs_lookuppath_async ( nfs , rename_data - > oldpath , cb , private_data , nfs_rename_continue_1_internal , rename_data , free_nfs_rename_data , 0 ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
return - 1 ;
2011-02-06 07:45:09 +03:00
}
return 0 ;
}
/*
* Async link ( )
*/
struct nfs_link_data {
char * oldpath ;
struct nfs_fh3 oldfh ;
char * newpath ;
char * newobject ;
struct nfs_fh3 newdir ;
} ;
static void free_nfs_link_data ( void * mem )
{
struct nfs_link_data * data = mem ;
if ( data - > oldpath ! = NULL ) {
free ( data - > oldpath ) ;
}
if ( data - > oldfh . data . data_val ! = NULL ) {
free ( data - > oldfh . data . data_val ) ;
}
if ( data - > newpath ! = NULL ) {
free ( data - > newpath ) ;
}
if ( data - > newdir . data . data_val ! = NULL ) {
free ( data - > newdir . data . data_val ) ;
}
free ( data ) ;
}
2012-11-24 20:18:54 +04:00
static void nfs_link_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
2011-02-06 07:45:09 +03:00
{
LINK3res * res ;
struct nfs_cb_data * data = private_data ;
struct nfs_context * nfs = data - > nfs ;
struct nfs_link_data * link_data = data - > continue_data ;
2014-02-14 01:36:54 +04:00
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-02-06 07:45:09 +03:00
if ( status = = RPC_STATUS_ERROR ) {
data - > cb ( - EFAULT , nfs , command_data , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( - EINTR , nfs , " Command was cancelled " , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
res = command_data ;
if ( res - > status ! = NFS3_OK ) {
rpc_set_error ( nfs - > rpc , " NFS: LINK %s -> %s/%s failed with %s(%d) " , link_data - > oldpath , link_data - > newpath , link_data - > newobject , nfsstat3_to_str ( res - > status ) , nfsstat3_to_errno ( res - > status ) ) ;
data - > cb ( nfsstat3_to_errno ( res - > status ) , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return ;
}
data - > cb ( 0 , nfs , NULL , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
}
2014-06-08 20:45:22 +04:00
static int nfs_link_continue_2_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
struct nfs_link_data * link_data = data - > continue_data ;
2014-01-01 03:43:00 +04:00
LINK3args args ;
2011-02-06 07:45:09 +03:00
/* steal the filehandle */
2014-01-01 04:11:11 +04:00
link_data - > newdir = data - > fh ;
2011-02-06 07:45:09 +03:00
data - > fh . data . data_val = NULL ;
2014-01-01 03:43:00 +04:00
memset ( & args , 0 , sizeof ( LINK3args ) ) ;
args . file = link_data - > oldfh ;
args . link . dir = link_data - > newdir ;
args . link . name = link_data - > newobject ;
if ( rpc_nfs3_link_async ( nfs - > rpc , nfs_link_cb , & args , data ) ! = 0 ) {
2011-02-06 07:45:09 +03:00
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send LINK call for %s " , data - > path ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
2014-06-08 20:45:22 +04:00
static int nfs_link_continue_1_internal ( struct nfs_context * nfs , fattr3 * attr _U_ , struct nfs_cb_data * data )
2011-02-06 07:45:09 +03:00
{
struct nfs_link_data * link_data = data - > continue_data ;
/* steal the filehandle */
2014-01-01 04:11:11 +04:00
link_data - > oldfh = data - > fh ;
2011-02-06 07:45:09 +03:00
data - > fh . data . data_val = NULL ;
if ( nfs_lookuppath_async ( nfs , link_data - > newpath , data - > cb , data - > private_data , nfs_link_continue_2_internal , link_data , free_nfs_link_data , 0 ) ! = 0 ) {
rpc_set_error ( nfs - > rpc , " RPC error: Failed to send LOOKUP call for %s " , link_data - > newpath ) ;
data - > cb ( - ENOMEM , nfs , rpc_get_error ( nfs - > rpc ) , data - > private_data ) ;
free_nfs_cb_data ( data ) ;
return - 1 ;
}
data - > continue_data = NULL ;
free_nfs_cb_data ( data ) ;
return 0 ;
}
int nfs_link_async ( struct nfs_context * nfs , const char * oldpath , const char * newpath , nfs_cb cb , void * private_data )
{
char * ptr ;
struct nfs_link_data * link_data ;
link_data = malloc ( sizeof ( struct nfs_link_data ) ) ;
if ( link_data = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate buffer for link data " ) ;
2011-02-06 07:45:09 +03:00
return - 1 ;
}
2011-09-03 08:11:22 +04:00
memset ( link_data , 0 , sizeof ( struct nfs_link_data ) ) ;
2011-02-06 07:45:09 +03:00
link_data - > oldpath = strdup ( oldpath ) ;
if ( link_data - > oldpath = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate buffer for oldpath " ) ;
2011-02-06 07:45:09 +03:00
free_nfs_link_data ( link_data ) ;
2011-06-19 03:03:04 +04:00
return - 1 ;
2011-02-06 07:45:09 +03:00
}
link_data - > newpath = strdup ( newpath ) ;
if ( link_data - > newpath = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory, failed to allocate buffer for newpath " ) ;
2011-02-06 07:45:09 +03:00
free_nfs_link_data ( link_data ) ;
2011-06-19 03:03:04 +04:00
return - 1 ;
2011-02-06 07:45:09 +03:00
}
2011-08-28 13:27:23 +04:00
ptr = strrchr ( link_data - > newpath , ' / ' ) ;
2011-02-06 07:45:09 +03:00
if ( ptr = = NULL ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Invalid path %s " , newpath ) ;
2011-02-06 07:45:09 +03:00
free_nfs_link_data ( link_data ) ;
2011-06-19 03:03:04 +04:00
return - 1 ;
2011-02-06 07:45:09 +03:00
}
* ptr = 0 ;
ptr + + ;
link_data - > newobject = ptr ;
if ( nfs_lookuppath_async ( nfs , link_data - > oldpath , cb , private_data , nfs_link_continue_1_internal , link_data , free_nfs_link_data , 0 ) ! = 0 ) {
2011-06-19 03:03:04 +04:00
rpc_set_error ( nfs - > rpc , " Out of memory: failed to start parsing the path components " ) ;
return - 1 ;
2011-02-06 07:45:09 +03:00
}
return 0 ;
}
//qqq replace later with lseek()
2011-11-27 07:49:08 +04:00
uint64_t nfs_get_current_offset ( struct nfsfh * nfsfh )
2011-02-06 07:45:09 +03:00
{
return nfsfh - > offset ;
}
2011-05-31 18:08:29 +04:00
/*
* Get the maximum supported READ3 size by the server
*/
2011-11-27 07:49:08 +04:00
uint64_t nfs_get_readmax ( struct nfs_context * nfs )
2011-05-31 18:08:29 +04:00
{
return nfs - > readmax ;
}
/*
* Get the maximum supported WRITE3 size by the server
*/
2011-11-27 07:49:08 +04:00
uint64_t nfs_get_writemax ( struct nfs_context * nfs )
2011-05-31 18:08:29 +04:00
{
2013-10-24 06:18:41 +04:00
return nfs - > writemax ;
2011-05-31 18:08:29 +04:00
}
2011-06-19 03:38:20 +04:00
2014-01-13 14:22:21 +04:00
void nfs_set_tcp_syncnt ( struct nfs_context * nfs , int v ) {
rpc_set_tcp_syncnt ( nfs - > rpc , v ) ;
}
void nfs_set_uid ( struct nfs_context * nfs , int uid ) {
rpc_set_uid ( nfs - > rpc , uid ) ;
}
void nfs_set_gid ( struct nfs_context * nfs , int gid ) {
rpc_set_gid ( nfs - > rpc , gid ) ;
}
2014-06-23 18:31:32 +04:00
void nfs_set_readahead ( struct nfs_context * nfs , uint32_t v ) {
rpc_set_readahead ( nfs - > rpc , v ) ;
}
2011-06-19 03:38:20 +04:00
void nfs_set_error ( struct nfs_context * nfs , char * error_string , . . . )
{
va_list ap ;
2011-06-21 12:33:50 +04:00
char * str = NULL ;
2011-06-19 03:38:20 +04:00
2011-06-21 12:33:50 +04:00
va_start ( ap , error_string ) ;
2011-08-29 12:00:09 +04:00
str = malloc ( 1024 ) ;
vsnprintf ( str , 1024 , error_string , ap ) ;
2011-06-19 03:38:20 +04:00
if ( nfs - > rpc - > error_string ! = NULL ) {
free ( nfs - > rpc - > error_string ) ;
}
nfs - > rpc - > error_string = str ;
2014-01-28 08:54:14 +04:00
va_end ( ap ) ;
2011-06-19 03:38:20 +04:00
}
2011-06-19 08:54:17 +04:00
struct mount_cb_data {
rpc_cb cb ;
void * private_data ;
char * server ;
} ;
static void free_mount_cb_data ( struct mount_cb_data * data )
{
if ( data - > server ! = NULL ) {
free ( data - > server ) ;
data - > server = NULL ;
}
free ( data ) ;
}
static void mount_export_5_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
{
struct mount_cb_data * data = private_data ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
if ( status = = RPC_STATUS_ERROR ) {
2011-06-19 08:54:17 +04:00
data - > cb ( rpc , - EFAULT , command_data , data - > private_data ) ;
free_mount_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( rpc , - EINTR , " Command was cancelled " , data - > private_data ) ;
free_mount_cb_data ( data ) ;
return ;
}
data - > cb ( rpc , 0 , command_data , data - > private_data ) ;
if ( rpc_disconnect ( rpc , " normal disconnect " ) ! = 0 ) {
rpc_set_error ( rpc , " Failed to disconnect \n " ) ;
}
free_mount_cb_data ( data ) ;
}
static void mount_export_4_cb ( struct rpc_context * rpc , int status , void * command_data , void * private_data )
{
struct mount_cb_data * data = private_data ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-10-09 12:47:07 +04:00
/* Dont want any more callbacks even if the socket is closed */
rpc - > connect_cb = NULL ;
2014-02-14 01:36:54 +04:00
if ( status = = RPC_STATUS_ERROR ) {
2011-06-19 08:54:17 +04:00
data - > cb ( rpc , - EFAULT , command_data , data - > private_data ) ;
free_mount_cb_data ( data ) ;
return ;
}
if ( status = = RPC_STATUS_CANCEL ) {
data - > cb ( rpc , - EINTR , " Command was cancelled " , data - > private_data ) ;
free_mount_cb_data ( data ) ;
return ;
}
2013-12-26 21:11:05 +04:00
if ( rpc_mount3_export_async ( rpc , mount_export_5_cb , data ) ! = 0 ) {
2011-06-19 08:54:17 +04:00
data - > cb ( rpc , - ENOMEM , command_data , data - > private_data ) ;
free_mount_cb_data ( data ) ;
return ;
}
}
int mount_getexports_async ( struct rpc_context * rpc , const char * server , rpc_cb cb , void * private_data )
{
struct mount_cb_data * data ;
2012-11-24 20:18:54 +04:00
assert ( rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-06-19 08:54:17 +04:00
data = malloc ( sizeof ( struct mount_cb_data ) ) ;
if ( data = = NULL ) {
return - 1 ;
}
2011-09-03 08:11:22 +04:00
memset ( data , 0 , sizeof ( struct mount_cb_data ) ) ;
2011-06-19 08:54:17 +04:00
data - > cb = cb ;
data - > private_data = private_data ;
data - > server = strdup ( server ) ;
if ( data - > server = = NULL ) {
free_mount_cb_data ( data ) ;
return - 1 ;
2014-02-14 01:36:54 +04:00
}
2014-03-17 02:06:56 +04:00
if ( rpc_connect_program_async ( rpc , data - > server , MOUNT_PROGRAM , MOUNT_V3 , mount_export_4_cb , data ) ! = 0 ) {
rpc_set_error ( rpc , " Failed to start connection " ) ;
2011-06-19 08:54:17 +04:00
free_mount_cb_data ( data ) ;
return - 1 ;
}
return 0 ;
}
2011-06-19 16:31:34 +04:00
struct rpc_context * nfs_get_rpc_context ( struct nfs_context * nfs )
{
2012-11-24 20:18:54 +04:00
assert ( nfs - > rpc - > magic = = RPC_CONTEXT_MAGIC ) ;
2011-06-19 16:31:34 +04:00
return nfs - > rpc ;
}
2011-07-31 04:46:34 +04:00
const char * nfs_get_server ( struct nfs_context * nfs ) {
return nfs - > server ;
}
const char * nfs_get_export ( struct nfs_context * nfs ) {
return nfs - > export ;
}
2011-08-28 13:48:01 +04:00
2012-01-11 00:04:01 +04:00
const struct nfs_fh3 * nfs_get_rootfh ( struct nfs_context * nfs ) {
return & nfs - > rootfh ;
}
2012-03-08 14:25:21 +04:00
struct nfs_fh3 * nfs_get_fh ( struct nfsfh * nfsfh ) {
return & nfsfh - > fh ;
}