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