00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "common_bundle.h"
00022
00023 #include <basis/array.cpp>
00024 #include <basis/byte_array.h>
00025 #include <basis/portable.h>
00026 #include <data_struct/string_table.h>
00027 #include <opsystem/application_shell.h>
00028 #include <opsystem/byte_filer.h>
00029 #include <opsystem/command_line.h>
00030 #include <loggers/console_logger.h>
00031 #include <opsystem/directory.h>
00032 #include <opsystem/filename.h>
00033 #include <loggers/file_logger.h>
00034 #include <opsystem/filetime.h>
00035 #include <opsystem/ini_config.h>
00036 #include <opsystem/path_configuration.h>
00037 #include <data_struct/static_memory_gremlin.h>
00038 #include <textual/byte_format.h>
00039 #include <textual/list_parsing.h>
00040 #include <textual/parser_bits.h>
00041 #include <textual/tokenizer.h>
00042
00043 #include <stdio.h>
00044 #include <sys/stat.h>
00045 #include <zlib.h>
00046 #ifdef __WIN32__
00047 #include <io.h>
00048 #endif
00049
00050 const int CHUNKING_SIZE = 256 * KILOBYTE;
00051
00052
00053 #define BASE_LOG(to_print) program_wide_logger().log(to_print)
00054 #define LOG(to_print) CLASS_EMERGENCY_LOG(program_wide_logger(), to_print)
00055
00056
00057
00058
00059
00060 #define FAIL_RETURN(retval, where) { \
00061 LOG(istring("failure in ") + where + isprintf(", exit=%d", retval)); \
00062 return retval; \
00063 }
00064
00066
00067 inline bool true_value(const istring &value)
00068 { return (value != "0") && (value != "false"); }
00069
00071
00072
00073
00074 struct bundled_chunk : manifest_chunk
00075 {
00076 istring _source;
00077 virtual ~bundled_chunk() {}
00078 };
00079
00081
00082
00083
00084 class bundle_creator : public application_shell
00085 {
00086 public:
00087 bundle_creator()
00088 : application_shell(static_class_name()),
00089 _app_name(filename(__argv[0]).basename()),
00090 _bundle(NIL), _stub_size(0), _keyword() {}
00091
00092 virtual ~bundle_creator() {
00093 WHACK(_bundle);
00094 }
00095
00096 IMPLEMENT_CLASS_NAME("bundle_creator");
00097 virtual int execute();
00098 int print_instructions();
00099
00100 int open_output_file();
00102
00104 int read_manifest();
00106
00108 int write_stub_and_toc();
00110
00111 int bundle_sources();
00113
00114 int finalize_file();
00116
00117 int write_offset();
00119
00121 int patch_recursive_target(const istring &source, const istring &target,
00122 int manifest_index);
00124
00128 int recurse_into_dir(const istring &source, const istring &target,
00129 int manifest_index);
00131
00132 int patch_wildcard_target(const istring &source, const istring &target,
00133 int manifest_index);
00135
00137 int add_files_here(directory &dirndl, const istring &source,
00138 const istring &target, int manifest_index);
00140
00141 bool get_file_size(const istring &file, int &size, byte_array ×tamp);
00143
00144 private:
00145 istring _app_name;
00146 istring _output_file;
00147 istring _manifest_file;
00148 array<bundled_chunk> _manifest_list;
00149 byte_filer *_bundle;
00150 int _stub_size;
00151 istring _keyword;
00152 };
00153
00155
00156 int bundle_creator::print_instructions()
00157 {
00158 BASE_LOG(isprintf("\
00159 %s: This program needs two parameters on the command line.\n\
00160 The -o flag must point at the bundled output file to create. The -m flag\n\
00161 must point at a valid manifest file that defines what will be packed into\n\
00162 the output file. See the example manifest file for more information on\n\
00163 the required file format.\n\
00164 ", _app_name.s()));
00165 return 4;
00166 }
00167
00168 int bundle_creator::execute()
00169 {
00170 FUNCDEF("execute");
00171
00172 BASE_LOG(istring("starting file bundling at ") + timestamp(false, true));
00173
00174 command_line cmds(__argc, __argv);
00175 istring temp;
00176 if (cmds.get_value('?', temp)) return print_instructions();
00177 if (cmds.get_value("?", temp)) return print_instructions();
00178 if (!cmds.get_value('o', _output_file)) return print_instructions();
00179 if (!cmds.get_value('m', _manifest_file)) return print_instructions();
00180
00181 if (filename(_output_file).exists()) {
00182 BASE_LOG(isprintf("\
00183 %s: The output file already exists. Please move it out of\n\
00184 the way; this program will not overwrite existing files.\n",
00185 _app_name.s()));
00186 return 3;
00187 }
00188
00189 if (!filename(_manifest_file).exists()) {
00190 BASE_LOG(isprintf("\
00191 %s: The manifest file does not exist. This program cannot do anything\n\
00192 without a valid packing manifest.\n", _app_name.s()));
00193 return 2;
00194 }
00195
00196
00197 cmds.get_value("keyword", _keyword);
00198
00199
00200
00201
00202
00203
00204 #ifndef __WIN32__
00205 portable::set_environ("EXE_END", "");
00206 portable::set_environ("DLL_START", "lib");
00207 portable::set_environ("DLL_END", ".so");
00208 #else
00209 portable::set_environ("EXE_END", ".exe");
00210 portable::set_environ("DLL_START", "");
00211 portable::set_environ("DLL_END", ".dll");
00212 #endif
00213
00214 int ret = 0;
00215 if ( (ret = read_manifest()) ) FAIL_RETURN(ret, "reading manifest");
00216
00217 if ( (ret = open_output_file()) ) FAIL_RETURN(ret, "opening output file");
00218
00219 if ( (ret = write_stub_and_toc()) ) FAIL_RETURN(ret, "writing stub and TOC");
00220
00221
00222 if ( (ret = bundle_sources()) ) FAIL_RETURN(ret, "bundling source files");
00223
00224 if ( (ret = finalize_file()) ) FAIL_RETURN(ret, "finalizing file");
00225
00226 if ( (ret = write_offset()) ) FAIL_RETURN(ret, "writing offset");
00227
00228
00229
00230
00231 return 0;
00232 }
00233
00234 int bundle_creator::open_output_file()
00235 {
00236 FUNCDEF("open_output_file");
00237 _bundle = new byte_filer(_output_file, "wb");
00238 if (!_bundle->good()) {
00239 LOG(istring("failed to open the output file: ") + _output_file);
00240 return 65;
00241 }
00242 return 0;
00243 }
00244
00245 bool bundle_creator::get_file_size(const istring &infile, int &size,
00246 byte_array &time_stamp)
00247 {
00248 FUNCDEF("get_file_size");
00249 time_stamp.reset();
00250
00251 byte_filer source_file(infile, "rb");
00252 if (!source_file.good()) {
00253 LOG(istring("could not access the file for size check: ") + infile);
00254 return false;
00255 }
00256 size = int(source_file.length());
00257 file_time tim(infile);
00258 tim.pack(time_stamp);
00259 return true;
00260 }
00261
00262 int bundle_creator::add_files_here(directory &dirndl, const istring &source,
00263 const istring &target, int manifest_index)
00264 {
00265 FUNCDEF("add_files_here");
00266 for (int i = 0; i < dirndl.files().length(); i++) {
00267 istring s = dirndl.files()[i];
00268
00269 bundled_chunk new_guy;
00270 new_guy._source = source + "/" + s;
00271 new_guy._target = target + "/" + s;
00272 new_guy._keywords = _manifest_list[manifest_index]._keywords;
00273
00274
00275 bool okaysize = get_file_size(new_guy._source, new_guy._size,
00276 new_guy._timestamp);
00277 if (!okaysize || (new_guy._size < 0) ) {
00278 LOG(istring("failed to get file size for ") + new_guy._source);
00279 return 75;
00280 }
00281
00282 _manifest_list.insert(manifest_index + 1, 1);
00283 _manifest_list[manifest_index + 1] = new_guy;
00284 }
00285 return 0;
00286 }
00287
00288 int bundle_creator::recurse_into_dir(const istring &source,
00289 const istring &target, int manifest_index)
00290 {
00291 FUNCDEF("recurse_into_dir");
00292
00293
00294 string_array dirs;
00295 {
00296
00297
00298 directory dirndl(source);
00299
00300 int ret = add_files_here(dirndl, source, target, manifest_index);
00301
00302 if (ret != 0) {
00303
00304 return 75;
00305 }
00306 dirs = dirndl.directories();
00307 }
00308
00309
00310
00311
00312 for (int i = 0; i < dirs.length(); i++) {
00313 istring s = dirs[i];
00314
00315 int ret = recurse_into_dir(source + "/" + s, target + "/"
00316 + s, manifest_index);
00317 if (ret != 0) return ret;
00318 }
00319
00320 return 0;
00321 }
00322
00323 int bundle_creator::patch_recursive_target(const istring &source,
00324 const istring &target, int manifest_index)
00325 {
00326 FUNCDEF("patch_recursive_target");
00327
00328 return recurse_into_dir(source, target, manifest_index);
00329 }
00330
00331 int bundle_creator::patch_wildcard_target(const istring &source,
00332 const istring &target, int manifest_index)
00333 {
00334 FUNCDEF("patch_wildcard_target");
00335
00336 int src_end = source.end();
00337 int slash_indy = source.find('/', src_end, true);
00338 istring real_source = source.substring(0, slash_indy - 1);
00339 istring wild_pat = source.substring(slash_indy + 1, src_end);
00340
00341
00342 directory dirndl(real_source, wild_pat.s());
00343
00344 int ret = add_files_here(dirndl, real_source, target, manifest_index);
00345 if (ret != 0) {
00346
00347 return 75;
00348 }
00349
00350 return 0;
00351 }
00352
00353 int bundle_creator::read_manifest()
00354 {
00355 FUNCDEF("read_manifest");
00356 ini_configurator ini(_manifest_file, configurator::RETURN_ONLY);
00357 string_table toc;
00358 bool worked = ini.get_section("toc", toc);
00359 if (!worked) {
00360 LOG(istring("failed to read TOC section in manifest:\n") + _manifest_file
00361 + "\ndoes that file exist?");
00362 return 65;
00363 }
00364
00365
00366 file_logger noisy_logfile(path_configuration::make_logfile_name
00367 ("bundle_creator_activity.log"));
00368 noisy_logfile.log(istring('-', 76));
00369 noisy_logfile.log(istring("Bundling starts at ") + timestamp(false, true));
00370
00371
00372 _manifest_list.insert(0, toc.symbols());
00373 istring value;
00374 int final_return = 0;
00375
00376 #define BAIL(retval) \
00377 final_return = retval; \
00378 toc.zap_index(i); \
00379 _manifest_list.zap(i, i); \
00380 i--; \
00381 continue
00382
00383 for (int i = 0; i < toc.symbols(); i++) {
00384
00385 istring section_name = toc.name(i);
00386 section_name.strip_spaces(istring::FROM_FRONT);
00387 if (section_name[0] == '#') {
00388
00389 toc.zap_index(i);
00390 _manifest_list.zap(i, i);
00391 i--;
00392 continue;
00393 }
00394
00395
00396
00397 if (ini.get(section_name, "keyword", value)) {
00399 string_array keys;
00400 bool worked = list_parsing::parse_csv_line(value, keys);
00401 if (!worked) {
00402 LOG(istring("failed to parse keywords for section ")
00403 + section_name + " in " + _manifest_file);
00404 BAIL(82);
00405 }
00407 _manifest_list[i]._keywords = keys;
00408 istring dumped;
00409 list_parsing::create_csv_line(_manifest_list[i]._keywords, dumped);
00410 noisy_logfile.log(section_name + " keywords: " + dumped);
00411 }
00412
00413 if (ini.get(section_name, "variable", value)) {
00414
00415
00416 tokenizer zohre;
00417 zohre.parse(value);
00418 if (zohre.symbols() < 1) {
00419 LOG(istring("failed to parse a variable statement from ") + value);
00420 BAIL(37);
00421 }
00422 _manifest_list[i]._flags = SET_VARIABLE;
00423
00424 _manifest_list[i]._target = zohre.table().name(0);
00425 _manifest_list[i]._parms = zohre.table()[0];
00426 BASE_LOG(istring("will set ") + _manifest_list[i]._target + " = "
00427 + _manifest_list[i]._parms);
00428
00429 portable::set_environ(_manifest_list[i]._target,
00430 parser_bits::substitute_env_vars(_manifest_list[i]._parms));
00431 continue;
00432 }
00433
00434 if (!ini.get(section_name, "source", _manifest_list[i]._source)) {
00435
00436 bool okay_to_omit_source = false;
00437 istring value2;
00438 if (ini.get(section_name, "no_pack", value)
00439 && ini.get(section_name, "exec_target", value2) ) {
00440 if (true_value(value) && true_value(value2)) {
00441
00442 okay_to_omit_source = true;
00443 }
00444 }
00445 if (!okay_to_omit_source) {
00446 LOG(istring("failed to read the source entry for section ")
00447 + section_name + " in " + _manifest_file);
00448 BAIL(67);
00449 }
00450 }
00451
00452 _manifest_list[i]._source.replace_all('\\', '/');
00453
00454 if (!ini.get(section_name, "target", _manifest_list[i]._target)) {
00455
00456 bool okay_to_omit_target = false;
00457 istring value2;
00458 if (ini.get(section_name, "no_pack", value)
00459 && ini.get(section_name, "exec_source", value2) ) {
00460 if (true_value(value) && true_value(value2)) {
00461
00462 okay_to_omit_target = true;
00463 }
00464 }
00465 if (!okay_to_omit_target) {
00466 LOG(istring("failed to read the target entry for section ")
00467 + section_name + " in " + _manifest_file);
00468 BAIL(68);
00469 }
00470 }
00471
00472 _manifest_list[i]._target.replace_all('\\', '/');
00473
00474
00475 if (ini.get(section_name, "parms", value)) {
00476 _manifest_list[i]._parms = value;
00477 #ifdef DEBUG_BUNDLER
00478 BASE_LOG(istring("got parms for ") + section_name + " as: " + value);
00479 #endif
00480 if (value[0] != '"') {
00481
00482 _manifest_list[i]._parms = istring("\"") + value + "\"";
00483 }
00484 noisy_logfile.log(section_name + " parms: " + _manifest_list[i]._parms);
00485 }
00486
00487
00488 if (ini.get(section_name, "error_okay", value)) {
00489 if (true_value(value))
00490 _manifest_list[i]._flags |= IGNORE_ERRORS;
00491 }
00492
00493
00494 if (ini.get(section_name, "no_replace", value)) {
00495 if (true_value(value))
00496 _manifest_list[i]._flags |= NO_OVERWRITE;
00497 }
00498
00499
00500 if (ini.get(section_name, "quiet", value)) {
00501 if (true_value(value))
00502 _manifest_list[i]._flags |= QUIET_FAILURE;
00503 }
00504
00505
00506 if (ini.get(section_name, "recurse", value)) {
00507 if (true_value(value))
00508 _manifest_list[i]._flags |= RECURSIVE_SRC;
00509 } else {
00510
00511
00512
00513 if (ini.get(section_name, "no_pack", value)) {
00514
00515 if (true_value(value))
00516 _manifest_list[i]._flags |= OMIT_PACKING;
00517 }
00518
00519
00520 if (ini.get(section_name, "exec_source", value)) {
00521 if (true_value(value)) {
00522 _manifest_list[i]._flags |= SOURCE_EXECUTE;
00523 }
00524 } else {
00525
00526
00527 if (ini.get(section_name, "exec_target", value)) {
00528 if (true_value(value))
00529 _manifest_list[i]._flags |= TARGET_EXECUTE;
00530 }
00531 }
00532 }
00533
00534
00535 _manifest_list[i]._source = parser_bits::substitute_env_vars
00536 (_manifest_list[i]._source, false);
00537
00538
00539 int indy = _manifest_list[i]._source.find("*");
00540
00541
00542
00543 if (!!_keyword && !_manifest_list[i]._keywords.member(_keyword)) {
00544
00545 noisy_logfile.log(istring("skipping ") + _manifest_list[i]._target
00546 + " file check; doesn't match keyword \"" + _keyword + "\"");
00547 continue;
00548 }
00549
00550
00551
00552
00553 if (!(_manifest_list[i]._flags & RECURSIVE_SRC) && negative(indy)
00554 && !(_manifest_list[i]._flags & OMIT_PACKING) ) {
00555
00556 byte_filer source_file(_manifest_list[i]._source, "rb");
00557 if (!source_file.good()) {
00558 LOG(istring("could not access the source file for bundling: ")
00559 + _manifest_list[i]._source);
00560 BAIL(69);
00561 }
00562 bool okaysize = get_file_size(_manifest_list[i]._source,
00563 _manifest_list[i]._size, _manifest_list[i]._timestamp);
00564 if (!okaysize || (_manifest_list[i]._size < 0) ) {
00565
00566 BAIL(75);
00567 }
00568 }
00569 }
00570
00571
00572 for (int i = 0; i < _manifest_list.length(); i++) {
00573 bundled_chunk curr = _manifest_list[i];
00574
00575 if (!!_keyword && !curr._keywords.member(_keyword)) {
00576
00577 noisy_logfile.log(istring("zapping entry for ") + curr._target
00578 + "; doesn't match keyword \"" + _keyword + "\"");
00579 _manifest_list.zap(i, i);
00580 i--;
00581 continue;
00582 }
00583
00584 if (curr._flags & SET_VARIABLE) {
00585
00586 continue;
00587 } else if (curr._flags & RECURSIVE_SRC) {
00588
00589 int star_indy = curr._source.find("*");
00590 if (non_negative(star_indy)) {
00591
00592 LOG(istring("illegal combination of recursion and wildcard: ")
00593 + curr._source);
00594 BAIL(70);
00595 }
00596
00597 int ret = patch_recursive_target(curr._source, curr._target, i);
00598 if (ret != 0) {
00599 LOG(istring("failed during packing of recursive source: ")
00600 + curr._source);
00601 BAIL(72);
00602 }
00603
00604 _manifest_list.zap(i, i);
00605 i--;
00606 continue;
00607 } else if (curr._flags & SOURCE_EXECUTE) {
00608
00609
00610 BASE_LOG(istring("launching ") + curr._source);
00611 if (!!curr._parms)
00612 BASE_LOG(istring("\tparameters ") + curr._parms);
00613 BASE_LOG(istring('-', 76));
00614 u_int kid;
00615 u_int retval = portable::launch_process(curr._source, curr._parms,
00616 portable::AWAIT_APP_EXIT, kid);
00617 if (retval != 0) {
00618 LOG(istring("failed to launch process, source=") + curr._source
00619 + ", with parms " + curr._parms);
00620 if (! (curr._flags & IGNORE_ERRORS) ) {
00621 BAIL(92);
00622 }
00623 }
00624 BASE_LOG(istring('-', 76));
00625 if (curr._flags & OMIT_PACKING) {
00626
00627 _manifest_list.zap(i, i);
00628 i--;
00629 }
00630 continue;
00631 } else {
00632
00633 int star_indy = curr._source.find("*");
00634 if (negative(star_indy)) continue;
00635
00636
00637 int slash_indy = curr._source.find('/', curr._source.end(), true);
00638 if (star_indy < slash_indy) {
00639 BASE_LOG(istring("illegal wildcard placement in ") + curr._source);
00640 BASE_LOG(" (the wildcard must be in the last component of the path)");
00641 BAIL(71);
00642 }
00643
00644 int ret = patch_wildcard_target(curr._source, curr._target, i);
00645 if (ret != 0) {
00646 LOG(istring("failed during packing of wildcarded source: ")
00647 + curr._source);
00648 BAIL(73);
00649 }
00650 _manifest_list.zap(i, i);
00651 i--;
00652 continue;
00653 }
00654 }
00655
00656 #ifdef DEBUG_BUNDLER
00657 if (!final_return) {
00658
00659 LOG("read the following info from manifest:");
00660 BASE_LOG("size\tsource\t\t\ttarget");
00661 for (int i = 0; i < _manifest_list.length(); i++) {
00662 bundled_chunk &curr = _manifest_list[i];
00663 BASE_LOG(isprintf("%d\t%s\t\t\t%s", curr._size,
00664 curr._source.s(), curr._target.s()));
00665 }
00666 }
00667 #endif
00668
00669 return final_return;
00670 }
00671
00672 int bundle_creator::write_stub_and_toc()
00673 {
00674 FUNCDEF("write_stub_and_toc");
00675
00676
00677
00678 #ifdef __UNIX__
00679 istring stub_file("$REPOSITORY_DIR/exe/unpacker_stub");
00680 #endif
00681 #ifdef __WIN32__
00682 istring stub_file("$REPOSITORY_DIR/exe/unpacker_stub.exe");
00683 #endif
00684
00685
00686 stub_file = parser_bits::substitute_env_vars(stub_file, false);
00687
00688
00689 byte_filer stubby(stub_file, "rb");
00690 if (!stubby.good()) {
00691 LOG(istring("could not access the unpacking stub at: ") + stub_file);
00692 return 80;
00693 }
00694 _stub_size = int(stubby.length());
00695 byte_array whole_stub;
00696 stubby.read(whole_stub, _stub_size + 100);
00697 stubby.close();
00698 _bundle->write(whole_stub);
00699
00700 byte_array packed_toc_len;
00701 basis::obscure_attach(packed_toc_len, _manifest_list.length());
00702 int ret = _bundle->write(packed_toc_len);
00703 if (ret < 0) {
00704 LOG(istring("could not write the TOC length to the bundle: ")
00705 + _output_file);
00706 return 81;
00707 }
00708
00709
00710 for (int i = 0; i < _manifest_list.length(); i++) {
00711 bundled_chunk &curr = _manifest_list[i];
00712
00713 byte_array chunk;
00714 curr.pack(chunk);
00715 if (_bundle->write(chunk) <= 0) {
00716 LOG(isprintf("could not write item #%d [%s] to the bundle: ", i,
00717 curr._source.s())
00718 + _output_file);
00719 return 88;
00720 }
00721 }
00722
00723 return 0;
00724 }
00725
00726 int bundle_creator::bundle_sources()
00727 {
00728 FUNCDEF("bundle_sources");
00729
00730 file_logger noisy_logfile(path_configuration::make_logfile_name
00731 ("bundle_creator_activity.log"));
00732 for (int i = 0; i < _manifest_list.length(); i++) {
00733 bundled_chunk &curr = _manifest_list[i];
00734
00735 if (curr._flags & SET_VARIABLE) {
00736
00737 noisy_logfile.log(istring("bundling: variable setting ") + curr._target
00738 + "=" + curr._parms);
00739 continue;
00740 } else if (curr._flags & OMIT_PACKING) {
00741
00742 continue;
00743 }
00744
00745 noisy_logfile.log(istring("bundling: ") + curr._source);
00746 byte_filer source(curr._source, "rb");
00747 if (!source.good()) {
00748 LOG(isprintf("could not read item #%d for the bundle: \"", i)
00749 + curr._source + "\"");
00750 return 98;
00751 }
00752
00753 byte_array compressed(256 * KILOBYTE);
00754 byte_array temp;
00755
00756
00757
00758 int total_written = 0;
00759 do {
00760 int ret = source.read(temp, CHUNKING_SIZE);
00761 if (ret < 0) {
00762 LOG(isprintf("failed while reading item #%d: ", i) + curr._source);
00763 return 99;
00764 }
00765 total_written += ret;
00766
00767 uLongf destlen = 0;
00768 bool null_chunk = false;
00769 if (ret == 0) {
00770 compressed.reset();
00771 null_chunk = true;
00772 } else {
00773 compressed.reset(int(0.1 * ret) + ret + KILOBYTE);
00774
00775
00776 destlen = compressed.length();
00777
00778 int comp_ret = compress(compressed.access(), &destlen, temp.observe(),
00779 temp.length());
00780 if (comp_ret != Z_OK) {
00781 LOG(isprintf("failed while compressing item #%d: ", i)
00782 + curr._source);
00783 return 99;
00784 }
00785 compressed.zap(destlen, compressed.length() - 1);
00786 }
00787 byte_array just_sizes;
00788 basis::obscure_attach(just_sizes, temp.length());
00789
00790 basis::obscure_attach(just_sizes, int(destlen));
00791
00792 ret = _bundle->write(just_sizes);
00793 if (ret <= 0) {
00794 LOG(isprintf("failed while writing sizes for item #%d: ", i)
00795 + curr._source);
00796 return 93;
00797 }
00798 if (!null_chunk) {
00799 ret = _bundle->write(compressed);
00800 if (ret <= 0) {
00801 LOG(isprintf("failed while writing item #%d: ", i) + curr._source);
00802 return 93;
00803 } else if (ret != compressed.length()) {
00804 LOG(isprintf("wrote different size for item #%d (tried %d, "
00805 "wrote %d): ", i, compressed.length(), ret) + curr._source);
00806 return 93;
00807 }
00808 }
00809 } while (!source.eof());
00810
00811 byte_array just_sizes;
00812 basis::obscure_attach(just_sizes, -1);
00813 basis::obscure_attach(just_sizes, -1);
00814 int ret = _bundle->write(just_sizes);
00815 if (ret <= 0) {
00816 LOG(isprintf("failed while writing sentinel of item #%d: ", i)
00817 + curr._source);
00818 return 96;
00819 }
00820 source.close();
00821 if (total_written != curr._size) {
00822 LOG(isprintf("size (%d) disagrees with initial size (%d) for "
00823 "item #%d: ", total_written, curr._size, i) + curr._source);
00824 }
00825 }
00826 noisy_logfile.log(istring("Bundling run ends at ") + timestamp(false, true));
00827 noisy_logfile.log(istring('-', 76));
00828
00829 return 0;
00830 }
00831
00832 int bundle_creator::finalize_file()
00833 {
00834 _bundle->close();
00835 return 0;
00836 }
00837
00838 int bundle_creator::write_offset()
00839 {
00840 FUNCDEF("write_offset");
00841 byte_filer bun(_output_file, "r+b");
00842
00843 istring magic_string("muftiloc");
00844 istring temp_string;
00845
00846 while (!bun.eof()) {
00847
00848 bool found_it = false;
00849 int location = 0;
00850 for (int i = 0; i < magic_string.length(); i++) {
00851 int ret = bun.read(temp_string, 1);
00852 if (ret <= 0) break;
00853 if (temp_string[0] != magic_string[i]) break;
00854 if (i == magic_string.end()) {
00855
00856 found_it = true;
00857 location = int(bun.tell());
00858
00859 }
00860 }
00861 if (!found_it) continue;
00862 bun.seek(location);
00863 byte_array packed_offset;
00864 basis::obscure_attach(packed_offset, _stub_size);
00865
00866
00867
00868 bun.write(packed_offset);
00869
00870 break;
00871 }
00872 bun.close();
00873
00874 chmod(_output_file.s(), 0766);
00875
00876
00877 BASE_LOG(istring("done file bundling at ") + timestamp(false, true));
00878
00879 return 0;
00880 }
00881
00883
00884 HOOPLE_MAIN(bundle_creator, )
00885
00886 #ifdef __BUILD_STATIC_APPLICATION__
00887
00888 #include <basis/array.cpp>
00889 #include <basis/byte_array.cpp>
00890 #include <basis/callstack_tracker.cpp>
00891 #include <basis/chaos.cpp>
00892 #include <basis/convert_utf.cpp>
00893 #include <basis/definitions.cpp>
00894 #include <basis/earth_time.cpp>
00895 #include <basis/guards.cpp>
00896 #include <basis/istring.cpp>
00897 #include <basis/log_base.cpp>
00898 #include <basis/memory_checker.cpp>
00899 #include <basis/mutex.cpp>
00900 #include <basis/object_base.cpp>
00901 #include <basis/outcome.cpp>
00902 #include <basis/packable.cpp>
00903 #include <basis/portable.cpp>
00904 #include <basis/sequence.cpp>
00905 #include <basis/set.cpp>
00906 #include <basis/utility.cpp>
00907 #include <basis/version_record.cpp>
00908 #include <data_struct/amorph.cpp>
00909 #include <data_struct/bit_vector.cpp>
00910 #include <data_struct/byte_hasher.cpp>
00911 #include <data_struct/configurator.cpp>
00912 #include <data_struct/hash_table.cpp>
00913 #include <data_struct/pointer_hash.cpp>
00914 #include <data_struct/stack.cpp>
00915 #include <data_struct/static_memory_gremlin.cpp>
00916 #include <data_struct/string_hash.cpp>
00917 #include <data_struct/string_hasher.cpp>
00918 #include <data_struct/string_table.cpp>
00919 #include <data_struct/symbol_table.cpp>
00920 #include <data_struct/table_configurator.cpp>
00921 #include <loggers/console_logger.cpp>
00922 #include <loggers/file_logger.cpp>
00923 #include <loggers/locked_logger.cpp>
00924 #include <loggers/null_logger.cpp>
00925 #include <loggers/program_wide_logger.cpp>
00926 #include <opsystem/application_base.cpp>
00927 #include <opsystem/application_shell.cpp>
00928 #include <opsystem/byte_filer.cpp>
00929 #include <opsystem/command_line.cpp>
00930 #include <opsystem/critical_events.cpp>
00931 #include <opsystem/directory.cpp>
00932 #include <opsystem/filename.cpp>
00933 #include <opsystem/filetime.cpp>
00934 #include <opsystem/ini_config.cpp>
00935 #include <opsystem/ini_parser.cpp>
00936 #include <opsystem/path_configuration.cpp>
00937 #include <opsystem/rendezvous.cpp>
00938 #include <textual/byte_format.cpp>
00939 #include <textual/list_parsing.cpp>
00940 #include <textual/parser_bits.cpp>
00941 #include <textual/string_manipulation.cpp>
00942 #include <textual/tokenizer.cpp>
00943 #endif // __BUILD_STATIC_APPLICATION__
00944