gitoff.c (86037B)
1 // TODO 2 // use the path function 3 // handle wrong config like getLog 4 // check parameters from CLI 5 // 6 // parse params 7 // use logger 8 // 9 // How to add a new config 10 // add variable in runtimeConfig 11 // add default settings in offDEFAULTS 12 // add a helper in offHelpers 13 // add setting of default in offCommands.install 14 // add a command for setting value in offCommands 15 // print value in offCommands.env 16 // add command in CLI parser 17 // update help 18 // 19 // How to add a new transport 20 // add transport functions in offHelpers.setTransport 21 // add transport in offHelpers.mkdirStore and offHelpers.rmAllStore 22 // add transport in offCommands.clearAll 23 // update git off mode help 24 // if needed, add store creation in offCommands.install 25 // 26 // How to add a new command 27 // add command in offCommands 28 // add command in CLI parser 29 // update help 30 // 31 ////// 32 // CODE 33 // 34 // modules 35 // defaults 36 // helpers 37 // core 38 // main 39 // 40 // 41 // modules 42 // all dependencies 43 // 44 // defaults 45 // objInfo fields: for indexing cat-diff response in push command 46 // externalHelpers: shell commands to be used with the exec function 47 // runtimeConfig: config built by offHelpers 48 // offDEFAULTS: default configuration for first time install 49 // 50 // helpers 51 // expandHome: expands ~/ 52 // gitConfig: handles global git config 53 // offLog: appends log to git config off.log 54 // offLogRepo: log for commands run in git repo 55 // exec: runs an externalHelpers with parameters 56 // mkdirParents: recursive mkdir 57 // rmAll: delete recursively files and directories 58 // copy: copies files 59 // offHelpers: git-off helpers 60 // 61 // core 62 // transport: transport functions for git off store 63 // offCommands: command line functions 64 // 65 // main 66 // parse CLI arguments 67 ////// 68 69 ////// 70 // modules 71 ////// 72 // includes and function prototypes 73 #ifdef unitTest 74 // gitoff.h is used in unit tests 75 #include "gitoff.h" 76 #else 77 typedef void (*gConfig_set_t)(char*, char*); 78 typedef void (*cmdSetF_t)(gConfig_set_t); 79 #endif 80 81 #define internal static 82 83 #include <sys/stat.h> 84 #include <inttypes.h> 85 #include <stdio.h> 86 #include <dirent.h> 87 #include <libgen.h> 88 #if (!__OpenBSD__) 89 #include <wordexp.h> 90 #endif 91 #include <stdbool.h> 92 #include <string.h> 93 #include <stdlib.h> 94 #include <unistd.h> 95 #include <stdint.h> 96 97 char *expandHome(char *p); 98 void offLog(char* s); 99 void offLogRepo(char* s); 100 char *exec(int cmdName, char* paramsArray); 101 bool strEq(char *string1, char *string2); 102 void gitConfig_set(char* key, char* value); 103 void gitConfig_setLocal(char* key, char* value); 104 void gitConfig_setThisRepo(char* key, char* value); 105 char *gitConfig_getDefault(char* key); 106 char *gitConfig_get(char *key); 107 void mkdirParents(char* p); 108 void rmAll(char* p); 109 void copy(char* src, char* dst); 110 char **execOut(char *cmd); 111 char **walkDir(char* dir); 112 void freeList(void **list); 113 char **split(char *string, char* delim); 114 char *join(char **list, char* delim); 115 char *offHelpers_gitRepoRoot(); 116 char *offHelpers_objectPath(); 117 char *offHelpers_offStore(); 118 char *offHelpers_offHttp(); 119 char *offHelpers_offCurlOptions(); 120 char *offHelpers_offMode(); 121 char *offHelpers_offIntegrity(); 122 char *offHelpers_offPem(); 123 char *offHelpers_offSshOptions(); 124 char *offHelpers_offScpOptions(); 125 char *offHelpers_offRsyncOptions(); 126 char *offHelpers_offScp(); 127 char *offHelpers_offScpUser(); 128 char *offHelpers_log(); 129 char *offHelpers_getLog(); 130 char *offHelpers_offConfigAlways(); 131 char *offHelpers_s3Region(); 132 char *offHelpers_s3Bucket(); 133 char *offHelpers_transform(); 134 char *offHelpers_transformTo(); 135 char *offHelpers_transformFrom(); 136 char *offHelpers_userAt(); 137 char **offHelpers_getSSHConfig(); 138 void offHelpers_mkdirStore(char *p); 139 void offHelpers_rmAllStore(char *p); 140 void offHelpers_copyTo(); 141 bool offHelpers_checkIntegrity(char *p); 142 void transportCopySend(char *file); 143 void transportCopyReceive(char *file); 144 void transportRsyncSend(char *file); 145 void transportRsyncReceive(char *file); 146 void transportScpSend(char *file); 147 void transportScpReceive(char *file); 148 void transportHttpSend(char *file); 149 void transportHttpReceive(char *file); 150 void offHelpers_setTransport(char *mode ); 151 #define offHelpers_setTransport_mode() offHelpers_setTransport( "config") 152 char **offHelpers_getOffFilePath(char *offFile); 153 void send(char *src); 154 void receive(char *src); 155 void transport_transformFrom(char *file); 156 void thisrepo(cmdSetF_t cmd); 157 int findCommand(char *p); 158 void showAllCommandsHelp(); 159 void offCommands_localSetup(); 160 void offCommands_install(gConfig_set_t setF ); 161 #define offCommands_install_setF() offCommands_install( gitConfig_set) 162 void offCommands_track(); 163 void offCommands_configAlways(); 164 void offCommands_setGetGitConfig(gConfig_set_t setF); 165 void offCommands_clean(); 166 void offCommands_prepush(); 167 void offCommands_push(char *line); 168 void offCommands_smudge(); 169 void offCommands_copyTo(); 170 void offCommands_pushTo(); 171 void offCommands_clearAll(); 172 void offCommands_clearCache(); 173 void offCommands_clearStore(); 174 void offCommands_clearTmp(); 175 void offCommands_defaults(); 176 void offCommands_env(); 177 void offCommands_help(); 178 void installF(); 179 void modeF(); 180 void storeF(); 181 void scpF(); 182 void httpF(); 183 void curlF(); 184 void integrityF(); 185 void pemF(); 186 void sshoptionsF(); 187 void scpoptionsF(); 188 void rsyncoptionsF(); 189 void scpuserF(); 190 void trackF(); 191 void configAlwaysF(); 192 void s3regionF(); 193 void s3bucketF(); 194 void transformF(); 195 void transformToF(); 196 void transformFromF(); 197 void cleanF(); 198 void prepushF(); 199 void smudgeF(); 200 void copyToF(); 201 void pushF(); 202 void clearAllF(); 203 void caF(); 204 void clearCacheF(); 205 void ccF(); 206 void clearStoreF(); 207 void csF(); 208 void clearTmpF(); 209 void ctF(); 210 void defaultsF(); 211 void envF(); 212 void helpF(); 213 void initCOMMAND_FUNC(); 214 int MAIN(int ARGC, char** ARGV); 215 216 int argc; char **argv; 217 218 ////// 219 // defaults 220 ////// 221 222 // objInfo fields for indexing cat-diff response in push command 223 #define oiPREVIOUSPERMISSIONS 0 224 #define oiPERMISSIONS 1 225 #define oiPREVIOUSOID 2 226 #define oiOID 3 227 #define oiNAME 4 228 229 // shell commands to be used with the exec function 230 // example: exec 'gitRepoRoot' 231 enum { gitConfigGlobal, gitConfig, gitRepoRoot, gitList, gitDff, gitCat, sha, listAttr, ssh, scp, rsync, curl, mv, mkdirE, cp, rm }; 232 char* externalHelpers[16] = { "git config --global", "git config", "git rev-parse --show-toplevel", "git rev-list", "git show --raw --format=\"\" --no-abbrev", "git cat-file -p", "git hash-object --no-filters", "git check-attr -a", "ssh", "scp", "rsync", "curl", "mv", "mkdir -p", "cp -u", "rm -rf" }; 233 234 // config built by offHelpers 235 // use offHelpers to access runtimeConfig 236 enum { currentRepoRoot, objectPath, offStore, offHttp, offMode, offIntegrity, offScp, offScpUser, offPem, offSshOptions, offScpOptions, offRsyncOptions, offCurlOptions, log, offConfigAlways, s3Region, s3Bucket, transform, transformTo, transformFrom, scpHost, scpPath, scpPort }; 237 char* runtimeConfig[23] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; 238 239 // default configuration for first time install 240 // objectPath is git off cache in repo 241 enum { objectPathD, modeD, integrityD, pemD, scpHostD, scpUserD, sshOptionsD, scpOptionsD, rsyncOptionsD, storeD, httpD, curlOptionsD, logD, configAlwaysD, s3RegionD, s3BucketD, transformD, transformToD, transformFromD, prePushD, offSignatureD, lastD }; 242 char* offDEFAULTS[22] = { "/.git/off/objects", "copy", "disable", "offNoValue", "offNoValue", "", "-C -o StrictHostKeyChecking=no -o ConnectTimeout=3", "-C -o StrictHostKeyChecking=no -o ConnectTimeout=3 -p", "-az -e \"ssh -i _i\"", "~/.git-off/offStore", "offNoValue", "-o", "~/.git-off/log", "offNoValue", "offNoValue", "offNoValue", "disable", "pbzip2 -9 -c _1 > _2", "pbzip2 -d -c _1 > _2", "#!/bin/sh\ncommand -v git-off >/dev/null 2>&1 || { echo >&2 \"\\nThis repository is configured for Git off but \"git-off\" was not found on your path. If you no longer wish to use git off, remove this hook by deleting .git/hooks/pre-push.\\n\"; exit 2; }\ngit off pre-push \"$@\"", "### git-off v1 sha:", "not used" }; 243 244 #define offDEFAULTS_shaLength 40 245 246 ////// 247 // helpers 248 ////// 249 250 #if (!__OpenBSD__) 251 // expands ~/ 252 char *expandHome(char *p) { 253 wordexp_t exp_result; 254 size_t len; 255 256 if (p == NULL) { 257 return(NULL); 258 } 259 wordexp(p, &exp_result, 0); 260 p = realloc(p, strlen(exp_result.we_wordv[0])+1); 261 strcpy(p, exp_result.we_wordv[0]); 262 wordfree(&exp_result); 263 return(p); 264 } 265 #else 266 #define and && 267 #define or || 268 #define not ! 269 #define elif else if 270 #define TOKENPASTE2(a, b) a ## b 271 #define TOKENPASTE(a, b) TOKENPASTE2(a, b) 272 #define UNIQVAR(name) TOKENPASTE(name, __LINE__) 273 #define forEachS(list, element) \ 274 ;size_t UNIQVAR(libsheepyInternalIndex) = 0; \ 275 for (char *element = list[0]; list[UNIQVAR(libsheepyInternalIndex)]!= NULL ; UNIQVAR(libsheepyInternalIndex)++, element = list[UNIQVAR(libsheepyInternalIndex)]) 276 char *findS(const char *string, const char *needle) { 277 278 // sanity checks 279 if (!string || !needle) { 280 return(NULL); 281 } 282 return(strstr(string, needle)); 283 } 284 char *strLCpy(char *dst, size_t dstSize, const char *src) { 285 286 if (!dst || !src) { 287 return(NULL); 288 } 289 290 char *r = strncpy(dst, src, dstSize);; 291 if (dstSize) { 292 r[dstSize-1] = 0; 293 } 294 return(r); 295 } 296 char *strLNCat(char *dst, size_t dstSize, const char *src, size_t srcLen) { 297 298 if (!dst || !src) { 299 return(NULL); 300 } 301 302 size_t dL = strnlen(dst, dstSize); 303 size_t dstLen = dstSize-1; 304 305 if (dL >= dstLen) { 306 // buffer is full 307 return(dst); 308 } 309 310 size_t sL = strnlen(src, srcLen); 311 312 if (dL+sL > dstLen) { 313 // truncate 314 return(strncat(dst, src, dstLen - dL)); 315 } 316 else { 317 return(strncat(dst, src, srcLen)); 318 } 319 } 320 #define forEachCharP(list, element) \ 321 for (char **element=list ; *element != NULL ; element++) 322 size_t listLengthS(char **list) { 323 size_t r = 0;; 324 325 // sanity checks 326 if (!list) { 327 return(0); 328 } 329 forEachCharP(list, i) { 330 r++; 331 } 332 return(r); 333 } 334 char **listPushS(char ***list, const char *s) { 335 336 // sanity checks 337 if (!list) { 338 return(NULL); 339 } 340 341 if (!*list) { 342 *list = malloc(2 * sizeof(char *)); 343 if (!s) { 344 (*list)[0] = NULL; 345 } 346 else { 347 (*list)[0] = strdup(s); 348 } 349 (*list)[1] = NULL; 350 } 351 else { 352 // realloc list and copy s to last element 353 size_t len; 354 len = listLengthS(*list); 355 char **tmp = realloc(*list, (len+2) * sizeof(char *)); 356 if (!tmp) { 357 return(NULL); 358 } 359 else { 360 *list = tmp; 361 (*list)[len+1] = NULL; 362 if (!s) { 363 // s is NULL, add NULL in list 364 (*list)[len] = NULL; 365 } 366 else { 367 (*list)[len] = strdup(s); 368 } 369 } 370 } 371 return(*list); 372 } 373 #define listEmptyS(list) \ 374 do {\ 375 list = malloc(1 * sizeof(char *)); \ 376 if (list) list[0] = NULL; \ 377 } while(0); 378 char **readText(const char *filePath) { 379 FILE *fp = NULL; 380 size_t len; 381 char* line = NULL; 382 ssize_t read; 383 char **list = NULL; 384 385 // sanity checks 386 if (!filePath) { 387 return(NULL); 388 } 389 fp = fopen(filePath, "r"); 390 if (!fp) { 391 //pFuncError 392 //shEPrintfS("The path was: \"%s\"\n", filePath); 393 return(NULL); 394 } 395 // read all lines 396 read = getline(&line, &len, fp); 397 while (read != -1) { 398 { 399 char* pos = NULL; 400 pos = strchr(line, '\n'); 401 if (pos != NULL) 402 *pos = '\0'; 403 } 404 listPushS(&list, line); 405 read = getline(&line, &len, fp); 406 } 407 fclose(fp); 408 free(line); 409 if (!list) { 410 // nothing was read 411 listEmptyS(list); 412 } 413 return(list); 414 } 415 bool startsWithS(const char *string1, const char *string2) { 416 417 // sanity checks 418 if (!string1 || !string2) { 419 return(false); 420 } 421 return(strncmp(string1, string2, strlen(string2)) == 0);; 422 } 423 void listFreeS(char **list) { 424 425 // sanity checks 426 if (list) { 427 forEachCharP(list, e) { 428 free(*e); 429 } 430 free(list); 431 } 432 } 433 char *iAppendS(char **string1, const char *string2) { 434 char *tmp = NULL; 435 size_t l1; 436 size_t l2; 437 438 if (!string1 || !string2) { 439 return(NULL); 440 } 441 442 if (!*string1) { 443 *string1 = strdup(string2); 444 return(*string1); 445 } 446 447 l1 = strlen(*string1); 448 l2 = strlen(string2); 449 450 if (!l2) { 451 // empty string 452 return(*string1); 453 } 454 455 tmp = realloc(*string1, l1 + l2 + 1); 456 if (!tmp) { 457 return(NULL); 458 } 459 460 *string1 = tmp; 461 strcat(*string1, string2); 462 return(*string1); 463 } 464 char *expandHome(char *path) { 465 466 // sanity checks 467 if (!path) { 468 return(NULL); 469 } 470 471 472 if (path[0] == 0) { 473 // path is empty 474 return(path); 475 } 476 477 // steps 478 // determine path format 479 // set user name, either current user or user name in path 480 // add : at the end of username to match line in the /etc/passwd file 481 // find home path in the passwd file 482 483 enum {noExpand, currentUser, otherUser}; 484 485 // determine path format 486 int status = noExpand; 487 if (path[0] == '~' and (path[1] == '/' or path[1] == 0)) { 488 // path="~/..." 489 status = currentUser; 490 } 491 elif (path[0] == '~' and path[1] != '/') { 492 // path="~USER..." 493 status = otherUser; 494 } 495 496 // there is no tilde to expand, return path unchanged 497 if (status == noExpand) { 498 return(path); 499 } 500 501 // set user name, either current user or user name in path 502 char user[33] = {0}; 503 size_t pathStart = 0; 504 505 if (status == currentUser) { 506 // use getlogin to find current username 507 // sizeof(user)-1 to keep a char tp append final ':' 508 if (getlogin_r(user, sizeof(user)-1)) { 509 // error 510 //logE("getlogin for current user"); 511 } { 512 pathStart = 1; 513 } 514 } 515 else { 516 // username is in path 517 // from index 1 (skip ~) to the first / 518 char *slash = findS(path, "/"); 519 if (!slash) { 520 // no slash found, path is in the form: ~USER 521 // copy string after ~ to the end of the string 522 strLCpy(user, sizeof(user)-1, path+1); 523 pathStart = strlen(path); 524 } 525 else { 526 // copy string after ~ to first slash 527 pathStart = slash - path; 528 strLNCat(user, sizeof(user)-1, path+1, pathStart-1); 529 } 530 } 531 532 // add : at the end of username to match line in passwd 533 size_t len = strlen(user); 534 user[len] = ':'; 535 user[len+1] = 0; 536 537 538 // find home path in the passwd file 539 char **pwd = readText("/etc/passwd"); 540 541 if (!pwd) { 542 return(NULL); 543 } 544 545 // result 546 char *r = NULL; 547 548 forEachS(pwd, l) { 549 if (startsWithS(l, user)) { 550 // found the user 551 char **l_l = split(l, ":"); 552 // copy home path to result 553 r = strdup(l_l[5]); 554 listFreeS(l_l); 555 break; 556 } 557 } 558 559 listFreeS(pwd); 560 561 if (!r) { 562 // user not found in this system 563 return(NULL); 564 } 565 566 // append rest of the path to the result 567 iAppendS(&r, path + pathStart); 568 569 free(path); 570 571 return(r); 572 } 573 #endif 574 575 576 // appends log to git config off.log 577 void offLog(char* s) { 578 char* r = NULL; 579 char* dirName = NULL; 580 DIR* d = NULL; 581 FILE* f = NULL; 582 583 if (runtimeConfig[log] == NULL) { 584 // set runtimeConfig.log and get config in git 585 r = exec(gitConfigGlobal, "off.log"); 586 r = expandHome(r); 587 runtimeConfig[log] = r; 588 // error handling 589 if (r == NULL) { 590 printf("Missing off.log config. Run \"git config --global off.log ~/.git-off/log\"."); 591 printf("\n"); 592 exit(EXIT_FAILURE); 593 } 594 } 595 dirName = strdup(runtimeConfig[log]); 596 dirname(dirName); 597 d = opendir(dirName); 598 if (d == NULL) { 599 mkdirParents(dirName); 600 } 601 free(dirName); 602 free(d); 603 604 f = fopen(runtimeConfig[log], "a"); 605 fprintf(f, "%s\n", s); 606 fclose(f); 607 } 608 609 // log for commands run in git repo 610 // adds current repo path to string s in log 611 void offLogRepo(char* s) { 612 // depends on offHelpers 613 char* ss = NULL; 614 615 ss = malloc(strlen(offHelpers_gitRepoRoot()) + strlen(s) + 1 + 12); 616 sprintf(ss, "REPO path: %s %s", offHelpers_gitRepoRoot(), s); 617 offLog(ss); 618 free(ss); 619 } 620 621 622 // runs an externalHelpers with parameters 623 // cmdName is string 624 // paramsArray is an array of strings 625 // returns line 626 char *exec(int cmdName, char* paramsArray) { 627 char* cmd = NULL; 628 FILE* fp = NULL; 629 size_t len; 630 char* line = NULL; 631 ssize_t read; 632 633 cmd = malloc(strlen(externalHelpers[cmdName]) + strlen(paramsArray) + 1 + 1); 634 sprintf(cmd, "%s %s", externalHelpers[cmdName], paramsArray); 635 //print cmd 636 637 fp = popen(cmd, "r"); 638 if (fp == NULL) { 639 exit(EXIT_FAILURE); 640 } 641 free(cmd); 642 643 read = getline(&line, &len, fp); 644 pclose(fp); 645 646 if (read == -1) { 647 // nothing was read 648 return(NULL); 649 } 650 651 { 652 char* pos = NULL; 653 pos = strchr(line, '\n'); 654 if (pos != NULL) 655 *pos = '\0'; 656 } 657 //print line 658 return(line); 659 } 660 661 // compare strings 662 bool strEq(char *string1, char *string2) { 663 664 if (string1 == NULL) { 665 return(false); 666 } 667 if (string2 == NULL) { 668 return(false); 669 } 670 return(strcmp(string1,string2) == 0);; 671 } 672 673 674 // handles global git config 675 void gitConfig_set(char* key, char* value) { 676 char* p = NULL; 677 char* r = NULL; 678 679 // dont use double quote, problem with rsyncOptions - p = '%s \"%s\"', key, value 680 p = malloc(strlen(key) + strlen(value) + 1 + 5);; 681 sprintf(p, "%s '%s'", key, value); 682 r = exec(gitConfigGlobal, p); 683 free(p); 684 free(r); 685 } 686 687 void gitConfig_setLocal(char* key, char* value) { 688 char* p = NULL; 689 char* r = NULL; 690 691 p = malloc(strlen(key) + strlen(value) + 1 + 5); 692 sprintf(p, "%s \"%s\"", key, value); 693 r = exec(gitConfig, p); 694 free(p); 695 free(r); 696 } 697 698 void gitConfig_setThisRepo(char* key, char* value) { 699 char* p = NULL; 700 char* r = NULL; 701 702 p = malloc(strlen(offHelpers_gitRepoRoot()) + strlen(key) + strlen(value) + 1 + 22); 703 sprintf(p, "--file %s/.git-off %s \"%s\"", offHelpers_gitRepoRoot() , key, value); 704 r = exec(gitConfig, p); 705 free(p); 706 free(r); 707 } 708 709 char *gitConfig_getDefault(char* key) { 710 711 return(exec(gitConfig, key)); 712 } 713 714 char *gitConfig_get(char *key) { 715 // use configAlways setting or 716 // return value from 717 // GIT_OFF_CONFIG if found 718 // repo config if found 719 // global config 720 char* r = NULL; 721 char* p = NULL; 722 char* gitOffConfigEnv = NULL; 723 724 // configAlways 725 if (strEq(offHelpers_offConfigAlways(), "GIT_OFF_CONFIG")) { 726 gitOffConfigEnv = getenv("GIT_OFF_CONFIG"); 727 if ((gitOffConfigEnv != NULL) && (access(gitOffConfigEnv, F_OK) != -1)) { 728 p = malloc(strlen(gitOffConfigEnv) + strlen(key) + 1 + 8); 729 sprintf(p, "--file %s %s", gitOffConfigEnv, key); 730 r = exec(gitConfig, p); 731 free(p); 732 } 733 return(r); 734 } 735 if (strEq(offHelpers_offConfigAlways(), "repo")) { 736 p = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 9); 737 sprintf(p, "%s/.git-off", offHelpers_gitRepoRoot()); 738 if (access(p, F_OK) != -1) { 739 free(p); 740 p = malloc(strlen(offHelpers_gitRepoRoot()) + strlen(key) + 1 + 17); 741 sprintf(p, "--file %s/.git-off %s", offHelpers_gitRepoRoot() , key); 742 r = exec(gitConfig, p); 743 } 744 free(p); 745 return(r); 746 } 747 if (strEq(offHelpers_offConfigAlways(), "global")) { 748 r = gitConfig_getDefault(key); 749 return(r); 750 } 751 752 // interpolate 753 gitOffConfigEnv = getenv("GIT_OFF_CONFIG"); 754 if ((gitOffConfigEnv != NULL) && (access(gitOffConfigEnv, F_OK) != -1)) { 755 p = malloc(strlen(gitOffConfigEnv) + strlen(key) + 1 + 8); 756 sprintf(p, "--file %s %s", gitOffConfigEnv, key); 757 r = exec(gitConfig, p); 758 free(p); 759 if (r != NULL) { 760 return(r); 761 } 762 } 763 764 if (offHelpers_gitRepoRoot()) { 765 // skip repo config when running outside a git repo 766 p = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 9); 767 sprintf(p, "%s/.git-off", offHelpers_gitRepoRoot()); 768 if (access(p, F_OK) != -1) { 769 free(p); 770 p = malloc(strlen(offHelpers_gitRepoRoot()) + strlen(key) + 1 + 17); 771 sprintf(p, "--file %s/.git-off %s", offHelpers_gitRepoRoot() , key); 772 r = exec(gitConfig, p); 773 if (r != NULL) { 774 free(p); 775 return(r); 776 } 777 } 778 free(p); 779 } 780 r = gitConfig_getDefault(key); 781 return(r); 782 } 783 784 785 // recursive mkdir 786 void mkdirParents(char* p) { 787 char* r = NULL; 788 789 r = exec(mkdirE, p); 790 free(r); 791 } 792 793 // delete recursively files and directories 794 void rmAll(char* p) { 795 char* r = NULL; 796 797 r = exec(rm, p); 798 free(r); 799 } 800 801 // copies files 802 // file modes are not kept 803 void copy(char* src, char* dst) { 804 char* r = NULL; 805 char* p = NULL; 806 807 p = malloc(strlen(src) + strlen(dst) + 1 + 1); 808 sprintf(p, "%s %s", src, dst); 809 r = exec(cp, p); 810 free(p); 811 free(r); 812 } 813 814 // exec 815 // return stdout from cmd 816 char **execOut(char *cmd) { 817 FILE* fp = NULL; 818 size_t len; 819 char* line = NULL; 820 ssize_t read; 821 char **list = NULL; 822 int count = 0;; 823 824 //print cmd 825 826 fp = popen(cmd, "r"); 827 if (fp == NULL) { 828 exit(EXIT_FAILURE); 829 } 830 831 read = getline(&line, &len, fp); 832 while (read != -1) { 833 { 834 char* pos = NULL; 835 pos = strchr(line, '\n'); 836 if (pos != NULL) 837 *pos = '\0'; 838 } 839 if (list == NULL) { 840 list = malloc(2 * sizeof(int *)); 841 list[1] = NULL; 842 } 843 else { 844 list = realloc(list, (count+2) * sizeof(int *)); 845 if (list == NULL) { 846 exit(EXIT_FAILURE); 847 } 848 list[count+1] = NULL; 849 } 850 list[count] = strdup(line); 851 read = getline(&line, &len, fp); 852 count++; 853 } 854 855 pclose(fp); 856 return(list); 857 } 858 859 // List all files in a directory 860 char **walkDir(char* dir) { 861 char* cmd = NULL; 862 char **list = NULL; 863 864 cmd = malloc(strlen(dir) + 1 + 13); 865 sprintf(cmd, "find %s -type f", dir); 866 list = execOut(cmd); 867 free(cmd); 868 return(list); 869 } 870 871 void freeList(void **list) { 872 int i = 0;; 873 874 if (list != NULL) { 875 while (list[i] != NULL) { 876 free(list[i]); 877 i++; 878 } 879 free(list); 880 } 881 } 882 883 884 char **split(char *string, char* delim) { 885 char *startString = NULL; 886 char *workingString = NULL; 887 char *line = NULL; 888 char *token = NULL; 889 int count = 0;; 890 char **r = NULL; 891 892 startString = strdup(string); 893 workingString = startString; 894 while (strlen(workingString) != 0) { 895 line = workingString; 896 token = strtok_r(line, delim, &workingString); 897 if (r == NULL) { 898 r = malloc(2 * sizeof(int *)); 899 r[1] = NULL; 900 } 901 else { 902 r = realloc(r, (count+2) * sizeof(int *)); 903 if (r == NULL) { 904 exit(EXIT_FAILURE); 905 } 906 r[count+1] = NULL; 907 } 908 r[count] = strdup(token); 909 count++; 910 // macOS sets workingString to NULL at the end 911 if (!workingString) { 912 break; 913 } 914 } 915 916 free(startString); 917 return(r); 918 } 919 920 char *join(char **list, char* delim) { 921 char *r = NULL; 922 923 while (*list != NULL) { 924 if (r == NULL) { 925 r = strdup(*list); 926 } 927 else { 928 char *tmp; 929 tmp = realloc(r, strlen(r) + strlen(delim) + 1); 930 if (tmp == NULL) { 931 exit(EXIT_FAILURE); 932 } 933 r = tmp; 934 strcat(r, delim); 935 tmp = realloc(r, strlen(r) + strlen(*list) + 1); 936 if (tmp == NULL) { 937 exit(EXIT_FAILURE); 938 } 939 r = tmp; 940 strcat(r, *list); 941 } 942 list++; 943 } 944 return(r); 945 } 946 947 948 // transport 949 950 typedef void (*transportSend_t)(char *); 951 typedef void (*transportReceive_t)(char *); 952 typedef struct {transportSend_t send; transportReceive_t receive;} transport_t; 953 transport_t transport; 954 955 // git-off helpers 956 // gitRepoRoot: sets and returns runtimeConfig.currentRepoRoot 957 // objectPath: sets and returns runtimeConfig.objectPath 958 // offStore: sets and returns runtimeConfig.offStore 959 // offMode: sets and returns runtimeConfig.offMode 960 // offIntegrity sets and returns runtimeConfig.offIntegrity 961 // offScp: sets and returns runtimeConfig.offScp 962 // offScpUser: sets and returns runtimeConfig.offScpUser 963 // log: sets and returns runtimeConfig.log 964 // getLog: sets and returns runtimeConfig.log with error checking 965 // userAt: returns user@ or '' 966 // getSSHConfig extracts host, port and path from off.sshhost 967 // mkdirStore mkdir in remote store 968 // rmAllStore rm in remote store 969 // checkIntegrity check integrity of files coming from the store 970 // setTransport: set send and receive functions for transport 971 // getOffFilePath: creates path for offFile 972 973 char *offHelpers_gitRepoRoot() { 974 975 if (runtimeConfig[currentRepoRoot] == NULL) { 976 runtimeConfig[currentRepoRoot] = exec(gitRepoRoot, ""); 977 } 978 return(runtimeConfig[currentRepoRoot]); 979 } 980 981 char *offHelpers_objectPath() { 982 983 if (runtimeConfig[objectPath] == NULL) { 984 runtimeConfig[objectPath] = malloc(strlen(offHelpers_gitRepoRoot()) + strlen(offDEFAULTS[objectPathD]) + 1 + 0); 985 sprintf(runtimeConfig[objectPath], "%s%s", offHelpers_gitRepoRoot(), offDEFAULTS[objectPathD]); 986 } 987 return(runtimeConfig[objectPath]); 988 } 989 990 char *offHelpers_offStore() { 991 992 if (runtimeConfig[offStore] == NULL) { 993 runtimeConfig[offStore] = gitConfig_get("off.store"); 994 } 995 return(runtimeConfig[offStore]); 996 } 997 998 char *offHelpers_offHttp() { 999 1000 if (runtimeConfig[offHttp] == NULL) { 1001 runtimeConfig[offHttp] = gitConfig_get("off.http"); 1002 } 1003 return(runtimeConfig[offHttp]); 1004 } 1005 1006 char *offHelpers_offCurlOptions() { 1007 1008 if (runtimeConfig[offCurlOptions] == NULL) { 1009 runtimeConfig[offCurlOptions] = gitConfig_get("off.curloptions"); 1010 } 1011 return(runtimeConfig[offCurlOptions]); 1012 } 1013 1014 char *offHelpers_offMode() { 1015 1016 if (runtimeConfig[offMode] == NULL) { 1017 runtimeConfig[offMode] = gitConfig_get("off.mode"); 1018 } 1019 return(runtimeConfig[offMode]); 1020 } 1021 1022 char *offHelpers_offIntegrity() { 1023 1024 if (runtimeConfig[offIntegrity] == NULL) { 1025 runtimeConfig[offIntegrity] = gitConfig_get("off.integrity"); 1026 } 1027 return(runtimeConfig[offIntegrity]); 1028 } 1029 1030 char *offHelpers_offPem() { 1031 1032 if (runtimeConfig[offPem] == NULL) { 1033 runtimeConfig[offPem] = gitConfig_get("off.pem"); 1034 } 1035 return(runtimeConfig[offPem]); 1036 } 1037 1038 char *offHelpers_offSshOptions() { 1039 1040 if (runtimeConfig[offSshOptions] == NULL) { 1041 runtimeConfig[offSshOptions] = gitConfig_get("off.sshoptions"); 1042 } 1043 return(runtimeConfig[offSshOptions]); 1044 } 1045 1046 char *offHelpers_offScpOptions() { 1047 1048 if (runtimeConfig[offScpOptions] == NULL) { 1049 runtimeConfig[offScpOptions] = gitConfig_get("off.scpoptions"); 1050 } 1051 return(runtimeConfig[offScpOptions]); 1052 } 1053 1054 char *offHelpers_offRsyncOptions() { 1055 1056 if (runtimeConfig[offRsyncOptions] == NULL) { 1057 runtimeConfig[offRsyncOptions] = gitConfig_get("off.rsyncoptions"); 1058 } 1059 return(runtimeConfig[offRsyncOptions]); 1060 } 1061 1062 char *offHelpers_offScp() { 1063 1064 if (runtimeConfig[offScp] == NULL) { 1065 runtimeConfig[offScp] = gitConfig_get("off.scphost"); 1066 } 1067 return(runtimeConfig[offScp]); 1068 } 1069 1070 char *offHelpers_offScpUser() { 1071 1072 if (runtimeConfig[offScpUser] == NULL) { 1073 runtimeConfig[offScpUser] = gitConfig_get("off.scpuser"); 1074 } 1075 return(runtimeConfig[offScpUser]); 1076 } 1077 1078 char *offHelpers_log() { 1079 1080 if (runtimeConfig[log] == NULL) { 1081 runtimeConfig[log] = gitConfig_getDefault("off.log"); 1082 runtimeConfig[log] = expandHome(runtimeConfig[log]); 1083 } 1084 return(runtimeConfig[log]); 1085 } 1086 1087 char *offHelpers_getLog() { 1088 1089 offHelpers_log(); 1090 // error handling 1091 if (runtimeConfig[log] == NULL) { 1092 printf("Missing off.log config. Run \"git config --global off.log ~/.git-off/log\"."); 1093 printf("\n"); 1094 exit(EXIT_FAILURE); 1095 } 1096 return(runtimeConfig[log]); 1097 } 1098 1099 char *offHelpers_offConfigAlways() { 1100 1101 if (runtimeConfig[offConfigAlways] == NULL) { 1102 runtimeConfig[offConfigAlways] = gitConfig_getDefault("off.configAlways"); 1103 } 1104 return(runtimeConfig[offConfigAlways]); 1105 } 1106 1107 char *offHelpers_s3Region() { 1108 1109 if (runtimeConfig[s3Region] == NULL) { 1110 runtimeConfig[s3Region] = gitConfig_get("off.s3Region"); 1111 } 1112 return(runtimeConfig[s3Region]); 1113 } 1114 1115 char *offHelpers_s3Bucket() { 1116 1117 if (runtimeConfig[s3Bucket] == NULL) { 1118 runtimeConfig[s3Bucket] = gitConfig_get("off.s3Bucket"); 1119 } 1120 return(runtimeConfig[s3Bucket]); 1121 } 1122 1123 char *offHelpers_transform() { 1124 1125 if (runtimeConfig[transform] == NULL) { 1126 runtimeConfig[transform] = gitConfig_get("off.transform"); 1127 } 1128 return(runtimeConfig[transform]); 1129 } 1130 1131 char *offHelpers_transformTo() { 1132 1133 if (runtimeConfig[transformTo] == NULL) { 1134 runtimeConfig[transformTo] = gitConfig_get("off.transformTo"); 1135 } 1136 return(runtimeConfig[transformTo]); 1137 } 1138 1139 char *offHelpers_transformFrom() { 1140 1141 if (runtimeConfig[transformFrom] == NULL) { 1142 runtimeConfig[transformFrom] = gitConfig_get("off.transformFrom"); 1143 } 1144 return(runtimeConfig[transformFrom]); 1145 } 1146 1147 char *offHelpers_userAt() { 1148 1149 if ((offHelpers_offScpUser() != NULL) && (!strEq(offHelpers_offScpUser(), ""))) { 1150 char *u; 1151 u = malloc(strlen(offHelpers_offScpUser()) + 1 + 1); 1152 sprintf(u, "%s@", offHelpers_offScpUser()); 1153 return(u); 1154 } 1155 else { 1156 return ""; 1157 } 1158 } 1159 1160 char **offHelpers_getSSHConfig() { 1161 char *user = NULL; 1162 char **h_l = NULL; 1163 char *port = NULL; 1164 char *host = NULL; 1165 char *storePath = NULL; 1166 char **portAndPath_l = NULL; 1167 char **r = NULL; 1168 1169 // extract host, port and path from off.sshhost 1170 1171 user = offHelpers_userAt(); 1172 h_l = split(offHelpers_offScp(), ":"); 1173 host = strdup(h_l[0]); 1174 if (h_l[1] != NULL) { 1175 int i; 1176 1177 portAndPath_l = split(h_l[1], "/"); 1178 i = strtoumax(portAndPath_l[0], NULL, 10); 1179 if (i != 0) { 1180 port = strdup(portAndPath_l[0]); 1181 } 1182 } 1183 if (port == NULL) { 1184 // use default port 1185 storePath = strdup(h_l[1]); 1186 } 1187 else { 1188 storePath = strdup("/"); 1189 char *tmp; 1190 tmp = join(portAndPath_l + 1, "/"); 1191 char *tmpr; 1192 tmpr = realloc(storePath, strlen(storePath) + strlen(tmp) + 1); 1193 if (tmpr == NULL) { 1194 exit(EXIT_FAILURE); 1195 } 1196 storePath = tmpr; 1197 strcat(storePath, tmp); 1198 free(tmp); 1199 } 1200 freeList((void **) h_l); 1201 freeList((void **) portAndPath_l); 1202 1203 // result [user + host, storePath, port] 1204 r = malloc(4 * sizeof(int *)); 1205 r[3] = NULL; 1206 r[0] = strdup(user); 1207 char *t; 1208 t = realloc(r[0], strlen(r[0]) + strlen(host) + 1); 1209 if (t == NULL) { 1210 exit(EXIT_FAILURE); 1211 } 1212 r[0] = t; 1213 strcat(r[0], host); 1214 r[1] = storePath; 1215 r[2] = port; 1216 free(host); 1217 return(r); 1218 } 1219 1220 1221 void offHelpers_mkdirStore(char *p) { 1222 // mkdir in remote store 1223 char *params = NULL; 1224 char *sshCmd = NULL; 1225 char *pem = NULL; 1226 char **h_l = NULL; 1227 1228 // TODO handle multiple transports 1229 h_l = offHelpers_getSSHConfig(); 1230 1231 sshCmd = malloc(strlen(h_l[1]) + strlen(p) + 1 + 10); 1232 sprintf(sshCmd, "mkdir -p %s/%s", h_l[1], p); 1233 1234 // setup ssh/scp private key 1235 if ((offHelpers_offPem() == NULL) || (strEq(offHelpers_offPem(), "offNoValue")) || (offHelpers_offPem() == NULL)) { 1236 pem = strdup(""); 1237 } 1238 else { 1239 pem = malloc(strlen(offHelpers_offPem()) + 1 + 3); 1240 sprintf(pem, "-i %s", offHelpers_offPem()); 1241 } 1242 1243 // ignore error from mkdir for already existing store 1244 if (h_l[2] == NULL) { 1245 params = malloc(strlen(offHelpers_offSshOptions()) + strlen(pem) + strlen(h_l[0]) + strlen(sshCmd) + 1 + 7); 1246 sprintf(params, "%s %s %s \"%s\"", offHelpers_offSshOptions(), pem, h_l[0], sshCmd); 1247 } 1248 else { 1249 params = malloc(strlen(offHelpers_offSshOptions()) + strlen(pem) + strlen(h_l[2]) + strlen(h_l[0]) + strlen(sshCmd) + 1 + 11); 1250 sprintf(params, "%s %s -p %s %s \"%s\"", offHelpers_offSshOptions(), pem, h_l[2], h_l[0], sshCmd); 1251 } 1252 1253 freeList((void **) h_l); 1254 free(sshCmd); 1255 free(pem); 1256 exec(ssh, params); 1257 free(params); 1258 } 1259 1260 1261 void offHelpers_rmAllStore(char *p) { 1262 // rm in remote store 1263 char *params = NULL; 1264 char *sshCmd = NULL; 1265 char *pem = NULL; 1266 char **h_l = NULL; 1267 1268 // setup ssh/scp private key 1269 if ((offHelpers_offPem() == NULL) || (strEq(offHelpers_offPem(), "offNoValue")) || (offHelpers_offPem() == NULL)) { 1270 pem = strdup(""); 1271 } 1272 else { 1273 pem = malloc(strlen(offHelpers_offPem()) + 1 + 3); 1274 sprintf(pem, "-i %s", offHelpers_offPem()); 1275 } 1276 1277 // scphost format is host:path 1278 h_l = offHelpers_getSSHConfig(); 1279 1280 sshCmd = malloc(strlen(h_l[1]) + strlen(p) + 1 + 8); 1281 sprintf(sshCmd, "rm -rf %s/%s", h_l[1], p); 1282 1283 // ignore error from rm 1284 if (h_l[2] == NULL) { 1285 params = malloc(strlen(offHelpers_offSshOptions()) + strlen(pem) + strlen(h_l[0]) + strlen(sshCmd) + 1 + 7); 1286 sprintf(params, "%s %s %s \"%s\"", offHelpers_offSshOptions(), pem, h_l[0], sshCmd); 1287 } 1288 else { 1289 params = malloc(strlen(offHelpers_offSshOptions()) + strlen(pem) + strlen(h_l[2]) + strlen(h_l[0]) + strlen(sshCmd) + 1 + 11); 1290 sprintf(params, "%s %s -p %s %s \"%s\"", offHelpers_offSshOptions(), pem, h_l[2], h_l[0], sshCmd); 1291 } 1292 1293 freeList((void **) h_l); 1294 free(sshCmd); 1295 free(pem); 1296 exec(ssh, params); 1297 free(params); 1298 } 1299 1300 void offHelpers_copyTo() { 1301 // list file in cache 1302 // copy to store 1303 char **files = NULL; 1304 int i; 1305 1306 // list file in cache 1307 1308 files = walkDir(offHelpers_objectPath()); 1309 if (files == NULL) { 1310 return; 1311 } 1312 1313 i = 0; 1314 while (files[i] != NULL) { 1315 char *tmp; 1316 tmp = strdup(files[i] + strlen(offHelpers_objectPath()) + 1); 1317 free(files[i]); 1318 files[i] = tmp; 1319 i++; 1320 } 1321 1322 // copy to store 1323 1324 i = 0; 1325 while (files[i] != NULL) { 1326 transport.send(files[i]); 1327 i++; 1328 } 1329 freeList((void **) files); 1330 } 1331 1332 bool offHelpers_checkIntegrity(char *p) { 1333 // check integrity of files coming from the store 1334 bool result = true;; 1335 char *receivedSha = NULL; 1336 char *base = NULL; 1337 1338 if (strEq(offHelpers_offIntegrity(), "disable")) { 1339 return(true); 1340 } 1341 1342 receivedSha = exec(sha, p); 1343 1344 base = strdup(basename(p)); 1345 if (!strEq(base, receivedSha)) { 1346 // the file received is different from the one that was sent. 1347 printf("git-off: The file %s differs from the one that was pushed.", p); { 1348 printf("\n"); 1349 result = false; 1350 } 1351 } 1352 free(base); 1353 1354 return(result); 1355 } 1356 1357 void transportCopySend(char *file) { 1358 // create file directories in store 1359 char **f_l = NULL; 1360 char *p = NULL; 1361 DIR *d = NULL; 1362 1363 f_l = split(file, "/"); 1364 p = malloc(strlen(offHelpers_offStore()) + strlen(f_l[0]) + strlen(f_l[1]) + 1 + 2); 1365 sprintf(p, "%s/%s/%s", offHelpers_offStore(), f_l[0], f_l[1]); 1366 d = opendir(p);; 1367 if (d == NULL) { 1368 mkdirParents(p); 1369 } 1370 free(p); 1371 1372 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1373 sprintf(p, "%s/%s", offHelpers_objectPath(), file); 1374 char *dest; 1375 dest = malloc(strlen(offHelpers_offStore()) + strlen(file) + 1 + 1); 1376 sprintf(dest, "%s/%s", offHelpers_offStore(), file); 1377 copy(p, dest); 1378 free(dest); 1379 free(p); 1380 freeList((void **)f_l); 1381 } 1382 1383 void transportCopyReceive(char *file) { 1384 // transfer and transform 1385 char *p = NULL; 1386 int sR; 1387 char b[1024]; 1388 FILE *f = NULL; 1389 1390 if ((strEq(offHelpers_transform(), "enable")) && (offHelpers_transformFrom() != NULL)) { 1391 // create file directories in objectPath 1392 char **f_l; 1393 DIR *d; 1394 f_l = split(file, "/"); 1395 p = malloc(strlen(offHelpers_objectPath()) + strlen(f_l[0]) + strlen(f_l[1]) + 1 + 2); 1396 sprintf(p, "%s/%s/%s", offHelpers_objectPath(), f_l[0], f_l[1]); 1397 d = opendir(p);; 1398 if (d == NULL) { 1399 mkdirParents(p); 1400 } 1401 free(p); 1402 1403 p = malloc(strlen(offHelpers_offStore()) + strlen(file) + 1 + 1); 1404 sprintf(p, "%s/%s", offHelpers_offStore(), file); 1405 char *dest; 1406 dest = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1407 sprintf(dest, "%s/%s", offHelpers_objectPath(), file); 1408 copy(p, dest); 1409 1410 transport_transformFrom(file); 1411 1412 free(p); 1413 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 8); 1414 sprintf(p, "%s/../tmp/%s", offHelpers_objectPath(), file); 1415 if (offHelpers_checkIntegrity(p)) { 1416 f = fopen(p, "r"); 1417 sR = fread(b, 1, 1024, f); 1418 while (sR != 0) { 1419 fwrite(b, 1, sR, stdout); 1420 sR = fread(b, 1, 1024, f); 1421 } 1422 fclose(f); 1423 } 1424 1425 free(dest); 1426 freeList((void **)f_l); 1427 } 1428 else { 1429 p = malloc(strlen(offHelpers_offStore()) + strlen(file) + 1 + 1); 1430 sprintf(p, "%s/%s", offHelpers_offStore(), file); 1431 if (offHelpers_checkIntegrity(p)) { 1432 f = fopen(p, "r"); 1433 sR = fread(b, 1, 1024, f); 1434 while (sR != 0) { 1435 fwrite(b, 1, sR, stdout); 1436 sR = fread(b, 1, 1024, f); 1437 } 1438 fclose(f); 1439 } 1440 } 1441 1442 free(p); 1443 } 1444 1445 1446 void transportRsyncSend(char *file) { 1447 // create file directories in store 1448 char **f_l = NULL; 1449 char *p = NULL; 1450 char *pem = NULL; 1451 char *params = NULL; 1452 char *options = NULL; 1453 char *options2 = NULL; 1454 char *tmp = NULL; 1455 1456 f_l = split(file, "/"); 1457 p = malloc(strlen(f_l[0]) + strlen(f_l[1]) + 1 + 1); 1458 sprintf(p, "%s/%s", f_l[0], f_l[1]); 1459 offHelpers_mkdirStore(p); 1460 free(p); 1461 1462 options = strdup(offHelpers_offRsyncOptions()); 1463 1464 // set pem or not? check rsyncoptions 1465 // find _i index in options 1466 tmp = strstr(options, " _i"); 1467 if (tmp != NULL) { 1468 if ((offHelpers_offPem() == NULL) || (strEq(offHelpers_offPem(), "offNoValue"))) { 1469 options2 = strdup(options); 1470 } 1471 else { 1472 tmp[1] = 0; 1473 options2 = malloc(strlen(options) + strlen(offHelpers_offPem()) + strlen(tmp+3) + 1 + 0); 1474 sprintf(options2, "%s%s%s", options, offHelpers_offPem(), tmp+3); 1475 } 1476 } 1477 else { 1478 options2 = strdup(options); 1479 } 1480 1481 char *dest; 1482 1483 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1484 sprintf(p, "%s/%s", offHelpers_objectPath(), file); 1485 dest = malloc(strlen(offHelpers_offScp()) + strlen(file) + 1 + 1); 1486 sprintf(dest, "%s/%s", offHelpers_offScp(), file); 1487 1488 params = malloc(strlen(options2) + strlen(p) + strlen(dest) + 1 + 2); 1489 sprintf(params, "%s %s %s", options2, p, dest); 1490 1491 exec(rsync, params); 1492 1493 free(p); 1494 free(dest); 1495 free(pem); 1496 free(params); 1497 free(options); 1498 free(options2); 1499 } 1500 1501 void transportRsyncReceive(char *file) { 1502 char *p = NULL; 1503 char **f_l = NULL; 1504 DIR *d = NULL; 1505 char *pem = NULL; 1506 char *params = NULL; 1507 char *options = NULL; 1508 char *options2 = NULL; 1509 char *tmp = NULL; 1510 1511 // create file directories in cache 1512 f_l = split(file, "/"); 1513 p = malloc(strlen(offHelpers_objectPath()) + strlen(f_l[0]) + strlen(f_l[1]) + 1 + 2); 1514 sprintf(p, "%s/%s/%s", offHelpers_objectPath(), f_l[0], f_l[1]); 1515 d = opendir(p);; 1516 if (d == NULL) { 1517 mkdirParents(p); 1518 } 1519 free(p); 1520 freeList((void **)f_l); 1521 1522 1523 options = strdup(offHelpers_offRsyncOptions()); 1524 1525 // set pem or not? check rsyncoptions 1526 // find _i index in options 1527 tmp = strstr(options, " _i"); 1528 if (tmp != NULL) { 1529 if ((offHelpers_offPem() == NULL) || (strEq(offHelpers_offPem(), "offNoValue"))) { 1530 options2 = strdup(options); 1531 } 1532 else { 1533 tmp[1] = 0; 1534 options2 = malloc(strlen(options) + strlen(offHelpers_offPem()) + strlen(tmp+3) + 1 + 0); 1535 sprintf(options2, "%s%s%s", options, offHelpers_offPem(), tmp+3); 1536 } 1537 } 1538 else { 1539 options2 = strdup(options); 1540 } 1541 1542 char *dest; 1543 1544 dest = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1545 sprintf(dest, "%s/%s", offHelpers_objectPath(), file); 1546 p = malloc(strlen(offHelpers_offScp()) + strlen(file) + 1 + 1); 1547 sprintf(p, "%s/%s", offHelpers_offScp(), file); 1548 1549 params = malloc(strlen(options2) + strlen(p) + strlen(dest) + 1 + 2); 1550 sprintf(params, "%s %s %s", options2, p, dest); 1551 1552 exec(rsync, params); 1553 1554 free(p); 1555 free(dest); 1556 free(pem); 1557 free(params); 1558 free(options); 1559 free(options2); 1560 1561 // transform 1562 int sR; 1563 char b[1024]; 1564 FILE *f; 1565 1566 if ((strEq(offHelpers_transform(), "enable")) && (offHelpers_transformFrom() != NULL)) { 1567 transport_transformFrom(file); 1568 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 8); 1569 sprintf(p, "%s/../tmp/%s", offHelpers_objectPath(), file); 1570 if (offHelpers_checkIntegrity(p)) { 1571 f = fopen(p, "r"); 1572 sR = fread(b, 1, 1024, f); 1573 while (sR != 0) { 1574 fwrite(b, 1, sR, stdout); 1575 sR = fread(b, 1, 1024, f); 1576 } 1577 fclose(f); 1578 } 1579 } 1580 else { 1581 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1582 sprintf(p, "%s/%s", offHelpers_objectPath(), file); 1583 if (offHelpers_checkIntegrity(p)) { 1584 f = fopen(p, "r"); 1585 sR = fread(b, 1, 1024, f); 1586 while (sR != 0) { 1587 fwrite(b, 1, sR, stdout); 1588 sR = fread(b, 1, 1024, f); 1589 } 1590 fclose(f); 1591 } 1592 } 1593 1594 free(p); 1595 } 1596 1597 1598 void transportScpSend(char *file) { 1599 // create file directories in store 1600 char **f_l = NULL; 1601 char *p = NULL; 1602 char *pem = NULL; 1603 char *params = NULL; 1604 char **h_l = NULL; 1605 1606 f_l = split(file, "/"); 1607 p = malloc(strlen(f_l[0]) + strlen(f_l[1]) + 1 + 1); 1608 sprintf(p, "%s/%s", f_l[0], f_l[1]); 1609 offHelpers_mkdirStore(p); 1610 free(p); 1611 1612 h_l = offHelpers_getSSHConfig(); 1613 1614 // setup ssh/scp private key 1615 if ((offHelpers_offPem() == NULL) || (strEq(offHelpers_offPem(), "offNoValue"))) { 1616 pem = strdup(""); 1617 } 1618 else { 1619 pem = malloc(strlen(offHelpers_offPem()) + 1 + 3); 1620 sprintf(pem, "-i %s", offHelpers_offPem()); 1621 } 1622 1623 char *dest; 1624 1625 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1626 sprintf(p, "%s/%s", offHelpers_objectPath(), file); 1627 dest = malloc(strlen(h_l[0]) + strlen(h_l[1]) + strlen(file) + 1 + 2); 1628 sprintf(dest, "%s:%s/%s", h_l[0], h_l[1], file); 1629 1630 if (h_l[2] == NULL) { 1631 params = malloc(strlen(offHelpers_offScpOptions()) + strlen(pem) + strlen(p) + strlen(dest) + 1 + 3); 1632 sprintf(params, "%s %s %s %s", offHelpers_offScpOptions(), pem, p, dest); 1633 } 1634 else { 1635 params = malloc(strlen(offHelpers_offScpOptions()) + strlen(pem) + strlen(h_l[2]) + strlen(p) + strlen(dest) + 1 + 7); 1636 sprintf(params, "%s %s -P %s %s %s", offHelpers_offScpOptions(), pem, h_l[2], p, dest); 1637 } 1638 1639 exec(scp, params); 1640 1641 free(p); 1642 free(dest); 1643 freeList((void **) h_l); 1644 free(pem); 1645 free(params); 1646 } 1647 1648 void transportScpReceive(char *file) { 1649 char *p = NULL; 1650 char **f_l = NULL; 1651 DIR *d = NULL; 1652 char **h_l = NULL; 1653 char *pem = NULL; 1654 char *params = NULL; 1655 1656 // create file directories in cache 1657 f_l = split(file, "/"); 1658 p = malloc(strlen(offHelpers_objectPath()) + strlen(f_l[0]) + strlen(f_l[1]) + 1 + 2); 1659 sprintf(p, "%s/%s/%s", offHelpers_objectPath(), f_l[0], f_l[1]); 1660 d = opendir(p);; 1661 if (d == NULL) { 1662 mkdirParents(p); 1663 } 1664 free(p); 1665 freeList((void **)f_l); 1666 1667 h_l = offHelpers_getSSHConfig(); 1668 1669 // setup ssh/scp private key 1670 if ((offHelpers_offPem() == NULL) || (strEq(offHelpers_offPem(), "offNoValue"))) { 1671 pem = strdup(""); 1672 } 1673 else { 1674 pem = malloc(strlen(offHelpers_offPem()) + 1 + 3); 1675 sprintf(pem, "-i %s", offHelpers_offPem()); 1676 } 1677 1678 char *dest; 1679 1680 dest = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1681 sprintf(dest, "%s/%s", offHelpers_objectPath(), file); 1682 p = malloc(strlen(h_l[0]) + strlen(h_l[1]) + strlen(file) + 1 + 2); 1683 sprintf(p, "%s:%s/%s", h_l[0], h_l[1], file); 1684 1685 if (h_l[2] == NULL) { 1686 params = malloc(strlen(offHelpers_offScpOptions()) + strlen(pem) + strlen(p) + strlen(dest) + 1 + 3); 1687 sprintf(params, "%s %s %s %s", offHelpers_offScpOptions(), pem, p, dest); 1688 } 1689 else { 1690 params = malloc(strlen(offHelpers_offScpOptions()) + strlen(pem) + strlen(h_l[2]) + strlen(p) + strlen(dest) + 1 + 7); 1691 sprintf(params, "%s %s -P %s %s %s", offHelpers_offScpOptions(), pem, h_l[2], p, dest); 1692 } 1693 1694 exec(scp, params); 1695 1696 free(p); 1697 free(dest); 1698 freeList((void **) h_l); 1699 free(pem); 1700 free(params); 1701 1702 // transform 1703 int sR; 1704 char b[1024]; 1705 FILE *f; 1706 1707 if ((strEq(offHelpers_transform(), "enable")) && (offHelpers_transformFrom() != NULL)) { 1708 transport_transformFrom(file); 1709 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 8); 1710 sprintf(p, "%s/../tmp/%s", offHelpers_objectPath(), file); 1711 if (offHelpers_checkIntegrity(p)) { 1712 f = fopen(p, "r"); 1713 sR = fread(b, 1, 1024, f); 1714 while (sR != 0) { 1715 fwrite(b, 1, sR, stdout); 1716 sR = fread(b, 1, 1024, f); 1717 } 1718 fclose(f); 1719 } 1720 } 1721 else { 1722 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1723 sprintf(p, "%s/%s", offHelpers_objectPath(), file); 1724 if (offHelpers_checkIntegrity(p)) { 1725 f = fopen(p, "r"); 1726 sR = fread(b, 1, 1024, f); 1727 while (sR != 0) { 1728 fwrite(b, 1, sR, stdout); 1729 sR = fread(b, 1, 1024, f); 1730 } 1731 fclose(f); 1732 } 1733 } 1734 1735 free(p); 1736 } 1737 1738 1739 void transportHttpSend(char *file) { 1740 char *p = NULL; 1741 1742 p = malloc(strlen(file) + 1 + 48); 1743 sprintf(p, "Http mode is read-only: %s is stored in cache only", file); 1744 offLogRepo(p); 1745 free(p); 1746 } 1747 1748 void transportHttpReceive(char *file) { 1749 char *p = NULL; 1750 char **f_l = NULL; 1751 DIR *d = NULL; 1752 1753 // create file directories in cache 1754 f_l = split(file, "/"); 1755 p = malloc(strlen(offHelpers_objectPath()) + strlen(f_l[0]) + strlen(f_l[1]) + 1 + 2); 1756 sprintf(p, "%s/%s/%s", offHelpers_objectPath(), f_l[0], f_l[1]); 1757 d = opendir(p);; 1758 if (d == NULL) { 1759 mkdirParents(p); 1760 } 1761 free(p); 1762 freeList((void **)f_l); 1763 1764 p = malloc(strlen(offHelpers_offCurlOptions()) + strlen(offHelpers_objectPath()) + strlen(file) + strlen(offHelpers_offHttp()) + strlen(file) + 1 + 4); 1765 sprintf(p, "%s %s/%s %s/%s", offHelpers_offCurlOptions(), offHelpers_objectPath(), file, offHelpers_offHttp(), file); 1766 exec(curl, p); 1767 free(p); 1768 1769 // transform 1770 int sR; 1771 char b[1024]; 1772 FILE *f; 1773 1774 if ((strEq(offHelpers_transform(), "enable")) && (offHelpers_transformFrom() != NULL)) { 1775 transport_transformFrom(file); 1776 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 8); 1777 sprintf(p, "%s/../tmp/%s", offHelpers_objectPath(), file); 1778 if (offHelpers_checkIntegrity(p)) { 1779 f = fopen(p, "r"); 1780 sR = fread(b, 1, 1024, f); 1781 while (sR != 0) { 1782 fwrite(b, 1, sR, stdout); 1783 sR = fread(b, 1, 1024, f); 1784 } 1785 fclose(f); 1786 } 1787 } 1788 else { 1789 p = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1790 sprintf(p, "%s/%s", offHelpers_objectPath(), file); 1791 if (offHelpers_checkIntegrity(p)) { 1792 f = fopen(p, "r"); 1793 sR = fread(b, 1, 1024, f); 1794 while (sR != 0) { 1795 fwrite(b, 1, sR, stdout); 1796 sR = fread(b, 1, 1024, f); 1797 } 1798 fclose(f); 1799 } 1800 } 1801 1802 free(p); 1803 } 1804 1805 void offHelpers_setTransport(char *mode ) { 1806 char *m = NULL; 1807 1808 // set send and receive functions for transport 1809 // copy, scp 1810 1811 // use mode from config or from parameter 1812 if (strEq(mode, "config")) { 1813 m = strdup(offHelpers_offMode()); 1814 } 1815 else { 1816 m = mode; 1817 } 1818 1819 // copy mode 1820 if (strEq(m, "copy")) { 1821 transport.send = transportCopySend; 1822 transport.receive = transportCopyReceive; 1823 } 1824 1825 // rsync mode 1826 else if (strEq(m, "rsync")) { 1827 transport.send = transportRsyncSend; 1828 transport.receive = transportRsyncReceive; 1829 } 1830 1831 // scp mode 1832 else if (strEq(m, "scp")) { 1833 transport.send = transportScpSend; 1834 transport.receive = transportScpReceive; 1835 } 1836 1837 // http mode 1838 else if (strEq(m, "http")) { 1839 transport.send = transportHttpSend; 1840 transport.receive = transportHttpReceive; 1841 } 1842 1843 if (m != mode) { 1844 free(m); 1845 } 1846 } 1847 // 1848 // // s3 mode 1849 // else if mode == 's3' 1850 // transport['send'] = (file) -> 1851 // AWS = require 'aws-sdk' 1852 // s3 = new AWS.S3({region: offHelpers.s3Region(), signatureVersion: 'v4'}) 1853 // 1854 // // upload to s3 1855 // upParams = {Bucket: offHelpers.s3Bucket(), Key: file, Body: ''} 1856 // fileStream = fs.createReadStream(offHelpers.objectPath() + '/' + file) 1857 // upParams.Body = fileStream 1858 // s3.upload(upParams, (err, data) -> 1859 // // TODO log eventual error 1860 // return 1861 // ) 1862 // 1863 // return 1864 // transport['receive'] = (file) -> 1865 // AWS = require 'aws-sdk' 1866 // s3 = new AWS.S3({region: offHelpers.s3Region(), signatureVersion: 'v4'}) 1867 // 1868 // // create file directories in cache 1869 // f_l = file.split '/' 1870 // if fs.existsSync(offHelpers.objectPath() + '/' + f_l[0] + '/' + f_l[1]) == false 1871 // mkdirParents offHelpers.objectPath() + '/' + f_l[0] + '/' + f_l[1] 1872 // 1873 // // download from s3 1874 // dlParams = {Bucket: offHelpers.s3Bucket(), Key: file} 1875 // fileStream = fs.createWriteStream(offHelpers.objectPath() + '/' + file) 1876 // fileStream.on('finish', -> 1877 // // transfer is finished, the complete file is in the cache 1878 // // transform 1879 // if offHelpers.transform() == 'enable' and offHelpers.transformFrom() != '' 1880 // transport['transformFrom'](file) 1881 // if offHelpers.checkIntegrity offHelpers.objectPath() + '/../tmp/' + file 1882 // readStream = fs.createReadStream(offHelpers.objectPath() + '/../tmp/' + file) 1883 // readStream.pipe(process.stdout) 1884 // else 1885 // if offHelpers.checkIntegrity offHelpers.objectPath() + '/' + file 1886 // readStream = fs.createReadStream(offHelpers.objectPath() + '/' + file) 1887 // readStream.pipe(process.stdout) 1888 // return 1889 // ) 1890 // s3.getObject(dlParams, (err, data) -> 1891 // // TODO log eventual error 1892 // return 1893 // ).on('httpData', (chunk) -> 1894 // fileStream.write chunk 1895 // return 1896 // ).on('httpDone', -> 1897 // fileStream.end() 1898 // return 1899 // ) 1900 // return 1901 // return 1902 1903 char **offHelpers_getOffFilePath(char *offFile) { 1904 char **r = NULL; 1905 char tmp[6]; 1906 1907 tmp[0] = offFile[0]; 1908 tmp[1] = offFile[1]; 1909 tmp[2] = '/'; 1910 tmp[3] = offFile[2]; 1911 tmp[4] = offFile[3]; 1912 tmp[5] = 0; 1913 1914 // [offFile.slice(0,2) + '/' + offFile.slice(2,4) + '/' + offFile, offFile.slice(0,2) + '/' + offFile.slice(2,4)] 1915 r = malloc(3 * sizeof(int *)); 1916 r[2] = NULL; 1917 r[0] = malloc(strlen(tmp) + strlen(offFile) + 1 + 1); 1918 sprintf(r[0], "%s/%s", tmp, offFile); 1919 r[1] = strdup(tmp); 1920 return(r); 1921 } 1922 1923 1924 1925 ////// 1926 // core 1927 ////// 1928 1929 // transport functions 1930 1931 void send(char *src) { 1932 1933 // to be initialized by setTransport 1934 printf("SEND %s", src); 1935 printf("\n"); 1936 } 1937 1938 void receive(char *src) { 1939 1940 // to be initialized by setTransport 1941 printf("RECEIVE %s", src); 1942 printf("\n"); 1943 } 1944 1945 void transport_transformFrom(char *file) { 1946 // transform file in objectPath to objectPath/../tmp/file 1947 // create directories in tmp 1948 char *offFile = NULL; 1949 char **offFilePath = NULL; 1950 char *tmp = NULL; 1951 DIR *d = NULL; 1952 char *cmd = NULL; 1953 char *cmd2 = NULL; 1954 char *p1 = NULL; 1955 char *p2 = NULL; 1956 1957 offFile = strdup(basename(file)); 1958 offFilePath = offHelpers_getOffFilePath(offFile); 1959 1960 tmp = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[1]) + 1 + 8); 1961 sprintf(tmp, "%s/../tmp/%s", offHelpers_objectPath(), offFilePath[1]); 1962 d = opendir(tmp); 1963 if (d == NULL) { 1964 // create the file directory 1965 mkdirParents(tmp); 1966 } 1967 free(tmp); 1968 1969 cmd = strdup(offHelpers_transformFrom()); 1970 1971 p1 = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 1); 1972 sprintf(p1, "%s/%s", offHelpers_objectPath(), file); 1973 // find _1 index in cmd 1974 tmp = strstr(cmd, " _1"); 1975 if (tmp != NULL) { 1976 tmp[1] = 0; 1977 } 1978 cmd2 = malloc(strlen(cmd) + strlen(p1) + strlen(tmp+3) + 1 + 0); 1979 sprintf(cmd2, "%s%s%s", cmd, p1, tmp+3); 1980 free(p1); 1981 free(cmd); 1982 1983 p2 = malloc(strlen(offHelpers_objectPath()) + strlen(file) + 1 + 8); 1984 sprintf(p2, "%s/../tmp/%s", offHelpers_objectPath(), file); 1985 // find _2 and replace 1986 tmp = strstr(cmd2, " _2"); 1987 if (tmp != NULL) { 1988 tmp[1] = 0; 1989 } 1990 cmd = malloc(strlen(cmd2) + strlen(p2) + strlen(tmp+3) + 1 + 0); 1991 sprintf(cmd, "%s%s%s", cmd2, p2, tmp+3); 1992 free(p2); 1993 //print cmd 1994 free(cmd2); 1995 freeList((void **)offFilePath); 1996 offFilePath = execOut(cmd); 1997 freeList((void **)offFilePath); 1998 free(offFile); 1999 free(cmd); 2000 } 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 void thisrepo(cmdSetF_t cmd) { 2011 2012 if ((argc > 2) && (strEq(argv[2], "thisrepo"))) { 2013 cmd(gitConfig_setThisRepo); 2014 return; 2015 } 2016 cmd(gitConfig_set); 2017 } 2018 2019 2020 2021 enum { installH, modeH, storeH, scpH, httpH, curlH, integrityH, pemH, sshoptionsH, scpoptionsH, rsyncoptionsH, scpuserH, trackH, configAlwaysH, s3regionH, s3bucketH, transformH, transformToH, transformFromH, cleanH, prepushH, smudgeH, copyToH, pushH, clearAllH, caH, clearCacheH, ccH, clearStoreH, csH, clearTmpH, ctH, defaultsH, envH, helpH, lastH }; 2022 char* COMMAND_HELP[36] = { "git off install [thisrepo]\n setup git config (default global)\n thisrepo sets up config in current repo", "git off mode [thisrepo] [copy|rsync|scp|http|s3]\n set/show git off mode", "git off store [thisrepo] [path]\n set/show git off store path for copy mode", "git off scp [thisrepo] [host]\n setup scp config\n host has format host:path, user@host:path, user@host:port/path\n Example: localhost:/tmp/offStore", "git off http [thisrepo] [host]\n setup http config\n host has format http://host/path\n Example http://localhost/offStore", "git off curl [thisrepo] [options]\n setup curl config", "git off integrity [thisrepo] [enable|disable]\n set/show git off integrity.\n when enabled, the SHA of the file received from the store is\n checked again the SHA of the original file", "git off pem [thisrepo] [pathToPrivateKey]\n set/show git off pem.\n off.pem is the private key for ssh and scp\n set \"offNoValue\" to set an empty value (useful when there are multiple configs)", "git off sshoptions [thisrepo] [options]\n set/show git off sshoptions", "git off scpoptions [thisrepo] [options]\n set/show git off scpoptions", "git off rsyncoptions [thisrepo] [options]\n set/show git off rsyncoptions", "git off scpuser [thisrepo] [username]\n setup scp username config", "git off track\n setup gitattribute filters\n example: git off track \"*.bin\"\n without parameter, list git off attributes\n calls git off install", "git off configAlways [\"\"|GIT_OFF_CONFIG|repo|global]\n \"\" disable configAlways\n GIT_OFF_CONFIG load all configurations from $GIT_OFF_CONFIG\n repo load all configurations from current git repo\n global load all configurations from global git config\n set \"offNoValue\" to set an empty value", "git off s3region [thisrepo] [region]\n setup amazon s3 region for the bucket", "git off s3bucket [thisrepo] [bucket]\n setup amazon s3 bucket", "git off transform [thisrepo] [enable|disable]\n enable transform in clean and smudge filters", "git off transformTo [thisrepo] [\"cmd _1 _2\"]\n setup transform command for clear filter\n When the command is empty the regular transport is performed", "git off transformFrom [thisrepo] [\"cmd _1 _2\"]\n setup transform command for smudge filter\n When the command is empty the regular transport is performed", "git off clean\n internal filter\n dont use directly", "git off pre-push\n internal filter\n dont use directly", "git off smudge\n internal filter\n dont use directly", "git off copyTo [copy|rsync|scp|s3]\n copy cache to store for specified mode", "git off push\n copy cache to store for selected mode", "git off clearAll\n delete store, cache and log", "git off ca\n delete store, cache and log", "git off clearCache\n delete cache in current git", "git off cc\n delete cache in current git", "git off clearStore\n delete store", "git off cs\n delete store", "git off clearTmp\n delete tmp in git off cache\n Useful when transform is enabled", "git off ct\n delete tmp in git off cache\n Useful when transform is enabled", "git off defaults\n shows first time config", "git off env\n shows config", "git off help [cmd]\n git off help. Run git off help command to get help for a specific command.", "not a command" }; 2023 2024 enum { installC, modeC, storeC, scpC, httpC, curlC, integrityC, pemC, sshoptionsC, scpoptionsC, rsyncoptionsC, scpuserC, trackC, configAlwaysC, s3regionC, s3bucketC, transformC, transformToC, transformFromC, cleanC, prepushC, smudgeC, copyToC, pushC, clearAllC, caC, clearCacheC, ccC, clearStoreC, csC, clearTmpC, ctC, defaultsC, envC, helpC, lastC }; 2025 char* COMMAND_MAP[36] = { "install", "mode", "store", "scp", "http", "curl", "integrity", "pem", "sshoptions", "scpoptions", "rsyncoptions", "scpuser", "track", "configAlways", "s3region", "s3bucket", "transform", "transformTo", "transformFrom", "clean", "pre-push", "smudge", "copyTo", "push", "clearAll", "ca", "clearCache", "cc", "clearStore", "cs", "clearTmp", "ct", "defaults", "env", "help", "not a command" }; 2026 2027 enum { installG, modeG, storeG, scpG, httpG, curlG, integrityG, pemG, sshoptionsG, scpoptionsG, rsyncoptionsG, scpuserG, trackG, configAlwaysG, s3regionG, s3bucketG, transformG, transformToG, transformFromG, cleanG, prepushG, smudgeG, copyToG, pushG, clearAllG, caG, clearCacheG, ccG, clearStoreG, csG, clearTmpG, ctG, defaultsG, envG, helpG, lastG }; 2028 char* COMMAND_GITCONFIG[36] = { "empty", "off.mode", "off.store", "off.scphost", "off.http", "off.curloptions", "off.integrity", "off.pem", "off.sshoptions", "off.scpoptions", "off.rsyncoptions", "off.scpuser", "empty", "off.configAlways", "off.s3region", "off.s3bucket", "off.transform", "off.transformTo", "off.transformFrom", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "empty", "not a command" }; 2029 2030 // functions called for commands 2031 typedef void (*cmdF_t)(); 2032 2033 // lastC is the index of last element 2034 cmdF_t COMMAND_FUNC[lastC + 1 ]; 2035 2036 // helpers called for commands that read a git config 2037 typedef char *(*cmdH_t)(); 2038 cmdH_t COMMAND_HELPERS[lastC + 1 ]; 2039 2040 int findCommand(char *p) { 2041 int i; 2042 2043 for (i=0; i < lastC ;i++) { 2044 if (strEq(p, COMMAND_MAP[i])) { 2045 break; 2046 } 2047 } 2048 if (i == lastC) { 2049 i = -1; 2050 } 2051 return(i); 2052 } 2053 2054 void showAllCommandsHelp() { 2055 int i; 2056 2057 for (i=0; i < lastH ;i++) { 2058 printf("%s\n", COMMAND_HELP[i]); 2059 } 2060 } 2061 2062 2063 2064 2065 // command line functions 2066 // localSetup: setup current git 2067 // install: setup git config (default global) 2068 // mode: set/show git off mode 2069 // scp: setup scp config 2070 // scpuser: setup scp username config 2071 // track: setup gitattribute filters 2072 // clean: replace files handled by git off with reference 2073 // prepush: read stdin and calls push 2074 // push: copy objects to off.store 2075 // smudge: copy objects from off.store for files handled by git off 2076 // clearAll: delete store, cache in current git and log 2077 // clearCache: delete cache in current git 2078 // clearStore: delete store 2079 // defaults: show first time config (offDEFAULTS) 2080 // env: show config 2081 void offCommands_localSetup() { 2082 // setup current git 2083 // create off directories in current .git 2084 // install pre-push hooks 2085 char *hook = NULL; 2086 2087 mkdirParents(offHelpers_objectPath()); 2088 2089 hook = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 20); 2090 sprintf(hook, "%s/.git/hooks/pre-push", offHelpers_gitRepoRoot()); 2091 if (access(hook, F_OK) == -1) { 2092 FILE *f; 2093 f = fopen(hook, "w"); 2094 fprintf(f, "%s\n", offDEFAULTS[prePushD]); 2095 fclose(f); 2096 chmod(hook, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 2097 } 2098 // error disabled because localSetup is run many times (called from clean and smudge) 2099 // else 2100 // console.error hook.red.bold + ' already exists. Skipping pre-push hook setup.'.red.bold 2101 // process.exit(1) 2102 free(hook); 2103 } 2104 2105 void offCommands_install(gConfig_set_t setF ) { 2106 2107 // setup git config 2108 // create off.store 2109 2110 offCommands_localSetup(); 2111 2112 // setup config only if not already set 2113 if ((gitConfig_get("filter.off.clean") == NULL) || (setF != gitConfig_set)) { 2114 if (setF == gitConfig_setThisRepo) { 2115 gitConfig_setLocal("filter.off.clean","git off clean %f"); 2116 } 2117 else { 2118 setF("filter.off.clean","git off clean %f"); 2119 } 2120 } 2121 if ((gitConfig_get("filter.off.smudge") == NULL) || (setF != gitConfig_set)) { 2122 if (setF == gitConfig_setThisRepo) { 2123 gitConfig_setLocal("filter.off.smudge","git off smudge %f"); 2124 } 2125 else { 2126 setF("filter.off.smudge","git off smudge %f"); 2127 } 2128 } 2129 if ((offHelpers_log() == NULL) || (setF != gitConfig_set)) { 2130 // log always in global config 2131 gitConfig_set("off.log",offDEFAULTS[logD]); 2132 } 2133 2134 if ((offHelpers_offMode() == NULL) || (setF != gitConfig_set)) { 2135 setF("off.mode", offDEFAULTS[modeD]); 2136 } 2137 if ((offHelpers_offIntegrity() == NULL) || (setF != gitConfig_set)) { 2138 setF("off.integrity", offDEFAULTS[integrityD]); 2139 } 2140 if ((offHelpers_offPem() == NULL) || (setF != gitConfig_set)) { 2141 setF("off.pem", offDEFAULTS[pemD]); 2142 } 2143 if ((offHelpers_offScp() == NULL) || (setF != gitConfig_set)) { 2144 setF("off.scphost", offDEFAULTS[scpHostD]); 2145 } 2146 if ((offHelpers_offScpUser() == NULL) || (setF != gitConfig_set)) { 2147 setF("off.scpuser", offDEFAULTS[scpUserD]); 2148 } 2149 if ((offHelpers_offSshOptions() == NULL) || (setF != gitConfig_set)) { 2150 setF("off.sshoptions", offDEFAULTS[sshOptionsD]); 2151 } 2152 if ((offHelpers_offScpOptions() == NULL) || (setF != gitConfig_set)) { 2153 setF("off.scpoptions", offDEFAULTS[scpOptionsD]); 2154 } 2155 if ((offHelpers_offRsyncOptions() == NULL) || (setF != gitConfig_set)) { 2156 setF("off.rsyncoptions", offDEFAULTS[rsyncOptionsD]); 2157 } 2158 if ((offHelpers_offStore() == NULL) || (setF != gitConfig_set)) { 2159 setF("off.store", offDEFAULTS[storeD]); 2160 } 2161 if ((offHelpers_offHttp() == NULL) || (setF != gitConfig_set)) { 2162 setF("off.http", offDEFAULTS[httpD]); 2163 } 2164 if ((offHelpers_offCurlOptions() == NULL) || (setF != gitConfig_set)) { 2165 setF("off.curloptions", offDEFAULTS[curlOptionsD]); 2166 } 2167 if ((offHelpers_offConfigAlways() == NULL) || (setF != gitConfig_set)) { 2168 setF("off.configAlways", offDEFAULTS[configAlwaysD]); 2169 } 2170 if ((offHelpers_s3Region() == NULL) || (setF != gitConfig_set)) { 2171 setF("off.s3Region", offDEFAULTS[s3RegionD]); 2172 } 2173 if ((offHelpers_s3Bucket() == NULL) || (setF != gitConfig_set)) { 2174 setF("off.s3Bucket", offDEFAULTS[s3BucketD]); 2175 } 2176 if ((offHelpers_transform() == NULL) || (setF != gitConfig_set)) { 2177 setF("off.transform", offDEFAULTS[transformD]); 2178 } 2179 if ((offHelpers_transformTo() == NULL) || (setF != gitConfig_set)) { 2180 setF("off.transformTo", offDEFAULTS[transformToD]); 2181 } 2182 if ((offHelpers_transformFrom() == NULL) || (setF != gitConfig_set)) { 2183 setF("off.transformFrom", offDEFAULTS[transformFromD]); 2184 } 2185 2186 // create off.store 2187 2188 if (strEq(runtimeConfig[offMode], "copy")) { 2189 mkdirParents(runtimeConfig[offStore]); 2190 } 2191 2192 if (strEq(runtimeConfig[offMode], "scp") || strEq(runtimeConfig[offMode], "rsync")) { 2193 offHelpers_mkdirStore(""); 2194 } 2195 } 2196 2197 void offCommands_track() { 2198 FILE* f = NULL; 2199 2200 // setup gitattribute filters in current folder 2201 // list current git off attributes when there is no parameter 2202 if (argc > 2) { 2203 char *fileName; 2204 char *line; 2205 offCommands_install_setF(); 2206 fileName = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 15); 2207 sprintf(fileName, "%s/.gitattributes", offHelpers_gitRepoRoot()); 2208 f = fopen(fileName, "a"); 2209 free(fileName); 2210 line = malloc(strlen(argv[2]) + 1 + 17); 2211 sprintf(line, "%s filter=off -text", argv[2]); 2212 fprintf(f, "%s\n", line); 2213 free(line); 2214 fclose(f); 2215 } 2216 else { 2217 // list current git off attributes 2218 char *cmd; 2219 char **list; 2220 int i; 2221 2222 cmd = malloc(strlen(externalHelpers[listAttr]) + strlen(offHelpers_gitRepoRoot()) + 1 + 20); 2223 sprintf(cmd, "%s `cd %s; git ls-files`", externalHelpers[listAttr], offHelpers_gitRepoRoot()); 2224 list = execOut(cmd); 2225 free(cmd); 2226 2227 // gff/b.bin: filter: off 2228 if (list != NULL) { 2229 i = 0; 2230 while (list[i] != NULL) { 2231 // find string 2232 if (strstr(list[i], ": filter: off") != NULL) { 2233 printf("%s\n", list[i]); 2234 } 2235 i++; 2236 } 2237 } 2238 freeList((void **)list); 2239 } 2240 } 2241 2242 void offCommands_configAlways() { 2243 2244 if (!strEq(argv[argc-1], "configAlways")) { 2245 gitConfig_set(COMMAND_GITCONFIG[configAlwaysC], argv[argc-1]); 2246 } 2247 else { 2248 if (COMMAND_HELPERS[configAlwaysC]()) { 2249 // print when config is available 2250 printf("%s %s", COMMAND_GITCONFIG[configAlwaysC], COMMAND_HELPERS[configAlwaysC]()); 2251 printf("\n"); 2252 } 2253 else { 2254 printf("Not in config: %s", COMMAND_GITCONFIG[configAlwaysC]); 2255 printf("\n"); 2256 } 2257 } 2258 } 2259 2260 void offCommands_setGetGitConfig(gConfig_set_t setF) { 2261 int i; 2262 2263 i = findCommand(argv[1]); 2264 if ((argc > 2) && (!strEq(argv[argc-1], "thisrepo"))) { 2265 setF(COMMAND_GITCONFIG[i], argv[argc-1]); 2266 } 2267 else { 2268 if (COMMAND_HELPERS[i]()) { 2269 printf("%s %s", COMMAND_GITCONFIG[i], COMMAND_HELPERS[i]()); 2270 printf("\n"); 2271 } 2272 else { 2273 printf("Not in config: %s", COMMAND_GITCONFIG[i]); 2274 printf("\n"); 2275 } 2276 } 2277 } 2278 2279 void offCommands_clean() { 2280 char *file = NULL; 2281 uint64_t size; 2282 char **offFilePath = NULL; 2283 char *offFile = NULL; 2284 char *fileDir = NULL; 2285 char *filePath = NULL; 2286 DIR *d = NULL; 2287 char b[1024]; 2288 FILE *f = NULL; 2289 int sR; 2290 char *quotedFile = NULL; 2291 2292 // replace files handled by git off with reference 2293 // stdin is data from the working directory file 2294 // 2295 // create local setup in case the repo is freshly cloned 2296 // create file information (size, sha = git off filename) 2297 // copy stdin to git off cache in current git 2298 // transform input file 2299 // print git off ref to stdout for git 2300 2301 // create local setup in case the repo is freshly cloned 2302 offCommands_localSetup(); 2303 2304 // create file information (size, sha) 2305 file = argv[2]; 2306 //print file 2307 struct stat st; 2308 stat(file, &st); 2309 size = st.st_size; 2310 quotedFile = malloc(strlen(file) + 1 + 4); 2311 sprintf(quotedFile, "\"%s\"", file); 2312 offFile = exec(sha, quotedFile); 2313 free(quotedFile); 2314 offFilePath = offHelpers_getOffFilePath(offFile); 2315 2316 fileDir = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[1]) + 1 + 1); 2317 sprintf(fileDir, "%s/%s", offHelpers_objectPath(), offFilePath[1]); 2318 d = opendir(fileDir); 2319 if (d == NULL) { 2320 // create the file directory 2321 mkdirParents(fileDir); 2322 } 2323 2324 // copy stdin to git off cache in current git 2325 // clean runs during git add and git commit, do work only once 2326 filePath = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[0]) + 1 + 1); 2327 sprintf(filePath, "%s/%s", offHelpers_objectPath(), offFilePath[0]); 2328 if (access(filePath, F_OK) == -1) { 2329 // stream stdin to sha in git off cache 2330 f = fopen(filePath, "w"); 2331 2332 sR = fread(b, 1, 1024, stdin); 2333 while (sR != 0) { 2334 fwrite(b, 1, sR, f); 2335 sR = fread(b, 1, 1024, stdin); 2336 } 2337 fclose(f); 2338 2339 // all objects in cache are read-only 2340 chmod(filePath, S_IRUSR | S_IRGRP | S_IROTH); 2341 2342 // transform input file 2343 if ((strEq(offHelpers_transform(), "enable")) && (offHelpers_transformTo() != NULL)) { 2344 char *tmpDir; 2345 tmpDir = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[1]) + 1 + 8); 2346 sprintf(tmpDir, "%s/../tmp/%s", offHelpers_objectPath(), offFilePath[1]); 2347 d = opendir(tmpDir); 2348 if (d == NULL) { 2349 // create the file directory 2350 mkdirParents(tmpDir); 2351 } 2352 2353 // original file is moved to tmp 2354 // transformed file is stored in objectPath under the same name 2355 char *p; 2356 p = malloc(strlen(filePath) + strlen(offHelpers_objectPath()) + strlen(offFilePath[0]) + 1 + 9); 2357 sprintf(p, "%s %s/../tmp/%s", filePath, offHelpers_objectPath(), offFilePath[0]); 2358 exec(mv, p); 2359 free(p); 2360 2361 char *cmd; 2362 char *cmd2; 2363 char *p1; 2364 char *tmp; 2365 2366 cmd = strdup(offHelpers_transformTo()); 2367 2368 p1 = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[0]) + 1 + 8); 2369 sprintf(p1, "%s/../tmp/%s", offHelpers_objectPath(), offFilePath[0]); 2370 // find _1 index in cmd 2371 tmp = strstr(cmd, " _1"); 2372 if (tmp != NULL) { 2373 tmp[1] = 0; 2374 } 2375 cmd2 = malloc(strlen(cmd) + strlen(p1) + strlen(tmp+3) + 1 + 0); 2376 sprintf(cmd2, "%s%s%s", cmd, p1, tmp+3); 2377 free(p1); 2378 free(cmd); 2379 2380 // find _2 and replace 2381 tmp = strstr(cmd2, " _2"); 2382 if (tmp != NULL) { 2383 tmp[1] = 0; 2384 } 2385 cmd = malloc(strlen(cmd2) + strlen(filePath) + strlen(tmp+3) + 1 + 0); 2386 sprintf(cmd, "%s%s%s", cmd2, filePath, tmp+3); 2387 freeList((void **)offFilePath); 2388 offFilePath = execOut(cmd); 2389 free(cmd); 2390 free(tmpDir); 2391 } 2392 } 2393 else { 2394 // file already exists, discard data 2395 f = fopen("/dev/null", "w"); 2396 2397 sR = fread(b, 1, 1024, stdin); 2398 while (sR != 0) { 2399 fwrite(b, 1, sR, f); 2400 sR = fread(b, 1, 1024, stdin); 2401 } 2402 fclose(f); 2403 } 2404 2405 free(fileDir); 2406 free(filePath); 2407 2408 // print git off ref to stdout for git 2409 // ### git-off v1 sha:be3e02b60effe3eab232d5590a6a2e2c2c2f443b size:119 2410 char sst[20]; 2411 sprintf(sst,"%lu", size); 2412 char *tmp; 2413 tmp = malloc(strlen(offDEFAULTS[offSignatureD]) + strlen(offFile) + strlen(sst) + 1 + 6); 2414 sprintf(tmp, "%s%s size:%s", offDEFAULTS[offSignatureD], offFile, sst); 2415 printf("%s\n", tmp); 2416 free(tmp); 2417 freeList((void **)offFilePath); 2418 free(offFile); 2419 sR = 0; 2420 } 2421 2422 void offCommands_prepush() { 2423 size_t len; 2424 char* line = NULL; 2425 ssize_t read; 2426 char **list = NULL; 2427 int count = 0;; 2428 2429 // add offCommands_push function 2430 // read stdin and calls push 2431 // stdin (data from git) is a line with remoteName url localRef localSha remoteRef remoteSha 2432 2433 offHelpers_setTransport_mode(); 2434 2435 read = getline(&line, &len, stdin); 2436 if (read == -1) { 2437 // exit directly when there is nothing to do 2438 exit(EXIT_SUCCESS); 2439 } 2440 while (read != -1) { 2441 { 2442 char* pos = NULL; 2443 pos = strchr(line, '\n'); 2444 if (pos != NULL) 2445 *pos = '\0'; 2446 } 2447 if (list == NULL) { 2448 list = malloc(2 * sizeof(int *)); 2449 list[1] = NULL; 2450 } 2451 else { 2452 list = realloc(list, (count+2) * sizeof(int *)); 2453 if (list == NULL) { 2454 exit(EXIT_FAILURE); 2455 } 2456 list[count+1] = NULL; 2457 } 2458 list[count] = strdup(line); 2459 read = getline(&line, &len, stdin); 2460 count++; 2461 } 2462 2463 count = 0; 2464 while (list[count] != NULL) { 2465 offCommands_push(list[count]); 2466 count++; 2467 } 2468 free(line); 2469 freeList((void **)list); 2470 count = 0; 2471 } 2472 2473 void offCommands_push(char *line) { 2474 // copy objects to off.store 2475 // 2476 // set remoteName url localRef localSha remoteRef remoteSha 2477 // list missing commits in remote 2478 // list changed objects in missing commits 2479 // check header with git cat 2480 // copy git off objects to off.store 2481 char *remoteName = NULL; 2482 char *url = NULL; 2483 char *localRef = NULL; 2484 char *localSha = NULL; 2485 char *remoteRef = NULL; 2486 char *remoteSha = NULL; 2487 char **line_l = NULL; 2488 char **commitListToPush = NULL; 2489 char *cmd = NULL; 2490 int i; 2491 2492 // set remoteName url localRef localSha remoteRef remoteSha 2493 remoteName = argv[argc-2]; 2494 url = argv[argc-1]; 2495 2496 line_l = split(line, " "); 2497 localRef = line_l[0]; 2498 localSha = line_l[1]; 2499 remoteRef = line_l[2]; 2500 remoteSha = line_l[3]; 2501 2502 // list missing commits in remote 2503 // handle empty cloned repo 2504 if (strEq(remoteSha, "0000000000000000000000000000000000000000")) { 2505 // run git rev-list --max-parents=0 localSha 2506 // when an empty git was cloned. 2507 char *parent = "--max-parents=0";; 2508 cmd = malloc(strlen(externalHelpers[gitList]) + strlen(parent) + strlen(localSha) + 1 + 2); 2509 sprintf(cmd, "%s %s %s", externalHelpers[gitList], parent, localSha); 2510 } 2511 else { 2512 cmd = malloc(strlen(externalHelpers[gitList]) + strlen(localSha) + strlen(remoteSha) + 1 + 3); 2513 sprintf(cmd, "%s %s ^%s", externalHelpers[gitList], localSha, remoteSha); 2514 } 2515 commitListToPush = execOut(cmd); 2516 free(cmd); 2517 2518 // list changed objects in missing commits 2519 int commitListIndex = 0; 2520 while (commitListToPush[commitListIndex] != NULL) { 2521 2522 // list changes for commit sha 2523 char **objInfoList; 2524 cmd = malloc(strlen(externalHelpers[gitDff]) + strlen(commitListToPush[commitListIndex]) + 1 + 1); 2525 sprintf(cmd, "%s %s", externalHelpers[gitDff], commitListToPush[commitListIndex]); 2526 objInfoList = execOut(cmd); 2527 free(cmd); 2528 // :000000 100644 0000000000000000000000000000000000000000 23636079ef005f53e81066aaf092521d8f2346df A dsd 2529 // TODO filter according to .gitattributes, check files in filter only 2530 2531 int oi = 0; 2532 while (objInfoList[oi] != NULL) { 2533 char **objInfo; 2534 objInfo = split(objInfoList[oi], " "); 2535 2536 // only lines starting with : (the first line from git diff-tree is the sha) 2537 // dont consider deleted files 2538 if ((objInfoList[oi][0] == ':') && (objInfo[oiNAME][0] != 'D')) { 2539 2540 // check header with git cat 2541 2542 char *offRef; 2543 offRef = exec(gitCat, objInfo[oiOID]); 2544 2545 if (offRef && (strstr(offRef, offDEFAULTS[offSignatureD]) != NULL)) { 2546 2547 // copy git off objects to off.store 2548 // found an off reference 2549 // ### git-off v1 sha:be3e02b60effe3eab232d5590a6a2e2c2c2f443b size:119 b.bin 2550 2551 char **offRefS1; 2552 char **offRefS2; 2553 char *offFile; 2554 char **offFilePath; 2555 offRefS1 = split(offRef, ":"); 2556 offRefS2 = split(offRefS1[1], " "); 2557 offFile = offRefS2[0]; 2558 offFilePath = offHelpers_getOffFilePath(offFile); 2559 2560 transport.send(offFilePath[0]); 2561 freeList((void **)offFilePath); 2562 freeList((void **)offRefS1); 2563 freeList((void **)offRefS2); 2564 } 2565 free(offRef); 2566 } 2567 freeList((void **)objInfo); 2568 oi++; 2569 } 2570 freeList((void **)objInfoList); 2571 commitListIndex++; 2572 } 2573 2574 freeList((void **)commitListToPush); 2575 freeList((void **)line_l); 2576 2577 // test prevent push by issuing an error 2578 //exit(EXIT_FAILURE); 2579 } 2580 2581 void offCommands_smudge() { 2582 2583 // copy objects from off.store for files handled by git off 2584 // stdin is the data from the git repo 2585 // 2586 // load header 2587 // for git off object, replace git off reference with data from cache or off.store 2588 // for normal object, copy data from repo to stdout 2589 2590 offHelpers_setTransport_mode(); 2591 offCommands_localSetup(); 2592 2593 // load header 2594 char b[1024]; 2595 int sR; 2596 sR = fread(b, 1, strlen(offDEFAULTS[offSignatureD]) + offDEFAULTS_shaLength, stdin); 2597 if (sR == 0) { 2598 // error no data 2599 offLogRepo("smudge error: cant get data from stdin."); 2600 exit(EXIT_FAILURE); 2601 } 2602 2603 if (strncmp(b, offDEFAULTS[offSignatureD], strlen(offDEFAULTS[offSignatureD])) == 0) { 2604 // for git off object, replace git off reference with data from cache or off.store 2605 2606 b[strlen(offDEFAULTS[offSignatureD]) + offDEFAULTS_shaLength] = 0; 2607 char **header_l; 2608 char *offFile; 2609 char **offFilePath; 2610 header_l = split(b, ":"); 2611 offFile = header_l[1]; 2612 offFilePath = offHelpers_getOffFilePath(offFile); 2613 2614 // detect if file is already in cache 2615 char *filePath; 2616 filePath = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[0]) + 1 + 1); 2617 sprintf(filePath, "%s/%s", offHelpers_objectPath(), offFilePath[0]); 2618 if (access(filePath, F_OK) != -1) { 2619 // copy from cache 2620 FILE *fCache; 2621 if ((strEq(offHelpers_transform(), "enable")) && (offHelpers_transformFrom() != NULL)) { 2622 // transform file 2623 2624 transport_transformFrom(offFilePath[0]); 2625 2626 char *p; 2627 p = malloc(strlen(offHelpers_objectPath()) + strlen(offFilePath[0]) + 1 + 8); 2628 sprintf(p, "%s/../tmp/%s", offHelpers_objectPath(), offFilePath[0]); 2629 2630 fCache = fopen(p, "r"); 2631 2632 free(p); 2633 } 2634 else { 2635 fCache = fopen(filePath, "r"); 2636 } 2637 2638 sR = fread(b, 1, 1024, fCache); 2639 while (sR != 0) { 2640 fwrite(b, 1, sR, stdout); 2641 sR = fread(b, 1, 1024, fCache); 2642 } 2643 fclose(fCache); 2644 } 2645 else { 2646 // copy from off.store 2647 transport.receive(offFilePath[0]); 2648 } 2649 2650 free(filePath); 2651 freeList((void **)header_l); 2652 freeList((void **)offFilePath); 2653 } 2654 else { 2655 // for normal object, copy data from repo to stdout 2656 2657 //store header 2658 fwrite(b, 1, sR, stdout); 2659 2660 sR = fread(b, 1, 1024, stdin); 2661 while (sR != 0) { 2662 fwrite(b, 1, sR, stdout); 2663 sR = fread(b, 1, 1024, stdin); 2664 } 2665 } 2666 sR = 0; 2667 } 2668 2669 void offCommands_copyTo() { 2670 2671 // copy cache to store for argv[2] mode 2672 if (argc < 3) { 2673 printf("Choose a mode where to copy the cache"); 2674 printf("\n"); 2675 return; 2676 } 2677 2678 offHelpers_setTransport(argv[2]); 2679 offHelpers_copyTo(); 2680 } 2681 2682 void offCommands_pushTo() { 2683 2684 if (offHelpers_offMode() != NULL) { 2685 printf("mode: %s", offHelpers_offMode()); 2686 printf("\n"); 2687 offHelpers_setTransport(offHelpers_offMode()); 2688 offHelpers_copyTo(); 2689 } 2690 } 2691 2692 void offCommands_clearAll() { 2693 2694 // delete store, cache in current git and log 2695 offCommands_clearStore(); 2696 offCommands_clearCache(); 2697 rmAll(offHelpers_getLog()); 2698 } 2699 2700 void offCommands_clearCache() { 2701 char *p = NULL; 2702 2703 // delete cache in current git 2704 p = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 9); 2705 sprintf(p, "%s/.git/off", offHelpers_gitRepoRoot()); 2706 rmAll(p); 2707 free(p); 2708 } 2709 2710 void offCommands_clearStore() { 2711 2712 // delete store 2713 if (strEq(offHelpers_offMode(), "copy")) { 2714 rmAll(offHelpers_offStore()); 2715 } 2716 if (strEq(offHelpers_offMode(), "scp") || strEq(offHelpers_offMode(), "rsync")) { 2717 offHelpers_rmAllStore(""); 2718 } 2719 } 2720 2721 void offCommands_clearTmp() { 2722 char *p = NULL; 2723 2724 // delete tmp in cache in current git 2725 p = malloc(strlen(offHelpers_gitRepoRoot()) + 1 + 13); 2726 sprintf(p, "%s/.git/off/tmp", offHelpers_gitRepoRoot()); 2727 rmAll(p); 2728 free(p); 2729 } 2730 2731 void offCommands_defaults() { 2732 int i; 2733 2734 // TODO add default key strings 2735 // show first time config (offDEFAULTS) 2736 for (i=0; i < lastD ; i++) { 2737 printf("%s\n", offDEFAULTS[i]); 2738 } 2739 } 2740 2741 void offCommands_env() { 2742 char *s = NULL; 2743 2744 s = offHelpers_offMode(); 2745 if (s != NULL) { 2746 printf("off.mode %s", offHelpers_offMode()); 2747 printf("\n"); 2748 } 2749 s = offHelpers_offIntegrity(); 2750 if (s != NULL) { 2751 printf("off.integrity %s", offHelpers_offIntegrity()); 2752 printf("\n"); 2753 } 2754 s = offHelpers_offPem(); 2755 if (s != NULL) { 2756 printf("off.pem %s", offHelpers_offPem()); 2757 printf("\n"); 2758 } 2759 s = offHelpers_offSshOptions(); 2760 if (s != NULL) { 2761 printf("off.sshoptions %s", offHelpers_offSshOptions()); 2762 printf("\n"); 2763 } 2764 s = offHelpers_offScpOptions(); 2765 if (s != NULL) { 2766 printf("off.scpoptions %s", offHelpers_offScpOptions()); 2767 printf("\n"); 2768 } 2769 s = offHelpers_offRsyncOptions(); 2770 if (s != NULL) { 2771 printf("off.rsyncoptions %s", offHelpers_offRsyncOptions()); 2772 printf("\n"); 2773 } 2774 s = offHelpers_offStore(); 2775 if (s != NULL) { 2776 printf("off.store %s", offHelpers_offStore()); 2777 printf("\n"); 2778 } 2779 s = offHelpers_offHttp(); 2780 if (s != NULL) { 2781 printf("off.http %s", offHelpers_offHttp()); 2782 printf("\n"); 2783 } 2784 s = offHelpers_offCurlOptions(); 2785 if (s != NULL) { 2786 printf("off.curloptions %s", offHelpers_offCurlOptions()); 2787 printf("\n"); 2788 } 2789 s = offHelpers_offScp(); 2790 if (s != NULL) { 2791 printf("off.scphost %s", offHelpers_offScp()); 2792 printf("\n"); 2793 } 2794 s = offHelpers_offScpUser(); 2795 if (s != NULL) { 2796 printf("off.scpuser %s", offHelpers_offScpUser()); 2797 printf("\n"); 2798 } 2799 s = offHelpers_getLog(); 2800 if (s != NULL) { 2801 printf("off.log %s", offHelpers_getLog()); 2802 printf("\n"); 2803 } 2804 s = offHelpers_offConfigAlways(); 2805 if (s != NULL) { 2806 printf("off.configAlways %s", offHelpers_offConfigAlways()); 2807 printf("\n"); 2808 } 2809 s = offHelpers_s3Region(); 2810 if (s != NULL) { 2811 printf("off.s3region %s", offHelpers_s3Region()); 2812 printf("\n"); 2813 } 2814 s = offHelpers_s3Bucket(); 2815 if (s != NULL) { 2816 printf("off.s3bucket %s", offHelpers_s3Bucket()); 2817 printf("\n"); 2818 } 2819 s = offHelpers_transform(); 2820 if (s != NULL) { 2821 printf("off.transform %s", offHelpers_transform()); 2822 printf("\n"); 2823 } 2824 s = offHelpers_transformTo(); 2825 if (s != NULL) { 2826 printf("off.transformTo %s", offHelpers_transformTo()); 2827 printf("\n"); 2828 } 2829 s = offHelpers_transformFrom(); 2830 if (s != NULL) { 2831 printf("off.transformFrom %s", offHelpers_transformFrom()); 2832 printf("\n"); 2833 } 2834 } 2835 2836 void offCommands_help() { 2837 2838 printf("git-off help\n"); 2839 printf("\n"); 2840 if (argc < 3) { 2841 printf("# Quick Start"); 2842 printf("\n"); 2843 printf("Setup:"); 2844 printf("\n"); 2845 printf("git off track '*.bin'"); 2846 printf("\n"); 2847 printf("git add ."); 2848 printf("\n"); 2849 printf("git commit"); 2850 printf("\n"); 2851 printf("git push"); 2852 printf("\n"); 2853 printf("git checkout master"); 2854 printf("\n"); 2855 printf("\n# Other"); 2856 printf("\n"); 2857 printf("git off install"); 2858 printf("\n"); 2859 printf("git off mode scp"); 2860 printf("\n"); 2861 printf("git off scp localhost:/tmp/offStore"); 2862 printf("\n"); 2863 printf("git off scpuser username"); 2864 printf("\n"); 2865 printf("git off cc"); 2866 printf("\n"); 2867 printf("git off ca"); 2868 printf("\n"); 2869 printf("git off env"); 2870 printf("\n"); 2871 printf("git off defaults\n"); 2872 printf("\n"); 2873 2874 showAllCommandsHelp(); 2875 2876 printf("More information at https://noulin.net/git-off/file/README.md.html"); 2877 printf("\n"); 2878 } 2879 else { 2880 int cmd; 2881 cmd = findCommand(argv[2]); 2882 if (cmd == -1) { 2883 // show help for help 2884 printf("git-off command \"%s\" not found.\n", argv[2]); 2885 printf("\n"); 2886 printf("%s\n", COMMAND_HELP[helpC]); 2887 } 2888 else { 2889 printf("%s\n", COMMAND_HELP[cmd]); 2890 } 2891 } 2892 } 2893 2894 // -------------------------------------------------------------------------------------------- 2895 void installF() { 2896 2897 thisrepo(offCommands_install); 2898 } 2899 2900 void modeF() { 2901 2902 thisrepo(offCommands_setGetGitConfig); 2903 } 2904 2905 void storeF() { 2906 2907 thisrepo(offCommands_setGetGitConfig); 2908 } 2909 2910 void scpF() { 2911 2912 thisrepo(offCommands_setGetGitConfig); 2913 } 2914 2915 void httpF() { 2916 2917 thisrepo(offCommands_setGetGitConfig); 2918 } 2919 2920 void curlF() { 2921 2922 thisrepo(offCommands_setGetGitConfig); 2923 } 2924 2925 void integrityF() { 2926 2927 thisrepo(offCommands_setGetGitConfig); 2928 } 2929 2930 void pemF() { 2931 2932 thisrepo(offCommands_setGetGitConfig); 2933 } 2934 2935 void sshoptionsF() { 2936 2937 thisrepo(offCommands_setGetGitConfig); 2938 } 2939 2940 void scpoptionsF() { 2941 2942 thisrepo(offCommands_setGetGitConfig); 2943 } 2944 2945 void rsyncoptionsF() { 2946 2947 thisrepo(offCommands_setGetGitConfig); 2948 } 2949 2950 void scpuserF() { 2951 2952 thisrepo(offCommands_setGetGitConfig); 2953 } 2954 2955 void trackF() { 2956 2957 offCommands_track(); 2958 } 2959 2960 void configAlwaysF() { 2961 2962 offCommands_configAlways(); 2963 } 2964 2965 void s3regionF() { 2966 2967 thisrepo(offCommands_setGetGitConfig); 2968 } 2969 2970 void s3bucketF() { 2971 2972 thisrepo(offCommands_setGetGitConfig); 2973 } 2974 2975 void transformF() { 2976 2977 thisrepo(offCommands_setGetGitConfig); 2978 } 2979 2980 void transformToF() { 2981 2982 thisrepo(offCommands_setGetGitConfig); 2983 } 2984 2985 void transformFromF() { 2986 2987 thisrepo(offCommands_setGetGitConfig); 2988 } 2989 2990 void cleanF() { 2991 2992 offCommands_clean(); 2993 } 2994 2995 void prepushF() { 2996 2997 offCommands_prepush(); 2998 } 2999 3000 void smudgeF() { 3001 3002 offCommands_smudge(); 3003 } 3004 3005 void copyToF() { 3006 3007 offCommands_copyTo(); 3008 } 3009 3010 void pushF() { 3011 3012 offCommands_pushTo(); 3013 } 3014 3015 void clearAllF() { 3016 3017 offCommands_clearAll(); 3018 } 3019 3020 void caF() { 3021 3022 offCommands_clearAll(); 3023 } 3024 3025 void clearCacheF() { 3026 3027 offCommands_clearCache(); 3028 } 3029 3030 void ccF() { 3031 3032 offCommands_clearCache(); 3033 } 3034 3035 void clearStoreF() { 3036 3037 offCommands_clearStore(); 3038 } 3039 3040 void csF() { 3041 3042 offCommands_clearStore(); 3043 } 3044 3045 void clearTmpF() { 3046 3047 offCommands_clearTmp(); 3048 } 3049 3050 void ctF() { 3051 3052 offCommands_clearTmp(); 3053 } 3054 3055 void defaultsF() { 3056 3057 offCommands_defaults(); 3058 } 3059 3060 void envF() { 3061 3062 offCommands_env(); 3063 } 3064 3065 void helpF() { 3066 3067 offCommands_help(); 3068 } 3069 3070 // Initialize commands 3071 void initCOMMAND_FUNC() { 3072 3073 COMMAND_FUNC[0] = installF; 3074 COMMAND_FUNC[1] = modeF; 3075 COMMAND_FUNC[2] = storeF; 3076 COMMAND_FUNC[3] = scpF; 3077 COMMAND_FUNC[4] = httpF; 3078 COMMAND_FUNC[5] = curlF; 3079 COMMAND_FUNC[6] = integrityF; 3080 COMMAND_FUNC[7] = pemF; 3081 COMMAND_FUNC[8] = sshoptionsF; 3082 COMMAND_FUNC[9] = scpoptionsF; 3083 COMMAND_FUNC[10] = rsyncoptionsF; 3084 COMMAND_FUNC[11] = scpuserF; 3085 COMMAND_FUNC[12] = trackF; 3086 COMMAND_FUNC[13] = configAlwaysF; 3087 COMMAND_FUNC[14] = s3regionF; 3088 COMMAND_FUNC[15] = s3bucketF; 3089 COMMAND_FUNC[16] = transformF; 3090 COMMAND_FUNC[17] = transformToF; 3091 COMMAND_FUNC[18] = transformFromF; 3092 COMMAND_FUNC[19] = cleanF; 3093 COMMAND_FUNC[20] = prepushF; 3094 COMMAND_FUNC[21] = smudgeF; 3095 COMMAND_FUNC[22] = copyToF; 3096 COMMAND_FUNC[23] = pushF; 3097 COMMAND_FUNC[24] = clearAllF; 3098 COMMAND_FUNC[25] = caF; 3099 COMMAND_FUNC[26] = clearCacheF; 3100 COMMAND_FUNC[27] = ccF; 3101 COMMAND_FUNC[28] = clearStoreF; 3102 COMMAND_FUNC[29] = csF; 3103 COMMAND_FUNC[30] = clearTmpF; 3104 COMMAND_FUNC[31] = ctF; 3105 COMMAND_FUNC[32] = defaultsF; 3106 COMMAND_FUNC[33] = envF; 3107 COMMAND_FUNC[34] = helpF; 3108 COMMAND_FUNC[lastC] = NULL; 3109 3110 COMMAND_HELPERS[0] = NULL; 3111 COMMAND_HELPERS[1] = offHelpers_offMode; 3112 COMMAND_HELPERS[2] = offHelpers_offStore; 3113 COMMAND_HELPERS[3] = offHelpers_offScp; 3114 COMMAND_HELPERS[4] = offHelpers_offHttp; 3115 COMMAND_HELPERS[5] = offHelpers_offCurlOptions; 3116 COMMAND_HELPERS[6] = offHelpers_offIntegrity; 3117 COMMAND_HELPERS[7] = offHelpers_offPem; 3118 COMMAND_HELPERS[8] = offHelpers_offSshOptions; 3119 COMMAND_HELPERS[9] = offHelpers_offScpOptions; 3120 COMMAND_HELPERS[10] = offHelpers_offRsyncOptions; 3121 COMMAND_HELPERS[11] = offHelpers_offScpUser; 3122 COMMAND_HELPERS[12] = NULL; 3123 COMMAND_HELPERS[13] = offHelpers_offConfigAlways; 3124 COMMAND_HELPERS[14] = offHelpers_s3Region; 3125 COMMAND_HELPERS[15] = offHelpers_s3Bucket; 3126 COMMAND_HELPERS[16] = offHelpers_transform; 3127 COMMAND_HELPERS[17] = offHelpers_transformTo; 3128 COMMAND_HELPERS[18] = offHelpers_transformFrom; 3129 COMMAND_HELPERS[19] = NULL; 3130 COMMAND_HELPERS[20] = NULL; 3131 COMMAND_HELPERS[21] = NULL; 3132 COMMAND_HELPERS[22] = NULL; 3133 COMMAND_HELPERS[23] = NULL; 3134 COMMAND_HELPERS[24] = NULL; 3135 COMMAND_HELPERS[25] = NULL; 3136 COMMAND_HELPERS[26] = NULL; 3137 COMMAND_HELPERS[27] = NULL; 3138 COMMAND_HELPERS[28] = NULL; 3139 COMMAND_HELPERS[29] = NULL; 3140 COMMAND_HELPERS[30] = NULL; 3141 COMMAND_HELPERS[31] = NULL; 3142 COMMAND_HELPERS[32] = NULL; 3143 COMMAND_HELPERS[33] = NULL; 3144 COMMAND_HELPERS[34] = NULL; 3145 COMMAND_HELPERS[lastC] = NULL; 3146 } 3147 3148 #ifndef unitTest 3149 // Remove main when running the unit tests 3150 #define MAIN main 3151 #endif 3152 int MAIN(int ARGC, char** ARGV) { 3153 int dummy; 3154 // TODO remove dummy 3155 3156 argc = ARGC; argv = ARGV;;// init transport functions 3157 transport.send = send; 3158 transport.receive = receive; 3159 initCOMMAND_FUNC(); 3160 3161 // parse CLI arguments 3162 3163 if (argc == 1) { 3164 offCommands_help(); 3165 } 3166 else { 3167 // call argv[1] command 3168 int i; 3169 i = findCommand(argv[1]); 3170 if (i == -1) { 3171 offCommands_help(); 3172 } 3173 else { 3174 COMMAND_FUNC[i](); 3175 } 3176 } 3177 }