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])
-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 \
nfs_cp_SOURCES = nfs-cp.c
+nfs_io_SOURCES = nfs-io.c
+
nfsclient_async_SOURCES = nfsclient-async.c
nfsclient_raw_SOURCES = nfsclient-raw.c
int fd;
struct nfs_context *nfs;
struct nfsfh *nfsfh;
+ struct nfs_url *url;
};
void usage(void)
if (file_context->nfs != NULL) {
nfs_destroy_context(file_context->nfs);
}
+ nfs_destroy_url(file_context->url);
free(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) {
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);
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;
}
--- /dev/null
+/*
+ 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;
+}
+
#include <inttypes.h>
#include <string.h>
#include <sys/stat.h>
+#include <sys/statvfs.h>
#ifndef AROS
#include <sys/statvfs.h>
#endif
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;
- struct nfsdirent *nfsdirent;
- struct statvfs svfs;
- exports export, tmp;
- const char *url = NULL;
- char *server = NULL, *path = NULL, *strp;
+int process_server(const char *server) {
+ struct exportnode *exports;
+ struct exportnode *export;
-#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);
+ exports = mount_getexports(server);
+ if (exports == NULL) {
+ fprintf(stderr, "Failed to get exports for server %s.\n", server);
+ return -1;
}
-
- if (strncmp(url, "nfs://", 6)) {
- fprintf(stderr, "Invalid URL specified.\n");
- print_usage();
- exit(0);
+ for (export=exports; export; export = export->ex_next) {
+ printf("nfs://%s%s\n", server, export->ex_dir);
}
+ mount_free_export_list(exports);
+ return 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);
+void process_dir(struct nfs_context *nfs, char *dir, int level) {
+ int ret;
+ struct nfsdirent *nfsdirent;
+ struct statvfs svfs;
+ struct nfsdir *nfsdir;
+ struct stat st;
+
+ if (!level) {
+ printf("Recursion detected!\n");
exit(10);
}
- *strp = 0;
- 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;
- }
-
- ret = nfs_mount(nfs, client.server, client.export);
- if (ret != 0) {
- printf("Failed to mount nfs share : %s\n", nfs_get_error(nfs));
- goto finished;
- }
-
-
- ret = nfs_opendir(nfs, "/", &nfsdir);
+ ret = nfs_opendir(nfs, dir, &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) {
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));
switch (st.st_mode & S_IFMT) {
#ifndef WIN32
case S_IFLNK:
+ printf("l");
+ break;
#endif
case S_IFREG:
printf("-");
"-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);
+}
+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:
- free(server);
- free(path);
- if (nfs != NULL) {
+ if (ret > 0) {
+ print_usage();
+ }
+ nfs_destroy_url(url);
+ if (nfs != NULL) {
nfs_destroy_context(nfs);
}
- return 0;
+ return ret;
}
-
};
#define RPC_CONTEXT_MAGIC 0xc6e46435
+#define RPC_PARAM_UNDEFINED -1
struct rpc_context {
- uint32_t magic;
+ uint32_t magic;
int fd;
int is_connected;
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 {
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);
struct nfs_context;
struct rpc_context;
+struct nfs_url {
+ char *server;
+ char *path;
+ char *file;
+};
+
#if defined(WIN32)
#define EXTERN __declspec( dllexport )
#else
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.
*/
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;
/*
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;
}
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, ...)
{
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:
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;
#include <sys/socket.h>
#endif
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#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);
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;
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);