/[hurd]/hurd/utils/ftpcp.c
ViewVC logotype

Contents of /hurd/utils/ftpcp.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.5 - (show annotations) (download)
Sat Aug 9 23:51:26 1997 UTC (26 years, 10 months ago) by miles
Branch: MAIN
CVS Tags: roland_after_io_map_segment, flaviocruz-soc2008-lisp-branch-merge_helper, roland_before_io_map_segment, hurd-19990329, before-miles-orphaned-changes, hurd-19981227, zhengda-soc2008-virt-branch-merge_helper, hurd-19981204, hurd-19990315, hurd-19990314, hammy-libchannel-base, madhusudancs-soc2008-procfs-branch-merge_helper, marcus_before_ihash_rewrite, hurd-19980915, hurd-19990215, mmenal-soc2006-nfs-base, hurd-19990325, hurd-19980716, hurd-19990320, hurd-19980812, hurd-19990323, scolobb-soc2008-namespace-branch-merge_helper, ams-base, marcus_after_ihash_rewrite, HEAD
Branch point for: flaviocruz-soc2008-lisp-branch, scolobb-soc2008-namespace-branch, mmenal-soc2006-nfs-branch, ams-branch, miles-orphaned-changes, hammy-libchannel-branch, madhusudancs-soc2008-procfs-branch, zhengda-soc2008-virt-branch
Changes since 1.4: +2 -0 lines
File MIME type: text/plain
Doc fix.

