00001
00002
00003
00004
00005
00006
00007
00008
00009
00022 #include <sys/types.h>
00023 #include <limits.h>
00024 #include <unistd.h>
00025 #include <gdbm.h>
00026 #include <fcntl.h>
00027 #include <subversion-1/svn_props.h>
00028
00029 #include "global.h"
00030 #include "waa.h"
00031 #include "url.h"
00032 #include "helper.h"
00033 #include "actions.h"
00034 #include "hash_ops.h"
00035 #include "props.h"
00036 #include "update.h"
00037 #include "ignore.h"
00038 #include "est_ops.h"
00039 #include "add_unvers.h"
00040 #include "warnings.h"
00041
00042
00072
00135 #define FSVS_PROP_PREFIX "fsvs:"
00136
00195 #define FSVS_PROP_COMMIT_PIPE FSVS_PROP_PREFIX "commit-pipe"
00196
00212 #define FSVS_PROP_UPDATE_PIPE FSVS_PROP_PREFIX "update-pipe"
00213
00253 #define FSVS_PROP_INSTALL_CMD FSVS_PROP_PREFIX "install"
00254
00255
00264 #define FSVS_PROP_ORIG_MD5 FSVS_PROP_PREFIX "original-md5"
00265
00274 #ifndef SVN_PROP_TEXT_TIME
00275 #define SVN_PROP_TEXT_TIME SVN_PROP_PREFIX "text-time"
00276 #endif
00277 #ifndef SVN_PROP_OWNER
00278 #define SVN_PROP_OWNER SVN_PROP_PREFIX "owner"
00279 #endif
00280 #ifndef SVN_PROP_GROUP
00281 #define SVN_PROP_GROUP SVN_PROP_PREFIX "group"
00282 #endif
00283 #ifndef SVN_PROP_UNIX_MODE
00284 #define SVN_PROP_UNIX_MODE SVN_PROP_PREFIX "unix-mode"
00285 #endif
00286
00305 char propname_mtime[]=SVN_PROP_TEXT_TIME,
00307 propname_owner[]=SVN_PROP_OWNER,
00309 propname_group[]=SVN_PROP_GROUP,
00311 propname_origmd5[]=FSVS_PROP_ORIG_MD5,
00313 propname_umode[]=SVN_PROP_UNIX_MODE,
00316 propname_special[]=SVN_PROP_SPECIAL,
00318 propval_special []=SVN_PROP_SPECIAL_VALUE,
00319
00323 propval_commitpipe[]=FSVS_PROP_COMMIT_PIPE,
00328 propval_updatepipe[]=FSVS_PROP_UPDATE_PIPE,
00330 propval_orig_md5 []=FSVS_PROP_ORIG_MD5;
00340 const char prp___to_be_removed_value[]=
00341 "FSVS:INTERNAL-\nto-be-removed\n-"
00342 "\x8f\xc1\xa6\xe5\x86\x0a\x01\x72\x54\x89\x25\x23\x03\xc3\xfa\x75";
00343
00344
00345
00351 int prp__open_byname(char *wcfile, int gdbm_mode, hash_t *db)
00352 {
00353 int status;
00354
00355 status=hsh__new(wcfile, WAA__PROP_EXT, gdbm_mode, db);
00356 if (status != ENOENT)
00357 STOPIF(status, "Opening property file for %s", wcfile);
00358
00359 ex:
00360 return status;
00361 }
00362
00363
00367 int prp__open_byestat(struct estat *sts, int gdbm_mode, hash_t *db)
00368 {
00369 int status;
00370 char *fn;
00371
00372 STOPIF( ops__build_path(&fn, sts), NULL);
00373 status=prp__open_byname(fn, gdbm_mode, db);
00374 if (status != ENOENT) STOPIF(status, NULL);
00375
00376 ex:
00377 return status;
00378 }
00379
00380
00384 int prp__set(hash_t db,
00385 const char *name,
00386 const char *data, int datalen)
00387 {
00388 int status;
00389 datum key, value;
00390
00391 key.dptr=(char*)name;
00392 key.dsize=strlen(name)+1;
00393
00394 if (data)
00395 {
00396 value.dptr=(char*)data;
00397 value.dsize=datalen;
00398
00399 if (datalen == -1)
00400 value.dsize= *data ? strlen(data)+1 : 0;
00401 #ifdef ENABLE_DEBUG
00402 else
00403 BUG_ON(value.dptr[value.dsize-1] != 0, "Not terminated!");
00404 #endif
00405 }
00406 else
00407 {
00408 value.dptr=NULL;
00409 value.dsize=0;
00410 }
00411
00412 STOPIF( prp__store(db, key, value), NULL);
00413
00414 ex:
00415 return status;
00416 }
00417
00418
00423 int prp__set_svnstr(hash_t db,
00424 const char *name,
00425 const svn_string_t *utf8_value)
00426 {
00427 return prp__set(db, name, utf8_value->data, utf8_value->len+1);
00428 }
00429
00430
00433 int prp__store(hash_t db, datum key, datum value)
00434 {
00435 int status;
00436
00437 DEBUGP("storing property %s=%s", key.dptr, value.dptr);
00438 STOPIF( hsh__store(db, key, value), NULL);
00439 ex:
00440 return status;
00441 }
00442
00443
00446 int prp__get(hash_t db, char *keycp, datum *value)
00447 {
00448 static datum key;
00449
00450 key.dptr=keycp;
00451 key.dsize=strlen(keycp)+1;
00452 return prp__fetch(db, key, value);
00453 }
00454
00455
00462 int prp__set_from_aprhash(struct estat *sts,
00463 apr_hash_t *props,
00464 enum prp__set_from_aprhash_e flags,
00465 hash_t *props_db,
00466 apr_pool_t *pool)
00467 {
00468 int status;
00469 apr_hash_index_t *hi;
00470 char *prop_key;
00471 apr_ssize_t prop_key_len;
00472
00473 svn_string_t *prop_val;
00474 hash_t db;
00475 int to_store, count;
00476 void *k, *v;
00477
00478
00479 status=0;
00480 count=0;
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498 db=NULL;
00499 hi=apr_hash_first(pool, props);
00500
00501 if (flags & STORE_IN_FS)
00502 {
00503
00504
00505
00506 if (!hi && !props_db)
00507 {
00508 STOPIF( prp__unlink_db_for_estat(sts), NULL);
00509 goto ex;
00510 }
00511
00512 STOPIF( prp__open_byestat(sts,
00513 GDBM_NEWDB | HASH_REMEMBER_FILENAME, &db), NULL);
00514 }
00515
00516 for (; hi; hi = apr_hash_next(hi))
00517 {
00518
00519
00520
00521
00522 k=&prop_key;
00523 v=&prop_val;
00524 apr_hash_this(hi, k, &prop_key_len, v);
00525
00526 to_store=0;
00527 STOPIF( up__parse_prop(sts, prop_key, prop_val,
00528 &to_store, pool), NULL);
00529
00530 if (to_store)
00531 {
00532 if (db)
00533 {
00537 STOPIF( prp__set_svnstr(db, prop_key, prop_val), NULL);
00538 }
00539 count++;
00540 }
00541 else
00542 {
00543
00544 if (flags & ONLY_KEEP_USERDEF)
00545 apr_hash_set(props, prop_key, prop_key_len, NULL);
00546 }
00547 }
00548
00549 DEBUGP("%d properties stored", count);
00550 if (props_db)
00551 *props_db=db;
00552 else
00553 STOPIF( hsh__close(db, status), NULL);
00554
00555 ex:
00556 return status;
00557 }
00558
00559
00562 int prp__g_work(struct estat *root, int argc, char *argv[])
00563 {
00564 int status, st2;
00565 datum key, value;
00566 hash_t db;
00567 FILE *output;
00568 char **normalized;
00569
00570
00571 status=0;
00572 output=stdout;
00573 if (argc<2) ac__Usage_this();
00574
00575
00576 key.dptr=*(argv++);
00577 key.dsize=strlen(key.dptr)+1;
00578 argc--;
00579
00580
00581 STOPIF( waa__find_common_base(argc, argv, &normalized), NULL);
00582
00583
00584 for(; *argv; argv++)
00585 {
00586 db=NULL;
00587 status=prp__open_byname( *normalized, GDBM_READER, &db);
00588 if (!status)
00589 status=prp__fetch(db, key, &value);
00590
00591 if (status == ENOENT)
00592 {
00593 DEBUGP("No such property");
00594 }
00595 else if (status)
00596 {
00597
00598 STOPIF( status, NULL);
00599 }
00600 else if (value.dptr && !prp__prop_will_be_removed(value))
00601 {
00602 STOPIF_CODE_EPIPE( fputs(value.dptr, output), NULL);
00603 STOPIF_CODE_EPIPE( fputc('\n', output), NULL);
00604 }
00605
00606 if (db)
00607 STOPIF( hsh__close(db, status), NULL);
00608 db=NULL;
00609 }
00610
00611 status=0;
00612
00613 ex:
00614 if (db)
00615 {
00616 st2=hsh__close(db, status);
00617 db=NULL;
00618 if (!status && st2)
00619 STOPIF( st2, NULL);
00620 }
00621 return status;
00622 }
00623
00624
00629 int prp__s_work(struct estat *root, int argc, char *argv[])
00630 {
00631 int status, st2;
00632 datum key, value, rv;
00633 hash_t db;
00634 char **normalized;
00635 struct estat *sts;
00636 int change;
00637
00638
00639 status=0;
00640 if (argc<2) ac__Usage_this();
00641
00642
00643 if (svn_prop_is_svn_prop(*argv))
00644 STOPIF( wa__warn( WRN__PROP_NAME_RESERVED, EINVAL,
00645 "This is a reserved property name and should not be used." ),
00646 NULL );
00647
00648
00649 key.dptr=*(argv++);
00650 key.dsize=strlen(key.dptr)+1;
00651 argc--;
00652
00653 if (action->i_val == FS_REMOVED)
00654 {
00655 value.dptr=(char*)prp___to_be_removed_value;
00656
00657 value.dsize=strlen(prp___to_be_removed_value)+1;
00658 }
00659 else
00660 {
00661 value.dptr=*(argv++);
00662 value.dsize=strlen(value.dptr)+1;
00663 argc--;
00664 if (argc<1) ac__Usage_this();
00665 }
00666
00667
00668 STOPIF( waa__find_common_base(argc, argv, &normalized), NULL);
00669
00670 STOPIF( au__prepare_for_added(), NULL);
00671
00672 STOPIF( waa__input_tree(root, NULL, NULL), NULL);
00673
00674
00675 for(; *normalized; normalized++)
00676 {
00677 STOPIF( ops__traverse(root, *normalized,
00678 OPS__CREATE | OPS__FAIL_NOT_LIST, RF_ADD, &sts), NULL);
00679
00680 if (sts->flags & RF_ISNEW)
00681 {
00682
00683 STOPIF( ign__is_ignore(sts, &change), NULL);
00684 STOPIF( ops__apply_group(sts, &db, NULL), NULL);
00685
00686 if (!sts->url)
00687 sts->url=current_url;
00688
00689 STOPIF( hlp__lstat( *normalized, & sts->st),
00690 "!'%s' can not be queried", *normalized);
00691
00692
00693 sts->flags |= RF_ADD;
00694 }
00695 else
00696 STOPIF( prp__open_byestat(sts, GDBM_WRCREAT, &db), NULL);
00697
00698
00699
00700 change=0;
00701 status=prp__fetch(db, key, &rv);
00702 if (action->i_val == FS_REMOVED)
00703 {
00704 if (status == ENOENT)
00705 DEBUGP("%s on %s didnt exist anyway", key.dptr, *normalized);
00706 else
00707 change++;
00708 }
00709 else
00710 {
00711 if (status == ENOENT)
00712 change++;
00713 else
00714 {
00715 change = (rv.dsize != value.dsize) ||
00716 memcmp(rv.dptr, value.dptr, value.dsize) != 0;
00717 DEBUGP("%s on %s change? %d", key.dptr, *normalized, change);
00718 }
00719 }
00720
00721 if (change)
00722 {
00723 STOPIF( prp__store(db, key, value), NULL);
00724 sts->flags |= RF_PUSHPROPS;
00725 }
00726
00727 STOPIF( hsh__close(db, status), NULL);
00728 db=NULL;
00729 }
00730
00731 STOPIF( waa__output_tree(root), NULL);
00732
00733 ex:
00734 if (db)
00735 {
00736 st2=hsh__close(db, status);
00737 db=NULL;
00738 if (!status && st2)
00739 STOPIF( st2, NULL);
00740 }
00741 return status;
00742 }
00743
00744
00750 int prp__open_get_close(struct estat *sts, char *name,
00751 char **data, int *len)
00752 {
00753 int status;
00754 hash_t props;
00755 datum value;
00756
00757 props=NULL;
00758
00759 status=prp__open_byestat(sts, GDBM_READER, &props);
00760 if (status == ENOENT) goto ex;
00761 STOPIF(status, NULL);
00762
00763 status=prp__get(props, name, &value);
00764 if (status == ENOENT) goto ex;
00765 STOPIF(status, NULL);
00766
00767 if (len) *len=value.dsize;
00768 if (data) *data=value.dptr;
00769 else IF_FREE(value.dptr);
00770
00771 ex:
00772 if (props)
00773 hsh__close(props, status);
00774 return status;
00775 }
00776
00777
00780 int prp__l_work(struct estat *root, int argc, char *argv[])
00781 {
00782 int status, count;
00783 int many_files;
00784 char indent[5]=" ";
00785 hash_t db;
00786 FILE *output;
00787 datum key, data;
00788 char **normalized;
00789
00790
00791 status=0;
00792 db=NULL;
00793 if (!argc) ac__Usage_this();
00794
00795
00796 STOPIF( waa__find_common_base(argc, argv, &normalized), NULL);
00797
00798
00799 output=stdout;
00800 many_files= argc>1;
00801 if (!many_files) *indent=0;
00802
00803 for(; *normalized; normalized++)
00804 {
00805 status=prp__open_byname( *normalized, GDBM_READER, &db);
00806 if (status == ENOENT) goto noprops;
00807
00808 if (status)
00809 STOPIF(status, "Cannot open properties file for '%s'",
00810 *normalized);
00811
00812
00813 count=0;
00814 status=prp__first(db, &key);
00815 while (status == 0)
00816 {
00817 DEBUGP("got key with len=%d: %.30s", key.dsize, key.dptr);
00818
00819 STOPIF( prp__fetch(db, key, &data), NULL);
00820 if (prp__prop_will_be_removed(data))
00821 {
00822
00823 }
00824 else
00825 {
00826 count++;
00827
00828 if (count==1 && many_files)
00829 STOPIF_CODE_EPIPE( printf("Properties of %s:\n", *normalized), NULL);
00830
00831 STOPIF_CODE_EPIPE( fputs(indent, output), NULL);
00832
00833
00834 STOPIF( hlp__safe_print(output, key.dptr, key.dsize-1), NULL);
00835
00836 if (opt__is_verbose() > 0)
00837 {
00838 STOPIF_CODE_EPIPE( fputc('=',output), NULL);
00839 STOPIF( hlp__safe_print(output, data.dptr, data.dsize-1), NULL);
00840
00841 free(data.dptr);
00842 }
00843
00844 STOPIF_CODE_EPIPE( fputc('\n', output), NULL);
00845 }
00846
00847 status=prp__next(db, &key, &key);
00848 }
00849
00850 if (count == 0)
00851 {
00852 noprops:
00853 printf("%s has no properties.\n", *normalized);
00854 status=0;
00855 continue;
00856 }
00857
00858
00859 STOPIF( hsh__close(db, status), NULL);
00860 db=NULL;
00861 }
00862
00863 ex:
00864 hsh__close(db, status);
00865 return status;
00866 }
00867
00868
00870 int prp__unlink_db_for_estat(struct estat *sts)
00871 {
00872 int status;
00873 char *cp, *eos, *path;
00874
00875 STOPIF( ops__build_path(&path, sts), NULL);
00876
00877 STOPIF( waa__get_waa_directory(path, &cp, &eos, NULL,
00878 waa__get_gwd_flag(WAA__PROP_EXT)), NULL);
00879 strcpy(eos, WAA__PROP_EXT);
00880
00881 status= unlink(cp) == -1 ? errno : 0;
00882 if (status == ENOENT)
00883 status=0;
00884 else STOPIF(status, "deleting properties of %s (%s)", path, cp);
00885
00886 ex:
00887 return status;
00888 }