47
48
code. See also adm_files.c:check_adm_exists(), which should
48
49
probably be merged with this. */
50
svn_wc_check_wc (const char *path,
51
svn_wc_check_wc(const char *path,
54
55
svn_error_t *err = SVN_NO_ERROR;
57
SVN_ERR (svn_io_check_path (path, &kind, pool));
59
if (kind == svn_node_none)
61
return svn_error_createf
62
(APR_ENOENT, NULL, _("'%s' does not exist"),
63
svn_path_local_style (path, pool));
57
const char *format_file_path
58
= svn_wc__adm_path(path, FALSE, pool, SVN_WC__ADM_ENTRIES, NULL);
60
/* First try to read the format number from the entries file. */
61
err = svn_io_read_version_file(wc_format, format_file_path, pool);
63
/* If that didn't work and the first line of the entries file contains
64
something other than a number, then it is probably in XML format. */
65
if (err && err->apr_err == SVN_ERR_BAD_VERSION_FILE_FORMAT)
68
/* Fall back on reading the format file instead.
69
Note that the format file might not exist in newer working copies
70
(format 7 and higher), but in that case, the entries file should
71
have contained the format number. */
73
= svn_wc__adm_path(path, FALSE, pool, SVN_WC__ADM_FORMAT, NULL);
75
err = svn_io_read_version_file(wc_format, format_file_path, pool);
78
if (err && (APR_STATUS_IS_ENOENT(err->apr_err)
79
|| APR_STATUS_IS_ENOTDIR(err->apr_err)))
85
/* Check path itself exists. */
86
SVN_ERR(svn_io_check_path(path, &kind, pool));
88
if (kind == svn_node_none)
90
return svn_error_createf
91
(APR_ENOENT, NULL, _("'%s' does not exist"),
92
svn_path_local_style(path, pool));
95
/* If the format file does not exist or path not directory, then for
96
our purposes this is not a working copy, so return 0. */
65
else if (kind != svn_node_dir)
67
else /* okay, it's a directory, but is it a working copy? */
69
const char *format_file_path
70
= svn_wc__adm_path (path, FALSE, pool, SVN_WC__ADM_FORMAT, NULL);
72
err = svn_io_read_version_file (wc_format, format_file_path, pool);
74
if (err && (APR_STATUS_IS_ENOENT(err->apr_err)
75
|| APR_STATUS_IS_ENOTDIR(err->apr_err)))
77
/* If the format file does not exist, then for our purposes
78
this is not a working copy, so return 0. */
79
svn_error_clear (err);
86
/* If we managed to read the format file we assume that we
87
are dealing with a real wc so we can return a nice
89
SVN_ERR (svn_wc__check_format (*wc_format, path, pool));
103
/* If we managed to read the format file we assume that we
104
are dealing with a real wc so we can return a nice
106
SVN_ERR(svn_wc__check_format(*wc_format, path, pool));
93
109
return SVN_NO_ERROR;
225
svn_wc__versioned_file_modcheck (svn_boolean_t *modified_p,
226
const char *versioned_file,
227
svn_wc_adm_access_t *adm_access,
228
const char *base_file,
232
const char *tmp_vfile;
233
svn_error_t *err = SVN_NO_ERROR, *err2 = SVN_NO_ERROR;
235
SVN_ERR (svn_wc_translated_file (&tmp_vfile, versioned_file, adm_access,
238
err = svn_io_files_contents_same_p (&same, tmp_vfile, base_file, pool);
239
*modified_p = (! same);
241
if (tmp_vfile != versioned_file)
242
err2 = svn_io_remove_file (tmp_vfile, pool);
247
svn_error_compose (err, err2);
255
/* Set *MODIFIED_P to true if (after translation) VERSIONED_FILE
256
* differs from BASE_FILE, else to false if not. Also, verify that
257
* BASE_FILE matches the entry checksum for VERSIONED_FILE; if it
258
* does not match, return the error SVN_ERR_WC_CORRUPT_TEXT_BASE.
233
/* Set *MODIFIED_P to TRUE if (after translation) VERSIONED_FILE
234
* differs from BASE_FILE, else to FALSE if not. Also verify that
235
* BASE_FILE matches the entry checksum for VERSIONED_FILE, if
236
* verify_checksum is TRUE. If checksum does not match, return the error
237
* SVN_ERR_WC_CORRUPT_TEXT_BASE.
260
239
* ADM_ACCESS is an access baton for VERSIONED_FILE. Use POOL for
261
240
* temporary allocation.
263
242
static svn_error_t *
264
compare_and_verify (svn_boolean_t *modified_p,
265
const char *versioned_file,
266
svn_wc_adm_access_t *adm_access,
267
const char *base_file,
243
compare_and_verify(svn_boolean_t *modified_p,
244
const char *versioned_file,
245
svn_wc_adm_access_t *adm_access,
246
const char *base_file,
247
svn_boolean_t compare_textbases,
248
svn_boolean_t verify_checksum,
271
const char *tmp_vfile;
272
svn_error_t *err = SVN_NO_ERROR, *err2 = SVN_NO_ERROR;
273
const svn_wc_entry_t *entry;
275
SVN_ERR (svn_wc_entry (&entry, versioned_file, adm_access, TRUE, pool));
278
SVN_ERR (svn_wc_translated_file (&tmp_vfile, versioned_file, adm_access,
281
/* Compare the files, while maybe calculating the base file's checksum. */
283
/* "v_" means versioned_file, "b_" means base_file. */
284
svn_error_t *v_err = SVN_NO_ERROR;
285
svn_error_t *b_err = SVN_NO_ERROR;
286
apr_size_t v_file_bytes_read, b_file_bytes_read;
287
char v_buf[BUFSIZ], b_buf[BUFSIZ];
288
apr_file_t *v_file_h = NULL;
289
apr_file_t *b_file_h = NULL;
290
apr_pool_t *loop_pool;
292
int identical = TRUE;
293
unsigned char digest[APR_MD5_DIGESTSIZE];
294
apr_md5_ctx_t context;
296
SVN_ERR (svn_io_file_open (&v_file_h, tmp_vfile,
297
APR_READ, APR_OS_DEFAULT, pool));
298
SVN_ERR (svn_io_file_open (&b_file_h, base_file, APR_READ, APR_OS_DEFAULT,
252
svn_subst_eol_style_t eol_style;
254
apr_hash_t *keywords;
255
svn_boolean_t special;
256
svn_boolean_t need_translation;
259
SVN_ERR(svn_wc__get_eol_style(&eol_style, &eol_str, versioned_file,
261
SVN_ERR(svn_wc__get_keywords(&keywords, versioned_file,
262
adm_access, NULL, pool));
263
SVN_ERR(svn_wc__get_special(&special, versioned_file, adm_access, pool));
266
need_translation = svn_subst_translation_required(eol_style, eol_str,
267
keywords, special, TRUE);
268
if (verify_checksum || need_translation)
270
/* Reading files is necessary. */
271
const unsigned char *digest;
272
/* "v_" means versioned_file, "b_" means base_file. */
273
apr_file_t *v_file_h, *b_file_h;
274
svn_stream_t *v_stream, *b_stream;
275
const svn_wc_entry_t *entry;
277
SVN_ERR(svn_io_file_open(&b_file_h, base_file, APR_READ,
278
APR_OS_DEFAULT, pool));
280
b_stream = svn_stream_from_aprfile2(b_file_h, FALSE, pool);
284
/* Need checksum verification, so read checksum from entries file
285
* and setup checksummed stream for base file. */
286
SVN_ERR(svn_wc_entry(&entry, versioned_file, adm_access, TRUE,
301
apr_md5_init (&context);
303
loop_pool = svn_pool_create (pool);
306
svn_pool_clear (loop_pool);
308
/* The only way v_err can be true here is if we hit EOF. */
311
v_err = svn_io_file_read_full (v_file_h, v_buf, sizeof(v_buf),
312
&v_file_bytes_read, loop_pool);
313
if (v_err && !APR_STATUS_IS_EOF(v_err->apr_err))
317
b_err = svn_io_file_read_full (b_file_h, b_buf, sizeof(b_buf),
318
&b_file_bytes_read, loop_pool);
319
if (b_err && !APR_STATUS_IS_EOF(b_err->apr_err))
323
apr_md5_update (&context, b_buf, b_file_bytes_read);
325
if ((v_err && (! b_err))
326
|| (v_file_bytes_read != b_file_bytes_read)
327
|| (memcmp (v_buf, b_buf, v_file_bytes_read)))
333
svn_pool_destroy (loop_pool);
335
/* Clear any errors, but don't set the error variables to null, as
336
we still depend on them for conditionals. */
337
svn_error_clear (v_err);
338
svn_error_clear (b_err);
340
SVN_ERR (svn_io_file_close (v_file_h, pool));
341
SVN_ERR (svn_io_file_close (b_file_h, pool));
345
const char *checksum;
346
apr_md5_final (digest, &context);
347
checksum = svn_md5_digest_to_cstring_display (digest, pool);
348
if (strcmp (checksum, entry->checksum) != 0)
350
289
return svn_error_createf
351
(SVN_ERR_WC_CORRUPT_TEXT_BASE, NULL,
352
_("Checksum mismatch indicates corrupt text base: '%s'\n"
355
svn_path_local_style (base_file, pool),
361
*modified_p = ! identical;
364
if (tmp_vfile != versioned_file)
365
err2 = svn_io_remove_file (tmp_vfile, pool);
290
(SVN_ERR_UNVERSIONED_RESOURCE, NULL,
291
_("'%s' is not under version control"),
292
svn_path_local_style(versioned_file, pool));
295
b_stream = svn_stream_checksummed(b_stream, &digest, NULL, TRUE,
299
if (compare_textbases && need_translation)
301
/* Create stream for detranslate versioned file to normal form. */
302
SVN_ERR(svn_subst_stream_detranslated(&v_stream,
311
SVN_ERR(svn_io_file_open(&v_file_h, versioned_file, APR_READ,
312
APR_OS_DEFAULT, pool));
313
v_stream = svn_stream_from_aprfile2(v_file_h, FALSE, pool);
315
if (need_translation)
317
/* Translate text-base to working copy form. */
318
b_stream = svn_subst_stream_translated(b_stream, eol_str,
319
FALSE, keywords, TRUE,
324
SVN_ERR(svn_stream_contents_same(&same, b_stream, v_stream, pool));
326
SVN_ERR(svn_stream_close(v_stream));
327
SVN_ERR(svn_stream_close(b_stream));
329
if (verify_checksum && entry->checksum)
331
const char *checksum;
332
checksum = svn_md5_digest_to_cstring_display(digest, pool);
333
if (strcmp(checksum, entry->checksum) != 0)
335
return svn_error_createf
336
(SVN_ERR_WC_CORRUPT_TEXT_BASE, NULL,
337
_("Checksum mismatch indicates corrupt text base: '%s'\n"
340
svn_path_local_style(base_file, pool),
370
svn_error_compose (err, err2);
348
/* Translation would be a no-op, so compare the original file. */
349
SVN_ERR(svn_io_files_contents_same_p(&same, base_file, versioned_file,
379
svn_wc_text_modified_p (svn_boolean_t *modified_p,
380
const char *filename,
381
svn_boolean_t force_comparison,
382
svn_wc_adm_access_t *adm_access,
355
*modified_p = (! same);
360
svn_wc__versioned_file_modcheck(svn_boolean_t *modified_p,
361
const char *versioned_file,
362
svn_wc_adm_access_t *adm_access,
363
const char *base_file,
364
svn_boolean_t compare_textbases,
367
return compare_and_verify(modified_p, versioned_file, adm_access,
368
base_file, compare_textbases, FALSE, pool);
372
svn_wc__text_modified_internal_p(svn_boolean_t *modified_p,
373
const char *filename,
374
svn_boolean_t force_comparison,
375
svn_wc_adm_access_t *adm_access,
376
svn_boolean_t compare_textbases,
385
379
const char *textbase_filename;
386
380
svn_boolean_t equal_timestamps;
387
apr_pool_t *subpool = svn_pool_create (pool);
381
apr_pool_t *subpool = svn_pool_create(pool);
388
382
svn_node_kind_t kind;
389
383
svn_error_t *err;
428
422
/* If there's no text-base file, we have to assume the working file
429
423
is modified. For example, a file scheduled for addition but not
430
424
yet committed. */
431
textbase_filename = svn_wc__text_base_path (filename, 0, subpool);
432
SVN_ERR (svn_io_check_path (textbase_filename, &kind, subpool));
425
textbase_filename = svn_wc__text_base_path(filename, 0, subpool);
426
SVN_ERR(svn_io_check_path(textbase_filename, &kind, subpool));
433
427
if (kind != svn_node_file)
435
429
*modified_p = TRUE;
440
if (force_comparison) /* Check all bytes, and verify checksum. */
442
SVN_ERR (compare_and_verify (modified_p,
448
else /* Else, fall back on the standard mod detector. */
450
SVN_ERR (svn_wc__versioned_file_modcheck (modified_p,
434
/* Check all bytes, and verify checksum if requested. */
435
SVN_ERR(compare_and_verify(modified_p,
457
443
/* It is quite legitimate for modifications to the working copy to
458
444
produce a timestamp variation with no text variation. If it turns out
459
445
that there are no differences then we might be able to "repair" the
460
446
text-time in the entries file and so avoid the expensive file contents
461
447
comparison in the future. */
462
if (! *modified_p && svn_wc_adm_locked (adm_access))
448
if (! *modified_p && svn_wc_adm_locked(adm_access))
464
450
svn_wc_entry_t tmp;
465
SVN_ERR (svn_io_file_affected_time (&tmp.text_time, filename, pool));
466
SVN_ERR (svn_wc__entry_modify (adm_access,
467
svn_path_basename (filename, pool),
468
&tmp, SVN_WC__ENTRY_MODIFY_TEXT_TIME, TRUE,
451
SVN_ERR(svn_io_file_affected_time(&tmp.text_time, filename, pool));
452
SVN_ERR(svn_wc__entry_modify(adm_access,
453
svn_path_basename(filename, pool),
454
&tmp, SVN_WC__ENTRY_MODIFY_TEXT_TIME, TRUE,
473
svn_pool_destroy (subpool);
459
svn_pool_destroy(subpool);
475
461
return SVN_NO_ERROR;
466
svn_wc_text_modified_p(svn_boolean_t *modified_p,
467
const char *filename,
468
svn_boolean_t force_comparison,
469
svn_wc_adm_access_t *adm_access,
472
return svn_wc__text_modified_internal_p(modified_p, filename,
473
force_comparison, adm_access,
482
svn_wc_conflicted_p (svn_boolean_t *text_conflicted_p,
483
svn_boolean_t *prop_conflicted_p,
484
const char *dir_path,
485
const svn_wc_entry_t *entry,
480
svn_wc_conflicted_p(svn_boolean_t *text_conflicted_p,
481
svn_boolean_t *prop_conflicted_p,
482
const char *dir_path,
483
const svn_wc_entry_t *entry,
488
486
const char *path;
489
487
svn_node_kind_t kind;
490
apr_pool_t *subpool = svn_pool_create (pool); /* ### Why? */
488
apr_pool_t *subpool = svn_pool_create(pool); /* ### Why? */
492
490
*text_conflicted_p = FALSE;
493
491
*prop_conflicted_p = FALSE;