00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <stdio.h>
00010 #include <unistd.h>
00011 #include <time.h>
00012
00013 #include "global.h"
00014 #include "actions.h"
00015 #include "status.h"
00016 #include "helper.h"
00017 #include "direnum.h"
00018 #include "cache.h"
00019 #include "url.h"
00020 #include "cp_mv.h"
00021 #include "ignore.h"
00022 #include "options.h"
00023 #include "est_ops.h"
00024 #include "waa.h"
00025 #include "checksum.h"
00026 #include "url.h"
00027
00028
00105 static FILE *progress_output=NULL;
00106 static int max_progress_len=0;
00107
00108
00112 char * st___visible_file_size(struct estat *sts)
00113 {
00114 static char buffer[20];
00115
00116 switch ( (sts->st.mode ? sts->st.mode : sts->st.mode) & S_IFMT)
00117 {
00118 case S_IFBLK:
00119 case S_IFCHR:
00120 return "dev";
00121 case S_IFDIR:
00122 return "dir";
00123 default:
00124
00125
00126 case S_IFREG:
00127 case S_IFLNK:
00128 sprintf(buffer, "%llu", (t_ull) sts->st.size);
00129 break;
00130 }
00131
00132 return buffer;
00133 }
00134
00135
00137 inline char * st___meta_string(int status_bits, int flags)
00138 {
00139 static char buffer[4];
00140 int prop;
00141
00142 prop=(status_bits & FS_PROPERTIES) | (flags & RF_PUSHPROPS);
00143
00144 if (opt__is_verbose() > 0)
00145 {
00146 buffer[0] = status_bits & FS_META_MTIME ? 't' : '.';
00147 buffer[1] = status_bits &
00148 (FS_META_OWNER | FS_META_GROUP | FS_META_UMODE) ? 'p' : '.';
00149 buffer[2] = prop ? 'P' : '.';
00150 buffer[3] = 0;
00151 }
00152 else
00153 {
00154 buffer[0] = status_bits & FS_META_CHANGED ? 'm' :
00155 prop ? 'P' : '.';
00156 buffer[1]=0;
00157 }
00158
00159 return buffer;
00160 }
00161
00162
00164 char *st___color(int status_bits)
00165 {
00166 if ((status_bits & FS_REPLACED) == FS_REMOVED)
00167 return ANSI__RED;
00168 if (status_bits & FS_NEW)
00169 return ANSI__GREEN;
00170 if (status_bits & FS_CHANGED)
00171 return ANSI__BLUE;
00172 return "";
00173 }
00174
00175
00178 int st__print_status(char *path, int status_bits, int flags, char* size,
00179 struct estat *sts)
00180 {
00181 int status;
00182 char *copyfrom, *url;
00183 int copy_inherited;
00184 FILE* output=stdout;
00185
00186
00187 DEBUGP("VERBOSITY=%d", opt__get_int(OPT__VERBOSE));
00188 status=0;
00189
00190 if (opt__verbosity() <= VERBOSITY_QUIET) goto ex;
00191
00192
00193
00194
00195
00196 if ((status_bits & (FS_NEW | FS_REMOVED)) ||
00197 (flags & (RF_ADD | RF_UNVERSION)))
00198 status_bits &= ~(FS_META_CHANGED | FS_LIKELY | FS_CHANGED);
00199
00200
00201
00202
00203 if (opt__is_verbose() > 0 ||
00204 (status_bits & FS__CHANGE_MASK) ||
00205 (flags & ~RF_CHECK))
00206 {
00207 copyfrom=NULL;
00208 copy_inherited=0;
00209
00210
00211
00212 if (opt__get_int(OPT__VERBOSE) & VERBOSITY_COPYFROM)
00213 {
00214 copy_inherited= (flags & RF_COPY_SUB);
00215
00216 if (flags & RF_COPY_BASE)
00217 {
00218 status=cm__get_source(sts, NULL, ©from, NULL, 0);
00219 BUG_ON(status == ENOENT, "Marked as copied, but no info?");
00220 STOPIF(status, NULL);
00221 }
00222 }
00223
00224
00225 if (opt__get_int(OPT__VERBOSE) & VERBOSITY_TOP_URL)
00226 STOPIF( url__full_url(sts, &url), NULL);
00227 else
00228 url=NULL;
00229
00230
00231
00232
00233 STOPIF( hlp__format_path(sts, path, &path), NULL);
00234
00235
00236
00237
00238
00239
00240 if (opt__get_int(OPT__STATUS_COLOR))
00241 STOPIF_CODE_EPIPE( fputs(st___color(status_bits), output), NULL);
00242
00243 if (opt__get_int(OPT__VERBOSE) & VERBOSITY_SHOWCHG)
00244 STOPIF_CODE_EPIPE( fprintf(output, "%c%s%c%c ",
00245 flags & RF_ADD ? 'n' :
00246 flags & RF_UNVERSION ? 'd' :
00247 (status_bits & FS_REPLACED) == FS_REPLACED ? 'R' :
00248 status_bits & FS_NEW ? 'N' :
00249 status_bits & FS_REMOVED ? 'D' : '.',
00250
00251 st___meta_string(status_bits, flags),
00252
00253 flags & RF_CONFLICT ? 'x' :
00254 status_bits & FS_CHANGED ? 'C' : '.',
00255
00256 flags & RF___IS_COPY ? '+' :
00257 status_bits & FS_LIKELY ? '?' :
00258
00259
00260 ( ( status_bits & FS_REMOVED ) &&
00261 ( flags & (RF_UNVERSION | RF_ADD) ) ) ? '!' : '.'
00262 ), NULL);
00263
00264
00265 if (opt__get_int(OPT__VERBOSE) & VERBOSITY_SHOWSIZE)
00266 STOPIF_CODE_EPIPE( fprintf(output, "%8s ", size), NULL);
00267
00268 if (opt__get_int(OPT__VERBOSE) & VERBOSITY_GROUP)
00269 STOPIF_CODE_EPIPE( fprintf(output, "%-*s",
00270 ign__max_group_name_len+2,
00271 sts->match_pattern ? sts->match_pattern->group_name :
00272 "(none)"), NULL);
00273
00274 if (opt__get_int(OPT__VERBOSE) & VERBOSITY_SHOWNAME)
00275 STOPIF_CODE_EPIPE( fputs(path, output), NULL);
00276
00277 if (opt__get_int(OPT__STATUS_COLOR))
00278 STOPIF_CODE_EPIPE( fputs(ANSI__NORMAL, output), NULL);
00279
00280
00281
00282 if (copyfrom || copy_inherited)
00283 STOPIF_CODE_EPIPE( fprintf(output,
00284 copy_inherited ? " (inherited)" : " (copied from %s)",
00285 copyfrom), NULL);
00286
00287 if (url)
00288 STOPIF_CODE_EPIPE( fprintf(output, " %s", url), NULL);
00289
00290
00291 STOPIF_CODE_EPIPE( fputs("\n", output), NULL);
00292 }
00293
00294
00295 ex:
00296 return status;
00297 }
00298
00299
00302 int st__status(struct estat *sts)
00303 {
00304 int status;
00305 int e_stat, flags;
00306 char *path;
00307 int would_be_ignored;
00308
00309
00310 status=0;
00311 STOPIF( ops__build_path(&path, sts), NULL);
00312
00313
00314 BUG_ON(sts->was_output, "%s was already output ...", path);
00315 sts->was_output=1;
00316
00317
00318 e_stat=sts->entry_status;
00319 flags=sts->flags;
00320
00321
00322
00323 if (flags & RF_ISNEW)
00324 {
00325 e_stat = ( e_stat & ~FS_REPLACED) | FS_NEW;
00326 flags &= ~RF_ADD;
00327 DEBUGP("Re-create the NEW status.");
00328
00329 if (opt__get_int(OPT__VERBOSE) & VERBOSITY_GROUP)
00330 STOPIF( ign__is_ignore(sts, &would_be_ignored), NULL);
00331 }
00332
00333 STOPIF( st__print_status(path,
00334 e_stat, flags,
00335 st___visible_file_size(sts),
00336 sts), NULL);
00337
00338 ex:
00339 return status;
00340 }
00341
00342
00345 int st__action(struct estat *sts)
00346 {
00347 int status;
00348
00349 if (opt__get_int(OPT__STOP_ON_CHANGE) &&
00350 sts->entry_status)
00351
00352 exit(1);
00353
00354 STOPIF( st__status(sts), NULL);
00355
00356 ex:
00357 return status;
00358 }
00359
00360
00363 int st__rm_status(struct estat *sts)
00364 {
00365 int status;
00366 char *path;
00367
00368
00369 status=0;
00370 STOPIF( ops__build_path(&path, sts), NULL);
00371
00372 STOPIF( st__print_status(path,
00373 sts->remote_status, 0,
00374 st___visible_file_size(sts),
00375 sts), NULL);
00376
00377 ex:
00378 return status;
00379 }
00380
00381
00384 int st__work(struct estat *root, int argc, char *argv[])
00385 {
00386 int status;
00387 char **normalized;
00388
00389
00390
00391
00392
00393
00394
00395 STOPIF( waa__find_common_base(argc, argv, &normalized), NULL);
00396
00397
00398 status=url__load_list(NULL, 0);
00399
00400 if (status != ENOENT) STOPIF(status, NULL);
00401
00402 STOPIF( ign__load_list(NULL), NULL);
00403
00404 if (opt__get_int(OPT__DIR_SORT) &&
00405 !opt__get_int(OPT__STOP_ON_CHANGE))
00406 {
00407 action->local_callback=st__progress;
00408 action->local_uninit=st__progress_uninit;
00409 }
00410
00411 STOPIF( waa__read_or_build_tree(root, argc, normalized, argv, NULL, 0),
00412 "No working copy data could be found.");
00413
00414
00415 if (opt__get_int(OPT__DIR_SORT))
00416 {
00417 action->local_callback=st__status;
00418 STOPIF( waa__do_sorted_tree(root, ac__dispatch), NULL);
00419 }
00420
00421 if (opt__get_int(OPT__GROUP_STATS))
00422 STOPIF( ign__print_group_stats(stdout), NULL);
00423
00424 ex:
00425 return status;
00426 }
00427
00428
00438 int st__progress(struct estat *sts)
00439 {
00440 static unsigned int counter=0;
00441 static int is_tty=0;
00442 static int last_outp;
00443 static time_t last;
00444 static time_t too_many_new=0;
00445 int status;
00446 time_t now;
00447 int print;
00448 const int bar_chart_width=20;
00449 static const char bar_chart[bar_chart_width+1]="###################>";
00450 float pct;
00451
00452
00453 status=0;
00454 now=time(NULL);
00455
00456
00457 if (!progress_output) progress_output=stderr;
00458
00459 if (is_tty == 0)
00460 {
00461 is_tty= isatty(fileno(progress_output)) ? +1 : -1;
00462 DEBUGP("we're on a tty");
00463 }
00464
00465 if (is_tty == +1)
00466 {
00467
00468 counter++;
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478 print= (counter & 0xfff) == 0 ? 1 : 0;
00479 if (!print && ((counter & 0x3f) == 0))
00480 {
00481 now=time(NULL);
00482
00483
00484 if (now != last) print=1;
00485 }
00486
00487 if (print)
00488 {
00489
00490
00491 if (counter <= approx_entry_count && now<too_many_new)
00492 {
00493 pct=(float)counter/approx_entry_count;
00494 print = (int)((float)bar_chart_width*pct +0.5);
00495
00496
00497
00498
00499
00500 print=fprintf(progress_output,
00501 "\r%8d of %8d done (%5.1f%%); [%s%*s]",
00502 counter, approx_entry_count,
00503 pct*100.0,
00504 bar_chart+bar_chart_width-print,
00505 bar_chart_width-print, "");
00506
00507 if (pct > 0.96 && !too_many_new)
00508 too_many_new=now+5;
00509 }
00510 else
00511 {
00512
00513
00514
00515 print=fprintf(progress_output, "\r%8d entries done",
00516 counter);
00517 }
00518
00519 STOPIF_CODE_ERR(print < 0, errno,
00520 "Progress status could not be written");
00521
00522
00523
00524
00525 if (print < last_outp)
00526 fprintf(progress_output, "%*s ", last_outp-print, "");
00527 last_outp=print;
00528
00529
00530
00531
00532
00533 if (print > max_progress_len) max_progress_len=print;
00534
00535
00536
00537
00538
00539 time(&last);
00540 }
00541
00542 }
00543
00544 ex:
00545 return status;
00546 }
00547
00548
00552 int st__progress_uninit(void)
00553 {
00554 static const char err[]="Clearing the progress space";
00555 int status;
00556 char buff[max_progress_len+3];
00557
00558 status=0;
00559 if (max_progress_len>0)
00560 {
00561
00562
00563
00564 buff[0]='\r';
00565 memset(buff+1, ' ', max_progress_len);
00566 buff[1+max_progress_len]='\r';
00567 buff[2+max_progress_len]=0;
00568
00569 STOPIF_CODE_ERR( fputs(buff, progress_output) == EOF, errno, err);
00570 fflush(progress_output);
00571 }
00572
00573 ex:
00574 return status;
00575 }
00576
00577
00578 struct st___bit_info
00579 {
00580 int val;
00581 char *string;
00582 int str_len;
00583 };
00584 #define BIT_INFO(v, s) { .val=v, .string=s, .str_len=strlen(s) }
00585
00586
00590 #define st___string_from_bits(v, a, t) _st___string_from_bits(v, a, sizeof(a)/sizeof(a[0]), t)
00591 volatile char *_st___string_from_bits(int value,
00592 const struct st___bit_info data[], int max,
00593 char *text_for_none)
00594 {
00595 int status;
00596 static struct cache_t *cache=NULL;
00597 static const char sep[]=", ";
00598 char *string;
00599 int i;
00600 int last_len, new_len;
00601 struct cache_entry_t **cc;
00602
00603
00604 STOPIF( cch__new_cache(&cache, 4), NULL);
00605 STOPIF( cch__add(cache, 0, NULL, 128, &string), NULL);
00606 cc=cache->entries + cache->lru;
00607
00608 last_len=0;
00609 if (string) *string=0;
00610 for(i=0; i<max; i++)
00611 {
00612 if (value & data[i].val)
00613 {
00614 new_len = last_len + data[i].str_len +
00615 (last_len ? strlen(sep) : 0);
00616
00617 if (new_len + 8 > (*cc)->len)
00618 {
00619 STOPIF( cch__entry_set(cc, 0, NULL, new_len+64, 1, &string), NULL);
00620 string[last_len]=0;
00621 }
00622
00623 if (last_len)
00624 {
00625 strcpy(string + last_len, sep);
00626 last_len += strlen(sep);
00627 }
00628
00629 strcpy(string + last_len, data[i].string);
00630 last_len=new_len;
00631 #if 0
00632
00633 DEBUGP("match bit 0x%X on 0x%X: %s",
00634 data[i].val, value,
00635 data[i].string);
00636 #endif
00637 }
00638 }
00639
00640 ex:
00641
00642 if (status) return NULL;
00643
00644 return string && *string ? string : text_for_none;
00645 }
00646
00647
00648 inline volatile char* st__flags_string_fromint(int mask)
00649 {
00650 const struct st___bit_info flags[]={
00651 BIT_INFO( RF_ADD, "add"),
00652 BIT_INFO( RF_UNVERSION, "unversion"),
00653
00654
00655
00656 BIT_INFO( RF_CHECK, "check"),
00657 BIT_INFO( RF_COPY_BASE, "copy_base"),
00658 BIT_INFO( RF_COPY_SUB, "copy_sub"),
00659 BIT_INFO( RF_CONFLICT, "conflict"),
00660 BIT_INFO( RF_PUSHPROPS, "push_props"),
00661 };
00662
00663 return st___string_from_bits(mask, flags, "none");
00664 }
00665
00666
00667 inline volatile char* st__status_string_fromint(int mask)
00668 {
00669 const struct st___bit_info statii[]={
00670 BIT_INFO( FS_NEW, "new"),
00671 BIT_INFO( FS_REMOVED, "removed"),
00672 BIT_INFO( FS_CHANGED, "changed"),
00673 BIT_INFO( FS_META_OWNER, "owner"),
00674 BIT_INFO( FS_META_GROUP, "group"),
00675 BIT_INFO( FS_META_MTIME, "mtime"),
00676 BIT_INFO( FS_META_UMODE, "umode"),
00677 BIT_INFO( FS_PROPERTIES, "props"),
00678 BIT_INFO( FS_CHILD_CHANGED, "child"),
00679 BIT_INFO( FS_LIKELY, "likely"),
00680 };
00681 return st___string_from_bits(mask, statii, "unmodified");
00682 }
00683
00684
00685 char *st__type_string(mode_t mode)
00686 {
00687 switch (mode & S_IFMT)
00688 {
00689 case S_IFDIR: return "directory";
00690 case S_IFBLK: return "block-dev";
00691 case S_IFCHR: return "char-dev";
00692 case S_IFREG: return "file";
00693 case S_IFLNK: return "symlink";
00694 case S_IFSOCK: return "any-special";
00695 case S_IFGARBAGE: return "garbage";
00696 }
00697
00698 return "invalid";
00699 }
00700
00701
00702 inline volatile char* st__status_string(const struct estat * const sts)
00703 {
00704 return st__status_string_fromint(sts->entry_status);
00705 }
00706
00707
00708 int st__print_entry_info(struct estat *sts)
00709 {
00710 int status;
00711 char *path, *waa_path, *url, *copyfrom;
00712 svn_revnum_t copy_rev;
00713
00714
00715 status=errno=0;
00716 STOPIF( ops__build_path(&path, sts), NULL);
00717 STOPIF( url__full_url(sts, &url), NULL);
00718
00719 copyfrom=NULL;
00720 if ((opt__get_int(OPT__VERBOSE) & VERBOSITY_COPYFROM) &&
00721 (sts->flags & RF___IS_COPY))
00722 {
00723 STOPIF( cm__get_source(sts, path, ©from, ©_rev, 0), NULL);
00724 }
00725
00726 STOPIF_CODE_EPIPE( printf(" Type: \t%s\n",
00727 st__type_string(sts->st.mode)), NULL);
00728 if (S_ISDIR(sts->st.mode))
00729 STOPIF_CODE_EPIPE( printf( " ChildCount:\t%u\n",
00730 sts->entry_count), NULL);
00731 STOPIF_CODE_EPIPE( printf(" URL: \t%s\n", url), NULL);
00732 STOPIF_CODE_EPIPE( printf(" Status:\t0x%X (%s)\n",
00733 sts->entry_status, st__status_string(sts)), NULL);
00734 STOPIF_CODE_EPIPE( printf(" Flags:\t0x%X (%s)\n",
00735 sts->flags & ~RF_PRINT,
00736 st__flags_string_fromint(sts->flags)), NULL);
00737
00738 if (copyfrom)
00739 {
00740 STOPIF_CODE_EPIPE( printf(" Copyfrom:\trev. %llu of %s\n",
00741 (t_ull)copy_rev, copyfrom), NULL);
00742 }
00743
00744 STOPIF_CODE_EPIPE( printf(" Dev: \t%llu\n",
00745 (t_ull)sts->st.dev), NULL);
00746 STOPIF_CODE_EPIPE( printf(" Inode: \t%llu\n",
00747 (t_ull)sts->st.ino), NULL);
00748 STOPIF_CODE_EPIPE( printf(" Mode: \t0%4o\n",
00749 sts->st.mode), NULL);
00750 STOPIF_CODE_EPIPE( printf(" UID/GID:\t%u (%s)/%u (%s)\n",
00751 sts->st.uid, hlp__get_uname(sts->st.uid, "undefined"),
00752 sts->st.gid, hlp__get_grname(sts->st.gid, "undefined") ), NULL);
00753
00754 STOPIF_CODE_EPIPE( printf(" MTime: \t%.24s\n",
00755 ctime( &(sts->st.mtim.tv_sec) )), NULL);
00756 STOPIF_CODE_EPIPE( printf(" CTime: \t%.24s\n",
00757 ctime( &(sts->st.ctim.tv_sec) )), NULL);
00758
00759 STOPIF( waa__get_waa_directory(path, &waa_path, NULL, NULL,
00760 GWD_WAA), NULL);
00761 STOPIF_CODE_EPIPE( printf(" WAA-Path:\t%s\n",
00762 waa_path), NULL);
00763
00764 if (!sts->parent)
00765 {
00766 STOPIF( waa__get_waa_directory(path, &waa_path, NULL, NULL,
00767 GWD_CONF), NULL);
00768 STOPIF_CODE_EPIPE( printf(" Conf-Path:\t%s\n",
00769 waa_path), NULL);
00770 }
00771
00772
00773
00774 STOPIF_CODE_EPIPE( printf(" Revision:\t%li\n",
00775 sts->parent ? sts->repos_rev : urllist[0]->current_rev), NULL);
00776
00777 if (S_ISREG(sts->st.mode))
00778 STOPIF_CODE_EPIPE( printf(" Repos-MD5:\t%s\n",
00779 cs__md5tohex_buffered(sts->md5)), NULL);
00780
00781 if (S_ISBLK(sts->st.mode) || S_ISCHR(sts->st.mode))
00782 {
00783 #ifdef DEVICE_NODES_DISABLED
00784 DEVICE_NODES_DISABLED();
00785 #else
00786 STOPIF_CODE_EPIPE( printf(" Device nr.:\t%llu:%llu\n",
00787 (t_ull)MAJOR(sts->st.rdev),
00788 (t_ull)MINOR(sts->st.rdev)), NULL);
00789 }
00790 #endif
00791 else
00792 STOPIF_CODE_EPIPE( printf(" Size: \t%llu\n",
00793 (t_ull)sts->st.size), NULL);
00794
00795
00796 STOPIF_CODE_EPIPE( printf("\n"), NULL);
00797
00798 ex:
00799 return status;
00800 }
00801
00802