Fix compiler warning due to missing function prototype.
[svn.git] / tools / examples / svnput.c
blob7d75ddca6c1a9c9d92ec15c1212c37cce4dca0eb
1 /*
2 * svnput.c : upload a single file to a repository, overwriting
3 * any existing file by the same name.
5 * ***************************************************************
7 * WARNING!! Despite the warnings it gives, this program allows
8 * you to potentially overwrite a file you've never seen.
9 * USE AT YOUR OWN RISK!
11 * (While the repository won't 'lose' overwritten data, the
12 * overwriting may happen without your knowledge, and has the
13 * potential to cause much grief with your collaborators!)
15 * ***************************************************************
17 * ====================================================================
18 * Copyright (c) 2000-2004 CollabNet. All rights reserved.
20 * This software is licensed as described in the file COPYING, which
21 * you should have received as part of this distribution. The terms
22 * are also available at http://subversion.tigris.org/license-1.html.
23 * If newer versions of this license are posted there, you may use a
24 * newer version instead, at your option.
26 * This software consists of voluntary contributions made by many
27 * individuals. For exact contribution history, see the revision
28 * history and logs, available at http://subversion.tigris.org/.
29 * ====================================================================
31 * To compile on unix against Subversion and APR libraries, try
32 * something like:
34 * cc svnput.c -o svnput \
35 * -I/usr/local/include/subversion-1 -I/usr/local/apache2/include \
36 * -L/usr/local/apache2/lib -L/usr/local/lib \
37 * -lsvn_client-1 -lapr-0 -laprutil-0
41 #include "svn_client.h"
42 #include "svn_pools.h"
43 #include "svn_config.h"
44 #include "svn_fs.h"
45 #include "svn_cmdline.h"
46 #include "svn_path.h"
47 #include "svn_time.h"
50 /* Display a prompt and read a one-line response into the provided buffer,
51 removing a trailing newline if present. */
52 static svn_error_t *
53 prompt_and_read_line(const char *prompt,
54 char *buffer,
55 size_t max)
57 int len;
58 printf("%s: ", prompt);
59 if (fgets(buffer, max, stdin) == NULL)
60 return svn_error_create(0, NULL, "error reading stdin");
61 len = strlen(buffer);
62 if (len > 0 && buffer[len-1] == '\n')
63 buffer[len-1] = 0;
64 return SVN_NO_ERROR;
67 /* A tiny callback function of type 'svn_auth_simple_prompt_func_t'. For
68 a much better example, see svn_cl__auth_simple_prompt in the official
69 svn cmdline client. */
70 static svn_error_t *
71 my_simple_prompt_callback (svn_auth_cred_simple_t **cred,
72 void *baton,
73 const char *realm,
74 const char *username,
75 svn_boolean_t may_save,
76 apr_pool_t *pool)
78 svn_auth_cred_simple_t *ret = apr_pcalloc (pool, sizeof (*ret));
79 char answerbuf[100];
81 if (realm)
83 printf ("Authentication realm: %s\n", realm);
86 if (username)
87 ret->username = apr_pstrdup (pool, username);
88 else
90 SVN_ERR (prompt_and_read_line("Username", answerbuf, sizeof(answerbuf)));
91 ret->username = apr_pstrdup (pool, answerbuf);
94 SVN_ERR (prompt_and_read_line("Password", answerbuf, sizeof(answerbuf)));
95 ret->password = apr_pstrdup (pool, answerbuf);
97 *cred = ret;
98 return SVN_NO_ERROR;
102 /* A tiny callback function of type 'svn_auth_username_prompt_func_t'. For
103 a much better example, see svn_cl__auth_username_prompt in the official
104 svn cmdline client. */
105 static svn_error_t *
106 my_username_prompt_callback (svn_auth_cred_username_t **cred,
107 void *baton,
108 const char *realm,
109 svn_boolean_t may_save,
110 apr_pool_t *pool)
112 svn_auth_cred_username_t *ret = apr_pcalloc (pool, sizeof (*ret));
113 char answerbuf[100];
115 if (realm)
117 printf ("Authentication realm: %s\n", realm);
120 SVN_ERR (prompt_and_read_line("Username", answerbuf, sizeof(answerbuf)));
121 ret->username = apr_pstrdup (pool, answerbuf);
123 *cred = ret;
124 return SVN_NO_ERROR;
127 /* A callback function used when the RA layer needs a handle to a
128 temporary file. This is a reduced version of the callback used in
129 the official svn cmdline client. */
130 static svn_error_t *
131 open_tmp_file (apr_file_t **fp,
132 void *callback_baton,
133 apr_pool_t *pool)
135 const char *path;
136 const char *ignored_filename;
138 SVN_ERR (svn_io_temp_dir (&path, pool));
139 path = svn_path_join (path, "tempfile", pool);
141 /* Open a unique file, with delete-on-close set. */
142 SVN_ERR (svn_io_open_unique_file2 (fp, &ignored_filename,
143 path, ".tmp",
144 svn_io_file_del_on_close, pool));
146 return SVN_NO_ERROR;
150 /* Called when a commit is successful. */
151 static svn_error_t *
152 my_commit_callback (svn_revnum_t new_revision,
153 const char *date,
154 const char *author,
155 void *baton)
157 printf ("Upload complete. Committed revision %ld.\n", new_revision);
158 return SVN_NO_ERROR;
164 main (int argc, const char **argv)
166 apr_pool_t *pool;
167 svn_error_t *err;
168 apr_hash_t *dirents;
169 const char *upload_file, *URL;
170 const char *parent_URL, *basename;
171 svn_ra_plugin_t *ra_lib;
172 void *session, *ra_baton;
173 svn_revnum_t rev;
174 const svn_delta_editor_t *editor;
175 void *edit_baton;
176 svn_dirent_t *dirent;
177 svn_ra_callbacks_t *cbtable;
178 apr_hash_t *cfg_hash;
179 svn_auth_baton_t *auth_baton;
181 if (argc <= 2)
183 printf ("Usage: %s PATH URL\n", argv[0]);
184 printf (" Uploads file at PATH to Subversion repository URL.\n");
185 return EXIT_FAILURE;
187 upload_file = argv[1];
188 URL = argv[2];
190 /* Initialize the app. Send all error messages to 'stderr'. */
191 if (svn_cmdline_init ("minimal_client", stderr) != EXIT_SUCCESS)
192 return EXIT_FAILURE;
194 /* Create top-level memory pool. Be sure to read the HACKING file to
195 understand how to properly use/free subpools. */
196 pool = svn_pool_create (NULL);
198 /* Initialize the FS library. */
199 err = svn_fs_initialize (pool);
200 if (err) goto hit_error;
202 /* Make sure the ~/.subversion run-time config files exist, and load. */
203 err = svn_config_ensure (NULL, pool);
204 if (err) goto hit_error;
206 err = svn_config_get_config (&cfg_hash, NULL, pool);
207 if (err) goto hit_error;
209 /* Build an authentication baton. */
211 /* There are many different kinds of authentication back-end
212 "providers". See svn_auth.h for a full overview. */
213 svn_auth_provider_object_t *provider;
214 apr_array_header_t *providers
215 = apr_array_make (pool, 4, sizeof (svn_auth_provider_object_t *));
217 svn_client_get_simple_prompt_provider (&provider,
218 my_simple_prompt_callback,
219 NULL, /* baton */
220 2, /* retry limit */ pool);
221 APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
223 svn_client_get_username_prompt_provider (&provider,
224 my_username_prompt_callback,
225 NULL, /* baton */
226 2, /* retry limit */ pool);
227 APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
229 /* Register the auth-providers into the context's auth_baton. */
230 svn_auth_open (&auth_baton, providers, pool);
233 /* Create a table of callbacks for the RA session, mostly nonexistent. */
234 cbtable = apr_pcalloc (pool, sizeof(*cbtable));
235 cbtable->auth_baton = auth_baton;
236 cbtable->open_tmp_file = open_tmp_file;
238 /* Now do the real work. */
240 /* Open an RA session to the parent URL, fetch current HEAD rev and
241 "lock" onto that revnum for the remainder of the session. */
242 svn_path_split (URL, &parent_URL, &basename, pool);
244 err = svn_ra_init_ra_libs (&ra_baton, pool);
245 if (err) goto hit_error;
247 err = svn_ra_get_ra_library (&ra_lib, ra_baton, parent_URL, pool);
248 if (err) goto hit_error;
250 err = ra_lib->open (&session, parent_URL, cbtable, NULL, cfg_hash, pool);
251 if (err) goto hit_error;
253 err = ra_lib->get_latest_revnum (session, &rev, pool);
254 if (err) goto hit_error;
256 /* Examine contents of parent dir in the rev. */
257 err = ra_lib->get_dir (session, "", rev, &dirents, NULL, NULL, pool);
258 if (err) goto hit_error;
260 /* Sanity checks. Don't let the user shoot himself *too* much. */
261 dirent = apr_hash_get (dirents, basename, APR_HASH_KEY_STRING);
262 if (dirent && dirent->kind == svn_node_dir)
264 printf ("Sorry, a directory already exists at that URL.\n");
265 return EXIT_FAILURE;
267 if (dirent && dirent->kind == svn_node_file)
269 char answer[5];
271 printf ("\n*** WARNING ***\n\n");
272 printf ("You're about to overwrite r%ld of this file.\n", rev);
273 printf ("It was last changed by user '%s',\n",
274 dirent->last_author ? dirent->last_author : "?");
275 printf ("on %s.\n", svn_time_to_human_cstring (dirent->time, pool));
276 printf ("\nSomebody *might* have just changed the file seconds ago,\n"
277 "and your upload would be overwriting their changes!\n\n");
279 err = prompt_and_read_line("Are you SURE you want to upload? [y/n]",
280 answer, sizeof(answer));
281 if (err) goto hit_error;
283 if (apr_strnatcasecmp (answer, "y"))
285 printf ("Operation aborted.\n");
286 return EXIT_SUCCESS;
290 /* Fetch a commit editor (it's anchored on the parent URL, because
291 the session is too.) */
292 /* ### someday add an option for a user-written commit message? */
293 err = ra_lib->get_commit_editor (session, &editor, &edit_baton,
294 "File upload from 'svnput' program.",
295 my_commit_callback, NULL, pool);
296 if (err) goto hit_error;
298 /* Drive the editor */
300 void *root_baton, *file_baton, *handler_baton;
301 svn_txdelta_window_handler_t handler;
302 svn_stream_t *contents;
303 apr_file_t *f = NULL;
305 err = editor->open_root (edit_baton, rev, pool, &root_baton);
306 if (err) goto hit_error;
308 if (! dirent)
310 err = editor->add_file (basename, root_baton, NULL, SVN_INVALID_REVNUM,
311 pool, &file_baton);
313 else
315 err = editor->open_file (basename, root_baton, rev, pool,
316 &file_baton);
318 if (err) goto hit_error;
320 err = editor->apply_textdelta (file_baton, NULL, pool,
321 &handler, &handler_baton);
322 if (err) goto hit_error;
324 err = svn_io_file_open (&f, upload_file, APR_READ, APR_OS_DEFAULT, pool);
325 if (err) goto hit_error;
327 contents = svn_stream_from_aprfile (f, pool);
328 err = svn_txdelta_send_stream (contents, handler, handler_baton,
329 NULL, pool);
330 if (err) goto hit_error;
332 err = svn_io_file_close (f, pool);
333 if (err) goto hit_error;
335 err = editor->close_file (file_baton, NULL, pool);
336 if (err) goto hit_error;
338 err = editor->close_edit (edit_baton, pool);
339 if (err) goto hit_error;
342 return EXIT_SUCCESS;
344 hit_error:
345 svn_handle_error2 (err, stderr, FALSE, "svnput: ");
346 return EXIT_FAILURE;