2 |
- |
1 |
/* Copyright (C) 2001 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: gsiodisk.c,v 1.2 2002/06/14 04:04:39 ray Exp $ */
|
|
|
18 |
/* %disk*% IODevice implementation for Ghostscript */
|
|
|
19 |
|
|
|
20 |
/*
|
|
|
21 |
* This file contains the sources for implmenting the 'flat' disk
|
|
|
22 |
* file structure specified by Adobe. This disk file structure is used
|
|
|
23 |
* to implement the I/O devices refered to as %disk0% to %disk9%.
|
|
|
24 |
*
|
|
|
25 |
* These 'disks' are implemented as a set of directories of the
|
|
|
26 |
* operating system. The location of the directories on the operating
|
|
|
27 |
* system disk structure is defined by the /Root I/O device key. Thus
|
|
|
28 |
* the following Postscript:
|
|
|
29 |
* mark /Root (/gs/disk0) (%disk0) .putdevparams
|
|
|
30 |
* would use the /gs/disk0 directory for storing the data for the disk0
|
|
|
31 |
* iodevice.
|
|
|
32 |
*
|
|
|
33 |
* Due to conflicts between file name formats (name lengths, restricted
|
|
|
34 |
* characters, etc.) a 'mapping file' (map.txt) is used to translate
|
|
|
35 |
* between a logical file name and a real file name on the system.
|
|
|
36 |
* This name translation also flattens the directory structure of the
|
|
|
37 |
* logical file names. (This may be changed in the future. But for
|
|
|
38 |
* now it makes the implementation easier.)
|
|
|
39 |
*
|
|
|
40 |
* A special thanks is given for Noriyuki Matsushima for his creation of
|
|
|
41 |
* the original version of the mapping file logic.
|
|
|
42 |
*/
|
|
|
43 |
|
|
|
44 |
/*
|
|
|
45 |
* Mapping file:
|
|
|
46 |
*
|
|
|
47 |
* The mapping file is used to create a 'flat disk' file structure. All file
|
|
|
48 |
* are stored in a single directory. To accomplish this, the logical file
|
|
|
49 |
* name, including the path, are stored in a 'mapping file'. For each file in
|
|
|
50 |
* flat disk, there is a single line entry in the mapping file. The mapping
|
|
|
51 |
* file entry also includes a file number value. This file number is used as
|
|
|
52 |
* the actual file name in the flat disk directory.
|
|
|
53 |
*
|
|
|
54 |
* The flat disk format and the mapping file are used to eliminate problems
|
|
|
55 |
* with trying to emulate a logical directory structure on different operating
|
|
|
56 |
* systems which have different rules about what is allowed and not allowed
|
|
|
57 |
* in a file name and path.
|
|
|
58 |
*
|
|
|
59 |
* Mapping file format:
|
|
|
60 |
*
|
|
|
61 |
* First line:
|
|
|
62 |
* FileVersion<tab>1<tab>This file is machine generated. No not edit.<newline>
|
|
|
63 |
*
|
|
|
64 |
* Remaining lines:
|
|
|
65 |
* <space>filenumber<tab>file_name<newline>
|
|
|
66 |
*
|
|
|
67 |
* The first line of the mapping file contains the text "FileVersion" followed
|
|
|
68 |
* by a tab character. Then the number 1 (ascii - 31 hex) followed by a tab
|
|
|
69 |
* and then a short message telling people to not edit the file. This is an
|
|
|
70 |
* attempt to keep the mapping file from being corrupted.
|
|
|
71 |
*
|
|
|
72 |
* The file version number must be a "1". This is the only version currently
|
|
|
73 |
* supported. This line exists in case it is necessary to modify the mapping
|
|
|
74 |
* file format at some future date. The presence of a version number allows
|
|
|
75 |
* for seamless upgrading of the file format.
|
|
|
76 |
*
|
|
|
77 |
* The format of the entry lines has been created so that the read entry
|
|
|
78 |
* routine would:
|
|
|
79 |
* 1. Grab the number (including the space if it has not already been read.)
|
|
|
80 |
* 2. Grab the tab
|
|
|
81 |
* 3. Grab everything up to a linefeed or carriage return as the file name.
|
|
|
82 |
* 4. Grab any remaining linefeeds/carriage returns. Note this step might
|
|
|
83 |
* grab the first character of the next line if there is only a single
|
|
|
84 |
* carriage return or linefeed. Since it is not desireable to have to worry
|
|
|
85 |
* about doing an 'unget character', an extra space has been put at the
|
|
|
86 |
* beginning of each line. The extra logic with the linefeed/carriage return
|
|
|
87 |
* is primarily there in case someone accidentally mangles the file by looking
|
|
|
88 |
* at it with a text editor.
|
|
|
89 |
*
|
|
|
90 |
* This basically allows for any file name except one that includes
|
|
|
91 |
* a zero, a carriage return, or a linefeed. The requirement for excluding
|
|
|
92 |
* zero is that there are too many C string routines that assume zero is
|
|
|
93 |
* a string terminator (including much of the current Ghostscript code and
|
|
|
94 |
* the current map handler). The carriage return/linefeed requirement is
|
|
|
95 |
* there simply because it is being used as a terminator for the file name.
|
|
|
96 |
* It could easily be eliminated by adding a zero as the name terminator.
|
|
|
97 |
* The only disadvantage is that the file is no longer totally printable ascii.
|
|
|
98 |
*/
|
|
|
99 |
|
|
|
100 |
#include "errno_.h"
|
|
|
101 |
#include "string_.h"
|
|
|
102 |
#include "unistd_.h"
|
|
|
103 |
#include "gx.h"
|
|
|
104 |
#include "gserrors.h"
|
|
|
105 |
#include "gp.h"
|
|
|
106 |
#include "gscdefs.h"
|
|
|
107 |
#include "gsparam.h"
|
|
|
108 |
#include "gsstruct.h"
|
|
|
109 |
#include "gxiodev.h"
|
|
|
110 |
#include "gsutil.h"
|
|
|
111 |
|
|
|
112 |
/* Function prototypes */
|
|
|
113 |
private iodev_proc_init(iodev_diskn_init);
|
|
|
114 |
private iodev_proc_fopen(iodev_diskn_fopen);
|
|
|
115 |
private iodev_proc_delete_file(diskn_delete);
|
|
|
116 |
private iodev_proc_rename_file(diskn_rename);
|
|
|
117 |
private iodev_proc_file_status(diskn_status);
|
|
|
118 |
private iodev_proc_enumerate_files(diskn_enumerate_files);
|
|
|
119 |
private iodev_proc_enumerate_next(diskn_enumerate_next);
|
|
|
120 |
private iodev_proc_enumerate_close(diskn_enumerate_close);
|
|
|
121 |
private iodev_proc_get_params(diskn_get_params);
|
|
|
122 |
private iodev_proc_put_params(diskn_put_params);
|
|
|
123 |
iodev_proc_put_params(diskn_os_put_params);
|
|
|
124 |
|
|
|
125 |
/* Define a diskn (%diskn%) device macro */
|
|
|
126 |
#define diskn(varname,diskname) \
|
|
|
127 |
const gx_io_device varname = \
|
|
|
128 |
{ \
|
|
|
129 |
diskname, "FileSystem", \
|
|
|
130 |
{iodev_diskn_init, iodev_no_open_device, \
|
|
|
131 |
NULL /* no longer used */ , iodev_diskn_fopen, iodev_os_fclose, \
|
|
|
132 |
diskn_delete, diskn_rename, diskn_status, \
|
|
|
133 |
iodev_no_enumerate_files, /* Only until we have a root location */ \
|
|
|
134 |
diskn_enumerate_next, diskn_enumerate_close, \
|
|
|
135 |
diskn_get_params, diskn_put_params \
|
|
|
136 |
} \
|
|
|
137 |
}
|
|
|
138 |
|
|
|
139 |
/*
|
|
|
140 |
* Define the disk0-6 (%diskn%) devices. These devices are
|
|
|
141 |
* used in the device list in gconf.c.
|
|
|
142 |
*/
|
|
|
143 |
diskn(gs_iodev_disk0,"%disk0%");
|
|
|
144 |
diskn(gs_iodev_disk1,"%disk1%");
|
|
|
145 |
diskn(gs_iodev_disk2,"%disk2%");
|
|
|
146 |
diskn(gs_iodev_disk3,"%disk3%");
|
|
|
147 |
diskn(gs_iodev_disk4,"%disk4%");
|
|
|
148 |
diskn(gs_iodev_disk5,"%disk5%");
|
|
|
149 |
diskn(gs_iodev_disk6,"%disk6%");
|
|
|
150 |
/* We could have more disks, but the DynaLab font installer */
|
|
|
151 |
/* has problems with more than 7 disks */
|
|
|
152 |
#undef diskn
|
|
|
153 |
|
|
|
154 |
typedef struct diskn_state_s {
|
|
|
155 |
int root_size; /* size of root buffer */
|
|
|
156 |
char * root; /* root path pointer */
|
|
|
157 |
gs_memory_t * memory; /* memory structure used */
|
|
|
158 |
} diskn_state;
|
|
|
159 |
|
|
|
160 |
gs_private_st_ptrs1(st_diskn_state, struct diskn_state_s, "diskn_state",
|
|
|
161 |
diskn_state_enum_ptrs, diskn_state_reloc_ptrs, root);
|
|
|
162 |
|
|
|
163 |
#define MAP_FILE_NAME "map.txt"
|
|
|
164 |
#define TEMP_FILE_NAME "Tmp.txt"
|
|
|
165 |
#define MAP_FILE_VERSION 1
|
|
|
166 |
#define InitialNumber 0
|
|
|
167 |
#define BUFFER_LENGTH gp_file_name_sizeof
|
|
|
168 |
|
|
|
169 |
typedef struct map_file_enum_s {
|
|
|
170 |
FILE * stream; /* stream to map file */
|
|
|
171 |
char * pattern; /* pattern pointer */
|
|
|
172 |
char * root; /* root path pointer */
|
|
|
173 |
gs_memory_t * memory; /* memory structure used */
|
|
|
174 |
} map_file_enum;
|
|
|
175 |
|
|
|
176 |
gs_private_st_ptrs2(st_map_file_enum, struct map_file_enum_s, "map_file_enum",
|
|
|
177 |
map_file_enum_enum_ptrs, map_file_enum_reloc_ptrs, pattern, root);
|
|
|
178 |
|
|
|
179 |
private void * map_file_enum_init(gs_memory_t *, const char *, const char *);
|
|
|
180 |
private bool map_file_enum_next(void *, char *);
|
|
|
181 |
private void map_file_enum_close(void *);
|
|
|
182 |
private bool map_file_name_get(const char *, const char *, char *);
|
|
|
183 |
private void map_file_name_add(const char *, const char *);
|
|
|
184 |
private void map_file_name_ren(const char*, const char *, const char *);
|
|
|
185 |
private void map_file_name_del(const char *, const char *);
|
|
|
186 |
|
|
|
187 |
private int
|
|
|
188 |
iodev_diskn_init(gx_io_device * iodev, gs_memory_t * mem)
|
|
|
189 |
{
|
|
|
190 |
diskn_state * pstate = gs_alloc_struct(mem, diskn_state, &st_diskn_state,
|
|
|
191 |
"iodev_diskn_init(state)");
|
|
|
192 |
if (!pstate)
|
|
|
193 |
return gs_error_VMerror;
|
|
|
194 |
pstate->root_size = 0;
|
|
|
195 |
pstate->root = NULL;
|
|
|
196 |
pstate->memory = mem;
|
|
|
197 |
iodev->state = pstate;
|
|
|
198 |
return 0;
|
|
|
199 |
}
|
|
|
200 |
|
|
|
201 |
|
|
|
202 |
private int
|
|
|
203 |
iodev_diskn_fopen(gx_io_device * iodev, const char *fname, const char *access,
|
|
|
204 |
FILE ** pfile, char *rfname, uint rnamelen)
|
|
|
205 |
{
|
|
|
206 |
char realname[gp_file_name_sizeof];
|
|
|
207 |
diskn_state * pstate = (diskn_state *)iodev->state;
|
|
|
208 |
|
|
|
209 |
/* Exit if we do not have a root location */
|
|
|
210 |
if (!pstate->root)
|
|
|
211 |
return_error(gs_error_undefinedfilename);
|
|
|
212 |
|
|
|
213 |
/* Remap filename (if it exists). */
|
|
|
214 |
if (!map_file_name_get((char *)pstate->root, fname, realname)) {
|
|
|
215 |
if (strchr(access, 'w')) {
|
|
|
216 |
map_file_name_add(pstate->root, fname);
|
|
|
217 |
map_file_name_get(pstate->root, fname, realname);
|
|
|
218 |
}
|
|
|
219 |
else
|
|
|
220 |
return_error(gs_error_undefinedfilename);
|
|
|
221 |
}
|
|
|
222 |
|
|
|
223 |
return iodev_os_fopen(iodev_default, realname, access, pfile, rfname, rnamelen);
|
|
|
224 |
}
|
|
|
225 |
|
|
|
226 |
private int
|
|
|
227 |
diskn_delete(gx_io_device * iodev, const char *fname)
|
|
|
228 |
{
|
|
|
229 |
char realname[gp_file_name_sizeof];
|
|
|
230 |
diskn_state * pstate = (diskn_state *)iodev->state;
|
|
|
231 |
|
|
|
232 |
/* Exit if we do not have a root location */
|
|
|
233 |
if (!pstate->root)
|
|
|
234 |
return_error(gs_error_undefinedfilename);
|
|
|
235 |
|
|
|
236 |
/* Map filename (if it exists). */
|
|
|
237 |
if (!map_file_name_get((char *)pstate->root, fname, realname))
|
|
|
238 |
return_error(gs_error_undefinedfilename);
|
|
|
239 |
|
|
|
240 |
map_file_name_del((char *)pstate->root, fname);
|
|
|
241 |
return (unlink(realname) == 0 ? 0 : gs_error_ioerror);
|
|
|
242 |
}
|
|
|
243 |
|
|
|
244 |
private int
|
|
|
245 |
diskn_rename(gx_io_device * iodev, const char *from, const char *to)
|
|
|
246 |
{
|
|
|
247 |
char toreal[gp_file_name_sizeof];
|
|
|
248 |
int code = 0;
|
|
|
249 |
diskn_state * pstate = (diskn_state *)iodev->state;
|
|
|
250 |
|
|
|
251 |
/* Exit if we do not have a root location */
|
|
|
252 |
if (!pstate->root)
|
|
|
253 |
return_error(gs_error_undefinedfilename);
|
|
|
254 |
|
|
|
255 |
/* if filenames are the same them we are done. */
|
|
|
256 |
if (strcmp(to, from) == 0)
|
|
|
257 |
return 0;
|
|
|
258 |
|
|
|
259 |
/*
|
|
|
260 |
* If the destination file already exists, then we want to delete it.
|
|
|
261 |
*/
|
|
|
262 |
if (map_file_name_get((char *)pstate->root, to, toreal)) {
|
|
|
263 |
map_file_name_del((char *)pstate->root, to);
|
|
|
264 |
code = unlink(toreal) == 0 ? 0 : gs_error_ioerror;
|
|
|
265 |
}
|
|
|
266 |
|
|
|
267 |
map_file_name_ren((char *)pstate->root, from, to);
|
|
|
268 |
return code;
|
|
|
269 |
}
|
|
|
270 |
|
|
|
271 |
private int
|
|
|
272 |
diskn_status(gx_io_device * iodev, const char *fname, struct stat *pstat)
|
|
|
273 |
{
|
|
|
274 |
char realname[gp_file_name_sizeof];
|
|
|
275 |
diskn_state * pstate = (diskn_state *)iodev->state;
|
|
|
276 |
|
|
|
277 |
/* Exit if we do not have a root location */
|
|
|
278 |
if (!pstate->root)
|
|
|
279 |
return_error(gs_error_undefinedfilename);
|
|
|
280 |
|
|
|
281 |
/* Map filename (if it exists). */
|
|
|
282 |
if (!map_file_name_get((char *)pstate->root, fname, realname))
|
|
|
283 |
return_error(gs_error_undefinedfilename);
|
|
|
284 |
|
|
|
285 |
return (stat((char *)realname, pstat) < 0 ? gs_error_undefinedfilename : 0);
|
|
|
286 |
}
|
|
|
287 |
|
|
|
288 |
private file_enum *
|
|
|
289 |
diskn_enumerate_files_init(gx_io_device * iodev, const char *pat, uint patlen,
|
|
|
290 |
gs_memory_t * mem)
|
|
|
291 |
{
|
|
|
292 |
char patstr[gp_file_name_sizeof];
|
|
|
293 |
diskn_state * pstate = (diskn_state *)iodev->state;
|
|
|
294 |
|
|
|
295 |
memcpy(patstr, pat, patlen); /* Copy string to buffer */
|
|
|
296 |
patstr[patlen]=0; /* Terminate string */
|
|
|
297 |
return (file_enum *)map_file_enum_init(mem, (char *)pstate->root, patstr);
|
|
|
298 |
}
|
|
|
299 |
|
|
|
300 |
private void
|
|
|
301 |
diskn_enumerate_close(file_enum *pfen)
|
|
|
302 |
{
|
|
|
303 |
map_file_enum_close((void *)pfen);
|
|
|
304 |
}
|
|
|
305 |
|
|
|
306 |
private uint
|
|
|
307 |
diskn_enumerate_next(file_enum *pfen, char *ptr, uint maxlen)
|
|
|
308 |
{
|
|
|
309 |
if (map_file_enum_next((void *)pfen, ptr))
|
|
|
310 |
return strlen(ptr);
|
|
|
311 |
/* If we did not find a file then clean up */
|
|
|
312 |
diskn_enumerate_close(pfen);
|
|
|
313 |
return ~(uint) 0;
|
|
|
314 |
}
|
|
|
315 |
|
|
|
316 |
private int
|
|
|
317 |
diskn_get_params(gx_io_device * iodev, gs_param_list * plist)
|
|
|
318 |
{
|
|
|
319 |
int code;
|
|
|
320 |
int i0 = 0, so = 1;
|
|
|
321 |
bool btrue = true, bfalse = false;
|
|
|
322 |
diskn_state * pstate = (diskn_state *)iodev->state;
|
|
|
323 |
bool bsearch = pstate->root != 0;
|
|
|
324 |
int BlockSize;
|
|
|
325 |
long Free, LogicalSize;
|
|
|
326 |
gs_param_string rootstring;
|
|
|
327 |
|
|
|
328 |
/*
|
|
|
329 |
* Return fake values for BlockSize and Free, since we can't get the
|
|
|
330 |
* correct values in a platform-independent manner.
|
|
|
331 |
*/
|
|
|
332 |
BlockSize = 1024;
|
|
|
333 |
LogicalSize = bsearch ? 2000000000 / BlockSize : 0; /* about 2 Gb */
|
|
|
334 |
Free = LogicalSize * 3 / 4; /* about 1.5 Gb */
|
|
|
335 |
|
|
|
336 |
if (
|
|
|
337 |
(code = param_write_bool(plist, "HasNames", &btrue)) < 0 ||
|
|
|
338 |
(code = param_write_int(plist, "BlockSize", &BlockSize)) < 0 ||
|
|
|
339 |
(code = param_write_long(plist, "Free", &Free)) < 0 ||
|
|
|
340 |
(code = param_write_int(plist, "InitializeAction", &i0)) < 0 ||
|
|
|
341 |
(code = param_write_bool(plist, "Mounted", &bsearch)) < 0 ||
|
|
|
342 |
(code = param_write_bool(plist, "Removable", &bfalse)) < 0 ||
|
|
|
343 |
(code = param_write_bool(plist, "Searchable", &bsearch)) < 0 ||
|
|
|
344 |
(code = param_write_int(plist, "SearchOrder", &so)) < 0 ||
|
|
|
345 |
(code = param_write_bool(plist, "Writeable", &bsearch)) < 0 ||
|
|
|
346 |
(code = param_write_long(plist, "LogicalSize", &LogicalSize)) < 0
|
|
|
347 |
)
|
|
|
348 |
return code;
|
|
|
349 |
|
|
|
350 |
if (pstate->root) {
|
|
|
351 |
rootstring.data = (const byte *)pstate->root;
|
|
|
352 |
rootstring.size = strlen(pstate->root);
|
|
|
353 |
rootstring.persistent = false;
|
|
|
354 |
return param_write_string(plist, "Root", &rootstring);
|
|
|
355 |
}
|
|
|
356 |
else {
|
|
|
357 |
return param_write_null(plist, "Root");
|
|
|
358 |
}
|
|
|
359 |
}
|
|
|
360 |
|
|
|
361 |
private int
|
|
|
362 |
diskn_put_params(gx_io_device *iodev, gs_param_list *plist)
|
|
|
363 |
{
|
|
|
364 |
gs_param_string rootstr;
|
|
|
365 |
int code;
|
|
|
366 |
diskn_state * pstate = (diskn_state *)iodev->state;
|
|
|
367 |
|
|
|
368 |
switch (code = param_read_string(plist, "Root", &rootstr)) {
|
|
|
369 |
case 0:
|
|
|
370 |
break;
|
|
|
371 |
default:
|
|
|
372 |
param_signal_error(plist, "Root", code);
|
|
|
373 |
case 1:
|
|
|
374 |
rootstr.data = 0;
|
|
|
375 |
break;
|
|
|
376 |
}
|
|
|
377 |
|
|
|
378 |
/* Process the other device parameters */
|
|
|
379 |
code = iodev_no_put_params(iodev, plist);
|
|
|
380 |
if (code < 0)
|
|
|
381 |
return code;
|
|
|
382 |
|
|
|
383 |
/* Process parameter changes */
|
|
|
384 |
|
|
|
385 |
if (rootstr.data) {
|
|
|
386 |
/* Make sure that we have room for the root string */
|
|
|
387 |
if (!pstate->root || pstate->root_size <= rootstr.size) {
|
|
|
388 |
if (pstate->root) /* The current storge is too small */
|
|
|
389 |
gs_free_object(pstate->memory, pstate->root, "diskn(rootdir)");
|
|
|
390 |
pstate->root = (char *)gs_alloc_byte_array(pstate->memory,
|
|
|
391 |
gp_file_name_sizeof, sizeof(char), "diskn(rootdir)");
|
|
|
392 |
if (!pstate->root)
|
|
|
393 |
return gs_error_VMerror;
|
|
|
394 |
pstate->root_size = rootstr.size + 1;
|
|
|
395 |
/* Now allow enumeration of files on the disk */
|
|
|
396 |
iodev->procs.enumerate_files = diskn_enumerate_files_init;
|
|
|
397 |
}
|
|
|
398 |
|
|
|
399 |
memcpy(pstate->root, rootstr.data, rootstr.size);
|
|
|
400 |
pstate->root[rootstr.size] = 0;
|
|
|
401 |
}
|
|
|
402 |
return 0;
|
|
|
403 |
}
|
|
|
404 |
|
|
|
405 |
/*
|
|
|
406 |
* Open the specified file with specified attributes.
|
|
|
407 |
*
|
|
|
408 |
* rootpath - Path to base disk location.
|
|
|
409 |
* filename - File name string
|
|
|
410 |
* attributes - File attributes string
|
|
|
411 |
* Returns - NULL if error, file structure pointer if no error
|
|
|
412 |
*/
|
|
|
413 |
private FILE *
|
|
|
414 |
MapFileOpen(const char * rootpath, const char * filename, const char * attributes)
|
|
|
415 |
{
|
|
|
416 |
char fullname[BUFFER_LENGTH];
|
|
|
417 |
|
|
|
418 |
if (strlen(rootpath) + strlen(filename) >= BUFFER_LENGTH)
|
|
|
419 |
return NULL;
|
|
|
420 |
sprintf(fullname, "%s%s", rootpath, filename);
|
|
|
421 |
return gp_fopen(fullname, attributes);
|
|
|
422 |
}
|
|
|
423 |
|
|
|
424 |
/*
|
|
|
425 |
* Read map file version (first line)
|
|
|
426 |
*
|
|
|
427 |
* mapfile - Mapping file structure pointer
|
|
|
428 |
* value - pointer to version number storage location
|
|
|
429 |
* Returns 1 if data read, else 0
|
|
|
430 |
*/
|
|
|
431 |
private int
|
|
|
432 |
MapFileReadVersion(FILE * mapfile, int * value)
|
|
|
433 |
{
|
|
|
434 |
int code = fscanf(mapfile, "FileVersion\t%d\t", value) == 1 ? 1 : 0;
|
|
|
435 |
int c;
|
|
|
436 |
|
|
|
437 |
/* Skip comment on version line. */
|
|
|
438 |
do {
|
|
|
439 |
c = fgetc(mapfile);
|
|
|
440 |
} while (c != EOF && c != '\n' && c != '\r');
|
|
|
441 |
|
|
|
442 |
/* Clean up any trailing linefeeds or carriage returns */
|
|
|
443 |
while (c != EOF && (c == '\n' || c == '\r')) {
|
|
|
444 |
c = fgetc(mapfile);
|
|
|
445 |
}
|
|
|
446 |
return code;
|
|
|
447 |
}
|
|
|
448 |
|
|
|
449 |
/*
|
|
|
450 |
* Write a map file version (first line) into the map file
|
|
|
451 |
*
|
|
|
452 |
* stream - File structure pointer
|
|
|
453 |
* value - version number
|
|
|
454 |
*/
|
|
|
455 |
private void
|
|
|
456 |
MapFileWriteVersion(FILE * mapfile, int value)
|
|
|
457 |
{
|
|
|
458 |
fprintf(mapfile,
|
|
|
459 |
"FileVersion\t%d\tThis file is machine generated. Do not edit.\n",
|
|
|
460 |
value);
|
|
|
461 |
}
|
|
|
462 |
|
|
|
463 |
/*
|
|
|
464 |
* Read an entry in the map file
|
|
|
465 |
*
|
|
|
466 |
* mapfile - Mapping file structure pointer
|
|
|
467 |
* namebuf - Buffer for the file name storage
|
|
|
468 |
* value - pointer to file number storage location
|
|
|
469 |
* Returns 1 if data read, else 0
|
|
|
470 |
*/
|
|
|
471 |
private int
|
|
|
472 |
MapFileRead(FILE * mapfile, char * namebuf, int * value)
|
|
|
473 |
{
|
|
|
474 |
int count = 0;
|
|
|
475 |
int c;
|
|
|
476 |
|
|
|
477 |
/* Get the file number */
|
|
|
478 |
if (fscanf(mapfile, "%d\t", value) != 1)
|
|
|
479 |
return 0;
|
|
|
480 |
|
|
|
481 |
/* Get the file name */
|
|
|
482 |
do {
|
|
|
483 |
namebuf[count++] = c = fgetc(mapfile);
|
|
|
484 |
} while (count < BUFFER_LENGTH && c != EOF && c != '\n' && c != '\r');
|
|
|
485 |
namebuf[--count] = 0; /* Terminate file name */
|
|
|
486 |
|
|
|
487 |
/* Clean up any trailing linefeeds or carriage returns */
|
|
|
488 |
while (c != EOF && (c == '\n' || c == '\r')) {
|
|
|
489 |
c = fgetc(mapfile);
|
|
|
490 |
}
|
|
|
491 |
|
|
|
492 |
return count != 0 ? 1: 0;
|
|
|
493 |
}
|
|
|
494 |
|
|
|
495 |
/*
|
|
|
496 |
* Write an entry in the map file
|
|
|
497 |
*
|
|
|
498 |
* stream - File structure pointer
|
|
|
499 |
* namebuf - Buffer for the file name storage
|
|
|
500 |
* value - file number
|
|
|
501 |
*/
|
|
|
502 |
private void
|
|
|
503 |
MapFileWrite(FILE * mapfile, const char * namebuf, int value)
|
|
|
504 |
{
|
|
|
505 |
fprintf(mapfile, " %d\t%s\n", value, namebuf);
|
|
|
506 |
}
|
|
|
507 |
|
|
|
508 |
/*
|
|
|
509 |
* Remove the specified file
|
|
|
510 |
*
|
|
|
511 |
* rootpath - Path to base disk location.
|
|
|
512 |
* filename - File name string
|
|
|
513 |
*/
|
|
|
514 |
private void
|
|
|
515 |
MapFileUnlink(const char * rootpath, const char * filename)
|
|
|
516 |
{
|
|
|
517 |
char fullname[BUFFER_LENGTH];
|
|
|
518 |
|
|
|
519 |
if (strlen(rootpath) + strlen(filename) >= BUFFER_LENGTH)
|
|
|
520 |
return;
|
|
|
521 |
sprintf(fullname, "%s%s", rootpath, filename);
|
|
|
522 |
unlink(fullname);
|
|
|
523 |
}
|
|
|
524 |
|
|
|
525 |
/*
|
|
|
526 |
* Rename the specified file to new specified name
|
|
|
527 |
*
|
|
|
528 |
* rootpath - Path to base disk location.
|
|
|
529 |
* oldfilename - Old file name string
|
|
|
530 |
* newfilename - New file name string
|
|
|
531 |
*/
|
|
|
532 |
private void
|
|
|
533 |
MapFileRename(const char * rootpath, const char * newfilename, const char * oldfilename)
|
|
|
534 |
{
|
|
|
535 |
char oldfullname[BUFFER_LENGTH];
|
|
|
536 |
char newfullname[BUFFER_LENGTH];
|
|
|
537 |
|
|
|
538 |
if (strlen(rootpath) + strlen(oldfilename) >= BUFFER_LENGTH)
|
|
|
539 |
return;
|
|
|
540 |
if (strlen(rootpath) + strlen(newfilename) >= BUFFER_LENGTH)
|
|
|
541 |
return;
|
|
|
542 |
sprintf(oldfullname, "%s%s", rootpath, oldfilename);
|
|
|
543 |
sprintf(newfullname, "%s%s", rootpath, newfilename);
|
|
|
544 |
rename(oldfullname, newfullname);
|
|
|
545 |
}
|
|
|
546 |
|
|
|
547 |
/*
|
|
|
548 |
* MapToFile
|
|
|
549 |
*
|
|
|
550 |
* Search for mapped number from map file with requied name. If same name exist,
|
|
|
551 |
* first (lowest number) will be returned.
|
|
|
552 |
* rootpath char* string of the base path where in disk0 reside (C:\PS\Disk0\)
|
|
|
553 |
* name char* string to search pattern for full match (font\Ryumin-Light)
|
|
|
554 |
* returns -1 if file not found, file number if found.
|
|
|
555 |
*/
|
|
|
556 |
private int
|
|
|
557 |
MapToFile(const char* rootpath, const char* name)
|
|
|
558 |
{
|
|
|
559 |
FILE * mapfile;
|
|
|
560 |
int d = -1;
|
|
|
561 |
char filename[BUFFER_LENGTH];
|
|
|
562 |
int file_version;
|
|
|
563 |
|
|
|
564 |
mapfile = MapFileOpen(rootpath, MAP_FILE_NAME, "r");
|
|
|
565 |
if (mapfile == NULL)
|
|
|
566 |
return -1;
|
|
|
567 |
|
|
|
568 |
/* Verify the mapping file version number */
|
|
|
569 |
|
|
|
570 |
if (MapFileReadVersion(mapfile, &file_version)
|
|
|
571 |
&& file_version == MAP_FILE_VERSION) {
|
|
|
572 |
|
|
|
573 |
/* Scan the file looking for the given name */
|
|
|
574 |
|
|
|
575 |
while (MapFileRead(mapfile, filename, &d)) {
|
|
|
576 |
if (strcmp(filename, name) == 0)
|
|
|
577 |
break;
|
|
|
578 |
d = -1;
|
|
|
579 |
}
|
|
|
580 |
}
|
|
|
581 |
fclose(mapfile);
|
|
|
582 |
return d;
|
|
|
583 |
}
|
|
|
584 |
|
|
|
585 |
/*
|
|
|
586 |
* map_file_enum_init
|
|
|
587 |
*
|
|
|
588 |
* create enumiate structure for a mapped file and fill pattern for search
|
|
|
589 |
* root_name char* string of the base path where in disk0 reside (e.g. C:\PS\Disk0\)
|
|
|
590 |
* search_pattern char* string to search pattern (font\*) or full match
|
|
|
591 |
* (e.g. font\Ryumin-Light) or NULL
|
|
|
592 |
* NULL means all files
|
|
|
593 |
* Returns: NULL if error, else pointer to enumeration structure.
|
|
|
594 |
*/
|
|
|
595 |
private void *
|
|
|
596 |
map_file_enum_init(gs_memory_t * mem, const char * root_name, const char * search_pattern)
|
|
|
597 |
{
|
|
|
598 |
int file_version;
|
|
|
599 |
map_file_enum * mapfileenum = gs_alloc_struct(mem, map_file_enum, &st_map_file_enum,
|
|
|
600 |
"diskn:enum_init(file_enum)");
|
|
|
601 |
|
|
|
602 |
if (mapfileenum == NULL)
|
|
|
603 |
return NULL;
|
|
|
604 |
memset(mapfileenum, 0, sizeof(map_file_enum));
|
|
|
605 |
mapfileenum->memory = mem;
|
|
|
606 |
|
|
|
607 |
if (search_pattern) {
|
|
|
608 |
mapfileenum->pattern = (char *)gs_alloc_bytes(mem, strlen(search_pattern) + 1,
|
|
|
609 |
"diskn:enum_init(pattern)");
|
|
|
610 |
if (mapfileenum->pattern == NULL) {
|
|
|
611 |
map_file_enum_close((file_enum *) mapfileenum);
|
|
|
612 |
return NULL;
|
|
|
613 |
}
|
|
|
614 |
strcpy(mapfileenum->pattern, search_pattern);
|
|
|
615 |
}
|
|
|
616 |
|
|
|
617 |
mapfileenum->root = (char *)gs_alloc_bytes(mem, strlen(root_name) + 1,
|
|
|
618 |
"diskn:enum_init(root)");
|
|
|
619 |
if (mapfileenum->root == NULL) {
|
|
|
620 |
map_file_enum_close((file_enum *) mapfileenum);
|
|
|
621 |
return NULL;
|
|
|
622 |
}
|
|
|
623 |
|
|
|
624 |
if (strlen(root_name) >= BUFFER_LENGTH)
|
|
|
625 |
return NULL;
|
|
|
626 |
strcpy(mapfileenum->root, root_name);
|
|
|
627 |
mapfileenum->stream = MapFileOpen(root_name, MAP_FILE_NAME, "r");
|
|
|
628 |
|
|
|
629 |
/* Check the mapping file version number */
|
|
|
630 |
if (mapfileenum->stream != NULL
|
|
|
631 |
&& (!MapFileReadVersion(mapfileenum->stream, &file_version)
|
|
|
632 |
|| file_version != MAP_FILE_VERSION)) {
|
|
|
633 |
fclose(mapfileenum->stream); /* Invalid file version */
|
|
|
634 |
mapfileenum->stream = NULL;
|
|
|
635 |
}
|
|
|
636 |
|
|
|
637 |
return mapfileenum;
|
|
|
638 |
}
|
|
|
639 |
|
|
|
640 |
/*
|
|
|
641 |
* map_file_enum_next
|
|
|
642 |
*
|
|
|
643 |
* enum_mem void* pointer for map file enum structure
|
|
|
644 |
* search_pattern char* string array for next target
|
|
|
645 |
*/
|
|
|
646 |
private bool
|
|
|
647 |
map_file_enum_next(void * enum_mem, char* target)
|
|
|
648 |
{
|
|
|
649 |
int d = -1;
|
|
|
650 |
map_file_enum * mapfileenum;
|
|
|
651 |
|
|
|
652 |
if (enum_mem == NULL)
|
|
|
653 |
return false;
|
|
|
654 |
|
|
|
655 |
mapfileenum = (map_file_enum*)enum_mem;
|
|
|
656 |
if (mapfileenum->stream == NULL)
|
|
|
657 |
return false;
|
|
|
658 |
|
|
|
659 |
if (mapfileenum->pattern) {
|
|
|
660 |
/* Search for next entry that matches pattern */
|
|
|
661 |
while (MapFileRead(mapfileenum->stream, target, &d)) {
|
|
|
662 |
if (string_match((byte *)target, strlen(target),
|
|
|
663 |
(byte *)mapfileenum->pattern,
|
|
|
664 |
strlen(mapfileenum->pattern), 0))
|
|
|
665 |
return true;
|
|
|
666 |
}
|
|
|
667 |
}
|
|
|
668 |
else {
|
|
|
669 |
/* Just get next */
|
|
|
670 |
if (MapFileRead(mapfileenum->stream, target, &d))
|
|
|
671 |
return true;
|
|
|
672 |
}
|
|
|
673 |
return false;
|
|
|
674 |
}
|
|
|
675 |
|
|
|
676 |
/*
|
|
|
677 |
* map_file_enum_close
|
|
|
678 |
*
|
|
|
679 |
* cleans up after an enumeration, this may only be called
|
|
|
680 |
* if map_file_enum_init did not fail
|
|
|
681 |
*/
|
|
|
682 |
private void
|
|
|
683 |
map_file_enum_close(void * enum_mem)
|
|
|
684 |
{
|
|
|
685 |
map_file_enum * mapfileenum = (map_file_enum *) enum_mem;
|
|
|
686 |
gs_memory_t * mem = mapfileenum->memory;
|
|
|
687 |
|
|
|
688 |
if (mapfileenum->stream)
|
|
|
689 |
fclose(mapfileenum->stream);
|
|
|
690 |
if (mapfileenum->root)
|
|
|
691 |
gs_free_object(mem, mapfileenum->root, "diskn_enum_init(root)");
|
|
|
692 |
if (mapfileenum->pattern)
|
|
|
693 |
gs_free_object(mem, mapfileenum->pattern, "diskn_enum_init(pattern)");
|
|
|
694 |
gs_free_object(mem, mapfileenum, "diskn_enum_init(mapfileenum)");
|
|
|
695 |
}
|
|
|
696 |
|
|
|
697 |
/*
|
|
|
698 |
* map_file_name_get
|
|
|
699 |
*
|
|
|
700 |
* maps the psname(Fname) to the osname using concatening the root_name and id
|
|
|
701 |
* Id will be a lowest one if same psname exists more than one in map file. See MapToFile
|
|
|
702 |
* for detail.
|
|
|
703 |
* root_name char* string of the base path where in disk0 reside
|
|
|
704 |
* (e.g.C:\PS\Disk0\)
|
|
|
705 |
* Fname char* name of the entry to find in the map
|
|
|
706 |
* osname char* resulting os specific path to the file
|
|
|
707 |
*/
|
|
|
708 |
private bool
|
|
|
709 |
map_file_name_get(const char * root_name, const char * Fname, char * osname)
|
|
|
710 |
{
|
|
|
711 |
int d = MapToFile(root_name, Fname);
|
|
|
712 |
|
|
|
713 |
if (d != -1) {
|
|
|
714 |
/* 20 characters are enough for even a 64 bit integer */
|
|
|
715 |
if ((strlen(root_name) + 20) < BUFFER_LENGTH) {
|
|
|
716 |
sprintf(osname, "%s%d", root_name, d);
|
|
|
717 |
return true;
|
|
|
718 |
}
|
|
|
719 |
}
|
|
|
720 |
|
|
|
721 |
*osname = 0;
|
|
|
722 |
return false;
|
|
|
723 |
}
|
|
|
724 |
|
|
|
725 |
/*
|
|
|
726 |
* map_file_name_del
|
|
|
727 |
*
|
|
|
728 |
* Deletes Fname from the mapping table and does not delete the actual file
|
|
|
729 |
* If same Fname exists, all same Fname will be deleted
|
|
|
730 |
* root_name char* string of the base path where in disk0 reside (C:\PS\Disk0\)
|
|
|
731 |
* Fname char* name of the entry to add to the map
|
|
|
732 |
*/
|
|
|
733 |
private void
|
|
|
734 |
map_file_name_del(const char * root_name, const char * Fname)
|
|
|
735 |
{
|
|
|
736 |
/* search for target entry */
|
|
|
737 |
int d = MapToFile(root_name, Fname);
|
|
|
738 |
int file_version;
|
|
|
739 |
|
|
|
740 |
if (d != -1) { /* if the file exists ... */
|
|
|
741 |
char name[BUFFER_LENGTH];
|
|
|
742 |
FILE* newMap;
|
|
|
743 |
FILE* oldMap;
|
|
|
744 |
|
|
|
745 |
/* Open current map file and a working file */
|
|
|
746 |
|
|
|
747 |
MapFileUnlink(root_name, TEMP_FILE_NAME );
|
|
|
748 |
newMap = MapFileOpen(root_name, TEMP_FILE_NAME, "w");
|
|
|
749 |
if (newMap == NULL)
|
|
|
750 |
return;
|
|
|
751 |
oldMap = MapFileOpen(root_name, MAP_FILE_NAME, "r");
|
|
|
752 |
if (oldMap != NULL && (!MapFileReadVersion(oldMap, &file_version)
|
|
|
753 |
|| file_version != MAP_FILE_VERSION)) {
|
|
|
754 |
fclose(oldMap);
|
|
|
755 |
oldMap= NULL;
|
|
|
756 |
}
|
|
|
757 |
if (oldMap == NULL) {
|
|
|
758 |
fclose(newMap);
|
|
|
759 |
MapFileUnlink(root_name, TEMP_FILE_NAME);
|
|
|
760 |
return;
|
|
|
761 |
}
|
|
|
762 |
|
|
|
763 |
/* Copy every line of the map file except the one with given name */
|
|
|
764 |
|
|
|
765 |
MapFileWriteVersion(newMap, MAP_FILE_VERSION);
|
|
|
766 |
while (MapFileRead(oldMap, name, &d))
|
|
|
767 |
if (strcmp(name, Fname))
|
|
|
768 |
MapFileWrite(newMap, name, d);
|
|
|
769 |
fclose(newMap);
|
|
|
770 |
fclose(oldMap);
|
|
|
771 |
MapFileUnlink(root_name, MAP_FILE_NAME);
|
|
|
772 |
MapFileRename(root_name, MAP_FILE_NAME, TEMP_FILE_NAME);
|
|
|
773 |
}
|
|
|
774 |
}
|
|
|
775 |
|
|
|
776 |
/*
|
|
|
777 |
* map_file_add
|
|
|
778 |
*
|
|
|
779 |
* adds Fname to the mapping table and does not create an unique new empty file
|
|
|
780 |
* If same Fname exists, new Fname will not be added.
|
|
|
781 |
* root_name char* string of the base path where in disk0 reside (C:\PS\Disk0\)
|
|
|
782 |
* Fname char* name of the entry to add to the map
|
|
|
783 |
*/
|
|
|
784 |
private void
|
|
|
785 |
map_file_name_add(const char * root_name, const char * Fname)
|
|
|
786 |
{
|
|
|
787 |
/*
|
|
|
788 |
* add entry to map file
|
|
|
789 |
* entry number is one greater than biggest number
|
|
|
790 |
*/
|
|
|
791 |
char name[BUFFER_LENGTH];
|
|
|
792 |
int d;
|
|
|
793 |
int dmax = -1;
|
|
|
794 |
int file_version;
|
|
|
795 |
FILE* newMap;
|
|
|
796 |
FILE* oldMap;
|
|
|
797 |
|
|
|
798 |
oldMap = MapFileOpen(root_name, MAP_FILE_NAME, "r");
|
|
|
799 |
if (oldMap != NULL && (!MapFileReadVersion(oldMap, &file_version)
|
|
|
800 |
|| file_version != MAP_FILE_VERSION)) {
|
|
|
801 |
fclose(oldMap);
|
|
|
802 |
oldMap = NULL;
|
|
|
803 |
}
|
|
|
804 |
if (oldMap == NULL) {
|
|
|
805 |
oldMap = MapFileOpen(root_name, MAP_FILE_NAME, "w");
|
|
|
806 |
if (!oldMap)
|
|
|
807 |
return;
|
|
|
808 |
MapFileWriteVersion(oldMap, MAP_FILE_VERSION);
|
|
|
809 |
MapFileWrite(oldMap, Fname, InitialNumber);
|
|
|
810 |
fclose(oldMap);
|
|
|
811 |
}
|
|
|
812 |
else {
|
|
|
813 |
MapFileUnlink(root_name, TEMP_FILE_NAME);
|
|
|
814 |
newMap = MapFileOpen(root_name, TEMP_FILE_NAME, "w");
|
|
|
815 |
if (newMap != NULL) {
|
|
|
816 |
MapFileWriteVersion(newMap, MAP_FILE_VERSION);
|
|
|
817 |
while (MapFileRead(oldMap, name, &d)) {
|
|
|
818 |
MapFileWrite(newMap, name, d);
|
|
|
819 |
if (dmax < d)
|
|
|
820 |
dmax = d;
|
|
|
821 |
}
|
|
|
822 |
|
|
|
823 |
dmax += 1;
|
|
|
824 |
MapFileWrite(newMap, Fname, dmax);
|
|
|
825 |
fclose(newMap);
|
|
|
826 |
fclose(oldMap);
|
|
|
827 |
MapFileUnlink(root_name, MAP_FILE_NAME);
|
|
|
828 |
MapFileRename(root_name, MAP_FILE_NAME, TEMP_FILE_NAME);
|
|
|
829 |
}
|
|
|
830 |
}
|
|
|
831 |
}
|
|
|
832 |
|
|
|
833 |
/*
|
|
|
834 |
* map_file_name_ren
|
|
|
835 |
*
|
|
|
836 |
* renames the oldname into newname in the mapping table. newname must not exist and must be
|
|
|
837 |
* checked by the caller. If same name exist, all same name will be renamed.
|
|
|
838 |
* root_name char* string of the base path where in disk0 reside (C:\PS\Disk0\)
|
|
|
839 |
* oldname char* name currently existing in the map
|
|
|
840 |
* newname char* name to change the entry indicated by oldname into
|
|
|
841 |
*/
|
|
|
842 |
private void
|
|
|
843 |
map_file_name_ren(const char* root_name, const char * oldname, const char * newname)
|
|
|
844 |
{
|
|
|
845 |
/* search for target entry */
|
|
|
846 |
|
|
|
847 |
int d = MapToFile(root_name, oldname);
|
|
|
848 |
int file_version;
|
|
|
849 |
|
|
|
850 |
if (d != -1) { /* if target exists ... */
|
|
|
851 |
char name[BUFFER_LENGTH];
|
|
|
852 |
FILE* newMap;
|
|
|
853 |
FILE* oldMap;
|
|
|
854 |
|
|
|
855 |
/* Open current map file and a working file */
|
|
|
856 |
|
|
|
857 |
MapFileUnlink(root_name, TEMP_FILE_NAME );
|
|
|
858 |
newMap = MapFileOpen(root_name, TEMP_FILE_NAME, "w");
|
|
|
859 |
if (newMap == NULL)
|
|
|
860 |
return;
|
|
|
861 |
oldMap = MapFileOpen(root_name, MAP_FILE_NAME, "r");
|
|
|
862 |
if (oldMap != NULL && (!MapFileReadVersion(oldMap, &file_version)
|
|
|
863 |
|| file_version != MAP_FILE_VERSION)) {
|
|
|
864 |
fclose(oldMap);
|
|
|
865 |
oldMap= NULL;
|
|
|
866 |
}
|
|
|
867 |
if (oldMap == NULL) {
|
|
|
868 |
fclose(newMap);
|
|
|
869 |
MapFileUnlink(root_name, TEMP_FILE_NAME);
|
|
|
870 |
return;
|
|
|
871 |
}
|
|
|
872 |
|
|
|
873 |
/* Now copy data from old to new, change file name when found */
|
|
|
874 |
|
|
|
875 |
MapFileWriteVersion(newMap, MAP_FILE_VERSION); /* Copy the version number */
|
|
|
876 |
while (MapFileRead(oldMap, name, &d))
|
|
|
877 |
if (strcmp(name, oldname))
|
|
|
878 |
MapFileWrite(newMap, name, d);
|
|
|
879 |
else
|
|
|
880 |
MapFileWrite(newMap, newname, d);
|
|
|
881 |
fclose(newMap);
|
|
|
882 |
fclose(oldMap);
|
|
|
883 |
MapFileUnlink(root_name, MAP_FILE_NAME);
|
|
|
884 |
MapFileRename(root_name, MAP_FILE_NAME, TEMP_FILE_NAME);
|
|
|
885 |
}
|
|
|
886 |
}
|