ocran 1.4.4 → 1.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.txt +18 -0
- data/README.md +435 -16
- data/lib/ocran/cosmo_toolchain.rb +383 -0
- data/lib/ocran/direction.rb +592 -58
- data/lib/ocran/option.rb +165 -3
- data/lib/ocran/rubyopt_processor.rb +95 -0
- data/lib/ocran/runner.rb +80 -0
- data/lib/ocran/runtime_environment.rb +19 -1
- data/lib/ocran/stub_builder.rb +23 -6
- data/lib/ocran/version.rb +1 -1
- data/lib/ocran/zip_payload_builder.rb +282 -0
- data/lib/ocran/zip_writer.rb +287 -0
- data/src/Makefile +9 -0
- data/src/script_info.c +15 -2
- data/src/script_info.h +15 -1
- data/src/stub.c +51 -1
- data/src/system_utils_posix.c +40 -0
- data/src/unpack.c +4 -0
- data/src/unpack.h +10 -0
- metadata +5 -1
data/src/stub.c
CHANGED
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
#include <stdio.h>
|
|
9
9
|
#include <stdbool.h>
|
|
10
10
|
#include <stdlib.h>
|
|
11
|
+
#ifdef __COSMOPOLITAN__
|
|
12
|
+
#include <cosmo.h> /* IsWindows() */
|
|
13
|
+
#include <libc/nt/runtime.h> /* ExitProcess() */
|
|
14
|
+
#endif
|
|
11
15
|
#include "error.h"
|
|
12
16
|
#include "system_utils.h"
|
|
13
17
|
#include "inst_dir.h"
|
|
@@ -21,6 +25,7 @@ int main(int argc, char *argv[])
|
|
|
21
25
|
OperationModes op_modes = 0;
|
|
22
26
|
const char *extract_dir = NULL;
|
|
23
27
|
char *image_path = NULL;
|
|
28
|
+
char *exe_dir = NULL;
|
|
24
29
|
|
|
25
30
|
/*
|
|
26
31
|
Initialize signal and control handling so the parent process remains
|
|
@@ -96,12 +101,41 @@ int main(int argc, char *argv[])
|
|
|
96
101
|
goto cleanup;
|
|
97
102
|
}
|
|
98
103
|
|
|
104
|
+
/* Resolve the executable's directory when the script should start
|
|
105
|
+
with its working directory next to the .exe (--chdir-exe-dir). */
|
|
106
|
+
if (IsChdirToExeDir(op_modes)) {
|
|
107
|
+
exe_dir = GetParentPath(image_path);
|
|
108
|
+
if (!exe_dir) {
|
|
109
|
+
FATAL("Failed to resolve the executable directory");
|
|
110
|
+
goto cleanup;
|
|
111
|
+
}
|
|
112
|
+
DEBUG("Will start script in executable directory: %s", exe_dir);
|
|
113
|
+
}
|
|
114
|
+
#ifdef __COSMOPOLITAN__
|
|
115
|
+
/*
|
|
116
|
+
This stub is itself an APE. It fork/execs the payload interpreter and
|
|
117
|
+
reads the result with WEXITSTATUS() (system_utils_posix.c), so on
|
|
118
|
+
Windows the child must keep Cosmopolitan's wait-status exit encoding
|
|
119
|
+
(status << 8) -- otherwise `exit 3` would come back looking like death
|
|
120
|
+
by signal 3. CosmoRuby reports the plain status by default now, which
|
|
121
|
+
is right for a native parent but wrong for this one; the variable asks
|
|
122
|
+
it for the old encoding. Harmless for interpreters that do not know
|
|
123
|
+
the variable, and a no-op off Windows. This process still reports the
|
|
124
|
+
plain status to ITS native parent, at the end of main().
|
|
125
|
+
*/
|
|
126
|
+
DEBUG("Set 'COSMORUBY_WAIT_STATUS_EXIT' so the payload's status survives waitpid()");
|
|
127
|
+
if (!SetEnvVar("COSMORUBY_WAIT_STATUS_EXIT", "1")) {
|
|
128
|
+
FATAL("The script cannot be launched due to a configuration error");
|
|
129
|
+
goto cleanup;
|
|
130
|
+
}
|
|
131
|
+
#endif
|
|
132
|
+
|
|
99
133
|
/*
|
|
100
134
|
RunScript uses the current value of status as its initial value
|
|
101
135
|
and then overwrites it with the external script’s return code.
|
|
102
136
|
*/
|
|
103
137
|
DEBUG("Run application script");
|
|
104
|
-
if (!RunScript(argv, IsChdirBeforeScript(op_modes), &status)) {
|
|
138
|
+
if (!RunScript(argv, IsChdirBeforeScript(op_modes), exe_dir, &status)) {
|
|
105
139
|
FATAL("Failed to run script");
|
|
106
140
|
goto cleanup;
|
|
107
141
|
}
|
|
@@ -119,6 +153,10 @@ cleanup:
|
|
|
119
153
|
free(image_path);
|
|
120
154
|
}
|
|
121
155
|
|
|
156
|
+
if (exe_dir) {
|
|
157
|
+
free(exe_dir);
|
|
158
|
+
}
|
|
159
|
+
|
|
122
160
|
if (unpack_ctx) {
|
|
123
161
|
ClosePackFile(unpack_ctx);
|
|
124
162
|
unpack_ctx = NULL;
|
|
@@ -140,5 +178,17 @@ cleanup:
|
|
|
140
178
|
|
|
141
179
|
FreeInstDir();
|
|
142
180
|
extract_dir = NULL;
|
|
181
|
+
|
|
182
|
+
#ifdef __COSMOPOLITAN__
|
|
183
|
+
/* On Windows, Cosmopolitan Libc's exit path encodes the full wait
|
|
184
|
+
status into the process exit code (code << 8) so that cosmo
|
|
185
|
+
parents can reconstruct it. Native Windows parents (cmd,
|
|
186
|
+
PowerShell, CI runners) expect the plain code, so bypass the
|
|
187
|
+
libc exit path and report the code as-is. */
|
|
188
|
+
if (IsWindows()) {
|
|
189
|
+
fflush(NULL);
|
|
190
|
+
ExitProcess(status);
|
|
191
|
+
}
|
|
192
|
+
#endif
|
|
143
193
|
return status;
|
|
144
194
|
}
|
data/src/system_utils_posix.c
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
#ifdef __APPLE__
|
|
2
2
|
#include <mach-o/dyld.h>
|
|
3
3
|
#endif
|
|
4
|
+
#ifdef __COSMOPOLITAN__
|
|
5
|
+
#include <cosmo.h> /* GetProgramExecutableName() */
|
|
6
|
+
#endif
|
|
4
7
|
#include <unistd.h>
|
|
5
8
|
#include <fcntl.h>
|
|
6
9
|
#include <sys/stat.h>
|
|
@@ -360,6 +363,23 @@ bool ExportFile(const char *path, const void *buffer, size_t buffer_size) {
|
|
|
360
363
|
/* ===== Path utilities ===== */
|
|
361
364
|
|
|
362
365
|
char *GetImagePath(void) {
|
|
366
|
+
#ifdef __COSMOPOLITAN__
|
|
367
|
+
/* Cosmopolitan Libc defines neither __linux__ nor __APPLE__; it resolves
|
|
368
|
+
the executable path itself on every OS the APE binary runs on. */
|
|
369
|
+
const char *exe = GetProgramExecutableName();
|
|
370
|
+
if (!exe || !*exe) {
|
|
371
|
+
FATAL("GetImagePath: GetProgramExecutableName failed");
|
|
372
|
+
return NULL;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
char *result = strdup(exe);
|
|
376
|
+
if (!result) {
|
|
377
|
+
FATAL("GetImagePath: strdup failed");
|
|
378
|
+
return NULL;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return result;
|
|
382
|
+
#else
|
|
363
383
|
static char path_buffer[4096];
|
|
364
384
|
#ifdef __APPLE__
|
|
365
385
|
uint32_t size = sizeof(path_buffer);
|
|
@@ -388,10 +408,30 @@ char *GetImagePath(void) {
|
|
|
388
408
|
|
|
389
409
|
strcpy(result, path_buffer);
|
|
390
410
|
return result;
|
|
411
|
+
#endif /* __COSMOPOLITAN__ */
|
|
391
412
|
}
|
|
392
413
|
|
|
393
414
|
char *GetTempDirectoryPath(void) {
|
|
394
415
|
const char *tmpdir = getenv("TMPDIR");
|
|
416
|
+
#ifdef __COSMOPOLITAN__
|
|
417
|
+
/* On Windows, Cosmopolitan Libc translates the magic "/tmp" prefix to
|
|
418
|
+
a real directory, but WHERE it points differs between cosmo
|
|
419
|
+
releases (%TMP% in some, C:\tmp in others). This stub and the
|
|
420
|
+
packed cosmopolitan Ruby may be built against different cosmo
|
|
421
|
+
versions, so a literal "/tmp/..." extraction path handed to the
|
|
422
|
+
child can resolve to a DIFFERENT directory than the one the stub
|
|
423
|
+
extracted into. TMP/TEMP, by contrast, are presented by cosmo in
|
|
424
|
+
its unambiguous drive-letter form (e.g. /C/Users/x/AppData/Local/
|
|
425
|
+
Temp) that every cosmo runtime resolves identically, so prefer
|
|
426
|
+
them. On POSIX hosts they are normally unset and the usual
|
|
427
|
+
TMPDIR -> /tmp behavior is preserved. */
|
|
428
|
+
if (!tmpdir || !*tmpdir) {
|
|
429
|
+
tmpdir = getenv("TMP");
|
|
430
|
+
}
|
|
431
|
+
if (!tmpdir || !*tmpdir) {
|
|
432
|
+
tmpdir = getenv("TEMP");
|
|
433
|
+
}
|
|
434
|
+
#endif
|
|
395
435
|
if (!tmpdir || !*tmpdir) {
|
|
396
436
|
tmpdir = "/tmp";
|
|
397
437
|
}
|
data/src/unpack.c
CHANGED
|
@@ -540,6 +540,10 @@ bool IsRunInExeDir(OperationModes modes) {
|
|
|
540
540
|
return IsMode(modes, RUN_IN_EXE_DIR);
|
|
541
541
|
}
|
|
542
542
|
|
|
543
|
+
bool IsChdirToExeDir(OperationModes modes) {
|
|
544
|
+
return IsMode(modes, CHDIR_TO_EXE_DIR);
|
|
545
|
+
}
|
|
546
|
+
|
|
543
547
|
bool ProcessImage(const UnpackContext *context)
|
|
544
548
|
{
|
|
545
549
|
if (!context) {
|
data/src/unpack.h
CHANGED
|
@@ -74,6 +74,15 @@ typedef enum {
|
|
|
74
74
|
* the stub executable. Restores the pre-1.4 (OCRA) wrapper behavior.
|
|
75
75
|
*/
|
|
76
76
|
RUN_IN_EXE_DIR = 0x20,
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Change the current directory to the directory containing the
|
|
80
|
+
* executable before running the script. This makes relative file
|
|
81
|
+
* access resolve next to the .exe, regardless of how it was invoked
|
|
82
|
+
* (Explorer, command prompt, file association). Opt-in via the
|
|
83
|
+
* --chdir-exe-dir build option.
|
|
84
|
+
*/
|
|
85
|
+
CHDIR_TO_EXE_DIR = 0x40,
|
|
77
86
|
} OperationModes;
|
|
78
87
|
|
|
79
88
|
bool IsDebugMode(OperationModes modes);
|
|
@@ -82,6 +91,7 @@ bool IsAutoCleanInstDir(OperationModes modes);
|
|
|
82
91
|
bool IsChdirBeforeScript(OperationModes modes);
|
|
83
92
|
bool IsDataCompressed(OperationModes modes);
|
|
84
93
|
bool IsRunInExeDir(OperationModes modes);
|
|
94
|
+
bool IsChdirToExeDir(OperationModes modes);
|
|
85
95
|
|
|
86
96
|
typedef struct UnpackContext UnpackContext;
|
|
87
97
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ocran
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.4.
|
|
4
|
+
version: 1.4.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andi Idogawa
|
|
@@ -50,6 +50,7 @@ files:
|
|
|
50
50
|
- lib/ocran/build_facade.rb
|
|
51
51
|
- lib/ocran/build_helper.rb
|
|
52
52
|
- lib/ocran/command_output.rb
|
|
53
|
+
- lib/ocran/cosmo_toolchain.rb
|
|
53
54
|
- lib/ocran/dir_builder.rb
|
|
54
55
|
- lib/ocran/direction.rb
|
|
55
56
|
- lib/ocran/ed_icon.rb
|
|
@@ -64,11 +65,14 @@ files:
|
|
|
64
65
|
- lib/ocran/library_detector_posix.rb
|
|
65
66
|
- lib/ocran/option.rb
|
|
66
67
|
- lib/ocran/refine_pathname.rb
|
|
68
|
+
- lib/ocran/rubyopt_processor.rb
|
|
67
69
|
- lib/ocran/runner.rb
|
|
68
70
|
- lib/ocran/runtime_environment.rb
|
|
69
71
|
- lib/ocran/stub_builder.rb
|
|
70
72
|
- lib/ocran/version.rb
|
|
71
73
|
- lib/ocran/windows_command_escaping.rb
|
|
74
|
+
- lib/ocran/zip_payload_builder.rb
|
|
75
|
+
- lib/ocran/zip_writer.rb
|
|
72
76
|
- share/ocran/lzma.exe
|
|
73
77
|
- src/Makefile
|
|
74
78
|
- src/error.c
|