85
* This must not have more than SVN_OPT_MAX_OPTIONS entries; if you
86
* need more, increase that limit first.
88
85
* The entire list must be terminated with an entry of nulls.
90
87
static const apr_getopt_option_t options_table[] =
93
N_("show help on a subcommand")},
96
N_("show help on a subcommand")},
98
{"version", svnlook__version, 0,
99
N_("show version information")},
102
N_("specify revision number ARG")},
104
{"transaction", 't', 1,
105
N_("specify transaction name ARG")},
110
{"show-ids", svnlook__show_ids, 0,
111
N_("show node revision ids for each path")},
113
{"no-diff-deleted", svnlook__no_diff_deleted, 0,
114
N_("do not print differences for deleted files")},
116
{"no-diff-added", svnlook__no_diff_added, 0,
117
N_("do not print differences for added files")},
119
{"diff-copy-from", svnlook__diff_copy_from, 0,
120
N_("print differences against the copy source")},
122
{"revprop", svnlook__revprop_opt, 0,
123
N_("operate on a revision property (use with -r or -t)")},
125
{"full-paths", svnlook__full_paths, 0,
126
N_("show full paths instead of indenting them")},
128
{"copy-info", svnlook__copy_info, 0,
129
N_("show details for copies")},
90
N_("show help on a subcommand")},
93
N_("show help on a subcommand")},
95
{"version", svnlook__version, 0,
96
N_("show program version information")},
99
N_("specify revision number ARG")},
101
{"transaction", 't', 1,
102
N_("specify transaction name ARG")},
107
{"show-ids", svnlook__show_ids, 0,
108
N_("show node revision ids for each path")},
110
{"no-diff-deleted", svnlook__no_diff_deleted, 0,
111
N_("do not print differences for deleted files")},
113
{"no-diff-added", svnlook__no_diff_added, 0,
114
N_("do not print differences for added files")},
116
{"diff-copy-from", svnlook__diff_copy_from, 0,
117
N_("print differences against the copy source")},
119
{"revprop", svnlook__revprop_opt, 0,
120
N_("operate on a revision property (use with -r or -t)")},
122
{"full-paths", svnlook__full_paths, 0,
123
N_("show full paths instead of indenting them")},
125
{"copy-info", svnlook__copy_info, 0,
126
N_("show details for copies")},
136
132
/* Array of available subcommands.
137
133
* The entire list must be terminated with an entry of nulls.
139
135
static const svn_opt_subcommand_desc_t cmd_table[] =
141
{"author", subcommand_author, {0},
142
N_("usage: svnlook author REPOS_PATH\n\n"
143
"Print the author.\n"),
146
{"cat", subcommand_cat, {0},
147
N_("usage: svnlook cat REPOS_PATH FILE_PATH\n\n"
148
"Print the contents of a file. Leading '/' on FILE_PATH is "
152
{"changed", subcommand_changed, {0},
153
N_("usage: svnlook changed REPOS_PATH\n\n"
154
"Print the paths that were changed.\n"),
155
{'r', 't', svnlook__copy_info} },
157
{"date", subcommand_date, {0},
158
N_("usage: svnlook date REPOS_PATH\n\n"
159
"Print the datestamp.\n"),
162
{"diff", subcommand_diff, {0},
163
N_("usage: svnlook diff REPOS_PATH\n\n"
164
"Print GNU-style diffs of changed files and properties.\n"),
165
{'r', 't', svnlook__no_diff_deleted, svnlook__no_diff_added,
166
svnlook__diff_copy_from} },
168
{"dirs-changed", subcommand_dirschanged, {0},
169
N_("usage: svnlook dirs-changed REPOS_PATH\n\n"
170
"Print the directories that were themselves changed (property edits)\n"
171
"or whose file children were changed.\n"),
174
{"help", subcommand_help, {"?", "h"},
175
N_("usage: svnlook help [SUBCOMMAND...]\n\n"
176
"Describe the usage of this program or its subcommands.\n"),
177
{svnlook__version} },
179
{"history", subcommand_history, {0},
180
N_("usage: svnlook history REPOS_PATH [PATH_IN_REPOS]\n\n"
181
"Print information about the history of a path in the repository (or\n"
182
"the root directory if no path is supplied).\n"),
183
{'r', svnlook__show_ids} },
185
{"info", subcommand_info, {0},
186
N_("usage: svnlook info REPOS_PATH\n\n"
187
"Print the author, datestamp, log message size, and log message.\n"),
190
{"lock", subcommand_lock, {0},
191
N_("usage: svnlook lock REPOS_PATH PATH_IN_REPOS\n\n"
192
"If a lock exists on a path in the repository, describe it.\n"),
195
{"log", subcommand_log, {0},
196
N_("usage: svnlook log REPOS_PATH\n\n"
197
"Print the log message.\n"),
200
{"propget", subcommand_pget, {"pget", "pg"},
201
N_("usage: svnlook propget REPOS_PATH PROPNAME [PATH_IN_REPOS]\n\n"
202
"Print the raw value of a property on a path in the repository.\n"
203
"With --revprop, prints the raw value of a revision property.\n"),
204
{'r', 't', svnlook__revprop_opt} },
206
{"proplist", subcommand_plist, {"plist", "pl"},
207
N_("usage: svnlook proplist REPOS_PATH [PATH_IN_REPOS]\n\n"
208
"List the properties of a path in the repository, or\n"
209
"with the --revprop option, revision properties.\n"
210
"With -v, show the property values too.\n"),
211
{'r', 't', 'v', svnlook__revprop_opt} },
213
{"tree", subcommand_tree, {0},
214
N_("usage: svnlook tree REPOS_PATH [PATH_IN_REPOS]\n\n"
215
"Print the tree, starting at PATH_IN_REPOS (if supplied, at the root\n"
216
"of the tree otherwise), optionally showing node revision ids.\n"),
217
{'r', 't', svnlook__show_ids, svnlook__full_paths} },
219
{"uuid", subcommand_uuid, {0},
220
N_("usage: svnlook uuid REPOS_PATH\n\n"
221
"Print the repository's UUID.\n"),
224
{"youngest", subcommand_youngest, {0},
225
N_("usage: svnlook youngest REPOS_PATH\n\n"
226
"Print the youngest revision number.\n"),
229
{ NULL, NULL, {0}, NULL, {0} }
137
{"author", subcommand_author, {0},
138
N_("usage: svnlook author REPOS_PATH\n\n"
139
"Print the author.\n"),
142
{"cat", subcommand_cat, {0},
143
N_("usage: svnlook cat REPOS_PATH FILE_PATH\n\n"
144
"Print the contents of a file. Leading '/' on FILE_PATH is optional.\n"),
147
{"changed", subcommand_changed, {0},
148
N_("usage: svnlook changed REPOS_PATH\n\n"
149
"Print the paths that were changed.\n"),
150
{'r', 't', svnlook__copy_info} },
152
{"date", subcommand_date, {0},
153
N_("usage: svnlook date REPOS_PATH\n\n"
154
"Print the datestamp.\n"),
157
{"diff", subcommand_diff, {0},
158
N_("usage: svnlook diff REPOS_PATH\n\n"
159
"Print GNU-style diffs of changed files and properties.\n"),
160
{'r', 't', svnlook__no_diff_deleted, svnlook__no_diff_added,
161
svnlook__diff_copy_from} },
163
{"dirs-changed", subcommand_dirschanged, {0},
164
N_("usage: svnlook dirs-changed REPOS_PATH\n\n"
165
"Print the directories that were themselves changed (property edits)\n"
166
"or whose file children were changed.\n"),
169
{"help", subcommand_help, {"?", "h"},
170
N_("usage: svnlook help [SUBCOMMAND...]\n\n"
171
"Describe the usage of this program or its subcommands.\n"),
174
{"history", subcommand_history, {0},
175
N_("usage: svnlook history REPOS_PATH [PATH_IN_REPOS]\n\n"
176
"Print information about the history of a path in the repository (or\n"
177
"the root directory if no path is supplied).\n"),
178
{'r', svnlook__show_ids} },
180
{"info", subcommand_info, {0},
181
N_("usage: svnlook info REPOS_PATH\n\n"
182
"Print the author, datestamp, log message size, and log message.\n"),
185
{"lock", subcommand_lock, {0},
186
N_("usage: svnlook lock REPOS_PATH PATH_IN_REPOS\n\n"
187
"If a lock exists on a path in the repository, describe it.\n"),
190
{"log", subcommand_log, {0},
191
N_("usage: svnlook log REPOS_PATH\n\n"
192
"Print the log message.\n"),
195
{"propget", subcommand_pget, {"pget", "pg"},
196
N_("usage: svnlook propget REPOS_PATH PROPNAME [PATH_IN_REPOS]\n\n"
197
"Print the raw value of a property on a path in the repository.\n"
198
"With --revprop, prints the raw value of a revision property.\n"),
199
{'r', 't', svnlook__revprop_opt} },
201
{"proplist", subcommand_plist, {"plist", "pl"},
202
N_("usage: svnlook proplist REPOS_PATH [PATH_IN_REPOS]\n\n"
203
"List the properties of a path in the repository, or\n"
204
"with the --revprop option, revision properties.\n"
205
"With -v, show the property values too.\n"),
206
{'r', 't', 'v', svnlook__revprop_opt} },
208
{"tree", subcommand_tree, {0},
209
N_("usage: svnlook tree REPOS_PATH [PATH_IN_REPOS]\n\n"
210
"Print the tree, starting at PATH_IN_REPOS (if supplied, at the root\n"
211
"of the tree otherwise), optionally showing node revision ids.\n"),
212
{'r', 't', svnlook__show_ids, svnlook__full_paths} },
214
{"uuid", subcommand_uuid, {0},
215
N_("usage: svnlook uuid REPOS_PATH\n\n"
216
"Print the repository's UUID.\n"),
219
{"youngest", subcommand_youngest, {0},
220
N_("usage: svnlook youngest REPOS_PATH\n\n"
221
"Print the youngest revision number.\n"),
224
{ NULL, NULL, {0}, NULL, {0} }
233
228
/* Baton for passing option/argument state to a subcommand function. */
543
539
return SVN_NO_ERROR;
545
541
/* Recursively handle the node's children. */
546
subpool = svn_pool_create (pool);
547
full_path = svn_path_join (path, node->name, subpool);
548
SVN_ERR (print_changed_tree (node, full_path, copy_info, subpool));
542
subpool = svn_pool_create(pool);
543
full_path = svn_path_join(path, node->name, subpool);
544
SVN_ERR(print_changed_tree(node, full_path, copy_info, subpool));
549
545
while (node->sibling)
551
svn_pool_clear (subpool);
547
svn_pool_clear(subpool);
552
548
node = node->sibling;
553
full_path = svn_path_join (path, node->name, subpool);
554
SVN_ERR (print_changed_tree (node, full_path, copy_info, subpool));
549
full_path = svn_path_join(path, node->name, subpool);
550
SVN_ERR(print_changed_tree(node, full_path, copy_info, subpool));
556
svn_pool_destroy (subpool);
552
svn_pool_destroy(subpool);
558
554
return SVN_NO_ERROR;
562
/* Set *FH to a file handle for a writable binary file at PATH.
563
Create the file if it doesn't exist, truncate it if it does.
564
Create ancestor directories if necessary. Allocate *FH in POOL. */
566
open_writable_binary_file (apr_file_t **fh,
567
const char *path /* UTF-8! */,
570
apr_array_header_t *path_pieces;
571
svn_error_t *err, *err2 = NULL;
573
const char *full_path, *dir;
575
/* Try the easy way to open the file. */
576
err = svn_io_file_open (fh, path,
577
APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY,
578
APR_OS_DEFAULT, pool);
582
svn_path_split (path, &dir, NULL, pool);
584
path_pieces = svn_path_decompose (dir, pool);
586
/* If the file path has no parent, then we've already tried to open
587
it as best as we care to try above. */
588
if (! path_pieces->nelts)
592
for (i = 0; i < path_pieces->nelts; i++)
594
svn_node_kind_t kind;
595
const char *piece = ((const char **) (path_pieces->elts))[i];
596
full_path = svn_path_join (full_path, piece, pool);
597
if ((err2 = svn_io_check_resolved_path (full_path, &kind, pool)))
600
/* Does this path component exist at all? */
601
if (kind == svn_node_none)
603
if ((err2 = svn_io_dir_make (full_path, APR_OS_DEFAULT, pool)))
606
else if (kind != svn_node_dir)
608
return svn_error_createf (err->apr_err, err,
609
_("Error creating dir '%s' (path exists)"),
614
/* Now that we are ensured that the parent path for this file
615
exists, try once more to open it. */
616
err2 = svn_io_file_open (fh, path,
617
APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY,
618
APR_OS_DEFAULT, pool);
621
svn_error_clear (err);
627
dump_contents (apr_file_t *fh,
629
const char *path /* UTF-8! */,
559
dump_contents(apr_file_t *fh,
561
const char *path /* UTF-8! */,
632
564
svn_stream_t *contents, *file_stream;
634
566
/* Grab the contents and copy them into fh. */
635
SVN_ERR (svn_fs_file_contents (&contents, root, path, pool));
636
file_stream = svn_stream_from_aprfile (fh, pool);
637
SVN_ERR (svn_stream_copy (contents, file_stream, pool));
567
SVN_ERR(svn_fs_file_contents(&contents, root, path, pool));
568
file_stream = svn_stream_from_aprfile(fh, pool);
569
SVN_ERR(svn_stream_copy(contents, file_stream, pool));
638
570
return SVN_NO_ERROR;
903
835
- Second, dump the contents of the new version of the file
904
into the svnlook temporary directory, building out the
905
actual directories that need to be created in order to
906
fully represent the filesystem path inside the tmp
836
into the temporary directory.
909
838
- Then, dump the contents of the old version of the file into
910
the svnlook temporary directory, also building out intermediate
911
directories as needed, using a unique temporary file name (we
912
do this *after* putting the new version of the file
913
there in case something actually versioned has a name
914
that looks like one of our unique identifiers).
839
the temporary directory.
916
841
- Next, we run 'diff', passing the repository paths as the
919
- Finally, we delete the temporary files (but leave the
920
built-out directories in place until after all diff
921
handling has been finished). */
844
- Finally, we delete the temporary files. */
922
845
if (node->action == 'R' && node->text_mod)
925
SVN_ERR (prepare_tmpfiles (&orig_path, &new_path, &binary,
926
base_root, base_path, root, path,
848
SVN_ERR(prepare_tmpfiles(&orig_path, &new_path, &binary,
849
base_root, base_path, root, path,
929
852
else if (c->diff_copy_from && node->action == 'A' && is_copy)
931
854
if (node->text_mod)
934
SVN_ERR (prepare_tmpfiles (&orig_path, &new_path, &binary,
935
base_root, base_path, root, path,
857
SVN_ERR(prepare_tmpfiles(&orig_path, &new_path, &binary,
858
base_root, base_path, root, path,
939
862
else if (! c->no_diff_added && node->action == 'A')
942
865
orig_empty = TRUE;
943
SVN_ERR (prepare_tmpfiles (&orig_path, &new_path, &binary,
944
NULL, base_path, root, path,
866
SVN_ERR(prepare_tmpfiles(&orig_path, &new_path, &binary,
867
NULL, base_path, root, path,
947
870
else if (! c->no_diff_deleted && node->action == 'D')
950
SVN_ERR (prepare_tmpfiles (&orig_path, &new_path, &binary,
951
base_root, base_path, NULL, path,
873
SVN_ERR(prepare_tmpfiles(&orig_path, &new_path, &binary,
874
base_root, base_path, NULL, path,
955
878
/* The header for the copy case has already been written, and we don't
957
880
if (! printed_header
958
881
&& (node->action != 'R' || node->text_mod))
960
SVN_ERR (svn_cmdline_printf (pool, "%s: %s\n",
961
((node->action == 'A') ? _("Added") :
962
((node->action == 'D') ? _("Deleted") :
963
((node->action == 'R') ? _("Modified")
883
SVN_ERR(svn_cmdline_printf(pool, "%s: %s\n",
884
((node->action == 'A') ? _("Added") :
885
((node->action == 'D') ? _("Deleted") :
886
((node->action == 'R') ? _("Modified")
966
889
printed_header = TRUE;
972
SVN_ERR (svn_cmdline_printf (pool, "%s\n", equal_string));
973
SVN_ERR (svn_cmdline_fflush (stdout));
895
SVN_ERR(svn_cmdline_printf(pool, "%s\n", equal_string));
896
SVN_ERR(svn_cmdline_fflush(stdout));
976
SVN_ERR (svn_cmdline_printf (pool, _("(Binary files differ)\n")));
899
SVN_ERR(svn_cmdline_printf(pool, _("(Binary files differ)\n")));
979
902
svn_diff_t *diff;
980
SVN_ERR (svn_diff_file_diff (&diff, orig_path, new_path, pool));
981
if (svn_diff_contains_diffs (diff))
903
SVN_ERR(svn_diff_file_diff(&diff, orig_path, new_path, pool));
904
if (svn_diff_contains_diffs(diff))
983
906
svn_stream_t *ostream;
984
907
const char *orig_label, *new_label;
986
SVN_ERR (svn_stream_for_stdout (&ostream, pool));
909
SVN_ERR(svn_stream_for_stdout(&ostream, pool));
989
SVN_ERR (generate_label (&orig_label, NULL, path, pool));
912
SVN_ERR(generate_label(&orig_label, NULL, path, pool));
991
SVN_ERR (generate_label (&orig_label, base_root,
993
SVN_ERR (generate_label (&new_label, root, path, pool));
994
SVN_ERR (svn_diff_file_output_unified2
995
(ostream, diff, orig_path, new_path,
996
orig_label, new_label,
997
svn_cmdline_output_encoding (pool), pool));
998
SVN_ERR (svn_stream_close (ostream));
914
SVN_ERR(generate_label(&orig_label, base_root,
916
SVN_ERR(generate_label(&new_label, root, path, pool));
917
SVN_ERR(svn_diff_file_output_unified2
918
(ostream, diff, orig_path, new_path,
919
orig_label, new_label,
920
svn_cmdline_output_encoding(pool), pool));
921
SVN_ERR(svn_stream_close(ostream));
1002
SVN_ERR (svn_cmdline_printf (pool, "\n"));
1003
SVN_ERR (svn_cmdline_fflush (stdout));
925
SVN_ERR(svn_cmdline_printf(pool, "\n"));
926
SVN_ERR(svn_cmdline_fflush(stdout));
1005
928
else if (printed_header)
1006
SVN_ERR (svn_cmdline_printf (pool, "\n"));
929
SVN_ERR(svn_cmdline_printf(pool, "\n"));
1008
931
/* Make sure we delete any temporary files. */
1010
SVN_ERR (svn_io_remove_file (orig_path, pool));
933
SVN_ERR(svn_io_remove_file(orig_path, pool));
1012
SVN_ERR (svn_io_remove_file (new_path, pool));
935
SVN_ERR(svn_io_remove_file(new_path, pool));
1014
937
/*** Now handle property diffs ***/
1015
938
if ((node->prop_mod) && (node->action != 'D'))
1068
991
Use POOL for all allocations. */
1069
992
static svn_error_t *
1070
print_tree (svn_fs_root_t *root,
1071
const char *path /* UTF-8! */,
1072
const svn_fs_id_t *id,
1073
svn_boolean_t is_dir,
1075
svn_boolean_t show_ids,
1076
svn_boolean_t full_paths,
993
print_tree(svn_fs_root_t *root,
994
const char *path /* UTF-8! */,
995
const svn_fs_id_t *id,
996
svn_boolean_t is_dir,
998
svn_boolean_t show_ids,
999
svn_boolean_t full_paths,
1079
1002
apr_pool_t *subpool;
1081
1004
apr_hash_t *entries;
1082
1005
apr_hash_index_t *hi;
1084
SVN_ERR (check_cancel (NULL));
1007
SVN_ERR(check_cancel(NULL));
1086
1009
/* Print the indentation. */
1087
1010
if(!full_paths)
1088
1011
for (i = 0; i < indentation; i++)
1089
SVN_ERR (svn_cmdline_fputs (" ", stdout, pool));
1012
SVN_ERR(svn_cmdline_fputs(" ", stdout, pool));
1091
1014
/* Print the node. */
1092
SVN_ERR (svn_cmdline_printf (pool, "%s%s",
1093
full_paths ? path : svn_path_basename (path,
1095
is_dir && strcmp (path, "/") ? "/" : ""));
1015
SVN_ERR(svn_cmdline_printf(pool, "%s%s",
1016
full_paths ? path : svn_path_basename(path,
1018
is_dir && strcmp(path, "/") ? "/" : ""));
1099
1022
svn_string_t *unparsed_id = NULL;
1101
unparsed_id = svn_fs_unparse_id (id, pool);
1102
SVN_ERR (svn_cmdline_printf (pool, " <%s>",
1024
unparsed_id = svn_fs_unparse_id(id, pool);
1025
SVN_ERR(svn_cmdline_printf(pool, " <%s>",
1107
SVN_ERR (svn_cmdline_fputs ("\n", stdout, pool));
1030
SVN_ERR(svn_cmdline_fputs("\n", stdout, pool));
1109
1032
/* Return here if PATH is not a directory. */
1111
1034
return SVN_NO_ERROR;
1113
1036
/* Recursively handle the node's children. */
1114
SVN_ERR (svn_fs_dir_entries (&entries, root, path, pool));
1115
subpool = svn_pool_create (pool);
1116
for (hi = apr_hash_first (pool, entries); hi; hi = apr_hash_next (hi))
1037
SVN_ERR(svn_fs_dir_entries(&entries, root, path, pool));
1038
subpool = svn_pool_create(pool);
1039
for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
1118
1041
const void *key;
1119
1042
apr_ssize_t keylen;
1121
1044
svn_fs_dirent_t *entry;
1123
svn_pool_clear (subpool);
1124
apr_hash_this (hi, &key, &keylen, &val);
1046
svn_pool_clear(subpool);
1047
apr_hash_this(hi, &key, &keylen, &val);
1126
SVN_ERR (print_tree (root, svn_path_join (path, entry->name, pool),
1127
entry->id, (entry->kind == svn_node_dir),
1128
indentation + 1, show_ids, full_paths, subpool));
1049
SVN_ERR(print_tree(root, svn_path_join(path, entry->name, pool),
1050
entry->id, (entry->kind == svn_node_dir),
1051
indentation + 1, show_ids, full_paths, subpool));
1130
svn_pool_destroy (subpool);
1053
svn_pool_destroy(subpool);
1132
1055
return SVN_NO_ERROR;
1325
1248
/* Print a list of all paths modified in a format compatible with `svn
1327
1250
static svn_error_t *
1328
do_changed (svnlook_ctxt_t *c, apr_pool_t *pool)
1251
do_changed(svnlook_ctxt_t *c, apr_pool_t *pool)
1330
1253
svn_fs_root_t *root;
1331
1254
svn_revnum_t base_rev_id;
1332
1255
svn_repos_node_t *tree;
1334
SVN_ERR (get_root (&root, c, pool));
1257
SVN_ERR(get_root(&root, c, pool));
1335
1258
if (c->is_revision)
1336
1259
base_rev_id = c->rev_id - 1;
1338
base_rev_id = svn_fs_txn_base_revision (c->txn);
1261
base_rev_id = svn_fs_txn_base_revision(c->txn);
1340
if (! SVN_IS_VALID_REVNUM (base_rev_id))
1263
if (! SVN_IS_VALID_REVNUM(base_rev_id))
1341
1264
return svn_error_createf
1342
1265
(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
1343
1266
_("Transaction '%s' is not based on a revision; how odd"),
1346
SVN_ERR (generate_delta_tree (&tree, c->repos, root, base_rev_id,
1269
SVN_ERR(generate_delta_tree(&tree, c->repos, root, base_rev_id,
1349
SVN_ERR (print_changed_tree (tree, "", c->copy_info, pool));
1272
SVN_ERR(print_changed_tree(tree, "", c->copy_info, pool));
1351
1274
return SVN_NO_ERROR;
1354
/* Create a new temporary directory with an 'svnlook' prefix. */
1355
static svn_error_t *
1356
create_unique_tmpdir (const char **name, apr_pool_t *pool)
1358
const char *unique_name;
1359
const char *sys_tmp_dir;
1363
SVN_ERR (svn_io_temp_dir (&sys_tmp_dir, pool));
1364
base = svn_path_join (sys_tmp_dir, "svnlook", pool);
1366
for (i = 1; i <= 99999; i++)
1370
unique_name = apr_psprintf (pool, "%s.%u", base, i);
1371
/* The directory has a predictable name so it is made writeable for
1372
the owner only (without relying on the umask) to inhibit symlink
1373
attacks on the filenames; the filenames are also, to a certain
1374
extent, predictable. */
1375
err = svn_io_dir_make (unique_name,
1376
APR_UREAD | APR_UWRITE | APR_UEXECUTE,
1381
*name = unique_name;
1382
return SVN_NO_ERROR;
1385
if (! APR_STATUS_IS_EEXIST (err->apr_err))
1388
svn_error_clear (err);
1392
return svn_error_createf (SVN_ERR_IO_UNIQUE_NAMES_EXHAUSTED,
1393
NULL, _("Can't create temporary directory"));
1396
1278
/* Print some diff-y stuff in a TBD way. :-) */
1397
1279
static svn_error_t *
1398
do_diff (svnlook_ctxt_t *c, apr_pool_t *pool)
1280
do_diff(svnlook_ctxt_t *c, apr_pool_t *pool)
1400
1282
svn_fs_root_t *root, *base_root;
1401
1283
svn_revnum_t base_rev_id;
1402
1284
svn_repos_node_t *tree;
1404
SVN_ERR (get_root (&root, c, pool));
1286
SVN_ERR(get_root(&root, c, pool));
1405
1287
if (c->is_revision)
1406
1288
base_rev_id = c->rev_id - 1;
1408
base_rev_id = svn_fs_txn_base_revision (c->txn);
1290
base_rev_id = svn_fs_txn_base_revision(c->txn);
1410
if (! SVN_IS_VALID_REVNUM (base_rev_id))
1292
if (! SVN_IS_VALID_REVNUM(base_rev_id))
1411
1293
return svn_error_createf
1412
1294
(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
1413
1295
_("Transaction '%s' is not based on a revision; how odd"),
1416
SVN_ERR (generate_delta_tree (&tree, c->repos, root, base_rev_id,
1298
SVN_ERR(generate_delta_tree(&tree, c->repos, root, base_rev_id,
1420
1302
const char *tmpdir;
1423
SVN_ERR (svn_fs_revision_root (&base_root, c->fs, base_rev_id, pool));
1424
SVN_ERR (create_unique_tmpdir (&tmpdir, pool));
1425
err = print_diff_tree (root, base_root, tree, "", "",
1429
svn_error_clear (svn_io_remove_dir (tmpdir, pool));
1432
SVN_ERR (svn_io_remove_dir (tmpdir, pool));
1304
SVN_ERR(svn_fs_revision_root(&base_root, c->fs, base_rev_id, pool));
1305
SVN_ERR(svn_io_temp_dir(&tmpdir, pool));
1307
SVN_ERR(print_diff_tree(root, base_root, tree, "", "",
1434
1310
return SVN_NO_ERROR;
1629
1505
/* Print the diff between revision 0 and our root. */
1630
1506
static svn_error_t *
1631
do_tree (svnlook_ctxt_t *c,
1633
svn_boolean_t show_ids,
1634
svn_boolean_t full_paths,
1507
do_tree(svnlook_ctxt_t *c,
1509
svn_boolean_t show_ids,
1510
svn_boolean_t full_paths,
1637
1513
svn_fs_root_t *root;
1638
1514
const svn_fs_id_t *id;
1639
1515
svn_boolean_t is_dir;
1641
SVN_ERR (get_root (&root, c, pool));
1642
SVN_ERR (svn_fs_node_id (&id, root, path, pool));
1643
SVN_ERR (svn_fs_is_dir (&is_dir, root, path, pool));
1644
SVN_ERR (print_tree (root, path, id, is_dir, 0, show_ids, full_paths, pool));
1517
SVN_ERR(get_root(&root, c, pool));
1518
SVN_ERR(svn_fs_node_id(&id, root, path, pool));
1519
SVN_ERR(svn_fs_is_dir(&is_dir, root, path, pool));
1520
SVN_ERR(print_tree(root, path, id, is_dir, 0, show_ids, full_paths, pool));
1645
1521
return SVN_NO_ERROR;
1649
1525
/* Custom filesystem warning function. */
1651
warning_func (void *baton,
1527
warning_func(void *baton,
1656
svn_handle_error2 (err, stderr, FALSE, "svnlook: ");
1532
svn_handle_error2(err, stderr, FALSE, "svnlook: ");
1660
1536
/* Factory function for the context baton. */
1661
1537
static svn_error_t *
1662
get_ctxt_baton (svnlook_ctxt_t **baton_p,
1663
struct svnlook_opt_state *opt_state,
1538
get_ctxt_baton(svnlook_ctxt_t **baton_p,
1539
struct svnlook_opt_state *opt_state,
1666
svnlook_ctxt_t *baton = apr_pcalloc (pool, sizeof (*baton));
1542
svnlook_ctxt_t *baton = apr_pcalloc(pool, sizeof(*baton));
1668
SVN_ERR (svn_repos_open (&(baton->repos), opt_state->repos_path, pool));
1669
baton->fs = svn_repos_fs (baton->repos);
1670
svn_fs_set_warning_func (baton->fs, warning_func, NULL);
1544
SVN_ERR(svn_repos_open(&(baton->repos), opt_state->repos_path, pool));
1545
baton->fs = svn_repos_fs(baton->repos);
1546
svn_fs_set_warning_func(baton->fs, warning_func, NULL);
1671
1547
baton->show_ids = opt_state->show_ids;
1672
1548
baton->no_diff_deleted = opt_state->no_diff_deleted;
1673
1549
baton->no_diff_added = opt_state->no_diff_added;
1715
1591
(SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
1716
1592
_("Missing repository path argument"));
1718
SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
1719
SVN_ERR (do_cat (c, opt_state->arg1, pool));
1720
return SVN_NO_ERROR;
1723
/* This implements `svn_opt_subcommand_t'. */
1724
static svn_error_t *
1725
subcommand_changed (apr_getopt_t *os, void *baton, apr_pool_t *pool)
1727
struct svnlook_opt_state *opt_state = baton;
1730
SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
1731
SVN_ERR (do_changed (c, pool));
1732
return SVN_NO_ERROR;
1735
/* This implements `svn_opt_subcommand_t'. */
1736
static svn_error_t *
1737
subcommand_date (apr_getopt_t *os, void *baton, apr_pool_t *pool)
1739
struct svnlook_opt_state *opt_state = baton;
1742
SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
1743
SVN_ERR (do_date (c, pool));
1744
return SVN_NO_ERROR;
1747
/* This implements `svn_opt_subcommand_t'. */
1748
static svn_error_t *
1749
subcommand_diff (apr_getopt_t *os, void *baton, apr_pool_t *pool)
1751
struct svnlook_opt_state *opt_state = baton;
1754
SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
1755
SVN_ERR (do_diff (c, pool));
1756
return SVN_NO_ERROR;
1759
/* This implements `svn_opt_subcommand_t'. */
1760
static svn_error_t *
1761
subcommand_dirschanged (apr_getopt_t *os, void *baton, apr_pool_t *pool)
1763
struct svnlook_opt_state *opt_state = baton;
1766
SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
1767
SVN_ERR (do_dirs_changed (c, pool));
1768
return SVN_NO_ERROR;
1771
/* This implements `svn_opt_subcommand_t'. */
1772
static svn_error_t *
1773
subcommand_help (apr_getopt_t *os, void *baton, apr_pool_t *pool)
1594
SVN_ERR(get_ctxt_baton(&c, opt_state, pool));
1595
SVN_ERR(do_cat(c, opt_state->arg1, pool));
1596
return SVN_NO_ERROR;
1599
/* This implements `svn_opt_subcommand_t'. */
1600
static svn_error_t *
1601
subcommand_changed(apr_getopt_t *os, void *baton, apr_pool_t *pool)
1603
struct svnlook_opt_state *opt_state = baton;
1606
SVN_ERR(get_ctxt_baton(&c, opt_state, pool));
1607
SVN_ERR(do_changed(c, pool));
1608
return SVN_NO_ERROR;
1611
/* This implements `svn_opt_subcommand_t'. */
1612
static svn_error_t *
1613
subcommand_date(apr_getopt_t *os, void *baton, apr_pool_t *pool)
1615
struct svnlook_opt_state *opt_state = baton;
1618
SVN_ERR(get_ctxt_baton(&c, opt_state, pool));
1619
SVN_ERR(do_date(c, pool));
1620
return SVN_NO_ERROR;
1623
/* This implements `svn_opt_subcommand_t'. */
1624
static svn_error_t *
1625
subcommand_diff(apr_getopt_t *os, void *baton, apr_pool_t *pool)
1627
struct svnlook_opt_state *opt_state = baton;
1630
SVN_ERR(get_ctxt_baton(&c, opt_state, pool));
1631
SVN_ERR(do_diff(c, pool));
1632
return SVN_NO_ERROR;
1635
/* This implements `svn_opt_subcommand_t'. */
1636
static svn_error_t *
1637
subcommand_dirschanged(apr_getopt_t *os, void *baton, apr_pool_t *pool)
1639
struct svnlook_opt_state *opt_state = baton;
1642
SVN_ERR(get_ctxt_baton(&c, opt_state, pool));
1643
SVN_ERR(do_dirs_changed(c, pool));
1644
return SVN_NO_ERROR;
1647
/* This implements `svn_opt_subcommand_t'. */
1648
static svn_error_t *
1649
subcommand_help(apr_getopt_t *os, void *baton, apr_pool_t *pool)
1775
1651
struct svnlook_opt_state *opt_state = baton;
1776
1652
const char *header =
1929
1806
(SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
1930
1807
_("Missing repository path argument"));
1932
SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
1933
SVN_ERR (do_plist (c, opt_state->revprop ? NULL : opt_state->arg1,
1934
opt_state->verbose, pool));
1935
return SVN_NO_ERROR;
1938
/* This implements `svn_opt_subcommand_t'. */
1939
static svn_error_t *
1940
subcommand_tree (apr_getopt_t *os, void *baton, apr_pool_t *pool)
1942
struct svnlook_opt_state *opt_state = baton;
1945
SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
1946
SVN_ERR (do_tree (c, opt_state->arg1 ? opt_state->arg1 : "",
1947
opt_state->show_ids, opt_state->full_paths, pool));
1948
return SVN_NO_ERROR;
1951
/* This implements `svn_opt_subcommand_t'. */
1952
static svn_error_t *
1953
subcommand_youngest (apr_getopt_t *os, void *baton, apr_pool_t *pool)
1955
struct svnlook_opt_state *opt_state = baton;
1958
SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
1959
SVN_ERR (svn_cmdline_printf (pool, "%ld\n", c->rev_id));
1960
return SVN_NO_ERROR;
1963
/* This implements `svn_opt_subcommand_t'. */
1964
static svn_error_t *
1965
subcommand_uuid (apr_getopt_t *os, void *baton, apr_pool_t *pool)
1809
SVN_ERR(get_ctxt_baton(&c, opt_state, pool));
1810
SVN_ERR(do_plist(c, opt_state->revprop ? NULL : opt_state->arg1,
1811
opt_state->verbose, pool));
1812
return SVN_NO_ERROR;
1815
/* This implements `svn_opt_subcommand_t'. */
1816
static svn_error_t *
1817
subcommand_tree(apr_getopt_t *os, void *baton, apr_pool_t *pool)
1819
struct svnlook_opt_state *opt_state = baton;
1822
SVN_ERR(get_ctxt_baton(&c, opt_state, pool));
1823
SVN_ERR(do_tree(c, opt_state->arg1 ? opt_state->arg1 : "",
1824
opt_state->show_ids, opt_state->full_paths, pool));
1825
return SVN_NO_ERROR;
1828
/* This implements `svn_opt_subcommand_t'. */
1829
static svn_error_t *
1830
subcommand_youngest(apr_getopt_t *os, void *baton, apr_pool_t *pool)
1832
struct svnlook_opt_state *opt_state = baton;
1835
SVN_ERR(get_ctxt_baton(&c, opt_state, pool));
1836
SVN_ERR(svn_cmdline_printf(pool, "%ld\n", c->rev_id));
1837
return SVN_NO_ERROR;
1840
/* This implements `svn_opt_subcommand_t'. */
1841
static svn_error_t *
1842
subcommand_uuid(apr_getopt_t *os, void *baton, apr_pool_t *pool)
1967
1844
struct svnlook_opt_state *opt_state = baton;
1968
1845
svnlook_ctxt_t *c;
1969
1846
const char *uuid;
1971
SVN_ERR (get_ctxt_baton (&c, opt_state, pool));
1972
SVN_ERR (svn_fs_get_uuid (c->fs, &uuid, pool));
1973
SVN_ERR (svn_cmdline_printf (pool, "%s\n", uuid));
1848
SVN_ERR(get_ctxt_baton(&c, opt_state, pool));
1849
SVN_ERR(svn_fs_get_uuid(c->fs, &uuid, pool));
1850
SVN_ERR(svn_cmdline_printf(pool, "%s\n", uuid));
1974
1851
return SVN_NO_ERROR;
1996
1873
/* Initialize the app. */
1997
if (svn_cmdline_init ("svnlook", stderr) != EXIT_SUCCESS)
1874
if (svn_cmdline_init("svnlook", stderr) != EXIT_SUCCESS)
1998
1875
return EXIT_FAILURE;
2000
1877
/* Create our top-level pool. Use a seperate mutexless allocator,
2001
1878
* given this application is single threaded.
2003
if (apr_allocator_create (&allocator))
1880
if (apr_allocator_create(&allocator))
2004
1881
return EXIT_FAILURE;
2006
apr_allocator_max_free_set (allocator, SVN_ALLOCATOR_RECOMMENDED_MAX_FREE);
2008
pool = svn_pool_create_ex (NULL, allocator);
2009
apr_allocator_owner_set (allocator, pool);
2011
received_opts = apr_array_make (pool, SVN_OPT_MAX_OPTIONS, sizeof (int));
1883
apr_allocator_max_free_set(allocator, SVN_ALLOCATOR_RECOMMENDED_MAX_FREE);
1885
pool = svn_pool_create_ex(NULL, allocator);
1886
apr_allocator_owner_set(allocator, pool);
1888
received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));
2013
1890
/* Check library versions */
2014
err = check_lib_versions ();
1891
err = check_lib_versions();
2016
return svn_cmdline_handle_exit_error (err, pool, "svnlook: ");
1893
return svn_cmdline_handle_exit_error(err, pool, "svnlook: ");
2018
1895
/* Initialize the FS library. */
2019
err = svn_fs_initialize (pool);
1896
err = svn_fs_initialize(pool);
2021
return svn_cmdline_handle_exit_error (err, pool, "svnlook: ");
1898
return svn_cmdline_handle_exit_error(err, pool, "svnlook: ");
2025
subcommand_help (NULL, NULL, pool);
2026
svn_pool_destroy (pool);
1902
subcommand_help(NULL, NULL, pool);
1903
svn_pool_destroy(pool);
2027
1904
return EXIT_FAILURE;
2030
1907
/* Initialize opt_state. */
2031
memset (&opt_state, 0, sizeof (opt_state));
1908
memset(&opt_state, 0, sizeof(opt_state));
2032
1909
opt_state.rev = SVN_INVALID_REVNUM;
2034
1911
/* Parse options. */
2035
apr_getopt_init (&os, pool, argc, argv);
1912
err = svn_cmdline__getopt_init(&os, argc, argv, pool);
1914
return svn_cmdline_handle_exit_error(err, pool, "svnlook: ");
2036
1916
os->interleave = 1;
2039
1919
const char *opt_arg;
2041
1921
/* Parse the next option. */
2042
apr_err = apr_getopt_long (os, options_table, &opt_id, &opt_arg);
2043
if (APR_STATUS_IS_EOF (apr_err))
1922
apr_err = apr_getopt_long(os, options_table, &opt_id, &opt_arg);
1923
if (APR_STATUS_IS_EOF(apr_err))
2045
1925
else if (apr_err)
2047
subcommand_help (NULL, NULL, pool);
2048
svn_pool_destroy (pool);
1927
subcommand_help(NULL, NULL, pool);
1928
svn_pool_destroy(pool);
2049
1929
return EXIT_FAILURE;
2052
1932
/* Stash the option code in an array before parsing it. */
2053
APR_ARRAY_PUSH (received_opts, int) = opt_id;
1933
APR_ARRAY_PUSH(received_opts, int) = opt_id;
2055
1935
switch (opt_id)
2059
1939
char *digits_end = NULL;
2060
opt_state.rev = strtol (opt_arg, &digits_end, 10);
2061
if ((! SVN_IS_VALID_REVNUM (opt_state.rev))
1940
opt_state.rev = strtol(opt_arg, &digits_end, 10);
1941
if ((! SVN_IS_VALID_REVNUM(opt_state.rev))
2062
1942
|| (! digits_end)
2063
1943
|| *digits_end)
2064
SVN_INT_ERR (svn_error_create
2065
(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
2066
_("Invalid revision number supplied")));
1944
SVN_INT_ERR(svn_error_create
1945
(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
1946
_("Invalid revision number supplied")));