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