1 : /**********************************************************************
2 : * $Id: cpl_vsil_unix_stdio_64.cpp 23506 2011-12-10 13:43:59Z 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 : #include "cpl_port.h"
39 :
40 : #if !defined(WIN32) && !defined(WIN32CE)
41 :
42 : #include "cpl_vsi_virtual.h"
43 : #include "cpl_string.h"
44 :
45 : #include <unistd.h>
46 : #include <sys/stat.h>
47 : #include <sys/types.h>
48 : #include <dirent.h>
49 : #include <errno.h>
50 :
51 : CPL_CVSID("$Id: cpl_vsil_unix_stdio_64.cpp 23506 2011-12-10 13:43:59Z rouault $");
52 :
53 : #if defined(UNIX_STDIO_64)
54 :
55 : #ifndef VSI_FTELL64
56 : #define VSI_FTELL64 ftell64
57 : #endif
58 : #ifndef VSI_FSEEK64
59 : #define VSI_FSEEK64 fseek64
60 : #endif
61 : #ifndef VSI_FOPEN64
62 : #define VSI_FOPEN64 fopen64
63 : #endif
64 : #ifndef VSI_STAT64
65 : #define VSI_STAT64 stat64
66 : #endif
67 : #ifndef VSI_STAT64_T
68 : #define VSI_STAT64_T stat64
69 : #endif
70 : #ifndef VSI_FTRUNCATE64
71 : #define VSI_FTRUNCATE64 ftruncate64
72 : #endif
73 :
74 : #else /* not UNIX_STDIO_64 */
75 :
76 : #ifndef VSI_FTELL64
77 : #define VSI_FTELL64 ftell
78 : #endif
79 : #ifndef VSI_FSEEK64
80 : #define VSI_FSEEK64 fseek
81 : #endif
82 : #ifndef VSI_FOPEN64
83 : #define VSI_FOPEN64 fopen
84 : #endif
85 : #ifndef VSI_STAT64
86 : #define VSI_STAT64 stat
87 : #endif
88 : #ifndef VSI_STAT64_T
89 : #define VSI_STAT64_T stat
90 : #endif
91 : #ifndef VSI_FTRUNCATE64
92 : #define VSI_FTRUNCATE64 ftruncate
93 : #endif
94 :
95 : #endif /* ndef UNIX_STDIO_64 */
96 :
97 : /************************************************************************/
98 : /* ==================================================================== */
99 : /* VSIUnixStdioFilesystemHandler */
100 : /* ==================================================================== */
101 : /************************************************************************/
102 :
103 : class VSIUnixStdioFilesystemHandler : public VSIFilesystemHandler
104 1275 : {
105 : public:
106 : virtual VSIVirtualHandle *Open( const char *pszFilename,
107 : const char *pszAccess);
108 : virtual int Stat( const char *pszFilename, VSIStatBufL *pStatBuf, int nFlags );
109 : virtual int Unlink( const char *pszFilename );
110 : virtual int Rename( const char *oldpath, const char *newpath );
111 : virtual int Mkdir( const char *pszDirname, long nMode );
112 : virtual int Rmdir( const char *pszDirname );
113 : virtual char **ReadDir( const char *pszDirname );
114 : };
115 :
116 : /************************************************************************/
117 : /* ==================================================================== */
118 : /* VSIUnixStdioHandle */
119 : /* ==================================================================== */
120 : /************************************************************************/
121 :
122 : class VSIUnixStdioHandle : public VSIVirtualHandle
123 43922 : {
124 : public:
125 : FILE *fp;
126 : vsi_l_offset nOffset;
127 : int bLastOpWrite;
128 : int bLastOpRead;
129 : int bAtEOF;
130 :
131 : virtual int Seek( vsi_l_offset nOffset, int nWhence );
132 : virtual vsi_l_offset Tell();
133 : virtual size_t Read( void *pBuffer, size_t nSize, size_t nMemb );
134 : virtual size_t Write( const void *pBuffer, size_t nSize, size_t nMemb );
135 : virtual int Eof();
136 : virtual int Flush();
137 : virtual int Close();
138 : virtual int Truncate( vsi_l_offset nNewSize );
139 : };
140 :
141 : /************************************************************************/
142 : /* Close() */
143 : /************************************************************************/
144 :
145 21961 : int VSIUnixStdioHandle::Close()
146 :
147 : {
148 : VSIDebug1( "VSIUnixStdioHandle::Close(%p)", fp );
149 :
150 21961 : return fclose( fp );
151 : }
152 :
153 : /************************************************************************/
154 : /* Seek() */
155 : /************************************************************************/
156 :
157 656091 : int VSIUnixStdioHandle::Seek( vsi_l_offset nOffset, int nWhence )
158 :
159 : {
160 : // seeks that do nothing are still surprisingly expensive with MSVCRT.
161 : // try and short circuit if possible.
162 656091 : if( nWhence == SEEK_SET && nOffset == this->nOffset )
163 179410 : return 0;
164 :
165 476681 : int nResult = VSI_FSEEK64( fp, nOffset, nWhence );
166 476681 : int nError = errno;
167 :
168 : #ifdef VSI_DEBUG
169 :
170 : if( nWhence == SEEK_SET )
171 : {
172 : VSIDebug3( "VSIUnixStdioHandle::Seek(%p," CPL_FRMT_GUIB ",SEEK_SET) = %d",
173 : fp, nOffset, nResult );
174 : }
175 : else if( nWhence == SEEK_END )
176 : {
177 : VSIDebug3( "VSIUnixStdioHandle::Seek(%p," CPL_FRMT_GUIB ",SEEK_END) = %d",
178 : fp, nOffset, nResult );
179 : }
180 : else if( nWhence == SEEK_CUR )
181 : {
182 : VSIDebug3( "VSIUnixStdioHandle::Seek(%p," CPL_FRMT_GUIB ",SEEK_CUR) = %d",
183 : fp, nOffset, nResult );
184 : }
185 : else
186 : {
187 : VSIDebug4( "VSIUnixStdioHandle::Seek(%p," CPL_FRMT_GUIB ",%d-Unknown) = %d",
188 : fp, nOffset, nWhence, nResult );
189 : }
190 :
191 : #endif
192 :
193 476681 : if( nResult != -1 )
194 : {
195 476681 : if( nWhence == SEEK_SET )
196 : {
197 202314 : this->nOffset = nOffset;
198 : }
199 274367 : else if( nWhence == SEEK_END )
200 : {
201 271184 : this->nOffset = VSI_FTELL64( fp );
202 : }
203 3183 : else if( nWhence == SEEK_CUR )
204 : {
205 3183 : this->nOffset += nOffset;
206 : }
207 : }
208 :
209 476681 : bLastOpWrite = FALSE;
210 476681 : bLastOpRead = FALSE;
211 476681 : bAtEOF = FALSE;
212 :
213 476681 : errno = nError;
214 476681 : return nResult;
215 : }
216 :
217 : /************************************************************************/
218 : /* Tell() */
219 : /************************************************************************/
220 :
221 759069 : vsi_l_offset VSIUnixStdioHandle::Tell()
222 :
223 : {
224 : #ifdef notdef
225 : vsi_l_offset nOffset = VSI_FTELL64( fp );
226 : int nError = errno;
227 :
228 : VSIDebug2( "VSIUnixStdioHandle::Tell(%p) = %ld", fp, (long)nOffset );
229 :
230 : errno = nError;
231 : return nOffset;
232 : #endif
233 759069 : return nOffset;
234 : }
235 :
236 : /************************************************************************/
237 : /* Flush() */
238 : /************************************************************************/
239 :
240 939 : int VSIUnixStdioHandle::Flush()
241 :
242 : {
243 : VSIDebug1( "VSIUnixStdioHandle::Flush(%p)", fp );
244 :
245 939 : return fflush( fp );
246 : }
247 :
248 : /************************************************************************/
249 : /* Read() */
250 : /************************************************************************/
251 :
252 1992623 : size_t VSIUnixStdioHandle::Read( void * pBuffer, size_t nSize, size_t nCount )
253 :
254 : {
255 : /* -------------------------------------------------------------------- */
256 : /* If a fwrite() is followed by an fread(), the POSIX rules are */
257 : /* that some of the write may still be buffered and lost. We */
258 : /* are required to do a seek between to force flushing. So we */
259 : /* keep careful track of what happened last to know if we */
260 : /* skipped a flushing seek that we may need to do now. */
261 : /* -------------------------------------------------------------------- */
262 1992623 : if( bLastOpWrite )
263 516 : VSI_FSEEK64( fp, nOffset, SEEK_SET );
264 :
265 : /* -------------------------------------------------------------------- */
266 : /* Perform the read. */
267 : /* -------------------------------------------------------------------- */
268 1992623 : size_t nResult = fread( pBuffer, nSize, nCount, fp );
269 1992623 : int nError = errno;
270 :
271 : VSIDebug4( "VSIUnixStdioHandle::Read(%p,%ld,%ld) = %ld",
272 : fp, (long)nSize, (long)nCount, (long)nResult );
273 :
274 1992623 : errno = nError;
275 :
276 : /* -------------------------------------------------------------------- */
277 : /* Update current offset. */
278 : /* -------------------------------------------------------------------- */
279 1992623 : nOffset += nSize * nResult;
280 1992623 : bLastOpWrite = FALSE;
281 1992623 : bLastOpRead = TRUE;
282 :
283 1992623 : if (nResult != nCount)
284 13700 : bAtEOF = feof(fp);
285 :
286 1992623 : return nResult;
287 : }
288 :
289 : /************************************************************************/
290 : /* Write() */
291 : /************************************************************************/
292 :
293 1962606 : size_t VSIUnixStdioHandle::Write( const void * pBuffer, size_t nSize,
294 : size_t nCount )
295 :
296 : {
297 : /* -------------------------------------------------------------------- */
298 : /* If a fwrite() is followed by an fread(), the POSIX rules are */
299 : /* that some of the write may still be buffered and lost. We */
300 : /* are required to do a seek between to force flushing. So we */
301 : /* keep careful track of what happened last to know if we */
302 : /* skipped a flushing seek that we may need to do now. */
303 : /* -------------------------------------------------------------------- */
304 1962606 : if( bLastOpRead )
305 1204 : VSI_FSEEK64( fp, nOffset, SEEK_SET );
306 :
307 : /* -------------------------------------------------------------------- */
308 : /* Perform the write. */
309 : /* -------------------------------------------------------------------- */
310 1962606 : size_t nResult = fwrite( pBuffer, nSize, nCount, fp );
311 1962606 : int nError = errno;
312 :
313 : VSIDebug4( "VSIUnixStdioHandle::Write(%p,%ld,%ld) = %ld",
314 : fp, (long)nSize, (long)nCount, (long)nResult );
315 :
316 1962606 : errno = nError;
317 :
318 : /* -------------------------------------------------------------------- */
319 : /* Update current offset. */
320 : /* -------------------------------------------------------------------- */
321 1962606 : nOffset += nSize * nResult;
322 1962606 : bLastOpWrite = TRUE;
323 1962606 : bLastOpRead = FALSE;
324 :
325 1962606 : return nResult;
326 : }
327 :
328 : /************************************************************************/
329 : /* Eof() */
330 : /************************************************************************/
331 :
332 290801 : int VSIUnixStdioHandle::Eof()
333 :
334 : {
335 290801 : if( bAtEOF )
336 2927 : return 1;
337 : else
338 287874 : return 0;
339 : }
340 :
341 : /************************************************************************/
342 : /* Truncate() */
343 : /************************************************************************/
344 :
345 2 : int VSIUnixStdioHandle::Truncate( vsi_l_offset nNewSize )
346 : {
347 2 : fflush(fp);
348 2 : int nRet = VSI_FTRUNCATE64(fileno(fp), nNewSize);
349 2 : return nRet;
350 : }
351 :
352 :
353 : /************************************************************************/
354 : /* ==================================================================== */
355 : /* VSIUnixStdioFilesystemHandler */
356 : /* ==================================================================== */
357 : /************************************************************************/
358 :
359 : /************************************************************************/
360 : /* Open() */
361 : /************************************************************************/
362 :
363 : VSIVirtualHandle *
364 39043 : VSIUnixStdioFilesystemHandler::Open( const char *pszFilename,
365 : const char *pszAccess )
366 :
367 : {
368 39043 : FILE *fp = VSI_FOPEN64( pszFilename, pszAccess );
369 39043 : int nError = errno;
370 :
371 : VSIDebug3( "VSIUnixStdioFilesystemHandler::Open(\"%s\",\"%s\") = %p",
372 : pszFilename, pszAccess, fp );
373 :
374 39043 : if( fp == NULL )
375 : {
376 17082 : errno = nError;
377 17082 : return NULL;
378 : }
379 :
380 21961 : VSIUnixStdioHandle *poHandle = new VSIUnixStdioHandle;
381 :
382 21961 : poHandle->fp = fp;
383 21961 : poHandle->nOffset = 0;
384 21961 : poHandle->bLastOpWrite = FALSE;
385 21961 : poHandle->bLastOpRead = FALSE;
386 21961 : poHandle->bAtEOF = FALSE;
387 :
388 21961 : errno = nError;
389 :
390 : /* -------------------------------------------------------------------- */
391 : /* If VSI_CACHE is set we want to use a cached reader instead */
392 : /* of more direct io on the underlying file. */
393 : /* -------------------------------------------------------------------- */
394 41171 : if( (EQUAL(pszAccess,"r") || EQUAL(pszAccess,"rb"))
395 : && CSLTestBoolean( CPLGetConfigOption( "VSI_CACHE", "FALSE" ) ) )
396 : {
397 0 : return VSICreateCachedFile( poHandle );
398 : }
399 : else
400 : {
401 21961 : return poHandle;
402 : }
403 : }
404 :
405 : /************************************************************************/
406 : /* Stat() */
407 : /************************************************************************/
408 :
409 45222 : int VSIUnixStdioFilesystemHandler::Stat( const char * pszFilename,
410 : VSIStatBufL * pStatBuf,
411 : int nFlags)
412 :
413 : {
414 45222 : return( VSI_STAT64( pszFilename, pStatBuf ) );
415 : }
416 :
417 : /************************************************************************/
418 : /* Unlink() */
419 : /************************************************************************/
420 :
421 2604 : int VSIUnixStdioFilesystemHandler::Unlink( const char * pszFilename )
422 :
423 : {
424 2604 : return unlink( pszFilename );
425 : }
426 :
427 : /************************************************************************/
428 : /* Rename() */
429 : /************************************************************************/
430 :
431 14 : int VSIUnixStdioFilesystemHandler::Rename( const char *oldpath,
432 : const char *newpath )
433 :
434 : {
435 14 : return rename( oldpath, newpath );
436 : }
437 :
438 : /************************************************************************/
439 : /* Mkdir() */
440 : /************************************************************************/
441 :
442 74 : int VSIUnixStdioFilesystemHandler::Mkdir( const char * pszPathname,
443 : long nMode )
444 :
445 : {
446 74 : return mkdir( pszPathname, nMode );
447 : }
448 :
449 : /************************************************************************/
450 : /* Rmdir() */
451 : /************************************************************************/
452 :
453 57 : int VSIUnixStdioFilesystemHandler::Rmdir( const char * pszPathname )
454 :
455 : {
456 57 : return rmdir( pszPathname );
457 : }
458 :
459 : /************************************************************************/
460 : /* ReadDir() */
461 : /************************************************************************/
462 :
463 8737 : char **VSIUnixStdioFilesystemHandler::ReadDir( const char *pszPath )
464 :
465 : {
466 : DIR *hDir;
467 : struct dirent *psDirEntry;
468 8737 : CPLStringList oDir;
469 :
470 8737 : if (strlen(pszPath) == 0)
471 4 : pszPath = ".";
472 :
473 8737 : if ( (hDir = opendir(pszPath)) != NULL )
474 : {
475 : // we want to avoid returning NULL for an empty list.
476 7244 : oDir.Assign( (char**) CPLCalloc(2,sizeof(char*)) );
477 :
478 432083 : while( (psDirEntry = readdir(hDir)) != NULL )
479 417595 : oDir.AddString( psDirEntry->d_name );
480 :
481 7244 : closedir( hDir );
482 : }
483 : else
484 : {
485 : /* Should we generate an error???
486 : * For now we'll just return NULL (at the end of the function)
487 : */
488 : }
489 :
490 8737 : return oDir.StealList();
491 : }
492 :
493 : /************************************************************************/
494 : /* VSIInstallLargeFileHandler() */
495 : /************************************************************************/
496 :
497 647 : void VSIInstallLargeFileHandler()
498 :
499 : {
500 647 : VSIFileManager::InstallHandler( "", new VSIUnixStdioFilesystemHandler );
501 647 : }
502 :
503 : #endif /* ndef WIN32 */
|