ocran 1.3.18 → 1.4.0

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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.txt +306 -292
  3. data/LICENSE.txt +22 -22
  4. data/README.md +549 -533
  5. data/exe/ocran +5 -5
  6. data/ext/extconf.rb +15 -0
  7. data/lib/ocran/build_constants.rb +16 -16
  8. data/lib/ocran/build_facade.rb +17 -17
  9. data/lib/ocran/build_helper.rb +110 -105
  10. data/lib/ocran/command_output.rb +22 -22
  11. data/lib/ocran/dir_builder.rb +162 -0
  12. data/lib/ocran/direction.rb +623 -458
  13. data/lib/ocran/file_path_set.rb +69 -69
  14. data/lib/ocran/gem_spec_queryable.rb +172 -172
  15. data/lib/ocran/host_config_helper.rb +57 -44
  16. data/lib/ocran/inno_setup_script_builder.rb +111 -111
  17. data/lib/ocran/launcher_batch_builder.rb +85 -85
  18. data/lib/ocran/library_detector.rb +61 -61
  19. data/lib/ocran/library_detector_posix.rb +55 -0
  20. data/lib/ocran/option.rb +323 -273
  21. data/lib/ocran/refine_pathname.rb +104 -104
  22. data/lib/ocran/runner.rb +115 -105
  23. data/lib/ocran/runtime_environment.rb +46 -46
  24. data/lib/ocran/stub_builder.rb +298 -264
  25. data/lib/ocran/version.rb +5 -5
  26. data/lib/ocran/windows_command_escaping.rb +15 -15
  27. data/lib/ocran.rb +7 -7
  28. data/share/ocran/lzma.exe +0 -0
  29. data/src/Makefile +75 -0
  30. data/src/edicon.c +161 -0
  31. data/src/error.c +100 -0
  32. data/src/error.h +66 -0
  33. data/src/inst_dir.c +334 -0
  34. data/src/inst_dir.h +157 -0
  35. data/src/lzma/7zTypes.h +529 -0
  36. data/src/lzma/Compiler.h +43 -0
  37. data/src/lzma/LzmaDec.c +1363 -0
  38. data/src/lzma/LzmaDec.h +236 -0
  39. data/src/lzma/Precomp.h +10 -0
  40. data/src/script_info.c +246 -0
  41. data/src/script_info.h +7 -0
  42. data/src/stub.c +133 -0
  43. data/src/stub.manifest +29 -0
  44. data/src/stub.rc +3 -0
  45. data/src/system_utils.c +1002 -0
  46. data/src/system_utils.h +209 -0
  47. data/src/system_utils_posix.c +500 -0
  48. data/src/unpack.c +574 -0
  49. data/src/unpack.h +85 -0
  50. data/src/vit-ruby.ico +0 -0
  51. metadata +52 -16
  52. data/share/ocran/edicon.exe +0 -0
  53. data/share/ocran/stub.exe +0 -0
  54. data/share/ocran/stubw.exe +0 -0
