xref: /plan9/sys/src/cmd/gs/src/gp_ntfs.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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