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
iodev_diskn_init(gx_io_device * iodev,gs_memory_t * mem)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
iodev_diskn_fopen(gx_io_device * iodev,const char * fname,const char * access,FILE ** pfile,char * rfname,uint rnamelen)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
diskn_delete(gx_io_device * iodev,const char * fname)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
diskn_rename(gx_io_device * iodev,const char * from,const char * to)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
diskn_status(gx_io_device * iodev,const char * fname,struct stat * pstat)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 *
diskn_enumerate_files_init(gx_io_device * iodev,const char * pat,uint patlen,gs_memory_t * mem)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
diskn_enumerate_close(file_enum * pfen)301 diskn_enumerate_close(file_enum *pfen)
302 {
303 map_file_enum_close((void *)pfen);
304 }
305
306 private uint
diskn_enumerate_next(file_enum * pfen,char * ptr,uint maxlen)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
diskn_get_params(gx_io_device * iodev,gs_param_list * plist)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
diskn_put_params(gx_io_device * iodev,gs_param_list * plist)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 *
MapFileOpen(const char * rootpath,const char * filename,const char * attributes)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
MapFileReadVersion(FILE * mapfile,int * value)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
MapFileWriteVersion(FILE * mapfile,int value)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
MapFileRead(FILE * mapfile,char * namebuf,int * value)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
MapFileWrite(FILE * mapfile,const char * namebuf,int value)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
MapFileUnlink(const char * rootpath,const char * filename)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
MapFileRename(const char * rootpath,const char * newfilename,const char * oldfilename)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
MapToFile(const char * rootpath,const char * name)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 *
map_file_enum_init(gs_memory_t * mem,const char * root_name,const char * search_pattern)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
map_file_enum_next(void * enum_mem,char * target)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
map_file_enum_close(void * enum_mem)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
map_file_name_get(const char * root_name,const char * Fname,char * osname)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
map_file_name_del(const char * root_name,const char * Fname)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
map_file_name_add(const char * root_name,const char * Fname)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
map_file_name_ren(const char * root_name,const char * oldname,const char * newname)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 }
887