data/src/inst_dir.c ADDED
@@ -0,0 +1,334 @@
1
+ #include <stdlib.h>
2
+ #include <string.h>
3
+ #ifndef _WIN32
4
+ #include <unistd.h>
5
+ #include <errno.h>
6
+ #endif
7
+ #include "error.h"
8
+ #include "system_utils.h"
9
+ #include "inst_dir.h"
10
+
11
+ // Static variable to hold the installation directory path.
12
+ static char *InstDir = NULL;
13
+
14
+ /**
15
+ * @brief Checks whether the installation directory is configured.
16
+ *
17
+ * @return true if InstDir is non-NULL and not empty; false otherwise.
18
+ */
19
+ static inline bool IsInstDirSet(void)
20
+ {
21
+ return InstDir != NULL && InstDir[0] != '\0';
22
+ }
23
+
24
+ // Creates an installation directory with a unique name in the specified target directory.
25
+ static char *create_uniq_dir(const char *target_dir)
26
+ {
27
+ char *base_path = JoinPath(target_dir, "ocran" "XXXXXX");
28
+ if (!base_path) {
29
+ APP_ERROR("Failed to construct a base path");
30
+ return NULL;
31
+ }
32
+ return CreateUniqueDirectory(base_path);
33
+ }
34
+
35
+ // Creates a debug installation directory next to the executable.
36
+ static char *create_debug_extract_inst_dir(void)
37
+ {
38
+ char *image_path = GetImagePath();
39
+ if (!image_path) {
40
+ APP_ERROR("Failed to get executable name");
41
+ return NULL;
42
+ }
43
+
44
+ char *image_dir = GetParentPath(image_path);
45
+ free(image_path);
46
+ if (!image_dir) {
47
+ APP_ERROR("Failed to obtain the directory path of the executable file");
48
+ return NULL;
49
+ }
50
+
51
+ char *inst_dir = create_uniq_dir(image_dir);
52
+
53
+ if (!inst_dir) {
54
+ APP_ERROR("Failed to create installation directory in '%s'", image_dir);
55
+ free(image_dir);
56
+ return NULL;
57
+ }
58
+
59
+ free(image_dir);
60
+ return inst_dir;
61
+ }
62
+
63
+ // Creates a temporary installation directory in the system's temp directory.
64
+ static char *create_temporary_inst_dir(void)
65
+ {
66
+ char *temp_dir = GetTempDirectoryPath();
67
+ if (!temp_dir) {
68
+ APP_ERROR("Failed to obtain the temporary directory path");
69
+ return NULL;
70
+ }
71
+
72
+ char *inst_dir = create_uniq_dir(temp_dir);
73
+ if (!inst_dir) {
74
+ APP_ERROR("Failed to create installation directory in '%s'", temp_dir);
75
+ free(temp_dir);
76
+ return NULL;
77
+ }
78
+
79
+ free(temp_dir);
80
+ return inst_dir;
81
+ }
82
+
83
+ const char *CreateInstDir(bool is_extract_to_exe_dir)
84
+ {
85
+ if (InstDir != NULL) {
86
+ APP_ERROR("Installation directory has already been set");
87
+ return NULL;
88
+ }
89
+
90
+ char *inst_dir = NULL;
91
+
92
+ if (is_extract_to_exe_dir) {
93
+ inst_dir = create_debug_extract_inst_dir();
94
+ } else {
95
+ inst_dir = create_temporary_inst_dir();
96
+ }
97
+ if (!inst_dir) {
98
+ return NULL;
99
+ }
100
+
101
+ InstDir = inst_dir;
102
+ return inst_dir;
103
+ }
104
+
105
+ // Frees the allocated memory for the installation directory path.
106
+ void FreeInstDir(void)
107
+ {
108
+ free(InstDir);
109
+ InstDir = NULL;
110
+ }
111
+
112
+ // Returns the path to the installation directory.
113
+ const char *GetInstDir()
114
+ {
115
+ if (!IsInstDirSet()) {
116
+ APP_ERROR("Installation directory has not been set");
117
+ return NULL;
118
+ }
119
+
120
+ return InstDir;
121
+ }
122
+
123
+ // Concatenates the installation directory path with a relative path.
124
+ char *ExpandInstDirPath(const char *rel_path)
125
+ {
126
+ if (!IsInstDirSet()) {
127
+ APP_ERROR("Installation directory has not been set");
128
+ return NULL;
129
+ }
130
+
131
+ if (!rel_path || !*rel_path) {
132
+ APP_ERROR("relative path is NULL or empty");
133
+ return NULL;
134
+ }
135
+
136
+ if (!IsCleanRelativePath(rel_path)) {
137
+ APP_ERROR("invalid relative path '%s'", rel_path);
138
+ return NULL;
139
+ }
140
+
141
+ char *full_path = JoinPath(InstDir, rel_path);
142
+ if (!full_path) {
143
+ APP_ERROR("Failed to build full path");
144
+ }
145
+ return full_path;
146
+ }
147
+
148
+ // Deletes the installation directory and all its contents.
149
+ bool DeleteInstDir(void)
150
+ {
151
+ if (!IsInstDirSet()) {
152
+ APP_ERROR("Installation directory has not been set");
153
+ return false;
154
+ }
155
+
156
+ return DeleteRecursively(InstDir);
157
+ }
158
+
159
+ // Replaces placeholders in a string with the installation directory path.
160
+ char *ReplaceInstDirPlaceholder(const char *tmpl)
161
+ {
162
+ if (!IsInstDirSet()) {
163
+ APP_ERROR("Installation directory has not been set");
164
+ return NULL;
165
+ }
166
+
167
+ const char *replacement = InstDir;
168
+ size_t replacement_len = strlen(replacement);
169
+ size_t c = 0;
170
+
171
+ for (const char *p = tmpl; *p; p++) { if (*p == PLACEHOLDER) c++; }
172
+ size_t replaced_len = strlen(tmpl) - c + replacement_len * c + 1;
173
+ char *replaced = calloc(replaced_len, sizeof(*replaced));
174
+ if (!replaced) {
175
+ APP_ERROR("Memory allocation failed for placeholder replacement");
176
+ return NULL;
177
+ }
178
+
179
+ char *out = replaced;
180
+ for (const char *in = tmpl; *in; in++) {
181
+ if (*in == PLACEHOLDER) {
182
+ memcpy(out, replacement, replacement_len);
183
+ out += replacement_len;
184
+ } else {
185
+ *out = *in;
186
+ out++;
187
+ }
188
+ }
189
+ *out = '\0';
190
+
191
+ return replaced;
192
+ }
193
+
194
+ bool CreateDirectoryUnderInstDir(const char *rel_path)
195
+ {
196
+ if (!IsInstDirSet()) {
197
+ APP_ERROR("Installation directory has not been set");
198
+ return false;
199
+ }
200
+
201
+ if (!rel_path) {
202
+ APP_ERROR("relative path is NULL");
203
+ return false;
204
+ }
205
+
206
+ /* Treat empty string as a no-op and return success */
207
+ if (rel_path[0] == '\0') {
208
+ return true;
209
+ }
210
+
211
+ char *dir = ExpandInstDirPath(rel_path);
212
+ if (!dir) {
213
+ APP_ERROR("Failed to build full path");
214
+ return false;
215
+ }
216
+
217
+ bool result = CreateDirectoriesRecursively(dir);
218
+ if (!result) {
219
+ APP_ERROR(
220
+ "Failed to create directory under installation directory: '%s'",
221
+ dir
222
+ );
223
+ }
224
+
225
+ free(dir);
226
+ return result;
227
+ }
228
+
229
+ bool ExportFileToInstDir(const char *rel_path, const void *buf, size_t len)
230
+ {
231
+ bool result = false;
232
+ char *path = NULL;
233
+
234
+ if (!IsInstDirSet()) {
235
+ APP_ERROR("Installation directory has not been set");
236
+ goto cleanup;
237
+ }
238
+
239
+ if (rel_path == NULL || *rel_path == '\0') {
240
+ APP_ERROR("Relative path is null or empty");
241
+ goto cleanup;
242
+ }
243
+
244
+ DEBUG("ExportFileToInstDir: rel_path=\"%s\", len=%zu", rel_path, len);
245
+
246
+ if (len > 0 && buf == NULL) {
247
+ APP_ERROR("Buffer pointer is NULL for non-zero length");
248
+ goto cleanup;
249
+ }
250
+
251
+ path = ExpandInstDirPath(rel_path);
252
+ if (!path) {
253
+ goto cleanup;
254
+ }
255
+
256
+ if (!ExportFile(path, buf, len)) {
257
+ APP_ERROR("Failed to export file: %s", path);
258
+ goto cleanup;
259
+ }
260
+
261
+ result = true;
262
+
263
+ cleanup:
264
+ if (path) {
265
+ free(path);
266
+ }
267
+ return result;
268
+ }
269
+
270
+ #ifndef _WIN32
271
+ bool CreateSymlinkUnderInstDir(const char *rel_link_path, const char *target)
272
+ {
273
+ if (!IsInstDirSet()) {
274
+ APP_ERROR("Installation directory has not been set");
275
+ return false;
276
+ }
277
+
278
+ if (!rel_link_path || !*rel_link_path) {
279
+ APP_ERROR("rel_link_path is NULL or empty");
280
+ return false;
281
+ }
282
+
283
+ if (!target || !*target) {
284
+ APP_ERROR("target is NULL or empty");
285
+ return false;
286
+ }
287
+
288
+ char *link_path = ExpandInstDirPath(rel_link_path);
289
+ if (!link_path) {
290
+ return false;
291
+ }
292
+
293
+ bool result = false;
294
+ char *parent = GetParentPath(link_path);
295
+ if (parent && *parent && !CreateDirectoriesRecursively(parent)) {
296
+ APP_ERROR("Failed to create parent directory for symlink '%s'", link_path);
297
+ goto cleanup;
298
+ }
299
+
300
+ if (symlink(target, link_path) < 0) {
301
+ APP_ERROR("Failed to create symlink '%s' -> '%s': %s", link_path, target, strerror(errno));
302
+ goto cleanup;
303
+ }
304
+
305
+ DEBUG("CreateSymlinkUnderInstDir: '%s' -> '%s'", link_path, target);
306
+ result = true;
307
+
308
+ cleanup:
309
+ if (parent) {
310
+ free(parent);
311
+ }
312
+ free(link_path);
313
+ return result;
314
+ }
315
+ #endif /* _WIN32 */
316
+
317
+ bool SetEnvWithInstDir(const char *name, const char *value)
318
+ {
319
+ char *replaced_value = ReplaceInstDirPlaceholder(value);
320
+ if (!replaced_value) {
321
+ APP_ERROR("Failed to replace the value placeholder");
322
+ return false;
323
+ }
324
+
325
+ DEBUG("SetEnv(%s, %s)", name, replaced_value);
326
+
327
+ bool result = SetEnvVar(name, replaced_value);
328
+ if (!result) {
329
+ APP_ERROR("Failed to set environment variable: %s", name);
330
+ }
331
+
332
+ free(replaced_value);
333
+ return result;
334
+ }
data/src/inst_dir.h ADDED
@@ -0,0 +1,157 @@
1
+ #include <stdbool.h>
2
+ #include <stddef.h>
3
+
4
+ /**
5
+ * @brief Creates an installation directory with a unique name.
6
+ *
7
+ * Attempts to create a directory within the specified target directory. This
8
+ * directory is assigned a unique name based on the "ocran" prefix to avoid
9
+ * conflicts. The function manages the lifetime of the created directory path's
10
+ * memory, which should not be freed by the caller.
11
+ * If directory cleanup is needed, call FreeInstDir().
12
+ *
13
+ * @param is_extract_to_exe_dir
14
+ * If true, the extraction directory will be created in the same folder as
15
+ * the executable; if false, it will be created in the system’s temporary
16
+ * directory.
17
+ * @return
18
+ * A pointer to the created directory path if successful, NULL if an error
19
+ * occurred. The returned path should not be freed by the caller.
20
+ */
21
+ const char *CreateInstDir(bool is_extract_to_exe_dir);
22
+
23
+ /**
24
+ * @brief Free the allocated installation directory path
25
+ * and reset the internal pointer to NULL.
26
+ *
27
+ * Frees memory previously allocated for the installation directory path
28
+ * and clears the stored pointer so that GetInstDir() returns NULL until
29
+ * a new directory is set.
30
+ */
31
+ void FreeInstDir(void);
32
+
33
+ /**
34
+ * @brief Get the current installation directory path.
35
+ *
36
+ * @return
37
+ * A pointer to the installation directory path if set, or NULL if the
38
+ * directory has not been initialized or has been freed.
39
+ */
40
+ const char *GetInstDir(void);
41
+
42
+ /**
43
+ * @brief Concatenates the installation directory path with a given
44
+ * relative path.
45
+ *
46
+ * This function guarantees that the resulting path will not escape the
47
+ * installation directory. It will fail and return NULL if any of the following
48
+ * conditions are met:
49
+ * - the installation directory (InstDir) is not set or is empty
50
+ * - rel_path is NULL or empty
51
+ * - rel_path contains prohibited path elements such as "." or "..", including
52
+ * patterns like "/./" or "/../"
53
+ *
54
+ * @param rel_path
55
+ * A relative path to be combined with the installation directory path.
56
+ * Must not be absolute, must not be empty, and must not contain any "." or
57
+ * ".." segments (e.g., "/./", "/../", "./", "../").
58
+ *
59
+ * @return
60
+ * A newly allocated string representing the full path on success; NULL on
61
+ * error (and an appropriate error message is logged).
62
+ */
63
+ char *ExpandInstDirPath(const char *rel_path);
64
+
65
+ /**
66
+ * @brief Deletes the installation directory and its contents.
67
+ *
68
+ * @return true if the directory and its contents were deleted successfully,
69
+ * false otherwise.
70
+ */
71
+ bool DeleteInstDir(void);
72
+
73
+ // Placeholder character used in paths.
74
+ #define PLACEHOLDER '|'
75
+
76
+ /**
77
+ * @brief Replace placeholders in a template string
78
+ * with the installation directory path.
79
+ *
80
+ * @param tmpl
81
+ * The template string containing placeholder characters defined by the
82
+ * PLACEHOLDER macro, which will be replaced by the installation directory
83
+ * path.
84
+ * @return
85
+ * A newly allocated string with all PLACEHOLDER occurrences replaced by the
86
+ * installation directory path. Returns NULL on failure.
87
+ */
88
+ char *ReplaceInstDirPlaceholder(const char *tmpl);
89
+
90
+ /**
91
+ * @brief Recursively create a directory under the installation directory.
92
+ *
93
+ * This function ensures that a directory exists at the specified relative
94
+ * path under the installation directory. An empty rel_path is treated as
95
+ * already existing (returns true). If rel_path is NULL, ExpandInstDirPath
96
+ * fails, or directory creation fails, the function returns false and logs
97
+ * an error.
98
+ *
99
+ * @param rel_path
100
+ * A relative path to a directory under the installation directory.
101
+ * NULL is invalid (returns false). An empty string is treated as
102
+ * already existing (returns true).
103
+ *
104
+ * @return
105
+ * true if the directory already exists or was created successfully;
106
+ * false on error (and an error is logged).
107
+ */
108
+ bool CreateDirectoryUnderInstDir(const char *rel_path);
109
+
110
+ /**
111
+ * @brief Atomically write a file under the installation dir.
112
+ *
113
+ * This function writes the given buffer as a file at the specified
114
+ * relative path under the installation directory. It validates rel_path
115
+ * and buf, expands the full path, creates any missing parent directories,
116
+ * and writes the data atomically. If len is zero, an empty file is
117
+ * created.
118
+ *
119
+ * @param rel_path
120
+ * A relative file path under the installation directory. NULL or empty
121
+ * string is invalid (returns false).
122
+ * @param buf
123
+ * Pointer to the data to write. Must be non-NULL if len > 0.
124
+ * @param len
125
+ * Number of bytes to write. Zero creates an empty file. Values above
126
+ * MAXDWORD cause an error.
127
+ *
128
+ * @return
129
+ * true on success; false on failure (error logged via APP_ERROR/DEBUG).
130
+ */
131
+ bool ExportFileToInstDir(const char *rel_path, const void *buf, size_t len);
132
+
133
+ /**
134
+ * @brief Expands any installation-directory placeholder found in 'value' and
135
+ * sets the environment variable.
136
+ *
137
+ * @param name Environment variable name to set (must not be NULL).
138
+ * @param value Value string that may include a placeholder for the
139
+ * installation directory.
140
+ *
141
+ * @return true on success; false on failure.
142
+ */
143
+ bool SetEnvWithInstDir(const char *name, const char *value);
144
+
145
+ /**
146
+ * @brief Create a symlink under the installation directory (POSIX only).
147
+ *
148
+ * Creates a symbolic link at rel_link_path that points to target.
149
+ * Both paths are relative to the installation directory.
150
+ * The target is treated as a bare filename within the same directory.
151
+ *
152
+ * @param rel_link_path Relative path for the new symlink (e.g. "bin/libruby.so").
153
+ * @param target Symlink target filename (e.g. "libruby.so.3.2.0").
154
+ *
155
+ * @return true on success; false on failure.
156
+ */
157
+ bool CreateSymlinkUnderInstDir(const char *rel_link_path, const char *target);