Merge pull request #43 from plieven/master

URL parsing functions and minor fixes + enhancements
libnfs-4.0.0-vitalif
Ronnie Sahlberg 2013-12-25 16:11:29 -08:00
commit 6d89ace041
11 changed files with 619 additions and 170 deletions

View File

@ -121,6 +121,10 @@ AC_CHECK_HEADERS([sys/statvfs.h])
dnl Check for sys/socket.h
AC_CHECK_HEADERS([sys/socket.h])
# check for netinet/tcp.h
dnl Check for netinet/tcp.h
AC_CHECK_HEADERS([netinet/tcp.h])
# check for netinet/in.h
dnl Check for netinet/in.h
AC_CHECK_HEADERS([netinet/in.h])

View File

@ -1,4 +1,4 @@
noinst_PROGRAMS = nfsclient-async nfsclient-raw nfsclient-sync nfsclient-bcast nfsclient-listservers nfs-ls nfs-cp
noinst_PROGRAMS = nfsclient-async nfsclient-raw nfsclient-sync nfsclient-bcast nfsclient-listservers nfs-ls nfs-cp nfs-io
AM_CPPFLAGS = \
-I$(abs_top_srcdir)/include \
@ -15,6 +15,8 @@ nfs_ls_SOURCES = nfs-ls.c
nfs_cp_SOURCES = nfs-cp.c
nfs_io_SOURCES = nfs-io.c
nfsclient_async_SOURCES = nfsclient-async.c
nfsclient_raw_SOURCES = nfsclient-raw.c

View File

