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) 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
}