1 /* Copy a file using the ftp protocol
2
3 Copyright (C) 1997 Free Software Foundation, Inc.
4
5 Written by Miles Bader <miles@gnu.ai.mit.edu>
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2, or (at
10 your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 #include <unistd.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <error.h>
25 #include <argp.h>
26 #include <netdb.h>
27 #include <fcntl.h>
28
29 #include <version.h>
30
31 #include <ftpconn.h>
32
33 #define COPY_SZ 65536
34
35 const char *argp_program_version = STANDARD_HURD_VERSION (ftpcp);
36
37 #define OPT_SRC_U -3
38 #define OPT_SRC_A -4
39 #define OPT_SRC_P -5
40 #define OPT_DST_U -6
41 #define OPT_DST_A -7
42 #define OPT_DST_P -8
43
44
45 static struct argp_option options[] =
46 {
47 {"user", 'u', "USER",0, "User to login as on both ftp servers"},
48 {"password", 'p', "PWD", 0, "USER's password"},
49 {"account", 'a', "ACCT",0, "Account to login as"},
50 {"src-user", OPT_SRC_U, "USER",0, "User to login as on the src ftp server"},
51 {"src-password",OPT_SRC_P, "PWD", 0, "The src USER's password"},
52 {"src-account", OPT_SRC_A, "ACCT",0, "Account to login as on the source server"},
53 {"dst-user", OPT_DST_U, "USER",0, "User to login as on the dst ftp server"},
54 {"dst-password",OPT_DST_P, "PWD", 0, "The dst USER's password"},
55 {"dst-account", OPT_DST_A, "ACCT",0, "Account to login as on the source server"},
56 {"debug", 'D', 0, 0, "Turn on debugging output for ftp connections"},
57 {0, 0}
58 };
59 static char *args_doc = "SRC [DST]";
60 static char *doc = "Copy file SRC over ftp to DST."
61 "\vBoth SRC and DST may have the form HOST:FILE, FILE, or -, where - is"
62 " standard input for SRC or standard output for DST, and FILE is a local"
63 " file. DST may be a directory, in which case the basename of SRC is"
64 " appended to make the actual destination filename.";
65
66 /* customization hooks. */
67 static struct ftp_conn_hooks conn_hooks = { 0 };
68
69 static void
70 cntl_debug (struct ftp_conn *conn, int type, const char *txt)
71 {
72 char *type_str;
73
74 switch (type)
75 {
76 case FTP_CONN_CNTL_DEBUG_CMD: type_str = ">"; break;
77 case FTP_CONN_CNTL_DEBUG_REPLY: type_str = "="; break;
78 default: type_str = "?"; break;
79 }
80
81 fprintf (stderr, "%s%s%s\n", (char *)conn->hook ?: "", type_str, txt);
82 }
83
84 /* Return an ftp connection for the host NAME using PARAMS. If an error
85 occurrs, a message is printed the program exits. If CNAME is non-zero,
86 the host's canonical name, in mallocated storage, is returned in it. */
87 struct ftp_conn *
88 get_host_conn (char *name, struct ftp_conn_params *params, char **cname)
89 {
90 error_t err;
91 struct hostent *he;
92 struct ftp_conn *conn;
93
94 he = gethostbyname (name);
95 if (! he)
96 error (10, 0, "%s: %s", name, hstrerror (h_errno));
97
98 params->addr = malloc (he->h_length);
99 if (! params->addr)
100 error (11, ENOMEM, "%s", name);
101
102 bcopy (he->h_addr_list[0], params->addr, he->h_length);
103 params->addr_len = he->h_length;
104 params->addr_type = he->h_addrtype;
105
106 err = ftp_conn_create (params, &conn_hooks, &conn);
107 if (err)
108 error (12, err, "%s", he->h_name);
109
110 if (cname)
111 *cname = strdup (he->h_name);
112
113 return conn;
114 }
115
116 static void
117 cp (int src, const char *src_name, int dst, const char *dst_name)
118 {
119 ssize_t rd;
120 static void *copy_buf = 0;
121
122 if (! copy_buf)
123 {
124 copy_buf = valloc (COPY_SZ);
125 if (! copy_buf)
126 error (13, ENOMEM, "Cannot allocate copy buffer");
127 }
128
129 while ((rd = read (src, copy_buf, COPY_SZ)) > 0)
130 do
131 {
132 int wr = write (dst, copy_buf, rd);
133 if (wr < 0)
134 error (14, errno, "%s", dst_name);
135 rd -= wr;
136 }
137 while (rd > 0);
138
139 if (rd != 0)
140 error (15, errno, "%s", src_name);
141 }
142
143 struct epoint
144 {
145 char *name; /* Name, of the form HOST:FILE, FILE, or -. */
146 char *file; /* If remote, the FILE portion, or 0. */
147 int fd; /* A file descriptor to use. */
148 struct ftp_conn *conn; /* An ftp connection to use. */
149 struct ftp_conn_params params;
150 };
151
152 static void
153 econnect (struct epoint *e, struct ftp_conn_params *def_params, char *name)
154 {
155 char *rmt;
156
157 if (! e->name)
158 e->name = "-";
159
160 rmt = strchr (e->name, ':');
161 if (rmt)
162 {
163 error_t err;
164
165 *rmt++ = 0;
166
167 if (! e->params.user)
168 e->params.user = def_params->user;
169 if (! e->params.pass)
170 e->params.pass = def_params->pass;
171 if (! e->params.acct)
172 e->params.acct = def_params->acct;
173
174 e->conn = get_host_conn (e->name, &e->params, &e->name);
175 e->name = realloc (e->name, strlen (e->name) + 1 + strlen (rmt) + 1);
176 if (! e->name)
177 error (22, ENOMEM, "Cannot allocate name storage");
178
179 e->conn->hook = name;
180
181 err = ftp_conn_set_type (e->conn, "I");
182 if (err)
183 error (23, err, "%s: Cannot set connection type to binary",
184 e->name);
185
186 strcat (e->name, ":");
187 strcat (e->name, rmt);
188
189 e->file = rmt;
190 }
191 else if (e->params.user || e->params.pass || e->params.acct)
192 error (20, 0,
193 "%s: Ftp login parameter specified for a local endpoint (%s,%s,%s)",
194 e->name, e->params.user, e->params.pass, e->params.acct);
195 else
196 e->file = strdup (e->name);
197 }
198
199 static error_t
200 eopen_wr (struct epoint *e, int *fd)
201 {
202 if (e->conn)
203 return ftp_conn_start_store (e->conn, e->file, fd);
204 else if (strcmp (e->name, "-") == 0)
205 *fd = 1;
206 else
207 {
208 *fd = open (e->name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
209 if (*fd < 0)
210 return errno;
211 }
212 return 0;
213 }
214
215 static error_t
216 eopen_rd (struct epoint *e, int *fd)
217 {
218 if (e->conn)
219 return ftp_conn_start_retrieve (e->conn, e->file, fd);
220 else if (strcmp (e->name, "-") == 0)
221 *fd = 0;
222 else
223 {
224 *fd = open (e->name, O_RDONLY, 0666);
225 if (*fd < 0)
226 return errno;
227 }
228 return 0;
229 }
230
231 static void
232 efinish (struct epoint *e)
233 {
234 if (e->conn)
235 {
236 error_t err = ftp_conn_finish_transfer (e->conn);
237 if (err)
238 error (31, err, "%s", e->name);
239 }
240 }
241
242 /* Give a name which refers to a directory file, and a name in that
243 directory, this should return in COMPOSITE the composite name refering to
244 that name in that directory, in malloced storage. */
245 error_t
246 eappend (struct epoint *e,
247 const char *dir, const char *name,
248 char **composite)
249 {
250 if (e->conn)
251 return ftp_conn_append_name (e->conn, dir, name, composite);
252 else
253 {
254 char *rval = malloc (strlen (dir) + 1 + strlen (name) + 1);
255
256 if (! rval)
257 return ENOMEM;
258
259 if (dir[0] == '/' && dir[1] == '\0')
260 stpcpy (stpcpy (rval, dir), name);
261 else
262 stpcpy (stpcpy (stpcpy (rval, dir), "/"), name);
263
264 *composite = rval;
265
266 return 0;
267 }
268 }
269
270 /* If the name of a file COMPOSITE is a composite name (containing both a
271 filename and a directory name), this function will return the name
272 component only in BASE, in malloced storage, otherwise it simply returns a
273 newly malloced copy of COMPOSITE in BASE. */
274 error_t
275 ebasename (struct epoint *e, const char *composite, char **base)
276 {
277 if (e->conn)
278 return ftp_conn_basename (e->conn, composite, base);
279 else
280 {
281 *base = strdup (basename (composite));
282 return 0;
283 }
284 }
285
286 static void
287 append_basename (struct epoint *dst, struct epoint *src)
288 {
289 char *bname;
290 error_t err = ebasename (src, src->file, &bname);
291
292 if (err)
293 error (33, err, "%s: Cannot find basename", src->name);
294
295 err = eappend (dst, dst->file, bname, &dst->file);
296 if (err)
297 error (34, err, "%s: Cannot append name component", dst->name);
298
299 err = eappend (dst, dst->name, bname, &dst->name);
300 if (err)
301 error (35, err, "%s: Cannot append name component", dst->name);
302 }
303
304 int
305 main (int argc, char **argv)
306 {
307 error_t err;
308 struct epoint rd = { 0 }, wr = { 0 };
309 struct ftp_conn_params def_params = { 0 }; /* default params */
310
311 /* Parse our options... */
312 error_t parse_opt (int key, char *arg, struct argp_state *state)
313 {
314 switch (key)
315 {
316 case ARGP_KEY_ARG:
317 switch (state->arg_num)
318 {
319 case 0: rd.name = arg; break;
320 case 1: wr.name = arg; break;
321 default: return ARGP_ERR_UNKNOWN;
322 }
323 break;
324 case ARGP_KEY_NO_ARGS:
325 argp_usage (state);
326
327 case 'u': def_params.user = arg; break;
328 case 'p': def_params.pass = arg; break;
329 case 'a': def_params.acct = arg; break;
330
331 case OPT_SRC_U: rd.params.user = arg; break;
332 case OPT_SRC_P: rd.params.pass = arg; break;
333 case OPT_SRC_A: rd.params.acct = arg; break;
334
335 case OPT_DST_U: wr.params.user = arg; break;
336 case OPT_DST_P: wr.params.pass = arg; break;
337 case OPT_DST_A: wr.params.acct = arg; break;
338
339 case 'D': conn_hooks.cntl_debug = cntl_debug; break;
340
341 default:
342 return ARGP_ERR_UNKNOWN;
343 }
344 return 0;
345 }
346 struct argp argp = {options, parse_opt, args_doc, doc};
347
348 argp_parse (&argp, argc, argv, 0, 0, 0);
349
350 econnect (&rd, &def_params, "SRC");
351 econnect (&wr, &def_params, "DST");
352
353 if (rd.conn && wr.conn)
354 /* Both endpoints are remote; directly copy between ftp servers. */
355 {
356 err = ftp_conn_rmt_copy (rd.conn, rd.file, wr.conn, wr.file);
357 if (err == EISDIR)
358 /* The destination name is a directory; try again with the source
359 basename appended. */
360 {
361 append_basename (&wr, &rd);
362 err = ftp_conn_rmt_copy (rd.conn, rd.file, wr.conn, wr.file);
363 }
364 if (err)
365 error (30, err, "Remote copy");
366 }
367 else
368 /* One endpoint is local, so do the copying ourself. */
369 {
370 int rd_fd, wr_fd;
371
372 err = eopen_rd (&rd, &rd_fd);
373 if (err)
374 error (31, err, "%s", rd.name);
375
376 err = eopen_wr (&wr, &wr_fd);
377 if (err == EISDIR)
378 /* The destination name is a directory; try again with the source
379 basename appended. */
380 {
381 append_basename (&wr, &rd);
382 err = eopen_wr (&wr, &wr_fd);
383 }
384 if (err)
385 error (32, err, "%s", wr.name);
386
387 cp (rd_fd, rd.name, wr_fd, wr.name);
388
389 close (rd_fd);
390 close (wr_fd);
391
392 efinish (&rd);
393 efinish (&wr);
394 }
395
396 exit (0);
397 }

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26