Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 2000-2003 artofcode LLC.  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: gpmisc.c,v 1.22 2003/12/04 12:35:35 igor Exp $ */
18
/* Miscellaneous support for platform facilities */
19
 
20
#include "unistd_.h"
21
#include "fcntl_.h"
22
#include "stdio_.h"
23
#include "stat_.h"
24
#include "memory_.h"
25
#include "string_.h"
26
#include "gp.h"
27
#include "gpgetenv.h"
28
#include "gpmisc.h"
29
 
30
/*
31
 * Get the name of the directory for temporary files, if any.  Currently
32
 * this checks the TMPDIR and TEMP environment variables, in that order.
33
 * The return value and the setting of *ptr and *plen are as for gp_getenv.
34
 */
35
int
36
gp_gettmpdir(char *ptr, int *plen)
37
{
38
    int max_len = *plen;
39
    int code = gp_getenv("TMPDIR", ptr, plen);
40
 
41
    if (code != 1)
42
	return code;
43
    *plen = max_len;
44
    return gp_getenv("TEMP", ptr, plen);
45
}
46
 
47
/*
48
 * Open a temporary file, using O_EXCL and S_I*USR to prevent race
49
 * conditions and symlink attacks.
50
 */
51
FILE *
52
gp_fopentemp(const char *fname, const char *mode)
53
{
54
    int flags = O_EXCL;
55
    /* Scan the mode to construct the flags. */
56
    const char *p = mode;
57
    int fildes;
58
    FILE *file;
59
 
60
    while (*p)
61
	switch (*p++) {
62
	case 'a':
63
	    flags |= O_CREAT | O_APPEND;
64
	    break;
65
	case 'r':
66
	    flags |= O_RDONLY;
67
	    break;
68
	case 'w':
69
	    flags |= O_CREAT | O_WRONLY | O_TRUNC;
70
	    break;
71
#ifdef O_BINARY
72
	    /* Watcom C insists on this non-ANSI flag being set. */
73
	case 'b':
74
	    flags |= O_BINARY;
75
	    break;
76
#endif
77
	case '+':
78
	    flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
79
	    break;
80
	default:		/* e.g., 'b' */
81
	    break;
82
	}
83
    fildes = open(fname, flags, S_IRUSR | S_IWUSR);
84
    if (fildes < 0)
85
	return 0;
86
    /*
87
     * The DEC VMS C compiler incorrectly defines the second argument of
88
     * fdopen as (char *), rather than following the POSIX.1 standard,
89
     * which defines it as (const char *).  Patch this here.
90
     */
91
    file = fdopen(fildes, (char *)mode); /* still really const */
92
    if (file == 0)
93
	close(fildes);
94
    return file;
95
}
96
 
97
/* Append a string to buffer. */
98
private inline bool
99
append(char **bp, const char *bpe, const char **ip, uint len)
100
{
101
    if (bpe - *bp < len)
102
	return false;
103
    memcpy(*bp, *ip, len);
104
    *bp += len;
105
    *ip += len;
106
    return true;
107
}
108
 
109
/* Search a separator forward. */
110
private inline uint
111
search_separator(const char **ip, const char *ipe, const char *item, int direction)
112
{   uint slen = 0;
113
    for (slen = 0; (*ip - ipe) * direction < 0; (*ip) += direction)
114
	if((slen = gs_file_name_check_separator(*ip, ipe - *ip, item)) != 0)
115
	    break;
116
    return slen;
117
}
118
 
119
 
120
/*
121
 * Combine a file name with a prefix.
122
 * Concatenates two paths and reduce parent references and current 
123
 * directory references from the concatenation when possible.
124
 * The trailing zero byte is being added.
125
 *
126
 * Examples : 
127
 *	"/gs/lib" + "../Resource/CMap/H" --> "/gs/Resource/CMap/H"
128
 *	"C:/gs/lib" + "../Resource/CMap/H" --> "C:/gs/Resource/CMap/H"
129
 *	"hard disk:gs:lib" + "::Resource:CMap:H" --> 
130
 *		"hard disk:gs:Resource:CMap:H"
131
 *	"DUA1:[GHOSTSCRIPT.LIB" + "-.RESOURCE.CMAP]H" --> 
132
 *		"DUA1:[GHOSTSCRIPT.RESOURCE.CMAP]H"
133
 *      "\\server\share/a/b///c/../d.e/./" + "../x.e/././/../../y.z/v.v" --> 
134
 *		"\\server\share/a/y.z/v.v"
135
 */
136
gp_file_name_combine_result
137
gp_file_name_combine_generic(const char *prefix, uint plen, const char *fname, uint flen, 
138
		    bool no_sibling, char *buffer, uint *blen)
