diff options
-rw-r--r-- | gs/base/gp.h | 18 | ||||
-rw-r--r-- | gs/base/gp_macio.c | 28 | ||||
-rw-r--r-- | gs/base/gp_mswin.c | 100 | ||||
-rw-r--r-- | gs/base/gp_os2fs.c | 28 | ||||
-rw-r--r-- | gs/base/gp_unifs.c | 40 | ||||
-rw-r--r-- | gs/base/gp_vms.c | 28 | ||||
-rw-r--r-- | gs/base/gxclfile.c | 297 |
7 files changed, 465 insertions, 74 deletions
diff --git a/gs/base/gp.h b/gs/base/gp.h index 829a782fd..1cdf34754 100644 --- a/gs/base/gp.h +++ b/gs/base/gp.h | |||
@@ -232,6 +232,24 @@ FILE *gp_open_scratch_file(const gs_memory_t *mem, | |||
232 | /* Open a file with the given name, as a stream of uninterpreted bytes. */ | 232 | /* Open a file with the given name, as a stream of uninterpreted bytes. */ |
233 | FILE *gp_fopen(const char *fname, const char *mode); | 233 | FILE *gp_fopen(const char *fname, const char *mode); |
234 | 234 | ||
235 | /* Test whether this platform supports the sharing of file descriptors */ | ||
236 | int gp_can_share_fdesc(void); | ||
237 | |||
238 | /* Create a self-deleting scratch file */ | ||
239 | FILE *gp_open_scratch_file_rm(const gs_memory_t *mem, | ||
240 | const char *prefix, | ||
241 | char fname[gp_file_name_sizeof], | ||
242 | const char *mode); | ||
243 | |||
244 | /* Create a second open FILE on the basis of a given one */ | ||
245 | FILE *gp_fdup(FILE *f, const char *mode); | ||
246 | |||
247 | /* Read from a specified offset within a FILE into a buffer */ | ||
248 | int gp_fpread(char *buf, uint count, int64_t offset, FILE *f); | ||
249 | |||
250 | /* Write to a specified offset within a FILE from a buffer */ | ||
251 | int gp_fpwrite(char *buf, uint count, int64_t offset, FILE *f); | ||
252 | |||
235 | /* Force given file into binary mode (no eol translations, etc) */ | 253 | /* Force given file into binary mode (no eol translations, etc) */ |
236 | /* if 2nd param true, text mode if 2nd param false */ | 254 | /* if 2nd param true, text mode if 2nd param false */ |
237 | int gp_setmode_binary(FILE * pfile, bool mode); | 255 | int gp_setmode_binary(FILE * pfile, bool mode); |
diff --git a/gs/base/gp_macio.c b/gs/base/gp_macio.c index c5190d561..8452312f0 100644 --- a/gs/base/gp_macio.c +++ b/gs/base/gp_macio.c | |||
@@ -549,6 +549,34 @@ gp_fopen (const char * fname, const char * mode) { | |||
549 | 549 | ||
550 | } | 550 | } |
551 | 551 | ||
552 | int gp_can_share_fdesc(void) | ||
553 | { | ||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | FILE *gp_open_scratch_file_rm(const gs_memory_t *mem, | ||
558 | const char *prefix, | ||
559 | char fname[gp_file_name_sizeof], | ||
560 | const char *mode) | ||
561 | { | ||
562 | return NULL; | ||
563 | } | ||
564 | |||
565 | FILE *gp_fdup(FILE *f, const char *mode) | ||
566 | { | ||
567 | return NULL; | ||
568 | } | ||
569 | |||
570 | int gp_fpread(char *buf, uint count, int64_t offset, FILE *f) | ||
571 | { | ||
572 | return -1; | ||
573 | } | ||
574 | |||
575 | int gp_fpwrite(char *buf, uint count, int64_t offset, FILE *f) | ||
576 | { | ||
577 | return -1; | ||
578 | } | ||
579 | |||
552 | FILE * | 580 | FILE * |
553 | popen (const char * fname, const char * mode ) { | 581 | popen (const char * fname, const char * mode ) { |
554 | return gp_fopen (fname, mode); | 582 | return gp_fopen (fname, mode); |
diff --git a/gs/base/gp_mswin.c b/gs/base/gp_mswin.c index b7f5a8166..d4e33af9b 100644 --- a/gs/base/gp_mswin.c +++ b/gs/base/gp_mswin.c | |||
@@ -612,11 +612,12 @@ FILE *mswin_popen(const char *cmd, const char *mode) | |||
612 | 612 | ||
613 | /* Create and open a scratch file with a given name prefix. */ | 613 | /* Create and open a scratch file with a given name prefix. */ |
614 | /* Write the actual file name at fname. */ | 614 | /* Write the actual file name at fname. */ |
615 | FILE * | 615 | static FILE * |
616 | gp_open_scratch_file(const gs_memory_t *mem, | 616 | gp_open_scratch_file_generic(const gs_memory_t *mem, |
617 | const char *prefix, | 617 | const char *prefix, |
618 | char *fname, | 618 | char *fname, |
619 | const char *mode) | 619 | const char *mode, |
620 | int remove) | ||
620 | { | 621 | { |
621 | UINT n; | 622 | UINT n; |
622 | DWORD l; | 623 | DWORD l; |
@@ -721,26 +722,19 @@ gp_open_scratch_file(const gs_memory_t *mem, | |||
721 | hfile = CreateFile2(uni, | 722 | hfile = CreateFile2(uni, |
722 | GENERIC_READ | GENERIC_WRITE | DELETE, | 723 | GENERIC_READ | GENERIC_WRITE | DELETE, |
723 | FILE_SHARE_READ | FILE_SHARE_WRITE, | 724 | FILE_SHARE_READ | FILE_SHARE_WRITE, |
724 | CREATE_ALWAYS, | 725 | CREATE_ALWAYS | (remove ? FILE_FLAG_DELETE_ON_CLOSE : 0), |
725 | NULL); | 726 | NULL); |
726 | #else | 727 | #else |
727 | hfile = CreateFileW(uni, | 728 | hfile = CreateFileW(uni, |
728 | GENERIC_READ | GENERIC_WRITE | DELETE, | 729 | GENERIC_READ | GENERIC_WRITE | DELETE, |
729 | FILE_SHARE_READ | FILE_SHARE_WRITE, | 730 | FILE_SHARE_READ | FILE_SHARE_WRITE, |
730 | NULL, CREATE_ALWAYS, | 731 | NULL, CREATE_ALWAYS, |
731 | FILE_ATTRIBUTE_NORMAL /* | FILE_FLAG_DELETE_ON_CLOSE */, | 732 | FILE_ATTRIBUTE_NORMAL | (remove ? FILE_FLAG_DELETE_ON_CLOSE : 0), |
732 | NULL); | 733 | NULL); |
733 | #endif | 734 | #endif |
734 | free(uni); | 735 | free(uni); |
735 | } | 736 | } |
736 | #endif | 737 | #endif |
737 | /* | ||
738 | * Can't apply FILE_FLAG_DELETE_ON_CLOSE due to | ||
739 | * the logics of clist_fclose. Also note that | ||
740 | * gdev_prn_render_pages requires multiple temporary files | ||
741 | * to exist simultaneousely, so that keeping all them opened | ||
742 | * may exceed available CRTL file handles. | ||
743 | */ | ||
744 | } | 738 | } |
745 | } | 739 | } |
746 | if (hfile != INVALID_HANDLE_VALUE) { | 740 | if (hfile != INVALID_HANDLE_VALUE) { |
@@ -769,6 +763,24 @@ gp_open_scratch_file(const gs_memory_t *mem, | |||
769 | return f; | 763 | return f; |
770 | } | 764 | } |
771 | 765 | ||
766 | FILE * | ||
767 | gp_open_scratch_file(const gs_memory_t *mem, | ||
768 | const char *prefix, | ||
769 | char *fname, | ||
770 | const char *mode) | ||
771 | { | ||
772 | return gp_open_scratch_file_generic(mem, prefix, fname, mode, 0); | ||
773 | } | ||
774 | |||
775 | FILE * | ||
776 | gp_open_scratch_file_rm(const gs_memory_t *mem, | ||
777 | const char *prefix, | ||
778 | char *fname, | ||
779 | const char *mode) | ||
780 | { | ||
781 | return gp_open_scratch_file_generic(mem, prefix, fname, mode, 1); | ||
782 | } | ||
783 | |||
772 | /* Open a file with the given name, as a stream of uninterpreted bytes. */ | 784 | /* Open a file with the given name, as a stream of uninterpreted bytes. */ |
773 | FILE * | 785 | FILE * |
774 | gp_fopen(const char *fname, const char *mode) | 786 | gp_fopen(const char *fname, const char *mode) |
@@ -794,6 +806,66 @@ gp_fopen(const char *fname, const char *mode) | |||
794 | #endif | 806 | #endif |
795 | } | 807 | } |
796 | 808 | ||
809 | /* test whether gp_fdup is supported on this platform */ | ||
810 | int gp_can_share_fdesc(void) | ||
811 | { | ||
812 | return 1; | ||
813 | } | ||
814 | |||
815 | /* Create a second open FILE on the basis of a given one */ | ||
816 | FILE *gp_fdup(FILE *f, const char *mode) | ||
817 | { | ||
818 | int fd = fileno(f); | ||
819 | if (fd < 0) | ||
820 | return NULL; | ||
821 | |||
822 | fd = dup(fd); | ||
823 | if (fd < 0) | ||
824 | return NULL; | ||
825 | |||
826 | return fdopen(fd, mode); | ||
827 | } | ||
828 | |||
829 | /* Read from a specified offset within a FILE into a buffer */ | ||
830 | int gp_fpread(char *buf, uint count, int64_t offset, FILE *f) | ||
831 | { | ||
832 | OVERLAPPED overlapped; | ||
833 | DWORD ret; | ||
834 | HANDLE hnd = _get_osfhandle(fileno(f)); | ||
835 | |||
836 | if (hnd == INVALID_HANDLE_VALUE) | ||
837 | return -1; | ||
838 | |||
839 | memset(&overlapped, 0, sizeof(OVERLAPPED)); | ||
840 | overlapped.Offset = (DWORD)offset; | ||
841 | overlapped.OffsetHigh = (DWORD)(offset >> 32); | ||
842 | |||
843 | if (!ReadFile((HANDLE)hnd, buf, count, &ret, &overlapped)) | ||
844 | return -1; | ||
845 | |||
846 | return ret; | ||
847 | } | ||
848 | |||
849 | /* Write to a specified offset within a FILE from a buffer */ | ||
850 | int gp_fpwrite(char *buf, uint count, int64_t offset, FILE *f) | ||
851 | { | ||
852 | OVERLAPPED overlapped; | ||
853 | DWORD ret; | ||
854 | HANDLE hnd = _get_osfhandle(fileno(f)); | ||
855 | |||
856 | if (hnd == INVALID_HANDLE_VALUE) | ||
857 | return -1; | ||
858 | |||
859 | memset(&overlapped, 0, sizeof(OVERLAPPED)); | ||
860 | overlapped.Offset = (DWORD)offset; | ||
861 | overlapped.OffsetHigh = (DWORD)(offset >> 32); | ||
862 | |||
863 | if (!WriteFile((HANDLE)hnd, buf, count, &ret, &overlapped)) | ||
864 | return -1; | ||
865 | |||
866 | return ret; | ||
867 | } | ||
868 | |||
797 | /* ------ Font enumeration ------ */ | 869 | /* ------ Font enumeration ------ */ |
798 | 870 | ||
799 | /* This is used to query the native os for a list of font names and | 871 | /* This is used to query the native os for a list of font names and |
diff --git a/gs/base/gp_os2fs.c b/gs/base/gp_os2fs.c index 1de5a3336..fd033bcc2 100644 --- a/gs/base/gp_os2fs.c +++ b/gs/base/gp_os2fs.c | |||
@@ -262,6 +262,34 @@ gp_fopen(const char *fname, const char *mode) | |||
262 | return fopen(fname, mode); | 262 | return fopen(fname, mode); |
263 | } | 263 | } |
264 | 264 | ||
265 | int gp_can_share_fdesc(void) | ||
266 | { | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | FILE *gp_open_scratch_file_rm(const gs_memory_t *mem, | ||
271 | const char *prefix, | ||
272 | char fname[gp_file_name_sizeof], | ||
273 | const char *mode) | ||
274 | { | ||
275 | return NULL; | ||
276 | } | ||
277 | |||
278 | FILE *gp_fdup(FILE *f, const char *mode) | ||
279 | { | ||
280 | return NULL; | ||
281 | } | ||
282 | |||
283 | int gp_fpread(char *buf, uint count, int64_t offset, FILE *f) | ||
284 | { | ||
285 | return -1; | ||
286 | } | ||
287 | |||
288 | int gp_fpwrite(char *buf, uint count, int64_t offset, FILE *f) | ||
289 | { | ||
290 | return -1; | ||
291 | } | ||
292 | |||
265 | /* -------------- Helpers for gp_file_name_combine_generic ------------- */ | 293 | /* -------------- Helpers for gp_file_name_combine_generic ------------- */ |
266 | 294 | ||
267 | uint gp_file_name_root(const char *fname, uint len) | 295 | uint gp_file_name_root(const char *fname, uint len) |
diff --git a/gs/base/gp_unifs.c b/gs/base/gp_unifs.c index f44b3d2bc..59fc86c3d 100644 --- a/gs/base/gp_unifs.c +++ b/gs/base/gp_unifs.c | |||
@@ -151,6 +151,46 @@ gp_fopen(const char *fname, const char *mode) | |||
151 | return fopen(fname, mode); | 151 | return fopen(fname, mode); |
152 | } | 152 | } |
153 | 153 | ||
154 | int gp_can_share_fdesc(void) | ||
155 | { | ||
156 | return 1; | ||
157 | } | ||
158 | |||
159 | FILE *gp_open_scratch_file_rm(const gs_memory_t *mem, | ||
160 | const char *prefix, | ||
161 | char fname[gp_file_name_sizeof], | ||
162 | const char *mode) | ||
163 | { | ||
164 | FILE *f = gp_open_scratch_file_generic(mem, prefix, fname, mode, false); | ||
165 | /* Unlink file immediately to avoid it being left around if the program | ||
166 | * is killed. On this platform readers access temp files by cloning the | ||
167 | * FILE pointer and without accessing the file by name */ | ||
168 | if (f) | ||
169 | unlink(fname); | ||
170 | return f; | ||
171 | } | ||
172 | |||
173 | FILE *gp_fdup(FILE *f, const char *mode) | ||
174 | { | ||
175 | int fd = fileno(f); | ||
176 | if (fd < 0) | ||
177 | return NULL; | ||
178 | fd = dup(fd); | ||
179 | if (fd < 0) | ||
180 | return NULL; | ||
181 | return fdopen(fd, mode); | ||
182 | } | ||
183 | |||
184 | int gp_fpread(char *buf, uint count, int64_t offset, FILE *f) | ||
185 | { | ||
186 | return pread(fileno(f), buf, count, offset); | ||
187 | } | ||
188 | |||
189 | int gp_fpwrite(char *buf, uint count, int64_t offset, FILE *f) | ||
190 | { | ||
191 | return pwrite(fileno(f), buf, count, offset); | ||
192 | } | ||
193 | |||
154 | /* Set a file into binary or text mode. */ | 194 | /* Set a file into binary or text mode. */ |
155 | int | 195 | int |
156 | gp_setmode_binary(FILE * pfile, bool mode) | 196 | gp_setmode_binary(FILE * pfile, bool mode) |
diff --git a/gs/base/gp_vms.c b/gs/base/gp_vms.c index 689f4ca88..f3b5f6f31 100644 --- a/gs/base/gp_vms.c +++ b/gs/base/gp_vms.c | |||
@@ -287,6 +287,34 @@ gp_fopen(const char *fname, const char *mode) | |||
287 | return fopen(fname, mode); | 287 | return fopen(fname, mode); |
288 | } | 288 | } |
289 | 289 | ||
290 | int gp_can_share_fdesc(void) | ||
291 | { | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | FILE *gp_open_scratch_file_rm(const gs_memory_t *mem, | ||
296 | const char *prefix, | ||
297 | char fname[gp_file_name_sizeof], | ||
298 | const char *mode) | ||
299 | { | ||
300 | return NULL; | ||
301 | } | ||
302 | |||
303 | FILE *gp_fdup(FILE *f, const char *mode) | ||
304 | { | ||
305 | return NULL; | ||
306 | } | ||
307 | |||
308 | int gp_fpread(char *buf, uint count, int64_t offset, FILE *f) | ||
309 | { | ||
310 | return -1; | ||
311 | } | ||
312 | |||
313 | int gp_fpwrite(char *buf, uint count, int64_t offset, FILE *f) | ||
314 | { | ||
315 | return -1; | ||
316 | } | ||
317 | |||
290 | /* Set a file into binary or text mode. */ | 318 | /* Set a file into binary or text mode. */ |
291 | int | 319 | int |
292 | gp_setmode_binary(FILE * pfile, bool binary) | 320 | gp_setmode_binary(FILE * pfile, bool binary) |
diff --git a/gs/base/gxclfile.c b/gs/base/gxclfile.c index 2ca35b60d..18ab29d45 100644 --- a/gs/base/gxclfile.c +++ b/gs/base/gxclfile.c | |||
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | 16 | ||
17 | /* File-based command list implementation */ | 17 | /* File-based command list implementation */ |
18 | #include "assert.h" | ||
18 | #include "stdio_.h" | 19 | #include "stdio_.h" |
19 | #include "string_.h" | 20 | #include "string_.h" |
20 | #include "unistd_.h" | 21 | #include "unistd_.h" |
@@ -32,38 +33,149 @@ | |||
32 | 33 | ||
33 | /* ------ Open/close/unlink ------ */ | 34 | /* ------ Open/close/unlink ------ */ |
34 | 35 | ||
36 | #define ENC_FILE_STR ("encoded_file_ptr_%p") | ||
37 | #define ENC_FILE_STRX ("encoded_file_ptr_0x%p") | ||
38 | |||
39 | static void | ||
40 | file_to_fake_path(clist_file_ptr file, char fname[gp_file_name_sizeof]) | ||
41 | { | ||
42 | gs_sprintf(fname, ENC_FILE_STR, file); | ||
43 | } | ||
44 | |||
45 | static clist_file_ptr | ||
46 | fake_path_to_file(const char *fname) | ||
47 | { | ||
48 | clist_file_ptr i1, i2; | ||
49 | |||
50 | int r1 = sscanf(fname, ENC_FILE_STR, &i1); | ||
51 | int r2 = sscanf(fname, ENC_FILE_STRX, &i2); | ||
52 | return r2 == 1 ? i2 : (r1 == 1 ? i1 : NULL); | ||
53 | } | ||
54 | |||
55 | /* Use our own FILE structure so that, on some platforms, we write and read | ||
56 | * tmp files via a single file descriptor. That allows cleaning of tmp files | ||
57 | * to be addressed via DELETE_ON_CLOSE under Windows, and immediate unlink | ||
58 | * after opening under Linux. When running in this mode, we keep our own | ||
59 | * record of position within the file for the sake of thread safety | ||
60 | */ | ||
61 | typedef struct | ||
62 | { | ||
63 | gs_memory_t *mem; | ||
64 | FILE *f; | ||
65 | int64_t pos; | ||
66 | } IFILE; | ||
67 | |||
68 | static IFILE *wrap_file(gs_memory_t *mem, FILE *f) | ||
69 | { | ||
70 | IFILE *ifile; | ||
71 | |||
72 | if (!f) return NULL; | ||
73 | ifile = (IFILE *)gs_alloc_bytes(mem->non_gc_memory, sizeof(*ifile), "Allocate wrapped IFILE"); | ||
74 | if (!ifile) | ||
75 | { | ||
76 | fclose(f); | ||
77 | return NULL; | ||
78 | } | ||
79 | ifile->mem = mem->non_gc_memory; | ||
80 | ifile->f = f; | ||
81 | ifile->pos = 0; | ||
82 | return ifile; | ||
83 | } | ||
84 | |||
85 | int close_file(IFILE *ifile) | ||
86 | { | ||
87 | int res = 0; | ||
88 | if (ifile) | ||
89 | { | ||
90 | res = fclose(ifile->f); | ||
91 | gs_free_object(ifile->mem, ifile, "Free wrapped IFILE"); | ||
92 | } | ||
93 | return res; | ||
94 | } | ||
95 | |||
35 | static int | 96 | static int |
36 | clist_fopen(char fname[gp_file_name_sizeof], const char *fmode, | 97 | clist_fopen(char fname[gp_file_name_sizeof], const char *fmode, |
37 | clist_file_ptr * pcf, gs_memory_t * mem, gs_memory_t *data_mem, | 98 | clist_file_ptr * pcf, gs_memory_t * mem, gs_memory_t *data_mem, |
38 | bool ok_to_compress) | 99 | bool ok_to_compress) |
39 | { | 100 | { |
40 | if (*fname == 0) { | 101 | if (*fname == 0) |
102 | { | ||
41 | if (fmode[0] == 'r') | 103 | if (fmode[0] == 'r') |
42 | return_error(gs_error_invalidfileaccess); | 104 | return_error(gs_error_invalidfileaccess); |
43 | *pcf = (clist_file_ptr)gp_open_scratch_file_64(mem, | 105 | if (gp_can_share_fdesc()) |
44 | gp_scratch_file_name_prefix, | 106 | { |
45 | fname, fmode); | 107 | *pcf = (clist_file_ptr)wrap_file(mem, gp_open_scratch_file_rm(mem, |
46 | } else | 108 | gp_scratch_file_name_prefix, |
47 | *pcf = gp_fopen(fname, fmode); | 109 | fname, fmode)); |
48 | if (*pcf == NULL) { | 110 | /* If the platform supports FILE duplication then we overwrite the |
111 | * file name with an encoded form of the FILE pointer */ | ||
112 | file_to_fake_path(*pcf, fname); | ||
113 | } | ||
114 | else | ||
115 | { | ||
116 | *pcf = (clist_file_ptr)wrap_file(mem, gp_open_scratch_file_64(mem, | ||
117 | gp_scratch_file_name_prefix, | ||
118 | fname, fmode)); | ||
119 | } | ||
120 | } | ||
121 | else | ||
122 | { | ||
123 | // Check if a special path is passed in. If so, clone the FILE handle | ||
124 | clist_file_ptr ocf = fake_path_to_file(fname); | ||
125 | if (ocf) | ||
126 | { | ||
127 | *pcf = wrap_file(mem, gp_fdup(((IFILE *)ocf)->f, fmode)); | ||
128 | } | ||
129 | else | ||
130 | { | ||
131 | *pcf = wrap_file(mem, gp_fopen(fname, fmode)); | ||
132 | } | ||
133 | } | ||
134 | |||
135 | if (*pcf == NULL) | ||
136 | { | ||
49 | emprintf1(mem, "Could not open the scratch file %s.\n", fname); | 137 | emprintf1(mem, "Could not open the scratch file %s.\n", fname); |
50 | return_error(gs_error_invalidfileaccess); | 138 | return_error(gs_error_invalidfileaccess); |
51 | } | 139 | } |
140 | |||
52 | return 0; | 141 | return 0; |
53 | } | 142 | } |
54 | 143 | ||
55 | static int | 144 | static int |
56 | clist_unlink(const char *fname) | 145 | clist_unlink(const char *fname) |
57 | { | 146 | { |
58 | return (unlink(fname) != 0 ? gs_note_error(gs_error_ioerror) : 0); | 147 | clist_file_ptr ocf = fake_path_to_file(fname); |
148 | if (ocf) | ||
149 | { | ||
150 | /* fname is an encoded file pointer. The file will either have been | ||
151 | * created with the delete-on-close option, or already have been | ||
152 | * unlinked. We need only close the FILE */ | ||
153 | return close_file((IFILE *)ocf) != 0 ? gs_note_error(gs_error_ioerror) : 0; | ||
154 | } | ||
155 | else | ||
156 | { | ||
157 | return (unlink(fname) != 0 ? gs_note_error(gs_error_ioerror) : 0); | ||
158 | } | ||
59 | } | 159 | } |
60 | 160 | ||
61 | static int | 161 | static int |
62 | clist_fclose(clist_file_ptr cf, const char *fname, bool delete) | 162 | clist_fclose(clist_file_ptr cf, const char *fname, bool delete) |
63 | { | 163 | { |
64 | return (fclose((FILE *) cf) != 0 ? gs_note_error(gs_error_ioerror) : | 164 | clist_file_ptr ocf = fake_path_to_file(fname); |
65 | delete ? clist_unlink(fname) : | 165 | if (ocf == cf) |
66 | 0); | 166 | { |
167 | /* fname is an encoded file pointer, and cf is the FILE used to create it. | ||
168 | * We shouldn't close it unless we have been asked to delete it, in which | ||
169 | * case closing it will delete it */ | ||
170 | if (delete) | ||
171 | close_file((IFILE *)ocf); | ||
172 | } | ||
173 | else | ||
174 | { | ||
175 | return (close_file((IFILE *) cf) != 0 ? gs_note_error(gs_error_ioerror) : | ||
176 | delete ? clist_unlink(fname) : | ||
177 | 0); | ||
178 | } | ||
67 | } | 179 | } |
68 | 180 | ||
69 | /* ------ Writing ------ */ | 181 | /* ------ Writing ------ */ |
@@ -71,7 +183,16 @@ clist_fclose(clist_file_ptr cf, const char *fname, bool delete) | |||
71 | static int | 183 | static int |
72 | clist_fwrite_chars(const void *data, uint len, clist_file_ptr cf) | 184 | clist_fwrite_chars(const void *data, uint len, clist_file_ptr cf) |
73 | { | 185 | { |
74 | return fwrite(data, 1, len, (FILE *) cf); | 186 | if (gp_can_share_fdesc()) |
187 | { | ||
188 | int res = gp_fpwrite(data, len, ((IFILE *)cf)->pos, ((IFILE *)cf)->f); | ||
189 | if (res >= 0) | ||
190 | ((IFILE *)cf)->pos += len; return res; | ||
191 | } | ||
192 | else | ||
193 | { | ||
194 | return fwrite(data, 1, len, ((IFILE *)cf)->f); | ||
195 | } | ||
75 | } | 196 | } |
76 | 197 | ||
77 | /* ------ Reading ------ */ | 198 | /* ------ Reading ------ */ |
@@ -79,33 +200,45 @@ clist_fwrite_chars(const void *data, uint len, clist_file_ptr cf) | |||
79 | static int | 200 | static int |
80 | clist_fread_chars(void *data, uint len, clist_file_ptr cf) | 201 | clist_fread_chars(void *data, uint len, clist_file_ptr cf) |
81 | { | 202 | { |
82 | FILE *f = (FILE *) cf; | 203 | if (gp_can_share_fdesc()) |
83 | byte *str = data; | 204 | { |
84 | 205 | int res = gp_fpread(data, len, ((IFILE *)cf)->pos, ((IFILE *)cf)->f); | |
85 | /* The typical implementation of fread */ | 206 | if (res >= 0) |
86 | /* is extremely inefficient for small counts, */ | 207 | ((IFILE *)cf)->pos += res; |
87 | /* so we just use straight-line code instead. */ | 208 | |
88 | switch (len) { | 209 | return res; |
89 | default: | 210 | } |
90 | return fread(str, 1, len, f); | 211 | else |
91 | case 8: | 212 | { |
92 | *str++ = (byte) getc(f); | 213 | FILE *f = ((IFILE *)cf)->f; |
93 | case 7: | 214 | byte *str = data; |
94 | *str++ = (byte) getc(f); | 215 | |
95 | case 6: | 216 | /* The typical implementation of fread */ |
96 | *str++ = (byte) getc(f); | 217 | /* is extremely inefficient for small counts, */ |
97 | case 5: | 218 | /* so we just use straight-line code instead. */ |
98 | *str++ = (byte) getc(f); | 219 | switch (len) { |
99 | case 4: | 220 | default: |
100 | *str++ = (byte) getc(f); | 221 | return fread(str, 1, len, f); |
101 | case 3: | 222 | case 8: |
102 | *str++ = (byte) getc(f); | 223 | *str++ = (byte) getc(f); |
103 | case 2: | 224 | case 7: |
104 | *str++ = (byte) getc(f); | 225 | *str++ = (byte) getc(f); |
105 | case 1: | 226 | case 6: |
106 | *str = (byte) getc(f); | 227 | *str++ = (byte) getc(f); |
107 | } | 228 | case 5: |
108 | return len; | 229 | *str++ = (byte) getc(f); |
230 | case 4: | ||
231 | *str++ = (byte) getc(f); | ||
232 | case 3: | ||
233 | *str++ = (byte) getc(f); | ||
234 | case 2: | ||
235 | *str++ = (byte) getc(f); | ||
236 | case 1: | ||
237 | *str = (byte) getc(f); | ||
238 | } | ||
239 | |||
240 | return len; | ||
241 | } | ||
109 | } | 242 | } |
110 | 243 | ||
111 | /* ------ Position/status ------ */ | 244 | /* ------ Position/status ------ */ |
@@ -119,43 +252,87 @@ clist_set_memory_warning(clist_file_ptr cf, int bytes_left) | |||
119 | static int | 252 | static int |
120 | clist_ferror_code(clist_file_ptr cf) | 253 | clist_ferror_code(clist_file_ptr cf) |
121 | { | 254 | { |
122 | return (ferror((FILE *) cf) ? gs_error_ioerror : 0); | 255 | return (ferror(((IFILE *)cf)->f) ? gs_error_ioerror : 0); |
123 | } | 256 | } |
124 | 257 | ||
125 | static int64_t | 258 | static int64_t |
126 | clist_ftell(clist_file_ptr cf) | 259 | clist_ftell(clist_file_ptr cf) |
127 | { | 260 | { |
128 | return gp_ftell_64((FILE *) cf); | 261 | IFILE *ifile = (IFILE *)cf; |
262 | |||
263 | return gp_can_share_fdesc() ? ifile->pos : ftell(ifile->f); | ||
129 | } | 264 | } |
130 | 265 | ||
131 | static void | 266 | static void |
132 | clist_rewind(clist_file_ptr cf, bool discard_data, const char *fname) | 267 | clist_rewind(clist_file_ptr cf, bool discard_data, const char *fname) |
133 | { | 268 | { |
134 | FILE *f = (FILE *) cf; | 269 | FILE *f = ((IFILE *)cf)->f; |
135 | 270 | IFILE *ocf = fake_path_to_file(fname); | |
136 | if (discard_data) { | 271 | char fmode[4]; |
137 | /* | 272 | |
138 | * The ANSI C stdio specification provides no operation for | 273 | strcpy(fmode, "w+"); |
139 | * truncating a file at a given position, or even just for | 274 | strcat(fmode, gp_fmode_binary_suffix); |
140 | * deleting its contents; we have to use a bizarre workaround to | 275 | |
141 | * get the same effect. | 276 | if (ocf) |
142 | */ | 277 | { |
143 | char fmode[4]; | 278 | if (discard_data) |
144 | 279 | { | |
145 | /* Opening with "w" mode deletes the contents when closing. */ | 280 | /* fname is an encoded ifile pointer. We can use an entirely |
146 | (void)freopen(fname, gp_fmode_wb, f); | 281 | * new scratch file. */ |
147 | strcpy(fmode, "w+"); | 282 | char tfname[gp_file_name_sizeof]; |
148 | strcat(fmode, gp_fmode_binary_suffix); | 283 | fclose(ocf->f); |
149 | (void)freopen(fname, fmode, f); | 284 | ocf->f = gp_open_scratch_file_rm(NULL, gp_scratch_file_name_prefix, tfname, fmode); |
150 | } else { | 285 | } |
151 | rewind(f); | 286 | else |
287 | { | ||
288 | ((IFILE *)cf)->pos = 0; | ||
289 | } | ||
290 | } | ||
291 | else | ||
292 | { | ||
293 | if (discard_data) { | ||
294 | /* | ||
295 | * The ANSI C stdio specification provides no operation for | ||
296 | * truncating a file at a given position, or even just for | ||
297 | * deleting its contents; we have to use a bizarre workaround to | ||
298 | * get the same effect. | ||
299 | */ | ||
300 | |||
301 | /* Opening with "w" mode deletes the contents when closing. */ | ||
302 | (void)freopen(fname, gp_fmode_wb, f); | ||
303 | (void)freopen(fname, fmode, f); | ||
304 | } else { | ||
305 | rewind(f); | ||
306 | } | ||
152 | } | 307 | } |
153 | } | 308 | } |
154 | 309 | ||
155 | static int | 310 | static int |
156 | clist_fseek(clist_file_ptr cf, int64_t offset, int mode, const char *ignore_fname) | 311 | clist_fseek(clist_file_ptr cf, int64_t offset, int mode, const char *ignore_fname) |
157 | { | 312 | { |
158 | return gp_fseek_64((FILE *) cf, offset, mode); | 313 | IFILE *ifile = (IFILE *)cf; |
314 | |||
315 | if (gp_can_share_fdesc()) | ||
316 | { | ||
317 | switch (mode) | ||
318 | { | ||
319 | case SEEK_SET: | ||
320 | ifile->pos = offset; | ||
321 | break; | ||
322 | case SEEK_CUR: | ||
323 | ifile->pos += offset; | ||
324 | break; | ||
325 | case SEEK_END: | ||
326 | gp_fseek_64(ifile->f, 0, SEEK_END); | ||
327 | ifile->pos = ftell(ifile->f); | ||
328 | break; | ||
329 | } | ||
330 | return 0; | ||
331 | } | ||
332 | else | ||
333 | { | ||
334 | return gp_fseek_64(ifile->f, offset, mode); | ||
335 | } | ||
159 | } | 336 | } |
160 | 337 | ||
161 | static clist_io_procs_t clist_io_procs_file = { | 338 | static clist_io_procs_t clist_io_procs_file = { |