1 /******************************************************************************
2 * $Id: gdalopeninfo.cpp 29107 2015-05-02 11:23:26Z rouault $
3 *
4 * Project: GDAL Core
5 * Purpose: Implementation of GDALOpenInfo class.
6 * Author: Frank Warmerdam, warmerdam@pobox.com
7 *
8 **********************************************************************
9 * Copyright (c) 2002, Frank Warmerdam
10 * Copyright (c) 2008-2012, Even Rouault <even dot rouault at mines-paris dot org>
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 "gdal_priv.h"
32 #include "cpl_conv.h"
33
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 CPL_CVSID("$Id: gdalopeninfo.cpp 29107 2015-05-02 11:23:26Z rouault $");
39
40 /************************************************************************/
41 /* ==================================================================== */
42 /* GDALOpenInfo */
43 /* ==================================================================== */
44 /************************************************************************/
45
46 /************************************************************************/
47 /* GDALOpenInfo() */
48 /************************************************************************/
49
GDALOpenInfo(const char * pszFilenameIn,int nOpenFlagsIn,char ** papszSiblingsIn)50 GDALOpenInfo::GDALOpenInfo( const char * pszFilenameIn, int nOpenFlagsIn,
51 char **papszSiblingsIn )
52
53 {
54 /* -------------------------------------------------------------------- */
55 /* Ensure that C: is treated as C:\ so we can stat it on */
56 /* Windows. Similar to what is done in CPLStat(). */
57 /* -------------------------------------------------------------------- */
58 #ifdef WIN32
59 if( strlen(pszFilenameIn) == 2 && pszFilenameIn[1] == ':' )
60 {
61 char szAltPath[10];
62
63 strcpy( szAltPath, pszFilenameIn );
64 strcat( szAltPath, "\\" );
65 pszFilename = CPLStrdup( szAltPath );
66 }
67 else
68 #endif
69 pszFilename = CPLStrdup( pszFilenameIn );
70
71 /* -------------------------------------------------------------------- */
72 /* Initialize. */
73 /* -------------------------------------------------------------------- */
74
75 nHeaderBytes = 0;
76 nHeaderBytesTried = 0;
77 pabyHeader = NULL;
78 bIsDirectory = FALSE;
79 bStatOK = FALSE;
80 nOpenFlags = nOpenFlagsIn;
81 eAccess = (nOpenFlags & GDAL_OF_UPDATE) ? GA_Update : GA_ReadOnly;
82 fpL = NULL;
83 papszOpenOptions = NULL;
84
85 #ifdef HAVE_READLINK
86 int bHasRetried = FALSE;
87 #endif
88
89 /* -------------------------------------------------------------------- */
90 /* Collect information about the file. */
91 /* -------------------------------------------------------------------- */
92 VSIStatBufL sStat;
93
94 #ifdef HAVE_READLINK
95 retry:
96 #endif
97 int bPotentialDirectory = FALSE;
98
99 /* Check if the filename might be a directory of a special virtual file system */
100 if( strncmp(pszFilename, "/vsizip/", strlen("/vsizip/")) == 0 ||
101 strncmp(pszFilename, "/vsitar/", strlen("/vsitar/")) == 0 )
102 {
103 const char* pszExt = CPLGetExtension(pszFilename);
104 if( EQUAL(pszExt, "zip") || EQUAL(pszExt, "tar") || EQUAL(pszExt, "gz") )
105 bPotentialDirectory = TRUE;
106 }
107 else if( strncmp(pszFilename, "/vsicurl/", strlen("/vsicurl/")) == 0 )
108 {
109 bPotentialDirectory = TRUE;
110 }
111
112 if( bPotentialDirectory )
113 {
114 /* For those special files, opening them with VSIFOpenL() might result */
115 /* in content, even if they should be considered as directories, so */
116 /* use stat */
117 if( VSIStatExL( pszFilename, &sStat,
118 VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG ) == 0 )
119 {
120 bStatOK = TRUE;
121 if( VSI_ISDIR( sStat.st_mode ) )
122 bIsDirectory = TRUE;
123 }
124 }
125
126 if( !bIsDirectory )
127 fpL = VSIFOpenL( pszFilename, (eAccess == GA_Update) ? "r+b" : "rb" );
128 if( fpL != NULL )
129 {
130 bStatOK = TRUE;
131 pabyHeader = (GByte *) CPLCalloc(1025,1);
132 nHeaderBytesTried = 1024;
133 nHeaderBytes = (int) VSIFReadL( pabyHeader, 1, nHeaderBytesTried, fpL );
134 VSIRewindL( fpL );
135
136 /* If we cannot read anything, check if it is not a directory instead */
137 if( nHeaderBytes == 0 &&
138 VSIStatExL( pszFilename, &sStat,
139 VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG ) == 0 &&
140 VSI_ISDIR( sStat.st_mode ) )
141 {
142 VSIFCloseL(fpL);
143 fpL = NULL;
144 CPLFree(pabyHeader);
145 pabyHeader = NULL;
146 bIsDirectory = TRUE;
147 }
148 }
149 else if( !bStatOK )
150 {
151 if( VSIStatExL( pszFilename, &sStat,
152 VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG ) == 0 )
153 {
154 bStatOK = TRUE;
155 if( VSI_ISDIR( sStat.st_mode ) )
156 bIsDirectory = TRUE;
157 }
158 #ifdef HAVE_READLINK
159 else if ( !bHasRetried && strncmp(pszFilename, "/vsi", strlen("/vsi")) != 0 )
160 {
161 /* If someone creates a file with "ln -sf /vsicurl/http://download.osgeo.org/gdal/data/gtiff/utm.tif my_remote_utm.tif" */
162 /* we will be able to open it by passing my_remote_utm.tif */
163 /* This helps a lot for GDAL based readers that only provide file explorers to open datasets */
164 char szPointerFilename[2048];
165 int nBytes = readlink(pszFilename, szPointerFilename, sizeof(szPointerFilename));
166 if (nBytes != -1)
167 {
168 szPointerFilename[MIN(nBytes, (int)sizeof(szPointerFilename)-1)] = 0;
169 CPLFree(pszFilename);
170 pszFilename = CPLStrdup(szPointerFilename);
171 papszSiblingsIn = NULL;
172 bHasRetried = TRUE;
173 goto retry;
174 }
175 }
176 #endif
177 }
178
179 /* -------------------------------------------------------------------- */
180 /* Capture sibling list either from passed in values, or by */
181 /* scanning for them only if requested through GetSiblingFiles(). */
182 /* -------------------------------------------------------------------- */
183 if( papszSiblingsIn != NULL )
184 {
185 papszSiblingFiles = CSLDuplicate( papszSiblingsIn );
186 bHasGotSiblingFiles = TRUE;
187 }
188 else if( bStatOK && !bIsDirectory )
189 {
190 const char* pszOptionVal =
191 CPLGetConfigOption( "GDAL_DISABLE_READDIR_ON_OPEN", "NO" );
192 if (EQUAL(pszOptionVal, "EMPTY_DIR"))
193 {
194 papszSiblingFiles = CSLAddString( NULL, CPLGetFilename(pszFilename) );
195 bHasGotSiblingFiles = TRUE;
196 }
197 else if( CSLTestBoolean(pszOptionVal) )
198 {
199 /* skip reading the directory */
200 papszSiblingFiles = NULL;
201 bHasGotSiblingFiles = TRUE;
202 }
203 else
204 {
205 /* will be lazy loaded */
206 papszSiblingFiles = NULL;
207 bHasGotSiblingFiles = FALSE;
208 }
209 }
210 else
211 {
212 papszSiblingFiles = NULL;
213 bHasGotSiblingFiles = TRUE;
214 }
215 }
216
217 /************************************************************************/
218 /* ~GDALOpenInfo() */
219 /************************************************************************/
220
~GDALOpenInfo()221 GDALOpenInfo::~GDALOpenInfo()
222
223 {
224 VSIFree( pabyHeader );
225 CPLFree( pszFilename );
226
227 if( fpL != NULL )
228 VSIFCloseL( fpL );
229 CSLDestroy( papszSiblingFiles );
230 }
231
232 /************************************************************************/
233 /* GetSiblingFiles() */
234 /************************************************************************/
235
GetSiblingFiles()236 char** GDALOpenInfo::GetSiblingFiles()
237 {
238 if( bHasGotSiblingFiles )
239 return papszSiblingFiles;
240 bHasGotSiblingFiles = TRUE;
241
242 CPLString osDir = CPLGetDirname( pszFilename );
243 papszSiblingFiles = VSIReadDir( osDir );
244
245 /* Small optimization to avoid unnecessary stat'ing from PAux or ENVI */
246 /* drivers. The MBTiles driver needs no companion file. */
247 if( papszSiblingFiles == NULL &&
248 strncmp(pszFilename, "/vsicurl/", 9) == 0 &&
249 EQUAL(CPLGetExtension( pszFilename ),"mbtiles") )
250 {
251 papszSiblingFiles = CSLAddString( NULL, CPLGetFilename(pszFilename) );
252 }
253
254 return papszSiblingFiles;
255 }
256
257
258 /************************************************************************/
259 /* TryToIngest() */
260 /************************************************************************/
261
TryToIngest(int nBytes)262 int GDALOpenInfo::TryToIngest(int nBytes)
263 {
264 if( fpL == NULL )
265 return FALSE;
266 if( nHeaderBytes < nHeaderBytesTried )
267 return TRUE;
268 pabyHeader = (GByte*) CPLRealloc(pabyHeader, nBytes + 1);
269 memset(pabyHeader, 0, nBytes + 1);
270 VSIRewindL(fpL);
271 nHeaderBytesTried = nBytes;
272 nHeaderBytes = (int) VSIFReadL(pabyHeader, 1, nBytes, fpL);
273 VSIRewindL(fpL);
274
275 return TRUE;
276 }
277