nfs_creat_async: plug potential memleak
[deb_libnfs.git] / lib / libnfs.c
index bfb1b7ce70bba59dd312c0bd7bdd79935886b820..969721e0330909f45e1906afba418d7b9c057c7e 100644 (file)
@@ -143,7 +143,6 @@ struct nfs_mcb_data {
 
 static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb_data *data, struct nfs_fh3 *fh);
 
-
 void nfs_set_auth(struct nfs_context *nfs, struct AUTH *auth)
 {
        rpc_set_auth(nfs->rpc, auth);
@@ -423,7 +422,7 @@ static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void *
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
-       if (status == RPC_STATUS_ERROR) {       
+       if (status == RPC_STATUS_ERROR) {
                data->cb(rpc, status, command_data, data->private_data);
                free_rpc_cb_data(data);
                return;
@@ -775,7 +774,7 @@ static void nfs_mount_3_cb(struct rpc_context *rpc, int status, void *command_da
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
-       if (status == RPC_STATUS_ERROR) {       
+       if (status == RPC_STATUS_ERROR) {
                data->cb(-EFAULT, nfs, command_data, data->private_data);
                free_nfs_cb_data(data);
                return;
@@ -1000,7 +999,7 @@ static int nfs_normalize_path(struct nfs_context *nfs, char *path)
        int len;
 
        /* // -> / */
-       while (str = strstr(path, "//")) {
+       while ((str = strstr(path, "//"))) {
                while(*str) {
                        *str = *(str + 1);
                        str++;
@@ -1008,7 +1007,7 @@ static int nfs_normalize_path(struct nfs_context *nfs, char *path)
        }
 
        /* /./ -> / */
-       while (str = strstr(path, "/./")) {
+       while ((str = strstr(path, "/./"))) {
                while(*(str + 1)) {
                        *str = *(str + 2);
                        str++;
@@ -1031,7 +1030,7 @@ static int nfs_normalize_path(struct nfs_context *nfs, char *path)
        }
 
        /* /string/../ -> / */
-       while (str = strstr(path, "/../")) {
+       while ((str = strstr(path, "/../"))) {
                char *tmp;
 
                if (!strncmp(path, "/../", 4)) {
@@ -1087,7 +1086,7 @@ static int nfs_normalize_path(struct nfs_context *nfs, char *path)
                        char *tmp = &path[len - 3];
                        while (*--tmp != '/')
                                ;
-                       *tmp = '\0'; 
+                       *tmp = '\0';
                }
        }
 
@@ -1106,6 +1105,8 @@ static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_c
        if (data == NULL) {
                rpc_set_error(nfs->rpc, "out of memory: failed to allocate "
                        "nfs_cb_data structure");
+               if (free_continue_data)
+                       free_continue_data(continue_data);
                return -1;
        }
        memset(data, 0, sizeof(struct nfs_cb_data));
@@ -1204,7 +1205,7 @@ static void nfs_stat_1_cb(struct rpc_context *rpc, int status, void *command_dat
 #ifndef WIN32
         st.st_blksize = 4096;
         st.st_blocks  = res->GETATTR3res_u.resok.obj_attributes.size / 4096;
-#endif//WIN32        
+#endif//WIN32
         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;
@@ -1244,6 +1245,55 @@ int nfs_stat_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *p
 /*
  * Async open()
  */
+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;
+       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);
+               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;
+       }
+
+       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;
+       }
+
+       /* steal the filehandle */
+       nfsfh->fh = data->fh;
+       data->fh.data.data_val = NULL;
+
+       data->cb(0, nfs, nfsfh, data->private_data);
+       free_nfs_cb_data(data);
+}
+
 static void nfs_open_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        ACCESS3res *res;
@@ -1297,6 +1347,28 @@ static void nfs_open_cb(struct rpc_context *rpc, int status, void *command_data,
                return;
        }
 
+       /* 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));
+               args.object = data->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_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;
+       }
+
        nfsfh = malloc(sizeof(struct nfsfh));
        if (nfsfh == NULL) {
                rpc_set_error(nfs->rpc, "NFS: Failed to allocate nfsfh structure");
@@ -1338,8 +1410,10 @@ static int nfs_open_continue_internal(struct nfs_context *nfs, struct nfs_cb_dat
        args.access = nfsmode;
 
        if (rpc_nfs3_access_async(nfs->rpc, nfs_open_cb, &args, data) != 0) {
-               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);
+               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;
        }
@@ -1775,7 +1849,7 @@ int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count
 /*
  * close
  */
+
 int nfs_close_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
 {
        if (nfsfh->fh.data.data_val != NULL){
@@ -1998,7 +2072,7 @@ static void nfs_mkdir_cb(struct rpc_context *rpc, int status, void *command_data
        struct nfs_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
        char *str = data->continue_data;
-       
+
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
        str = &str[strlen(str) + 1];
@@ -2088,7 +2162,7 @@ static void nfs_rmdir_cb(struct rpc_context *rpc, int status, void *command_data
        struct nfs_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
        char *str = data->continue_data;
-       
+
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
        str = &str[strlen(str) + 1];
@@ -2297,6 +2371,7 @@ int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb
        ptr = strrchr(new_path, '/');
        if (ptr == NULL) {
                rpc_set_error(nfs->rpc, "Invalid path %s", path);
+               free(new_path);
                return -1;
        }
        *ptr = 0;
@@ -2322,7 +2397,7 @@ static void nfs_unlink_cb(struct rpc_context *rpc, int status, void *command_dat
        struct nfs_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
        char *str = data->continue_data;
-       
+
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
        str = &str[strlen(str) + 1];
@@ -2420,7 +2495,7 @@ static void nfs_mknod_cb(struct rpc_context *rpc, int status, void *command_data
        struct nfs_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
        char *str = data->continue_data;
-       
+
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
        str = &str[strlen(str) + 1];
@@ -2453,7 +2528,7 @@ static int nfs_mknod_continue_internal(struct nfs_context *nfs, struct nfs_cb_da
        struct mknod_cb_data *cb_data = data->continue_data;
        char *str = cb_data->path;
        MKNOD3args args;
-       
+
        str = &str[strlen(str) + 1];
 
        args.where.dir = data->fh;
@@ -2511,13 +2586,14 @@ int nfs_mknod_async(struct nfs_context *nfs, const char *path, int mode, int dev
        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");
-               free(cb_data);          
+               free(cb_data);
                return -1;
        }
 
        ptr = strrchr(cb_data->path, '/');
        if (ptr == NULL) {
                rpc_set_error(nfs->rpc, "Invalid path %s", path);
+               free_mknod_cb_data(cb_data);
                return -1;
        }
        *ptr = 0;
@@ -2622,7 +2698,7 @@ static void nfs_opendir2_cb(struct rpc_context *rpc, int status, void *command_d
        struct entry3 *entry;
        uint64_t cookie = 0;
        struct rdpe_cb_data *rdpe_cb_data;
-       
+
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
        if (status == RPC_STATUS_ERROR) {
@@ -2749,7 +2825,7 @@ static void nfs_opendir_cb(struct rpc_context *rpc, int status, void *command_da
        struct nfsdir *nfsdir = data->continue_data;
        struct entryplus3 *entry;
        uint64_t cookie = 0;
-       
+
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
        if (status == RPC_STATUS_ERROR || (status == RPC_STATUS_SUCCESS && res->status == NFS3ERR_NOTSUPP) ){
@@ -2804,6 +2880,7 @@ static void nfs_opendir_cb(struct rpc_context *rpc, int status, void *command_da
                nfsdirent->name = strdup(entry->name);
                if (nfsdirent->name == NULL) {
                        data->cb(-ENOMEM, nfs, "Failed to allocate dirent->name", data->private_data);
+                       free(nfsdirent);
                        nfs_free_nfsdir(nfsdir);
                        data->continue_data = NULL;
                        free_nfs_cb_data(data);
@@ -3120,7 +3197,7 @@ static void nfs_readlink_1_cb(struct rpc_context *rpc, int status, void *command
                return;
        }
 
-       
+
        data->cb(0, nfs, res->READLINK3res_u.resok.data, data->private_data);
        free_nfs_cb_data(data);
 }
@@ -3632,7 +3709,7 @@ static void nfs_symlink_cb(struct rpc_context *rpc, int status, void *command_da
        struct nfs_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
        struct nfs_symlink_data *symlink_data = data->continue_data;
-       
+
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
        if (status == RPC_STATUS_ERROR) {
@@ -3768,7 +3845,7 @@ static void nfs_rename_cb(struct rpc_context *rpc, int status, void *command_dat
        struct nfs_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
        struct nfs_rename_data *rename_data = data->continue_data;
-       
+
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
        if (status == RPC_STATUS_ERROR) {
@@ -3929,7 +4006,7 @@ static void nfs_link_cb(struct rpc_context *rpc, int status, void *command_data,
        struct nfs_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
        struct nfs_link_data *link_data = data->continue_data;
-       
+
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
        if (status == RPC_STATUS_ERROR) {
@@ -4146,7 +4223,7 @@ static void mount_export_4_cb(struct rpc_context *rpc, int status, void *command
        /* Dont want any more callbacks even if the socket is closed */
        rpc->connect_cb = NULL;
 
-       if (status == RPC_STATUS_ERROR) {       
+       if (status == RPC_STATUS_ERROR) {
                data->cb(rpc, -EFAULT, command_data, data->private_data);
                free_mount_cb_data(data);
                return;
@@ -4266,7 +4343,7 @@ int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb c
        if (data->server == NULL) {
                free_mount_cb_data(data);
                return -1;
-       }       
+       }
        if (rpc_connect_async(rpc, data->server, 111, mount_export_1_cb, data) != 0) {
                free_mount_cb_data(data);
                return -1;