1 /******************************************************************************
2  *
3  * Project:  CPL - Common Portability Library
4  * Purpose:  Standalone shared library that can be LD_PRELOAD'ed as an overload of
5  *           libc to enable VSI Virtual FILE API to be used with binaries using
6  *           regular libc for I/O.
7  * Author:   Even Rouault <even dot rouault at spatialys.com>
8  *
9  ******************************************************************************
10  * Copyright (c) 2013, Even Rouault <even dot rouault at spatialys.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 // WARNING: Linux glibc ONLY
32 // Might work with some adaptations (mainly around 64bit symbols) on other Unix systems
33 
34 // Compile:
35 // g++ -Wall -fPIC port/vsipreload.cpp -shared -o vsipreload.so -Iport -L. -L.libs -lgdal
36 
37 // Run:
38 // LD_PRELOAD=./vsipreload.so ....
39 // e.g:
40 // LD_PRELOAD=./vsipreload.so gdalinfo /vsicurl/http://download.osgeo.org/gdal/data/ecw/spif83.ecw
41 // LD_PRELOAD=./vsipreload.so gdalinfo 'HDF4_EOS:EOS_GRID:"/vsicurl/http://download.osgeo.org/gdal/data/hdf4/MOD09Q1G_EVI.A2006233.h07v03.005.2008338190308.hdf":MODIS_NACP_EVI:MODIS_EVI'
42 // LD_PRELOAD=./vsipreload.so ogrinfo /vsicurl/http://svn.osgeo.org/gdal/trunk/autotest/ogr/data/testavc -ro
43 // even non GDAL binaries :
44 // LD_PRELOAD=./vsipreload.so h5dump -d /x /vsicurl/http://download.osgeo.org/gdal/data/netcdf/utm-big-chunks.nc
45 // LD_PRELOAD=./vsipreload.so sqlite3 /vsicurl/http://download.osgeo.org/gdal/data/sqlite3/polygon.db "select * from polygon limit 10"
46 // LD_PRELOAD=./vsipreload.so ls -al /vsicurl/http://download.osgeo.org/gdal/data/sqlite3
47 // LD_PRELOAD=./vsipreload.so find /vsicurl/http://download.osgeo.org/gdal/data/sqlite3
48 
49 #define _GNU_SOURCE 1
50 #define _LARGEFILE64_SOURCE 1
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <assert.h>
54 #include <dlfcn.h>
55 #include <string.h>
56 #include <fcntl.h>
57 #include <unistd.h>
58 #include <dirent.h>
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 
62 #include <set>
63 #include <map>
64 #include <string>
65 #include "cpl_vsi.h"
66 #include "cpl_multiproc.h"
67 #include "cpl_string.h"
68 #include "cpl_hash_set.h"
69 
70 CPL_CVSID("$Id: vsipreload.cpp 355b41831cd2685c85d1aabe5b95665a2c6e99b7 2019-06-19 17:07:04 +0200 Even Rouault $")
71 
72 static int DEBUG_VSIPRELOAD = 0;
73 static int DEBUG_VSIPRELOAD_ONLY_VSIL = 1;
74 #define DEBUG_OUTPUT_READ 0
75 
76 #ifndef NO_FSTATAT
77 #define HAVE_FSTATAT
78 #endif
79 
80 #define DECLARE_SYMBOL(x, retType, args) \
81     typedef retType (*fn ## x ## Type)args;\
82     static fn ## x ## Type pfn ## x = nullptr
83 
84 DECLARE_SYMBOL(fopen, FILE*, (const char *path, const char *mode));
85 DECLARE_SYMBOL(fopen64, FILE*, (const char *path, const char *mode));
86 DECLARE_SYMBOL(fread, size_t, (void *ptr, size_t size, size_t nmemb,
87                                FILE *stream));
88 DECLARE_SYMBOL(fwrite, size_t, (const void *ptr, size_t size, size_t nmemb,
89                                 FILE *stream));
90 DECLARE_SYMBOL(fclose, int, (FILE *stream));
91 DECLARE_SYMBOL(__xstat, int, (int ver, const char *path, struct stat *buf));
92 DECLARE_SYMBOL(__lxstat, int, (int ver, const char *path, struct stat *buf));
93 DECLARE_SYMBOL(__xstat64, int, (int ver, const char *path, struct stat64 *buf));
94 DECLARE_SYMBOL(fseeko64, int, (FILE *stream, off64_t off, int whence));
95 DECLARE_SYMBOL(fseek, int, (FILE *stream, off_t off, int whence));
96 DECLARE_SYMBOL(ftello64, off64_t, (FILE *stream));
97 DECLARE_SYMBOL(ftell, off_t, (FILE *stream));
98 DECLARE_SYMBOL(feof, int, (FILE *stream));
99 DECLARE_SYMBOL(fflush, int, (FILE *stream));
100 DECLARE_SYMBOL(fgetpos, int, (FILE *stream, fpos_t *pos));
101 DECLARE_SYMBOL(fsetpos, int, (FILE *stream, fpos_t *pos));
102 DECLARE_SYMBOL(fileno, int, (FILE *stream));
103 DECLARE_SYMBOL(ferror, int, (FILE *stream));
104 DECLARE_SYMBOL(clearerr, void, (FILE *stream));
105 
106 DECLARE_SYMBOL(fdopen, FILE*, (int fd, const char *mode));
107 DECLARE_SYMBOL(freopen, FILE*, (const char *path, const char *mode,
108                                 FILE *stream));
109 
110 DECLARE_SYMBOL(open, int, (const char *path, int flags, mode_t mode));
111 DECLARE_SYMBOL(open64, int, (const char *path, int flags, mode_t mode));
112 // DECLARE_SYMBOL(creat, int, (const char *path, mode_t mode));
113 DECLARE_SYMBOL(close, int, (int fd));
114 DECLARE_SYMBOL(read, ssize_t, (int fd, void *buf, size_t count));
115 DECLARE_SYMBOL(write, ssize_t, (int fd, const void *buf, size_t count));
116 DECLARE_SYMBOL(fsync, int, (int fd));
117 DECLARE_SYMBOL(fdatasync, int, (int fd));
118 DECLARE_SYMBOL(__fxstat, int, (int ver, int fd, struct stat *__stat_buf));
119 DECLARE_SYMBOL(__fxstat64, int, (int ver, int fd, struct stat64 *__stat_buf));
120 #ifdef HAVE_FSTATAT
121 DECLARE_SYMBOL(__fxstatat, int, (int ver, int dirfd, const char *pathname,
122                                  struct stat *buf, int flags));
123 #endif
124 
125 DECLARE_SYMBOL(lseek, off_t, (int fd, off_t off, int whence));
126 DECLARE_SYMBOL(lseek64, off64_t , (int fd, off64_t off, int whence));
127 
128 DECLARE_SYMBOL(truncate, int, (const char *path, off_t length));
129 DECLARE_SYMBOL(ftruncate, int, (int fd, off_t length));
130 
131 DECLARE_SYMBOL(opendir, DIR* , (const char *name));
132 DECLARE_SYMBOL(readdir, struct dirent*, (DIR *dirp));
133 DECLARE_SYMBOL(readdir64, struct dirent64*, (DIR *dirp));
134 DECLARE_SYMBOL(closedir, int, (DIR *dirp));
135 DECLARE_SYMBOL(dirfd, int, (DIR *dirp));
136 DECLARE_SYMBOL(fchdir, int, (int fd));
137 
138 static CPLLock* hLock = nullptr;
139 
140 typedef struct
141 {
142     char*  pszDirname;
143     char** papszDir;
144     int    nIter;
145     struct dirent ent;
146     struct dirent64 ent64;
147     int    fd;
148 } VSIDIRPreload;
149 
150 std::set<VSILFILE*> oSetFiles;
151 std::map<int, VSILFILE*> oMapfdToVSI;
152 std::map<VSILFILE*, int> oMapVSITofd;
153 std::map<VSILFILE*, std::string> oMapVSIToString;
154 std::set<VSIDIRPreload*> oSetVSIDIRPreload;
155 std::map<int, VSIDIRPreload*> oMapfdToVSIDIRPreload;
156 std::map<int, std::string> oMapDirFdToName;
157 std::string osCurDir;
158 
159 /************************************************************************/
160 /*                             myinit()                                 */
161 /************************************************************************/
162 
163 #define LOAD_SYMBOL(x) \
164     pfn ## x = (fn ## x ## Type) dlsym(RTLD_NEXT, #x); \
165     assert(pfn ## x)
166 
myinit()167 static void myinit()
168 {
169     CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
170 
171     if( pfnfopen64 != nullptr ) return;
172     DEBUG_VSIPRELOAD = getenv("DEBUG_VSIPRELOAD") != nullptr;
173     LOAD_SYMBOL(fopen);
174     LOAD_SYMBOL(fopen64);
175     LOAD_SYMBOL(fread);
176     LOAD_SYMBOL(fwrite);
177     LOAD_SYMBOL(fclose);
178     LOAD_SYMBOL(fseeko64);
179     LOAD_SYMBOL(fseek);
180     LOAD_SYMBOL(__xstat);
181     LOAD_SYMBOL(__lxstat);
182     LOAD_SYMBOL(__xstat64);
183     LOAD_SYMBOL(ftello64);
184     LOAD_SYMBOL(ftell);
185     LOAD_SYMBOL(feof);
186     LOAD_SYMBOL(fflush);
187     LOAD_SYMBOL(fgetpos);
188     LOAD_SYMBOL(fsetpos);
189     LOAD_SYMBOL(fileno);
190     LOAD_SYMBOL(ferror);
191     LOAD_SYMBOL(clearerr);
192 
193     LOAD_SYMBOL(fdopen);
194     LOAD_SYMBOL(freopen);
195 
196     LOAD_SYMBOL(open);
197     LOAD_SYMBOL(open64);
198     // LOAD_SYMBOL(creat);
199     LOAD_SYMBOL(close);
200     LOAD_SYMBOL(read);
201     LOAD_SYMBOL(write);
202     LOAD_SYMBOL(fsync);
203     LOAD_SYMBOL(fdatasync);
204     LOAD_SYMBOL(__fxstat);
205     LOAD_SYMBOL(__fxstat64);
206 #ifdef HAVE_FSTATAT
207     LOAD_SYMBOL(__fxstatat);
208 #endif
209     LOAD_SYMBOL(lseek);
210     LOAD_SYMBOL(lseek64);
211 
212     LOAD_SYMBOL(truncate);
213     LOAD_SYMBOL(ftruncate);
214 
215     LOAD_SYMBOL(opendir);
216     LOAD_SYMBOL(readdir);
217     LOAD_SYMBOL(readdir64);
218     LOAD_SYMBOL(closedir);
219     LOAD_SYMBOL(dirfd);
220     LOAD_SYMBOL(fchdir);
221 }
222 
223 /************************************************************************/
224 /*                          getVSILFILE()                               */
225 /************************************************************************/
226 
getVSILFILE(FILE * stream)227 static VSILFILE* getVSILFILE( FILE* stream )
228 {
229     CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
230     std::set<VSILFILE*>::iterator oIter = oSetFiles.find((VSILFILE*)stream);
231     VSILFILE* ret = nullptr;
232     if( oIter != oSetFiles.end() )
233         ret = *oIter;
234     else
235         ret = nullptr;
236     return ret;
237 }
238 
239 /************************************************************************/
240 /*                          getVSILFILE()                               */
241 /************************************************************************/
242 
getVSILFILE(int fd)243 static VSILFILE* getVSILFILE( int fd )
244 {
245     CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
246     std::map<int, VSILFILE*>::iterator oIter = oMapfdToVSI.find(fd);
247     VSILFILE* ret = nullptr;
248     if( oIter != oMapfdToVSI.end() )
249         ret = oIter->second;
250     else
251         ret = nullptr;
252     return ret;
253 }
254 
255 /************************************************************************/
256 /*                        VSIFSeekLHelper()                             */
257 /************************************************************************/
258 
VSIFSeekLHelper(VSILFILE * fpVSIL,off64_t off,int whence)259 static int VSIFSeekLHelper( VSILFILE* fpVSIL, off64_t off, int whence )
260 {
261     if( off < 0 && whence == SEEK_CUR )
262     {
263         return VSIFSeekL(fpVSIL, VSIFTellL(fpVSIL) + off, SEEK_SET);
264     }
265     else if( off < 0 && whence == SEEK_END )
266     {
267         VSIFSeekL(fpVSIL, 0, SEEK_END);
268         return VSIFSeekL(fpVSIL, VSIFTellL(fpVSIL) + off, SEEK_SET);
269     }
270 
271     return VSIFSeekL(fpVSIL, off, whence);
272 }
273 
274 /************************************************************************/
275 /*                          VSIFopenHelper()                            */
276 /************************************************************************/
277 
VSIFfopenHelper(const char * path,const char * mode)278 static VSILFILE* VSIFfopenHelper( const char *path, const char *mode )
279 {
280     VSILFILE* fpVSIL = VSIFOpenL(path, mode);
281     if( fpVSIL != nullptr )
282     {
283         CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
284         oSetFiles.insert(fpVSIL);
285         oMapVSIToString[fpVSIL] = path;
286     }
287     return fpVSIL;
288 }
289 
290 /************************************************************************/
291 /*                         getfdFromVSILFILE()                          */
292 /************************************************************************/
293 
getfdFromVSILFILE(VSILFILE * fpVSIL)294 static int getfdFromVSILFILE( VSILFILE* fpVSIL )
295 {
296     CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
297 
298     int fd = 0;
299     std::map<VSILFILE*, int>::iterator oIter = oMapVSITofd.find(fpVSIL);
300     if( oIter != oMapVSITofd.end() )
301         fd = oIter->second;
302     else
303     {
304         fd = open("/dev/zero", O_RDONLY);
305         assert(fd >= 0);
306         oMapVSITofd[fpVSIL] = fd;
307         oMapfdToVSI[fd] = fpVSIL;
308     }
309     return fd;
310 }
311 
312 /************************************************************************/
313 /*                          VSIFopenHelper()                            */
314 /************************************************************************/
315 
VSIFopenHelper(const char * path,int flags)316 static int VSIFopenHelper( const char *path, int flags )
317 {
318     const char* pszMode = "rb";
319     if( (flags & 3) == O_RDONLY )
320         pszMode = "rb";
321     else if( (flags & 3) == O_WRONLY )
322     {
323         if( flags & O_APPEND )
324             pszMode = "ab";
325         else
326             pszMode = "wb";
327     }
328     else
329     {
330         if( flags & O_APPEND )
331             pszMode = "ab+";
332         else
333             pszMode = "rb+";
334     }
335     VSILFILE* fpVSIL = VSIFfopenHelper(path, pszMode );
336     int fd = 0;
337     if( fpVSIL != nullptr )
338     {
339         if( flags & O_TRUNC )
340         {
341             VSIFTruncateL(fpVSIL, 0);
342             VSIFSeekL(fpVSIL, 0, SEEK_SET);
343         }
344         fd = getfdFromVSILFILE(fpVSIL);
345     }
346     else
347         fd = -1;
348     return fd;
349 }
350 
351 /************************************************************************/
352 /*                    GET_DEBUG_VSIPRELOAD_COND()                             */
353 /************************************************************************/
354 
GET_DEBUG_VSIPRELOAD_COND(const char * path)355 static bool GET_DEBUG_VSIPRELOAD_COND( const char* path )
356 {
357     return
358         DEBUG_VSIPRELOAD &&
359     // cppcheck-suppress knownConditionTrueFalse
360         (!DEBUG_VSIPRELOAD_ONLY_VSIL || STARTS_WITH(path, "/vsi"));
361 }
362 
GET_DEBUG_VSIPRELOAD_COND(VSILFILE * fpVSIL)363 static bool GET_DEBUG_VSIPRELOAD_COND(VSILFILE* fpVSIL)
364 {
365     // cppcheck-suppress knownConditionTrueFalse
366     return DEBUG_VSIPRELOAD && (!DEBUG_VSIPRELOAD_ONLY_VSIL || fpVSIL != nullptr);
367 }
368 
GET_DEBUG_VSIPRELOAD_COND(VSIDIRPreload * dirP)369 static bool GET_DEBUG_VSIPRELOAD_COND(VSIDIRPreload* dirP)
370 {
371     return
372         DEBUG_VSIPRELOAD &&
373     // cppcheck-suppress knownConditionTrueFalse
374         (!DEBUG_VSIPRELOAD_ONLY_VSIL ||
375          oSetVSIDIRPreload.find(dirP) != oSetVSIDIRPreload.end());
376 }
377 
378 /************************************************************************/
379 /*                     copyVSIStatBufLToBuf()                           */
380 /************************************************************************/
381 
copyVSIStatBufLToBuf(VSIStatBufL * bufSrc,struct stat * buf)382 static void copyVSIStatBufLToBuf( VSIStatBufL* bufSrc, struct stat *buf )
383 {
384     buf->st_dev = bufSrc->st_dev;
385     buf->st_ino = bufSrc->st_ino;
386     // S_IXUSR | S_IXGRP | S_IXOTH;
387     buf->st_mode = bufSrc->st_mode | S_IRUSR | S_IRGRP | S_IROTH;
388     buf->st_nlink = 1;   // bufSrc->st_nlink;
389     buf->st_uid = bufSrc->st_uid;
390     buf->st_gid = bufSrc->st_gid;
391     buf->st_rdev = bufSrc->st_rdev;
392     buf->st_size = bufSrc->st_size;
393     buf->st_blksize = bufSrc->st_blksize;
394     buf->st_blocks = bufSrc->st_blocks;
395     buf->st_atime = bufSrc->st_atime;
396     buf->st_mtime = bufSrc->st_mtime;
397     buf->st_ctime = bufSrc->st_ctime;
398 }
399 
400 /************************************************************************/
401 /*                     copyVSIStatBufLToBuf64()                         */
402 /************************************************************************/
403 
copyVSIStatBufLToBuf64(VSIStatBufL * bufSrc,struct stat64 * buf)404 static void copyVSIStatBufLToBuf64( VSIStatBufL *bufSrc, struct stat64 *buf )
405 {
406     buf->st_dev = bufSrc->st_dev;
407     buf->st_ino = bufSrc->st_ino;
408     // S_IXUSR | S_IXGRP | S_IXOTH;
409     buf->st_mode = bufSrc->st_mode | S_IRUSR | S_IRGRP | S_IROTH;
410     buf->st_nlink = 1; // bufSrc->st_nlink;
411     buf->st_uid = bufSrc->st_uid;
412     buf->st_gid = bufSrc->st_gid;
413     buf->st_rdev = bufSrc->st_rdev;
414     buf->st_size = bufSrc->st_size;
415     buf->st_blksize = bufSrc->st_blksize;
416     buf->st_blocks = bufSrc->st_blocks;
417     buf->st_atime = bufSrc->st_atime;
418     buf->st_mtime = bufSrc->st_mtime;
419     buf->st_ctime = bufSrc->st_ctime;
420 }
421 
422 /************************************************************************/
423 /*                             fopen()                                  */
424 /************************************************************************/
425 
fopen(const char * path,const char * mode)426 FILE CPL_DLL *fopen( const char *path, const char *mode )
427 {
428     myinit();
429     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
430     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "fopen(%s, %s)\n", path, mode);
431     FILE* ret;
432     if( STARTS_WITH(path, "/vsi") )
433         ret = (FILE*) VSIFfopenHelper(path, mode);
434     else
435         ret = pfnfopen(path, mode);
436     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "fopen() = %p\n", ret);
437     return ret;
438 }
439 
440 /************************************************************************/
441 /*                            fopen64()                                 */
442 /************************************************************************/
443 
fopen64(const char * path,const char * mode)444 FILE CPL_DLL *fopen64( const char *path, const char *mode )
445 {
446     myinit();
447     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
448     if( DEBUG_VSIPRELOAD_COND )
449         fprintf(stderr, "fopen64(%s, %s)\n", path, mode);
450     FILE* ret;
451     if( STARTS_WITH(path, "/vsi") )
452         ret = (FILE*) VSIFfopenHelper(path, mode);
453     else
454         ret = pfnfopen64(path, mode);
455     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "fopen64() = %p\n", ret);
456     return ret;
457 }
458 
459 /************************************************************************/
460 /*                            fread()                                   */
461 /************************************************************************/
462 
fread(void * ptr,size_t size,size_t nmemb,FILE * stream)463 size_t CPL_DLL fread( void *ptr, size_t size, size_t nmemb, FILE *stream )
464 {
465     myinit();
466     VSILFILE* fpVSIL = getVSILFILE(stream);
467     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
468     if( DEBUG_VSIPRELOAD_COND )
469         fprintf(stderr, "fread(stream=%p,size=%d,nmemb=%d)\n",
470                 stream, static_cast<int>(size), static_cast<int>(nmemb));
471     size_t ret = 0;
472     if( fpVSIL )
473         ret = VSIFReadL(ptr, size, nmemb, fpVSIL);
474     else
475         ret = pfnfread(ptr, size, nmemb, stream);
476     if( DEBUG_VSIPRELOAD_COND )
477         fprintf(stderr, "fread(stream=%p,size=%d,nmemb=%d) -> %d\n",
478                 stream, static_cast<int>(size), static_cast<int>(nmemb),
479                 static_cast<int>(ret));
480     return ret;
481 }
482 
483 /************************************************************************/
484 /*                            fwrite()                                  */
485 /************************************************************************/
486 
fwrite(const void * ptr,size_t size,size_t nmemb,FILE * stream)487 size_t CPL_DLL fwrite( const void *ptr, size_t size, size_t nmemb, FILE *stream )
488 {
489     myinit();
490     VSILFILE* fpVSIL = getVSILFILE(stream);
491     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
492     if( DEBUG_VSIPRELOAD_COND )
493         fprintf(stderr, "fwrite(stream=%p,size=%d,nmemb=%d)\n",
494                 stream, static_cast<int>(size), static_cast<int>(nmemb));
495     size_t ret = 0;
496     if( fpVSIL != nullptr )
497         ret = VSIFWriteL(ptr, size, nmemb, fpVSIL);
498     else
499         ret = pfnfwrite(ptr, size, nmemb, stream);
500     if( DEBUG_VSIPRELOAD_COND )
501         fprintf(stderr, "fwrite(stream=%p,size=%d,nmemb=%d) -> %d\n",
502                 stream, static_cast<int>(size), static_cast<int>(nmemb),
503                 static_cast<int>(ret));
504     return ret;
505 }
506 
507 /************************************************************************/
508 /*                            fclose()                                  */
509 /************************************************************************/
510 
fclose(FILE * stream)511 int CPL_DLL fclose( FILE *stream )
512 {
513     myinit();
514     VSILFILE* fpVSIL = getVSILFILE(stream);
515     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
516     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "fclose(stream=%p)\n", stream);
517     if( fpVSIL != nullptr )
518     {
519         CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
520 
521         int ret = VSIFCloseL(fpVSIL);
522         oMapVSIToString.erase(fpVSIL);
523         oSetFiles.erase(fpVSIL);
524 
525         std::map<VSILFILE*, int>::iterator oIter = oMapVSITofd.find(fpVSIL);
526         if( oIter != oMapVSITofd.end() )
527         {
528             int fd = oIter->second;
529             pfnclose(fd);
530             oMapVSITofd.erase(oIter);
531             oMapfdToVSI.erase(fd);
532         }
533 
534         return ret;
535     }
536     else
537         return pfnfclose(stream);
538 }
539 
540 /************************************************************************/
541 /*                            __xstat()                                 */
542 /************************************************************************/
543 
__xstat(int ver,const char * path,struct stat * buf)544 int CPL_DLL __xstat( int ver, const char *path, struct stat *buf )
545 {
546     myinit();
547     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
548     if( DEBUG_VSIPRELOAD && (!osCurDir.empty() && path[0] != '/') )
549         DEBUG_VSIPRELOAD_COND = 1;
550     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "__xstat(%s)\n", path);
551     if( (!osCurDir.empty() && path[0] != '/') || STARTS_WITH(path, "/vsi") )
552     {
553         VSIStatBufL sStatBufL;
554         std::string newpath;
555         if( (!osCurDir.empty() && path[0] != '/') )
556         {
557             newpath = CPLFormFilename(osCurDir.c_str(), path, nullptr);
558             path = newpath.c_str();
559         }
560         const int ret = VSIStatL(path, &sStatBufL);
561         sStatBufL.st_ino = static_cast<int>(CPLHashSetHashStr(path));
562         if( ret == 0 )
563         {
564             copyVSIStatBufLToBuf(&sStatBufL, buf);
565             if( DEBUG_VSIPRELOAD_COND )
566                 fprintf(stderr,
567                         "__xstat(%s) ret = 0, mode = %d, size=%d\n",
568                         path, sStatBufL.st_mode,
569                         static_cast<int>(sStatBufL.st_size));
570         }
571         return ret;
572     }
573     else
574     {
575         int ret = pfn__xstat(ver, path, buf);
576         if( ret == 0 )
577         {
578             if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr,
579                 "__xstat ret = 0, mode = %d\n", buf->st_mode);
580         }
581         return ret;
582     }
583 }
584 
585 /************************************************************************/
586 /*                           __lxstat()                                 */
587 /************************************************************************/
588 
__lxstat(int ver,const char * path,struct stat * buf)589 int CPL_DLL __lxstat( int ver, const char *path, struct stat *buf )
590 {
591     myinit();
592     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
593     if( DEBUG_VSIPRELOAD && (!osCurDir.empty() && path[0] != '/') )
594         DEBUG_VSIPRELOAD_COND = 1;
595     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "__lxstat(%s)\n", path);
596     if( (!osCurDir.empty() && path[0] != '/') || STARTS_WITH(path, "/vsi") )
597     {
598         VSIStatBufL sStatBufL;
599         std::string newpath;
600         if( (!osCurDir.empty() && path[0] != '/') )
601         {
602             newpath = CPLFormFilename(osCurDir.c_str(), path, nullptr);
603             path = newpath.c_str();
604         }
605         const int ret = VSIStatL(path, &sStatBufL);
606         sStatBufL.st_ino = static_cast<int>(CPLHashSetHashStr(path));
607         if( ret == 0 )
608         {
609             copyVSIStatBufLToBuf(&sStatBufL, buf);
610             if( DEBUG_VSIPRELOAD_COND )
611                 fprintf(stderr,
612                         "__lxstat(%s) ret = 0, mode = %d, size=%d\n",
613                         path, sStatBufL.st_mode,
614                         static_cast<int>(sStatBufL.st_size));
615         }
616         return ret;
617     }
618     else
619     {
620         int ret = pfn__lxstat(ver, path, buf);
621         if( ret == 0 )
622         {
623             if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr,
624                 "__lxstat ret = 0, mode = %d\n", buf->st_mode);
625         }
626         return ret;
627     }
628 }
629 
630 /************************************************************************/
631 /*                           __xstat64()                                */
632 /************************************************************************/
633 
__xstat64(int ver,const char * path,struct stat64 * buf)634 int CPL_DLL __xstat64( int ver, const char *path, struct stat64 *buf )
635 {
636     myinit();
637     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
638     if( DEBUG_VSIPRELOAD && (!osCurDir.empty() && path[0] != '/') )
639         DEBUG_VSIPRELOAD_COND = 1;
640     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "__xstat64(%s)\n", path);
641     if( (!osCurDir.empty() && path[0] != '/') || STARTS_WITH(path, "/vsi") )
642     {
643         VSIStatBufL sStatBufL;
644         std::string newpath;
645         if( (!osCurDir.empty() && path[0] != '/') )
646         {
647             newpath = CPLFormFilename(osCurDir.c_str(), path, nullptr);
648             path = newpath.c_str();
649         }
650         const int ret = VSIStatL(path, &sStatBufL);
651         sStatBufL.st_ino = static_cast<int>(CPLHashSetHashStr(path));
652         if( ret == 0 )
653         {
654             copyVSIStatBufLToBuf64(&sStatBufL, buf);
655             if( DEBUG_VSIPRELOAD_COND )
656                 fprintf(stderr,
657                         "__xstat64(%s) ret = 0, mode = %d, size = %d\n",
658                         path, buf->st_mode, static_cast<int>(buf->st_size));
659         }
660         return ret;
661     }
662     else
663         return pfn__xstat64(ver, path, buf);
664 }
665 
666 /************************************************************************/
667 /*                           fseeko64()                                 */
668 /************************************************************************/
669 
fseeko64(FILE * stream,off64_t off,int whence)670 int CPL_DLL fseeko64( FILE *stream, off64_t off, int whence )
671 {
672     myinit();
673     VSILFILE* fpVSIL = getVSILFILE(stream);
674     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
675     if( DEBUG_VSIPRELOAD_COND )
676         fprintf(stderr, "fseeko64(stream=%p, off=%d, whence=%d)\n",
677                 stream, static_cast<int>(off), whence);
678     if( fpVSIL != nullptr )
679         return VSIFSeekLHelper(fpVSIL, off, whence);
680     else
681         return pfnfseeko64(stream, off, whence);
682 }
683 
684 /************************************************************************/
685 /*                           fseeko()                                 */
686 /************************************************************************/
687 
fseeko(FILE * stream,off_t off,int whence)688 int CPL_DLL fseeko( FILE *stream, off_t off, int whence )
689 {
690     myinit();
691     VSILFILE* fpVSIL = getVSILFILE(stream);
692     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
693     if( DEBUG_VSIPRELOAD_COND )
694         fprintf(stderr, "fseeko(stream=%p, off=%d, whence=%d)\n",
695                 stream, static_cast<int>(off), whence);
696     if( fpVSIL != nullptr )
697         return VSIFSeekLHelper(fpVSIL, off, whence);
698     else
699         return pfnfseeko64(stream, off, whence);
700 }
701 
702 /************************************************************************/
703 /*                            fseek()                                   */
704 /************************************************************************/
705 
fseek(FILE * stream,off_t off,int whence)706 int CPL_DLL fseek( FILE *stream, off_t off, int whence )
707 {
708     myinit();
709     VSILFILE* fpVSIL = getVSILFILE(stream);
710     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
711     if( DEBUG_VSIPRELOAD_COND )
712         fprintf(stderr, "fseek(stream=%p, off=%d, whence=%d)\n",
713                 stream, static_cast<int>(off), whence);
714     if( fpVSIL != nullptr )
715         return VSIFSeekLHelper(fpVSIL, off, whence);
716     else
717         return pfnfseek(stream, off, whence);
718 }
719 
720 /************************************************************************/
721 /*                           ftello64()                                 */
722 /************************************************************************/
723 
ftello64(FILE * stream)724 off64_t CPL_DLL ftello64( FILE *stream )
725 {
726     myinit();
727     VSILFILE* fpVSIL = getVSILFILE(stream);
728     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
729     if( DEBUG_VSIPRELOAD_COND )
730         fprintf(stderr, "ftello64(stream=%p)\n", stream);
731     if( fpVSIL != nullptr )
732         return VSIFTellL(fpVSIL);
733     else
734         return pfnftello64(stream);
735 }
736 
737 /************************************************************************/
738 /*                            ftello()                                  */
739 /************************************************************************/
740 
ftello(FILE * stream)741 off_t CPL_DLL ftello( FILE *stream )
742 {
743     myinit();
744     VSILFILE* fpVSIL = getVSILFILE(stream);
745     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
746     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "ftello(stream=%p)\n", stream);
747     if( fpVSIL != nullptr )
748         return VSIFTellL(fpVSIL);
749     else
750         return pfnftello64(stream);
751 }
752 
753 /************************************************************************/
754 /*                            ftell()                                   */
755 /************************************************************************/
756 
ftell(FILE * stream)757 off_t CPL_DLL ftell( FILE *stream )
758 {
759     myinit();
760     VSILFILE* fpVSIL = getVSILFILE(stream);
761     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
762     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "ftell(stream=%p)\n", stream);
763     if( fpVSIL != nullptr )
764         return VSIFTellL(fpVSIL);
765     else
766         return pfnftell(stream);
767 }
768 
769 /************************************************************************/
770 /*                             feof()                                   */
771 /************************************************************************/
772 
feof(FILE * stream)773 int CPL_DLL feof( FILE *stream )
774 {
775     myinit();
776     VSILFILE* fpVSIL = getVSILFILE(stream);
777     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
778     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "feof(stream=%p)\n", stream);
779     if( fpVSIL != nullptr )
780         return VSIFEofL(fpVSIL);
781     else
782         return pfnfeof(stream);
783 }
784 
785 /************************************************************************/
786 /*                            rewind()                                  */
787 /************************************************************************/
788 
rewind(FILE * stream)789 void CPL_DLL rewind( FILE *stream )
790 {
791     fseek(stream, 0, SEEK_SET);
792 }
793 
794 /************************************************************************/
795 /*                            fflush()                                  */
796 /************************************************************************/
797 
fflush(FILE * stream)798 int CPL_DLL fflush( FILE *stream )
799 {
800     myinit();
801     VSILFILE* fpVSIL = getVSILFILE(stream);
802     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
803     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "fflush(stream=%p)\n", stream);
804     if( fpVSIL != nullptr )
805         return 0;
806     else
807         return pfnfflush(stream);
808 }
809 
810 /************************************************************************/
811 /*                            fgetpos()                                 */
812 /************************************************************************/
813 
fgetpos(FILE * stream,fpos_t * pos)814 int CPL_DLL fgetpos( FILE *stream, fpos_t *pos )
815 {
816     myinit();
817     VSILFILE* fpVSIL = getVSILFILE(stream);
818     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
819     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "fgetpos(stream=%p)\n", stream);
820     if( fpVSIL != nullptr )
821     {
822         fprintf(stderr, "fgetpos() unimplemented for VSILFILE\n");
823         return -1; // FIXME
824     }
825     else
826         return pfnfgetpos(stream, pos);
827 }
828 
829 /************************************************************************/
830 /*                            fsetpos()                                 */
831 /************************************************************************/
832 
fsetpos(FILE * stream,fpos_t * pos)833 int CPL_DLL fsetpos( FILE *stream, fpos_t *pos )
834 {
835     myinit();
836     VSILFILE* fpVSIL = getVSILFILE(stream);
837     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
838     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "fsetpos(stream=%p)\n", stream);
839     if( fpVSIL != nullptr )
840     {
841         fprintf(stderr, "fsetpos() unimplemented for VSILFILE\n");
842         return -1; // FIXME
843     }
844     else
845         return pfnfsetpos(stream, pos);
846 }
847 
848 /************************************************************************/
849 /*                             fileno()                                 */
850 /************************************************************************/
851 
fileno(FILE * stream)852 int CPL_DLL fileno( FILE *stream )
853 {
854     myinit();
855     VSILFILE* fpVSIL = getVSILFILE(stream);
856     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
857     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "fileno(stream=%p)\n", stream);
858     int fd = 0;
859     if( fpVSIL != nullptr )
860         fd = getfdFromVSILFILE(fpVSIL);
861     else
862         fd = pfnfileno(stream);
863     if( DEBUG_VSIPRELOAD_COND )
864         fprintf(stderr, "fileno(stream=%p) = %d\n", stream, fd);
865     return fd;
866 }
867 
868 /************************************************************************/
869 /*                             ferror()                                 */
870 /************************************************************************/
871 
ferror(FILE * stream)872 int CPL_DLL ferror( FILE *stream )
873 {
874     myinit();
875     VSILFILE* fpVSIL = getVSILFILE(stream);
876     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
877     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "ferror(stream=%p)\n", stream);
878     if( fpVSIL != nullptr )
879     {
880         fprintf(stderr, "ferror() unimplemented for VSILFILE\n");
881         return 0; // FIXME ?
882     }
883     else
884         return pfnferror(stream);
885 }
886 
887 /************************************************************************/
888 /*                             clearerr()                               */
889 /************************************************************************/
890 
clearerr(FILE * stream)891 void CPL_DLL clearerr( FILE *stream )
892 {
893     myinit();
894     VSILFILE* fpVSIL = getVSILFILE(stream);
895     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
896     if( DEBUG_VSIPRELOAD_COND )
897         fprintf(stderr, "clearerr(stream=%p)\n", stream);
898     if( fpVSIL != nullptr )
899     {
900         fprintf(stderr, "clearerr() unimplemented for VSILFILE\n");
901     }
902     else
903         pfnclearerr(stream);
904 }
905 
906 /************************************************************************/
907 /*                             fdopen()                                 */
908 /************************************************************************/
909 
fdopen(int fd,const char * mode)910 FILE CPL_DLL * fdopen( int fd, const char *mode )
911 {
912     myinit();
913     VSILFILE* fpVSIL = getVSILFILE(fd);
914     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
915     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "fdopen(fd=%d)\n", fd);
916     if( fpVSIL != nullptr )
917     {
918         fprintf(stderr, "fdopen() unimplemented for VSILFILE\n");
919         return nullptr; // FIXME ?
920     }
921     else
922         return pfnfdopen(fd, mode);
923 }
924 
925 /************************************************************************/
926 /*                             freopen()                                */
927 /************************************************************************/
928 
freopen(const char * path,const char * mode,FILE * stream)929 FILE CPL_DLL *freopen( const char *path, const char *mode, FILE *stream )
930 {
931     myinit();
932     VSILFILE* fpVSIL = getVSILFILE(stream);
933     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
934     if( DEBUG_VSIPRELOAD_COND )
935         fprintf(stderr, "freopen(path=%s,mode=%s,stream=%p)\n",
936                 path, mode, stream);
937     if( fpVSIL != nullptr )
938     {
939         fprintf(stderr, "freopen() unimplemented for VSILFILE\n");
940         return nullptr; // FIXME ?
941     }
942     else
943         return pfnfreopen(path, mode, stream);
944 }
945 
946 /************************************************************************/
947 /*                              open()                                  */
948 /************************************************************************/
949 
open(const char * path,int flags,...)950 int CPL_DLL open( const char *path, int flags, ... )
951 {
952     myinit();
953     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
954     if( DEBUG_VSIPRELOAD && !osCurDir.empty() && path[0] != '/' )
955         DEBUG_VSIPRELOAD_COND = 1;
956     if( DEBUG_VSIPRELOAD_COND )
957     {
958         if( !osCurDir.empty() && path[0] != '/' )
959             fprintf(stderr, "open(%s)\n",
960                     CPLFormFilename(osCurDir.c_str(), path, nullptr));
961         else
962             fprintf(stderr, "open(%s)\n", path);
963     }
964 
965     va_list args;
966     va_start(args, flags);
967     mode_t mode = va_arg(args, mode_t);
968     int fd = 0;
969     if( !osCurDir.empty() && path[0] != '/' &&
970         (flags & 3) == O_RDONLY && (flags & O_DIRECTORY) != 0 )
971     {
972         VSIStatBufL sStatBufL;
973         char* newname =
974             const_cast<char *>(CPLFormFilename(osCurDir.c_str(), path, nullptr));
975         if( strchr(osCurDir.c_str(), '/') != nullptr && strcmp(path, "..") == 0 )
976         {
977             char* lastslash = strrchr(newname, '/');
978             if( lastslash != nullptr )
979             {
980                 *lastslash = 0;
981                 lastslash = strrchr(newname, '/');
982                 if( lastslash != nullptr )
983                     *lastslash = 0;
984             }
985         }
986         if( VSIStatL(newname, &sStatBufL) == 0 &&
987             S_ISDIR(sStatBufL.st_mode) )
988         {
989             fd = open("/dev/zero", O_RDONLY);
990             CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX)
991             oMapDirFdToName[fd] = newname;
992         }
993         else
994             fd = -1;
995     }
996     else if( STARTS_WITH(path, "/vsi") )
997         fd = VSIFopenHelper(path, flags);
998     else
999         fd = pfnopen(path, flags, mode);
1000     va_end(args);
1001     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "open(%s) = %d\n", path, fd);
1002     return fd;
1003 }
1004 
1005 /************************************************************************/
1006 /*                             open64()                                 */
1007 /************************************************************************/
1008 
open64(const char * path,int flags,...)1009 int CPL_DLL open64( const char *path, int flags, ... )
1010 {
1011     myinit();
1012     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
1013     if( DEBUG_VSIPRELOAD && !osCurDir.empty() && path[0] != '/' )
1014         DEBUG_VSIPRELOAD_COND = 1;
1015     if( DEBUG_VSIPRELOAD_COND )
1016     {
1017         if( !osCurDir.empty() && path[0] != '/' )
1018             fprintf(stderr, "open64(%s)\n",
1019                     CPLFormFilename(osCurDir.c_str(), path, nullptr));
1020         else
1021             fprintf(stderr, "open64(%s)\n", path);
1022     }
1023 
1024     va_list args;
1025     va_start(args, flags);
1026     mode_t mode = va_arg(args, mode_t);
1027     int fd = 0;
1028     if( !osCurDir.empty() && path[0] != '/' &&
1029         (flags & 3) == O_RDONLY && (flags & O_DIRECTORY) != 0 )
1030     {
1031         VSIStatBufL sStatBufL;
1032         char* newname =
1033             const_cast<char *>(CPLFormFilename(osCurDir.c_str(), path, nullptr));
1034         if( strchr(osCurDir.c_str(), '/') != nullptr && strcmp(path, "..") == 0 )
1035         {
1036             char* lastslash = strrchr(newname, '/');
1037             if( lastslash != nullptr )
1038             {
1039                 *lastslash = 0;
1040                 lastslash = strrchr(newname, '/');
1041                 if( lastslash != nullptr )
1042                     *lastslash = 0;
1043             }
1044         }
1045         if( VSIStatL(newname, &sStatBufL) == 0 &&
1046             S_ISDIR(sStatBufL.st_mode) )
1047         {
1048             fd = open("/dev/zero", O_RDONLY);
1049             CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX)
1050             oMapDirFdToName[fd] = newname;
1051         }
1052         else
1053             fd = -1;
1054     }
1055     else if( STARTS_WITH(path, "/vsi") )
1056         fd = VSIFopenHelper(path, flags);
1057     else
1058         fd = pfnopen64(path, flags, mode);
1059     va_end(args);
1060     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "open64(%s) = %d\n", path, fd);
1061     return fd;
1062 }
1063 
1064 /************************************************************************/
1065 /*                             creat()                                  */
1066 /************************************************************************/
1067 
creat(const char * path,mode_t mode)1068 int CPL_DLL creat( const char *path, mode_t mode )
1069 {
1070     return open64(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
1071 }
1072 
1073 /************************************************************************/
1074 /*                             close()                                  */
1075 /************************************************************************/
1076 
close(int fd)1077 int CPL_DLL close( int fd )
1078 {
1079     myinit();
1080     VSILFILE* fpVSIL = getVSILFILE(fd);
1081     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1082     {
1083         CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
1084         assert( oMapfdToVSIDIRPreload.find(fd) == oMapfdToVSIDIRPreload.end() );
1085 
1086         // cppcheck-suppress redundantIfRemove
1087         if( oMapDirFdToName.find(fd) != oMapDirFdToName.end())
1088         {
1089             oMapDirFdToName.erase(fd);
1090             if( DEBUG_VSIPRELOAD )
1091                 DEBUG_VSIPRELOAD_COND = 1;
1092         }
1093     }
1094     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "close(fd=%d)\n", fd);
1095     if( fpVSIL != nullptr )
1096     {
1097         VSIFCloseL(fpVSIL);
1098         CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
1099         oSetFiles.erase(fpVSIL);
1100         pfnclose(oMapVSITofd[fpVSIL]);
1101         oMapVSITofd.erase(fpVSIL);
1102         oMapfdToVSI.erase(fd);
1103         oMapVSIToString.erase(fpVSIL);
1104         return 0;
1105     }
1106     else
1107         return pfnclose(fd);
1108 }
1109 
1110 /************************************************************************/
1111 /*                              read()                                  */
1112 /************************************************************************/
1113 
read(int fd,void * buf,size_t count)1114 ssize_t CPL_DLL read( int fd, void *buf, size_t count )
1115 {
1116     myinit();
1117     VSILFILE* fpVSIL = getVSILFILE(fd);
1118     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1119     if( DEBUG_VSIPRELOAD_COND )
1120         fprintf(stderr, "read(fd=%d, count=%d)\n",
1121                 fd, static_cast<int>(count));
1122     ssize_t ret = 0;
1123     if( fpVSIL != nullptr )
1124         ret = VSIFReadL(buf, 1, count, fpVSIL);
1125     else
1126         ret = pfnread(fd, buf, count);
1127     if( DEBUG_VSIPRELOAD_COND && DEBUG_OUTPUT_READ && ret < 40 )
1128     {
1129         fprintf(stderr, "read() : ");
1130         for( int i = 0; i < ret; i++ )
1131         {
1132             if( ((unsigned char*)buf)[i] >= 'A' &&
1133                 ((unsigned char*)buf)[i] <= 'Z' )
1134                 fprintf(stderr, "%c ", ((unsigned char*)buf)[i]);
1135             else
1136                 fprintf(stderr, "\\%02X ", ((unsigned char*)buf)[i]);
1137         }
1138         fprintf(stderr, "\n");
1139     }
1140     if( DEBUG_VSIPRELOAD_COND )
1141         fprintf(stderr, "read() -> %d\n", static_cast<int>(ret));
1142     return ret;
1143 }
1144 
1145 /************************************************************************/
1146 /*                              write()                                 */
1147 /************************************************************************/
1148 
write(int fd,const void * buf,size_t count)1149 ssize_t CPL_DLL write( int fd, const void *buf, size_t count )
1150 {
1151     myinit();
1152     VSILFILE* fpVSIL = getVSILFILE(fd);
1153     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1154     if( DEBUG_VSIPRELOAD_COND )
1155         fprintf(stderr, "write(fd=%d, count=%d)\n",
1156                 fd, static_cast<int>(count));
1157     if( fpVSIL != nullptr )
1158         return VSIFWriteL(buf, 1, count, fpVSIL);
1159     else
1160         return pfnwrite(fd, buf, count);
1161 }
1162 
1163 /************************************************************************/
1164 /*                              fsync()                                 */
1165 /************************************************************************/
1166 
fsync(int fd)1167 int CPL_DLL fsync( int fd )
1168 {
1169     myinit();
1170     VSILFILE* fpVSIL = getVSILFILE(fd);
1171     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1172     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "fsync(fd=%d)\n", fd);
1173     if( fpVSIL != nullptr )
1174         return 0;
1175     else
1176         return pfnfsync(fd);
1177 }
1178 
1179 /************************************************************************/
1180 /*                           fdatasync()                                */
1181 /************************************************************************/
1182 
fdatasync(int fd)1183 int CPL_DLL fdatasync( int fd )
1184 {
1185     myinit();
1186     VSILFILE* fpVSIL = getVSILFILE(fd);
1187     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1188     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "fdatasync(fd=%d)\n", fd);
1189     if( fpVSIL != nullptr )
1190         return 0;
1191     else
1192         return pfnfdatasync(fd);
1193 }
1194 
1195 /************************************************************************/
1196 /*                            __fxstat()                                */
1197 /************************************************************************/
1198 
__fxstat(int ver,int fd,struct stat * buf)1199 int CPL_DLL __fxstat( int ver, int fd, struct stat *buf )
1200 {
1201     myinit();
1202     VSILFILE* fpVSIL = getVSILFILE(fd);
1203     std::string name;
1204     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1205     {
1206         CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX)
1207         if( oMapDirFdToName.find(fd) != oMapDirFdToName.end())
1208         {
1209             name = oMapDirFdToName[fd];
1210             if( DEBUG_VSIPRELOAD )
1211                 DEBUG_VSIPRELOAD_COND = 1;
1212         }
1213     }
1214     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "__fxstat(fd=%d)\n", fd);
1215     if( !name.empty() )
1216     {
1217         VSIStatBufL sStatBufL;
1218         if( DEBUG_VSIPRELOAD_COND )
1219             fprintf(stderr, "__fxstat(%s)\n", name.c_str());
1220         int ret = VSIStatL(name.c_str(), &sStatBufL);
1221         sStatBufL.st_ino = static_cast<int>(CPLHashSetHashStr(name.c_str()));
1222         if( ret == 0 )
1223         {
1224             copyVSIStatBufLToBuf(&sStatBufL, buf);
1225             if( DEBUG_VSIPRELOAD_COND )
1226                 fprintf(stderr,
1227                         "__fxstat ret = 0, mode = %d, size = %d\n",
1228                         sStatBufL.st_mode, static_cast<int>(sStatBufL.st_size));
1229         }
1230         return ret;
1231     }
1232     else if( fpVSIL != nullptr )
1233     {
1234         VSIStatBufL sStatBufL;
1235         {
1236             CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
1237             name = oMapVSIToString[fpVSIL];
1238         }
1239         int ret = VSIStatL(name.c_str(), &sStatBufL);
1240         sStatBufL.st_ino = static_cast<int>(CPLHashSetHashStr(name.c_str()));
1241         if( ret == 0 )
1242         {
1243             copyVSIStatBufLToBuf(&sStatBufL, buf);
1244             if( DEBUG_VSIPRELOAD_COND )
1245                 fprintf(stderr,
1246                         "__fxstat ret = 0, mode = %d, size = %d\n",
1247                         sStatBufL.st_mode, static_cast<int>(sStatBufL.st_size));
1248         }
1249         return ret;
1250     }
1251     else
1252         return pfn__fxstat(ver, fd, buf);
1253 }
1254 
1255 /************************************************************************/
1256 /*                           __fxstat64()                               */
1257 /************************************************************************/
1258 
__fxstat64(int ver,int fd,struct stat64 * buf)1259 int CPL_DLL __fxstat64( int ver, int fd, struct stat64 *buf )
1260 {
1261     myinit();
1262     VSILFILE* fpVSIL = getVSILFILE(fd);
1263     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1264     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "__fxstat64(fd=%d)\n", fd);
1265     if( fpVSIL != nullptr )
1266     {
1267         VSIStatBufL sStatBufL;
1268         std::string name;
1269         {
1270             CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
1271             name = oMapVSIToString[fpVSIL];
1272         }
1273         int ret = VSIStatL(name.c_str(), &sStatBufL);
1274         sStatBufL.st_ino = static_cast<int>(CPLHashSetHashStr(name.c_str()));
1275         if( ret == 0 )
1276         {
1277             copyVSIStatBufLToBuf64(&sStatBufL, buf);
1278             if( DEBUG_VSIPRELOAD_COND )
1279                 fprintf(stderr,
1280                         "__fxstat64 ret = 0, mode = %d, size = %d\n",
1281                         buf->st_mode, static_cast<int>(buf->st_size));
1282         }
1283         return ret;
1284     }
1285     else
1286         return pfn__fxstat64(ver, fd, buf);
1287 }
1288 
1289 /************************************************************************/
1290 /*                           __fxstatat()                               */
1291 /************************************************************************/
1292 
1293 #ifdef HAVE_FSTATAT
__fxstatat(int ver,int dirfd,const char * pathname,struct stat * buf,int flags)1294 int CPL_DLL __fxstatat( int ver, int dirfd, const char *pathname, struct stat *buf,
1295                 int flags )
1296 {
1297     myinit();
1298     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(pathname);
1299     if( DEBUG_VSIPRELOAD && !osCurDir.empty() )
1300         DEBUG_VSIPRELOAD_COND = 1;
1301     if( DEBUG_VSIPRELOAD_COND )
1302         fprintf(stderr, "__fxstatat(dirfd=%d,pathname=%s,flags=%d)\n",
1303                 dirfd, pathname, flags);
1304 
1305     if( !osCurDir.empty() || STARTS_WITH(pathname, "/vsi") )
1306     {
1307         VSIStatBufL sStatBufL;
1308         if( !osCurDir.empty() && dirfd == AT_FDCWD && pathname[0] != '/' )
1309             pathname = CPLFormFilename(osCurDir.c_str(), pathname, nullptr);
1310         const int ret = VSIStatL(pathname, &sStatBufL);
1311         sStatBufL.st_ino = static_cast<int>(CPLHashSetHashStr(pathname));
1312         if( ret == 0 )
1313         {
1314             copyVSIStatBufLToBuf(&sStatBufL, buf);
1315             if( DEBUG_VSIPRELOAD_COND )
1316                 fprintf(stderr,
1317                         "__fxstatat(%s) ret = 0, mode = %d, size = %d\n",
1318                         pathname, buf->st_mode, static_cast<int>(buf->st_size));
1319         }
1320         return ret;
1321     }
1322     else
1323         return pfn__fxstatat(ver, dirfd, pathname, buf, flags);
1324 }
1325 #endif
1326 
1327 /************************************************************************/
1328 /*                              lseek()                                 */
1329 /************************************************************************/
1330 
lseek(int fd,off_t off,int whence)1331 off_t CPL_DLL lseek( int fd, off_t off, int whence )
1332 {
1333     myinit();
1334     off_t ret;
1335     VSILFILE* fpVSIL = getVSILFILE(fd);
1336     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1337     if( DEBUG_VSIPRELOAD_COND )
1338         fprintf(stderr,
1339                 "lseek(fd=%d, off=%d, whence=%d)\n",
1340                 fd, static_cast<int>(off), whence);
1341     if( fpVSIL != nullptr )
1342     {
1343         VSIFSeekLHelper(fpVSIL, off, whence);
1344         ret = VSIFTellL(fpVSIL);
1345     }
1346     else
1347         ret = pfnlseek(fd, off, whence);
1348     if( DEBUG_VSIPRELOAD_COND )
1349         fprintf(stderr, "lseek() -> ret = %d\n", static_cast<int>(ret));
1350     return ret;
1351 }
1352 
1353 /************************************************************************/
1354 /*                             lseek64()                                */
1355 /************************************************************************/
1356 
lseek64(int fd,off64_t off,int whence)1357 off64_t CPL_DLL lseek64( int fd, off64_t off, int whence )
1358 {
1359     myinit();
1360     off_t ret;
1361     VSILFILE* fpVSIL = getVSILFILE(fd);
1362     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1363     if( DEBUG_VSIPRELOAD_COND )
1364         fprintf(stderr,
1365                 "lseek64(fd=%d, off=%d, whence=%d)\n",
1366                 fd, static_cast<int>(off), whence);
1367     if( fpVSIL != nullptr )
1368     {
1369         VSIFSeekLHelper(fpVSIL, off, whence);
1370         ret = VSIFTellL(fpVSIL);
1371     }
1372     else
1373         ret = pfnlseek64(fd, off, whence);
1374     if( DEBUG_VSIPRELOAD_COND )
1375         fprintf(stderr,
1376                 "lseek64() -> ret = %d\n", static_cast<int>(ret));
1377     return ret;
1378 }
1379 
1380 /************************************************************************/
1381 /*                            truncate()                                */
1382 /************************************************************************/
1383 
truncate(const char * path,off_t length)1384 int CPL_DLL truncate( const char *path, off_t length )
1385 {
1386     myinit();
1387     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
1388     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "truncate(%s)\n", path);
1389 
1390     int ret = 0;
1391     if( STARTS_WITH(path, "/vsi") )
1392     {
1393         VSILFILE* fpVSIL = VSIFOpenL(path, "wb+");
1394         if( fpVSIL )
1395         {
1396             ret = VSIFTruncateL(fpVSIL, length);
1397             VSIFCloseL(fpVSIL);
1398         }
1399         else
1400             ret = -1;
1401     }
1402     else
1403         ret = pfntruncate(path, length);
1404     return ret;
1405 }
1406 
1407 /************************************************************************/
1408 /*                           ftruncate()                                */
1409 /************************************************************************/
1410 
ftruncate(int fd,off_t length)1411 int CPL_DLL ftruncate( int fd, off_t length )
1412 {
1413     myinit();
1414     VSILFILE* fpVSIL = getVSILFILE(fd);
1415     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1416     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "ftruncate(fd=%d)\n", fd);
1417     int ret = 0;
1418     if( fpVSIL != nullptr )
1419     {
1420         ret = VSIFTruncateL(fpVSIL, length);
1421     }
1422     else
1423         ret = pfnftruncate(fd, length);
1424     return ret;
1425 }
1426 
1427 /************************************************************************/
1428 /*                             opendir()                                */
1429 /************************************************************************/
1430 
opendir(const char * name)1431 DIR CPL_DLL *opendir( const char *name )
1432 {
1433     myinit();
1434     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(name);
1435     if( DEBUG_VSIPRELOAD && !osCurDir.empty() )
1436         DEBUG_VSIPRELOAD_COND = 1;
1437     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "opendir(%s)\n", name);
1438 
1439     DIR * ret;
1440     if( !osCurDir.empty() || STARTS_WITH(name, "/vsi") )
1441     {
1442         char** papszDir;
1443         if( !osCurDir.empty() && name[0] != '/' )
1444             name = CPLFormFilename(osCurDir.c_str(), name, nullptr);
1445         papszDir = VSIReadDir(name);
1446         if( papszDir == nullptr )
1447         {
1448             VSIStatBufL sStatBufL;
1449             if( VSIStatL(name, &sStatBufL) == 0 && S_ISDIR(sStatBufL.st_mode) )
1450             {
1451                 papszDir = static_cast<char **>(CPLMalloc(sizeof(char*)));
1452                 papszDir[0] = nullptr;
1453             }
1454         }
1455         if( papszDir == nullptr )
1456             ret = nullptr;
1457         else
1458         {
1459             VSIDIRPreload* mydir = static_cast<VSIDIRPreload *>(malloc(sizeof(VSIDIRPreload)));
1460             mydir->pszDirname = CPLStrdup(name);
1461             mydir->papszDir = papszDir;
1462             mydir->nIter = 0;
1463             mydir->fd = -1;
1464             ret = (DIR*)mydir;
1465             CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
1466             oSetVSIDIRPreload.insert(mydir);
1467         }
1468     }
1469     else
1470     {
1471         ret = pfnopendir(name);
1472     }
1473     if( DEBUG_VSIPRELOAD_COND )
1474         fprintf(stderr, "opendir(%s) -> %p\n", name, ret);
1475     return ret;
1476 }
1477 
1478 /************************************************************************/
1479 /*                             filldir()                                */
1480 /************************************************************************/
1481 
filldir(VSIDIRPreload * mydir)1482 static bool filldir( VSIDIRPreload* mydir )
1483 {
1484     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(mydir);
1485     char* pszName = mydir->papszDir[mydir->nIter++];
1486     if( pszName == nullptr )
1487         return false;
1488     mydir->ent.d_ino = 0;
1489     mydir->ent.d_off = 0;
1490     mydir->ent.d_reclen = sizeof(mydir->ent);
1491     VSIStatBufL sStatBufL;
1492     CPL_IGNORE_RET_VAL(VSIStatL(CPLFormFilename(mydir->pszDirname, pszName, nullptr), &sStatBufL));
1493     if( DEBUG_VSIPRELOAD_COND && S_ISDIR(sStatBufL.st_mode) )
1494         fprintf(stderr, "%s is dir\n", pszName);
1495     mydir->ent.d_type = S_ISDIR(sStatBufL.st_mode) ? DT_DIR :
1496                         S_ISREG(sStatBufL.st_mode) ? DT_REG :
1497                         S_ISLNK(sStatBufL.st_mode) ? DT_LNK :
1498                         DT_UNKNOWN;
1499     strncpy(mydir->ent.d_name, pszName, 256);
1500     mydir->ent.d_name[255] = '\0';
1501 
1502     mydir->ent64.d_ino = 0;
1503     mydir->ent64.d_off = 0;
1504     mydir->ent64.d_reclen = sizeof(mydir->ent64);
1505     mydir->ent64.d_type = mydir->ent.d_type;
1506     strcpy(mydir->ent64.d_name, mydir->ent.d_name);
1507 
1508     return true;
1509 }
1510 
1511 /************************************************************************/
1512 /*                             readdir()                                */
1513 /************************************************************************/
1514 
readdir(DIR * dirp)1515 struct dirent CPL_DLL *readdir( DIR *dirp )
1516 {
1517     myinit();
1518     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND((VSIDIRPreload*)dirp);
1519     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "readdir(%p)\n", dirp);
1520     if( oSetVSIDIRPreload.find((VSIDIRPreload*)dirp) != oSetVSIDIRPreload.end() )
1521     {
1522         VSIDIRPreload* mydir = (VSIDIRPreload*)dirp;
1523         if( !filldir(mydir) )
1524             return nullptr;
1525 
1526         return &(mydir->ent);
1527     }
1528     else
1529         return pfnreaddir(dirp);
1530 }
1531 
1532 /************************************************************************/
1533 /*                             readdir64()                              */
1534 /************************************************************************/
1535 
readdir64(DIR * dirp)1536 struct dirent64 CPL_DLL *readdir64( DIR *dirp )
1537 {
1538     myinit();
1539     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND((VSIDIRPreload*)dirp);
1540     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "readdir64(%p)\n", dirp);
1541     if( oSetVSIDIRPreload.find((VSIDIRPreload*)dirp) != oSetVSIDIRPreload.end() )
1542     {
1543         VSIDIRPreload* mydir = (VSIDIRPreload*)dirp;
1544         if( !filldir(mydir) )
1545             return nullptr;
1546 
1547         return &(mydir->ent64);
1548     }
1549     else
1550         return pfnreaddir64(dirp);
1551 }
1552 
1553 /************************************************************************/
1554 /*                             closedir()                               */
1555 /************************************************************************/
1556 
closedir(DIR * dirp)1557 int CPL_DLL closedir( DIR *dirp )
1558 {
1559     myinit();
1560     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND((VSIDIRPreload*)dirp);
1561     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "closedir(%p)\n", dirp);
1562     if( oSetVSIDIRPreload.find((VSIDIRPreload*)dirp) != oSetVSIDIRPreload.end() )
1563     {
1564         VSIDIRPreload* mydir = (VSIDIRPreload*)dirp;
1565         CPLFree(mydir->pszDirname);
1566         CSLDestroy(mydir->papszDir);
1567         CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
1568         if( mydir->fd >= 0 )
1569         {
1570             oMapfdToVSIDIRPreload.erase(mydir->fd);
1571             close(mydir->fd);
1572         }
1573         oSetVSIDIRPreload.erase(mydir);
1574         free(mydir);
1575         return 0;
1576     }
1577     else
1578         return pfnclosedir(dirp);
1579 }
1580 
1581 /************************************************************************/
1582 /*                               dirfd()                                */
1583 /************************************************************************/
1584 
dirfd(DIR * dirp)1585 int CPL_DLL dirfd( DIR *dirp )
1586 {
1587     myinit();
1588     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND((VSIDIRPreload*)dirp);
1589     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "dirfd(%p)\n", dirp);
1590     int ret = 0;
1591     if( oSetVSIDIRPreload.find((VSIDIRPreload*)dirp) != oSetVSIDIRPreload.end() )
1592     {
1593         VSIDIRPreload* mydir = (VSIDIRPreload*)dirp;
1594         if( mydir->fd < 0 )
1595         {
1596             mydir->fd = open("/dev/zero", O_RDONLY);
1597             CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
1598             oMapfdToVSIDIRPreload[mydir->fd] = mydir;
1599         }
1600         ret = mydir->fd;
1601     }
1602     else
1603         ret = pfndirfd(dirp);
1604     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "dirfd(%p) -> %d\n", dirp, ret);
1605     return ret;
1606 }
1607 
1608 /************************************************************************/
1609 /*                              fchdir()                                */
1610 /************************************************************************/
1611 
fchdir(int fd)1612 int CPL_DLL fchdir( int fd )
1613 {
1614     VSIDIRPreload* mydir = nullptr;
1615     {
1616         CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
1617         if( oMapfdToVSIDIRPreload.find(fd) != oMapfdToVSIDIRPreload.end() )
1618             mydir = oMapfdToVSIDIRPreload[fd];
1619     }
1620     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(mydir);
1621     std::string name;
1622     {
1623         CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX)
1624         if( oMapDirFdToName.find(fd) != oMapDirFdToName.end())
1625         {
1626             name = oMapDirFdToName[fd];
1627             if( DEBUG_VSIPRELOAD )
1628                 DEBUG_VSIPRELOAD_COND = 1;
1629         }
1630     }
1631     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "fchdir(%d)\n", fd);
1632     if( !name.empty() )
1633     {
1634         osCurDir = name;
1635         if( DEBUG_VSIPRELOAD_COND )
1636             fprintf(stderr, "fchdir(%d) -> %s\n", fd, osCurDir.c_str());
1637         return 0;
1638     }
1639     else if( mydir != nullptr )
1640     {
1641         osCurDir = mydir->pszDirname;
1642         if( DEBUG_VSIPRELOAD_COND )
1643             fprintf(stderr, "fchdir(%d) -> %s\n", fd, osCurDir.c_str());
1644         return 0;
1645     }
1646     else
1647     {
1648         osCurDir = "";
1649         if( DEBUG_VSIPRELOAD_COND )
1650             fprintf(stderr, "fchdir(%d) -> %s\n", fd, osCurDir.c_str());
1651         return pfnfchdir(fd);
1652     }
1653 }
1654 
1655 /************************************************************************/
1656 /*                        acl_extended_file()                           */
1657 /************************************************************************/
1658 
1659 // #include <acl/acl.h>
1660 extern "C" int CPL_DLL acl_extended_file(const char *name);
1661 DECLARE_SYMBOL(acl_extended_file, int, (const char *name));
1662 
acl_extended_file(const char * path)1663 int acl_extended_file( const char *path )
1664 {
1665     myinit();
1666     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
1667     if( DEBUG_VSIPRELOAD_COND )
1668         fprintf(stderr, "acl_extended_file(%s)\n", path);
1669     int ret = 0;
1670     if( STARTS_WITH(path, "/vsi") )
1671         ret = -1;
1672     else
1673     {
1674         if( pfnacl_extended_file == nullptr )
1675             pfnacl_extended_file =
1676                 (fnacl_extended_fileType) dlsym(RTLD_NEXT, "acl_extended_file");
1677         if( pfnacl_extended_file == nullptr )
1678             ret = -1;
1679         else
1680             ret = pfnacl_extended_file(path);
1681     }
1682     return ret;
1683 }
1684 
1685 /************************************************************************/
1686 /*                          getfilecon()                                */
1687 /************************************************************************/
1688 
1689 // #include <selinux/selinux.h>
1690 extern "C" int CPL_DLL getfilecon(const char *name, void* con);
1691 DECLARE_SYMBOL(getfilecon, int, (const char *name, void* con));
1692 
getfilecon(const char * path,void * con)1693 int getfilecon( const char *path, /*security_context_t **/ void* con )
1694 {
1695     myinit();
1696     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
1697     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "getfilecon(%s)\n", path);
1698     int ret = 0;
1699     if( STARTS_WITH(path, "/vsi") )
1700     {
1701         errno = ENOTSUP;
1702         ret = -1;
1703     }
1704     else
1705     {
1706         if( pfngetfilecon == nullptr )
1707             pfngetfilecon = (fngetfileconType) dlsym(RTLD_NEXT, "getfilecon");
1708         if( pfngetfilecon == nullptr )
1709             ret = -1;
1710         else
1711             ret = pfngetfilecon(path, con);
1712     }
1713     return ret;
1714 }
1715 
1716 /************************************************************************/
1717 /*                          lgetfilecon()                                */
1718 /************************************************************************/
1719 
1720 // #include <selinux/selinux.h>
1721 extern "C" int CPL_DLL lgetfilecon(const char *name, void* con);
1722 DECLARE_SYMBOL(lgetfilecon, int, (const char *name, void* con));
1723 
lgetfilecon(const char * path,void * con)1724 int lgetfilecon(const char *path, /*security_context_t **/ void* con)
1725 {
1726     myinit();
1727     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
1728     if( DEBUG_VSIPRELOAD_COND ) fprintf(stderr, "lgetfilecon(%s)\n", path);
1729     int ret = 0;
1730     if( STARTS_WITH(path, "/vsi") )
1731     {
1732         errno = ENOTSUP;
1733         ret = -1;
1734     }
1735     else
1736     {
1737         if( pfnlgetfilecon == nullptr )
1738             pfnlgetfilecon =
1739                 (fnlgetfileconType) dlsym(RTLD_NEXT, "lgetfilecon");
1740         if( pfnlgetfilecon == nullptr )
1741             ret = -1;
1742         else
1743             ret = pfnlgetfilecon(path, con);
1744     }
1745     return ret;
1746 }
1747