fe9911de50b6e79c520086ab0413b23db05fd975
[deb_libnfs.git] / examples / nfs-cp.c
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"
32 #pragma comment(lib, "ws2_32.lib")
33 WSADATA wsaData;
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
57 struct file_context {
58 int is_nfs;
59 int fd;
60 struct nfs_context *nfs;
61 struct nfsfh *nfsfh;
62 struct nfs_url *url;
63 };
64
65 void usage(void)
66 {
67 fprintf(stderr, "Usage: nfs-cp <src> <dst>\n");
68 fprintf(stderr, "<src>,<dst> can either be a local file or "
69 "an nfs URL.\n");
70 exit(0);
71 }
72
73 static void
74 free_file_context(struct file_context *file_context)
75 {
76 if (file_context->fd != -1) {
77 close(file_context->fd);
78 }
79 if (file_context->nfsfh != NULL) {
80 nfs_close(file_context->nfs, file_context->nfsfh);
81 }
82 if (file_context->nfs != NULL) {
83 nfs_destroy_context(file_context->nfs);
84 }
85 nfs_destroy_url(file_context->url);
86 free(file_context);
87 }
88
89 static int
90 fstat_file(struct file_context *fc, struct stat *st)
91 {
92 if (fc->is_nfs == 0) {
93 return fstat(fc->fd, st);
94 } else {
95 return nfs_fstat(fc->nfs, fc->nfsfh, st);
96 }
97 }
98
99 static int64_t
100 file_pread(struct file_context *fc, char *buf, int64_t count, uint64_t off)
101 {
102 if (fc->is_nfs == 0) {
103 lseek(fc->fd, off, SEEK_SET);
104 return read(fc->fd, buf, count);
105 } else {
106 return nfs_pread(fc->nfs, fc->nfsfh, off, count, buf);
107 }
108 }
109
110 static int64_t
111 file_pwrite(struct file_context *fc, char *buf, int64_t count, uint64_t off)
112 {
113 if (fc->is_nfs == 0) {
114 lseek(fc->fd, off, SEEK_SET);
115 return write(fc->fd, buf, count);
116 } else {
117 return nfs_pwrite(fc->nfs, fc->nfsfh, off, count, buf);
118 }
119 }
120
121 static struct file_context *
122 open_file(const char *url, int flags)
123 {
124 struct file_context *file_context;
125
126 file_context = malloc(sizeof(struct file_context));
127 if (file_context == NULL) {
128 fprintf(stderr, "Failed to malloc file_context\n");
129 return NULL;
130 }
131 file_context->is_nfs = 0;
132 file_context->fd = -1;
133 file_context->nfs = NULL;
134 file_context->nfsfh = NULL;
135 file_context->url = NULL;
136
137 if (strncmp(url, "nfs://", 6)) {
138 file_context->is_nfs = 0;
139 file_context->fd = open(url, flags, 0660);
140 if (file_context->fd == -1) {
141 fprintf(stderr, "Failed to open %s\n", url);
142 free_file_context(file_context);
143 return NULL;
144 }
145 return file_context;
146 }
147
148 file_context->is_nfs = 1;
149
150 file_context->nfs = nfs_init_context();
151 if (file_context->nfs == NULL) {
152 fprintf(stderr, "failed to init context\n");
153 free_file_context(file_context);
154 return NULL;
155 }
156
157 file_context->url = nfs_parse_url_full(file_context->nfs, url);
158 if (file_context->url == NULL) {
159 fprintf(stderr, "%s\n", nfs_get_error(file_context->nfs));
160 free_file_context(file_context);
161 return NULL;
162 }
163
164 if (nfs_mount(file_context->nfs, file_context->url->server,
165 file_context->url->path) != 0) {
166 fprintf(stderr, "Failed to mount nfs share : %s\n",
167 nfs_get_error(file_context->nfs));
168 free_file_context(file_context);
169 return NULL;
170 }
171
172 if (flags == O_RDONLY) {
173 if (nfs_open(file_context->nfs, file_context->url->file, flags,
174 &file_context->nfsfh) != 0) {
175 fprintf(stderr, "Failed to open file %s: %s\n",
176 file_context->url->file,
177 nfs_get_error(file_context->nfs));
178 free_file_context(file_context);
179 return NULL;
180 }
181 } else {
182 if (nfs_creat(file_context->nfs, file_context->url->file, 0660,
183 &file_context->nfsfh) != 0) {
184 fprintf(stderr, "Failed to creat file %s: %s\n",
185 file_context->url->file,
186 nfs_get_error(file_context->nfs));
187 free_file_context(file_context);
188 return NULL;
189 }
190 }
191 return file_context;
192 }
193
194 #define BUFSIZE 1024*1024
195 static char buf[BUFSIZE];
196
197 int main(int argc, char *argv[])
198 {
199 int ret;
200 struct stat st;
201 struct file_context *src;
202 struct file_context *dst;
203 uint64_t off;
204 int64_t count;
205
206 #ifdef WIN32
207 if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
208 printf("Failed to start Winsock2\n");
209 return 10;
210 }
211 #endif
212
213 #ifdef AROS
214 aros_init_socket();
215 #endif
216
217 if (argc != 3) {
218 usage();
219 }
220
221 src = open_file(argv[1], O_RDONLY);
222 if (src == NULL) {
223 fprintf(stderr, "Failed to open %s\n", argv[1]);
224 return 10;
225 }
226
227 dst = open_file(argv[2], O_WRONLY|O_CREAT|O_TRUNC);
228 if (dst == NULL) {
229 fprintf(stderr, "Failed to open %s\n", argv[2]);
230 free_file_context(src);
231 return 10;
232 }
233
234 if (fstat_file(src, &st) != 0) {
235 fprintf(stderr, "Failed to fstat source file\n");
236 free_file_context(src);
237 free_file_context(dst);
238 return 10;
239 }
240
241 off = 0;
242 while (off < st.st_size) {
243 count = st.st_size - off;
244 if (count > BUFSIZE) {
245 count = BUFSIZE;
246 }
247 count = file_pread(src, buf, count, off);
248 if (count < 0) {
249 fprintf(stderr, "Failed to read from source file\n");
250 free_file_context(src);
251 free_file_context(dst);
252 return 10;
253 }
254 count = file_pwrite(dst, buf, count, off);
255 if (count < 0) {
256 fprintf(stderr, "Failed to write to dest file\n");
257 free_file_context(src);
258 free_file_context(dst);
259 return 10;
260 }
261
262 off += count;
263 }
264 printf("copied %d bytes\n", (int)off);
265
266 free_file_context(src);
267 free_file_context(dst);
268
269 return 0;
270 }