1 : /******************************************************************************
2 : * $Id: cpl_vsil.cpp 25340 2012-12-21 20:30:21Z rouault $
3 : *
4 : * Project: VSI Virtual File System
5 : * Purpose: Implementation VSI*L File API and other file system access
6 : * methods going through file virtualization.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
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
23 : * OR 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 : #include "cpl_vsi_virtual.h"
32 : #include "cpl_multiproc.h"
33 : #include "cpl_string.h"
34 : #include <string>
35 :
36 : CPL_CVSID("$Id: cpl_vsil.cpp 25340 2012-12-21 20:30:21Z rouault $");
37 :
38 : /************************************************************************/
39 : /* VSIReadDir() */
40 : /************************************************************************/
41 :
42 : /**
43 : * \brief Read names in a directory.
44 : *
45 : * This function abstracts access to directory contains. It returns a
46 : * list of strings containing the names of files, and directories in this
47 : * directory. The resulting string list becomes the responsibility of the
48 : * application and should be freed with CSLDestroy() when no longer needed.
49 : *
50 : * Note that no error is issued via CPLError() if the directory path is
51 : * invalid, though NULL is returned.
52 : *
53 : * This function used to be known as CPLReadDir(), but the old name is now
54 : * deprecated.
55 : *
56 : * @param pszPath the relative, or absolute path of a directory to read.
57 : * UTF-8 encoded.
58 : * @return The list of entries in the directory, or NULL if the directory
59 : * doesn't exist. Filenames are returned in UTF-8 encoding.
60 : */
61 :
62 13032 : char **VSIReadDir(const char *pszPath)
63 : {
64 : VSIFilesystemHandler *poFSHandler =
65 13032 : VSIFileManager::GetHandler( pszPath );
66 :
67 13032 : return poFSHandler->ReadDir( pszPath );
68 : }
69 :
70 : /************************************************************************/
71 : /* VSIReadRecursive() */
72 : /************************************************************************/
73 :
74 : typedef struct
75 : {
76 : char **papszFiles;
77 : int nCount;
78 : int i;
79 : char* pszPath;
80 : char* pszDisplayedPath;
81 0 : } VSIReadDirRecursiveTask;
82 :
83 : /**
84 : * \brief Read names in a directory recursively.
85 : *
86 : * This function abstracts access to directory contents and subdirectories.
87 : * It returns a list of strings containing the names of files and directories
88 : * in this directory and all subdirectories. The resulting string list becomes
89 : * the responsibility of the application and should be freed with CSLDestroy()
90 : * when no longer needed.
91 : *
92 : * Note that no error is issued via CPLError() if the directory path is
93 : * invalid, though NULL is returned.
94 : *
95 : * @param pszPath the relative, or absolute path of a directory to read.
96 : * UTF-8 encoded.
97 : *
98 : * @return The list of entries in the directory and subdirectories
99 : * or NULL if the directory doesn't exist. Filenames are returned in UTF-8
100 : * encoding.
101 : * @since GDAL 1.10.0
102 : *
103 : */
104 :
105 2 : char **VSIReadDirRecursive( const char *pszPathIn )
106 : {
107 2 : CPLStringList oFiles = NULL;
108 2 : char **papszFiles = NULL;
109 : VSIStatBufL psStatBuf;
110 2 : CPLString osTemp1, osTemp2;
111 2 : int i = 0;
112 2 : int nCount = -1;
113 :
114 2 : std::vector<VSIReadDirRecursiveTask> aoStack;
115 2 : char* pszPath = CPLStrdup(pszPathIn);
116 2 : char* pszDisplayedPath = NULL;
117 :
118 2004 : while(TRUE)
119 : {
120 2006 : if( nCount < 0 )
121 : {
122 : // get listing
123 1004 : papszFiles = VSIReadDir( pszPath );
124 :
125 : // get files and directories inside listing
126 1004 : nCount = papszFiles ? CSLCount( papszFiles ) : 0;
127 1004 : i = 0;
128 : }
129 :
130 2012 : for ( ; i < nCount; i++ )
131 : {
132 : // build complete file name for stat
133 1008 : osTemp1.clear();
134 1008 : osTemp1.append( pszPath );
135 1008 : osTemp1.append( "/" );
136 1008 : osTemp1.append( papszFiles[i] );
137 :
138 : // if is file, add it
139 1008 : if ( VSIStatL( osTemp1.c_str(), &psStatBuf ) != 0 )
140 0 : continue;
141 :
142 1008 : if( VSI_ISREG( psStatBuf.st_mode ) )
143 : {
144 6 : if( pszDisplayedPath )
145 : {
146 4 : osTemp1.clear();
147 4 : osTemp1.append( pszDisplayedPath );
148 4 : osTemp1.append( "/" );
149 4 : osTemp1.append( papszFiles[i] );
150 4 : oFiles.AddString( osTemp1 );
151 : }
152 : else
153 2 : oFiles.AddString( papszFiles[i] );
154 : }
155 1002 : else if ( VSI_ISDIR( psStatBuf.st_mode ) )
156 : {
157 : // add directory entry
158 1002 : osTemp2.clear();
159 1002 : if( pszDisplayedPath )
160 : {
161 1000 : osTemp2.append( pszDisplayedPath );
162 1000 : osTemp2.append( "/" );
163 : }
164 1002 : osTemp2.append( papszFiles[i] );
165 1002 : osTemp2.append( "/" );
166 1002 : oFiles.AddString( osTemp2.c_str() );
167 :
168 : VSIReadDirRecursiveTask sTask;
169 1002 : sTask.papszFiles = papszFiles;
170 1002 : sTask.nCount = nCount;
171 1002 : sTask.i = i;
172 1002 : sTask.pszPath = CPLStrdup(pszPath);
173 1002 : sTask.pszDisplayedPath = pszDisplayedPath ? CPLStrdup(pszDisplayedPath) : NULL;
174 1002 : aoStack.push_back(sTask);
175 :
176 1002 : CPLFree(pszPath);
177 1002 : pszPath = CPLStrdup( osTemp1.c_str() );
178 :
179 : char* pszDisplayedPathNew;
180 1002 : if( pszDisplayedPath )
181 1000 : pszDisplayedPathNew = CPLStrdup( CPLSPrintf("%s/%s", pszDisplayedPath, papszFiles[i]) );
182 : else
183 2 : pszDisplayedPathNew = CPLStrdup( papszFiles[i] );
184 1002 : CPLFree(pszDisplayedPath);
185 1002 : pszDisplayedPath = pszDisplayedPathNew;
186 :
187 1002 : i = 0;
188 1002 : papszFiles = NULL;
189 1002 : nCount = -1;
190 :
191 1002 : break;
192 : }
193 : }
194 :
195 2006 : if( nCount >= 0 )
196 : {
197 1004 : CSLDestroy( papszFiles );
198 :
199 1004 : if( aoStack.size() )
200 : {
201 1002 : int iLast = (int)aoStack.size() - 1;
202 1002 : CPLFree(pszPath);
203 1002 : CPLFree(pszDisplayedPath);
204 1002 : nCount = aoStack[iLast].nCount;
205 1002 : papszFiles = aoStack[iLast].papszFiles;
206 1002 : i = aoStack[iLast].i + 1;
207 1002 : pszPath = aoStack[iLast].pszPath;
208 1002 : pszDisplayedPath = aoStack[iLast].pszDisplayedPath;
209 :
210 1002 : aoStack.resize(iLast);
211 : }
212 : else
213 : break;
214 : }
215 : }
216 :
217 2 : CPLFree(pszPath);
218 2 : CPLFree(pszDisplayedPath);
219 :
220 2 : return oFiles.StealList();
221 : }
222 :
223 :
224 : /************************************************************************/
225 : /* CPLReadDir() */
226 : /* */
227 : /* This is present only to provide ABI compatability with older */
228 : /* versions. */
229 : /************************************************************************/
230 : #undef CPLReadDir
231 :
232 : CPL_C_START
233 : char CPL_DLL **CPLReadDir( const char *pszPath );
234 : CPL_C_END
235 :
236 0 : char **CPLReadDir( const char *pszPath )
237 : {
238 0 : return VSIReadDir(pszPath);
239 : }
240 :
241 : /************************************************************************/
242 : /* VSIMkdir() */
243 : /************************************************************************/
244 :
245 : /**
246 : * \brief Create a directory.
247 : *
248 : * Create a new directory with the indicated mode. The mode is ignored
249 : * on some platforms. A reasonable default mode value would be 0666.
250 : * This method goes through the VSIFileHandler virtualization and may
251 : * work on unusual filesystems such as in memory.
252 : *
253 : * Analog of the POSIX mkdir() function.
254 : *
255 : * @param pszPathname the path to the directory to create. UTF-8 encoded.
256 : * @param mode the permissions mode.
257 : *
258 : * @return 0 on success or -1 on an error.
259 : */
260 :
261 141 : int VSIMkdir( const char *pszPathname, long mode )
262 :
263 : {
264 : VSIFilesystemHandler *poFSHandler =
265 141 : VSIFileManager::GetHandler( pszPathname );
266 :
267 141 : return poFSHandler->Mkdir( pszPathname, mode );
268 : }
269 :
270 : /************************************************************************/
271 : /* VSIUnlink() */
272 : /*************************a***********************************************/
273 :
274 : /**
275 : * \brief Delete a file.
276 : *
277 : * Deletes a file object from the file system.
278 : *
279 : * This method goes through the VSIFileHandler virtualization and may
280 : * work on unusual filesystems such as in memory.
281 : *
282 : * Analog of the POSIX unlink() function.
283 : *
284 : * @param pszFilename the path of the file to be deleted. UTF-8 encoded.
285 : *
286 : * @return 0 on success or -1 on an error.
287 : */
288 :
289 9766 : int VSIUnlink( const char * pszFilename )
290 :
291 : {
292 : VSIFilesystemHandler *poFSHandler =
293 9766 : VSIFileManager::GetHandler( pszFilename );
294 :
295 9766 : return poFSHandler->Unlink( pszFilename );
296 : }
297 :
298 : /************************************************************************/
299 : /* VSIRename() */
300 : /************************************************************************/
301 :
302 : /**
303 : * \brief Rename a file.
304 : *
305 : * Renames a file object in the file system. It should be possible
306 : * to rename a file onto a new filesystem, but it is safest if this
307 : * function is only used to rename files that remain in the same directory.
308 : *
309 : * This method goes through the VSIFileHandler virtualization and may
310 : * work on unusual filesystems such as in memory.
311 : *
312 : * Analog of the POSIX rename() function.
313 : *
314 : * @param oldpath the name of the file to be renamed. UTF-8 encoded.
315 : * @param newpath the name the file should be given. UTF-8 encoded.
316 : *
317 : * @return 0 on success or -1 on an error.
318 : */
319 :
320 14 : int VSIRename( const char * oldpath, const char * newpath )
321 :
322 : {
323 : VSIFilesystemHandler *poFSHandler =
324 14 : VSIFileManager::GetHandler( oldpath );
325 :
326 14 : return poFSHandler->Rename( oldpath, newpath );
327 : }
328 :
329 : /************************************************************************/
330 : /* VSIRmdir() */
331 : /************************************************************************/
332 :
333 : /**
334 : * \brief Delete a directory.
335 : *
336 : * Deletes a directory object from the file system. On some systems
337 : * the directory must be empty before it can be deleted.
338 : *
339 : * This method goes through the VSIFileHandler virtualization and may
340 : * work on unusual filesystems such as in memory.
341 : *
342 : * Analog of the POSIX rmdir() function.
343 : *
344 : * @param pszDirname the path of the directory to be deleted. UTF-8 encoded.
345 : *
346 : * @return 0 on success or -1 on an error.
347 : */
348 :
349 450 : int VSIRmdir( const char * pszDirname )
350 :
351 : {
352 : VSIFilesystemHandler *poFSHandler =
353 450 : VSIFileManager::GetHandler( pszDirname );
354 :
355 450 : return poFSHandler->Rmdir( pszDirname );
356 : }
357 :
358 : /************************************************************************/
359 : /* VSIStatL() */
360 : /************************************************************************/
361 :
362 : /**
363 : * \brief Get filesystem object info.
364 : *
365 : * Fetches status information about a filesystem object (file, directory, etc).
366 : * The returned information is placed in the VSIStatBufL structure. For
367 : * portability only the st_size (size in bytes), and st_mode (file type).
368 : * This method is similar to VSIStat(), but will work on large files on
369 : * systems where this requires special calls.
370 : *
371 : * This method goes through the VSIFileHandler virtualization and may
372 : * work on unusual filesystems such as in memory.
373 : *
374 : * Analog of the POSIX stat() function.
375 : *
376 : * @param pszFilename the path of the filesystem object to be queried. UTF-8 encoded.
377 : * @param psStatBuf the structure to load with information.
378 : *
379 : * @return 0 on success or -1 on an error.
380 : */
381 :
382 12268 : int VSIStatL( const char * pszFilename, VSIStatBufL *psStatBuf )
383 :
384 : {
385 12268 : return VSIStatExL(pszFilename, psStatBuf, 0);
386 : }
387 :
388 :
389 : /************************************************************************/
390 : /* VSIStatExL() */
391 : /************************************************************************/
392 :
393 : /**
394 : * \brief Get filesystem object info.
395 : *
396 : * Fetches status information about a filesystem object (file, directory, etc).
397 : * The returned information is placed in the VSIStatBufL structure. For
398 : * portability only the st_size (size in bytes), and st_mode (file type).
399 : * This method is similar to VSIStat(), but will work on large files on
400 : * systems where this requires special calls.
401 : *
402 : * This method goes through the VSIFileHandler virtualization and may
403 : * work on unusual filesystems such as in memory.
404 : *
405 : * Analog of the POSIX stat() function, with an extra parameter to specify
406 : * which information is needed, which offers a potential for speed optimizations
407 : * on specialized and potentially slow virtual filesystem objects (/vsigzip/, /vsicurl/)
408 : *
409 : * @param pszFilename the path of the filesystem object to be queried. UTF-8 encoded.
410 : * @param psStatBuf the structure to load with information.
411 : * @param nFlags 0 to get all information, or VSI_STAT_EXISTS_FLAG, VSI_STAT_NATURE_FLAG or
412 : * VSI_STAT_SIZE_FLAG, or a combination of those to get partial info.
413 : *
414 : * @return 0 on success or -1 on an error.
415 : *
416 : * @since GDAL 1.8.0
417 : */
418 :
419 64637 : int VSIStatExL( const char * pszFilename, VSIStatBufL *psStatBuf, int nFlags )
420 :
421 : {
422 : char szAltPath[4];
423 : /* enable to work on "C:" as if it were "C:\" */
424 64637 : if( strlen(pszFilename) == 2 && pszFilename[1] == ':' )
425 : {
426 0 : szAltPath[0] = pszFilename[0];
427 0 : szAltPath[1] = pszFilename[1];
428 0 : szAltPath[2] = '\\';
429 0 : szAltPath[3] = '\0';
430 :
431 0 : pszFilename = szAltPath;
432 : }
433 :
434 : VSIFilesystemHandler *poFSHandler =
435 64637 : VSIFileManager::GetHandler( pszFilename );
436 :
437 64637 : if (nFlags == 0)
438 12268 : nFlags = VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG | VSI_STAT_SIZE_FLAG;
439 :
440 64637 : return poFSHandler->Stat( pszFilename, psStatBuf, nFlags );
441 : }
442 :
443 : /************************************************************************/
444 : /* VSIIsCaseSensitiveFS() */
445 : /************************************************************************/
446 :
447 : /**
448 : * \brief Returns if the filenames of the filesystem are case sensitive.
449 : *
450 : * This method retrieves to which filesystem belongs the passed filename
451 : * and return TRUE if the filenames of that filesystem are case sensitive.
452 : *
453 : * Currently, this will return FALSE only for Windows real filenames. Other
454 : * VSI virtual filesystems are case sensitive.
455 : *
456 : * This methods avoid ugly #ifndef WIN32 / #endif code, that is wrong when
457 : * dealing with virtual filenames.
458 : *
459 : * @param pszFilename the path of the filesystem object to be tested. UTF-8 encoded.
460 : *
461 : * @return TRUE if the filenames of the filesystem are case sensitive.
462 : *
463 : * @since GDAL 1.8.0
464 : */
465 11894 : int VSIIsCaseSensitiveFS( const char * pszFilename )
466 : {
467 : VSIFilesystemHandler *poFSHandler =
468 11894 : VSIFileManager::GetHandler( pszFilename );
469 :
470 11894 : return poFSHandler->IsCaseSensitive( pszFilename );
471 : }
472 :
473 : /************************************************************************/
474 : /* VSIFOpenL() */
475 : /************************************************************************/
476 :
477 : /**
478 : * \brief Open file.
479 : *
480 : * This function opens a file with the desired access. Large files (larger
481 : * than 2GB) should be supported. Binary access is always implied and
482 : * the "b" does not need to be included in the pszAccess string.
483 : *
484 : * Note that the "VSILFILE *" returned since GDAL 1.8.0 by this function is
485 : * *NOT* a standard C library FILE *, and cannot be used with any functions
486 : * other than the "VSI*L" family of functions. They aren't "real" FILE objects.
487 : *
488 : * On windows it is possible to define the configuration option
489 : * GDAL_FILE_IS_UTF8 to have pszFilename treated as being in the local
490 : * encoding instead of UTF-8, retoring the pre-1.8.0 behavior of VSIFOpenL().
491 : *
492 : * This method goes through the VSIFileHandler virtualization and may
493 : * work on unusual filesystems such as in memory.
494 : *
495 : * Analog of the POSIX fopen() function.
496 : *
497 : * @param pszFilename the file to open. UTF-8 encoded.
498 : * @param pszAccess access requested (ie. "r", "r+", "w".
499 : *
500 : * @return NULL on failure, or the file handle.
501 : */
502 :
503 100368 : VSILFILE *VSIFOpenL( const char * pszFilename, const char * pszAccess )
504 :
505 : {
506 : VSIFilesystemHandler *poFSHandler =
507 100368 : VSIFileManager::GetHandler( pszFilename );
508 :
509 100367 : VSILFILE* fp = (VSILFILE *) poFSHandler->Open( pszFilename, pszAccess );
510 :
511 : VSIDebug3( "VSIFOpenL(%s,%s) = %p", pszFilename, pszAccess, fp );
512 :
513 100368 : return fp;
514 : }
515 :
516 : /************************************************************************/
517 : /* VSIFCloseL() */
518 : /************************************************************************/
519 :
520 : /**
521 : * \brief Close file.
522 : *
523 : * This function closes the indicated file.
524 : *
525 : * This method goes through the VSIFileHandler virtualization and may
526 : * work on unusual filesystems such as in memory.
527 : *
528 : * Analog of the POSIX fclose() function.
529 : *
530 : * @param fp file handle opened with VSIFOpenL().
531 : *
532 : * @return 0 on success or -1 on failure.
533 : */
534 :
535 69980 : int VSIFCloseL( VSILFILE * fp )
536 :
537 : {
538 69980 : VSIVirtualHandle *poFileHandle = (VSIVirtualHandle *) fp;
539 :
540 : VSIDebug1( "VSICloseL(%p)", fp );
541 :
542 69980 : int nResult = poFileHandle->Close();
543 :
544 69980 : delete poFileHandle;
545 :
546 69980 : return nResult;
547 : }
548 :
549 : /************************************************************************/
550 : /* VSIFSeekL() */
551 : /************************************************************************/
552 :
553 : /**
554 : * \brief Seek to requested offset.
555 : *
556 : * Seek to the desired offset (nOffset) in the indicated file.
557 : *
558 : * This method goes through the VSIFileHandler virtualization and may
559 : * work on unusual filesystems such as in memory.
560 : *
561 : * Analog of the POSIX fseek() call.
562 : *
563 : * @param fp file handle opened with VSIFOpenL().
564 : * @param nOffset offset in bytes.
565 : * @param nWhence one of SEEK_SET, SEEK_CUR or SEEK_END.
566 : *
567 : * @return 0 on success or -1 one failure.
568 : */
569 :
570 3691452 : int VSIFSeekL( VSILFILE * fp, vsi_l_offset nOffset, int nWhence )
571 :
572 : {
573 3691452 : VSIVirtualHandle *poFileHandle = (VSIVirtualHandle *) fp;
574 :
575 3691452 : return poFileHandle->Seek( nOffset, nWhence );
576 : }
577 :
578 : /************************************************************************/
579 : /* VSIFTellL() */
580 : /************************************************************************/
581 :
582 : /**
583 : * \brief Tell current file offset.
584 : *
585 : * Returns the current file read/write offset in bytes from the beginning of
586 : * the file.
587 : *
588 : * This method goes through the VSIFileHandler virtualization and may
589 : * work on unusual filesystems such as in memory.
590 : *
591 : * Analog of the POSIX ftell() call.
592 : *
593 : * @param fp file handle opened with VSIFOpenL().
594 : *
595 : * @return file offset in bytes.
596 : */
597 :
598 1012464 : vsi_l_offset VSIFTellL( VSILFILE * fp )
599 :
600 : {
601 1012464 : VSIVirtualHandle *poFileHandle = (VSIVirtualHandle *) fp;
602 :
603 1012464 : return poFileHandle->Tell();
604 : }
605 :
606 : /************************************************************************/
607 : /* VSIRewindL() */
608 : /************************************************************************/
609 :
610 631 : void VSIRewindL( VSILFILE * fp )
611 :
612 : {
613 631 : VSIFSeekL( fp, 0, SEEK_SET );
614 631 : }
615 :
616 : /************************************************************************/
617 : /* VSIFFlushL() */
618 : /************************************************************************/
619 :
620 : /**
621 : * \brief Flush pending writes to disk.
622 : *
623 : * For files in write or update mode and on filesystem types where it is
624 : * applicable, all pending output on the file is flushed to the physical disk.
625 : *
626 : * This method goes through the VSIFileHandler virtualization and may
627 : * work on unusual filesystems such as in memory.
628 : *
629 : * Analog of the POSIX fflush() call.
630 : *
631 : * @param fp file handle opened with VSIFOpenL().
632 : *
633 : * @return 0 on success or -1 on error.
634 : */
635 :
636 4339 : int VSIFFlushL( VSILFILE * fp )
637 :
638 : {
639 4339 : VSIVirtualHandle *poFileHandle = (VSIVirtualHandle *) fp;
640 :
641 4339 : return poFileHandle->Flush();
642 : }
643 :
644 : /************************************************************************/
645 : /* VSIFReadL() */
646 : /************************************************************************/
647 :
648 : /**
649 : * \brief Read bytes from file.
650 : *
651 : * Reads nCount objects of nSize bytes from the indicated file at the
652 : * current offset into the indicated buffer.
653 : *
654 : * This method goes through the VSIFileHandler virtualization and may
655 : * work on unusual filesystems such as in memory.
656 : *
657 : * Analog of the POSIX fread() call.
658 : *
659 : * @param pBuffer the buffer into which the data should be read (at least
660 : * nCount * nSize bytes in size.
661 : * @param nSize size of objects to read in bytes.
662 : * @param nCount number of objects to read.
663 : * @param fp file handle opened with VSIFOpenL().
664 : *
665 : * @return number of objects successfully read.
666 : */
667 :
668 7340099 : size_t VSIFReadL( void * pBuffer, size_t nSize, size_t nCount, VSILFILE * fp )
669 :
670 : {
671 7340099 : VSIVirtualHandle *poFileHandle = (VSIVirtualHandle *) fp;
672 :
673 7340099 : return poFileHandle->Read( pBuffer, nSize, nCount );
674 : }
675 :
676 :
677 : /************************************************************************/
678 : /* VSIFReadMultiRangeL() */
679 : /************************************************************************/
680 :
681 : /**
682 : * \brief Read several ranges of bytes from file.
683 : *
684 : * Reads nRanges objects of panSizes[i] bytes from the indicated file at the
685 : * offset panOffsets[i] into the buffer ppData[i].
686 : *
687 : * Ranges must be sorted in ascending start offset, and must not overlap each
688 : * other.
689 : *
690 : * This method goes through the VSIFileHandler virtualization and may
691 : * work on unusual filesystems such as in memory or /vsicurl/.
692 : *
693 : * @param nRanges number of ranges to read.
694 : * @param ppData array of nRanges buffer into which the data should be read
695 : * (ppData[i] must be at list panSizes[i] bytes).
696 : * @param panOffsets array of nRanges offsets at which the data should be read.
697 : * @param panSizes array of nRanges sizes of objects to read (in bytes).
698 : * @param fp file handle opened with VSIFOpenL().
699 : *
700 : * @return 0 in case of success, -1 otherwise.
701 : * @since GDAL 1.9.0
702 : */
703 :
704 1 : int VSIFReadMultiRangeL( int nRanges, void ** ppData,
705 : const vsi_l_offset* panOffsets,
706 : const size_t* panSizes, VSILFILE * fp )
707 : {
708 1 : VSIVirtualHandle *poFileHandle = (VSIVirtualHandle *) fp;
709 :
710 1 : return poFileHandle->ReadMultiRange( nRanges, ppData, panOffsets, panSizes );
711 : }
712 :
713 : /************************************************************************/
714 : /* VSIFWriteL() */
715 : /************************************************************************/
716 :
717 : /**
718 : * \brief Write bytes to file.
719 : *
720 : * Writess nCount objects of nSize bytes to the indicated file at the
721 : * current offset into the indicated buffer.
722 : *
723 : * This method goes through the VSIFileHandler virtualization and may
724 : * work on unusual filesystems such as in memory.
725 : *
726 : * Analog of the POSIX fwrite() call.
727 : *
728 : * @param pBuffer the buffer from which the data should be written (at least
729 : * nCount * nSize bytes in size.
730 : * @param nSize size of objects to read in bytes.
731 : * @param nCount number of objects to read.
732 : * @param fp file handle opened with VSIFOpenL().
733 : *
734 : * @return number of objects successfully written.
735 : */
736 :
737 2487487 : size_t VSIFWriteL( const void *pBuffer, size_t nSize, size_t nCount, VSILFILE *fp )
738 :
739 : {
740 2487487 : VSIVirtualHandle *poFileHandle = (VSIVirtualHandle *) fp;
741 :
742 2487487 : return poFileHandle->Write( pBuffer, nSize, nCount );
743 : }
744 :
745 : /************************************************************************/
746 : /* VSIFEofL() */
747 : /************************************************************************/
748 :
749 : /**
750 : * \brief Test for end of file.
751 : *
752 : * Returns TRUE (non-zero) if an end-of-file condition occured during the
753 : * previous read operation. The end-of-file flag is cleared by a successfull
754 : * VSIFSeekL() call.
755 : *
756 : * This method goes through the VSIFileHandler virtualization and may
757 : * work on unusual filesystems such as in memory.
758 : *
759 : * Analog of the POSIX feof() call.
760 : *
761 : * @param fp file handle opened with VSIFOpenL().
762 : *
763 : * @return TRUE if at EOF else FALSE.
764 : */
765 :
766 104855 : int VSIFEofL( VSILFILE * fp )
767 :
768 : {
769 104855 : VSIVirtualHandle *poFileHandle = (VSIVirtualHandle *) fp;
770 :
771 104855 : return poFileHandle->Eof();
772 : }
773 :
774 : /************************************************************************/
775 : /* VSIFTruncateL() */
776 : /************************************************************************/
777 :
778 : /**
779 : * \brief Truncate/expand the file to the specified size
780 :
781 : * This method goes through the VSIFileHandler virtualization and may
782 : * work on unusual filesystems such as in memory.
783 : *
784 : * Analog of the POSIX ftruncate() call.
785 : *
786 : * @param fp file handle opened with VSIFOpenL().
787 : * @param nNewSize new size in bytes.
788 : *
789 : * @return 0 on success
790 : * @since GDAL 1.9.0
791 : */
792 :
793 102 : int VSIFTruncateL( VSILFILE * fp, vsi_l_offset nNewSize )
794 :
795 : {
796 102 : VSIVirtualHandle *poFileHandle = (VSIVirtualHandle *) fp;
797 :
798 102 : return poFileHandle->Truncate(nNewSize);
799 : }
800 :
801 : /************************************************************************/
802 : /* VSIFPrintfL() */
803 : /************************************************************************/
804 :
805 : /**
806 : * \brief Formatted write to file.
807 : *
808 : * Provides fprintf() style formatted output to a VSI*L file. This formats
809 : * an internal buffer which is written using VSIFWriteL().
810 : *
811 : * Analog of the POSIX fprintf() call.
812 : *
813 : * @param fp file handle opened with VSIFOpenL().
814 : * @param pszFormat the printf style format string.
815 : *
816 : * @return the number of bytes written or -1 on an error.
817 : */
818 :
819 27086 : int VSIFPrintfL( VSILFILE *fp, const char *pszFormat, ... )
820 :
821 : {
822 : va_list args;
823 27086 : CPLString osResult;
824 :
825 27086 : va_start( args, pszFormat );
826 27086 : osResult.vPrintf( pszFormat, args );
827 27086 : va_end( args );
828 :
829 27086 : return VSIFWriteL( osResult.c_str(), 1, osResult.length(), fp );
830 : }
831 :
832 : /************************************************************************/
833 : /* VSIFPutcL() */
834 : /************************************************************************/
835 :
836 181 : int VSIFPutcL( int nChar, VSILFILE * fp )
837 :
838 : {
839 181 : unsigned char cChar = (unsigned char)nChar;
840 181 : return VSIFWriteL(&cChar, 1, 1, fp);
841 : }
842 :
843 : /************************************************************************/
844 : /* ==================================================================== */
845 : /* VSIFileManager() */
846 : /* ==================================================================== */
847 : /************************************************************************/
848 :
849 : /*
850 : ** Notes on Multithreading:
851 : **
852 : ** The VSIFileManager maintains a list of file type handlers (mem, large
853 : ** file, etc). It should be thread safe as long as all the handlers are
854 : ** instantiated before multiple threads begin to operate.
855 : **/
856 :
857 : /************************************************************************/
858 : /* VSIFileManager() */
859 : /************************************************************************/
860 :
861 712 : VSIFileManager::VSIFileManager()
862 :
863 : {
864 712 : poDefaultHandler = NULL;
865 712 : }
866 :
867 : /************************************************************************/
868 : /* ~VSIFileManager() */
869 : /************************************************************************/
870 :
871 687 : VSIFileManager::~VSIFileManager()
872 : {
873 687 : std::map<std::string,VSIFilesystemHandler*>::const_iterator iter;
874 :
875 8244 : for( iter = oHandlers.begin();
876 : iter != oHandlers.end();
877 : ++iter )
878 : {
879 7557 : delete iter->second;
880 : }
881 :
882 687 : delete poDefaultHandler;
883 687 : }
884 :
885 :
886 : /************************************************************************/
887 : /* Get() */
888 : /************************************************************************/
889 :
890 : static VSIFileManager *poManager = NULL;
891 :
892 210773 : VSIFileManager *VSIFileManager::Get()
893 :
894 : {
895 : static void* hMutex = NULL;
896 : static volatile int nConstructerPID = 0;
897 210773 : if( poManager != NULL )
898 : {
899 210061 : if( nConstructerPID != 0 )
900 : {
901 8544 : int nCurrentPID = (int)CPLGetPID();
902 8544 : if( nConstructerPID != nCurrentPID )
903 : {
904 : //printf("Thread %d: Waiting for VSIFileManager to be finished by other thread.\n", nCurrentPID);
905 : {
906 0 : CPLMutexHolder oHolder( &hMutex );
907 : }
908 : //printf("Thread %d: End of wait for VSIFileManager construction to be finished\n", nCurrentPID);
909 0 : CPLAssert(nConstructerPID == 0);
910 : }
911 : }
912 210061 : return poManager;
913 : }
914 :
915 712 : CPLMutexHolder oHolder2( &hMutex );
916 712 : if( poManager == NULL )
917 : {
918 712 : nConstructerPID = (int)CPLGetPID();
919 : //printf("Thread %d: VSIFileManager in construction\n", nConstructerPID);
920 712 : poManager = new VSIFileManager;
921 712 : VSIInstallLargeFileHandler();
922 712 : VSIInstallSubFileHandler();
923 712 : VSIInstallMemFileHandler();
924 : #ifdef HAVE_LIBZ
925 712 : VSIInstallGZipFileHandler();
926 712 : VSIInstallZipFileHandler();
927 : #endif
928 : #ifdef HAVE_CURL
929 712 : VSIInstallCurlFileHandler();
930 712 : VSIInstallCurlStreamingFileHandler();
931 : #endif
932 712 : VSIInstallStdinHandler();
933 712 : VSIInstallStdoutHandler();
934 712 : VSIInstallSparseFileHandler();
935 712 : VSIInstallTarFileHandler();
936 : //printf("Thread %d: VSIFileManager construction finished\n", nConstructerPID);
937 712 : nConstructerPID = 0;
938 : }
939 :
940 712 : return poManager;
941 : }
942 :
943 : /************************************************************************/
944 : /* GetHandler() */
945 : /************************************************************************/
946 :
947 202229 : VSIFilesystemHandler *VSIFileManager::GetHandler( const char *pszPath )
948 :
949 : {
950 202229 : VSIFileManager *poThis = Get();
951 202229 : std::map<std::string,VSIFilesystemHandler*>::const_iterator iter;
952 202229 : int nPathLen = strlen(pszPath);
953 :
954 2059918 : for( iter = poThis->oHandlers.begin();
955 : iter != poThis->oHandlers.end();
956 : ++iter )
957 : {
958 1906034 : const char* pszIterKey = iter->first.c_str();
959 1906036 : int nIterKeyLen = iter->first.size();
960 1906025 : if( strncmp(pszPath,pszIterKey,nIterKeyLen) == 0 )
961 47651 : return iter->second;
962 :
963 : /* "/vsimem\foo" should be handled as "/vsimem/foo" */
964 5052227 : if (nIterKeyLen && nPathLen > nIterKeyLen &&
965 1596927 : pszIterKey[nIterKeyLen-1] == '/' &&
966 1596926 : pszPath[nIterKeyLen-1] == '\\' &&
967 : strncmp(pszPath,pszIterKey,nIterKeyLen-1) == 0 )
968 4 : return iter->second;
969 :
970 : /* /vsimem should be treated as a match for /vsimem/ */
971 1858370 : if( nPathLen == nIterKeyLen - 1
972 : && strncmp(pszPath,pszIterKey,nIterKeyLen-1) == 0 )
973 681 : return iter->second;
974 : }
975 :
976 153892 : return poThis->poDefaultHandler;
977 : }
978 :
979 : /************************************************************************/
980 : /* InstallHandler() */
981 : /************************************************************************/
982 :
983 8544 : void VSIFileManager::InstallHandler( const std::string& osPrefix,
984 : VSIFilesystemHandler *poHandler )
985 :
986 : {
987 8544 : if( osPrefix == "" )
988 712 : Get()->poDefaultHandler = poHandler;
989 : else
990 7832 : Get()->oHandlers[osPrefix] = poHandler;
991 8544 : }
992 :
993 : /************************************************************************/
994 : /* VSICleanupFileManager() */
995 : /************************************************************************/
996 :
997 1033 : void VSICleanupFileManager()
998 :
999 : {
1000 1033 : if( poManager )
1001 : {
1002 687 : delete poManager;
1003 687 : poManager = NULL;
1004 : }
1005 1033 : }
1006 :
1007 : /************************************************************************/
1008 : /* ReadMultiRange() */
1009 : /************************************************************************/
1010 :
1011 0 : int VSIVirtualHandle::ReadMultiRange( int nRanges, void ** ppData,
1012 : const vsi_l_offset* panOffsets,
1013 : const size_t* panSizes )
1014 : {
1015 0 : int nRet = 0;
1016 0 : vsi_l_offset nCurOffset = Tell();
1017 0 : for(int i=0;i<nRanges;i++)
1018 : {
1019 0 : if (Seek(panOffsets[i], SEEK_SET) < 0)
1020 : {
1021 0 : nRet = -1;
1022 0 : break;
1023 : }
1024 :
1025 0 : size_t nRead = Read(ppData[i], 1, panSizes[i]);
1026 0 : if (panSizes[i] != nRead)
1027 : {
1028 0 : nRet = -1;
1029 0 : break;
1030 : }
1031 : }
1032 :
1033 0 : Seek(nCurOffset, SEEK_SET);
1034 :
1035 0 : return nRet;
1036 : }
|