From 934692999f690989b0319250977add6b0d211c12 Mon Sep 17 00:00:00 2001 From: David Helkowski Date: Wed, 15 May 2024 21:34:07 +0900 Subject: [PATCH] Initial version --- .gitignore | 9 ++ Makefile | 22 ++++ bin/.gitkeep | 0 bottle/.gitkeep | 0 curlprog.m | 178 +++++++++++++++++++++++++++ deploy.pl | 9 ++ dl.pl | 156 ++++++++++++++++++++++++ dlinfo.json | 205 ++++++++++++++++++++++++++++++++ dlsize.json | 166 ++++++++++++++++++++++++++ extract.pl | 79 ++++++++++++ genbin.pl | 100 ++++++++++++++++ genlib.pl | 92 ++++++++++++++ lib/.gitkeep | 0 mod/Ujsonin.pm | 271 ++++++++++++++++++++++++++++++++++++++++++ pkgs/.gitkeep | 0 rebase.pl | 89 ++++++++++++++ scan.c | 192 ++++++++++++++++++++++++++++++ tarball_incremental.c | 220 ++++++++++++++++++++++++++++++++++ 18 files changed, 1788 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 bin/.gitkeep create mode 100644 bottle/.gitkeep create mode 100644 curlprog.m create mode 100755 deploy.pl create mode 100755 dl.pl create mode 100644 dlinfo.json create mode 100644 dlsize.json create mode 100755 extract.pl create mode 100755 genbin.pl create mode 100755 genlib.pl create mode 100644 lib/.gitkeep create mode 100644 mod/Ujsonin.pm create mode 100644 pkgs/.gitkeep create mode 100755 rebase.pl create mode 100644 scan.c create mode 100644 tarball_incremental.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..685a604 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*~ +lib +pkgs +bottle +bin +curlprog +tarball_incremental +scan +minibrew.tar.xz diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6b010bd --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +all: minibrew.tar.xz + +SOURCES := dl.pl extract.pl genlib.pl genbin.pl rebase.pl deploy.pl $(wildcard *.json) curlprog tarball_incremental scan mod/Ujsonin.pm +EMPTY_FOLDERS := bin pkgs lib bottle + +minibrew.tar.xz: $(SOURCES) + tar --no-recursion -cJf minibrew.tar.xz $(SOURCES) $(EMPTY_FOLDERS) + +scan: scan.c + clang -arch x86_64 -arch arm64 -o scan scan.c + codesign --sign - scan + +tarball_incremental: tarball_incremental.c + clang -arch x86_64 -arch arm64 -o tarball_incremental tarball_incremental.c -I/usr/local/opt/libarchive/include -ldl + codesign --sign - tarball_incremental + +curlprog: curlprog.m + clang -arch x86_64 -arch arm64 -fobjc-arc -o curlprog curlprog.m -ldl -framework Foundation + codesign --sign - curlprog + +clean: + rm scan curlprog tarball_incremental minibrew.tar.xz \ No newline at end of file diff --git a/bin/.gitkeep b/bin/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/bottle/.gitkeep b/bottle/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/curlprog.m b/curlprog.m new file mode 100644 index 0000000..bd4ac64 --- /dev/null +++ b/curlprog.m @@ -0,0 +1,178 @@ +#include +#include +#include +#include +#import +#include +#import + +// Define a structure to hold function pointers for the libcurl functions we need +struct curl_functions { + CURL* (*easy_init )(void); + CURLcode (*easy_setopt )(CURL *curl, CURLoption option, ...); + CURLcode (*easy_perform )(CURL *curl); + void (*easy_cleanup )(CURL *curl); + const char* (*easy_strerror )(CURLcode); + struct curl_slist* (*slist_append )(struct curl_slist *, const char *); + void (*slist_free_all)(struct curl_slist *); + const char* (*version )(void); +}; + +// Callback function for writing received data to a file +size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp) { + FILE *writehere = (FILE *)userp; + return fwrite(buffer, size, nmemb, writehere); +} + +// Progress callback function +int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) { + static double last_dl = 0; + if (dlnow - last_dl > 20480) { // 20KB + printf("%.0f\n", dlnow-last_dl); + last_dl = dlnow; + } + return 0; +} + +// Header callback function to print each header line +size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata) { + fwrite(buffer, size, nitems, (FILE *)userdata); + return nitems * size; +} + +int main( int argc, char **argv ) { + void *libcurl; + struct curl_functions curl; + CURL *handle; + CURLcode res; + + if( argc < 3 ) { + printf("Usage: %s [url] [save location]\n\n", argv[0] ); + return 1; + } + + // Load the libcurl shared library + libcurl = dlopen("/usr/lib/libcurl.dylib", RTLD_LAZY); + if (!libcurl) { + fprintf(stderr, "Error loading libcurl: %s\n", dlerror()); + return 1; + } + + // Load function symbols + curl.easy_init = dlsym(libcurl, "curl_easy_init"); + curl.easy_setopt = dlsym(libcurl, "curl_easy_setopt"); + curl.easy_perform = dlsym(libcurl, "curl_easy_perform"); + curl.easy_cleanup = dlsym(libcurl, "curl_easy_cleanup"); + curl.easy_strerror = dlsym(libcurl, "curl_easy_strerror"); + curl.slist_append = dlsym(libcurl, "curl_slist_append"); + curl.slist_free_all = dlsym(libcurl, "curl_slist_free_all"); + curl.version = dlsym(libcurl, "curl_version"); + + if (!curl.easy_init || !curl.easy_setopt || !curl.easy_perform || !curl.easy_cleanup || + !curl.easy_strerror || !curl.slist_append || !curl.slist_free_all || !curl.version) { + fprintf(stderr, "Error loading functions: %s\n", dlerror()); + dlclose(libcurl); + return 1; + } + + char *curlVersion = strdup( curl.version() ); + for( int i=0;i{pkgs}; + my $shas = $root2->{sha256}; + + #my $totSize = 0; + for my $pkg ( @$pkgs ) { + my $plats = $pkg->{platforms}; + my $sha = $plats->{ $plat } || $plats->{all}; + #print "$name - $sha\n"; + my $size = $shas->{ $sha }; + if( !$size ) { + print "Could not find size for $sha\n"; + } + $totSize += $size; + } + print "Total size of packages to download: $totSize\n"; + print "Downloading raw brew packages...\n"; + print_progress( 0 ); + + #exit; + + for my $pkg ( @$pkgs ) { + my $name = $pkg->{name}; + my $url = $pkg->{url}; + my $plats = $pkg->{platforms}; + my $sha = $plats->{ $plat } || $plats->{all}; + my $size = $shas->{ $sha }; + #print "$name - $sha\n"; + $dlTot += $size; + ghcr_dl( "$url$sha", "bottle/$name.tar.gz", $curlVersion, $size ); + #delete $plats->{_parent}; + #print Dumper( $plats ); + } + print "\n"; + #print "\nDl tot: $dlTot\n"; +} + +sub get_curl_version { + my $curlInfo = `curl --version`; + my @curlLines = split("\n",$curlInfo); + my $curlVersion = "8.4.0"; + if( $curlLines[0] =~ m/curl ([0-9\.]+)/ ) { + $curlVersion = $1; + } + return $curlVersion; +} + +sub ghcr_dl { + my ( $url, $out, $curlVersion, $size ) = @_; + #my $ua = '--user-agent "Homebrew/4.2.20 (Macintosh; Intel Mac OS X 13.6.4) curl/'.$curlVersion.'"'; + #my $lang = '--header Accept-Language:\\ en'; + #my $auth = '--header "Authorization: Bearer QQ=="'; + #my $fixed = "--disable --cookie /dev/null --globoff --show-error $ua $lang --fail --retry 3 $auth --remote-time"; + + if( ! -e "$out" ) { + #`curl $fixed --location $url -o $out`; + #print " curl $fixed --location $url -o $out\n"; + + #my $fileDone = 0; + #for( my $i=0;$i<5000;$i++ ) { + # $fileDone += 20000; + # last if( $fileDone >= $size ); + # $doneSize += 20000; + # print_progress( int( ($doneSize/$totSize)*100 ) ); + # select(undef, undef, undef, 0.001); + #} + + my $cmd = "./curlprog \"$url\" \"$out\""; + open my $cmdfh, '-|', $cmd; + while( my $line = <$cmdfh> ) { + my $bytes = int( $line ); + if( $bytes ) { + $doneSize += $bytes; + print_progress( int( ($doneSize/$totSize)*100 ) ); + } + else { + print "Line: $line\n"; + } + } + } +} + +sub print_progress { + my ($percent) = @_; + return if( $percent == $lastPercent ); + $percent *= 1.08; + $percent = 100 if( $percent > 100 ); + my $num_blocks = int($percent / 2); + my $bar = '[' . '=' x $num_blocks . ' ' x (50 - $num_blocks) . ']'; + printf("\r%s %3d%%", $bar, $percent); + STDOUT->flush(); # Flush the output buffer to update the display immediately + $lastPercent = $percent; +} + +sub read_file { + my $fn = shift; + open my $fh, '<', $fn or return ""; + my $data = do { local $/; <$fh> }; + close( $fh ); + return $data; +} diff --git a/dlinfo.json b/dlinfo.json new file mode 100644 index 0000000..3e57e01 --- /dev/null +++ b/dlinfo.json @@ -0,0 +1,205 @@ +{ + pkgs:[ + { + name:"xz" + url:"https://ghcr.io/v2/homebrew/core/xz/blobs/sha256:" + platforms:{ + arm64_sonoma: "01ced87d92d0c1131c069108efb14f6940f9e528e2d044ac41d9a0d8f5169f2e" + arm64_ventura: "baba463d36447d4c858e51dfac347792eb65216e21eedab7b98fe79793335f28" + arm64_monterey: "d7a51a59ce7e63b9e3f81be7f3b239d951ac83ab429a7c4423ba14c064ec7921" + sonoma: "139fcf6d46fb85d3693f5d7452a37ec5f50f17b5ef044ac96a2c7deccb7983b4" + ventura: "8a3f7325f367f90a22f3c17c0bcc65af615de713a8598e973691e84f118b325c" + monterey: "9195af5a2fcbecf42267f4738254a3a58257d2a303fa6c63ec09eb4def7f7c1e" + } + } + { + name:"libimobiledevice-glue" + url:"https://ghcr.io/v2/homebrew/core/libimobiledevice-glue/blobs/sha256:" + platforms:{ + arm64_sonoma: "5e00139aad86809adde7ad17bceeedda2a3177372df04fbe9a91bc3fa1366a5b" + arm64_ventura: "005fde87e6014290eb3c9e08712b6dc93dc3febf2d56c44094f37f34fe149d10" + arm64_monterey: "f433d2bd7a0f0af23fe462fcd8df88e87fc0c8f908d92c7f67a4a2f7a320a441" + sonoma: "a248f4d3c9fdf4608e941d818317e5d86c2132c1140daa45bbf6a82f8f90a53c" + ventura: "4580c48aec859791cb1771caf7ff609f09af8a4d9352883d1b104d6039cb193b" + monterey: "607706dd2f6675ee2ff5900fe82ae1b666e10bb17892eb9c2b5ba9d3391219b4" + } + } + { + name:"libplist" + url:"https://ghcr.io/v2/homebrew/core/libplist/blobs/sha256:" + platforms:{ + arm64_sonoma: "59354164cd075ee3597dfc2670b2283a439b0154730dd0f4d9ccc694cbcb54f1" + arm64_ventura: "42fa24333cc5431048e01a225ded9addb37447575032d579c845eadd1b1cd4db" + arm64_monterey: "a8bec99b0a62f01f1078fc21207ebe68d5cb1f12925782ce0139134935ab39e4" + sonoma: "10e9d29e5c3c3354a3af67dab61b1e1d98d2020e3b5e0e2780ee4b2587bc0817" + ventura: "4680532f5124cd9bba37b8192ee8ecd005b05df1a15290feb18fc38ea37570bc" + monterey: "666028bbd050fd8c2454c952ed04ab78043de7cd15abd0c55388c8a995098af8" + } + } + { + name:"libusbmuxd" + url:"https://ghcr.io/v2/homebrew/core/libusbmuxd/blobs/sha256:" + platforms:{ + arm64_sonoma: "8149dcd7d29cdf463c40a10e8030dcb23a4eb9e69078a88fb2e8671d9a27bdad" + arm64_ventura: "3908c3a4d699d2aff22b40e6353c498042153a47798357c4500b76b495f24e88" + arm64_monterey: "738b1efb11135136a9066ee73379829f29c57df598e989631d26e4ae5401f456" + sonoma: "9b366b324e9758bd9f5d10c536e40ef2d90ed2caf2886ff7e55e13fe496628dd" + ventura: "b188d3fcab748c6ac1e5740129bf4a07b2756dedd557d89f6f1291715bf6c45e" + monterey: "4ea63ce7da1344b4e2fde47b7c2a9d8bad424bd5ce9282f6af1aa66a1155135b" + } + } + { + name:"libtasn1" + url:"https://ghcr.io/v2/homebrew/core/libtasn1/blobs/sha256:" + platforms:{ + arm64_sonoma: "975eaba8f266020c3c82a667a0e693a1c6b1f76e317a95bb79b6906fd248bcc5" + arm64_ventura: "9fcf93a7992888a29caf2bc3ad37fb27ee8ceef180367797f4a11040fa761eac" + arm64_monterey: "cf95a18e2fabf1675d77ec8a1abb41fdb091cef689dec3318a420ad2f25beb76" + sonoma: "7218661c69488f1147868d53d6bf50d53ad5eafe3020b07a7846ddcd8743fc50" + ventura: "ee3b036d7d82561e743131c0ec97d4a425e18a593253830753c519a04db6b200" + monterey: "2aa4f8396ba40b05b237d503eb4de02c37175903d3e0f26d7a48a031707a71b5" + catalina: "7bf11a4603037c490e83caaddc03fba59dfae11385e2f6bd4555b8ee9aaf1507" + } + } + { + name:"sqlite" + url:"https://ghcr.io/v2/homebrew/core/sqlite/blobs/sha256:" + platforms:{ + arm64_sonoma: "253a7732af34b28f992072e84d9977d511844a0ebd238e94a5cb2f3fe254604c" + arm64_ventura: "844fbdee84f718f211936a2aea851a6983af3501533af643afccb17314e30fd2" + arm64_monterey: "e51cd4fb90a3a233f8b19d0068f1f4dfd537198be60b25261069b86a463090d5" + sonoma: "47e8a06001c02bd20d69431a76023baa4662a60127faf9fb8a3106d5f532dd29" + ventura: "0b7a573709f3fad083805cd2cf0d7649721386a177cc18a08613c10a2d4c9753" + monterey: "71900ed318d6491eac58d5828b46e939f8dbcb5e1b1cb70c6bbc8c21bbe93192" + } + } + { + name:"openssl-3" + url:"https://ghcr.io/v2/homebrew/core/openssl/3/blobs/sha256:" + platforms:{ + arm64_sonoma: "ec6f9daf8e32d96f4a2f4cd56d18533ee47bb8d9e7cb3d832ac64115d8a1a4ca" + arm64_ventura: "58665ec9e2873dba2799be5992eab3973f230acc352d09bd4a69131ac3ccd2d4" + arm64_monterey: "1afa5e6964d9418fb8bb2d489e5069becd55f963c1ea7a2a30ca838b17d9bf66" + sonoma: "f37328addd300e16046ee900f26d3ed026a6c810ea88269e114a4e0f06ed41b6" + ventura: "28be258776e175a8c29a19be5312b885574a98324d7b03c7ec12f2d7eadcbce1" + monterey: "f5b70155f3fdbf574843741924758ca05fc996263e348660ac817e75052dacf9" + } + } + { + name:"mpdecimal" + url:"https://ghcr.io/v2/homebrew/core/mpdecimal/blobs/sha256:" + platforms:{ + arm64_sonoma: "2965eec8a30f462b3bd6a8cc2756c1645e75f4399471594e434e36e886239e2e" + arm64_ventura: "1fd72d5f4b35a3d4735efd7d934154ec8b3666267571f96d64244ad35b3ee814" + arm64_monterey: "57311ecd036fae8d74c541ab5a30944a5a5cfea7abaa6b8c936b7376821edafd" + sonoma: "377dc5e30dd1292ac1666dd43a447b861ad283024f70a3e914c7e11572ae869e" + ventura: "bb1729bd410275aab1bd276f99fb22678b6ad53de2c9c474fdda854ed0ebaebd" + monterey: "266a3f517227bb9f3806b18313c3b8a33688f9659e5001751e15f1f38538dacc" + } + } + { + name:"ideviceinstaller" + url:"https://ghcr.io/v2/homebrew/core/ideviceinstaller/blobs/sha256:" + platforms:{ + arm64_sonoma: "818061a6b3ede66696892086a119faa1df036d6d4a3242672fdb955db0d23e6c" + arm64_ventura: "dfaf6de5dc0578c882412ef904195d77a6aacf7f1b9b28855ba5d8610ce17ca1" + arm64_monterey: "64803ee9f44f71a81476e4f609a96be3c33276da4eaa07f5f4c402e758fbd18c" + sonoma: "904a3bd25f933d636a094b0f16aaa8559fddac5c50f13e749b533c02f7717de6" + ventura: "cca7171c1e51ae86824029858e05c382a4f8088644aa0ac1d075c8d8a901b5ee" + monterey: "baade9b3f29b7de45b0ddfd66f911eadaba2b7d4a2fe6601e69f660757400ff7" + } + } + { + name:"libimobiledevice" + url:"https://ghcr.io/v2/homebrew/core/libimobiledevice/blobs/sha256:" + platforms:{ + arm64_sonoma: "f496e32077cc020a7ffcb6a6afee3034fc4c55ced685ba0b2155c0355bbf7a95" + arm64_ventura: "c0f9da975e59842256875121304fdb0825909f3c43b8cf1271b505cd7436955e" + arm64_monterey: "b465efbb59cafd4d9ea16cefd5b0d33c1411da49855e14b5864ce139b65df8c6" + sonoma: "dfcb200312b7e57c99699a47ffc0ed522f3fe4d1913037003b706fe545daa082" + ventura: "a91555bb6c89202bbb68d84bfe425aeb63c50d4001c310d39643637d93bde290" + monterey: "aa17026544ec683e544113478c07c1d387e3566d949c32834b083ad72042be16" + } + } + { + name:"python-3.12" + url:"https://ghcr.io/v2/homebrew/core/python/3.12/blobs/sha256:" + platforms:{ + arm64_sonoma: "fd301f96783de7d57e8d704ca0967e5cf111350acbf1ad8bec36fa27bb75fc3c" + arm64_ventura: "94baa02aa52145f2a41a11ef2f12787510ab31c449457e334abd9f09b126c01f" + arm64_monterey: "a04e80f97f70f22b4ca6dc15160585bf4f7863c689497e38a44b984e9c5f533e" + sonoma: "2bd309f8e329a645ac48a64e7b7983accf6773711491f635c9c5ed5c5f3a78fb" + ventura: "9f5d156dee8517f0dd0bd7542974787cd38156bab4f897c4700d5787106e02a5" + monterey: "75ae75d6dafd805e42ba57d823d4dd8ffdbfde545ccc0340a2229ec183619274" + } + } + { + name:"readline" + url:"https://ghcr.io/v2/homebrew/core/readline/blobs/sha256:" + platforms:{ + arm64_sonoma: "713fd1fa8544426b7e97eb21d13153195fea4c407db8a174bd183777b81c9192" + arm64_ventura: "90351660d5ceca72a4c0a287555f2045db95f78aa5f65011b94213429f729cde" + arm64_monterey: "e58bc8376c36602c3cedf94075bb1097b04b77438c5a946fdbd37bf0eb6579c2" + sonoma: "9796e0ff1cc29ae7e75d8fc1a3e2c5e8ae2aeade8d9d59a16363306bf6c5b8f4" + ventura: "952e2975dffc98bd35673c86474dbb91fadc8d993c0720e4f085597f7a484af9" + monterey: "3633320dce51662036ea90acfc9adf5bb5e6f1dca7dbdb539839736129c474b0" + } + } + { + name:"ca-certificates" + url:"https://ghcr.io/v2/homebrew/core/ca-certificates/blobs/sha256:" + platforms:{ + all: "cab828953672906e00a8f25db751977b8dc4115f021f8dfe82b644ade03dacdb" + } + } + { + name:"krb5" + url:"https://ghcr.io/v2/homebrew/core/krb5/blobs/sha256:" + platforms:{ + arm64_sonoma: "2d4dc47f318eb4b612c6082831602dabf86737abaf16205efca110f79d2c4582" + arm64_ventura: "7d9d7b0073393cd9629f017b4dfe5866363884703fff78cbbff8a6cb39390f77" + arm64_monterey: "23e6b429459601ee94ff71df2130d01e31498a2c2b6ffbc37223cb84fb71a06b" + sonoma: "20a39d385f0cdc34029de2e0c030fc0787940a7be69cdcaa9de6899170cbb731" + ventura: "3d61bf09ad35a994a36390723f15d2be2be9969a980884a45941300a8c9b33cf" + monterey: "aba14932d5689bc4f527838ff4750fcdce0c1f634d579e7e3b9fee4bd67d8c84" + } + } + { + name:"zstd" + url:"https://ghcr.io/v2/homebrew/core/zstd/blobs/sha256:" + platforms:{ + arm64_sonoma: "2028141683f55bffcd0693b9e49eef1e3dabc1e184214cacb173ca9bd54dabc0" + arm64_ventura: "035cbadb205abbe00107f0c7746f3715e3841c007e4b3a309398e65d50c43cf5" + arm64_monterey: "7f12fa16033d6576099c481f93a7423a526a7b3252a0ea0921ea0016c18f49f8" + sonoma: "09953f22fd56bc85e0d7ceac8de7e35ed622f3affe78dd782154e5e21623037b" + ventura: "78fd5d1b6afaef60879445e3de8227257e79ec6fca6af1e1324896bc93cf2a75" + monterey: "b5099f7c339af2fff89af3a844a004b35aba400787ef71e1db6e856889f56557" + } + } + { + name:"lz4" + url:"https://ghcr.io/v2/homebrew/core/lz4/blobs/sha256:" + platforms:{ + arm64_sonoma: "5a8b7116d978e403c525e61794c60b43480d0afc83e499a763f7f14641bbc9b1" + arm64_ventura: "cd29e40287b0a2d665a647acbea5512e8db4c371687147aab5c60bf9059b2cca" + arm64_monterey: "284fa580570efdc8056e4fc95dc05f7b0546aa0c346795dd616d4cec8eb99426" + sonoma: "2bad368b2869db32b1b22cea76a6e65da2f4e599ac8ee327b4825d54c4579445" + ventura: "6a911ee2a3ea072f414d2983d532b28c34b63a68ff388a0008e1528dc0668838" + monterey: "88b369cea90a0a119c24aa96a614fe7d77de58d18cb1803023dc925679eb905f" + catalina: "ddb59c42498843638f1f9d80bd0c7b7126910c4fc8ee7c69fa8784dd4bc95c1f" + } + } + { + name:"libzip" + url:"https://ghcr.io/v2/homebrew/core/libzip/blobs/sha256:" + platforms:{ + arm64_sonoma: "8ecf154f8c0bab71c0008c6f73eb8cd2df78cfa424d8bdcffc66dc95b3bf7c14" + arm64_ventura: "cd7bda731a8b2e5d1a3cdf5be6b515718c56d55d16a5b45faa1a91daf9c0ca2b" + arm64_monterey: "a0d8bae54df1068c92ad894eddca0cd7465ecbaa3ef875c07c46bcea764bac71" + sonoma: "f782643b254f58ddf3830272c0221f5d35db84ebd4f3d4ef19894ca0c91648ad" + ventura: "4fca00c15a69f25064b40b12e37a6f552edd632f77e2947e076745b55aaeffd3" + monterey: "5fbb0e2a2cd9b17a416d518d324d9eb3eac88626851bad41d9fb144ccebd8757" + } + } + ] +} diff --git a/dlsize.json b/dlsize.json new file mode 100644 index 0000000..4013b65 --- /dev/null +++ b/dlsize.json @@ -0,0 +1,166 @@ +{ + sha256:{ + "19c6df6badb6b13631670b917595f63a49a06cadd73e2484e5546129cadcf04c": 173606 + "2aa4f8396ba40b05b237d503eb4de02c37175903d3e0f26d7a48a031707a71b5": 171087 + "7bf11a4603037c490e83caaddc03fba59dfae11385e2f6bd4555b8ee9aaf1507": 171399 + "cf95a18e2fabf1675d77ec8a1abb41fdb091cef689dec3318a420ad2f25beb76": 172508 + "45a9352536560b5a69bef3e85ca615bad19d44eab23c6ad797c4305a27bd15d8": 171460 + "e994c7b8c16afb59368d8d09a3f193451c9deab1e4a83f8a94650e27674d9278": 178728 + "9fcf93a7992888a29caf2bc3ad37fb27ee8ceef180367797f4a11040fa761eac": 172132 + "ee3b036d7d82561e743131c0ec97d4a425e18a593253830753c519a04db6b200": 169722 + "975eaba8f266020c3c82a667a0e693a1c6b1f76e317a95bb79b6906fd248bcc5": 171973 + "7218661c69488f1147868d53d6bf50d53ad5eafe3020b07a7846ddcd8743fc50": 169635 + "7f12fa16033d6576099c481f93a7423a526a7b3252a0ea0921ea0016c18f49f8": 843283 + "2028141683f55bffcd0693b9e49eef1e3dabc1e184214cacb173ca9bd54dabc0": 776771 + "035cbadb205abbe00107f0c7746f3715e3841c007e4b3a309398e65d50c43cf5": 775757 + "b5099f7c339af2fff89af3a844a004b35aba400787ef71e1db6e856889f56557": 1015014 + "09953f22fd56bc85e0d7ceac8de7e35ed622f3affe78dd782154e5e21623037b": 916072 + "78fd5d1b6afaef60879445e3de8227257e79ec6fca6af1e1324896bc93cf2a75": 916244 + "0e6ddbd4c969bb84261f12b759fb78a828d6f734c9e515793c6ac2c3a846b01e": 1102115 + "0dfe944eaa47cad87ad22f70dbbcefdb6b27bbeb83ca1f7a229827c03054c07c": 25079 + "6d98523b90770662e350311c375f1157ac0c708769ce2145036aeed451e26621": 25669 + "30f56186281509d1f77d7a00cbcd1f313cd80135e3f9e2a235ca649f9a23e5f1": 26147 + "6ed5e4f7ace33fd5f4d1b4c6b9f0fd519836080e170b981e63942087698351c6": 25057 + "6ee12db78e8c224c0eb0cf88eb4f43242eb1ba672eb006636273b99b75b02a87": 25148 + "e225e3d9f0e6508b4fb73d9e7ea5eaec71b75d9d7ca7ac591adcfb3b9fd324fc": 27917 + "e6e374f35c4eeb37763e7755228c108ee96024b8599943fa741450be35915d93": 25520 + "e5bf0e5ed6aad688593878bdf8e78c5aa84530ee053f5ea21ad433cf99f59873": 24941 + "fb42f5fc7e6da997dc22dd68fe9c57a711250259c737992eeb162cfe871cce99": 24931 + "d99cfeb0873b28db4ded6c9fdeb4ba29aa7603a20a284444752ca97c6e7af3b6": 24512 + "cca7171c1e51ae86824029858e05c382a4f8088644aa0ac1d075c8d8a901b5ee": 24584 + "904a3bd25f933d636a094b0f16aaa8559fddac5c50f13e749b533c02f7717de6": 24537 + "b76c11584f52a003b8b473a8b6e74a44244255b372d129a9dc0c89ae920a6c6b": 25894 + "818061a6b3ede66696892086a119faa1df036d6d4a3242672fdb955db0d23e6c": 24924 + "76b96ca732ae1bbba325139477cca6fe6f601cb62f0435232e497d619c56d828": 25496 + "dfaf6de5dc0578c882412ef904195d77a6aacf7f1b9b28855ba5d8610ce17ca1": 25010 + "baade9b3f29b7de45b0ddfd66f911eadaba2b7d4a2fe6601e69f660757400ff7": 25419 + "64803ee9f44f71a81476e4f609a96be3c33276da4eaa07f5f4c402e758fbd18c": 24909 + "85e4dd1751770e3068d164a48202b714923ac6acb344934f67ee2c9b6bd5b375": 28619 + "a04e80f97f70f22b4ca6dc15160585bf4f7863c689497e38a44b984e9c5f533e": 16631403 + "fd301f96783de7d57e8d704ca0967e5cf111350acbf1ad8bec36fa27bb75fc3c": 16509500 + "94baa02aa52145f2a41a11ef2f12787510ab31c449457e334abd9f09b126c01f": 16649157 + "75ae75d6dafd805e42ba57d823d4dd8ffdbfde545ccc0340a2229ec183619274": 16577678 + "2bd309f8e329a645ac48a64e7b7983accf6773711491f635c9c5ed5c5f3a78fb": 16411628 + "9f5d156dee8517f0dd0bd7542974787cd38156bab4f897c4700d5787106e02a5": 16486381 + "faa009be56acac74433c08417d4ba15d65faae30535edc465601e33324c399d3": 19013876 + "738b1efb11135136a9066ee73379829f29c57df598e989631d26e4ae5401f456": 58166 + "8149dcd7d29cdf463c40a10e8030dcb23a4eb9e69078a88fb2e8671d9a27bdad": 57755 + "3908c3a4d699d2aff22b40e6353c498042153a47798357c4500b76b495f24e88": 57752 + "4ea63ce7da1344b4e2fde47b7c2a9d8bad424bd5ce9282f6af1aa66a1155135b": 54049 + "9b366b324e9758bd9f5d10c536e40ef2d90ed2caf2886ff7e55e13fe496628dd": 49485 + "b188d3fcab748c6ac1e5740129bf4a07b2756dedd557d89f6f1291715bf6c45e": 52978 + "f3e9212633194e2e9436afd98d00fd5e167ec0ff13f1abfd065112dd2dd32bd3": 62901 + "e58bc8376c36602c3cedf94075bb1097b04b77438c5a946fdbd37bf0eb6579c2": 589273 + "713fd1fa8544426b7e97eb21d13153195fea4c407db8a174bd183777b81c9192": 588907 + "90351660d5ceca72a4c0a287555f2045db95f78aa5f65011b94213429f729cde": 588911 + "3633320dce51662036ea90acfc9adf5bb5e6f1dca7dbdb539839736129c474b0": 562010 + "9796e0ff1cc29ae7e75d8fc1a3e2c5e8ae2aeade8d9d59a16363306bf6c5b8f4": 563283 + "952e2975dffc98bd35673c86474dbb91fadc8d993c0720e4f085597f7a484af9": 563286 + "65181d2c0a9bd1d91ded6f7ec4a69b1110f65e875b332947e86a30aed7eab20f": 652798 + "7e3d143445f45d8a2b0483d0d67e6d850d31304e39b5186999359788aada498b": 23642098 + "3552b61376eea832cbc2a763c725c77c56f0ce3c94b72cb80acdb5b6b26d7e45": 23579820 + "0b494da812a74d56cb31bcca41dcff11e82cf84dfbaeca52a6923ef7f2882578": 24076604 + "55d4b9058c542dd9a9e90915c45fa0e4aaf4a2d9d5564df08acc4b6b2b0febb7": 23579283 + "ac63e0443e2c939ca35be34dda37e8fe978c2ce97ca7f387972ffcb7a58437a4": 23640661 + "5d16240f2a7ff2d057db048058d9b0644e152e50989f78ce66121e6350afa8a4": 23644438 + "402f563d09b08afed7bc62e117b0fad4d1cbc39fec14c49ddd4b1e58a4dc9846": 23581462 + "7e1f6f67ce491e8636f9095fa45854e7b5720745b909e3b84cad8400b28418fd": 23586044 + "5aa0875cdd7bd504abf8f7365e47f5ac4b0e1b9e4ca004d6eb58e2f1564a9621": 23659688 + "8c9ea685725256b2b50e856c23d20af734f20bc69fc92383e1819e4f867c8ac3": 23583423 + "c0e2906cc6657dc497fec75629560b0a404b81cebadf5e10c1f70616a14fa886": 24081328 + "944b439dd5dcb02c5219b307d6ed739b9808a4eced27f6605a977e550e47c8bd": 23661951 + "36aaa79c9fc3eb2b7690c24bdf74be3d0f7e1752983a63a17538945e2bce7452": 23659822 + "65a70e28dcf089e0ec6d247c32df257c8bc2532ece6f4c447200a48e7ad17a8d": 23583526 + "9ef4df0db041470e7eba4335524ea0348f0061bd4e10ab7a7f6051841f7a7e11": 23586954 + "7fdd38c90e7bfcb57b4a061423d38602471f568e37393820889ee56d1c9fd003": 23653715 + "db128eb3926e9941b0db4aaf52df8848c74194128712f153f46df7810395ff5e": 23643912 + "1757fefc3840e11c4822e4c2a95aa62aca44a4eaccce6f5c414ea51d1e58bf8e": 284178 + "aafb93487e108d302d060265898e4eaa82f5c806ff36dec50871db1c33fdc04d": 282743 + "8cf59a354786ad0ed95a7b531d7149ae03612081818dcdf2d9ca8cb4fe28c07a": 259590 + "88b369cea90a0a119c24aa96a614fe7d77de58d18cb1803023dc925679eb905f": 279868 + "ddb59c42498843638f1f9d80bd0c7b7126910c4fc8ee7c69fa8784dd4bc95c1f": 275784 + "284fa580570efdc8056e4fc95dc05f7b0546aa0c346795dd616d4cec8eb99426": 259248 + "cd29e40287b0a2d665a647acbea5512e8db4c371687147aab5c60bf9059b2cca": 256992 + "6a911ee2a3ea072f414d2983d532b28c34b63a68ff388a0008e1528dc0668838": 276812 + "5a8b7116d978e403c525e61794c60b43480d0afc83e499a763f7f14641bbc9b1": 245777 + "2bad368b2869db32b1b22cea76a6e65da2f4e599ac8ee327b4825d54c4579445": 263443 + "a8bec99b0a62f01f1078fc21207ebe68d5cb1f12925782ce0139134935ab39e4": 166484 + "59354164cd075ee3597dfc2670b2283a439b0154730dd0f4d9ccc694cbcb54f1": 168236 + "42fa24333cc5431048e01a225ded9addb37447575032d579c845eadd1b1cd4db": 166894 + "666028bbd050fd8c2454c952ed04ab78043de7cd15abd0c55388c8a995098af8": 165553 + "10e9d29e5c3c3354a3af67dab61b1e1d98d2020e3b5e0e2780ee4b2587bc0817": 165329 + "4680532f5124cd9bba37b8192ee8ecd005b05df1a15290feb18fc38ea37570bc": 164718 + "585da0b2bd5441d61b963c37a5c6f1e7bff9ea7cf88a33db857e4d95bc854975": 213248 + "d7a51a59ce7e63b9e3f81be7f3b239d951ac83ab429a7c4423ba14c064ec7921": 690586 + "01ced87d92d0c1131c069108efb14f6940f9e528e2d044ac41d9a0d8f5169f2e": 691134 + "baba463d36447d4c858e51dfac347792eb65216e21eedab7b98fe79793335f28": 691133 + "9195af5a2fcbecf42267f4738254a3a58257d2a303fa6c63ec09eb4def7f7c1e": 693385 + "139fcf6d46fb85d3693f5d7452a37ec5f50f17b5ef044ac96a2c7deccb7983b4": 676501 + "8a3f7325f367f90a22f3c17c0bcc65af615de713a8598e973691e84f118b325c": 676508 + "0736983b952c5273bb5a345008bac7311c2f4b60758d69cc05495d5b050f88f1": 744773 + "57311ecd036fae8d74c541ab5a30944a5a5cfea7abaa6b8c936b7376821edafd": 185043 + "2965eec8a30f462b3bd6a8cc2756c1645e75f4399471594e434e36e886239e2e": 182249 + "1fd72d5f4b35a3d4735efd7d934154ec8b3666267571f96d64244ad35b3ee814": 182179 + "266a3f517227bb9f3806b18313c3b8a33688f9659e5001751e15f1f38538dacc": 188530 + "377dc5e30dd1292ac1666dd43a447b861ad283024f70a3e914c7e11572ae869e": 185877 + "bb1729bd410275aab1bd276f99fb22678b6ad53de2c9c474fdda854ed0ebaebd": 185786 + "ca79318fa094531bd57b3f07d5b8574cd9986bac4c876043336ea4176e8c294f": 229908 + "f433d2bd7a0f0af23fe462fcd8df88e87fc0c8f908d92c7f67a4a2f7a320a441": 64787 + "5e00139aad86809adde7ad17bceeedda2a3177372df04fbe9a91bc3fa1366a5b": 64090 + "005fde87e6014290eb3c9e08712b6dc93dc3febf2d56c44094f37f34fe149d10": 64083 + "607706dd2f6675ee2ff5900fe82ae1b666e10bb17892eb9c2b5ba9d3391219b4": 63111 + "a248f4d3c9fdf4608e941d818317e5d86c2132c1140daa45bbf6a82f8f90a53c": 62328 + "4580c48aec859791cb1771caf7ff609f09af8a4d9352883d1b104d6039cb193b": 62727 + "1c30c5964567df2dcb1b86e70e41622aaf72d533effecc6ee0ef7348171eefdd": 78182 + "e51cd4fb90a3a233f8b19d0068f1f4dfd537198be60b25261069b86a463090d5": 2304585 + "253a7732af34b28f992072e84d9977d511844a0ebd238e94a5cb2f3fe254604c": 2296844 + "844fbdee84f718f211936a2aea851a6983af3501533af643afccb17314e30fd2": 2296990 + "71900ed318d6491eac58d5828b46e939f8dbcb5e1b1cb70c6bbc8c21bbe93192": 2375627 + "47e8a06001c02bd20d69431a76023baa4662a60127faf9fb8a3106d5f532dd29": 2369818 + "0b7a573709f3fad083805cd2cf0d7649721386a177cc18a08613c10a2d4c9753": 2370213 + "ea3542fea62b40b86e30d357fab3679ede4e2172662b594bf638464ae9708154": 2909281 + "aba14932d5689bc4f527838ff4750fcdce0c1f634d579e7e3b9fee4bd67d8c84": 1347170 + "4bb56ec3b3263b64169a57e3722f54f60ee048a57d290dfffc0481e09d05ceb3": 1700380 + "7d9d7b0073393cd9629f017b4dfe5866363884703fff78cbbff8a6cb39390f77": 1331524 + "b6dd4f6d440efce85e407f663b288586919fc99e442e94d0eb04f9371b34a65d": 1365231 + "23e6b429459601ee94ff71df2130d01e31498a2c2b6ffbc37223cb84fb71a06b": 1328513 + "3d61bf09ad35a994a36390723f15d2be2be9969a980884a45941300a8c9b33cf": 1335125 + "4e3b7e7e810be949b2182a3e30a0a95a5c478fa70abb07de852a14a7664bc548": 1368296 + "2d4dc47f318eb4b612c6082831602dabf86737abaf16205efca110f79d2c4582": 1324727 + "20a39d385f0cdc34029de2e0c030fc0787940a7be69cdcaa9de6899170cbb731": 1333301 + "cab828953672906e00a8f25db751977b8dc4115f021f8dfe82b644ade03dacdb": 132490 + "1afa5e6964d9418fb8bb2d489e5069becd55f963c1ea7a2a30ca838b17d9bf66": 10001457 + "ec6f9daf8e32d96f4a2f4cd56d18533ee47bb8d9e7cb3d832ac64115d8a1a4ca": 9999763 + "58665ec9e2873dba2799be5992eab3973f230acc352d09bd4a69131ac3ccd2d4": 10000104 + "f5b70155f3fdbf574843741924758ca05fc996263e348660ac817e75052dacf9": 9198838 + "f37328addd300e16046ee900f26d3ed026a6c810ea88269e114a4e0f06ed41b6": 9179125 + "28be258776e175a8c29a19be5312b885574a98324d7b03c7ec12f2d7eadcbce1": 9181826 + "005380f94547e270e9c8617fe0211c30daad8a5712d038f7edee3fb5bc0f1226": 10207312 + "072d224a0fa2a77bccde27eee39b65300a387613b41f07fc677108a7812ec003": 295860 + "eb7f28d86797461d5ef859d00629176e1ce3234790ef17b9ee3f9c9990a664e2": 303932 + "41a64c9856f7845bb4c21bba4f42eb55c640301b59c032eb4db416db19ecf97d": 326989 + "0fe21433f470130b972354d411d05f43ab37d82198565bb6b947734a95e98c5d": 321938 + "5143eaf34011a22dd1951f10495a7568e77a2e862fb9f4dbae9bab2f784f926e": 294960 + "d3a744d1aa95788a31c40fa0029e5f70631e81b040375bf92f18c845371a7f4a": 375089 + "f3c97e567f59c4a8ab79f8a3d66a32d109fc9a7c22891589b998edb6a4e5ba28": 314492 + "2cde67c8eef4e971ce74428a9162e9680d7a9ab542571f438602efe431d3a121": 316806 + "011e027433848f23cd9d96aee9f46531f48f8462bd763fe799e09b36eeaa4851": 314220 + "3db04118fec82077bd2b1a3e137f3a6a6037aeaa094865fc3d1187d7f795a308": 306614 + "f496e32077cc020a7ffcb6a6afee3034fc4c55ced685ba0b2155c0355bbf7a95": 361851 + "b465efbb59cafd4d9ea16cefd5b0d33c1411da49855e14b5864ce139b65df8c6": 362727 + "c418aa763659463002269201586cd356c69e6a233b2040ced02a352498b362d8": 432501 + "c0f9da975e59842256875121304fdb0825909f3c43b8cf1271b505cd7436955e": 361860 + "aa17026544ec683e544113478c07c1d387e3566d949c32834b083ad72042be16": 354507 + "a91555bb6c89202bbb68d84bfe425aeb63c50d4001c310d39643637d93bde290": 343754 + "dfcb200312b7e57c99699a47ffc0ed522f3fe4d1913037003b706fe545daa082": 326988 + "db6453b117d39f0fe310f30e0d92124c453dd1568edd5800fd886bdb2b35e9df": 142253 + "cd7bda731a8b2e5d1a3cdf5be6b515718c56d55d16a5b45faa1a91daf9c0ca2b": 139369 + "5fbb0e2a2cd9b17a416d518d324d9eb3eac88626851bad41d9fb144ccebd8757": 141350 + "4fca00c15a69f25064b40b12e37a6f552edd632f77e2947e076745b55aaeffd3": 139829 + "a5c180236137518d040277c1310e4b7c34337a0d396053e9a2534861453f70bc": 183645 + "a0d8bae54df1068c92ad894eddca0cd7465ecbaa3ef875c07c46bcea764bac71": 139279 + "6549fda9b8f6ac3904b55bc0b8c601ecf15773eb4c97c40091148559d69bfec1": 141486 + "f782643b254f58ddf3830272c0221f5d35db84ebd4f3d4ef19894ca0c91648ad": 139490 + "8ecf154f8c0bab71c0008c6f73eb8cd2df78cfa424d8bdcffc66dc95b3bf7c14": 139123 + } +} diff --git a/extract.pl b/extract.pl new file mode 100755 index 0000000..5c467df --- /dev/null +++ b/extract.pl @@ -0,0 +1,79 @@ +#!/usr/bin/perl -w +# Copyright (c) 2024 Dry Ark LLC +use strict; +use Cwd qw/getcwd/; + +opendir( my $dh, "bottle" ); +my @files = readdir( $dh ); +closedir( $dh ); + +my $totSize = 0; +my $totXSize = 0; +for my $file ( @files ) { + next if( $file =~ m/^\.+$/ ); + next if( $file !~ m/\.tar\.gz$/ ); + my $full = "bottle/$file"; + #print "$full\n"; + $totSize += -s $full; + my @lines = `gzip -l \"$full\"`; + my $line = $lines[1]; + $line =~ s/^ +//; + my @parts = split(/ +/,$line); + $totXSize += $parts[1]; +} + +my $hrSize = bytesToHR( $totXSize ); + +print "Total extracted size: $hrSize\n"; +#exit(0); + +print "Extracting packages...\n"; +my $doneSize = 0; +print_progress( 0 ); +my $cwd = getcwd(); +for my $file ( @files ) { + next if( $file =~ m/^\.+$/ ); + next if( $file !~ m/\.tar\.gz$/ ); + my $folder = $file; + $folder =~ s/\.tar\.gz$//; + if( $folder =~ m/^(.+)\-([0-9\.]+)$/ ) { + $folder = "$1\@$2"; + } + + #print "../tarball_incremental \"$file\" \"$cwd/minibrew/pkgs\"\n"; + #exit(0); + open( my $pipe, "./tarball_incremental \"bottle/$file\" \"$cwd/pkgs\" |" ); + my $prev = ''; + while( my $line = <$pipe> ) { + $doneSize += $line; + print_progress( int( ($doneSize/$totXSize)*100 ) ); + } + close( $pipe ); +} +print_progress( 100 ); +print "\n"; +my $hrDone = bytesToHR( $doneSize ); +print "Done extracted size: $hrDone\n"; + +sub bytesToHR { + my $bytes = shift; + if( $bytes > ( 1024 * 1024 ) ) { + my $num = int( $bytes / ( 1024 * 1024 ) * 100 ) / 100; + return "${num} mb"; + } + if( $bytes > 1024 ) { + my $num = int( $bytes / ( 1024 ) * 100 ) / 100; + return "${num} kb"; + } + return "${bytes} b"; +} + +sub print_progress { + my ($percent) = @_; + $percent *= 1.08; + $percent = 100 if( $percent > 100 ); + my $num_blocks = int($percent / 2); + my $bar = '[' . '=' x $num_blocks . ' ' x (50 - $num_blocks) . ']'; + printf("\r%s %3d%%", $bar, $percent); + STDOUT->flush(); # Flush the output buffer to update the display immediately +} \ No newline at end of file diff --git a/genbin.pl b/genbin.pl new file mode 100755 index 0000000..9cdb30a --- /dev/null +++ b/genbin.pl @@ -0,0 +1,100 @@ +#!/usr/bin/perl -w +# Copyright (c) 2024 Dry Ark LLC +use strict; +use FindBin qw($RealBin); + +my $libabs = "$RealBin/lib"; +my $binabs = "$RealBin/bin"; + +opendir( my $dh, "pkgs" ); +my @files = readdir( $dh ); +closedir( $dh ); + +for my $file ( @files ) { + next if( $file =~ m/^\.+$/ ); + next if( $file =~ m/~$/ ); + #next if( $file eq 'lib' ); + my $full = "pkgs/$file"; + next if( ! -d $full ); + handle_dir( $full ); +} + +sub handle_dir { + my $dir = shift; + + opendir( my $dh, "./$dir" ) or die "Could not open ./$dir"; + my @files = readdir( $dh ); + closedir( $dh ); + + for my $file ( @files ) { + next if( $file =~ m/^\.+$/ ); + if( $file =~ m/^[0-9\.\_]+$/ ) { + #print "$dir/$file\n"; + my $bindir = "$dir/$file/bin"; + if( -e $bindir ) { + #print "$libdir\n"; + handle_bin( $bindir ); + } + } + } +} + +sub handle_bin { + my $bindir = shift; + my @bins; + bin_rec( $bindir, "", \@bins ); + for my $bin ( @bins ) { + my $rel = $bin->{rel}; + my $full = $bin->{full}; + + + my $symlink = "bin/$rel"; + if( -e $symlink ) { + unlink $symlink; + } + + my $dest = "../$full"; + #if( -l $full ) { + # my $dest2 = readlink( $full ); + # my $pathToFull = $full; + # $pathToFull =~ s|/[^/]+||; + # my $newDest = "../$pathToFull/$dest2"; + # $dest = $newDest; + #} + #print "$rel -> $dest\n"; + + if( $rel eq 'python3' ) { + symlink( $dest, "bin/python3-real" ); + open( my $fh, ">bin/python3" ); + print $fh "#!/bin/bash\n". + "export PYTHONHOME=$libabs/pythonHome\n". + "exec $binabs/python3-real \"\$\@\"\n"; + close( $fh ); + chmod 0755, "bin/python3"; + } + else { + symlink( $dest, $symlink ); + } + } +} + +sub bin_rec { + my ( $abs, $rel, $res ) = @_; + opendir( my $dh, $abs ); + my @files = readdir( $dh ); + closedir( $dh ); + + for my $file ( @files ) { + next if( $file =~ m/^\.+$/ ); + my $full = "$abs/$file"; + if( -d $full ) { + #dylib_rec( $full, $rel ? "$rel/$file" : "$file", $res ); + } + elsif( -x $full ) { + push( @$res, { + full => $full, + rel => ( $rel ? "$rel/$file" : "$file" ), + } ); + } + } +} \ No newline at end of file diff --git a/genlib.pl b/genlib.pl new file mode 100755 index 0000000..a6469fb --- /dev/null +++ b/genlib.pl @@ -0,0 +1,92 @@ +#!/usr/bin/perl -w +# Copyright (c) 2024 Dry Ark LLC +use strict; + +opendir( my $dh, "pkgs" ); +my @files = readdir( $dh ); +closedir( $dh ); + +for my $file ( @files ) { + next if( $file =~ m/^\.+$/ ); + next if( $file =~ m/~$/ ); + next if( $file eq 'lib' ); + my $full = "pkgs/$file"; + next if( ! -d $full ); + handle_dir( $full, $file ); +} + +sub handle_dir { + my ( $dir, $pkg ) = @_; + + opendir( my $dh, "./$dir" ) or die "Could not open ./$dir"; + my @files = readdir( $dh ); + closedir( $dh ); + + for my $file ( @files ) { + next if( $file =~ m/^\.+$/ ); + if( $file =~ m/^[0-9\.\_]+$/ ) { + #print "$dir/$file\n"; + my $libdir = "$dir/$file/lib"; + if( -e $libdir ) { + #print "$libdir\n"; + handle_lib( $libdir ); + } + + if( $pkg =~ m/^python/ ) { + if( $file =~ m/^([0-9]+)\.([0-9]+)/ ) { + my $twoParts = "$1.$2"; + my $pyHome = "../$dir/$file/Frameworks/Python.framework/Versions/$twoParts"; + symlink( $pyHome, "lib/pythonHome" ); + } + } + } + } +} + +sub handle_lib { + my $libdir = shift; + my @dylibs; + dylib_rec( $libdir, "", \@dylibs ); + for my $dy ( @dylibs ) { + my $rel = $dy->{rel}; + my $full = $dy->{full}; + + + my $symlink = "lib/$rel"; + if( -e $symlink ) { + unlink $symlink; + } + + my $dest = "../$full"; + #if( -l $full ) { + # my $dest2 = readlink( $full ); + # my $pathToFull = $full; + # $pathToFull =~ s|/[^/]+||; + # my $newDest = "../$pathToFull/$dest2"; + # $dest = $newDest; + #} + #print "$rel -> $dest\n"; + symlink( $dest, $symlink ); + } +} + +sub dylib_rec { + my ( $abs, $rel, $res ) = @_; + opendir( my $dh, $abs ); + my @files = readdir( $dh ); + closedir( $dh ); + + for my $file ( @files ) { + next if( $file =~ m/^\.+$/ ); + my $full = "$abs/$file"; + if( -d $full ) { + dylib_rec( $full, $rel ? "$rel/$file" : "$file", $res ); + } + elsif( $file =~ m/\.dylib$/ ) { + push( @$res, { + full => $full, + rel => ( $rel ? "$rel/$file" : "$file" ), + } ); + } + } +} \ No newline at end of file diff --git a/lib/.gitkeep b/lib/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/mod/Ujsonin.pm b/mod/Ujsonin.pm new file mode 100644 index 0000000..d5cb76e --- /dev/null +++ b/mod/Ujsonin.pm @@ -0,0 +1,271 @@ +# Copyright (c) 2024 Dry Ark LLC +package Ujsonin; + +my $handlers = {}; + +sub handle_true { + my ( $data, $pos ) = @_; + return { node => 1 }; #{ _type => 6 } }; +} + +sub handle_false { + my ( $data, $pos ) = @_; + return { node => 0 }; #{ _type => 7 } }; +} + +sub handle_null { + my ( $data, $pos ) = @_; + return { node => 0 }; #{ _type => 8 } }; +} + +sub init { + $handlers->{"true"} = [ \&handle_true, 0 ]; + $handlers->{"false"} = [ \&handle_false, 0 ]; + $handlers->{"null"} = [ \&handle_null, 0 ]; +} + +sub parse { + my ( $data, $beginState ) = @_; + my $pos = 0; + my $endstate = 0; + my $neg = 0; + my ( $keyLen,$typeStart,$keyStart,$strStart,$let,@stack ); + my $root = { _type => 1 }; + my $cur = $root; + my $len = length( $data ); +Begin: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos++, 1 ); + #print "Let: $let\n"; + if( $let eq '{' ) { goto Hash; } + if( $let eq '[' ) { + #print "Starting with array\n"; + $root = $cur = { _parent => undef, _type => 3, arr => [] }; + goto AfterColon; + } + goto Begin; +Hash: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos++, 1 ); + if( $let eq '"' ) { goto QQKeyName1; } + if( $let eq '\'' ) { goto QKeyName1; } + if( ord($let) >= ord('a') && ord($let) <= ord('z') ) { $pos--; goto KeyName1; } + if( $let eq '}' && $cur->{_parent} ) { + $cur = $cur->{_parent}; + if( $cur->{_type} == 3 ) { goto AfterColon; } + goto Hash; + } + if( $let eq '/' && $pos < ($len-1) ) { + if( substr( $data, $pos, 1 ) eq '/' ) { $pos++; goto HashComment; } + if( substr( $data, $pos, 1 ) eq '*' ) { $pos++; goto HashComment2; } + } + goto Hash; +HashComment: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos++, 1 ); + if( $let eq "\x0d" || $let eq "\x0a" ) { goto Hash; } + goto HashComment; +HashComment2: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos++, 1 ); + if( $let eq '*' && $pos < ($len-1) && substr( $data, $pos, 1 ) eq '/' ) { $pos++; goto Hash; } + goto HashComment2; +QQKeyName1: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos, 1 ); + $keyStart = $pos++; + if( $let eq '\\' ) { $pos++; } +QQKeyNameX: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos++, 1 ); + if( $let eq '\\' ) { $pos++; goto QQKeyNameX; } + if( $let eq '"' ) { + $keyLen = ( $pos-1 ) - $keyStart; + goto Colon; + } + goto QQKeyNameX; +QKeyName1: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos, 1 ); + $keyStart = substr( $data, $pos++, 1 ); + if( $let eq '\\' ) { $pos++; } +QKeyNameX: $let = substr( $data, $pos++, 1 ); + if( $let eq '\\' ) { $pos++; goto QKeyNameX; } + if( $let eq '\'' ) { + $keyLen = ( $pos-1 ) - $keyStart; + goto Colon; + } + goto QKeyNameX; +KeyName1: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos, 1 ); + $keyStart = $pos++; +KeyNameX: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos++, 1 ); + if( $let eq ':' ) { + $keyLen = ($pos-1) - $keyStart; + goto AfterColon; + } + if( $let eq ' ' || $let eq '\t' ) { + $keyLen = ($pos-1) - $keyStart; + goto Colon; + } + goto KeyNameX; +Colon: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos++, 1 ); + if( $let eq ':' ) { goto AfterColon; } + goto Colon; +AfterColon: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos++, 1 ); + if( $let eq '"' ) { goto String1; } + if( $let eq '{' ) { + my $newHash = { _type => 1, _parent => $cur }; + #$newHash->{_parent} = $cur; + if( $cur->{_type} == 1 ) { $cur->{ substr( $data, $keyStart, $keyLen ) } = $newHash; } + if( $cur->{_type} == 3 ) { push( @{$cur->{arr}}, $newHash ); } + $cur = $newHash; + goto Hash; + } + if( ord($let) >= ord('a') && ord($let) <= ord('z') ) { + $typeStart = $pos - 1; + goto TypeX; + } + if( $let eq '/' && $pos < ($len-1) ) { + if( substr( $data, $pos, 1 ) eq '/' ) { $pos++; goto AC_Comment; } + if( substr( $data, $pos, 1 ) eq '*' ) { $pos++; goto AC_Comment2; } + } + # if( $let == 't' || $let == 'f' ) ... for true/false + if( ord($let) >= ord('0') && ord($let) <= ord('9') ) { $neg=0; goto Number1; } + if( $let eq '-' ) { $neg=1; $pos++; goto Number1; } + if( $let eq '[' ) { + push( @stack, $cur ); + my $arr = []; + my $newArr = { _parent => $cur, _type => 3, arr => $arr }; + if( $cur->{_type} == 1 ) { $cur->{ substr( $data, $keyStart, $keyLen ) } = $arr; } + if( $cur->{_type} == 3 ) { push( @{$cur->{arr}}, $arr ); } + $cur = $newArr; + goto AfterColon; + } + if( $let eq ']' ) { + $cur = pop( @stack ); #$cur->{_parent}; + if( !$cur ) { goto Done; } + if( $cur->{_type} == 3 ) { goto AfterColon; } + if( $cur->{_type} == 1 ) { goto Hash; } + # should never reach here + } + goto AfterColon; +TypeX: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos++, 1 ); + if( ( ord($let) >= ord('0') && ord($let) <= ord('9') ) || ( ord($let) >= ord('a') && ord($let) <= ord('z') ) ) { goto TypeX; } + $pos--; # go back a character; we've encountered a non-type character + # Type name is done + $typeLen = $pos - $typeStart; + # do something with the type + my $info = $handlers->{ substr( $data, $typeStart, $typeLen ) }; + my $handler = $info->[0]; + my $htype = $info->[1]; + if( !$handler ) { + print("disaster"); + exit(1); + } + my $res = $handler->( $data, $pos ); + if( !$res ) { + print("disaster"); + exit(1); + } + if( !$res->{dest} ) { + if( $cur->{_type} == 1 ) { + $cur->{ substr( $data, $keyStart, $keyLen ) } = $res->{node}; + goto AfterVal; + } + if( $cur->{_type} == 3 ) { + push( @{$cur->{arr}}, $res->{node} ); + goto AfterColon; + } + } + goto TypeX; # should never reach here +Arr: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos++, 1 ); + # TODO: stack of array tails + if( $let eq ']' ) { + goto AfterVal; + } + goto Arr; +AC_Comment: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos++, 1 ); + if( $let eq "\x0d" || $let eq "\x0a" ) { goto AfterColon; } + goto AC_Comment; +AC_Comment2: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos++, 1 ); + if( $let eq '*' && $pos < ($len-1) && substr( $data, $pos, 1 ) eq '/' ) { $pos++; goto Hash; } + goto AC_Comment2; +Number1: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos, 1 ); + $strStart = $pos-1; +NumberX: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos++, 1 ); + #if( $let eq '.' ) goto AfterDot; + if( ord($let) < ord('0') || ord($let) > ord('9') ) { + my $strLen = ( $pos-1 ) - $strStart; + my $num = substr( $data, $strStart, $strLen ) * 1; + $num *= -1 if( $neg ); + if( $cur->{_type} == 1 ) { + $cur->{ substr( $data, $keyStart, $keyLen ) } = $num; + goto AfterVal; + } + if( $cur->{_type} == 3 ) { + push( @{$cur->{arr}}, $num ); + goto AfterColon; + } + } + goto NumberX; +#AfterDot: SAFEGET +String1: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos++, 1 ); + if( $let eq '"' ) { + if( $cur->{_type} == 1 ) { + $cur->{ substr( $data, $keyStart, $keyLen ) } = ""; + goto AfterVal; + } + if( $cur->{_type} == 3 ) { + push( @{$cur->{arr}}, "" ); + goto AfterColon; + } + goto AfterVal; # Should never be reached + } + $strStart = $pos-1; +StringX: + goto Done if( $pos >= $len ); + $let = substr( $data, $pos++, 1 ); + if( $let eq '"' ) { + my $strLen = ($pos-1) - $strStart; + my $newStr = substr( $data, $strStart, $strLen ); + if( $cur->{_type} == 1 ) { + $cur->{ substr( $data, $keyStart, $keyLen ) } = $newStr; + goto AfterVal; + } + if( $cur->{_type} == 3 ) { + push( @{$cur->{arr}}, $newStr ); + goto AfterColon; + } + goto AfterVal; # should never be reached + } + goto StringX; +AfterVal: + # who cares about commas in between things; we can just ignore them :D + goto Hash; +Done: + return $root; +} + +1; \ No newline at end of file diff --git a/pkgs/.gitkeep b/pkgs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/rebase.pl b/rebase.pl new file mode 100755 index 0000000..551fbaf --- /dev/null +++ b/rebase.pl @@ -0,0 +1,89 @@ +#!/usr/bin/perl -w +# Copyright (c) 2024 Dry Ark LLC +use strict; +use FindBin qw($RealBin); + +my $libabs = "$RealBin/lib"; + +my $arch = `uname -m`; +$arch =~ s/\n//; + +my $install_name_tool = "install_name_tool"; +if( ! -e "/usr/bin/install_name_name" ) { + $install_name_tool = "./install_name_tool"; +} + +my @lines = `./scan pkgs test share`; +my %files; +my $fileob; +for my $line ( @lines ) { + if( $line =~ m/^File:(.+)/ ) { + my $file = $1; + #print "File:$file\n"; + $fileob = { imports => [] }; + $files{ $file } = $fileob; + next; + } + if( $line =~ m/^ *LC_LOAD_DYLIB:(.+)/ ) { + my $import = $1; + push( @{ $fileob->{imports} }, $import ); + } +} + +my $count = keys %files; +my $done = 0; +my %checked; +print "Files to rebase: $count\n"; +print_progress(0); + +for my $file ( sort keys %files ) { + next if( -l $file ); + #print "File:$file\n"; + + my $ob = $files{$file}; + my $imports = $ob->{imports}; + my @changes; + for my $import ( @$imports ) { + my $rep = $import; + $rep =~ s|.+/(.+)$|$1|; + my $rep1 = $rep; + + $rep = "$libabs/$rep"; + + push( @changes, "-change \"$import\" \"$rep\"" ); + check_lib_existence( $rep1, $import ); + } + my $change = join( ' ', @changes ); + #print "install_name_tool $change \"$file\"\n"; + `$install_name_tool $change \"$file\" 2>/dev/null`; + if( $arch eq 'arm64' ) { + `codesign --sign - --force --preserve-metadata=entitlements,requirements,flags,runtime \"$file\" 2>/dev/null`; + } + $done++; + print_progress( int( ($done/$count)*100 ) ); +} +print_progress( 100 ); +print "\n"; + +sub check_lib_existence { + my ( $file, $import ) = @_; + return if( $checked{ $file } ); + $checked{ $file } = 1; + if( ! -e "lib/$file" ) { + if( $import =~ m/\@\@HOMEBREW_CELLAR\@\@(.+)/ ) { + my $dest = "../pkgs$1"; + #print "Missing lib/$file -> $dest\n"; + symlink( $dest, "lib/$file" ); + } + } +} + +sub print_progress { + my ($percent) = @_; + $percent *= 1.08; + $percent = 100 if( $percent > 100 ); + my $num_blocks = int($percent / 2); + my $bar = '[' . '=' x $num_blocks . ' ' x (50 - $num_blocks) . ']'; + printf("\r%s %3d%%", $bar, $percent); + STDOUT->flush(); # Flush the output buffer to update the display immediately +} \ No newline at end of file diff --git a/scan.c b/scan.c new file mode 100644 index 0000000..adbc6bc --- /dev/null +++ b/scan.c @@ -0,0 +1,192 @@ +// Copyright (c) 2024 Dry Ark LLC +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +void readMachO(const char *path); + +#define MAX_EXCLUDES 10 // Maximum number of directories that can be excluded + +// Check if directory should be excluded +int is_excluded(const char *dir, char exclude[][256], int exclude_count) { + for (int i = 0; i < exclude_count; i++) { + if (strcmp(dir, exclude[i]) == 0) { + return 1; + } + } + return 0; +} + +void scan_directory(const char *path, char exclude[][256], int exclude_count) { + DIR *dir; + struct dirent *entry; + struct stat statbuf; + + if (!(dir = opendir(path))) { + perror("Failed to open directory"); + return; + } + + while ((entry = readdir(dir)) != NULL) { + char fullpath[1024]; + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + + snprintf(fullpath, sizeof(fullpath), "%s/%s", path, entry->d_name); + + // Check if this directory should be excluded + if (entry->d_type == DT_DIR && is_excluded(entry->d_name, exclude, exclude_count)) { + //printf("Skipping excluded directory: %s\n", fullpath); + continue; + } + + if (stat(fullpath, &statbuf) == -1) { + perror("Failed to get file stats"); + continue; + } + + if (S_ISDIR(statbuf.st_mode)) { + // Recursively scan the directory + scan_directory(fullpath, exclude, exclude_count); + } else if (S_ISREG(statbuf.st_mode)) { + // Check for 'dylib' extension + + int ok = 0; + if (strstr(entry->d_name, ".dylib")) { + //printf("File:%s\n", fullpath); + ok = 1; + } + // Check if the file is executable + else if (statbuf.st_mode & S_IXUSR) { + if( + !strstr(entry->d_name, ".so") && + !strstr(entry->d_name, ".py") && + !strstr(entry->d_name, ".pl") + ) { + FILE *file = fopen(fullpath, "rb"); + if( !file ) continue; + unsigned char bytes[1]; + if (fread(bytes, 1, 1, file) != 1) { + fclose( file ); + continue; + } + fclose( file ); + if( bytes[0] != '#' ) { + //printf("File:%s\n", fullpath); + ok = 1; + } + } + } + + if( ok ) { + readMachO( fullpath ); + } + } + } + + closedir(dir); +} + +int main(int argc, char *argv[]) { + char *root_dir = "."; + char exclude[MAX_EXCLUDES][256]; // Array to store names of directories to exclude + int exclude_count = 0; + + // Assuming directories to exclude are passed after the root directory argument + root_dir = argc > 1 ? argv[1] : root_dir; + for (int i = 2; i < argc && exclude_count < MAX_EXCLUDES; i++) { + strncpy(exclude[exclude_count++], argv[i], 255); + exclude[exclude_count - 1][255] = '\0'; // Ensure null termination + } + + //printf("Scanning directory: %s\n", root_dir); + for (int i = 0; i < exclude_count; i++) { + //printf("Excluding directory: %s\n", exclude[i]); + } + + scan_directory(root_dir, exclude, exclude_count); + + return 0; +} + +void readMachO(const char *path) { + int fd = open( path, O_RDONLY ); + if (fd == -1) { + perror("Failed to open file"); + return; + } + + struct stat stat_buf; + if (fstat(fd, &stat_buf) == -1) { + perror("Failed to get file stats"); + close(fd); + return; + } + + void *map = mmap(NULL, stat_buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (map == MAP_FAILED) { + perror("Failed to map file"); + close(fd); + return; + } + + struct mach_header_64 *mh; + struct load_command *lc; + struct fat_header *fh = (struct fat_header *)map; + unsigned char *bmap = (unsigned char *) map; + + int filePrinted = 0; + if (fh->magic == FAT_MAGIC || fh->magic == FAT_CIGAM) { + // It's a FAT binary, iterate through architectures + struct fat_arch *archs = (struct fat_arch *)(fh + 1); + for (int i = 0; i < ntohl(fh->nfat_arch); i++) { + uint32_t offset = ntohl(archs[i].offset); + struct mach_header_64 *mh = (struct mach_header_64 *)((char *)map + offset); + //printArch(ntohl(archs[i].cputype), ntohl(archs[i].cpusubtype)); + struct load_command *lc = (struct load_command *)(mh + 1); + for (uint32_t j = 0; j < mh->ncmds; j++) { + if (lc->cmd == LC_LOAD_DYLIB) { + struct dylib_command *dylib = (struct dylib_command *)lc; + printf(" LC_LOAD_DYLIB:%s\n", (char *)dylib + dylib->dylib.name.offset); + } + lc = (struct load_command *)((char *)lc + lc->cmdsize); + } + } + } + //my $mach_o_magic = "\xCF\xFA\xED\xFE"; + else if( bmap[0] == 0xcf && bmap[1] == 0xfa && bmap[2] == 0xed && bmap[3] == 0xfe ) { + // It's a non-FAT binary + struct mach_header_64 *mh = (struct mach_header_64 *)map; + //printArch(mh->cputype, mh->cpusubtype); + struct load_command *lc = (struct load_command *)(mh + 1); + for (uint32_t i = 0; i < mh->ncmds; i++) { + if (lc->cmd == LC_LOAD_DYLIB) { + struct dylib_command *dylib = (struct dylib_command *)lc; + char *dylibn = (char *)dylib + dylib->dylib.name.offset; + if( dylibn[0] == '@' && dylibn[1] == '@' ) { + if( !filePrinted ) { + printf("File:%s\n", path ); + filePrinted = 1; + } + printf(" LC_LOAD_DYLIB:%s\n", (char *)dylib + dylib->dylib.name.offset); + } + } + lc = (struct load_command *)((char *)lc + lc->cmdsize); + } + } + + munmap(map, stat_buf.st_size); + close(fd); +} diff --git a/tarball_incremental.c b/tarball_incremental.c new file mode 100644 index 0000000..14b2d7c --- /dev/null +++ b/tarball_incremental.c @@ -0,0 +1,220 @@ +// Copyright (c) 2024 Dry Ark LLC +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // For dirname +#include + +#define CHUNK_SIZE 102400 // Chunk size of 100 KB + +// Function to create directories recursively +int create_dir_recursively(const char *dir_path, mode_t mode) { + char tmp[1024]; + strncpy(tmp, dir_path, sizeof(tmp)); + tmp[sizeof(tmp) - 1] = '\0'; + char *p = NULL; + + // Iterate over subpaths and create directories as needed + for (p = tmp + 1; *p; p++) { + if (*p == '/') { + *p = '\0'; + if (mkdir(tmp, mode) != 0 && errno != EEXIST) { + return -1; // Fail if unable to create directory and it doesn't already exist + } + *p = '/'; + } + } + return mkdir(tmp, mode); +} + +int main(int argc, char *argv[]) { + void *libarchive_handle; + struct archive *(*archive_read_new)(); + int (*archive_read_support_filter_all)(struct archive *); + int (*archive_read_support_format_all)(struct archive *); + int (*archive_read_open_filename)(struct archive *, const char *, size_t); + struct archive_entry *(*archive_read_next_header)(struct archive *, struct archive_entry **); + int (*archive_read_free)(struct archive *); + ssize_t (*archive_read_data)(struct archive *, void *, size_t); + const char *(*archive_entry_pathname)(struct archive_entry *); + int64_t (*archive_entry_size)(struct archive_entry *); + unsigned int (*archive_entry_filetype)(const struct archive_entry *); + const char *(*archive_entry_symlink)(struct archive_entry *); + struct archive *(*archive_write_disk_new)(); + int (*archive_write_disk_set_options)(struct archive *, int); + int (*archive_write_header)(struct archive *, struct archive_entry *); + int (*archive_write_finish_entry)(struct archive *); + int (*archive_write_free)(struct archive *); + const char *(*archive_error_string)(struct archive *); + mode_t (*archive_entry_mode)(struct archive_entry *); + void (*archive_entry_set_pathname)(struct archive_entry *, const char *); + + // Load the dynamic library + libarchive_handle = dlopen("libarchive.dylib", RTLD_LAZY); + if (!libarchive_handle) { + fprintf(stderr, "Failed to load libarchive.\n"); + exit(1); + } + + // Load the necessary libarchive functions + archive_read_new = dlsym(libarchive_handle, "archive_read_new"); + archive_read_support_filter_all = dlsym(libarchive_handle, "archive_read_support_filter_all"); + archive_read_support_format_all = dlsym(libarchive_handle, "archive_read_support_format_all"); + archive_read_open_filename = dlsym(libarchive_handle, "archive_read_open_filename"); + archive_read_next_header = dlsym(libarchive_handle, "archive_read_next_header"); + archive_read_free = dlsym(libarchive_handle, "archive_read_free"); + archive_read_data = dlsym(libarchive_handle, "archive_read_data"); + archive_entry_pathname = dlsym(libarchive_handle, "archive_entry_pathname"); + archive_entry_size = dlsym(libarchive_handle, "archive_entry_size"); + archive_entry_filetype = dlsym(libarchive_handle, "archive_entry_filetype"); + archive_entry_symlink = dlsym(libarchive_handle, "archive_entry_symlink"); + archive_write_disk_new = dlsym(libarchive_handle, "archive_write_disk_new"); + archive_write_disk_set_options = dlsym(libarchive_handle, "archive_write_disk_set_options"); + archive_write_header = dlsym(libarchive_handle, "archive_write_header"); + archive_write_finish_entry = dlsym(libarchive_handle, "archive_write_finish_entry"); + archive_write_free = dlsym(libarchive_handle, "archive_write_free"); + archive_error_string = dlsym(libarchive_handle, "archive_error_string"); + archive_entry_mode = dlsym(libarchive_handle, "archive_entry_mode"); + archive_entry_set_pathname = dlsym(libarchive_handle, "archive_entry_set_pathname"); + + if (!archive_read_new || !archive_read_support_filter_all || !archive_read_support_format_all || + !archive_read_open_filename || !archive_read_next_header || !archive_read_free || + !archive_read_data || !archive_entry_pathname || !archive_entry_size || + !archive_entry_filetype || !archive_entry_symlink || !archive_write_disk_new || + !archive_write_disk_set_options || !archive_write_header || + !archive_write_finish_entry || !archive_write_free || !archive_error_string || + !archive_entry_mode ) { + fprintf(stderr, "Failed to load functions.\n"); + exit(1); + } + + if (argc != 3) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(1); + } + + struct archive *a; + struct archive *a_disk; + struct archive_entry *entry; + int r; + + a = archive_read_new(); + archive_read_support_filter_all(a); + archive_read_support_format_all(a); + + r = archive_read_open_filename(a, argv[1], 10240); // Block size 10 KB + if (r != ARCHIVE_OK) { + fprintf(stderr, "Could not open archive: %s\n", argv[1]); + exit(1); + } + + // Ensure output directory exists; create it if not + struct stat st = {0}; + if (stat(argv[2], &st) == -1) { + mkdir(argv[2], 0755); + } + + long runningTotal = 0; + while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { + const char *path = archive_entry_pathname(entry); + char full_path[1024]; + snprintf(full_path, sizeof(full_path), "%s/%s", argv[2], path); + archive_entry_set_pathname(entry, full_path); + + mode_t mode = archive_entry_mode(entry); + + // Set file attributes + a_disk = archive_write_disk_new(); + archive_write_disk_set_options(a_disk, ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS); + archive_write_header(a_disk, entry); + archive_write_finish_entry(a_disk); + archive_write_free(a_disk); + + switch (archive_entry_filetype(entry)) { + case AE_IFREG: { + char *dir = dirname(full_path); + if( create_dir_recursively(dir, 0755) != 0 ) { + if( errno != EEXIST ) { + char error[400]; + snprintf( error, 400, "Failed to create dir: %s", dir ); + perror( error ); + continue; + } + } + + // Check if the file exists and unlink if not writable + struct stat file_stat; + if (stat(full_path, &file_stat) == 0) { // File exists + if (!(file_stat.st_mode & S_IWUSR)) { // Check if file is not writable + if (unlink(full_path) != 0) { // Attempt to delete the file + perror("Failed to delete existing file"); + continue; + } + } + } + + int fd = open(full_path, O_WRONLY | O_CREAT | O_TRUNC, mode); + if (fd == -1) { + char error[400]; + snprintf( error, 400, "Failed to open file for writing: %s",full_path ); + perror( error ); + continue; + } + + //printf("Extracting: %s\n", full_path); + + size_t total = 0; + ssize_t size; + char buffer[CHUNK_SIZE]; + while ((size = archive_read_data(a, buffer, CHUNK_SIZE)) > 0) { + if (write(fd, buffer, size) != size) { + perror("Failed to write all bytes"); + close(fd); + unlink(full_path); + break; + } + total += size; + if (total % CHUNK_SIZE == 0 || size < CHUNK_SIZE) { + //printf("%lu\n", size); + runningTotal += size; + if( runningTotal >= CHUNK_SIZE ) { + printf("%lu\n", runningTotal); + fflush( stdout ); + runningTotal = 0; + } + //printf("Written %lu KB of %s - Chunk=%lu\n", total / 1024, full_path, size); + } + } + close(fd); + break; + } + case AE_IFDIR: { + if (create_dir_recursively(full_path, mode) != 0) { + //perror("Failed to create directory"); + } + break; + } + case AE_IFLNK: { + const char *target = archive_entry_symlink(entry); + symlink(target, full_path); + break; + } + } + + + } + if( runningTotal > 0 ) { + printf("%lu\n", runningTotal); + } + + archive_read_free(a); + dlclose(libarchive_handle); + + return 0; +}