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