1 : /**********************************************************************
2 : * $Id: cpl_vsil_unix_stdio_64.cpp 17402 2009-07-16 20:11:00Z warmerdam $
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 17402 2009-07-16 20:11:00Z warmerdam $");
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 :
71 : #else /* not UNIX_STDIO_64 */
72 :
73 : #ifndef VSI_FTELL64
74 : #define VSI_FTELL64 ftell
75 : #endif
76 : #ifndef VSI_FSEEK64
77 : #define VSI_FSEEK64 fseek
78 : #endif
79 : #ifndef VSI_FOPEN64
80 : #define VSI_FOPEN64 fopen
81 : #endif
82 : #ifndef VSI_STAT64
83 : #define VSI_STAT64 stat
84 : #endif
85 : #ifndef VSI_STAT64_T
86 : #define VSI_STAT64_T stat
87 : #endif
88 :
89 : #endif /* ndef UNIX_STDIO_64 */
90 :
91 : /************************************************************************/
92 : /* ==================================================================== */
93 : /* VSIUnixStdioFilesystemHandler */
94 : /* ==================================================================== */
95 : /************************************************************************/
96 :
97 : class VSIUnixStdioFilesystemHandler : public VSIFilesystemHandler
98 1105 : {
99 : public:
100 : virtual VSIVirtualHandle *Open( const char *pszFilename,
101 : const char *pszAccess);
102 : virtual int Stat( const char *pszFilename, VSIStatBufL *pStatBuf );
103 : virtual int Unlink( const char *pszFilename );
104 : virtual int Rename( const char *oldpath, const char *newpath );
105 : virtual int Mkdir( const char *pszDirname, long nMode );
106 : virtual int Rmdir( const char *pszDirname );
107 : virtual char **ReadDir( const char *pszDirname );
108 : };
109 :
110 : /************************************************************************/
111 : /* ==================================================================== */
112 : /* VSIUnixStdioHandle */
113 : /* ==================================================================== */
114 : /************************************************************************/
115 :
116 : class VSIUnixStdioHandle : public VSIVirtualHandle
117 40123 : {
118 : public:
119 : FILE *fp;
120 : vsi_l_offset nOffset;
121 : int bLastOpWrite;
122 : int bLastOpRead;
123 : int bAtEOF;
124 :
125 : virtual int Seek( vsi_l_offset nOffset, int nWhence );
126 : virtual vsi_l_offset Tell();
127 : virtual size_t Read( void *pBuffer, size_t nSize, size_t nMemb );
128 : virtual size_t Write( const void *pBuffer, size_t nSize, size_t nMemb );
129 : virtual int Eof();
130 : virtual int Flush();
131 : virtual int Close();
132 : };
133 :
134 : /************************************************************************/
135 : /* Close() */
136 : /************************************************************************/
137 :
138 13374 : int VSIUnixStdioHandle::Close()
139 :
140 : {
141 : VSIDebug1( "VSIUnixStdioHandle::Close(%p)", fp );
142 :
143 13374 : return fclose( fp );
144 : }
145 :
146 : /************************************************************************/
147 : /* Seek() */
148 : /************************************************************************/
149 :
150 471667 : int VSIUnixStdioHandle::Seek( vsi_l_offset nOffset, int nWhence )
151 :
152 : {
153 : // seeks that do nothing are still surprisingly expensive with MSVCRT.
154 : // try and short circuit if possible.
155 471667 : if( nWhence == SEEK_SET && nOffset == this->nOffset )
156 145552 : return 0;
157 :
158 326115 : if( nWhence == SEEK_END && nOffset == 0 && bAtEOF )
159 238219 : return 0;
160 :
161 87896 : int nResult = VSI_FSEEK64( fp, nOffset, nWhence );
162 87896 : int nError = errno;
163 :
164 : #ifdef VSI_DEBUG
165 :
166 : if( nWhence == SEEK_SET )
167 : {
168 : VSIDebug3( "VSIUnixStdioHandle::Seek(%p,%d,SEEK_SET) = %d",
169 : fp, nOffset, nResult );
170 : }
171 : else if( nWhence == SEEK_END )
172 : {
173 : VSIDebug3( "VSIUnixStdioHandle::Seek(%p,%d,SEEK_END) = %d",
174 : fp, nOffset, nResult );
175 : }
176 : else if( nWhence == SEEK_CUR )
177 : {
178 : VSIDebug3( "VSIUnixStdioHandle::Seek(%p,%d,SEEK_CUR) = %d",
179 : fp, nOffset, nResult );
180 : }
181 : else
182 : {
183 : VSIDebug4( "VSIUnixStdioHandle::Seek(%p,%d,%d-Unknown) = %d",
184 : fp, nOffset, nWhence, nResult );
185 : }
186 :
187 : #endif
188 :
189 87896 : if( nResult != -1 )
190 : {
191 87896 : if( nWhence == SEEK_SET )
192 : {
193 78961 : this->nOffset = nOffset;
194 78961 : bAtEOF = FALSE;
195 : }
196 8935 : else if( nWhence == SEEK_END )
197 : {
198 7520 : this->nOffset = VSI_FTELL64( fp );
199 7520 : bAtEOF = TRUE;
200 : }
201 1415 : else if( nWhence == SEEK_CUR )
202 : {
203 1415 : this->nOffset += nOffset;
204 1415 : bAtEOF = FALSE;
205 : }
206 : }
207 :
208 87896 : bLastOpWrite = FALSE;
209 87896 : bLastOpRead = FALSE;
210 :
211 87896 : errno = nError;
212 87896 : return nResult;
213 : }
214 :
215 : /************************************************************************/
216 : /* Tell() */
217 : /************************************************************************/
218 :
219 580163 : vsi_l_offset VSIUnixStdioHandle::Tell()
220 :
221 : {
222 : #ifdef notdef
223 : vsi_l_offset nOffset = VSI_FTELL64( fp );
224 : int nError = errno;
225 :
226 : VSIDebug2( "VSIUnixStdioHandle::Tell(%p) = %ld", fp, (long)nOffset );
227 :
228 : errno = nError;
229 : return nOffset;
230 : #endif
231 580163 : return nOffset;
232 : }
233 :
234 : /************************************************************************/
235 : /* Flush() */
236 : /************************************************************************/
237 :
238 522 : int VSIUnixStdioHandle::Flush()
239 :
240 : {
241 : VSIDebug1( "VSIUnixStdioHandle::Flush(%p)", fp );
242 :
243 522 : return fflush( fp );
244 : }
245 :
246 : /************************************************************************/
247 : /* Read() */
248 : /************************************************************************/
249 :
250 1326255 : size_t VSIUnixStdioHandle::Read( void * pBuffer, size_t nSize, size_t nCount )
251 :
252 : {
253 : /* -------------------------------------------------------------------- */
254 : /* If a fwrite() is followed by an fread(), the POSIX rules are */
255 : /* that some of the write may still be buffered and lost. We */
256 : /* are required to do a seek between to force flushing. So we */
257 : /* keep careful track of what happened last to know if we */
258 : /* skipped a flushing seek that we may need to do now. */
259 : /* -------------------------------------------------------------------- */
260 1326255 : if( bLastOpWrite )
261 1086 : VSI_FSEEK64( fp, nOffset, SEEK_SET );
262 :
263 : /* -------------------------------------------------------------------- */
264 : /* Perform the read. */
265 : /* -------------------------------------------------------------------- */
266 1326255 : size_t nResult = fread( pBuffer, nSize, nCount, fp );
267 1326255 : int nError = errno;
268 :
269 : VSIDebug4( "VSIUnixStdioHandle::Read(%p,%ld,%ld) = %ld",
270 : fp, (long)nSize, (long)nCount, (long)nResult );
271 :
272 1326255 : errno = nError;
273 :
274 : /* -------------------------------------------------------------------- */
275 : /* Update current offset. */
276 : /* -------------------------------------------------------------------- */
277 1326255 : nOffset += nSize * nResult;
278 1326255 : bLastOpWrite = FALSE;
279 1326255 : bLastOpRead = TRUE;
280 :
281 1326255 : return nResult;
282 : }
283 :
284 : /************************************************************************/
285 : /* Write() */
286 : /************************************************************************/
287 :
288 1626641 : size_t VSIUnixStdioHandle::Write( const void * pBuffer, size_t nSize,
289 : size_t nCount )
290 :
291 : {
292 : /* -------------------------------------------------------------------- */
293 : /* If a fwrite() is followed by an fread(), the POSIX rules are */
294 : /* that some of the write may still be buffered and lost. We */
295 : /* are required to do a seek between to force flushing. So we */
296 : /* keep careful track of what happened last to know if we */
297 : /* skipped a flushing seek that we may need to do now. */
298 : /* -------------------------------------------------------------------- */
299 1626641 : if( bLastOpRead )
300 1975 : VSI_FSEEK64( fp, nOffset, SEEK_SET );
301 :
302 : /* -------------------------------------------------------------------- */
303 : /* Perform the write. */
304 : /* -------------------------------------------------------------------- */
305 1626641 : size_t nResult = fwrite( pBuffer, nSize, nCount, fp );
306 1626641 : int nError = errno;
307 :
308 : VSIDebug4( "VSIUnixStdioHandle::Write(%p,%ld,%ld) = %ld",
309 : fp, (long)nSize, (long)nCount, (long)nResult );
310 :
311 1626641 : errno = nError;
312 :
313 : /* -------------------------------------------------------------------- */
314 : /* Update current offset. */
315 : /* -------------------------------------------------------------------- */
316 1626641 : nOffset += nSize * nResult;
317 1626641 : bLastOpWrite = TRUE;
318 1626641 : bLastOpRead = FALSE;
319 :
320 1626641 : return nResult;
321 : }
322 :
323 : /************************************************************************/
324 : /* Eof() */
325 : /************************************************************************/
326 :
327 41113 : int VSIUnixStdioHandle::Eof()
328 :
329 : {
330 41113 : if( !bAtEOF )
331 40987 : bAtEOF = feof(fp);
332 :
333 41113 : if( bAtEOF )
334 1644 : return 1;
335 : else
336 39469 : return 0;
337 : }
338 :
339 : /************************************************************************/
340 : /* ==================================================================== */
341 : /* VSIUnixStdioFilesystemHandler */
342 : /* ==================================================================== */
343 : /************************************************************************/
344 :
345 : /************************************************************************/
346 : /* Open() */
347 : /************************************************************************/
348 :
349 : VSIVirtualHandle *
350 37865 : VSIUnixStdioFilesystemHandler::Open( const char *pszFilename,
351 : const char *pszAccess )
352 :
353 : {
354 37865 : FILE *fp = VSI_FOPEN64( pszFilename, pszAccess );
355 37865 : int nError = errno;
356 :
357 : VSIDebug3( "VSIUnixStdioFilesystemHandler::Open(\"%s\",\"%s\") = %p",
358 : pszFilename, pszAccess, fp );
359 :
360 37865 : if( fp == NULL )
361 : {
362 24490 : errno = nError;
363 24490 : return NULL;
364 : }
365 :
366 13375 : VSIUnixStdioHandle *poHandle = new VSIUnixStdioHandle;
367 :
368 13375 : poHandle->fp = fp;
369 13375 : poHandle->nOffset = 0;
370 13375 : poHandle->bLastOpWrite = FALSE;
371 13375 : poHandle->bLastOpRead = FALSE;
372 13375 : poHandle->bAtEOF = FALSE;
373 :
374 13375 : errno = nError;
375 13375 : return poHandle;
376 : }
377 :
378 : /************************************************************************/
379 : /* Stat() */
380 : /************************************************************************/
381 :
382 48964 : int VSIUnixStdioFilesystemHandler::Stat( const char * pszFilename,
383 : VSIStatBufL * pStatBuf )
384 :
385 : {
386 48964 : return( VSI_STAT64( pszFilename, pStatBuf ) );
387 : }
388 :
389 : /************************************************************************/
390 : /* Unlink() */
391 : /************************************************************************/
392 :
393 1752 : int VSIUnixStdioFilesystemHandler::Unlink( const char * pszFilename )
394 :
395 : {
396 1752 : return unlink( pszFilename );
397 : }
398 :
399 : /************************************************************************/
400 : /* Rename() */
401 : /************************************************************************/
402 :
403 9 : int VSIUnixStdioFilesystemHandler::Rename( const char *oldpath,
404 : const char *newpath )
405 :
406 : {
407 9 : return rename( oldpath, newpath );
408 : }
409 :
410 : /************************************************************************/
411 : /* Mkdir() */
412 : /************************************************************************/
413 :
414 21 : int VSIUnixStdioFilesystemHandler::Mkdir( const char * pszPathname,
415 : long nMode )
416 :
417 : {
418 21 : return mkdir( pszPathname, nMode );
419 : }
420 :
421 : /************************************************************************/
422 : /* Rmdir() */
423 : /************************************************************************/
424 :
425 10 : int VSIUnixStdioFilesystemHandler::Rmdir( const char * pszPathname )
426 :
427 : {
428 10 : return rmdir( pszPathname );
429 : }
430 :
431 : /************************************************************************/
432 : /* ReadDir() */
433 : /************************************************************************/
434 :
435 5398 : char **VSIUnixStdioFilesystemHandler::ReadDir( const char *pszPath )
436 :
437 : {
438 : DIR *hDir;
439 : struct dirent *psDirEntry;
440 5398 : char **papszDir = NULL;
441 :
442 5398 : if (strlen(pszPath) == 0)
443 3 : pszPath = ".";
444 :
445 5398 : if ( (hDir = opendir(pszPath)) != NULL )
446 : {
447 : /* In case of really big number of files in the directory, CSLAddString */
448 : /* can be slow (see #2158). We then directly build the list. */
449 4929 : int nItems=0;
450 4929 : int nAllocatedItems=0;
451 232542 : while( (psDirEntry = readdir(hDir)) != NULL )
452 : {
453 222684 : if (nItems == 0)
454 : {
455 4929 : papszDir = (char**) CPLCalloc(2,sizeof(char*));
456 4929 : nAllocatedItems = 1;
457 : }
458 217755 : else if (nItems >= nAllocatedItems)
459 : {
460 20953 : nAllocatedItems = nAllocatedItems * 2;
461 : papszDir = (char**)CPLRealloc(papszDir,
462 20953 : (nAllocatedItems+2)*sizeof(char*));
463 : }
464 :
465 222684 : papszDir[nItems] = CPLStrdup(psDirEntry->d_name);
466 222684 : papszDir[nItems+1] = NULL;
467 :
468 222684 : nItems++;
469 : }
470 :
471 4929 : closedir( hDir );
472 : }
473 : else
474 : {
475 : /* Should we generate an error???
476 : * For now we'll just return NULL (at the end of the function)
477 : */
478 : }
479 :
480 5398 : return papszDir;
481 : }
482 :
483 : /************************************************************************/
484 : /* VSIInstallLargeFileHandler() */
485 : /************************************************************************/
486 :
487 379 : void VSIInstallLargeFileHandler()
488 :
489 : {
490 379 : VSIFileManager::InstallHandler( "", new VSIUnixStdioFilesystemHandler );
491 379 : }
492 :
493 : #endif /* ndef WIN32 */
|