1 /* Copyright (C) 1992, 2000 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gp_ntfs.c,v 1.22 2003/12/10 23:07:10 ray Exp $ */
18 /* file system stuff for MS-Windows WIN32 and MS-Windows NT */
19 /* hacked from gp_dosfs.c by Russell Lang */
20
21 #include "stdio_.h"
22 #include <fcntl.h>
23 #include <io.h>
24 #include <stdio.h>
25 #include "memory_.h"
26 #include "string_.h"
27 #include "gstypes.h"
28 #include "gsmemory.h"
29 #include "gsstruct.h"
30 #include "gp.h"
31 #include "gpmisc.h"
32 #include "gsutil.h"
33 #include "windows_.h"
34
35 /* ------ Printer accessing ------ */
36
37 /* Put a printer file (which might be stdout) into binary or text mode. */
38 /* This is not a standard gp procedure, */
39 /* but all MS-DOS configurations need it. */
40 private int
setmode_binary(int fno,bool binary)41 setmode_binary(int fno, bool binary)
42 {
43 /* Use non-standard setmode that almost all NT compilers offer. */
44 #if defined(__STDC__) && !defined(__WATCOMC__)
45 return _setmode(fno, binary ? _O_BINARY : _O_TEXT);
46 #else
47 return setmode(fno, binary ? O_BINARY : O_TEXT);
48 #endif
49 }
50 void
gp_set_file_binary(int prnfno,int binary)51 gp_set_file_binary(int prnfno, int binary)
52 {
53 DISCARD(setmode_binary(prnfno, binary != 0));
54 }
55
56 /* ------ File accessing -------- */
57
58 /* Set a file into binary or text mode. */
59 int
gp_setmode_binary(FILE * pfile,bool binary)60 gp_setmode_binary(FILE * pfile, bool binary)
61 {
62 /* Use non-standard fileno that almost all NT compilers offer. */
63 #if defined(__STDC__) && !defined(__WATCOMC__)
64 int code = setmode_binary(_fileno(pfile), binary);
65 #else
66 int code = setmode_binary(fileno(pfile), binary);
67 #endif
68
69 return (code == -1 ? -1 : 0);
70 }
71
72 /* ------ File names ------ */
73
74 /* Define the character used for separating file names in a list. */
75 const char gp_file_name_list_separator = ';';
76
77 /* Define the string to be concatenated with the file mode */
78 /* for opening files without end-of-line conversion. */
79 const char gp_fmode_binary_suffix[] = "b";
80
81 /* Define the file modes for binary reading or writing. */
82 const char gp_fmode_rb[] = "rb";
83 const char gp_fmode_wb[] = "wb";
84
85 /* ------ File enumeration ------ */
86
87 struct file_enum_s {
88 WIN32_FIND_DATA find_data;
89 HANDLE find_handle;
90 char *pattern; /* orig pattern + modified pattern */
91 int patlen; /* orig pattern length */
92 int pat_size; /* allocate space for pattern */
93 int head_size; /* pattern length through last */
94 /* :, / or \ */
95 int first_time;
96 gs_memory_t *memory;
97 };
98 gs_private_st_ptrs1(st_file_enum, struct file_enum_s, "file_enum",
99 file_enum_enum_ptrs, file_enum_reloc_ptrs, pattern);
100
101 /* Initialize an enumeration. Note that * and ? in a directory */
102 /* don't work with the OS call currently used. The '\' escape */
103 /* character is removed for the 'Find...File' function. */
104 file_enum *
gp_enumerate_files_init(const char * pat,uint patlen,gs_memory_t * mem)105 gp_enumerate_files_init(const char *pat, uint patlen, gs_memory_t * mem)
106 {
107 file_enum *pfen = gs_alloc_struct(mem, file_enum, &st_file_enum, "gp_enumerate_files");
108 int pat_size = 2 * patlen + 1;
109 char *pattern;
110 int hsize = 0;
111 int i, j;
112
113 if (pfen == 0)
114 return 0;
115 /* pattern could be allocated as a string, */
116 /* but it's simpler for GC and freeing to allocate it as bytes. */
117 pattern = (char *)gs_alloc_bytes(mem, pat_size,
118 "gp_enumerate_files(pattern)");
119 if (pattern == 0)
120 return 0;
121 /* translate the template into a pattern discarding the escape */
122 /* char '\' (not needed by the OS Find...File logic). Note that */
123 /* a final '\' in the string is also discarded. */
124 for (i = 0, j=0; i < patlen; i++) {
125 if (pat[i] == '\\') {
126 i++;
127 if (i == patlen)
128 break; /* '\' at end ignored */
129 }
130 pattern[j++]=pat[i];
131 }
132 /* Scan for last path separator to determine 'head_size' (directory part) */
133 for (i = 0; i < j; i++) {
134 if(pattern[i] == '/' || pattern[i] == '\\' || pattern[i] == ':')
135 hsize = i+1;
136 }
137 pattern[j] = 0;
138 pfen->pattern = pattern;
139 pfen->patlen = j;
140 pfen->pat_size = pat_size;
141 pfen->head_size = hsize;
142 pfen->memory = mem;
143 pfen->first_time = 1;
144 memset(&pfen->find_data, 0, sizeof(pfen->find_data));
145 pfen->find_handle = INVALID_HANDLE_VALUE;
146 return pfen;
147 }
148
149 /* Enumerate the next file. */
150 uint
gp_enumerate_files_next(file_enum * pfen,char * ptr,uint maxlen)151 gp_enumerate_files_next(file_enum * pfen, char *ptr, uint maxlen)
152 {
153 int code = 0;
154 uint len;
155 for(;;)
156 { if (pfen->first_time)
157 { pfen->find_handle = FindFirstFile(pfen->pattern, &(pfen->find_data));
158 if (pfen->find_handle == INVALID_HANDLE_VALUE)
159 { code = -1;
160 break;
161 }
162 pfen->first_time = 0;
163 }
164 else
165 { if (!FindNextFile(pfen->find_handle, &(pfen->find_data)))
166 { code = -1;
167 break;
168 }
169 }
170 if ( strcmp(".", pfen->find_data.cFileName)
171 && strcmp("..", pfen->find_data.cFileName)
172 && (pfen->find_data.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY))
173 break;
174 }
175
176 if (code != 0) { /* All done, clean up. */
177 gp_enumerate_files_close(pfen);
178 return ~(uint) 0;
179 }
180 len = strlen(pfen->find_data.cFileName);
181
182 if (pfen->head_size + len < maxlen) {
183 memcpy(ptr, pfen->pattern, pfen->head_size);
184 strcpy(ptr + pfen->head_size, pfen->find_data.cFileName);
185 return pfen->head_size + len;
186 }
187 if (pfen->head_size >= maxlen)
188 return 0; /* no hope at all */
189
190 memcpy(ptr, pfen->pattern, pfen->head_size);
191 strncpy(ptr + pfen->head_size, pfen->find_data.cFileName,
192 maxlen - pfen->head_size - 1);
193 return maxlen;
194 }
195
196 /* Clean up the file enumeration. */
197 void
gp_enumerate_files_close(file_enum * pfen)198 gp_enumerate_files_close(file_enum * pfen)
199 {
200 gs_memory_t *mem = pfen->memory;
201
202 if (pfen->find_handle != INVALID_HANDLE_VALUE)
203 FindClose(pfen->find_handle);
204 gs_free_object(mem, pfen->pattern,
205 "gp_enumerate_files_close(pattern)");
206 gs_free_object(mem, pfen, "gp_enumerate_files_close");
207 }
208
209
210 /* -------------- Helpers for gp_file_name_combine_generic ------------- */
211
gp_file_name_root(const char * fname,uint len)212 uint gp_file_name_root(const char *fname, uint len)
213 { int i = 0;
214
215 if (len == 0)
216 return 0;
217 if (len > 1 && fname[0] == '\\' && fname[1] == '\\') {
218 /* A network path: "\\server\share\" */
219 int k = 0;
220
221 for (i = 2; i < len; i++)
222 if (fname[i] == '\\' || fname[i] == '/')
223 if (k++) {
224 i++;
225 break;
226 }
227 } else if (fname[0] == '/' || fname[0] == '\\') {
228 /* Absolute with no drive. */
229 i = 1;
230 } else if (len > 1 && fname[1] == ':') {
231 /* Absolute with a drive. */
232 i = (len > 2 && (fname[2] == '/' || fname[2] == '\\') ? 3 : 2);
233 }
234 return i;
235 }
236
gs_file_name_check_separator(const char * fname,int len,const char * item)237 uint gs_file_name_check_separator(const char *fname, int len, const char *item)
238 { if (len > 0) {
239 if (fname[0] == '/' || fname[0] == '\\')
240 return 1;
241 } else if (len < 0) {
242 if (fname[-1] == '/' || fname[-1] == '\\')
243 return 1;
244 }
245 return 0;
246 }
247
gp_file_name_is_parent(const char * fname,uint len)248 bool gp_file_name_is_parent(const char *fname, uint len)
249 { return len == 2 && fname[0] == '.' && fname[1] == '.';
250 }
251
gp_file_name_is_current(const char * fname,uint len)252 bool gp_file_name_is_current(const char *fname, uint len)
253 { return len == 1 && fname[0] == '.';
254 }
255
gp_file_name_separator(void)256 const char *gp_file_name_separator(void)
257 { return "/";
258 }
259
gp_file_name_directory_separator(void)260 const char *gp_file_name_directory_separator(void)
261 { return "/";
262 }
263
gp_file_name_parent(void)264 const char *gp_file_name_parent(void)
265 { return "..";
266 }
267
gp_file_name_current(void)268 const char *gp_file_name_current(void)
269 { return ".";
270 }
271
gp_file_name_is_partent_allowed(void)272 bool gp_file_name_is_partent_allowed(void)
273 { return true;
274 }
275
gp_file_name_is_empty_item_meanful(void)276 bool gp_file_name_is_empty_item_meanful(void)
277 { return false;
278 }
279
280 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)281 gp_file_name_combine(const char *prefix, uint plen, const char *fname, uint flen,
282 bool no_sibling, char *buffer, uint *blen)
283 {
284 return gp_file_name_combine_generic(prefix, plen,
285 fname, flen, no_sibling, buffer, blen);
286 }
287
288