1 : /**********************************************************************
2 : * $Id: cpl_vsil_unix_stdio_64.cpp 24270 2012-04-20 22:00:31Z rouault $
3 : *
4 : * Project: CPL - Common Portability Library
5 : * Purpose: Implement VSI large file api for Unix platforms with fseek64()
6 : * and ftell64() such as IRIX.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : **********************************************************************
10 : * Copyright (c) 2001, Frank Warmerdam
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************
30 : *
31 : * NB: Note that in wrappers we are always saving the error state (errno
32 : * variable) to avoid side effects during debug prints or other possible
33 : * standard function calls (error states will be overwritten after such
34 : * a call).
35 : *
36 : ****************************************************************************/
37 :
38 : #define VSI_COUNT_BYTES_READ
39 :
40 : #include "cpl_port.h"
41 :
42 : #if !defined(WIN32) && !defined(WIN32CE)
43 :
44 : #include "cpl_vsi_virtual.h"
45 : #include "cpl_string.h"
46 : #include "cpl_multiproc.h"
47 :
48 : #include <unistd.h>
49 : #include <sys/stat.h>
50 : #include <sys/types.h>
51 : #include <dirent.h>
52 : #include <errno.h>
53 :
54 : CPL_CVSID("$Id: cpl_vsil_unix_stdio_64.cpp 24270 2012-04-20 22:00:31Z rouault $");
55 :
56 : #if defined(UNIX_STDIO_64)
57 :
58 : #ifndef VSI_FTELL64
59 : #define VSI_FTELL64 ftell64
60 : #endif
61 : #ifndef VSI_FSEEK64
62 : #define VSI_FSEEK64 fseek64
63 : #endif
64 : #ifndef VSI_FOPEN64
65 : #define VSI_FOPEN64 fopen64
66 : #endif
67 : #ifndef VSI_STAT64
68 : #define VSI_STAT64 stat64
69 : #endif
70 : #ifndef VSI_STAT64_T
71 : #define VSI_STAT64_T stat64
72 : #endif
73 : #ifndef VSI_FTRUNCATE64
74 : #define VSI_FTRUNCATE64 ftruncate64
75 : #endif
76 :
77 : #else /* not UNIX_STDIO_64 */
78 :
79 : #ifndef VSI_FTELL64
80 : #define VSI_FTELL64 ftell
81 : #endif
82 : #ifndef VSI_FSEEK64
83 : #define VSI_FSEEK64 fseek
84 : #endif
85 : #ifndef VSI_FOPEN64
86 : #define VSI_FOPEN64 fopen
87 : #endif
88 : #ifndef VSI_STAT64
89 : #define VSI_STAT64 stat
90 : #endif
91 : #ifndef VSI_STAT64_T
92 : #define VSI_STAT64_T stat
93 : #endif
94 : #ifndef VSI_FTRUNCATE64
95 : #define VSI_FTRUNCATE64 ftruncate
96 : #endif
97 :
98 : #endif /* ndef UNIX_STDIO_64 */
99 :
100 : /************************************************************************/
101 : /* ==================================================================== */
102 : /* VSIUnixStdioFilesystemHandler */
103 : /* ==================================================================== */
104 : /************************************************************************/
105 :
106 : class VSIUnixStdioFilesystemHandler : public VSIFilesystemHandler
107 : {
108 : #ifdef VSI_COUNT_BYTES_READ
109 : vsi_l_offset nTotalBytesRead;
110 : void *hMutex;
111 : #endif
112 :
113 : public:
114 : VSIUnixStdioFilesystemHandler();
115 : #ifdef VSI_COUNT_BYTES_READ
116 : virtual ~VSIUnixStdioFilesystemHandler();
117 : #endif
118 :
119 : virtual VSIVirtualHandle *Open( const char *pszFilename,
120 : const char *pszAccess);
121 : virtual int Stat( const char *pszFilename, VSIStatBufL *pStatBuf, int nFlags );
122 : virtual int Unlink( const char *pszFilename );
123 : virtual int Rename( const char *oldpath, const char *newpath );
124 : virtual int Mkdir( const char *pszDirname, long nMode );
125 : virtual int Rmdir( const char *pszDirname );
126 : virtual char **ReadDir( const char *pszDirname );
127 :
128 : #ifdef VSI_COUNT_BYTES_READ
129 : void AddToTotal(vsi_l_offset nBytes);
130 : #endif
131 : };
132 :
133 : /************************************************************************/
134 : /* ==================================================================== */
135 : /* VSIUnixStdioHandle */
136 : /* ==================================================================== */
137 : /************************************************************************/
138 :
139 : class VSIUnixStdioHandle : public VSIVirtualHandle
140 53376 : {
141 : FILE *fp;
142 : vsi_l_offset nOffset;
143 : int bLastOpWrite;
144 : int bLastOpRead;
145 : int bAtEOF;
146 : #ifdef VSI_COUNT_BYTES_READ
147 : vsi_l_offset nTotalBytesRead;
148 : VSIUnixStdioFilesystemHandler *poFS;
149 : #endif
150 : public:
151 : VSIUnixStdioHandle(VSIUnixStdioFilesystemHandler *poFSIn,
152 : FILE* fpIn);
153 :
154 : virtual int Seek( vsi_l_offset nOffset, int nWhence );
155 : virtual vsi_l_offset Tell();
156 : virtual size_t Read( void *pBuffer, size_t nSize, size_t nMemb );
157 : virtual size_t Write( const void *pBuffer, size_t nSize, size_t nMemb );
158 : virtual int Eof();
159 : virtual int Flush();
160 : virtual int Close();
161 : virtual int Truncate( vsi_l_offset nNewSize );
162 : };
163 :
164 :
165 : /************************************************************************/
166 : /* VSIUnixStdioHandle() */
167 : /************************************************************************/
168 :
169 53377 : VSIUnixStdioHandle::VSIUnixStdioHandle(VSIUnixStdioFilesystemHandler *poFSIn,
170 : FILE* fpIn) :
171 : fp(fpIn), nOffset(0), bLastOpWrite(FALSE), bLastOpRead(FALSE), bAtEOF(FALSE)
172 : #ifdef VSI_COUNT_BYTES_READ
173 53377 : , nTotalBytesRead(0), poFS(poFSIn)
174 : #endif
175 : {
176 53377 : }
177 :
178 : /************************************************************************/
179 : /* Close() */
180 : /************************************************************************/
181 :
182 53376 : int VSIUnixStdioHandle::Close()
183 :
184 : {
185 : VSIDebug1( "VSIUnixStdioHandle::Close(%p)", fp );
186 :
187 : #ifdef VSI_COUNT_BYTES_READ
188 53376 : poFS->AddToTotal(nTotalBytesRead);
189 : #endif
190 :
191 53376 : return fclose( fp );
192 : }
193 :
194 : /************************************************************************/
195 : /* Seek() */
196 : /************************************************************************/
197 :
198 2867464 : int VSIUnixStdioHandle::Seek( vsi_l_offset nOffset, int nWhence )
199 :
200 : {
201 : // seeks that do nothing are still surprisingly expensive with MSVCRT.
202 : // try and short circuit if possible.
203 2867464 : if( nWhence == SEEK_SET && nOffset == this->nOffset )
204 270162 : return 0;
205 :
206 2597302 : int nResult = VSI_FSEEK64( fp, nOffset, nWhence );
207 2597304 : int nError = errno;
208 :
209 : #ifdef VSI_DEBUG
210 :
211 : if( nWhence == SEEK_SET )
212 : {
213 : VSIDebug3( "VSIUnixStdioHandle::Seek(%p," CPL_FRMT_GUIB ",SEEK_SET) = %d",
214 : fp, nOffset, nResult );
215 : }
216 : else if( nWhence == SEEK_END )
217 : {
218 : VSIDebug3( "VSIUnixStdioHandle::Seek(%p," CPL_FRMT_GUIB ",SEEK_END) = %d",
219 : fp, nOffset, nResult );
220 : }
221 : else if( nWhence == SEEK_CUR )
222 : {
223 : VSIDebug3( "VSIUnixStdioHandle::Seek(%p," CPL_FRMT_GUIB ",SEEK_CUR) = %d",
224 : fp, nOffset, nResult );
225 : }
226 : else
227 : {
228 : VSIDebug4( "VSIUnixStdioHandle::Seek(%p," CPL_FRMT_GUIB ",%d-Unknown) = %d",
229 : fp, nOffset, nWhence, nResult );
230 : }
231 :
232 : #endif
233 :
234 2597304 : if( nResult != -1 )
235 : {
236 2597304 : if( nWhence == SEEK_SET )
237 : {
238 2304885 : this->nOffset = nOffset;
239 : }
240 292419 : else if( nWhence == SEEK_END )
241 : {
242 277747 : this->nOffset = VSI_FTELL64( fp );
243 : }
244 14672 : else if( nWhence == SEEK_CUR )
245 : {
246 14672 : this->nOffset += nOffset;
247 : }
248 : }
249 :
250 2597304 : bLastOpWrite = FALSE;
251 2597304 : bLastOpRead = FALSE;
252 2597304 : bAtEOF = FALSE;
253 :
254 2597304 : errno = nError;
255 2597304 : return nResult;
256 : }
257 :
258 : /************************************************************************/
259 : /* Tell() */
260 : /************************************************************************/
261 :
262 830602 : vsi_l_offset VSIUnixStdioHandle::Tell()
263 :
264 : {
265 : #ifdef notdef
266 : vsi_l_offset nOffset = VSI_FTELL64( fp );
267 : int nError = errno;
268 :
269 : VSIDebug2( "VSIUnixStdioHandle::Tell(%p) = %ld", fp, (long)nOffset );
270 :
271 : errno = nError;
272 : return nOffset;
273 : #endif
274 830602 : return nOffset;
275 : }
276 :
277 : /************************************************************************/
278 : /* Flush() */
279 : /************************************************************************/
280 :
281 1082 : int VSIUnixStdioHandle::Flush()
282 :
283 : {
284 : VSIDebug1( "VSIUnixStdioHandle::Flush(%p)", fp );
285 :
286 1082 : return fflush( fp );
287 : }
288 :
289 : /************************************************************************/
290 : /* Read() */
291 : /************************************************************************/
292 :
293 4546036 : size_t VSIUnixStdioHandle::Read( void * pBuffer, size_t nSize, size_t nCount )
294 :
295 : {
296 : /* -------------------------------------------------------------------- */
297 : /* If a fwrite() is followed by an fread(), the POSIX rules are */
298 : /* that some of the write may still be buffered and lost. We */
299 : /* are required to do a seek between to force flushing. So we */
300 : /* keep careful track of what happened last to know if we */
301 : /* skipped a flushing seek that we may need to do now. */
302 : /* -------------------------------------------------------------------- */
303 4546036 : if( bLastOpWrite )
304 521 : VSI_FSEEK64( fp, nOffset, SEEK_SET );
305 :
306 : /* -------------------------------------------------------------------- */
307 : /* Perform the read. */
308 : /* -------------------------------------------------------------------- */
309 4546036 : size_t nResult = fread( pBuffer, nSize, nCount, fp );
310 4546041 : int nError = errno;
311 :
312 : VSIDebug4( "VSIUnixStdioHandle::Read(%p,%ld,%ld) = %ld",
313 : fp, (long)nSize, (long)nCount, (long)nResult );
314 :
315 4546041 : errno = nError;
316 :
317 : /* -------------------------------------------------------------------- */
318 : /* Update current offset. */
319 : /* -------------------------------------------------------------------- */
320 :
321 : #ifdef VSI_COUNT_BYTES_READ
322 4546041 : nTotalBytesRead += nSize * nResult;
323 : #endif
324 :
325 4546041 : nOffset += nSize * nResult;
326 4546041 : bLastOpWrite = FALSE;
327 4546041 : bLastOpRead = TRUE;
328 :
329 4546041 : if (nResult != nCount)
330 : {
331 17181 : nOffset = VSI_FTELL64( fp );
332 17181 : bAtEOF = feof(fp);
333 : }
334 :
335 4546041 : return nResult;
336 : }
337 :
338 : /************************************************************************/
339 : /* Write() */
340 : /************************************************************************/
341 :
342 2309889 : size_t VSIUnixStdioHandle::Write( const void * pBuffer, size_t nSize,
343 : size_t nCount )
344 :
345 : {
346 : /* -------------------------------------------------------------------- */
347 : /* If a fwrite() is followed by an fread(), the POSIX rules are */
348 : /* that some of the write may still be buffered and lost. We */
349 : /* are required to do a seek between to force flushing. So we */
350 : /* keep careful track of what happened last to know if we */
351 : /* skipped a flushing seek that we may need to do now. */
352 : /* -------------------------------------------------------------------- */
353 2309889 : if( bLastOpRead )
354 1215 : VSI_FSEEK64( fp, nOffset, SEEK_SET );
355 :
356 : /* -------------------------------------------------------------------- */
357 : /* Perform the write. */
358 : /* -------------------------------------------------------------------- */
359 2309889 : size_t nResult = fwrite( pBuffer, nSize, nCount, fp );
360 2309889 : int nError = errno;
361 :
362 : VSIDebug4( "VSIUnixStdioHandle::Write(%p,%ld,%ld) = %ld",
363 : fp, (long)nSize, (long)nCount, (long)nResult );
364 :
365 2309889 : errno = nError;
366 :
367 : /* -------------------------------------------------------------------- */
368 : /* Update current offset. */
369 : /* -------------------------------------------------------------------- */
370 2309889 : nOffset += nSize * nResult;
371 2309889 : bLastOpWrite = TRUE;
372 2309889 : bLastOpRead = FALSE;
373 :
374 2309889 : return nResult;
375 : }
376 :
377 : /************************************************************************/
378 : /* Eof() */
379 : /************************************************************************/
380 :
381 232079 : int VSIUnixStdioHandle::Eof()
382 :
383 : {
384 232079 : if( bAtEOF )
385 5093 : return 1;
386 : else
387 226986 : return 0;
388 : }
389 :
390 : /************************************************************************/
391 : /* Truncate() */
392 : /************************************************************************/
393 :
394 2 : int VSIUnixStdioHandle::Truncate( vsi_l_offset nNewSize )
395 : {
396 2 : fflush(fp);
397 2 : int nRet = VSI_FTRUNCATE64(fileno(fp), nNewSize);
398 2 : return nRet;
399 : }
400 :
401 :
402 : /************************************************************************/
403 : /* ==================================================================== */
404 : /* VSIUnixStdioFilesystemHandler */
405 : /* ==================================================================== */
406 : /************************************************************************/
407 :
408 : /************************************************************************/
409 : /* VSIUnixStdioFilesystemHandler() */
410 : /************************************************************************/
411 :
412 712 : VSIUnixStdioFilesystemHandler::VSIUnixStdioFilesystemHandler()
413 : #ifdef VSI_COUNT_BYTES_READ
414 712 : : nTotalBytesRead(0), hMutex(NULL)
415 : #endif
416 : {
417 712 : }
418 :
419 : #ifdef VSI_COUNT_BYTES_READ
420 : /************************************************************************/
421 : /* ~VSIUnixStdioFilesystemHandler() */
422 : /************************************************************************/
423 :
424 687 : VSIUnixStdioFilesystemHandler::~VSIUnixStdioFilesystemHandler()
425 : {
426 : CPLDebug( "VSI",
427 : "~VSIUnixStdioFilesystemHandler() : nTotalBytesRead = " CPL_FRMT_GUIB,
428 687 : nTotalBytesRead );
429 :
430 687 : if( hMutex != NULL )
431 658 : CPLDestroyMutex( hMutex );
432 687 : hMutex = NULL;
433 687 : }
434 : #endif
435 :
436 : /************************************************************************/
437 : /* Open() */
438 : /************************************************************************/
439 :
440 : VSIVirtualHandle *
441 76379 : VSIUnixStdioFilesystemHandler::Open( const char *pszFilename,
442 : const char *pszAccess )
443 :
444 : {
445 76379 : FILE *fp = VSI_FOPEN64( pszFilename, pszAccess );
446 76379 : int nError = errno;
447 :
448 : VSIDebug3( "VSIUnixStdioFilesystemHandler::Open(\"%s\",\"%s\") = %p",
449 : pszFilename, pszAccess, fp );
450 :
451 76379 : if( fp == NULL )
452 : {
453 23002 : errno = nError;
454 23002 : return NULL;
455 : }
456 :
457 53377 : VSIUnixStdioHandle *poHandle = new VSIUnixStdioHandle(this, fp);
458 :
459 53377 : errno = nError;
460 :
461 : /* -------------------------------------------------------------------- */
462 : /* If VSI_CACHE is set we want to use a cached reader instead */
463 : /* of more direct io on the underlying file. */
464 : /* -------------------------------------------------------------------- */
465 103628 : if( (EQUAL(pszAccess,"r") || EQUAL(pszAccess,"rb"))
466 : && CSLTestBoolean( CPLGetConfigOption( "VSI_CACHE", "FALSE" ) ) )
467 : {
468 3 : return VSICreateCachedFile( poHandle );
469 : }
470 : else
471 : {
472 53374 : return poHandle;
473 : }
474 : }
475 :
476 : /************************************************************************/
477 : /* Stat() */
478 : /************************************************************************/
479 :
480 53905 : int VSIUnixStdioFilesystemHandler::Stat( const char * pszFilename,
481 : VSIStatBufL * pStatBuf,
482 : int nFlags)
483 :
484 : {
485 53905 : return( VSI_STAT64( pszFilename, pStatBuf ) );
486 : }
487 :
488 : /************************************************************************/
489 : /* Unlink() */
490 : /************************************************************************/
491 :
492 2807 : int VSIUnixStdioFilesystemHandler::Unlink( const char * pszFilename )
493 :
494 : {
495 2807 : return unlink( pszFilename );
496 : }
497 :
498 : /************************************************************************/
499 : /* Rename() */
500 : /************************************************************************/
501 :
502 14 : int VSIUnixStdioFilesystemHandler::Rename( const char *oldpath,
503 : const char *newpath )
504 :
505 : {
506 14 : return rename( oldpath, newpath );
507 : }
508 :
509 : /************************************************************************/
510 : /* Mkdir() */
511 : /************************************************************************/
512 :
513 106 : int VSIUnixStdioFilesystemHandler::Mkdir( const char * pszPathname,
514 : long nMode )
515 :
516 : {
517 106 : return mkdir( pszPathname, nMode );
518 : }
519 :
520 : /************************************************************************/
521 : /* Rmdir() */
522 : /************************************************************************/
523 :
524 61 : int VSIUnixStdioFilesystemHandler::Rmdir( const char * pszPathname )
525 :
526 : {
527 61 : return rmdir( pszPathname );
528 : }
529 :
530 : /************************************************************************/
531 : /* ReadDir() */
532 : /************************************************************************/
533 :
534 9616 : char **VSIUnixStdioFilesystemHandler::ReadDir( const char *pszPath )
535 :
536 : {
537 : DIR *hDir;
538 : struct dirent *psDirEntry;
539 9616 : CPLStringList oDir;
540 :
541 9616 : if (strlen(pszPath) == 0)
542 4 : pszPath = ".";
543 :
544 9616 : if ( (hDir = opendir(pszPath)) != NULL )
545 : {
546 : // we want to avoid returning NULL for an empty list.
547 8712 : oDir.Assign( (char**) CPLCalloc(2,sizeof(char*)) );
548 :
549 566753 : while( (psDirEntry = readdir(hDir)) != NULL )
550 549329 : oDir.AddString( psDirEntry->d_name );
551 :
552 8712 : closedir( hDir );
553 : }
554 : else
555 : {
556 : /* Should we generate an error???
557 : * For now we'll just return NULL (at the end of the function)
558 : */
559 : }
560 :
561 9616 : return oDir.StealList();
562 : }
563 :
564 : #ifdef VSI_COUNT_BYTES_READ
565 : /************************************************************************/
566 : /* AddToTotal() */
567 : /************************************************************************/
568 :
569 53376 : void VSIUnixStdioFilesystemHandler::AddToTotal(vsi_l_offset nBytes)
570 : {
571 53376 : CPLMutexHolder oHolder(&hMutex);
572 53376 : nTotalBytesRead += nBytes;
573 53376 : }
574 :
575 : #endif
576 :
577 : /************************************************************************/
578 : /* VSIInstallLargeFileHandler() */
579 : /************************************************************************/
580 :
581 712 : void VSIInstallLargeFileHandler()
582 :
583 : {
584 712 : VSIFileManager::InstallHandler( "", new VSIUnixStdioFilesystemHandler() );
585 712 : }
586 :
587 : #endif /* ndef WIN32 */
|