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 }