139
{
140
    /*
141
     * THIS CODE IS SHARED FOR MULTIPLE PLATFORMS.
142
     * PLEASE DON'T CHANGE IT FOR A SPECIFIC PLATFORM.
143
     * Change gp_file_name_combine instead.
144
     */
145
    char *bp = buffer, *bpe = buffer + *blen;
146
    const char *ip, *ipe;
147
    uint slen;
148
    uint infix_type = 0; /* 0=none, 1=current, 2=parent. */
149
    uint infix_len = 0;
150
    uint rlen = gp_file_name_root(fname, flen);
151
    /* We need a special handling of infixes only immediately after a drive. */
152
 
153
    if (rlen != 0) {
154
        /* 'fname' is absolute, ignore the prefix. */
155
	ip = fname;
156
	ipe = fname + flen;
157
    } else {
158
        /* Concatenate with prefix. */
159
	ip = prefix;
160
	ipe = prefix + plen;
161
	rlen = gp_file_name_root(prefix, plen);
162
    }
163
    if (!append(&bp, bpe, &ip, rlen))
164
	return gp_combine_small_buffer;
165
    slen = gs_file_name_check_separator(bp, buffer - bp, bp); /* Backward search. */
166
    if (rlen != 0 && slen == 0) {
167
	/* Patch it against names like "c:dir" on Windows. */
168
	const char *sep = gp_file_name_directory_separator();
169
 
170
	slen = strlen(sep);
171
	if (!append(&bp, bpe, &sep, slen))
172
	    return gp_combine_small_buffer;
173
	rlen += slen;
174
    }
175
    for (;;) {
176
	const char *item = ip;
177
	uint ilen;
178
 
179
	slen = search_separator(&ip, ipe, item, 1);
180
	ilen = ip - item;
181
	if (ilen == 0 && !gp_file_name_is_empty_item_meanful()) {
182
	    ip += slen;
183
	    slen = 0;
184
	} else if (gp_file_name_is_current(item, ilen)) {
185
	    /* Skip the reference to 'current', except the starting one.
186
	     * We keep the starting 'current' for platforms, which
187
	     * require relative paths to start with it.
188
	     */
189
	    if (bp == buffer) {
190
		if (!append(&bp, bpe, &item, ilen))
191
		    return gp_combine_small_buffer;
192
		infix_type = 1;
193
		infix_len = ilen;
194
	    } else {
195
		ip += slen;
196
		slen = 0;
197
	    }
198
	} else if (!gp_file_name_is_parent(item, ilen)) {
199
	    if (!append(&bp, bpe, &item, ilen))
200
		return gp_combine_small_buffer;
201
	    /* The 'item' pointer is now broken; it may be restored using 'ilen'. */
202
	} else if (bp == buffer + rlen + infix_len) {
203
	    /* Input is a parent and the output only contains a root and an infix. */
204
	    if (rlen != 0)
205
		return gp_combine_cant_handle;
206
	    switch (infix_type) {
207
		case 1:
208
		    /* Replace the infix with parent. */
209
		    bp = buffer + rlen; /* Drop the old infix, if any. */
210
		    infix_len = 0;
211
		    /* Falls through. */
212
		case 0:
213
		    /* We have no infix, start with parent. */
214
		    if ((no_sibling && ipe == fname + flen && flen != 0) || 
215
			    !gp_file_name_is_partent_allowed())
216
			return gp_combine_cant_handle;
217
		    /* Falls through. */
218
		case 2:
219
		    /* Append one more parent - falls through. */
220
		    DO_NOTHING;
221
	    }
222
	    if (!append(&bp, bpe, &item, ilen))
223
		return gp_combine_small_buffer;
224
	    infix_type = 2;
225
	    infix_len += ilen;
226
	    /* Recompute the separator length. We cannot use the old slen on Mac OS. */
227
	    slen = gs_file_name_check_separator(ip, ipe - ip, ip);
228
	} else {
229
	    /* Input is a parent and the output continues after infix. */
230
	    /* Unappend the last separator and the last item. */
231
	    uint slen1 = gs_file_name_check_separator(bp, buffer + rlen - bp, bp); /* Backward search. */
232
	    char *bie = bp - slen1;
233
 
234
	    bp = bie;
235
	    DISCARD(search_separator((const char **)&bp, buffer + rlen, bp, -1));
236
	    /* The cast above quiets a gcc warning. We believe it's a bug in the compiler. */
237
	    /* Skip the input with separator. We cannot use slen on Mac OS. */
238
	    ip += gs_file_name_check_separator(ip, ipe - ip, ip);
239
	    if (no_sibling) {
240
		const char *p = ip;
241
 
242
		DISCARD(search_separator(&p, ipe, ip, 1));
243
		if (p - ip != bie - bp || memcmp(ip, bp, p - ip))    
244
		    return gp_combine_cant_handle;
245
	    }
246
	    slen = 0;
247
	}
248
	if (slen) {
249
	    if (bp == buffer + rlen + infix_len)
250
		infix_len += slen;
251
	    if (!append(&bp, bpe, &ip, slen))
252
		return gp_combine_small_buffer;
253
	}
254
	if (ip == ipe) {
255
	    if (ipe == fname + flen) {
256
		/* All done.
257
		 * Note that the case (prefix + plen == fname && flen == 0)
258
		 * falls here without appending a separator.
259
		 */
260
		const char *zero="";
261
 
262
		if (bp == buffer) {
263
		    /* Must not return empty path. */
264
		    const char *current = gp_file_name_current();
265
		    int clen = strlen(current);
266
 
267
		    if (!append(&bp, bpe, &current, clen))
268
			return gp_combine_small_buffer;
269
		}
270
		*blen = bp - buffer;
271
		if (!append(&bp, bpe, &zero, 1))
272
		    return gp_combine_small_buffer;
273
		return gp_combine_success;
274
	    } else {
275
	        /* ipe == prefix + plen */
276
		/* Switch to fname. */
277
		ip = fname;
278
		ipe = fname + flen;
279
		if (slen == 0) {
280
		    /* Insert a separator. */
281
		    const char *sep;
282
 
283
		    slen = search_separator(&ip, ipe, fname, 1);
284
		    sep = (slen != 0 ? gp_file_name_directory_separator() 
285
		                    : gp_file_name_separator());
286
		    slen = strlen(sep);
287
		    if (bp == buffer + rlen + infix_len)
288
			infix_len += slen;
289
		    if (!append(&bp, bpe, &sep, slen))
290
			return gp_combine_small_buffer;
291
		    ip = fname; /* Switch to fname. */
292
		}
293
	    }
294
	}
295
    }
296
}
297
 
