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.
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
  }
@@ -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
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