1 : /******************************************************************************
2 : * $Id: cpl_vsil.cpp 17758 2009-10-05 17:19:23Z 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_string.h"
33 : #include <string>
34 :
35 : CPL_CVSID("$Id: cpl_vsil.cpp 17758 2009-10-05 17:19:23Z rouault $");
36 :
37 : /************************************************************************/
38 : /* VSIReadDir() */
39 : /************************************************************************/
40 :
41 : /**
42 : * \brief Read names in a directory.
43 : *
44 : * This function abstracts access to directory contains. It returns a
45 : * list of strings containing the names of files, and directories in this
46 : * directory. The resulting string list becomes the responsibility of the
47 : * application and should be freed with CSLDestroy() when no longer needed.
48 : *
49 : * Note that no error is issued via CPLError() if the directory path is
50 : * invalid, though NULL is returned.
51 : *
52 : * This function used to be known as CPLReadDir(), but the old name is now
53 : * deprecated.
54 : *
55 : * @param pszPath the relative, or absolute path of a directory to read.
56 : * @return The list of entries in the directory, or NULL if the directory
57 : * doesn't exist.
58 : */
59 :
60 5433 : char **VSIReadDir(const char *pszPath)
61 : {
62 : VSIFilesystemHandler *poFSHandler =
63 5433 : VSIFileManager::GetHandler( pszPath );
64 :
65 5433 : return poFSHandler->ReadDir( pszPath );
66 : }
67 :
68 : /************************************************************************/
69 : /* CPLReadDir() */
70 : /* */
71 : /* This is present only to provide ABI compatability with older */
72 : /* versions. */
73 : /************************************************************************/
74 : #undef CPLReadDir
75 :
76 : CPL_C_START
77 : char CPL_DLL **CPLReadDir( const char *pszPath );
78 : CPL_C_END
79 :
80 0 : char **CPLReadDir( const char *pszPath )
81 : {
82 0 : return VSIReadDir(pszPath);
83 : }
84 :
85 : /************************************************************************/
86 : /* VSIMkdir() */
87 : /************************************************************************/
88 :
89 : /**
90 : * \brief Create a directory.
91 : *
92 : * Create a new directory with the indicated mode. The mode is ignored
93 : * on some platforms. A reasonable default mode value would be 0666.
94 : * This method goes through the VSIFileHandler virtualization and may
95 : * work on unusual filesystems such as in memory.
96 : *
97 : * Analog of the POSIX mkdir() function.
98 : *
99 : * @param pszPathname the path to the directory to create.
100 : * @param mode the permissions mode.
101 : *
102 : * @return 0 on success or -1 on an error.
103 : */
104 :
105 21 : int VSIMkdir( const char *pszPathname, long mode )
106 :
107 : {
108 : VSIFilesystemHandler *poFSHandler =
109 21 : VSIFileManager::GetHandler( pszPathname );
110 :
111 21 : return poFSHandler->Mkdir( pszPathname, mode );
112 : }
113 :
114 : /************************************************************************/
115 : /* VSIUnlink() */
116 : /*************************a***********************************************/
117 :
118 : /**
119 : * \brief Delete a file.
120 : *
121 : * Deletes a file object from the file system.
122 : *
123 : * This method goes through the VSIFileHandler virtualization and may
124 : * work on unusual filesystems such as in memory.
125 : *
126 : * Analog of the POSIX unlink() function.
127 : *
128 : * @param pszFilename the path of the file to be deleted.
129 : *
130 : * @return 0 on success or -1 on an error.
131 : */
132 :
133 1847 : int VSIUnlink( const char * pszFilename )
134 :
135 : {
136 : VSIFilesystemHandler *poFSHandler =
137 1847 : VSIFileManager::GetHandler( pszFilename );
138 :
139 1847 : return poFSHandler->Unlink( pszFilename );
140 : }
141 :
142 : /************************************************************************/
143 : /* VSIRename() */
144 : /************************************************************************/
145 :
146 : /**
147 : * \brief Rename a file.
148 : *
149 : * Renames a file object in the file system. It should be possible
150 : * to rename a file onto a new filesystem, but it is safest if this
151 : * function is only used to rename files that remain in the same directory.
152 : *
153 : * This method goes through the VSIFileHandler virtualization and may
154 : * work on unusual filesystems such as in memory.
155 : *
156 : * Analog of the POSIX rename() function.
157 : *
158 : * @param oldpath the name of the file to be renamed.
159 : * @param newpath the name the file should be given.
160 : *
161 : * @return 0 on success or -1 on an error.
162 : */
163 :
164 9 : int VSIRename( const char * oldpath, const char * newpath )
165 :
166 : {
167 : VSIFilesystemHandler *poFSHandler =
168 9 : VSIFileManager::GetHandler( oldpath );
169 :
170 9 : return poFSHandler->Rename( oldpath, newpath );
171 : }
172 :
173 : /************************************************************************/
174 : /* VSIRmdir() */
175 : /************************************************************************/
176 :
177 : /**
178 : * \brief Delete a directory.
179 : *
180 : * Deletes a directory object from the file system. On some systems
181 : * the directory must be empty before it can be deleted.
182 : *
183 : * This method goes through the VSIFileHandler virtualization and may
184 : * work on unusual filesystems such as in memory.
185 : *
186 : * Analog of the POSIX rmdir() function.
187 : *
188 : * @param pszDirname the path of the directory to be deleted.
189 : *
190 : * @return 0 on success or -1 on an error.
191 : */
192 :
193 10 : int VSIRmdir( const char * pszDirname )
194 :
195 : {
196 : VSIFilesystemHandler *poFSHandler =
197 10 : VSIFileManager::GetHandler( pszDirname );
198 :
199 10 : return poFSHandler->Rmdir( pszDirname );
200 : }
201 :
202 : /************************************************************************/
203 : /* VSIStatL() */
204 : /************************************************************************/
205 :
206 : /**
207 : * \brief Get filesystem object info.
208 : *
209 : * Fetches status information about a filesystem object (file, directory, etc).
210 : * The returned information is placed in the VSIStatBufL structure. For
211 : * portability only the st_size (size in bytes), and st_mode (file type).
212 : * This method is similar to VSIStat(), but will work on large files on
213 : * systems where this requires special calls.
214 : *
215 : * This method goes through the VSIFileHandler virtualization and may
216 : * work on unusual filesystems such as in memory.
217 : *
218 : * Analog of the POSIX stat() function.
219 : *
220 : * @param pszFilename the path of the filesystem object to be queried.
221 : * @param psStatBuf the structure to load with information.
222 : *
223 : * @return 0 on success or -1 on an error.
224 : */
225 :
226 49936 : int VSIStatL( const char * pszFilename, VSIStatBufL *psStatBuf )
227 :
228 : {
229 : char szAltPath[4];
230 : /* enable to work on "C:" as if it were "C:\" */
231 49936 : if( strlen(pszFilename) == 2 && pszFilename[1] == ':' )
232 : {
233 0 : szAltPath[0] = pszFilename[0];
234 0 : szAltPath[1] = pszFilename[1];
235 0 : szAltPath[2] = '\\';
236 0 : szAltPath[3] = '\0';
237 :
238 0 : pszFilename = szAltPath;
239 : }
240 :
241 : VSIFilesystemHandler *poFSHandler =
242 49936 : VSIFileManager::GetHandler( pszFilename );
243 :
244 49936 : return poFSHandler->Stat( pszFilename, psStatBuf );
245 : }
246 :
247 : /************************************************************************/
248 : /* VSIFOpenL() */
249 : /************************************************************************/
250 :
251 : /**
252 : * \brief Open file.
253 : *
254 : * This function opens a file with the desired access. Large files (larger
255 : * than 2GB) should be supported. Binary access is always implied and
256 : * the "b" does not need to be included in the pszAccess string.
257 : *
258 : * Note that the "FILE *" returned by this function is not really a
259 : * standard C library FILE *, and cannot be used with any functions other
260 : * than the "VSI*L" family of functions. They aren't "real" FILE objects.
261 : *
262 : * This method goes through the VSIFileHandler virtualization and may
263 : * work on unusual filesystems such as in memory.
264 : *
265 : * Analog of the POSIX fopen() function.
266 : *
267 : * @param pszFilename the file to open.
268 : * @param pszAccess access requested (ie. "r", "r+", "w".
269 : *
270 : * @return NULL on failure, or the file handle.
271 : */
272 :
273 38938 : FILE *VSIFOpenL( const char * pszFilename, const char * pszAccess )
274 :
275 : {
276 : VSIFilesystemHandler *poFSHandler =
277 38938 : VSIFileManager::GetHandler( pszFilename );
278 :
279 38938 : FILE* fp = (FILE *) poFSHandler->Open( pszFilename, pszAccess );
280 :
281 : VSIDebug3( "VSIFOpenL(%s,%s) = %p", pszFilename, pszAccess, fp );
282 :
283 38938 : return fp;
284 : }
285 :
286 : /************************************************************************/
287 : /* VSIFCloseL() */
288 : /************************************************************************/
289 :
290 : /**
291 : * \brief Close file.
292 : *
293 : * This function closes the indicated file.
294 : *
295 : * This method goes through the VSIFileHandler virtualization and may
296 : * work on unusual filesystems such as in memory.
297 : *
298 : * Analog of the POSIX fclose() function.
299 : *
300 : * @param fp file handle opened with VSIFOpenL().
301 : *
302 : * @return 0 on success or -1 on failure.
303 : */
304 :
305 13964 : int VSIFCloseL( FILE * fp )
306 :
307 : {
308 13964 : VSIVirtualHandle *poFileHandle = (VSIVirtualHandle *) fp;
309 :
310 : VSIDebug1( "VSICloseL(%p)", fp );
311 :
312 13964 : int nResult = poFileHandle->Close();
313 :
314 13964 : delete poFileHandle;
315 :
316 13964 : return nResult;
317 : }
318 :
319 : /************************************************************************/
320 : /* VSIFSeekL() */
321 : /************************************************************************/
322 :
323 : /**
324 : * \brief Seek to requested offset.
325 : *
326 : * Seek to the desired offset (nOffset) in the indicated file.
327 : *
328 : * This method goes through the VSIFileHandler virtualization and may
329 : * work on unusual filesystems such as in memory.
330 : *
331 : * Analog of the POSIX fseek() call.
332 : *
333 : * @param fp file handle opened with VSIFOpenL().
334 : * @param nOffset offset in bytes.
335 : * @param nWhence one of SEEK_SET, SEEK_CUR or SEEK_END.
336 : *
337 : * @return 0 on success or -1 one failure.
338 : */
339 :
340 475699 : int VSIFSeekL( FILE * fp, vsi_l_offset nOffset, int nWhence )
341 :
342 : {
343 475699 : VSIVirtualHandle *poFileHandle = (VSIVirtualHandle *) fp;
344 :
345 475699 : return poFileHandle->Seek( nOffset, nWhence );
346 : }
347 :
348 : /************************************************************************/
349 : /* VSIFTellL() */
350 : /************************************************************************/
351 :
352 : /**
353 : * \brief Tell current file offset.
354 : *
355 : * Returns the current file read/write offset in bytes from the beginning of
356 : * the file.
357 : *
358 : * This method goes through the VSIFileHandler virtualization and may
359 : * work on unusual filesystems such as in memory.
360 : *
361 : * Analog of the POSIX ftell() call.
362 : *
363 : * @param fp file handle opened with VSIFOpenL().
364 : *
365 : * @return file offset in bytes.
366 : */
367 :
368 585824 : vsi_l_offset VSIFTellL( FILE * fp )
369 :
370 : {
371 585824 : VSIVirtualHandle *poFileHandle = (VSIVirtualHandle *) fp;
372 :
373 585824 : return poFileHandle->Tell();
374 : }
375 :
376 : /************************************************************************/
377 : /* VSIRewindL() */
378 : /************************************************************************/
379 :
380 59 : void VSIRewindL( FILE * fp )
381 :
382 : {
383 59 : VSIFSeekL( fp, 0, SEEK_SET );
384 59 : }
385 :
386 : /************************************************************************/
387 : /* VSIFFlushL() */
388 : /************************************************************************/
389 :
390 : /**
391 : * \brief Flush pending writes to disk.
392 : *
393 : * For files in write or update mode and on filesystem types where it is
394 : * applicable, all pending output on the file is flushed to the physical disk.
395 : *
396 : * This method goes through the VSIFileHandler virtualization and may
397 : * work on unusual filesystems such as in memory.
398 : *
399 : * Analog of the POSIX fflush() call.
400 : *
401 : * @param fp file handle opened with VSIFOpenL().
402 : *
403 : * @return 0 on success or -1 on error.
404 : */
405 :
406 527 : int VSIFFlushL( FILE * fp )
407 :
408 : {
409 527 : VSIVirtualHandle *poFileHandle = (VSIVirtualHandle *) fp;
410 :
411 527 : return poFileHandle->Flush();
412 : }
413 :
414 : /************************************************************************/
415 : /* VSIFReadL() */
416 : /************************************************************************/
417 :
418 : /**
419 : * \brief Read bytes from file.
420 : *
421 : * Reads nCount objects of nSize bytes from the indicated file at the
422 : * current offset into the indicated buffer.
423 : *
424 : * This method goes through the VSIFileHandler virtualization and may
425 : * work on unusual filesystems such as in memory.
426 : *
427 : * Analog of the POSIX fread() call.
428 : *
429 : * @param pBuffer the buffer into which the data should be read (at least
430 : * nCount * nSize bytes in size.
431 : * @param nSize size of objects to read in bytes.
432 : * @param nCount number of objects to read.
433 : * @param fp file handle opened with VSIFOpenL().
434 : *
435 : * @return number of objects successfully read.
436 : */
437 :
438 1289733 : size_t VSIFReadL( void * pBuffer, size_t nSize, size_t nCount, FILE * fp )
439 :
440 : {
441 1289733 : VSIVirtualHandle *poFileHandle = (VSIVirtualHandle *) fp;
442 :
443 1289733 : return poFileHandle->Read( pBuffer, nSize, nCount );
444 : }
445 :
446 : /************************************************************************/
447 : /* VSIFWriteL() */
448 : /************************************************************************/
449 :
450 : /**
451 : * \brief Write bytes to file.
452 : *
453 : * Writess nCount objects of nSize bytes to the indicated file at the
454 : * current offset into the indicated buffer.
455 : *
456 : * This method goes through the VSIFileHandler virtualization and may
457 : * work on unusual filesystems such as in memory.
458 : *
459 : * Analog of the POSIX fwrite() call.
460 : *
461 : * @param pBuffer the buffer from which the data should be written (at least
462 : * nCount * nSize bytes in size.
463 : * @param nSize size of objects to read in bytes.
464 : * @param nCount number of objects to read.
465 : * @param fp file handle opened with VSIFOpenL().
466 : *
467 : * @return number of objects successfully written.
468 : */
469 :
470 1632903 : size_t VSIFWriteL( const void *pBuffer, size_t nSize, size_t nCount, FILE *fp )
471 :
472 : {
473 1632903 : VSIVirtualHandle *poFileHandle = (VSIVirtualHandle *) fp;
474 :
475 1632903 : return poFileHandle->Write( pBuffer, nSize, nCount );
476 : }
477 :
478 : /************************************************************************/
479 : /* VSIFEofL() */
480 : /************************************************************************/
481 :
482 : /**
483 : * \brief Test for end of file.
484 : *
485 : * Returns TRUE (non-zero) if the file read/write offset is currently at the
486 : * end of the file.
487 : *
488 : * This method goes through the VSIFileHandler virtualization and may
489 : * work on unusual filesystems such as in memory.
490 : *
491 : * Analog of the POSIX feof() call.
492 : *
493 : * @param fp file handle opened with VSIFOpenL().
494 : *
495 : * @return TRUE if at EOF else FALSE.
496 : */
497 :
498 44819 : int VSIFEofL( FILE * fp )
499 :
500 : {
501 44819 : VSIVirtualHandle *poFileHandle = (VSIVirtualHandle *) fp;
502 :
503 44819 : return poFileHandle->Eof();
504 : }
505 :
506 : /************************************************************************/
507 : /* VSIFPrintfL() */
508 : /************************************************************************/
509 :
510 : /**
511 : * \brief Formatted write to file.
512 : *
513 : * Provides fprintf() style formatted output to a VSI*L file. This formats
514 : * an internal buffer which is written using VSIFWriteL().
515 : *
516 : * Analog of the POSIX fprintf() call.
517 : *
518 : * @param fp file handle opened with VSIFOpenL().
519 : * @param pszFormat the printf style format string.
520 : *
521 : * @return the number of bytes written or -1 on an error.
522 : */
523 :
524 3430 : int VSIFPrintfL( FILE *fp, const char *pszFormat, ... )
525 :
526 : {
527 : va_list args;
528 3430 : CPLString osResult;
529 :
530 3430 : va_start( args, pszFormat );
531 3430 : osResult.vPrintf( pszFormat, args );
532 3430 : va_end( args );
533 :
534 3430 : return VSIFWriteL( osResult.c_str(), 1, osResult.length(), fp );
535 : }
536 :
537 : /************************************************************************/
538 : /* VSIFPutcL() */
539 : /************************************************************************/
540 :
541 0 : int VSIFPutcL( int nChar, FILE * fp )
542 :
543 : {
544 0 : unsigned char cChar = (unsigned char)nChar;
545 0 : return VSIFWriteL(&cChar, 1, 1, fp);
546 : }
547 :
548 : /************************************************************************/
549 : /* ==================================================================== */
550 : /* VSIFileManager() */
551 : /* ==================================================================== */
552 : /************************************************************************/
553 :
554 : /*
555 : ** Notes on Multithreading:
556 : **
557 : ** The VSIFileManager maintains a list of file type handlers (mem, large
558 : ** file, etc). It should be thread safe as long as all the handlers are
559 : ** instantiated before multiple threads begin to operate.
560 : **/
561 :
562 : /************************************************************************/
563 : /* VSIFileManager() */
564 : /************************************************************************/
565 :
566 379 : VSIFileManager::VSIFileManager()
567 :
568 : {
569 379 : poDefaultHandler = NULL;
570 379 : }
571 :
572 : /************************************************************************/
573 : /* ~VSIFileManager() */
574 : /************************************************************************/
575 :
576 363 : VSIFileManager::~VSIFileManager()
577 : {
578 363 : std::map<std::string,VSIFilesystemHandler*>::const_iterator iter;
579 :
580 1815 : for( iter = oHandlers.begin();
581 : iter != oHandlers.end();
582 : iter++ )
583 : {
584 1452 : delete iter->second;
585 : }
586 :
587 363 : delete poDefaultHandler;
588 363 : }
589 :
590 :
591 : /************************************************************************/
592 : /* Get() */
593 : /************************************************************************/
594 :
595 : static VSIFileManager *poManager = NULL;
596 :
597 98305 : VSIFileManager *VSIFileManager::Get()
598 :
599 : {
600 :
601 98305 : if( poManager == NULL )
602 : {
603 379 : poManager = new VSIFileManager;
604 379 : VSIInstallLargeFileHandler();
605 379 : VSIInstallSubFileHandler();
606 379 : VSIInstallMemFileHandler();
607 : #ifdef HAVE_LIBZ
608 379 : VSIInstallGZipFileHandler();
609 379 : VSIInstallZipFileHandler();
610 : #endif
611 : }
612 :
613 98305 : return poManager;
614 : }
615 :
616 : /************************************************************************/
617 : /* GetHandler() */
618 : /************************************************************************/
619 :
620 96410 : VSIFilesystemHandler *VSIFileManager::GetHandler( const char *pszPath )
621 :
622 : {
623 96410 : VSIFileManager *poThis = Get();
624 96410 : std::map<std::string,VSIFilesystemHandler*>::const_iterator iter;
625 96410 : int nPathLen = strlen(pszPath);
626 :
627 475627 : for( iter = poThis->oHandlers.begin();
628 : iter != poThis->oHandlers.end();
629 : iter++ )
630 : {
631 381558 : const char* pszIterKey = iter->first.c_str();
632 381558 : int nIterKeyLen = iter->first.size();
633 381558 : if( strncmp(pszPath,pszIterKey,nIterKeyLen) == 0 )
634 2341 : return iter->second;
635 :
636 : /* "/vsimem\foo" should be handled as "/vsimem/foo" */
637 1037935 : if (nIterKeyLen && nPathLen > nIterKeyLen &&
638 329359 : pszIterKey[nIterKeyLen-1] == '/' &&
639 329359 : pszPath[nIterKeyLen-1] == '\\' &&
640 : strncmp(pszPath,pszIterKey,nIterKeyLen-1) == 0 )
641 0 : return iter->second;
642 : }
643 :
644 94069 : return poThis->poDefaultHandler;
645 : }
646 :
647 : /************************************************************************/
648 : /* InstallHandler() */
649 : /************************************************************************/
650 :
651 1895 : void VSIFileManager::InstallHandler( const std::string& osPrefix,
652 : VSIFilesystemHandler *poHandler )
653 :
654 : {
655 1895 : if( osPrefix == "" )
656 379 : Get()->poDefaultHandler = poHandler;
657 : else
658 1516 : Get()->oHandlers[osPrefix] = poHandler;
659 1895 : }
660 :
661 : /************************************************************************/
662 : /* VSICleanupFileManager() */
663 : /************************************************************************/
664 :
665 617 : void VSICleanupFileManager()
666 :
667 : {
668 617 : if( poManager )
669 : {
670 363 : delete poManager;
671 363 : poManager = NULL;
672 : }
673 617 : }
|