298
/*
299
 * Reduces parent references and current directory references when possible.
300
 * The trailing zero byte is being added.
301
 *
302
 * Examples : 
303
 *	"/gs/lib/../Resource/CMap/H" --> "/gs/Resource/CMap/H"
304
 *	"C:/gs/lib/../Resource/CMap/H" --> "C:/gs/Resource/CMap/H"
305
 *	"hard disk:gs:lib::Resource:CMap:H" --> 
306
 *		"hard disk:gs:Resource:CMap:H"
307
 *	"DUA1:[GHOSTSCRIPT.LIB.-.RESOURCE.CMAP]H" --> 
308
 *		"DUA1:[GHOSTSCRIPT.RESOURCE.CMAP]H"
309
 *      "\\server\share/a/b///c/../d.e/./../x.e/././/../../y.z/v.v" --> 
310
 *		"\\server\share/a/y.z/v.v"
311
 *
312
 */
313
gp_file_name_combine_result
314
gp_file_name_reduce(const char *fname, uint flen, char *buffer, uint *blen)
315
{
316
    return gp_file_name_combine(fname, flen, fname + flen, 0, false, buffer, blen);
317
}
318
 
319
/* 
320
 * Answers whether a file name is absolute (starts from a root). 
321
 */
322
bool 
323
gp_file_name_is_absolute(const char *fname, uint flen)
324
{
325
    return (gp_file_name_root(fname, flen) > 0);
326
}
327
 
328
/* 
329
 * Returns length of all starting parent references.
330
 */
331
private uint 
332
gp_file_name_prefix(const char *fname, uint flen, 
333
		bool (*test)(const char *fname, uint flen))
334
{
335
    uint plen = gp_file_name_root(fname, flen), slen;
336
    const char *ip, *ipe; 
337
    const char *item = fname; /* plen == flen could cause an indeterminizm. */
338
 
339
    if (plen > 0)
340
	return 0;
341
    ip = fname + plen;
342
    ipe = fname + flen;
343
    for (; ip < ipe; ) {
344
	item = ip;
345
	slen = search_separator(&ip, ipe, item, 1);
346
	if (!(*test)(item, ip - item))
347
	    break;
348
	ip += slen;
349
    }
350
    return item - fname;
351
}
352
 
353
/* 
354
 * Returns length of all starting parent references.
355
 */
356
uint 
357
gp_file_name_parents(const char *fname, uint flen)
358
{
359
    return gp_file_name_prefix(fname, flen, gp_file_name_is_parent); 
360
}
361
 
362
/* 
363
 * Returns length of all starting cwd references.
364
 */
365
uint 
366
gp_file_name_cwds(const char *fname, uint flen)
367
{
368
    return gp_file_name_prefix(fname, flen, gp_file_name_is_current); 
369
}