@ -59,6 +59,7 @@ struct file_context {
int fd;
struct nfs_context *nfs;
struct nfsfh *nfsfh;
struct nfs_url *url;
};
void usage(void)
@ -81,6 +82,7 @@ free_file_context(struct file_context *file_context)
if (file_context->nfs != NULL) {
nfs_destroy_context(file_context->nfs);
}
nfs_destroy_url(file_context->url);
free(file_context);
}
@ -120,7 +122,6 @@ static struct file_context *
open_file(const char *url, int flags)
{
struct file_context *file_context;
char *server = NULL, *path = NULL, *file = NULL, *strp;
file_context = malloc(sizeof(struct file_context));
if (file_context == NULL) {
@ -132,7 +133,6 @@ open_file(const char *url, int flags)
file_context->nfs = NULL;
file_context->nfsfh = NULL;
if (strncmp(url, "nfs://", 6)) {
file_context->is_nfs = 0;
file_context->fd = open(url, flags, 0660);
@ -153,77 +153,40 @@ open_file(const char *url, int flags)
return NULL;
}
server = strdup(url + 6);
if (server == NULL) {
fprintf(stderr, "Failed to strdup server string\n");
free_file_context(file_context);
return NULL;
}
if (server[0] == '/' || server[0] == '\0') {
fprintf(stderr, "Invalid server string.\n");
free(server);
free_file_context(file_context);
return NULL;
}
strp = strchr(server, '/');
path = strdup(strp);
*strp = 0;
if (path == NULL) {
fprintf(stderr, "Invalid URL specified.\n");
free(server);
file_context->url = nfs_parse_url_full(file_context->nfs, url);
if (file_context->url == NULL) {
fprintf(stderr, "%s\n", nfs_get_error(file_context->nfs));
free_file_context(file_context);
return NULL;
}
strp = strrchr(path, '/');
if (strp == NULL) {
fprintf(stderr, "Invalid URL specified.\n");
free(path);
free(server);
free_file_context(file_context);
return NULL;
}
file = strdup(strp);
*strp = 0;
if (nfs_mount(file_context->nfs, server, path) != 0) {
fprintf(stderr, "Failed to mount nfs share : %s\n",
if (nfs_mount(file_context->nfs, file_context->url->server,
file_context->url->path) != 0) {
fprintf(stderr, "Failed to mount nfs share : %s\n",
nfs_get_error(file_context->nfs));
free(file);
free(path);
free(server);
free_file_context(file_context);
return NULL;
}
if (flags == O_RDONLY) {
if (nfs_open(file_context->nfs, file, flags,
if (nfs_open(file_context->nfs, file_context->url->file, flags,
&file_context->nfsfh) != 0) {
fprintf(stderr, "Failed to open file : %s\n",
fprintf(stderr, "Failed to open file %s: %s\n",
file_context->url->file,
nfs_get_error(file_context->nfs));
free(file);
free(path);
free(server);
free_file_context(file_context);
return NULL;
}
} else {
if (nfs_creat(file_context->nfs, file, 0660,
if (nfs_creat(file_context->nfs, file_context->url->file, 0660,
&file_context->nfsfh) != 0) {
fprintf(stderr, "Failed to creat file %s %s\n", file,
fprintf(stderr, "Failed to creat file %s: %s\n",
file_context->url->file,
nfs_get_error(file_context->nfs));
free(file);
free(path);
free(server);
free_file_context(file_context);
return NULL;
}
}
free(file);
free(path);
free(server);
return file_context;
}

177
examples/nfs-io.c Normal file
View File

@ -0,0 +1,177 @@
/*
Copyright (C) by Peter Lieven <pl@kamp.de> 2013
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#define _FILE_OFFSET_BITS 64
#define _GNU_SOURCE
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef AROS
#include "aros_compat.h"
#endif
#ifdef WIN32
#include "win32_compat.h"
#pragma comment(lib, "ws2_32.lib")
WSADATA wsaData;
#define PRId64 "ll"
#else
#include <inttypes.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#ifndef AROS
#include <sys/statvfs.h>
#endif
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "libnfs-zdr.h"
#include "libnfs.h"
#include "libnfs-raw.h"
#include "libnfs-raw-mount.h"
void print_usage(void)
{
fprintf(stderr, "Usage: nfs-io [-?|--help|--usage] [stat|creat|unlink|mkdir|rmdir] <url>\n");
}
int main(int argc, char *argv[])
{
int ret = 1;
struct nfs_context *nfs = NULL;
struct nfsfh *nfsfh = NULL;
struct nfs_url *url = NULL;
#ifdef WIN32
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
printf("Failed to start Winsock2\n");
exit(10);
}
#endif
#ifdef AROS
aros_init_socket();
#endif
if (argc < 3) {
fprintf(stderr, "No URL specified.\n");
goto finished;
}
nfs = nfs_init_context();
if (nfs == NULL) {
printf("failed to init context\n");
goto finished;
}
url = nfs_parse_url_full(nfs, argv[argc - 1]);
if (url == NULL) {
fprintf(stderr, "%s\n", nfs_get_error(nfs));
goto finished;
}
if (nfs_mount(nfs, url->server, url->path) != 0) {
fprintf(stderr, "Failed to mount nfs share : %s\n", nfs_get_error(nfs));
goto finished;
}
if (!strncmp(argv[1], "creat", 5)) {
ret = nfs_creat(nfs, url->file, 0600, &nfsfh);
} else if (!strncmp(argv[1], "unlink", 6)) {
ret = nfs_unlink(nfs, url->file);
} else if (!strncmp(argv[1], "mkdir", 5)) {
ret = nfs_mkdir(nfs, url->file);
} else if (!strncmp(argv[1], "rmdir", 5)) {
ret = nfs_rmdir(nfs, url->file);
} else if (!strncmp(argv[1], "stat", 4)) {
struct stat st;
ret = nfs_stat(nfs, url->file, &st);
if (!ret) {
switch (st.st_mode & S_IFMT) {
#ifndef WIN32
case S_IFLNK:
printf("l");
break;
#endif
case S_IFREG:
printf("-");
break;
case S_IFDIR:
printf("d");
break;
case S_IFCHR:
printf("c");
break;
case S_IFBLK:
printf("b");
break;
}
printf("%c%c%c",
"-r"[!!(st.st_mode & S_IRUSR)],
"-w"[!!(st.st_mode & S_IWUSR)],
"-x"[!!(st.st_mode & S_IXUSR)]
);
printf("%c%c%c",
"-r"[!!(st.st_mode & S_IRGRP)],
"-w"[!!(st.st_mode & S_IWGRP)],
"-x"[!!(st.st_mode & S_IXGRP)]
);
printf("%c%c%c",
"-r"[!!(st.st_mode & S_IROTH)],
"-w"[!!(st.st_mode & S_IWOTH)],
"-x"[!!(st.st_mode & S_IXOTH)]
);
printf(" %2d", (int) st.st_nlink);
printf(" %5d", st.st_uid);
printf(" %5d", st.st_gid);
printf(" %12" PRId64, st.st_size);
printf("\n");
}
} else {
goto finished;
}
if (ret) {
fprintf(stderr, "ERROR: %s\n", nfs_get_error(nfs));
}
finished:
if (ret > 0) {
print_usage();
}
nfs_destroy_url(url);
if (nfs != NULL) {
if (nfsfh) {
nfs_close(nfs, nfsfh);
}
nfs_destroy_context(nfs);
}
return !!ret;
}

View File

@ -35,6 +35,7 @@ WSADATA wsaData;
#include <inttypes.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#ifndef AROS
#include <sys/statvfs.h>
#endif
@ -62,103 +63,44 @@ struct client {
int is_finished;
};
int recursive = 0, summary = 0, discovery = 0;
void print_usage(void)
{
fprintf(stderr, "Usage: nfs-ls [-?|--help] [--usage] <url>\n");
fprintf(stderr, "Usage: nfs-ls [-?|--help|--usage] [-R|--recursive] [-s|--summary] [-D|--discovery] <url>\n");
}
int main(int argc, char *argv[])
{
struct nfs_context *nfs = NULL;
int i, ret, res;
uint64_t offset;
struct client client;
struct stat st;
struct nfsfh *nfsfh;
struct nfsdir *nfsdir;
int process_server(const char *server) {
struct exportnode *exports;
struct exportnode *export;
exports = mount_getexports(server);
if (exports == NULL) {
fprintf(stderr, "Failed to get exports for server %s.\n", server);
return -1;
}
for (export=exports; export; export = export->ex_next) {
printf("nfs://%s%s\n", server, export->ex_dir);
}
mount_free_export_list(exports);
return 0;
}
void process_dir(struct nfs_context *nfs, char *dir, int level) {
int ret;
struct nfsdirent *nfsdirent;
struct statvfs svfs;
exports export, tmp;
const char *url = NULL;
char *server = NULL, *path = NULL, *strp;
#ifdef WIN32
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
printf("Failed to start Winsock2\n");
exit(10);
}
#endif
#ifdef AROS
aros_init_socket();
#endif
url = argv[1];
if (url == NULL) {
fprintf(stderr, "No URL specified.\n");
print_usage();
exit(0);
}
if (strncmp(url, "nfs://", 6)) {
fprintf(stderr, "Invalid URL specified.\n");
print_usage();
exit(0);
}
server = strdup(url + 6);
if (server == NULL) {
fprintf(stderr, "Failed to strdup server string\n");
exit(10);
}
if (server[0] == '/' || server[0] == '\0') {
fprintf(stderr, "Invalid server string.\n");
free(server);
exit(10);
}
strp = strchr(server, '/');
if (strp == NULL) {
fprintf(stderr, "Invalid URL specified.\n");
print_usage();
free(server);
exit(0);
}
path = strdup(strp);
if (path == NULL) {
fprintf(stderr, "Failed to strdup server string\n");
free(server);
exit(10);
}
if (path[0] != '/') {
fprintf(stderr, "Invalid path.\n");
free(server);
free(path);
exit(10);
}
*strp = 0;
struct nfsdir *nfsdir;
struct stat st;
client.server = server;
client.export = path;
client.is_finished = 0;
nfs = nfs_init_context();
if (nfs == NULL) {
printf("failed to init context\n");
goto finished;
if (!level) {
printf("Recursion detected!\n");
exit(10);
}
ret = nfs_mount(nfs, client.server, client.export);
ret = nfs_opendir(nfs, dir, &nfsdir);
if (ret != 0) {
printf("Failed to mount nfs share : %s\n", nfs_get_error(nfs));
goto finished;
}
ret = nfs_opendir(nfs, "/", &nfsdir);
if (ret != 0) {
printf("Failed to opendir(\"/\")\n", nfs_get_error(nfs));
printf("Failed to opendir(\"%s\")\n", dir, nfs_get_error(nfs));
exit(10);
}
while((nfsdirent = nfs_readdir(nfs, nfsdir)) != NULL) {
@ -168,7 +110,7 @@ int main(int argc, char *argv[])
continue;
}
sprintf(path, "%s/%s", "/", nfsdirent->name);
snprintf(path, 1024, "%s/%s", dir, nfsdirent->name);
ret = nfs_stat(nfs, path, &st);
if (ret != 0) {
fprintf(stderr, "Failed to stat(%s) %s\n", path, nfs_get_error(nfs));
@ -178,6 +120,8 @@ int main(int argc, char *argv[])
switch (st.st_mode & S_IFMT) {
#ifndef WIN32
case S_IFLNK:
printf("l");
break;
#endif
case S_IFREG:
printf("-");
@ -207,22 +151,130 @@ int main(int argc, char *argv[])
"-w"[!!(st.st_mode & S_IWOTH)],
"-x"[!!(st.st_mode & S_IXOTH)]
);
printf(" %2d", st.st_nlink);
printf(" %2d", (int) st.st_nlink);
printf(" %5d", st.st_uid);
printf(" %5d", st.st_gid);
printf(" %12" PRId64, st.st_size);
printf(" %s\n", nfsdirent->name);
printf(" %s\n", path + 1);
if (recursive && (st.st_mode & S_IFMT) == S_IFDIR) {
process_dir(nfs, path, level - 1);
}
}
nfs_closedir(nfs, nfsdir);
finished:
free(server);
free(path);
if (nfs != NULL) {
nfs_destroy_context(nfs);
}
return 0;
}
int main(int argc, char *argv[])
{
struct nfs_context *nfs = NULL;
int i, ret = 1, res;
uint64_t offset;
struct client client;
struct statvfs stvfs;
struct nfs_url *url;
exports export, tmp;
#ifdef WIN32
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
printf("Failed to start Winsock2\n");
exit(10);
}
#endif
#ifdef AROS
aros_init_socket();
#endif
if (argc < 2) {
fprintf(stderr, "No URL specified.\n");
goto finished;
}
for (i=1; i < argc -1; i++) {
if (!strcmp(argv[i], "-R") || !strcmp(argv[i], "--recursive")) {
recursive++;
} else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--summary")) {
summary++;
} else if (!strcmp(argv[i], "-D") || !strcmp(argv[i], "--discovery")) {
discovery++;
} else{
goto finished;
}
}
nfs = nfs_init_context();
if (nfs == NULL) {
printf("failed to init context\n");
goto finished;
}
if (discovery) {
url = nfs_parse_url_incomplete(nfs, argv[argc - 1]);
if (url == NULL) {
fprintf(stderr, "%s\n", nfs_get_error(nfs));
goto finished;
}
if (!url->server) {
struct nfs_server_list *srvrs;
struct nfs_server_list *srv;
srvrs = nfs_find_local_servers();
if (srvrs == NULL) {
fprintf(stderr, "Failed to find local servers.\n");
goto finished;
}
for (srv=srvrs; srv; srv = srv->next) {
if (recursive) {
process_server(srv->addr);
} else {
printf("nfs://%s\n", srv->addr);
}
}
free_nfs_srvr_list(srvrs);
ret = 0;
goto finished;
}
if (url->server && !url->path) {
ret = process_server(url->server);
goto finished;
}
nfs_destroy_url(url);
}
url = nfs_parse_url_dir(nfs, argv[argc - 1]);
if (url == NULL) {
fprintf(stderr, "%s\n", nfs_get_error(nfs));
goto finished;
}
client.server = url->server;
client.export = url->path;
client.is_finished = 0;
if ((ret = nfs_mount(nfs, client.server, client.export)) != 0) {
fprintf(stderr, "Failed to mount nfs share : %s\n", nfs_get_error(nfs));
goto finished;
}
process_dir(nfs, "", 16);
if (summary) {
if (nfs_statvfs(nfs, "/", &stvfs) != 0) {
goto finished;
}
printf("\n%12" PRId64 " of %12" PRId64 " bytes free.\n",
stvfs.f_frsize * stvfs.f_bfree, stvfs.f_frsize * stvfs.f_blocks);
}
ret = 0;
finished:
if (ret > 0) {
print_usage();
}
nfs_destroy_url(url);
if (nfs != NULL) {
nfs_destroy_context(nfs);
}
return ret;
}

View File

@ -56,9 +56,10 @@ struct rpc_fragment {
};
#define RPC_CONTEXT_MAGIC 0xc6e46435
#define RPC_PARAM_UNDEFINED -1
struct rpc_context {
uint32_t magic;
uint32_t magic;
int fd;
int is_connected;
@ -70,29 +71,34 @@ struct rpc_context {
struct AUTH *auth;
uint32_t xid;
/* buffer used for encoding RPC PDU */
char *encodebuf;
int encodebuflen;
/* buffer used for encoding RPC PDU */
char *encodebuf;
int encodebuflen;
struct rpc_pdu *outqueue;
struct sockaddr_storage udp_src;
struct rpc_pdu *waitpdu;
struct rpc_pdu *outqueue;
struct sockaddr_storage udp_src;
struct rpc_pdu *waitpdu;
uint32_t inpos;
uint32_t insize;
char *inbuf;
uint32_t inpos;
uint32_t insize;
char *inbuf;
/* special fields for UDP, which can sometimes be BROADCASTed */
int is_udp;
struct sockaddr *udp_dest;
int is_broadcast;
/* special fields for UDP, which can sometimes be BROADCASTed */
int is_udp;
struct sockaddr *udp_dest;
int is_broadcast;
/* track the address we connect to so we can auto-reconnect on session failure */
struct sockaddr_storage s;
int auto_reconnect;
/* track the address we connect to so we can auto-reconnect on session failure */
struct sockaddr_storage s;
int auto_reconnect;
/* fragment reassembly */
struct rpc_fragment *fragments;
/* parameters passable via URL */
int tcp_syncnt;
int uid;
int gid;
};
struct rpc_pdu {
@ -135,6 +141,10 @@ struct sockaddr *rpc_get_recv_sockaddr(struct rpc_context *rpc);
void rpc_set_autoreconnect(struct rpc_context *rpc);
void rpc_unset_autoreconnect(struct rpc_context *rpc);
void rpc_set_tcp_syncnt(struct rpc_context *rpc, int v);
void rpc_set_uid(struct rpc_context *rpc, int uid);
void rpc_set_gid(struct rpc_context *rpc, int gid);
int rpc_add_fragment(struct rpc_context *rpc, char *data, uint64_t size);
void rpc_free_all_fragments(struct rpc_context *rpc);

View File

@ -28,6 +28,12 @@
struct nfs_context;
struct rpc_context;
struct nfs_url {
char *server;
char *path;
char *file;
};
#if defined(WIN32)
#define EXTERN __declspec( dllexport )
#else
@ -71,7 +77,6 @@ EXTERN int nfs_queue_length(struct nfs_context *nfs);
struct AUTH;
EXTERN void nfs_set_auth(struct nfs_context *nfs, struct AUTH *auth);
/*
* When an operation failed, this function can extract a detailed error string.
*/
@ -106,6 +111,31 @@ EXTERN struct nfs_context *nfs_init_context(void);
EXTERN void nfs_destroy_context(struct nfs_context *nfs);
/*
* Parse a complete NFS URL including, server, path and
* filename. Fail if any component is missing.
*/
EXTERN struct nfs_url *nfs_parse_url_full(struct nfs_context *nfs, const char *url);
/*
* Parse an NFS URL, but do not split path and file. File
* in the resulting struct remains NULL.
*/
EXTERN struct nfs_url *nfs_parse_url_dir(struct nfs_context *nfs, const char *url);
/*
* Parse an NFS URL, but do not fail if file, path or even server is missing.
* Check elements of the resulting struct for NULL.
*/
EXTERN struct nfs_url *nfs_parse_url_incomplete(struct nfs_context *nfs, const char *url);
/*
* Free the URL struct returned by the nfs_parse_url_* functions.
*/
EXTERN void nfs_destroy_url(struct nfs_url *url);
struct nfsfh;
/*

View File

@ -75,6 +75,14 @@ struct rpc_context *rpc_init_context(void)
rpc->xid = salt + time(NULL) + getpid() << 16;
salt += 0x01000000;
rpc->fd = -1;
rpc->tcp_syncnt = RPC_PARAM_UNDEFINED;
#ifdef WIN32
rpc->uid = 65534;
rpc->gid = 65534;
#else
rpc->uid = getuid();
rpc->gid = getgid();
#endif
return rpc;
}
@ -102,6 +110,24 @@ void rpc_set_auth(struct rpc_context *rpc, struct AUTH *auth)
rpc->auth = auth;
}
static void rpc_set_uid_gid(struct rpc_context *rpc, int uid, int gid) {
if (uid != rpc->uid || gid != rpc->gid) {
struct AUTH *auth = libnfs_authunix_create("libnfs", uid, gid, 0, NULL);
if (auth != NULL) {
rpc_set_auth(rpc, auth);
rpc->uid = uid;
rpc->gid = gid;
}
}
}
void rpc_set_uid(struct rpc_context *rpc, int uid) {
rpc_set_uid_gid(rpc, uid, rpc->gid);
}
void rpc_set_gid(struct rpc_context *rpc, int gid) {
rpc_set_uid_gid(rpc, rpc->uid, gid);
}
void rpc_set_error(struct rpc_context *rpc, char *error_string, ...)
{

View File

@ -219,6 +219,9 @@ bool_t libnfs_zdr_opaque(ZDR *zdrs, char *objp, uint32_t size)
case ZDR_ENCODE:
memcpy(&zdrs->buf[zdrs->pos], objp, size);
zdrs->pos += size;
if (zdrs->pos & 3) {
memset(&zdrs->buf[zdrs->pos], 0x00, 4 - (zdrs->pos & 3));
}
zdrs->pos = (zdrs->pos + 3) & ~3;
return TRUE;
case ZDR_DECODE:

View File

@ -173,6 +173,152 @@ char *nfs_get_error(struct nfs_context *nfs)
return rpc_get_error(nfs->rpc);
};
static struct nfs_url *nfs_parse_url(struct nfs_context *nfs, const char *url, int dir, int incomplete)
{
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;
}
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;
}
}
if (urls->server && strlen(urls->server) <= 1) {
free(urls->server);
urls->server = 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++;
if (!strncmp(strp, "tcp-syncnt", 10)) {
rpc_set_tcp_syncnt(nfs->rpc, atoi(strp2));
} else if (!strncmp(strp, "uid", 3)) {
rpc_set_uid(nfs->rpc, atoi(strp2));
} else if (!strncmp(strp, "gid", 3)) {
rpc_set_gid(nfs->rpc, atoi(strp2));
}
}
}
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);
}
struct nfs_context *nfs_init_context(void)
{
struct nfs_context *nfs;

View File

@ -46,6 +46,10 @@
#include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
@ -92,6 +96,26 @@ static void set_nonblocking(int fd)
#endif //FIXME
}
#ifdef HAVE_NETINET_TCP_H
int set_tcp_sockopt(int sockfd, int optname, int value)
{
int level;
#if defined(__FreeBSD__) || defined(__sun) || (defined(__APPLE__) && defined(__MACH__))
struct protoent *buf;
if ((buf = getprotobyname("tcp")) != NULL)
level = buf->p_proto;
else
return -1;
#else
level = SOL_TCP;
#endif
return setsockopt(sockfd, level, optname, (char *)&value, sizeof(value));
}
#endif
int rpc_get_fd(struct rpc_context *rpc)
{
assert(rpc->magic == RPC_CONTEXT_MAGIC);
@ -368,6 +392,13 @@ void rpc_unset_autoreconnect(struct rpc_context *rpc)
rpc->auto_reconnect = 0;
}
void rpc_set_tcp_syncnt(struct rpc_context *rpc, int v)
{
assert(rpc->magic == RPC_CONTEXT_MAGIC);
rpc->tcp_syncnt = v;
}
static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_storage *s)
{
int socksize;
@ -378,6 +409,11 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
case AF_INET:
socksize = sizeof(struct sockaddr_in);
rpc->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
#ifdef HAVE_NETINET_TCP_H
if (rpc->tcp_syncnt != RPC_PARAM_UNDEFINED) {
set_tcp_sockopt(rpc->fd, TCP_SYNCNT, rpc->tcp_syncnt);
}
#endif
break;
default:
rpc_set_error(rpc, "Can not handle AF_FAMILY:%d", s->ss_family);