1 /******************************************************************************
2 *
3 * NSSDC/CDF Virtual stream file.
4 *
5 * Version 4.7a, 18-Nov-97, Hughes STX.
6 *
7 * Modification history:
8 *
9 * V1.0 22-Jan-91, J Love Original version (developed for CDF V2.0).
10 * V2.0 12-Mar-91, J Love All fixes to V1.x. Modified vread and vwrite
11 * to buffer only when necessary.
12 * V3.0 14-May-91, J Love Added caching (for CDF V2.1).
13 * V3.1 31-Jul-91, J Love Added veof. Added 'memmove' for UNIX. Added
14 * "deq - default extension quantity" if VMS.
15 * Changed algorithm that looks for bufferN.
16 * Added number of CACHE buffers as a parameter
17 * specified in 'Vopen'. Renamed functions to
18 * avoid collisions on SGi/IRIX.
19 * V3.2 15-Aug-91, J Love Changed for IBM-PC/MS-DOS port.
20 * V4.0 20-May-92, J Love IBM PC port/CDF V2.2.
21 * V4.1 29-Sep-92, J Love CDF V2.3. Dealt with EOFs not at 512-byte
22 * boundaries (when FTPed from a UNIX machine).
23 * V4.2 21-Dec-93, J Love CDF V2.4.
24 * V4.3 12-Dec-94, J Love CDF V2.5.
25 * V4.3a 19-Jan-95, J Love IRIX 6.0 (64-bit).
26 * V4.3b 24-Feb-95, J Love Solaris 2.3 IDL i/f.
27 * V4.4 7-Jun-95, J Love Virtual memory under Microsoft C 7.00.
28 * V4.5 25-Jul-95, J Love More virtual memory under Microsoft C 7.00.
29 * V4.6 29-Sep-95, J Love Improved performance...on non-VMS systems don't
30 * extend files a block at a time, don't clear
31 * bytes (anywhere), etc.
32 * V4.7 26-Aug-96, J Love CDF V2.6.
33 * V4.7a 18-Nov-97, J Love Windows NT/Visual C++.
34 * V4.8 29-Jun-04, M Liu Added LFS (Large File Support > 2G).
35 * V4.9 25-Apr-07, D Berger Changed all instances of hardcoded 512 to
36 * nCACHE_BUFFER_BYTEs.
37 * V4.10 20-Jun-07, D Berger Added initialization of variables to support
38 * READONLYon enhancements.
39 * V4.11 18-Jun-08, M Liu Modified the V_read and V_write to make sure
40 * the actual read/write bytes is within the
41 * buffer size.
42 *
43 ******************************************************************************/
44
45 /******************************************************************************
46 * Include files.
47 ******************************************************************************/
48
49 #include "cdflib.h"
50 #include "cdflib64.h"
51
52 /******************************************************************************
53 * Local macros/typedef's.
54 ******************************************************************************/
55
56 #define CLEAR_BYTES 0
57
58 #if defined(vms) || defined(MPW_C)
59 #define EXTEND_FILE 1
60 #else
61 #define EXTEND_FILE 0
62 #endif
63
64 #define LASTphyBLOCKn(vFp) \
65 BOO(vFp->phyLength == 0,NO_BLOCK,((vFp->phyLength - 1)/nCACHE_BUFFER_BYTEs))
66
67 #if defined(MICROSOFTC_700) && INCLUDEvMEMORY
68 #define CACHEbufferREADfrom(cache) \
69 BOO(useVmem,LoadVMemory((MemHandle)cache->ptr,FALSE),cache->ptr)
70 #define CACHEbufferWRITEto(cache) \
71 BOO(useVmem,LoadVMemory((MemHandle)cache->ptr,TRUE),cache->ptr)
72 #else
73 #define CACHEbufferREADfrom(cache) cache->ptr
74 #define CACHEbufferWRITEto(cache) cache->ptr
75 #endif
76
77 /******************************************************************************
78 * Local function prototypes.
79 ******************************************************************************/
80
81 static FILE *OpenFile PROTOARGs((char *file_spec, char *a_mode));
82 static Logical FreeCache PROTOARGs((vCACHE *firstCache));
83 static vCACHE *FindCache PROTOARGs((vFILE *vFp, long blockN));
84 static Logical vRead PROTOARGs((
85 long offset, void *buffer, size_t nBytes, vFILE *vFp
86 ));
87 static Logical vWrite PROTOARGs((
88 long offset, void *buffer, size_t nBytes, vFILE *vFp
89 ));
90 static vCACHE *AllocateBuffer PROTOARGs((vFILE *vFp));
91 static vCACHE *PageIn PROTOARGs((vFILE *vFp, long blockN));
92 static Logical WriteBlockFromCache PROTOARGs((
93 vFILE *vFp, vCACHE *cache, size_t Nbytes
94 ));
95 static Logical WriteBlockFromBuffer PROTOARGs((
96 vFILE *vFp, long blockN, void *buffer, size_t Nbytes
97 ));
98 #if EXTEND_FILE
99 static Logical ExtendFile PROTOARGs((vFILE *vFp, long toBlockN));
100 #endif
101
102 /******************************************************************************
103 * OpenFile.
104 ******************************************************************************/
105
OpenFile(file_spec,a_mode)106 static FILE *OpenFile (file_spec, a_mode)
107 char *file_spec;
108 char *a_mode;
109 {
110 #if defined(vms)
111 char mrs[10+1]; /* Maximum record size. */
112 char deq[10+1]; /* Default allocation quantity. */
113 sprintf (mrs, "mrs=%d", nCACHE_BUFFER_BYTEs);
114 sprintf (deq, "deq=%d", VMS_DEFAULT_nALLOCATION_BLOCKS);
115 return fopen(file_spec,a_mode,"rfm=fix",mrs,deq);
116 #else
117 return FOPEN(file_spec,a_mode);
118 #endif
119 }
120
121 /******************************************************************************
122 * FindCache.
123 ******************************************************************************/
124
FindCache(vFp,blockN)125 static vCACHE *FindCache (vFp, blockN)
126 vFILE *vFp;
127 long blockN;
128 {
129 vCACHE *cache = vFp->cacheHead;
130 while (cache != NULL) {
131 if (cache->blockN == blockN) {
132 if (cache != vFp->cacheHead) {
133 if (cache == vFp->cacheTail) {
134 cache->prev->next = NULL;
135 vFp->cacheTail = cache->prev;
136 }
137 else {
138 cache->next->prev = cache->prev;
139 cache->prev->next = cache->next;
140 }
141 vFp->cacheHead->prev = cache;
142 cache->next = vFp->cacheHead;
143 vFp->cacheHead = cache;
144 cache->prev = NULL;
145 }
146 return cache;
147 }
148 cache = cache->next;
149 }
150 return NULL;
151 }
152
153 /******************************************************************************
154 * FlushCache.
155 * Write cache buffers to disk from the specified starting buffer to the last
156 * buffer.
157 ******************************************************************************/
158
FlushCache(vFp,firstCache)159 VISIBLE_PREFIX Logical FlushCache (vFp, firstCache)
160 vFILE *vFp; /* Pointer to vFILE structure. */
161 vCACHE *firstCache; /* Pointer to the first cache structure to flush. */
162 {
163 vCACHE *cache; long nBytes;
164 for (cache = firstCache; cache != NULL; cache = cache->next) {
165 if (cache->modified) {
166 #if defined(vms)
167 nBytes = nCACHE_BUFFER_BYTEs;
168 #else
169 nBytes = vFp->length - (cache->blockN * nCACHE_BUFFER_BYTEs);
170 nBytes = MINIMUM (nBytes, nCACHE_BUFFER_BYTEs);
171 #endif
172 if (!WriteBlockFromCache(vFp,cache,(size_t)nBytes)) return FALSE;
173 cache->modified = FALSE;
174 }
175 }
176 return TRUE;
177 }
178
179 /******************************************************************************
180 * FreeCache.
181 ******************************************************************************/
182
FreeCache(firstCache)183 static Logical FreeCache (firstCache)
184 vCACHE *firstCache; /* Pointer to the first cache structure to free. */
185 {
186 vCACHE *cache = firstCache;
187 while (cache != NULL) {
188 vCACHE *nextCache = cache->next;
189 #if defined(MICROSOFTC_700) && INCLUDEvMEMORY
190 if (useVmem)
191 FreeVMemory ((MemHandle) cache->ptr);
192 else
193 #endif
194 cdf_FreeMemory (cache->ptr, NULL);
195 cdf_FreeMemory (cache, NULL);
196 cache = nextCache;
197 }
198 return TRUE;
199 }
200
201 /******************************************************************************
202 * AllocateBuffer.
203 * Allocate a cache structure to use. It may be necessary to page out a block
204 * to the file. Returns a pointer to the allocated cache structure (or NULL if
205 * an error occurred).
206 ******************************************************************************/
207
AllocateBuffer(vFp)208 static vCACHE *AllocateBuffer (vFp)
209 vFILE *vFp;
210 {
211 vCACHE *cache; long nBytes;
212 #if !defined(vms)
213 long offset;
214 #endif
215 /****************************************************************************
216 * Check if a new cache structure can be allocated. If the allocation(s)
217 * fail, process as if the maximum number of cache buffers has already been
218 * reached.
219 ****************************************************************************/
220 if (vFp->nBuffers < vFp->maxBuffers) {
221 cache = (vCACHE *) cdf_AllocateMemory (sizeof(vCACHE), NULL);
222 if (cache != NULL) {
223 #if defined(MICROSOFTC_700) && INCLUDEvMEMORY
224 if (useVmem)
225 cache->ptr = (void *) AllocateVMemory (nCACHE_BUFFER_BYTEs);
226 else
227 #endif
228 cache->ptr = cdf_AllocateMemory (nCACHE_BUFFER_BYTEs, NULL);
229 if (cache->ptr != NULL) {
230 if (vFp->cacheHead == NULL) {
231 vFp->cacheHead = cache;
232 vFp->cacheTail = cache;
233 cache->next = NULL;
234 cache->prev = NULL;
235 }
236 else {
237 vFp->cacheHead->prev = cache;
238 cache->next = vFp->cacheHead;
239 vFp->cacheHead = cache;
240 cache->prev = NULL;
241 }
242 (vFp->nBuffers)++;
243 return cache;
244 }
245 else {
246 cdf_FreeMemory (cache, NULL);
247 if (vFp->nBuffers == 0) return NULL;
248 }
249 }
250 }
251 /****************************************************************************
252 * The maximum number of cache buffers have already been created. Scan the
253 * linked list of cache structures searching for the oldest buffer which has
254 * not been modified. If one is found, it is moved to the head of the linked
255 * list.
256 ****************************************************************************/
257 for (cache = vFp->cacheTail; cache != NULL; cache = cache->prev) {
258 if (!cache->modified) {
259 if (cache != vFp->cacheHead) {
260 if (cache == vFp->cacheTail) {
261 cache->prev->next = NULL;
262 vFp->cacheTail = cache->prev;
263 }
264 else {
265 cache->prev->next = cache->next;
266 cache->next->prev = cache->prev;
267 }
268 vFp->cacheHead->prev = cache;
269 cache->next = vFp->cacheHead;
270 vFp->cacheHead = cache;
271 cache->prev = NULL;
272 }
273 return cache;
274 }
275 }
276 /****************************************************************************
277 * An unmodified buffer was not found. The last buffer on the linked list
278 * will be paged back out to the file and then this cache structure is moved
279 * to the head of the linked list.
280 ****************************************************************************/
281 cache = vFp->cacheTail;
282 #if defined(vms)
283 nBytes = nCACHE_BUFFER_BYTEs;
284 #else
285 offset = nCACHE_BUFFER_BYTEs * cache->blockN;
286 nBytes = vFp->length - offset;
287 nBytes = MINIMUM (nBytes, nCACHE_BUFFER_BYTEs);
288 #endif
289 if (!WriteBlockFromCache(vFp,cache,(size_t)nBytes)) return NULL;
290 if (cache != vFp->cacheHead) {
291 cache->prev->next = NULL;
292 vFp->cacheTail = cache->prev;
293 vFp->cacheHead->prev = cache;
294 cache->next = vFp->cacheHead;
295 vFp->cacheHead = cache;
296 cache->prev = NULL;
297 }
298 (vFp->nPageOuts)++;
299 return cache;
300 }
301
302 /******************************************************************************
303 * ExtendFile.
304 * Extend the file to a specified number of blocks.
305 ******************************************************************************/
306
307 #if EXTEND_FILE
ExtendFile(vFp,toBlockN)308 static Logical ExtendFile (vFp, toBlockN)
309 vFILE *vFp;
310 long toBlockN;
311 {
312 vCACHE *cache; long blockN;
313 /****************************************************************************
314 * First check to see if the physical end-of-file must be extended out to the
315 * next multiple of the cache/block size.
316 ****************************************************************************/
317 if (vFp->phyLength > 0) {
318 long lastPhyBlockN = LASTphyBLOCKn (vFp);
319 long nBytes = vFp->phyLength - (nCACHE_BUFFER_BYTEs * lastPhyBlockN);
320 if (nBytes < nCACHE_BUFFER_BYTEs) {
321 cache = FindCache (vFp, lastPhyBlockN);
322 if (cache != NULL) {
323 void *buffer = CACHEbufferREADfrom (cache);
324 if (buffer == NULL) return FALSE;
325 if (!vWrite(nCACHE_BUFFER_BYTEs * lastPhyBlockN,
326 buffer,nCACHE_BUFFER_BYTEs,vFp)) return FALSE;
327 cache->modified = FALSE;
328 }
329 else {
330 Byte buffer[nCACHE_BUFFER_BYTEs];
331 if (!vRead(nCACHE_BUFFER_BYTEs * lastPhyBlockN,
332 buffer,(size_t)nBytes,vFp)) return FALSE;
333 #if CLEAR_BYTES
334 ClearBytes (buffer, (int) nBytes, nCACHE_BUFFER_BYTEs - 1);
335 #endif
336 if (!vWrite(nCACHE_BUFFER_BYTEs * lastPhyBlockN,
337 buffer,nCACHE_BUFFER_BYTEs,vFp)) return FALSE;
338 }
339 vFp->phyLength = nCACHE_BUFFER_BYTEs * (lastPhyBlockN + 1);
340 }
341 }
342 /****************************************************************************
343 * Then extend the file the remaining blocks.
344 ****************************************************************************/
345 for (blockN = LASTphyBLOCKn(vFp) + 1; blockN <= toBlockN; blockN++) {
346 cache = FindCache (vFp, blockN);
347 if (cache != NULL) {
348 void *buffer = CACHEbufferREADfrom (cache);
349 if (buffer == NULL) return FALSE;
350 if (!vWrite(nCACHE_BUFFER_BYTEs * blockN,
351 buffer,nCACHE_BUFFER_BYTEs,vFp)) return FALSE;
352 cache->modified = FALSE;
353 }
354 else {
355 Byte buffer[nCACHE_BUFFER_BYTEs];
356 #if CLEAR_BYTES
357 ClearBytes (buffer, 0, nCACHE_BUFFER_BYTEs - 1);
358 #endif
359 if (!vWrite(nCACHE_BUFFER_BYTEs * blockN,
360 buffer,nCACHE_BUFFER_BYTEs,vFp)) return FALSE;
361 }
362 vFp->phyLength = nCACHE_BUFFER_BYTEs * (blockN + 1);
363 }
364 return TRUE;
365 }
366 #endif
367
368 /******************************************************************************
369 * PageIn.
370 * Page in a block from the file. Returns pointer to cache structure used (or
371 * NULL if an error occurred).
372 ******************************************************************************/
373
PageIn(vFp,blockN)374 static vCACHE *PageIn (vFp, blockN)
375 vFILE *vFp;
376 long blockN;
377 {
378 long offset, nBytes; vCACHE *cache; void *buffer;
379 cache = AllocateBuffer (vFp);
380 if (cache == NULL) return NULL;
381 offset = blockN * nCACHE_BUFFER_BYTEs;
382 nBytes = vFp->phyLength - offset;
383 nBytes = MINIMUM (nBytes, nCACHE_BUFFER_BYTEs);
384 buffer = CACHEbufferWRITEto (cache);
385 if (buffer == NULL) return NULL;
386 if (!vRead(offset,buffer,(size_t)nBytes,vFp)) return NULL;
387 #if CLEAR_BYTES
388 ClearBytes (buffer, (int) nBytes, nCACHE_BUFFER_BYTEs - 1);
389 #endif
390 cache->blockN = blockN;
391 cache->modified = FALSE;
392 (vFp->nPageIns)++;
393 return cache;
394 }
395
396 /******************************************************************************
397 * WriteBlockFromCache.
398 * Write a block out to the file from a cache buffer. Returns TRUE if
399 * successful, FALSE if an error occurred.
400 ******************************************************************************/
401
WriteBlockFromCache(vFp,cache,nBytes)402 static Logical WriteBlockFromCache (vFp, cache, nBytes)
403 vFILE *vFp;
404 vCACHE *cache;
405 size_t nBytes;
406 {
407 long offset; void *buffer;
408 offset = nCACHE_BUFFER_BYTEs * cache->blockN;
409 #if EXTEND_FILE
410 if (offset > vFp->phyLength) {
411 if (!ExtendFile(vFp,cache->blockN-1)) return FALSE;
412 }
413 #endif
414 buffer = CACHEbufferREADfrom (cache);
415 if (buffer == NULL) return FALSE;
416 if (!vWrite(offset,buffer,nBytes,vFp)) return FALSE;
417 vFp->phyLength = MaxLong (vFp->phyLength, (long) (offset + nBytes));
418 return TRUE;
419 }
420
421 /******************************************************************************
422 * WriteBlockFromBuffer.
423 * Write a block out to the file from the caller's buffer. Returns TRUE if
424 * successful, FALSE if an error occurred.
425 ******************************************************************************/
426
WriteBlockFromBuffer(vFp,blockN,buffer,nBytes)427 static Logical WriteBlockFromBuffer (vFp, blockN, buffer, nBytes)
428 vFILE *vFp;
429 long blockN;
430 void *buffer;
431 size_t nBytes;
432 {
433 long offset = nCACHE_BUFFER_BYTEs * blockN;
434 #if EXTEND_FILE
435 if (offset > vFp->phyLength) {
436 if (!ExtendFile(vFp,blockN-1)) return FALSE;
437 }
438 #endif
439 if (!vWrite(offset,buffer,nBytes,vFp)) return FALSE;
440 vFp->phyLength = MaxLong (vFp->phyLength, (long) (offset + nBytes));
441 return TRUE;
442 }
443
444 /******************************************************************************
445 * vRead.
446 ******************************************************************************/
447
vRead(offset,buffer,nBytes,vFp)448 static Logical vRead (offset, buffer, nBytes, vFp)
449 long offset;
450 void *buffer;
451 size_t nBytes;
452 vFILE *vFp;
453 {
454 int tryN;
455 /****************************************************************************
456 * Does the scratch file exist? It doesn't make sense for it not to.
457 ****************************************************************************/
458 if (vFp->fp == NULL) return FALSE;
459 /****************************************************************************
460 * Tally a block read.
461 ****************************************************************************/
462 (vFp->nBlockReads)++;
463 /****************************************************************************
464 * Read the block. Multiple attempts are made for optical disks.
465 ****************************************************************************/
466 for (tryN = 1; tryN <= vMAX_TRYs; tryN++) {
467 if (fseek(vFp->fp,offset,vSEEK_SET) == EOF) return FALSE;
468 if (fread(buffer,nBytes,1,vFp->fp) == 1) return TRUE;
469 }
470 return FALSE;
471 }
472
473 /******************************************************************************
474 * vWrite.
475 ******************************************************************************/
476
vWrite(offset,buffer,nBytes,vFp)477 static Logical vWrite(offset,buffer,nBytes,vFp)
478 long offset;
479 void *buffer;
480 size_t nBytes;
481 vFILE *vFp;
482 {
483 int tryN;
484 #if defined(__MWERKS__)
485 int ii;
486 #endif
487 /****************************************************************************
488 * Create the scratch file if necessary. If so, the current file path is
489 * actually the scratch directory to be used.
490 ****************************************************************************/
491 if (vFp->fp == NULL) {
492 long i; char *tmpPath; size_t pathLength;
493 pathLength = strlen(vFp->path) + 1 + 8 + 1 + EXT_LEN;
494 tmpPath = (char *) cdf_AllocateMemory (pathLength + 1, NULL);
495 if (tmpPath == NULL) return FALSE;
496 for (i = 1; i <= MAX_TMP; i++) {
497 strcpyX (tmpPath, vFp->path, 0);
498 AppendToDir (tmpPath, "");
499 sprintf (EofS(tmpPath), "TMP%05ld.%s", i, vFp->scratchExt);
500 if (!IsReg(tmpPath)) {
501 FILE *fp = OpenFile (tmpPath, WRITE_PLUS_a_mode);
502 if (fp == NULL) {
503 cdf_FreeMemory (tmpPath, NULL);
504 return FALSE;
505 }
506 cdf_FreeMemory (vFp->path, NULL);
507 vFp->path = tmpPath;
508 vFp->fp = fp;
509 break;
510 }
511 }
512 if (vFp->fp == NULL) { /* Hardly seems likely but we'll check... */
513 cdf_FreeMemory (tmpPath, NULL);
514 return FALSE;
515 }
516 }
517 /****************************************************************************
518 * Tally a block write.
519 ****************************************************************************/
520 (vFp->nBlockWrites)++;
521
522 #if defined(__MWERKS__)
523 ii = fseek(vFp->fp, (long)0, vSEEK_END);
524 #endif
525
526 /****************************************************************************
527 * Write the block. Multiple attempts are made for optical disks.
528 ****************************************************************************/
529 for (tryN = 1; tryN <= vMAX_TRYs; tryN++) {
530 if (fseek(vFp->fp,offset,vSEEK_SET) == EOF) return FALSE;
531 if (fwrite(buffer,nBytes,1,vFp->fp) == 1) return TRUE;
532 }
533 return FALSE;
534 }
535
536 /******************************************************************************
537 * V_open.
538 * Open the file and setup vFILE structure.
539 ******************************************************************************/
540
V_open(file_spec,a_mode)541 VISIBLE_PREFIX vFILE *V_open (file_spec, a_mode)
542 char *file_spec; /* File specification. */
543 char *a_mode; /* Access mode. */
544 {
545 FILE *fp; /* Temporary file pointer. */
546 vFILE *vFp; /* Pointer to vFILE structure. */
547 #if defined(vms)
548 struct STAT st; /* Status block from `stat'. */
549 #endif
550 /****************************************************************************
551 * Open the file.
552 ****************************************************************************/
553 fp = OpenFile (file_spec, a_mode);
554 if (fp == NULL) return NULL;
555 #if defined(vms)
556 /****************************************************************************
557 * If the file is being opened in a mode which may require it to be extended
558 * (`r+' [read/write] or `a/a+' [append]), check that the EOF offset in the
559 * last block is zero (0). If not, rewrite the last block out to the end.
560 * `r' is not checked because it is read only.
561 * `w/w+' is not checked because a new file (with EOF == 0) will have been
562 * created.
563 ****************************************************************************/
564 if (strstr(a_mode,"r+") || strchr(a_mode,'a')) {
565 long eof; size_t EOFoffsetInBlock;
566 if (fseek(fp,0,vSEEK_END) == EOF) {
567 fclose (fp);
568 return NULL;
569 }
570 eof = ftell (fp);
571 if (eof == EOF) {
572 fclose (fp);
573 return NULL;
574 }
575 EOFoffsetInBlock = eof % nCACHE_BUFFER_BYTEs;
576 if (EOFoffsetInBlock != 0) {
577 long offsetToLastBlock; char buffer[nCACHE_BUFFER_BYTEs]; size_t numitems; int i;
578 offsetToLastBlock = nCACHE_BUFFER_BYTEs * (eof / nCACHE_BUFFER_BYTEs);
579 if (fseek(fp,offsetToLastBlock,vSEEK_SET) == EOF) {
580 fclose (fp);
581 return NULL;
582 }
583 for (i = 0; i < nCACHE_BUFFER_BYTEs; i++) buffer[i] = 0;
584 if (fread(buffer,EOFoffsetInBlock,1,fp) != 1) {
585 fclose (fp);
586 return NULL;
587 }
588 if (fseek(fp,offsetToLastBlock,vSEEK_SET) == EOF) {
589 fclose (fp);
590 return NULL;
591 }
592 if (fwrite(buffer,nCACHE_BUFFER_BYTEs,1,fp) != 1) {
593 fclose (fp);
594 return NULL;
595 }
596 if (fclose(fp) == EOF) {
597 fclose (fp);
598 return NULL;
599 }
600 fp = OpenFile (file_spec, a_mode);
601 if (fp == NULL) return NULL;
602 }
603 }
604 #endif
605 /****************************************************************************
606 * Allocate and load vFILE structure.
607 ****************************************************************************/
608 vFp = (vFILE *) cdf_AllocateMemory (sizeof(vFILE), NULL);
609 if (vFp == NULL) {
610 fclose (fp);
611 return NULL;
612 }
613 vFp->magic_number = VSTREAM_MAGIC_NUMBER;
614 vFp->fp = fp;
615 vFp->path = (char *) cdf_AllocateMemory (strlen(file_spec) + 1, NULL);
616 if (vFp->path == NULL) {
617 cdf_FreeMemory (vFp, NULL);
618 fclose (fp);
619 return NULL;
620 }
621 else
622 strcpyX (vFp->path, file_spec, 0);
623 vFp->scratch = FALSE;
624 vFp->error = FALSE;
625 vFp->eof = FALSE;
626 vFp->cacheHead = NULL;
627 vFp->cacheTail = NULL;
628 vFp->maxBuffers = DEFAULT_nCACHE_BUFFERs;
629 vFp->nBuffers = 0;
630 vFp->nBlockReads = 0;
631 vFp->nBlockWrites = 0;
632 vFp->nV_reads = 0;
633 vFp->nV_writes = 0;
634 vFp->nPageIns = 0;
635 vFp->nPageOuts = 0;
636 vFp->GDR = NULL;
637 vFp->GDR64 = NULL;
638 vFp->ADRList = NULL;
639 vFp->ADRList64 = NULL;
640 /****************************************************************************
641 * Determine length of file and set current offset.
642 ****************************************************************************/
643 #if defined(vms)
644 /****************************************************************************
645 * This method is used on VMS systems in case the file is on a CD-ROM. Some
646 * VMS CD-ROM drivers do not correctly handle the EOF marker of a file.
647 * `stat' might fail, however, if the file specification contains a DECnet
648 * node. If `stat' fails, try the other method before giving up.
649 ****************************************************************************/
650 if (stat(file_spec,&st) == 0) {
651 vFp->length = st.st_size;
652 vFp->phyLength = st.st_size;
653 }
654 else {
655 #endif
656 if (fseek(vFp->fp,0,vSEEK_END) == EOF) {
657 cdf_FreeMemory (vFp->path, NULL);
658 cdf_FreeMemory (vFp, NULL);
659 fclose (vFp->fp);
660 return NULL;
661 }
662 vFp->length = ftell (vFp->fp);
663 if (vFp->length == EOF) {
664 cdf_FreeMemory (vFp->path, NULL);
665 cdf_FreeMemory (vFp, NULL);
666 fclose (vFp->fp);
667 return NULL;
668 }
669 vFp->phyLength = vFp->length;
670 #if defined(vms)
671 }
672 #endif
673 vFp->offset = BOO(strchr(a_mode,'a') == NULL,0,vFp->length);
674 /****************************************************************************
675 * Return pointer to vFILE structure.
676 ****************************************************************************/
677 return vFp;
678 }
679
680 /******************************************************************************
681 * V_scratch.
682 * Creates a scratch file. Note that the file is not actually created until a
683 * block needs to be paged out.
684 ******************************************************************************/
685
V_scratch(directory,extension)686 VISIBLE_PREFIX vFILE *V_scratch (directory, extension)
687 char *directory; /* Directory in which to create the scratch file (if
688 necessary). If NULL, use the current directory. */
689 char *extension; /* Extension to use for the scratch file. If NULL,
690 `.ich' is used. */
691 {
692 vFILE *vFp; /* Pointer to vFILE structure. */
693 /****************************************************************************
694 * Allocate and load vFILE structure.
695 ****************************************************************************/
696 vFp = (vFILE *) cdf_AllocateMemory (sizeof(vFILE), NULL);
697 if (vFp == NULL) return NULL;
698 vFp->magic_number = VSTREAM_MAGIC_NUMBER;
699 vFp->fp = NULL;
700 vFp->fh = 0;
701 vFp->path = (char *) cdf_AllocateMemory (BOO(directory == NULL,
702 0,strlen(directory)) + 1, NULL);
703 if (vFp->path == NULL) {
704 cdf_FreeMemory (vFp, NULL);
705 return NULL;
706 }
707 else
708 strcpyX (vFp->path, BOO(directory == NULL,"",directory), 0);
709 strcpyX (vFp->scratchExt, BOO(extension == NULL,"ich",extension), EXT_LEN);
710 vFp->scratch = TRUE;
711 vFp->error = FALSE;
712 vFp->eof = FALSE;
713 vFp->cacheHead = NULL;
714 vFp->cacheTail = NULL;
715 vFp->maxBuffers = DEFAULT_nCACHE_BUFFERs;
716 vFp->nBuffers = 0;
717 vFp->nBlockReads = 0;
718 vFp->nBlockWrites = 0;
719 vFp->nV_reads = 0;
720 vFp->nV_writes = 0;
721 vFp->nPageIns = 0;
722 vFp->nPageOuts = 0;
723 vFp->length = 0;
724 vFp->length64 = (OFF_T) 0;
725 vFp->phyLength = 0;
726 vFp->phyLength64 = (OFF_T) 0;
727 vFp->offset = 0;
728 vFp->offset64 = (OFF_T) 0;
729 vFp->GDR = NULL;
730 vFp->GDR64 = NULL;
731 vFp->ADRList = NULL;
732 vFp->ADRList64 = NULL;
733
734 /****************************************************************************
735 * Return pointer to vFILE structure.
736 ****************************************************************************/
737 return vFp;
738 }
739
740 /******************************************************************************
741 * V_setcache.
742 * Set number of cache buffers. This can be done at any time after the file
743 * is opened. Note that in some cases the new cache size may be the same as
744 * the old cache size (do nothing).
745 ******************************************************************************/
746
V_setcache(vFp,maxBuffers)747 VISIBLE_PREFIX int V_setcache (vFp, maxBuffers)
748 vFILE *vFp; /* Pointer to vFILE structure. */
749 int maxBuffers; /* New maximum number of cache buffers. */
750 {
751 if (vFp == NULL) return EOF;
752 if (vFp->magic_number != VSTREAM_MAGIC_NUMBER) return EOF;
753 if (vFp->error) return EOF;
754 if (maxBuffers < 1) return EOF;
755 if (maxBuffers > vFp->maxBuffers) {
756 /**************************************************************************
757 * The number of cache buffers is increasing.
758 **************************************************************************/
759 vFp->maxBuffers = maxBuffers;
760 }
761 else {
762 if (maxBuffers < vFp->maxBuffers) {
763 /************************************************************************
764 * The number of cache buffers is decreasing - flush to disk and free
765 * the buffers which are going away.
766 ************************************************************************/
767 vCACHE *cache; int count;
768 if (vFp->nBuffers > maxBuffers) {
769 for (count = 1,
770 cache = vFp->cacheHead;
771 count < maxBuffers; count++) cache = cache->next;
772 if (!FlushCache(vFp,cache->next)) {
773 vFp->error = TRUE;
774 return EOF;
775 }
776 FreeCache (cache->next);
777 cache->next = NULL;
778 vFp->cacheTail = cache;
779 vFp->nBuffers = maxBuffers;
780 }
781 vFp->maxBuffers = maxBuffers;
782 }
783 }
784 return 0;
785 }
786
787 /******************************************************************************
788 * V_seek.
789 * Seek to a position in the file.
790 ******************************************************************************/
791
V_seek(vFp,offset,direction)792 VISIBLE_PREFIX int V_seek (vFp, offset, direction)
793 vFILE *vFp; /* Pointer to vFILE structure. */
794 long offset; /* New current file offset. */
795 int direction; /* Reference for offset. */
796 {
797 if (vFp == NULL) return EOF;
798 if (vFp->magic_number != VSTREAM_MAGIC_NUMBER) return EOF;
799 if (vFp->error) return EOF;
800 vFp->eof = FALSE; /* Cleared before proceeding. */
801 switch (direction) {
802 case vSEEK_SET:
803 if (offset < 0) return EOF;
804 vFp->offset = offset;
805 break;
806 case vSEEK_CUR:
807 if (vFp->offset + offset < 0) return EOF;
808 vFp->offset += offset;
809 break;
810 case vSEEK_END:
811 vFp->offset = vFp->length;
812 break;
813 default:
814 return EOF;
815 }
816 return 0;
817 }
818
819 /******************************************************************************
820 * V_tell.
821 * Return current offset (position) in file. This is the byte offset one past
822 * the last byte that exists.
823 ******************************************************************************/
824
V_tell(vFp)825 VISIBLE_PREFIX long V_tell (vFp)
826 vFILE *vFp; /* Pointer to vFILE structure. */
827 {
828 if (vFp == NULL) return EOF;
829 if (vFp->magic_number != VSTREAM_MAGIC_NUMBER) return EOF;
830 if (vFp->error) return EOF;
831 return vFp->offset;
832 }
833
834 /******************************************************************************
835 * V_eof.
836 * Returns non-zero if EOF indicator is set. A read at the EOF must occur
837 * before the EOF indicator will be set (just like `feof').
838 ******************************************************************************/
839
V_eof(vFp)840 VISIBLE_PREFIX int V_eof (vFp)
841 vFILE *vFp; /* Pointer to vFILE structure. */
842 {
843 if (vFp == NULL) return EOF;
844 if (vFp->magic_number != VSTREAM_MAGIC_NUMBER) return EOF;
845 if (vFp->eof) return 1;
846 return 0;
847 }
848
849 /******************************************************************************
850 * V_error.
851 * Returns non-zero if error indicator is set.
852 ******************************************************************************/
853
V_error(vFp)854 VISIBLE_PREFIX int V_error (vFp)
855 vFILE *vFp; /* Pointer to vFILE structure. */
856 {
857 if (vFp == NULL) return EOF;
858 if (vFp->magic_number != VSTREAM_MAGIC_NUMBER) return EOF;
859 if (vFp->error) return 1;
860 return 0;
861 }
862
863 /******************************************************************************
864 * V_read.
865 ******************************************************************************/
866
V_read(buffer,item_size,n_items,vFp)867 VISIBLE_PREFIX size_t V_read (buffer, item_size, n_items, vFp)
868 void *buffer; /* Pointer to buffer. */
869 size_t item_size; /* Size (in bytes) of each item to read. */
870 size_t n_items; /* Number of items to read. */
871 vFILE *vFp; /* Pointer to vFILE structure. */
872 {
873 size_t nBytesX; /* Total number of bytes in buffer. */
874 size_t nBytes; /* Total number of bytes to read. */
875 long remainingItems; /* Number of items remaining after the offset. */
876 size_t nItems; /* Number of items to actually be read. */
877 long firstBlockN; /* First block involved in read. */
878 long lastBlockN; /* Last block involved in read. */
879 int bufferOffset; /* Offset (bytes) into buffer. */
880 long fileOffset; /* Offset (bytes) into file. */
881 size_t xBytes; /* Number of bytes in a transfer. */
882 long blockN; /* Block number in file (from 0). */
883 long atBlockN; /* Block number in file (from 0) at which to read. */
884 vCACHE *cache; /* Pointer to cache structure. */
885 Byte *cBuffer; /* Pointer to cache buffer. */
886 int remainingBytes; /* Number of bytes remaining in a block. */
887 /****************************************************************************
888 * Validate read.
889 ****************************************************************************/
890 #if defined(DEBUG)
891 if (getenv("READ.ERROR") != NULL) return 0;
892 #endif
893 if (vFp == NULL) return 0;
894 if (vFp->magic_number != VSTREAM_MAGIC_NUMBER) return 0;
895 if (vFp->error) return 0;
896 if ((int) item_size <= 0 || (int) n_items <= 0) return 0;
897 remainingItems = (vFp->length - vFp->offset) / ((long) item_size);
898 if (remainingItems < 1) {
899 vFp->eof = TRUE;
900 vFp->offset = vFp->length;
901 return 0;
902 }
903 if ((long) n_items > remainingItems) {
904 nItems = (size_t) remainingItems;
905 vFp->eof = TRUE; /* File offset set to EOF before returning. */
906 }
907 else
908 nItems = n_items;
909 nBytes = nItems * item_size;
910 nBytesX = n_items * item_size;
911 (vFp->nV_reads)++;
912 /****************************************************************************
913 * Read from first block...
914 ****************************************************************************/
915 firstBlockN = vFp->offset / nCACHE_BUFFER_BYTEs;
916 bufferOffset = (int) (vFp->offset % nCACHE_BUFFER_BYTEs);
917 remainingBytes = nCACHE_BUFFER_BYTEs - bufferOffset;
918 xBytes = MINIMUM (nBytes, (size_t) remainingBytes);
919 if (xBytes > nBytesX) return 0;
920 if (bufferOffset > 0 || xBytes < nCACHE_BUFFER_BYTEs) {
921 cache = FindCache (vFp, firstBlockN);
922 if (cache == NULL) cache = PageIn (vFp, firstBlockN);
923 if (cache == NULL) {
924 vFp->error = TRUE;
925 return 0;
926 }
927 cBuffer = CACHEbufferREADfrom (cache);
928 if (cBuffer == NULL) {
929 vFp->error = TRUE;
930 return 0;
931 }
932 memmove (buffer, cBuffer + bufferOffset, xBytes);
933 buffer = (Byte *) buffer + xBytes;
934 atBlockN = firstBlockN + 1;
935 }
936 else
937 atBlockN = firstBlockN;
938 /****************************************************************************
939 * Read from remaining blocks...
940 ****************************************************************************/
941 lastBlockN = (vFp->offset + nBytes - 1) / nCACHE_BUFFER_BYTEs;
942 for (blockN = atBlockN; blockN <= lastBlockN; blockN++) {
943 xBytes = (size_t) (vFp->offset + nBytes - (nCACHE_BUFFER_BYTEs * blockN));
944 xBytes = MINIMUM (xBytes, nCACHE_BUFFER_BYTEs);
945 if (xBytes > nBytesX) return 0;
946 cache = FindCache (vFp, blockN);
947 if (cache != NULL) {
948 cBuffer = CACHEbufferREADfrom (cache);
949 if (cBuffer == NULL) {
950 vFp->error = TRUE;
951 return 0;
952 }
953 memmove (buffer, cBuffer, xBytes);
954 }
955 else {
956 if (xBytes < nCACHE_BUFFER_BYTEs) {
957 cache = PageIn (vFp, blockN);
958 if (cache == NULL) {
959 vFp->error = TRUE;
960 return 0;
961 }
962 cBuffer = CACHEbufferREADfrom (cache);
963 if (cBuffer == NULL) {
964 vFp->error = TRUE;
965 return 0;
966 }
967 memmove (buffer, cBuffer, xBytes);
968 }
969 else {
970 fileOffset = nCACHE_BUFFER_BYTEs * blockN;
971 if (!vRead(fileOffset,buffer,nCACHE_BUFFER_BYTEs,vFp)) {
972 vFp->error = TRUE;
973 return 0;
974 }
975 }
976 }
977 buffer = (Byte *) buffer + xBytes;
978 }
979 /****************************************************************************
980 * Increment current file offset or set to EOF if the EOF indicator was set.
981 ****************************************************************************/
982 vFp->offset = BOO(vFp->eof,vFp->length,vFp->offset + nBytes);
983 return nItems;
984 }
985
986 /******************************************************************************
987 * V_write.
988 ******************************************************************************/
989
V_write(buffer,item_size,n_items,vFp)990 VISIBLE_PREFIX size_t V_write (buffer, item_size, n_items, vFp)
991 void *buffer; /* Pointer to buffer. */
992 size_t item_size; /* Size (in bytes) of each item to write. */
993 size_t n_items; /* Number of items to write. */
994 vFILE *vFp; /* Pointer to vFILE structure. */
995 {
996 size_t nBytesX; /* Total number of bytes in buffer. */
997 size_t nBytes; /* Total number of bytes in write. */
998 long firstBlockN; /* First block involved in write. */
999 long lastBlockN; /* Last block involved in write. */
1000 int bufferOffset; /* Offset (bytes) into buffer. */
1001 long blockN; /* Block number in file (from 0). */
1002 long atBlockN; /* Block number in file (from 0) at which to write. */
1003 size_t xBytes; /* Number of bytes in a transfer. */
1004 vCACHE *cache; /* Pointer to cache structure. */
1005 Byte *cBuffer; /* Pointer to cache buffer. */
1006 size_t nBytesInBlock; /* Number of bytes to the end of the block. */
1007 /****************************************************************************
1008 * Validate write.
1009 ****************************************************************************/
1010 #if defined(DEBUG)
1011 if (getenv("WRITE.ERROR") != NULL) return 0;
1012 #endif
1013 if (vFp == NULL) return 0;
1014 if (vFp->magic_number != VSTREAM_MAGIC_NUMBER) return 0;
1015 if (vFp->error) return 0;
1016 if ((int) item_size <= 0 || (int) n_items <= 0) return 0;
1017 vFp->eof = FALSE; /* Cleared before proceeding. */
1018 nBytes = item_size * n_items;
1019 nBytesX = n_items * item_size;
1020 if (nBytes < 1) return 0;
1021 (vFp->nV_writes)++;
1022 /****************************************************************************
1023 * Write to first block...
1024 * Note that if this is a scratch file, the first block is always placed in
1025 * the cache (even if a full block).
1026 ****************************************************************************/
1027 firstBlockN = vFp->offset / nCACHE_BUFFER_BYTEs;
1028 bufferOffset = (int) (vFp->offset % nCACHE_BUFFER_BYTEs);
1029 nBytesInBlock = nCACHE_BUFFER_BYTEs - bufferOffset;
1030 xBytes = MINIMUM (nBytes, nBytesInBlock);
1031 if (xBytes > nBytesX) return 0;
1032 if (vFp->scratch || bufferOffset > 0 || xBytes < nCACHE_BUFFER_BYTEs) {
1033 cache = FindCache (vFp, firstBlockN);
1034 if (cache == NULL) {
1035 if (firstBlockN <= LASTphyBLOCKn(vFp)) {
1036 cache = PageIn (vFp, firstBlockN);
1037 if (cache == NULL) {
1038 vFp->error = TRUE;
1039 return 0;
1040 }
1041 }
1042 else {
1043 cache = AllocateBuffer (vFp);
1044 if (cache == NULL) {
1045 vFp->error = TRUE;
1046 return 0;
1047 }
1048 cache->blockN = firstBlockN;
1049 #if CLEAR_BYTES
1050 cBuffer = CACHEbufferWRITEto (cache);
1051 if (cBuffer == NULL) {
1052 vFp->error = TRUE;
1053 return 0;
1054 }
1055 ClearBytes (cBuffer, 0, bufferOffset - 1);
1056 ClearBytes (cBuffer, (int) (bufferOffset + xBytes),
1057 nCACHE_BUFFER_BYTEs - 1);
1058 #endif
1059 }
1060 }
1061 cBuffer = CACHEbufferWRITEto (cache);
1062 if (cBuffer == NULL) {
1063 vFp->error = TRUE;
1064 return 0;
1065 }
1066 memmove (cBuffer + bufferOffset, buffer, xBytes);
1067 cache->modified = TRUE;
1068 vFp->length = MaxLong (vFp->length,(long) (vFp->offset + xBytes));
1069 buffer = (Byte *) buffer + xBytes;
1070 atBlockN = firstBlockN + 1;
1071 }
1072 else
1073 atBlockN = firstBlockN;
1074 /****************************************************************************
1075 * Write to remaining blocks...
1076 ****************************************************************************/
1077 lastBlockN = (vFp->offset + nBytes - 1) / nCACHE_BUFFER_BYTEs;
1078 for (blockN = atBlockN; blockN <= lastBlockN; blockN++) {
1079 xBytes = (size_t) (vFp->offset + nBytes - (nCACHE_BUFFER_BYTEs * blockN));
1080 xBytes = MINIMUM (xBytes, nCACHE_BUFFER_BYTEs);
1081 if (xBytes > nBytesX) return 0;
1082 /*************************************************************************
1083 * Is this block in the cache? If so, move the number of bytes to be
1084 * written at this block to its cache buffer.
1085 *************************************************************************/
1086 cache = FindCache (vFp, blockN);
1087 if (cache != NULL) {
1088 cBuffer = CACHEbufferWRITEto (cache);
1089 if (cBuffer == NULL) {
1090 vFp->error = TRUE;
1091 return 0;
1092 }
1093 memmove (cBuffer, buffer, xBytes);
1094 cache->modified = TRUE;
1095 }
1096 else {
1097 /***********************************************************************
1098 * This block is not in the cache. Is a partial block to be written?
1099 * Note that if this is a scratch file, the block is always placed in
1100 * the cache (even if not a partial block).
1101 ***********************************************************************/
1102 if (vFp->scratch || xBytes < nCACHE_BUFFER_BYTEs) {
1103 if (blockN <= LASTphyBLOCKn(vFp)) {
1104 cache = PageIn (vFp, blockN);
1105 if (cache == NULL) {
1106 vFp->error = TRUE;
1107 return 0;
1108 }
1109 }
1110 else {
1111 cache = AllocateBuffer (vFp);
1112 if (cache == NULL) {
1113 vFp->error = TRUE;
1114 return 0;
1115 }
1116 cache->blockN = blockN;
1117 #if CLEAR_BYTES
1118 cBuffer = CACHEbufferWRITEto (cache);
1119 if (cBuffer == NULL) {
1120 vFp->error = TRUE;
1121 return 0;
1122 }
1123 ClearBytes (cBuffer, (int) xBytes, nCACHE_BUFFER_BYTEs - 1);
1124 #endif
1125 }
1126 cBuffer = CACHEbufferWRITEto (cache);
1127 if (cBuffer == NULL) {
1128 vFp->error = TRUE;
1129 return 0;
1130 }
1131 memmove (cBuffer, buffer, xBytes);
1132 cache->modified = TRUE;
1133 }
1134 else {
1135 /*********************************************************************
1136 * A full block is to be written.
1137 *********************************************************************/
1138 if (!WriteBlockFromBuffer(vFp,blockN,buffer,nCACHE_BUFFER_BYTEs)) {
1139 vFp->error = TRUE;
1140 return 0;
1141 }
1142 }
1143 }
1144 vFp->length = MaxLong (vFp->length,
1145 (long) ((nCACHE_BUFFER_BYTEs * blockN) + xBytes));
1146 buffer = (Byte *) buffer + xBytes;
1147 }
1148 /****************************************************************************
1149 * Increment current file offset.
1150 ****************************************************************************/
1151 vFp->offset += nBytes;
1152 return n_items;
1153 }
1154
1155 /******************************************************************************
1156 * V_getc.
1157 ******************************************************************************/
1158
V_getc(fp)1159 VISIBLE_PREFIX int V_getc (fp)
1160 vFILE *fp;
1161 {
1162 uByte tmp;
1163 if (V_read(&tmp,1,1,fp) != 1) return EOF;
1164 return ((int) tmp);
1165 }
1166
1167 /******************************************************************************
1168 * V_putc.
1169 ******************************************************************************/
1170
V_putc(value,fp)1171 VISIBLE_PREFIX int V_putc (value, fp)
1172 int value;
1173 vFILE *fp;
1174 {
1175 uByte tmp = (uByte) value;
1176 if (V_write(&tmp,1,1,fp) != 1) return EOF;
1177 return value;
1178 }
1179
1180 /******************************************************************************
1181 * V_clear.
1182 * Marks all cache buffers as unmodified. This is used with scratch files to
1183 * prevent blocks of unwanted data from being paged out to disk.
1184 ******************************************************************************/
1185
V_clear(vFp)1186 VISIBLE_PREFIX int V_clear (vFp)
1187 vFILE *vFp; /* Pointer to vFILE structure. */
1188 {
1189 vCACHE *cache;
1190 if (vFp == NULL) return EOF;
1191 if (vFp->magic_number != VSTREAM_MAGIC_NUMBER) return EOF;
1192 if (vFp->error) return EOF;
1193 for (cache = vFp->cacheHead; cache != NULL; cache = cache->next) {
1194 cache->modified = FALSE;
1195 }
1196 return 0;
1197 }
1198
1199 /******************************************************************************
1200 * V_flush.
1201 * Flush the file to disk.
1202 ******************************************************************************/
1203
V_flush(vFp)1204 VISIBLE_PREFIX int V_flush (vFp)
1205 vFILE *vFp; /* Pointer to vFILE structure. */
1206 {
1207 /****************************************************************************
1208 * Validate.
1209 ****************************************************************************/
1210 if (vFp == NULL) return EOF;
1211 if (vFp->magic_number != VSTREAM_MAGIC_NUMBER) return EOF;
1212 if (vFp->error) return EOF;
1213 /****************************************************************************
1214 * Flush cache buffers. If this is a scratch file, this will cause the file
1215 * to be created if it hasn't been already (unless nothing has been written).
1216 ****************************************************************************/
1217 if (!FlushCache(vFp,vFp->cacheHead)) {
1218 vFp->error = TRUE;
1219 return EOF;
1220 }
1221 /****************************************************************************
1222 * Flush file. Note that the file will not be flushed if this is a scratch
1223 * file to which nothing has been written.
1224 ****************************************************************************/
1225 if (vFp->fp != NULL) {
1226 if (fflush(vFp->fp) == EOF) {
1227 vFp->error = TRUE;
1228 return EOF;
1229 }
1230 }
1231 /****************************************************************************
1232 * Return success.
1233 ****************************************************************************/
1234 return 0;
1235 }
1236
1237 /******************************************************************************
1238 * V_close.
1239 * Returns EOF if an error occurred.
1240 ******************************************************************************/
1241
V_close(vFp,CDF,vStats)1242 VISIBLE_PREFIX int V_close (vFp, CDF, vStats)
1243 vFILE *vFp; /* Pointer to vFILE structure. */
1244 struct CDFstruct *CDF; /* Indicator whether to perform check sum operation. */
1245 vSTATS *vStats; /* Pointer to statistics structure. */
1246 {
1247 Logical error = FALSE; /* Has an error occurred? */
1248 /****************************************************************************
1249 * Check if a valid pointer to a vFILE structure.
1250 ****************************************************************************/
1251 if (vFp == NULL) return EOF;
1252 if (vFp->magic_number != VSTREAM_MAGIC_NUMBER) return EOF;
1253 /****************************************************************************
1254 * Write cache buffers. If this is a scratch file, this will cause the file
1255 * to be created if it hasn't been already (unless nothing has been written).
1256 ****************************************************************************/
1257 if (!FlushCache(vFp,vFp->cacheHead)) error = TRUE;
1258 /****************************************************************************
1259 * Close the file. Note that the file will not be closed if this is a
1260 * scratch file to which nothing has been written.
1261 ****************************************************************************/
1262 if (vFp->fp != NULL) {
1263 if (CDF != NULL && (!CDF->readOnly || CDF->status == READ_WRITE) &&
1264 CDF->singleFile && (CDF->checksum != NONE_CHECKSUM)) {
1265 /* if (!FLUSHv(vFp)) error = TRUE; */
1266 if (!CDFAddChecksum(CDF)) error = TRUE;
1267 }
1268 if (fclose(vFp->fp) == EOF) error = TRUE;
1269 }
1270 /****************************************************************************
1271 * Pass back statistics (if requested).
1272 ****************************************************************************/
1273 if (vStats != NULL) {
1274 vStats->maxBuffers = vFp->maxBuffers;
1275 vStats->nBuffers = vFp->nBuffers;
1276 vStats->nV_reads = vFp->nV_reads;
1277 vStats->nV_writes = vFp->nV_writes;
1278 vStats->nBlockReads = vFp->nBlockReads;
1279 vStats->nBlockWrites = vFp->nBlockWrites;
1280 vStats->nPageIns = vFp->nPageIns;
1281 vStats->nPageOuts = vFp->nPageOuts;
1282 }
1283 /****************************************************************************
1284 * Deallocate cache and vFILE structure.
1285 ****************************************************************************/
1286 FreeCache (vFp->cacheHead);
1287 cdf_FreeMemory (vFp->path, NULL);
1288 cdf_FreeMemory (vFp, NULL);
1289 /****************************************************************************
1290 * Return status.
1291 ****************************************************************************/
1292 return BOO(error,EOF,0);
1293 }
1294
1295 /******************************************************************************
1296 * V_delete.
1297 * Returns EOF if an error occurred.
1298 ******************************************************************************/
1299
V_delete(vFp,vStats)1300 VISIBLE_PREFIX int V_delete (vFp, vStats)
1301 vFILE *vFp; /* Pointer to vFILE structure. */
1302 vSTATS *vStats; /* Pointer to statistics structure. */
1303 {
1304 Logical error = FALSE; /* Has an error occurred? */
1305 /****************************************************************************
1306 * Check if a valid pointer to a vFILE structure.
1307 ****************************************************************************/
1308 if (vFp == NULL) return EOF;
1309 if (vFp->magic_number != VSTREAM_MAGIC_NUMBER) return EOF;
1310 /****************************************************************************
1311 * Close the file.
1312 ****************************************************************************/
1313 if (vFp->fp != NULL) {
1314 if (fclose(vFp->fp) == EOF) error = TRUE;
1315 }
1316 /****************************************************************************
1317 * Delete the file (unless it was never created).
1318 ****************************************************************************/
1319 if (vFp->fp != NULL) {
1320 if (!DeleteFile(vFp->path)) error = TRUE;
1321 }
1322 /****************************************************************************
1323 * Pass back statistics (if requested).
1324 ****************************************************************************/
1325 if (vStats != NULL) {
1326 vStats->maxBuffers = vFp->maxBuffers;
1327 vStats->nBuffers = vFp->nBuffers;
1328 vStats->nV_reads = vFp->nV_reads;
1329 vStats->nV_writes = vFp->nV_writes;
1330 vStats->nBlockReads = vFp->nBlockReads;
1331 vStats->nBlockWrites = vFp->nBlockWrites;
1332 vStats->nPageIns = vFp->nPageIns;
1333 vStats->nPageOuts = vFp->nPageOuts;
1334 }
1335 /****************************************************************************
1336 * Deallocate cache and vFILE structure.
1337 ****************************************************************************/
1338 FreeCache (vFp->cacheHead);
1339 cdf_FreeMemory (vFp->path, NULL);
1340 cdf_FreeMemory (vFp, NULL);
1341 /****************************************************************************
1342 * Return status.
1343 ****************************************************************************/
1344 return BOO(error,EOF,0);
1345 }
1346