Grow the marshalling buffer from 64k to 1M so we can marshall really large WRITE3s
[deb_libnfs.git] / examples / nfs-cp.c
CommitLineData
a6bc1707
RS
1/*
2 Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2013
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>.
16*/
17
18#define _FILE_OFFSET_BITS 64
19#define _GNU_SOURCE
20
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25#ifdef AROS
26#include "aros_compat.h"
27#endif
28
29
30#ifdef WIN32
31#include "win32_compat.h"
67a9f57e
RS
32#pragma comment(lib, "ws2_32.lib")
33WSADATA wsaData;
a6bc1707
RS
34#else
35#include <sys/stat.h>
36#include <string.h>
37#endif
38
39#ifdef HAVE_POLL_H
40#include <poll.h>
41#endif
42
43#ifdef HAVE_UNISTD_H
44#include <unistd.h>
45#endif
46
47#include <stdio.h>
48#include <stdlib.h>
49#include <stdint.h>
50#include <sys/types.h>
51#include <fcntl.h>
52#include "libnfs-zdr.h"
53#include "libnfs.h"
54#include "libnfs-raw.h"
55#include "libnfs-raw-mount.h"
56
57struct file_context {
58 int is_nfs;
59 int fd;
60 struct nfs_context *nfs;
61 struct nfsfh *nfsfh;
62};
63
64void usage(void)
65{
66 fprintf(stderr, "Usage: nfs-cp <src> <dst>\n");
67 fprintf(stderr, "<src>,<dst> can either be a local file or "
68 "an nfs URL.\n");
69 exit(0);
70}
71
72static void
73free_file_context(struct file_context *file_context)
74{
75 if (file_context->fd != -1) {
76 close(file_context->fd);
77 }
78 if (file_context->nfsfh != NULL) {
79 nfs_close(file_context->nfs, file_context->nfsfh);
80 }
81 if (file_context->nfs != NULL) {
82 nfs_destroy_context(file_context->nfs);
83 }
84 free(file_context);
85}
86
87static int
88fstat_file(struct file_context *fc, struct stat *st)
89{
90 if (fc->is_nfs == 0) {
91 return fstat(fc->fd, st);
92 } else {
93 return nfs_fstat(fc->nfs, fc->nfsfh, st);
94 }
95}
96
97static int64_t
98file_pread(struct file_context *fc, char *buf, int64_t count, uint64_t off)
99{
100 if (fc->is_nfs == 0) {
3d574b1e
RS
101 lseek(fc->fd, off, SEEK_SET);
102 return read(fc->fd, buf, count);
a6bc1707
RS
103 } else {
104 return nfs_pread(fc->nfs, fc->nfsfh, off, count, buf);
105 }
106}
107
108static int64_t
109file_pwrite(struct file_context *fc, char *buf, int64_t count, uint64_t off)
110{
111 if (fc->is_nfs == 0) {
3d574b1e
RS
112 lseek(fc->fd, off, SEEK_SET);
113 return write(fc->fd, buf, count);
a6bc1707
RS
114 } else {
115 return nfs_pwrite(fc->nfs, fc->nfsfh, off, count, buf);
116 }
117}
118
119static struct file_context *
120open_file(const char *url, int flags)
121{
122 struct file_context *file_context;
123 char *server = NULL, *path = NULL, *file = NULL, *strp;
124
125 file_context = malloc(sizeof(struct file_context));
126 if (file_context == NULL) {
127 fprintf(stderr, "Failed to malloc file_context\n");
128 return NULL;
129 }
130 file_context->is_nfs = 0;
131 file_context->fd = -1;
132 file_context->nfs = NULL;
133 file_context->nfsfh = NULL;
134
135
136 if (strncmp(url, "nfs://", 6)) {
137 file_context->is_nfs = 0;
138 file_context->fd = open(url, flags, 0660);
139 if (file_context->fd == -1) {
140 fprintf(stderr, "Failed to open %s\n", url);
141 free_file_context(file_context);
142 return NULL;
143 }
144 return file_context;
145 }
146
147 file_context->is_nfs = 1;
148
149 file_context->nfs = nfs_init_context();
150 if (file_context->nfs == NULL) {
151 fprintf(stderr, "failed to init context\n");
152 free_file_context(file_context);
153 return NULL;
154 }
155
156 server = strdup(url + 6);
157 if (server == NULL) {
158 fprintf(stderr, "Failed to strdup server string\n");
159 free_file_context(file_context);
160 return NULL;
161 }
162 if (server[0] == '/' || server[0] == '\0') {
163 fprintf(stderr, "Invalid server string.\n");
164 free(server);
165 free_file_context(file_context);
166 return NULL;
167 }
168 strp = strchr(server, '/');
169 path = strdup(strp);
170 *strp = 0;
171 if (path == NULL) {
172 fprintf(stderr, "Invalid URL specified.\n");
173 free(server);
174 free_file_context(file_context);
175 return NULL;
176 }
177
178 strp = strrchr(path, '/');
179 if (strp == NULL) {
180 fprintf(stderr, "Invalid URL specified.\n");
181 free(path);
182 free(server);
183 free_file_context(file_context);
184 return NULL;
185 }
186 file = strdup(strp);
187 *strp = 0;
188
189 if (nfs_mount(file_context->nfs, server, path) != 0) {
190 fprintf(stderr, "Failed to mount nfs share : %s\n",
191 nfs_get_error(file_context->nfs));
192 free(file);
193 free(path);
194 free(server);
195 free_file_context(file_context);
196 return NULL;
197 }
198
199 if (flags == O_RDONLY) {
200 if (nfs_open(file_context->nfs, file, flags,
201 &file_context->nfsfh) != 0) {
202 fprintf(stderr, "Failed to open file : %s\n",
203 nfs_get_error(file_context->nfs));
204 free(file);
205 free(path);
206 free(server);
207 free_file_context(file_context);
208 return NULL;
209 }
210 } else {
211 if (nfs_creat(file_context->nfs, file, 0660,
212 &file_context->nfsfh) != 0) {
213 fprintf(stderr, "Failed to creat file %s %s\n", file,
214 nfs_get_error(file_context->nfs));
215 free(file);
216 free(path);
217 free(server);
218 free_file_context(file_context);
219 return NULL;
220 }
221 }
222
223 free(file);
224 free(path);
225 free(server);
226
227 return file_context;
228}
229
230#define BUFSIZE 1024*1024
231static char buf[BUFSIZE];
232
233int main(int argc, char *argv[])
234{
235 int ret;
236 struct stat st;
237 struct file_context *src;
238 struct file_context *dst;
239 uint64_t off;
240 int64_t count;
241
242#ifdef WIN32
243 if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
244 printf("Failed to start Winsock2\n");
245 return 10;
246 }
247#endif
248
249#ifdef AROS
250 aros_init_socket();
251#endif
252
253 if (argc != 3) {
254 usage();
255 }
256
257 src = open_file(argv[1], O_RDONLY);
258 if (src == NULL) {
259 fprintf(stderr, "Failed to open %s\n", argv[1]);
260 return 10;
261 }
262
263 dst = open_file(argv[2], O_WRONLY|O_CREAT|O_TRUNC);
264 if (dst == NULL) {
265 fprintf(stderr, "Failed to open %s\n", argv[2]);
266 free_file_context(src);
267 return 10;
268 }
269
270 if (fstat_file(src, &st) != 0) {
271 fprintf(stderr, "Failed to fstat source file\n");
272 free_file_context(src);
273 free_file_context(dst);
274 return 10;
275 }
276
277 off = 0;
278 while (off < st.st_size) {
279 count = st.st_size - off;
280 if (count > BUFSIZE) {
281 count = BUFSIZE;
282 }
283 count = file_pread(src, buf, count, off);
284 if (count < 0) {
285 fprintf(stderr, "Failed to read from source file\n");
286 free_file_context(src);
287 free_file_context(dst);
288 return 10;
289 }
290 count = file_pwrite(dst, buf, count, off);
291 if (count < 0) {
292 fprintf(stderr, "Failed to write to dest file\n");
293 free_file_context(src);
294 free_file_context(dst);
295 return 10;
296 }
297
298 off += count;
299 }
300 printf("copied %d bytes\n", (int)count);
301
302 free_file_context(src);
303 free_file_context(dst);
304
305 return 0;
306}