1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17 /* File access and enumeration for OS/2 */
18
19 #define INCL_DOS
20 #define INCL_BASE
21 #define INCL_ERRORS
22 #include <os2.h>
23
24 #include "pipe_.h"
25 #include "stdio_.h"
26 #include "string_.h"
27 #include <fcntl.h>
28
29 #include "memory_.h"
30 #include "string_.h"
31 #include "gx.h"
32 #include "gsexit.h"
33 #include "gsmemory.h"
34 #include "gsstruct.h"
35 #include "gp.h"
36 #include "gpmisc.h"
37 #include "stdlib.h" /* need _osmode, exit */
38 #include "time_.h"
39 #include <time.h> /* should this be in time_.h? */
40 #include "gp_os2.h"
41 #ifdef __EMX__
42 #include <sys/emxload.h>
43 #endif
44
45 #ifdef __DLL__
46 #define isos2 TRUE
47 #else
48 #define isos2 (_osmode == OS2_MODE)
49 #endif
50
51 /* ------ File naming and accessing ------ */
52
53 /* Define the character used for separating file names in a list. */
54 const char gp_file_name_list_separator = ';';
55
56 /* Define the default scratch file name prefix. */
57 const char gp_scratch_file_name_prefix[] = "gs";
58
59 /* Define the name of the null output file. */
60 const char gp_null_file_name[] = "nul";
61
62 /* Define the name that designates the current directory. */
63 const char gp_current_directory_name[] = ".";
64
65 /* Define the string to be concatenated with the file mode */
66 /* for opening files without end-of-line conversion. */
67 const char* gp_fmode_binary_suffix = "b";
68
69 /* Define the file modes for binary reading or writing. */
70 const char gp_fmode_rb[] = "rb";
71 const char gp_fmode_wb[] = "wb";
72
73 /* ------ File enumeration ------ */
74
75 struct file_enum_s {
76 FILEFINDBUF3 findbuf;
77 HDIR hdir;
78 char *pattern;
79 int patlen; /* orig pattern length */
80 int pat_size; /* allocate space for pattern */
81 int head_size; /* pattern length through last */
82 /* :, / or \ */
83 int first_time;
84 gs_memory_t *memory;
85 };
86 gs_private_st_ptrs1(st_file_enum, struct file_enum_s, "file_enum",
87 file_enum_enum_ptrs, file_enum_reloc_ptrs, pattern);
88
89 /* Initialize an enumeration. may NEED WORK ON HANDLING * ? \. */
90 file_enum *
gp_enumerate_files_init_impl(gs_memory_t * mem,const char * pat,uint patlen)91 gp_enumerate_files_init_impl(gs_memory_t * mem, const char *pat, uint patlen)
92 {
93 file_enum *pfen = gs_alloc_struct(mem, file_enum, &st_file_enum, "gp_enumerate_files");
94 int pat_size = 2 * patlen + 1;
95 char *pattern;
96 int hsize = 0;
97 int i;
98
99 if (pfen == 0)
100 return 0;
101
102 /* pattern could be allocated as a string, */
103 /* but it's simpler for GC and freeing to allocate it as bytes. */
104
105 pattern = (char *)gs_alloc_bytes(mem, pat_size,
106 "gp_enumerate_files(pattern)");
107 if (pattern == 0)
108 return 0;
109 memcpy(pattern, pat, patlen);
110 /* find directory name = header */
111 for (i = 0; i < patlen; i++) {
112 switch (pat[i]) {
113 case '\\':
114 if (i + 1 < patlen && pat[i + 1] == '\\')
115 i++;
116 /* falls through */
117 case ':':
118 case '/':
119 hsize = i + 1;
120 }
121 }
122 pattern[patlen] = 0;
123 pfen->pattern = pattern;
124 pfen->patlen = patlen;
125 pfen->pat_size = pat_size;
126 pfen->head_size = hsize;
127 pfen->memory = mem;
128 pfen->first_time = 1;
129 pfen->hdir = HDIR_CREATE;
130 return pfen;
131 }
132
133 /* Enumerate the next file. */
134 uint
gp_enumerate_files_next_impl(gs_memory_t * mem,file_enum * pfen,char * ptr,uint maxlen)135 gp_enumerate_files_next_impl(gs_memory_t * mem, file_enum * pfen, char *ptr, uint maxlen)
136 {
137 APIRET rc;
138 ULONG cFilenames = 1;
139 (void)mem;
140
141 if (!isos2) {
142 /* CAN'T DO IT SO JUST RETURN THE PATTERN. */
143 if (pfen->first_time) {
144 char *pattern = pfen->pattern;
145 uint len = strlen(pattern);
146
147 pfen->first_time = 0;
148 if (len > maxlen)
149 return maxlen + 1;
150 strcpy(ptr, pattern);
151 return len;
152 }
153 return -1;
154 }
155 /* else OS/2 */
156 if (pfen->first_time) {
157 rc = DosFindFirst(pfen->pattern, &pfen->hdir, FILE_NORMAL,
158 &pfen->findbuf, sizeof(pfen->findbuf),
159 &cFilenames, FIL_STANDARD);
160 pfen->first_time = 0;
161 } else {
162 rc = DosFindNext(pfen->hdir, &pfen->findbuf, sizeof(pfen->findbuf),
163 &cFilenames);
164 }
165 if (rc)
166 return -1;
167
168 if (pfen->head_size + pfen->findbuf.cchName < maxlen) {
169 memcpy(ptr, pfen->pattern, pfen->head_size);
170 strcpy(ptr + pfen->head_size, pfen->findbuf.achName);
171 return pfen->head_size + pfen->findbuf.cchName;
172 }
173 if (pfen->head_size >= maxlen)
174 return 0; /* no hope at all */
175
176 memcpy(ptr, pfen->pattern, pfen->head_size);
177 strncpy(ptr + pfen->head_size, pfen->findbuf.achName,
178 maxlen - pfen->head_size - 1);
179 return maxlen;
180 }
181
182 /* Clean up the file enumeration. */
183 void
gp_enumerate_files_close_impl(gs_memory_t * mem,file_enum * pfen)184 gp_enumerate_files_close_impl(gs_memory_t * mem, file_enum * pfen)
185 {
186 gs_memory_t *mem2 = pfen->memory;
187 (void)mem;
188
189 if (isos2)
190 DosFindClose(pfen->hdir);
191 gs_free_object(mem2, pfen->pattern,
192 "gp_enumerate_files_close(pattern)");
193 gs_free_object(mem2, pfen, "gp_enumerate_files_close");
194 }
195
196 /* ------ File naming and accessing ------ */
197
198 /* Create and open a scratch file with a given name prefix. */
199 /* Write the actual file name at fname. */
200 FILE *
gp_open_scratch_file_impl(const gs_memory_t * mem,const char * prefix,char fname[gp_file_name_sizeof],const char * mode,int remove)201 gp_open_scratch_file_impl(const gs_memory_t *mem,
202 const char *prefix,
203 char fname[gp_file_name_sizeof],
204 const char *mode,
205 int remove)
206 {
207 FILE *f;
208
209 if (remove)
210 return NULL;
211 #ifdef __IBMC__
212 char *temp = 0;
213 char *tname;
214 int prefix_length = strlen(prefix);
215
216 if (!gp_file_name_is_absolute(prefix, prefix_length)) {
217 temp = getenv("TMPDIR");
218 if (temp == 0)
219 temp = getenv("TEMP");
220 }
221 *fname = 0;
222 tname = _tempnam(temp, (char *)prefix);
223 if (tname) {
224 if (strlen(tname) > gp_file_name_sizeof - 1) {
225 free(tname);
226 return 0; /* file name too long */
227 }
228 strcpy(fname, tname);
229 free(tname);
230 }
231 #else
232 /* The -7 is for XXXXXX plus a possible final \. */
233 int prefix_length = strlen(prefix);
234 int len = gp_file_name_sizeof - prefix_length - 7;
235
236 if (gp_file_name_is_absolute(prefix, prefix_length) ||
237 gp_gettmpdir(fname, &len) != 0)
238 *fname = 0;
239 else {
240 char last = '\\';
241 char *temp;
242
243 /* Prevent X's in path from being converted by mktemp. */
244 for (temp = fname; *temp; temp++)
245 *temp = last = tolower(*temp);
246 switch (last) {
247 default:
248 strcat(fname, "\\");
249 case ':':
250 case '\\':
251 ;
252 }
253 }
254 if (strlen(fname) + prefix_length + 7 >= gp_file_name_sizeof)
255 return 0; /* file name too long */
256 strcat(fname, prefix);
257 strcat(fname, "XXXXXX");
258 mktemp(fname);
259 #endif
260 f = gp_fopentemp(fname, mode);
261 return f;
262 }
263
264 /* Open a file with the given name, as a stream of uninterpreted bytes. */
265 FILE *
gp_fopen_impl(const gs_memory_t * mem,const char * fname,const char * mode)266 gp_fopen_impl(const gs_memory_t *mem, const char *fname, const char *mode)
267 {
268 return fopen(fname, mode);
269 }
270
gp_stat_impl(gs_memory_t * mem,const char * path,struct stat * buf)271 int gp_stat_impl(gs_memory_t *mem, const char *path, struct stat *buf)
272 {
273 return stat(path, buf);
274 }
275
gp_can_share_fdesc(void)276 int gp_can_share_fdesc(void)
277 {
278 return 0;
279 }
280
gp_fdup_impl(FILE * f,const char * mode)281 FILE *gp_fdup_impl(FILE *f, const char *mode)
282 {
283 return NULL;
284 }
285
gp_pread_impl(char * buf,size_t count,gs_offset_t offset,FILE * f)286 int gp_pread_impl(char *buf, size_t count, gs_offset_t offset, FILE *f)
287 {
288 return -1;
289 }
290
gp_pwrite_impl(char * buf,size_t count,gs_offset_t offset,FILE * f)291 int gp_pwrite_impl(char *buf, size_t count, gs_offset_t offset, FILE *f)
292 {
293 return -1;
294 }
295
296 /* -------------- Helpers for gp_file_name_combine_generic ------------- */
297
gp_file_name_root(const char * fname,uint len)298 uint gp_file_name_root(const char *fname, uint len)
299 { int i = 0;
300
301 if (len == 0)
302 return 0;
303 if (len > 1 && fname[0] == '\\' && fname[1] == '\\') {
304 /* A network path: "\\server\share\" */
305 int k = 0;
306
307 for (i = 2; i < len; i++)
308 if (fname[i] == '\\' || fname[i] == '/')
309 if (k++) {
310 i++;
311 break;
312 }
313 } else if (fname[0] == '/' || fname[0] == '\\') {
314 /* Absolute with no drive. */
315 i = 1;
316 } else if (len > 1 && fname[1] == ':') {
317 /* Absolute with a drive. */
318 i = (len > 2 && (fname[2] == '/' || fname[2] == '\\') ? 3 : 2);
319 }
320 return i;
321 }
322
gs_file_name_check_separator(const char * fname,int len,const char * item)323 uint gs_file_name_check_separator(const char *fname, int len, const char *item)
324 { if (len > 0) {
325 if (fname[0] == '/' || fname[0] == '\\')
326 return 1;
327 } else if (len < 0) {
328 if (fname[-1] == '/' || fname[-1] == '\\')
329 return 1;
330 }
331 return 0;
332 }
333
gp_file_name_is_parent(const char * fname,uint len)334 bool gp_file_name_is_parent(const char *fname, uint len)
335 { return len == 2 && fname[0] == '.' && fname[1] == '.';
336 }
337
gp_file_name_is_current(const char * fname,uint len)338 bool gp_file_name_is_current(const char *fname, uint len)
339 { return len == 1 && fname[0] == '.';
340 }
341
gp_file_name_separator(void)342 const char *gp_file_name_separator(void)
343 { return "/";
344 }
345
gp_file_name_directory_separator(void)346 const char *gp_file_name_directory_separator(void)
347 { return "/";
348 }
349
gp_file_name_parent(void)350 const char *gp_file_name_parent(void)
351 { return "..";
352 }
353
gp_file_name_current(void)354 const char *gp_file_name_current(void)
355 { return ".";
356 }
357
gp_file_name_is_parent_allowed(void)358 bool gp_file_name_is_parent_allowed(void)
359 { return true;
360 }
361
gp_file_name_is_empty_item_meanful(void)362 bool gp_file_name_is_empty_item_meanful(void)
363 { return false;
364 }
365
366 gp_file_name_combine_result
gp_file_name_combine(const char * prefix,uint plen,const char * fname,uint flen,bool no_sibling,char * buffer,uint * blen)367 gp_file_name_combine(const char *prefix, uint plen, const char *fname, uint flen,
368 bool no_sibling, char *buffer, uint *blen)
369 {
370 return gp_file_name_combine_generic(prefix, plen,
371 fname, flen, no_sibling, buffer, blen);
372 }
373
374 bool
gp_file_name_good_char(unsigned char c)375 gp_file_name_good_char(unsigned char c)
376 {
377 return !strchr("|\\?*<\":>/", c);
378 }
379