vsipreload.cpp

Etienne Tourigny, 2014-05-07 07:09 PM

Download (55.1 KB)

 
1
/******************************************************************************
2
 * $Id: vsipreload.cpp 27044 2014-03-16 23:41:27Z rouault $
3
 *
4
 * Project:  CPL - Common Portability Library
5
 * Purpose:  Standalone shared library that can be LD_PRELOAD'ed as an overload of
6
 *           libc to enable VSI Virtual FILE API to be used with binaries using
7
 *           regular libc for I/O.
8
 * Author:   Even Rouault <even dot rouault at mines dash paris.org>
9
 *
10
 ******************************************************************************
11
 * Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org>
12
 *
13
 * Permission is hereby granted, free of charge, to any person obtaining a
14
 * copy of this software and associated documentation files (the "Software"),
15
 * to deal in the Software without restriction, including without limitation
16
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17
 * and/or sell copies of the Software, and to permit persons to whom the
18
 * Software is furnished to do so, subject to the following conditions:
19
 *
20
 * The above copyright notice and this permission notice shall be included
21
 * in all copies or substantial portions of the Software.
22
 *
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29
 * DEALINGS IN THE SOFTWARE.
30
 ****************************************************************************/
31

    
32
// WARNING: Linux glibc ONLY
33
// Might work with some adaptations (mainly around 64bit symbols) on other Unix systems
34

    
35
// Compile:
36
// g++ -Wall -fPIC port/vsipreload.cpp -shared -o vsipreload.so -Iport -L. -L.libs -lgdal
37

    
38
// Run:
39
// LD_PRELOAD=./vsipreload.so ....
40
// e.g: 
41
// LD_PRELOAD=./vsipreload.so gdalinfo /vsicurl/http://download.osgeo.org/gdal/data/ecw/spif83.ecw
42
// 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'
43
// LD_PRELOAD=./vsipreload.so ogrinfo /vsicurl/http://svn.osgeo.org/gdal/trunk/autotest/ogr/data/testavc -ro
44
// even non GDAL binaries :
45
// LD_PRELOAD=./vsipreload.so h5dump -d /x /vsicurl/http://download.osgeo.org/gdal/data/netcdf/utm-big-chunks.nc
46
// LD_PRELOAD=./vsipreload.so sqlite3 /vsicurl/http://download.osgeo.org/gdal/data/sqlite3/polygon.db "select * from polygon limit 10"
47
// LD_PRELOAD=./vsipreload.so ls -al /vsicurl/http://download.osgeo.org/gdal/data/sqlite3
48
// LD_PRELOAD=./vsipreload.so find /vsicurl/http://download.osgeo.org/gdal/data/sqlite3
49

    
50
#define _GNU_SOURCE 1
51
#define _LARGEFILE64_SOURCE 1
52
#include <stdio.h>
53
#include <stdlib.h>
54
#include <assert.h>
55
#include <dlfcn.h>
56
#include <string.h>
57
#include <fcntl.h>
58
#include <unistd.h>
59
#include <dirent.h>
60
#include <sys/types.h>
61
#include <sys/stat.h>
62

    
63
#include <set>
64
#include <map>
65
#include <string>
66
#include "cpl_vsi.h"
67
#include "cpl_multiproc.h"
68
#include "cpl_string.h"
69
#include "cpl_hash_set.h"
70

    
71
CPL_CVSID("$Id: vsipreload.cpp 27044 2014-03-16 23:41:27Z rouault $");
72

    
73
static int DEBUG_VSIPRELOAD = 0;
74
static int DEBUG_VSIPRELOAD_ONLY_VSIL = 1;
75
#define DEBUG_OUTPUT_READ 0
76

    
77
#ifndef NO_FSTATAT
78
#define HAVE_FSTATAT
79
#endif
80

    
81
#define DECLARE_SYMBOL(x, retType, args) \
82
    typedef retType (*fn ## x ## Type)args;\
83
    static fn ## x ## Type pfn ## x = NULL
84

    
85
DECLARE_SYMBOL(fopen, FILE*, (const char *path, const char *mode));
86
DECLARE_SYMBOL(fopen64, FILE*, (const char *path, const char *mode));
87
DECLARE_SYMBOL(fread, size_t, (void *ptr, size_t size, size_t nmemb, FILE *stream));
88
DECLARE_SYMBOL(fwrite, size_t, (const void *ptr, size_t size, size_t nmemb, FILE *stream));
89
DECLARE_SYMBOL(fclose, int, (FILE *stream));
90
DECLARE_SYMBOL(__xstat, int, (int ver, const char *path, struct stat *buf));
91
DECLARE_SYMBOL(__lxstat, int, (int ver, const char *path, struct stat *buf));
92
DECLARE_SYMBOL(__xstat64, int, (int ver, const char *path, struct stat64 *buf));
93
DECLARE_SYMBOL(fseeko64, int, (FILE *stream, off64_t off, int whence));
94
DECLARE_SYMBOL(fseek, int, (FILE *stream, off_t off, int whence));
95
DECLARE_SYMBOL(ftello64, off64_t, (FILE *stream));
96
DECLARE_SYMBOL(ftell, off_t, (FILE *stream));
97
DECLARE_SYMBOL(feof, int, (FILE *stream));
98
DECLARE_SYMBOL(fflush, int, (FILE *stream));
99
DECLARE_SYMBOL(fgetpos, int, (FILE *stream, fpos_t *pos));
100
DECLARE_SYMBOL(fsetpos, int, (FILE *stream, fpos_t *pos));
101
DECLARE_SYMBOL(fileno, int, (FILE *stream));
102
DECLARE_SYMBOL(ferror, int, (FILE *stream));
103

    
104
DECLARE_SYMBOL(fdopen, FILE*, (int fd, const char *mode));
105
DECLARE_SYMBOL(freopen, FILE*, (const char *path, const char *mode, FILE *stream));
106

    
107
DECLARE_SYMBOL(open, int, (const char *path, int flags, mode_t mode));
108
DECLARE_SYMBOL(open64, int, (const char *path, int flags, mode_t mode));
109
//DECLARE_SYMBOL(creat, int, (const char *path, mode_t mode));
110
DECLARE_SYMBOL(close, int, (int fd));
111
DECLARE_SYMBOL(read, ssize_t, (int fd, void *buf, size_t count));
112
DECLARE_SYMBOL(write, ssize_t, (int fd, const void *buf, size_t count));
113
DECLARE_SYMBOL(fsync, int, (int fd));
114
DECLARE_SYMBOL(fdatasync, int, (int fd));
115
DECLARE_SYMBOL(__fxstat, int, (int ver, int fd, struct stat *__stat_buf));
116
DECLARE_SYMBOL(__fxstat64, int, (int ver, int fd, struct stat64 *__stat_buf));
117
#ifdef HAVE_FSTATAT
118
DECLARE_SYMBOL(__fxstatat, int, (int ver, int dirfd, const char *pathname, struct stat *buf, int flags));
119
#endif
120

    
121
DECLARE_SYMBOL(lseek, off_t, (int fd, off_t off, int whence));
122
DECLARE_SYMBOL(lseek64, off64_t , (int fd, off64_t off, int whence));
123

    
124
DECLARE_SYMBOL(truncate, int, (const char *path, off_t length));
125
DECLARE_SYMBOL(ftruncate, int, (int fd, off_t length));
126

    
127
DECLARE_SYMBOL(opendir, DIR* , (const char *name));
128
DECLARE_SYMBOL(readdir, struct dirent*, (DIR *dirp));
129
DECLARE_SYMBOL(closedir, int, (DIR *dirp));
130
DECLARE_SYMBOL(dirfd, int, (DIR *dirp));
131
DECLARE_SYMBOL(fchdir, int, (int fd));
132

    
133
static void* hMutex = NULL;
134

    
135
typedef struct
136
{
137
    char*  pszDirname;
138
    char** papszDir;
139
    int    nIter;
140
    struct dirent ent;
141
    int    fd;
142
} VSIDIR;
143

    
144
std::set<VSILFILE*> oSetFiles;
145
std::map<int, VSILFILE*> oMapfdToVSI;
146
std::map<VSILFILE*, int> oMapVSITofd;
147
std::map<VSILFILE*, std::string> oMapVSIToString;
148
std::set<VSIDIR*> oSetVSIDIR;
149
std::map<int, VSIDIR*> oMapfdToVSIDIR;
150
std::map<int, std::string> oMapDirFdToName;
151
std::string osCurDir;
152

    
153
/************************************************************************/
154
/*                             myinit()                                 */
155
/************************************************************************/
156

    
157
#define LOAD_SYMBOL(x) \
158
    pfn ## x = (fn ## x ## Type) dlsym(RTLD_NEXT, #x); \
159
    assert(pfn ## x)
160

    
161
static void myinit(void)
162
{
163
    CPLMutexHolderD(&hMutex);
164

    
165
    if( pfnfopen64 != NULL ) return;
166
    DEBUG_VSIPRELOAD = getenv("DEBUG_VSIPRELOAD") != NULL;
167
    LOAD_SYMBOL(fopen);
168
    LOAD_SYMBOL(fopen64);
169
    LOAD_SYMBOL(fread);
170
    LOAD_SYMBOL(fwrite);
171
    LOAD_SYMBOL(fclose);
172
    LOAD_SYMBOL(fseeko64);
173
    LOAD_SYMBOL(fseek);
174
    LOAD_SYMBOL(__xstat);
175
    LOAD_SYMBOL(__lxstat);
176
    LOAD_SYMBOL(__xstat64);
177
    LOAD_SYMBOL(ftello64);
178
    LOAD_SYMBOL(ftell);
179
    LOAD_SYMBOL(feof);
180
    LOAD_SYMBOL(fflush);
181
    LOAD_SYMBOL(fgetpos);
182
    LOAD_SYMBOL(fsetpos);
183
    LOAD_SYMBOL(fileno);
184
    LOAD_SYMBOL(ferror);
185

    
186
    LOAD_SYMBOL(fdopen);
187
    LOAD_SYMBOL(freopen);
188

    
189
    LOAD_SYMBOL(open);
190
    LOAD_SYMBOL(open64);
191
    //LOAD_SYMBOL(creat);
192
    LOAD_SYMBOL(close);
193
    LOAD_SYMBOL(read);
194
    LOAD_SYMBOL(write);
195
    LOAD_SYMBOL(fsync);
196
    LOAD_SYMBOL(fdatasync);
197
    LOAD_SYMBOL(__fxstat);
198
    LOAD_SYMBOL(__fxstat64);
199
#ifdef HAVE_FSTATAT
200
    LOAD_SYMBOL(__fxstatat);
201
#endif
202
    LOAD_SYMBOL(lseek);
203
    LOAD_SYMBOL(lseek64);
204

    
205
    LOAD_SYMBOL(truncate);
206
    LOAD_SYMBOL(ftruncate);
207

    
208
    LOAD_SYMBOL(opendir);
209
    LOAD_SYMBOL(readdir);
210
    LOAD_SYMBOL(closedir);
211
    LOAD_SYMBOL(dirfd);
212
    LOAD_SYMBOL(fchdir);
213
}
214

    
215
/************************************************************************/
216
/*                          getVSILFILE()                               */
217
/************************************************************************/
218

    
219
static VSILFILE* getVSILFILE(FILE* stream)
220
{
221
    VSILFILE* ret;
222
    CPLMutexHolderD(&hMutex);
223
    std::set<VSILFILE*>::iterator oIter = oSetFiles.find((VSILFILE*)stream);
224
    if( oIter != oSetFiles.end() )
225
        ret = *oIter;
226
    else
227
        ret = NULL;
228
    return ret;
229
}
230

    
231
/************************************************************************/
232
/*                          getVSILFILE()                               */
233
/************************************************************************/
234

    
235
static VSILFILE* getVSILFILE(int fd)
236
{
237
    VSILFILE* ret;
238
    CPLMutexHolderD(&hMutex);
239
    std::map<int, VSILFILE*>::iterator oIter = oMapfdToVSI.find(fd);
240
    if( oIter != oMapfdToVSI.end() )
241
        ret = oIter->second;
242
    else
243
        ret = NULL;
244
    return ret;
245
}
246

    
247
/************************************************************************/
248
/*                        VSIFSeekLHelper()                             */
249
/************************************************************************/
250

    
251
static int VSIFSeekLHelper(VSILFILE* fpVSIL, off64_t off, int whence)
252
{
253
    if( off < 0 && whence == SEEK_CUR )
254
    {
255
        return VSIFSeekL(fpVSIL, VSIFTellL(fpVSIL) + off, SEEK_SET);
256
    }
257
    else if( off < 0 && whence == SEEK_END )
258
    {
259
        VSIFSeekL(fpVSIL, 0, SEEK_END);
260
        return VSIFSeekL(fpVSIL, VSIFTellL(fpVSIL) + off, SEEK_SET);
261
    }
262
    else
263
        return VSIFSeekL(fpVSIL, off, whence);
264
}
265

    
266
/************************************************************************/
267
/*                          VSIFopenHelper()                            */
268
/************************************************************************/
269

    
270
static VSILFILE* VSIFfopenHelper(const char *path, const char *mode)
271
{
272
    VSILFILE* fpVSIL = VSIFOpenL(path, mode);
273
    if( fpVSIL != NULL )
274
    {
275
        CPLMutexHolderD(&hMutex);
276
        oSetFiles.insert(fpVSIL);
277
        oMapVSIToString[fpVSIL] = path;
278
    }
279
    return fpVSIL;
280
}
281

    
282
/************************************************************************/
283
/*                         getfdFromVSILFILE()                          */
284
/************************************************************************/
285

    
286
static int getfdFromVSILFILE(VSILFILE* fpVSIL)
287
{
288
    CPLMutexHolderD(&hMutex);
289

    
290
    int fd;
291
    std::map<VSILFILE*, int>::iterator oIter = oMapVSITofd.find(fpVSIL);
292
    if( oIter != oMapVSITofd.end() )
293
        fd = oIter->second;
294
    else
295
    {
296
        fd = open("/dev/zero", O_RDONLY);
297
        assert(fd >= 0);
298
        oMapVSITofd[fpVSIL] = fd;
299
        oMapfdToVSI[fd] = fpVSIL;
300
    }
301
    return fd;
302
}
303

    
304
/************************************************************************/
305
/*                          VSIFopenHelper()                            */
306
/************************************************************************/
307

    
308
static int VSIFopenHelper(const char *path, int flags)
309
{
310
    const char* pszMode = "rb";
311
    if ((flags & 3) == O_RDONLY) 
312
        pszMode = "rb";
313
    else if ((flags & 3) == O_WRONLY) 
314
    {
315
        if( flags & O_APPEND )
316
            pszMode = "ab";
317
        else
318
            pszMode = "wb";
319
    }
320
    else
321
    {
322
        if( flags & O_APPEND )
323
            pszMode = "ab+";
324
        else
325
            pszMode = "rb+";
326
    }
327
    VSILFILE* fpVSIL = VSIFfopenHelper(path, pszMode );
328
    int fd;
329
    if( fpVSIL != NULL )
330
    {
331
        if( flags & O_TRUNC )
332
        {
333
            VSIFTruncateL(fpVSIL, 0);
334
            VSIFSeekL(fpVSIL, 0, SEEK_SET);
335
        }
336
        fd = getfdFromVSILFILE(fpVSIL);
337
    }
338
    else
339
        fd = -1;
340
    return fd;
341
}
342

    
343
/************************************************************************/
344
/*                    GET_DEBUG_VSIPRELOAD_COND()                             */
345
/************************************************************************/
346

    
347
static int GET_DEBUG_VSIPRELOAD_COND(const char* path)
348
{
349
    return (DEBUG_VSIPRELOAD && (!DEBUG_VSIPRELOAD_ONLY_VSIL || strncmp(path, "/vsi", 4) == 0) );
350
}
351

    
352
static int GET_DEBUG_VSIPRELOAD_COND(VSILFILE* fpVSIL)
353
{
354
    return (DEBUG_VSIPRELOAD && (!DEBUG_VSIPRELOAD_ONLY_VSIL || fpVSIL != NULL));
355
}
356

    
357
static int GET_DEBUG_VSIPRELOAD_COND(VSIDIR* dirP)
358
{
359
    return (DEBUG_VSIPRELOAD && (!DEBUG_VSIPRELOAD_ONLY_VSIL || oSetVSIDIR.find(dirP) != oSetVSIDIR.end()));
360
}
361

    
362
/************************************************************************/
363
/*                     copyVSIStatBufLToBuf()                           */
364
/************************************************************************/
365

    
366
static void copyVSIStatBufLToBuf(VSIStatBufL* bufSrc, struct stat *buf)
367
{
368
    buf->st_dev = bufSrc->st_dev;
369
    buf->st_ino = bufSrc->st_ino;
370
    buf->st_mode = bufSrc->st_mode | S_IRUSR | S_IRGRP | S_IROTH; // S_IXUSR | S_IXGRP | S_IXOTH;
371
    buf->st_nlink = 1; //bufSrc->st_nlink;
372
    buf->st_uid = bufSrc->st_uid;
373
    buf->st_gid = bufSrc->st_gid;
374
    buf->st_rdev = bufSrc->st_rdev;
375
    buf->st_size = bufSrc->st_size;
376
    buf->st_blksize = bufSrc->st_blksize;
377
    buf->st_blocks = bufSrc->st_blocks;
378
    buf->st_atime = bufSrc->st_atime;
379
    buf->st_mtime = bufSrc->st_mtime;
380
    buf->st_ctime = bufSrc->st_ctime;
381
}
382

    
383
/************************************************************************/
384
/*                     copyVSIStatBufLToBuf64()                         */
385
/************************************************************************/
386

    
387
static void copyVSIStatBufLToBuf64(VSIStatBufL *bufSrc, struct stat64 *buf)
388
{
389
    buf->st_dev = bufSrc->st_dev;
390
    buf->st_ino = bufSrc->st_ino;
391
    buf->st_mode = bufSrc->st_mode | S_IRUSR | S_IRGRP | S_IROTH; // S_IXUSR | S_IXGRP | S_IXOTH;
392
    buf->st_nlink = 1; //bufSrc->st_nlink;
393
    buf->st_uid = bufSrc->st_uid;
394
    buf->st_gid = bufSrc->st_gid;
395
    buf->st_rdev = bufSrc->st_rdev;
396
    buf->st_size = bufSrc->st_size;
397
    buf->st_blksize = bufSrc->st_blksize;
398
    buf->st_blocks = bufSrc->st_blocks;
399
    buf->st_atime = bufSrc->st_atime;
400
    buf->st_mtime = bufSrc->st_mtime;
401
    buf->st_ctime = bufSrc->st_ctime;
402
}
403

    
404
/************************************************************************/
405
/*                             fopen()                                  */
406
/************************************************************************/
407

    
408
FILE *fopen(const char *path, const char *mode)
409
{
410
    myinit();
411
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
412
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fopen(%s, %s)\n", path, mode);
413
    FILE* ret;
414
    if( strncmp(path, "/vsi", 4) == 0 )
415
        ret = (FILE*) VSIFfopenHelper(path, mode);
416
    else
417
        ret = pfnfopen(path, mode);
418
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fopen() = %p\n", ret);
419
    return ret;
420
}
421

    
422
/************************************************************************/
423
/*                            fopen64()                                 */
424
/************************************************************************/
425

    
426
FILE *fopen64(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, "fopen64(%s, %s)\n", path, mode);
431
    FILE* ret;
432
    if( strncmp(path, "/vsi", 4) == 0 )
433
        ret = (FILE*) VSIFfopenHelper(path, mode);
434
    else
435
        ret = pfnfopen64(path, mode);
436
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fopen64() = %p\n", ret);
437
    return ret;
438
}
439

    
440
/************************************************************************/
441
/*                            fread()                                   */
442
/************************************************************************/
443

    
444
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
445
{
446
    myinit();
447
    VSILFILE* fpVSIL = getVSILFILE(stream);
448
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
449
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fread(stream=%p,size=%d,nmemb=%d)\n",
450
        stream, (int)size, (int)nmemb);
451
    size_t ret;
452
    if( fpVSIL )
453
        ret = VSIFReadL(ptr, size, nmemb, fpVSIL);
454
    else
455
        ret = pfnfread(ptr, size, nmemb, stream);
456
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fread(stream=%p,size=%d,nmemb=%d) -> %d\n",
457
        stream, (int)size, (int)nmemb, (int)ret);
458
    return ret;
459
}
460

    
461
/************************************************************************/
462
/*                            fwrite()                                  */
463
/************************************************************************/
464

    
465
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
466
{
467
    myinit();
468
    VSILFILE* fpVSIL = getVSILFILE(stream);
469
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
470
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fwrite(stream=%p,size=%d,nmemb=%d)\n",
471
        stream, (int)size, (int)nmemb);
472
    size_t ret;
473
    if( fpVSIL != NULL )
474
        ret = VSIFWriteL(ptr, size, nmemb, fpVSIL);
475
    else
476
        ret = pfnfwrite(ptr, size, nmemb, stream);
477
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fwrite(stream=%p,size=%d,nmemb=%d) -> %d\n",
478
        stream, (int)size, (int)nmemb, (int)ret);
479
    return ret;
480
}
481

    
482
/************************************************************************/
483
/*                            fclose()                                  */
484
/************************************************************************/
485

    
486
int fclose(FILE *stream)
487
{
488
    myinit();
489
    VSILFILE* fpVSIL = getVSILFILE(stream);
490
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
491
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fclose(stream=%p)\n", stream);
492
    if( fpVSIL != NULL )
493
    {
494
        CPLMutexHolderD(&hMutex);
495

    
496
        int ret = VSIFCloseL(fpVSIL);
497
        oMapVSIToString.erase(fpVSIL);
498
        oSetFiles.erase(fpVSIL);
499

    
500
        std::map<VSILFILE*, int>::iterator oIter = oMapVSITofd.find(fpVSIL);
501
        if( oIter != oMapVSITofd.end() )
502
        {
503
            int fd = oIter->second;
504
            pfnclose(fd);
505
            oMapVSITofd.erase(oIter);
506
            oMapfdToVSI.erase(fd);
507
        }
508

    
509
        return ret;
510
    }
511
    else
512
        return pfnfclose(stream);
513
}
514

    
515
/************************************************************************/
516
/*                            __xstat()                                 */
517
/************************************************************************/
518

    
519
int __xstat(int ver, const char *path, struct stat *buf)
520
{
521
    myinit();
522
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
523
    if( DEBUG_VSIPRELOAD && (osCurDir.size() != 0 && path[0] != '/') )
524
        DEBUG_VSIPRELOAD_COND = 1;
525
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "__xstat(%s)\n", path);
526
    if( (osCurDir.size() != 0 && path[0] != '/') || strncmp(path, "/vsi", 4) == 0 )
527
    {
528
        VSIStatBufL sStatBufL;
529
        int ret;
530
        std::string newpath;
531
        if( (osCurDir.size() != 0 && path[0] != '/') )
532
        {
533
            newpath = CPLFormFilename(osCurDir.c_str(), path, NULL);
534
            path = newpath.c_str();
535
        }
536
        ret = VSIStatL(path, &sStatBufL);
537
        sStatBufL.st_ino = (int)CPLHashSetHashStr(path);
538
        if( ret == 0 )
539
        {
540
            copyVSIStatBufLToBuf(&sStatBufL, buf);
541
            if (DEBUG_VSIPRELOAD_COND) fprintf(stderr,
542
                "__xstat(%s) ret = 0, mode = %d, size=%d\n",
543
                path, sStatBufL.st_mode, (int)sStatBufL.st_size);
544
        }
545
        return ret;
546
    }
547
    else
548
    {
549
        int ret = pfn__xstat(ver, path, buf);
550
        if( ret == 0 )
551
        {
552
            if (DEBUG_VSIPRELOAD_COND) fprintf(stderr,
553
                "__xstat ret = 0, mode = %d\n", buf->st_mode);
554
        }
555
        return ret;
556
    }
557
}
558

    
559
/************************************************************************/
560
/*                           __lxstat()                                 */
561
/************************************************************************/
562

    
563
int __lxstat(int ver, const char *path, struct stat *buf)
564
{
565
    myinit();
566
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
567
    if( DEBUG_VSIPRELOAD && (osCurDir.size() != 0 && path[0] != '/') )
568
        DEBUG_VSIPRELOAD_COND = 1;
569
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "__lxstat(%s)\n", path);
570
    if( (osCurDir.size() != 0 && path[0] != '/') || strncmp(path, "/vsi", 4) == 0 )
571
    {
572
        VSIStatBufL sStatBufL;
573
        int ret;
574
        std::string newpath;
575
        if( (osCurDir.size() != 0 && path[0] != '/') )
576
        {
577
            newpath = CPLFormFilename(osCurDir.c_str(), path, NULL);
578
            path = newpath.c_str();
579
        }
580
        ret = VSIStatL(path, &sStatBufL);
581
        sStatBufL.st_ino = (int)CPLHashSetHashStr(path);
582
        if( ret == 0 )
583
        {
584
            copyVSIStatBufLToBuf(&sStatBufL, buf);
585
            if (DEBUG_VSIPRELOAD_COND) fprintf(stderr,
586
                "__lxstat(%s) ret = 0, mode = %d, size=%d\n",
587
                path, sStatBufL.st_mode, (int)sStatBufL.st_size);
588
        }
589
        return ret;
590
    }
591
    else
592
    {
593
        int ret = pfn__lxstat(ver, path, buf);
594
        if( ret == 0 )
595
        {
596
            if (DEBUG_VSIPRELOAD_COND) fprintf(stderr,
597
                "__lxstat ret = 0, mode = %d\n", buf->st_mode);
598
        }
599
        return ret;
600
    }
601
}
602

    
603
/************************************************************************/
604
/*                           __xstat64()                                */
605
/************************************************************************/
606

    
607
int __xstat64(int ver, const char *path, struct stat64 *buf)
608
{
609
    myinit();
610
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
611
    if( DEBUG_VSIPRELOAD && (osCurDir.size() != 0 && path[0] != '/') )
612
        DEBUG_VSIPRELOAD_COND = 1;
613
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "__xstat64(%s)\n", path);
614
    if( (osCurDir.size() != 0 && path[0] != '/') || strncmp(path, "/vsi", 4) == 0 )
615
    {
616
        VSIStatBufL sStatBufL;
617
        int ret;
618
        std::string newpath;
619
        if( (osCurDir.size() != 0 && path[0] != '/') )
620
        {
621
            newpath = CPLFormFilename(osCurDir.c_str(), path, NULL);
622
            path = newpath.c_str();
623
        }
624
        ret = VSIStatL(path, &sStatBufL);
625
        sStatBufL.st_ino = (int)CPLHashSetHashStr(path);
626
        if( ret == 0 )
627
        {
628
            copyVSIStatBufLToBuf64(&sStatBufL, buf);
629
            if (DEBUG_VSIPRELOAD_COND) fprintf(stderr,
630
                "__xstat64(%s) ret = 0, mode = %d, size = %d\n",
631
                path, buf->st_mode, (int)buf->st_size);
632
        }
633
        return ret;
634
    }
635
    else
636
        return pfn__xstat64(ver, path, buf);
637
}
638

    
639
/************************************************************************/
640
/*                           fseeko64()                                 */
641
/************************************************************************/
642

    
643
int fseeko64 (FILE *stream, off64_t off, int whence)
644
{
645
    myinit();
646
    VSILFILE* fpVSIL = getVSILFILE(stream);
647
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
648
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fseeko64(stream=%p, off=%d, whence=%d)\n",
649
        stream, (int)off, whence);
650
    if( fpVSIL != NULL )
651
        return VSIFSeekLHelper(fpVSIL, off, whence);
652
    else
653
        return pfnfseeko64(stream, off, whence);
654
}
655

    
656
/************************************************************************/
657
/*                           fseeko()                                 */
658
/************************************************************************/
659

    
660
int fseeko (FILE *stream, off_t off, int whence)
661
{
662
    myinit();
663
    VSILFILE* fpVSIL = getVSILFILE(stream);
664
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
665
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fseeko(stream=%p, off=%d, whence=%d)\n",
666
        stream, (int)off, whence);
667
    if( fpVSIL != NULL )
668
        return VSIFSeekLHelper(fpVSIL, off, whence);
669
    else
670
        return pfnfseeko64(stream, off, whence);
671
}
672

    
673
/************************************************************************/
674
/*                            fseek()                                   */
675
/************************************************************************/
676

    
677
int fseek (FILE *stream, off_t off, int whence)
678
{
679
    myinit();
680
    VSILFILE* fpVSIL = getVSILFILE(stream);
681
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
682
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fseek(stream=%p, off=%d, whence=%d)\n",
683
        stream, (int)off, whence);
684
    if( fpVSIL != NULL )
685
        return VSIFSeekLHelper(fpVSIL, off, whence);
686
    else
687
        return pfnfseek(stream, off, whence);
688
}
689

    
690
/************************************************************************/
691
/*                           ftello64()                                 */
692
/************************************************************************/
693

    
694
off64_t ftello64(FILE *stream)
695
{
696
    myinit();
697
    VSILFILE* fpVSIL = getVSILFILE(stream);
698
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
699
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "ftello64(stream=%p)\n", stream);
700
    if( fpVSIL != NULL )
701
        return VSIFTellL(fpVSIL);
702
    else
703
        return pfnftello64(stream);
704
}
705

    
706
/************************************************************************/
707
/*                            ftello()                                  */
708
/************************************************************************/
709

    
710
off_t ftello(FILE *stream)
711
{
712
    myinit();
713
    VSILFILE* fpVSIL = getVSILFILE(stream);
714
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
715
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "ftello(stream=%p)\n", stream);
716
    if( fpVSIL != NULL )
717
        return VSIFTellL(fpVSIL);
718
    else
719
        return pfnftello64(stream);
720
}
721

    
722
/************************************************************************/
723
/*                            ftell()                                   */
724
/************************************************************************/
725

    
726
off_t ftell(FILE *stream)
727
{
728
    myinit();
729
    VSILFILE* fpVSIL = getVSILFILE(stream);
730
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
731
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "ftell(stream=%p)\n", stream);
732
    if( fpVSIL != NULL )
733
        return VSIFTellL(fpVSIL);
734
    else
735
        return pfnftell(stream);
736
}
737

    
738
/************************************************************************/
739
/*                             feof()                                   */
740
/************************************************************************/
741

    
742
int feof(FILE *stream)
743
{
744
    myinit();
745
    VSILFILE* fpVSIL = getVSILFILE(stream);
746
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
747
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "feof(stream=%p)\n", stream);
748
    if( fpVSIL != NULL )
749
        return VSIFEofL(fpVSIL);
750
    else
751
        return pfnfeof(stream);
752
}
753

    
754
/************************************************************************/
755
/*                            rewind()                                  */
756
/************************************************************************/
757

    
758
void rewind(FILE *stream)
759
{
760
    fseek(stream, 0, SEEK_SET);
761
}
762

    
763
/************************************************************************/
764
/*                            fflush()                                  */
765
/************************************************************************/
766

    
767
int fflush(FILE *stream)
768
{
769
    myinit();
770
    VSILFILE* fpVSIL = getVSILFILE(stream);
771
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
772
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fflush(stream=%p)\n", stream);
773
    if( fpVSIL != NULL )
774
        return 0;
775
    else
776
        return pfnfflush(stream);
777
}
778

    
779
/************************************************************************/
780
/*                            fgetpos()                                 */
781
/************************************************************************/
782

    
783
int fgetpos(FILE *stream, fpos_t *pos)
784
{
785
    myinit();
786
    VSILFILE* fpVSIL = getVSILFILE(stream);
787
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
788
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fgetpos(stream=%p)\n", stream);
789
    if( fpVSIL != NULL )
790
    {
791
        fprintf(stderr, "fgetpos() unimplemented for VSILFILE\n");
792
        return -1; // FIXME
793
    }
794
    else
795
        return pfnfgetpos(stream, pos);
796
}
797

    
798
/************************************************************************/
799
/*                            fsetpos()                                 */
800
/************************************************************************/
801

    
802
int fsetpos(FILE *stream, fpos_t *pos)
803
{
804
    myinit();
805
    VSILFILE* fpVSIL = getVSILFILE(stream);
806
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
807
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fsetpos(stream=%p)\n", stream);
808
    if( fpVSIL != NULL )
809
    {
810
        fprintf(stderr, "fsetpos() unimplemented for VSILFILE\n");
811
        return -1; // FIXME
812
    }
813
    else
814
        return pfnfsetpos(stream, pos);
815
}
816

    
817
/************************************************************************/
818
/*                             fileno()                                 */
819
/************************************************************************/
820

    
821
int fileno(FILE *stream)
822
{
823
    myinit();
824
    VSILFILE* fpVSIL = getVSILFILE(stream);
825
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
826
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fileno(stream=%p)\n", stream);
827
    int fd;
828
    if( fpVSIL != NULL )
829
        fd = getfdFromVSILFILE(fpVSIL);
830
    else
831
        fd = pfnfileno(stream);
832
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fileno(stream=%p) = %d\n", stream, fd);
833
    return fd;
834
}
835

    
836
/************************************************************************/
837
/*                             ferror()                                 */
838
/************************************************************************/
839

    
840
int ferror(FILE *stream)
841
{
842
    myinit();
843
    VSILFILE* fpVSIL = getVSILFILE(stream);
844
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
845
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "ferror(stream=%p)\n", stream);
846
    if( fpVSIL != NULL )
847
    {
848
        fprintf(stderr, "ferror() unimplemented for VSILFILE\n");
849
        return 0; // FIXME ?
850
    }
851
    else
852
        return pfnferror(stream);
853
}
854

    
855
/************************************************************************/
856
/*                             fdopen()                                 */
857
/************************************************************************/
858

    
859
FILE * fdopen(int fd, const char *mode)
860
{
861
    myinit();
862
    VSILFILE* fpVSIL = getVSILFILE(fd);
863
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
864
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fdopen(fd=%d)\n", fd);
865
    if( fpVSIL != NULL )
866
    {
867
        fprintf(stderr, "fdopen() unimplemented for VSILFILE\n");
868
        return NULL; // FIXME ?
869
    }
870
    else
871
        return pfnfdopen(fd, mode);
872
}
873

    
874
/************************************************************************/
875
/*                             freopen()                                */
876
/************************************************************************/
877

    
878
FILE *freopen(const char *path, const char *mode, FILE *stream)
879
{
880
    myinit();
881
    VSILFILE* fpVSIL = getVSILFILE(stream);
882
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
883
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "freopen(path=%s,mode=%s,stream=%p)\n", path, mode, stream);
884
    if( fpVSIL != NULL )
885
    {
886
        fprintf(stderr, "freopen() unimplemented for VSILFILE\n");
887
        return NULL; // FIXME ?
888
    }
889
    else
890
        return pfnfreopen(path, mode, stream);
891
}
892

    
893
/************************************************************************/
894
/*                              open()                                  */
895
/************************************************************************/
896

    
897
int open(const char *path, int flags, ...)
898
{
899
    myinit();
900
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
901
    if( DEBUG_VSIPRELOAD && osCurDir.size() != 0 && path[0] != '/' )
902
        DEBUG_VSIPRELOAD_COND = 1;
903
    if (DEBUG_VSIPRELOAD_COND)
904
    {
905
        if( osCurDir.size() != 0 && path[0] != '/' )
906
            fprintf(stderr, "open(%s)\n", CPLFormFilename(osCurDir.c_str(), path, NULL));
907
        else
908
            fprintf(stderr, "open(%s)\n", path);
909
    }
910

    
911
    va_list args;
912
    va_start(args, flags);
913
    mode_t mode = va_arg(args, mode_t);
914
    int fd;
915
    if( osCurDir.size() != 0 && path[0] != '/' && (flags & 3) == O_RDONLY && (flags & O_DIRECTORY) != 0 )
916
    {
917
        VSIStatBufL sStatBufL;
918
        char* newname = (char*)CPLFormFilename(osCurDir.c_str(), path, NULL);
919
        if( strchr(osCurDir.c_str(), '/') != NULL && strcmp(path, "..") == 0 )
920
        {
921
            char* lastslash = strrchr(newname, '/');
922
            if( lastslash != NULL )
923
            {
924
                *lastslash = 0;
925
                lastslash = strrchr(newname, '/');
926
                if( lastslash != NULL )
927
                    *lastslash = 0;
928
            }
929
        }
930
        if( VSIStatL(newname, &sStatBufL) == 0 &&
931
            S_ISDIR(sStatBufL.st_mode) )
932
        {
933
            fd = open("/dev/zero", O_RDONLY);
934
            CPLMutexHolderD(&hMutex)
935
            oMapDirFdToName[fd] = newname;
936
        }
937
        else
938
            fd = -1;
939
    }
940
    else if( strncmp(path, "/vsi", 4) == 0 )
941
        fd = VSIFopenHelper(path, flags);
942
    else
943
        fd = pfnopen(path, flags, mode);
944
    va_end(args);
945
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "open(%s) = %d\n", path, fd);
946
    return fd;
947
}
948

    
949
/************************************************************************/
950
/*                             open64()                                 */
951
/************************************************************************/
952

    
953
int open64(const char *path, int flags, ...)
954
{
955
    myinit();
956
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
957
    if( DEBUG_VSIPRELOAD && osCurDir.size() != 0 && path[0] != '/' )
958
        DEBUG_VSIPRELOAD_COND = 1;
959
    if (DEBUG_VSIPRELOAD_COND)
960
    {
961
        if( osCurDir.size() != 0 && path[0] != '/' )
962
            fprintf(stderr, "open64(%s)\n", CPLFormFilename(osCurDir.c_str(), path, NULL));
963
        else
964
            fprintf(stderr, "open64(%s)\n", path);
965
    }
966

    
967
    va_list args;
968
    va_start(args, flags);
969
    mode_t mode = va_arg(args, mode_t);
970
    int fd;
971
    if( osCurDir.size() != 0 && path[0] != '/' && (flags & 3) == O_RDONLY && (flags & O_DIRECTORY) != 0 )
972
    {
973
        VSIStatBufL sStatBufL;
974
        char* newname = (char*)CPLFormFilename(osCurDir.c_str(), path, NULL);
975
        if( strchr(osCurDir.c_str(), '/') != NULL && strcmp(path, "..") == 0 )
976
        {
977
            char* lastslash = strrchr(newname, '/');
978
            if( lastslash != NULL )
979
            {
980
                *lastslash = 0;
981
                lastslash = strrchr(newname, '/');
982
                if( lastslash != NULL )
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
            CPLMutexHolderD(&hMutex)
991
            oMapDirFdToName[fd] = newname;
992
        }
993
        else
994
            fd = -1;
995
    }
996
    else if( strncmp(path, "/vsi", 4) == 0 )
997
        fd = VSIFopenHelper(path, flags);
998
    else
999
        fd = pfnopen64(path, flags, mode);
1000
    va_end(args);
1001
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "open64(%s) = %d\n", path, fd);
1002
    return fd;
1003
}
1004

    
1005
/************************************************************************/
1006
/*                             creat()                                  */
1007
/************************************************************************/
1008

    
1009
int creat(const char *path, mode_t mode)
1010
{
1011
    return open64(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
1012
}
1013

    
1014
/************************************************************************/
1015
/*                             close()                                  */
1016
/************************************************************************/
1017

    
1018
int close(int fd)
1019
{
1020
    myinit();
1021
    VSILFILE* fpVSIL = getVSILFILE(fd);
1022
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1023
    {
1024
        CPLMutexHolderD(&hMutex);
1025
        assert( oMapfdToVSIDIR.find(fd) == oMapfdToVSIDIR.end() );
1026

    
1027
        if( oMapDirFdToName.find(fd) != oMapDirFdToName.end())
1028
        {
1029
            oMapDirFdToName.erase(fd);
1030
            if( DEBUG_VSIPRELOAD )
1031
                DEBUG_VSIPRELOAD_COND = 1;
1032
        }
1033
    }
1034
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "close(fd=%d)\n", fd);
1035
    if( fpVSIL != NULL )
1036
    {
1037
        VSIFCloseL(fpVSIL);
1038
        CPLMutexHolderD(&hMutex);
1039
        oSetFiles.erase(fpVSIL);
1040
        pfnclose(oMapVSITofd[fpVSIL]);
1041
        oMapVSITofd.erase(fpVSIL);
1042
        oMapfdToVSI.erase(fd);
1043
        oMapVSIToString.erase(fpVSIL);
1044
        return 0;
1045
    }
1046
    else
1047
        return pfnclose(fd);
1048
}
1049

    
1050
/************************************************************************/
1051
/*                              read()                                  */
1052
/************************************************************************/
1053

    
1054
ssize_t read(int fd, void *buf, size_t count)
1055
{
1056
    myinit();
1057
    VSILFILE* fpVSIL = getVSILFILE(fd);
1058
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1059
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "read(fd=%d, count=%d)\n", fd, (int)count);
1060
    ssize_t ret;
1061
    if( fpVSIL != NULL )
1062
        ret = VSIFReadL(buf, 1, count, fpVSIL);
1063
    else
1064
        ret = pfnread(fd, buf, count);
1065
    if (DEBUG_VSIPRELOAD_COND && DEBUG_OUTPUT_READ && ret < 40)
1066
    {
1067
        fprintf(stderr, "read() : ");
1068
        for(int i=0;i<ret;i++)
1069
        {
1070
            if( ((unsigned char*)buf)[i] >= 'A' && ((unsigned char*)buf)[i] <= 'Z' )
1071
                fprintf(stderr, "%c ", ((unsigned char*)buf)[i]);
1072
            else
1073
                fprintf(stderr, "\\%02X ", ((unsigned char*)buf)[i]);
1074
        }
1075
        fprintf(stderr, "\n");
1076
    }
1077
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "read() -> %d\n", (int)ret);
1078
    return ret;
1079
}
1080

    
1081
/************************************************************************/
1082
/*                              write()                                 */
1083
/************************************************************************/
1084

    
1085
ssize_t write(int fd, const void *buf, size_t count)
1086
{
1087
    myinit();
1088
    VSILFILE* fpVSIL = getVSILFILE(fd);
1089
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1090
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "write(fd=%d, count=%d)\n", fd, (int)count);
1091
    if( fpVSIL != NULL )
1092
        return VSIFWriteL(buf, 1, count, fpVSIL);
1093
    else
1094
        return pfnwrite(fd, buf, count);
1095
}
1096

    
1097
/************************************************************************/
1098
/*                              fsync()                                 */
1099
/************************************************************************/
1100

    
1101
int fsync(int fd)
1102
{
1103
    myinit();
1104
    VSILFILE* fpVSIL = getVSILFILE(fd);
1105
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1106
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fsync(fd=%d)\n", fd);
1107
    if( fpVSIL != NULL )
1108
        return 0;
1109
    else
1110
        return pfnfsync(fd);
1111
}
1112

    
1113
/************************************************************************/
1114
/*                           fdatasync()                                */
1115
/************************************************************************/
1116

    
1117
int fdatasync(int fd)
1118
{
1119
    myinit();
1120
    VSILFILE* fpVSIL = getVSILFILE(fd);
1121
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1122
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fdatasync(fd=%d)\n", fd);
1123
    if( fpVSIL != NULL )
1124
        return 0;
1125
    else
1126
        return pfnfdatasync(fd);
1127
}
1128

    
1129
/************************************************************************/
1130
/*                            __fxstat()                                */
1131
/************************************************************************/
1132

    
1133
int __fxstat (int ver, int fd, struct stat *buf)
1134
{
1135
    myinit();
1136
    VSILFILE* fpVSIL = getVSILFILE(fd);
1137
    std::string name;
1138
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1139
    {
1140
        CPLMutexHolderD(&hMutex)
1141
        if( oMapDirFdToName.find(fd) != oMapDirFdToName.end())
1142
        {
1143
            name = oMapDirFdToName[fd];
1144
            if( DEBUG_VSIPRELOAD )
1145
                DEBUG_VSIPRELOAD_COND = 1;
1146
        }
1147
    }
1148
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "__fxstat(fd=%d)\n", fd);
1149
    if( name.size() )
1150
    {
1151
        VSIStatBufL sStatBufL;
1152
        if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "__fxstat(%s)\n", name.c_str());
1153
        int ret = VSIStatL(name.c_str(), &sStatBufL);
1154
        sStatBufL.st_ino = (int)CPLHashSetHashStr(name.c_str());
1155
        if( ret == 0 )
1156
        {
1157
            copyVSIStatBufLToBuf(&sStatBufL, buf);
1158
            if (DEBUG_VSIPRELOAD_COND) fprintf(stderr,
1159
                "__fxstat ret = 0, mode = %d, size = %d\n",
1160
                sStatBufL.st_mode, (int)sStatBufL.st_size);
1161
        }
1162
        return ret;
1163
    }
1164
    else if( fpVSIL != NULL )
1165
    {
1166
        VSIStatBufL sStatBufL;
1167
        {
1168
            CPLMutexHolderD(&hMutex);
1169
            name = oMapVSIToString[fpVSIL];
1170
        }
1171
        int ret = VSIStatL(name.c_str(), &sStatBufL);
1172
        sStatBufL.st_ino = (int)CPLHashSetHashStr(name.c_str());
1173
        if( ret == 0 )
1174
        {
1175
            copyVSIStatBufLToBuf(&sStatBufL, buf);
1176
            if (DEBUG_VSIPRELOAD_COND) fprintf(stderr,
1177
                "__fxstat ret = 0, mode = %d, size = %d\n",
1178
                sStatBufL.st_mode, (int)sStatBufL.st_size);
1179
        }
1180
        return ret;
1181
    }
1182
    else
1183
        return pfn__fxstat(ver, fd, buf);
1184
}
1185

    
1186
/************************************************************************/
1187
/*                           __fxstat64()                               */
1188
/************************************************************************/
1189

    
1190
int __fxstat64 (int ver, int fd, struct stat64 *buf)
1191
{
1192
    myinit();
1193
    VSILFILE* fpVSIL = getVSILFILE(fd);
1194
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1195
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "__fxstat64(fd=%d)\n", fd);
1196
    if( fpVSIL != NULL )
1197
    {
1198
        VSIStatBufL sStatBufL;
1199
        std::string name;
1200
        {
1201
            CPLMutexHolderD(&hMutex);
1202
            name = oMapVSIToString[fpVSIL];
1203
        }
1204
        int ret = VSIStatL(name.c_str(), &sStatBufL);
1205
        sStatBufL.st_ino = (int)CPLHashSetHashStr(name.c_str());
1206
        if( ret == 0 )
1207
        {
1208
            copyVSIStatBufLToBuf64(&sStatBufL, buf);
1209
            if (DEBUG_VSIPRELOAD_COND) fprintf(stderr,
1210
                "__fxstat64 ret = 0, mode = %d, size = %d\n",
1211
                buf->st_mode, (int)buf->st_size);
1212
        }
1213
        return ret;
1214
    }
1215
    else
1216
        return pfn__fxstat64(ver, fd, buf);
1217
}
1218

    
1219
/************************************************************************/
1220
/*                           __fxstatat()                               */
1221
/************************************************************************/
1222

    
1223
#ifdef HAVE_FSTATAT
1224
int __fxstatat (int ver, int dirfd, const char *pathname, struct stat *buf,
1225
                int flags)
1226
{
1227
    myinit();
1228
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(pathname);
1229
    if( DEBUG_VSIPRELOAD && osCurDir.size() != 0 )
1230
        DEBUG_VSIPRELOAD_COND = 1;
1231
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "__fxstatat(dirfd=%d,pathname=%s,flags=%d)\n", dirfd, pathname, flags);
1232

    
1233
    if( osCurDir.size() != 0 || strncmp(pathname, "/vsi", 4) == 0 )
1234
    {
1235
        VSIStatBufL sStatBufL;
1236
        int ret;
1237
        if( osCurDir.size() && dirfd == AT_FDCWD && pathname[0] != '/' )
1238
            pathname = CPLFormFilename(osCurDir.c_str(), pathname, NULL);
1239
        ret = VSIStatL(pathname, &sStatBufL);
1240
        sStatBufL.st_ino = (int)CPLHashSetHashStr(pathname);
1241
        if( ret == 0 )
1242
        {
1243
            copyVSIStatBufLToBuf(&sStatBufL, buf);
1244
            if (DEBUG_VSIPRELOAD_COND) fprintf(stderr,
1245
                "__fxstatat(%s) ret = 0, mode = %d, size = %d\n",
1246
                pathname, buf->st_mode, (int)buf->st_size);
1247
        }
1248
        return ret;
1249
    }
1250
    else
1251
        return pfn__fxstatat(ver, dirfd, pathname, buf, flags);
1252
}
1253
#endif
1254

    
1255
/************************************************************************/
1256
/*                              lseek()                                 */
1257
/************************************************************************/
1258

    
1259
off_t lseek(int fd, off_t off, int whence)
1260
{
1261
    myinit();
1262
    off_t ret;
1263
    VSILFILE* fpVSIL = getVSILFILE(fd);
1264
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1265
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr,
1266
        "lseek(fd=%d, off=%d, whence=%d)\n", fd, (int)off, whence);
1267
    if( fpVSIL != NULL )
1268
    {
1269
        VSIFSeekLHelper(fpVSIL, off, whence);
1270
        ret = VSIFTellL(fpVSIL);
1271
    }
1272
    else
1273
        ret = pfnlseek(fd, off, whence);
1274
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "lseek() -> ret = %d\n", (int)ret);
1275
    return ret;
1276
}
1277

    
1278
/************************************************************************/
1279
/*                             lseek64()                                */
1280
/************************************************************************/
1281

    
1282
off64_t lseek64(int fd, off64_t off, int whence)
1283
{
1284
    myinit();
1285
    off_t ret;
1286
    VSILFILE* fpVSIL = getVSILFILE(fd);
1287
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1288
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr,
1289
        "lseek64(fd=%d, off=%d, whence=%d)\n", fd, (int)off, whence);
1290
    if( fpVSIL != NULL )
1291
    {
1292
        VSIFSeekLHelper(fpVSIL, off, whence);
1293
        ret = VSIFTellL(fpVSIL);
1294
    }
1295
    else
1296
        ret = pfnlseek64(fd, off, whence);
1297
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr,
1298
        "lseek64() -> ret = %d\n", (int)ret);
1299
    return ret;
1300
}
1301

    
1302
/************************************************************************/
1303
/*                            truncate()                                */
1304
/************************************************************************/
1305

    
1306
int truncate(const char *path, off_t length)
1307
{
1308
    myinit();
1309
    int ret;
1310
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
1311
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "truncate(%s)\n", path);
1312

    
1313
    if( strncmp(path, "/vsi", 4) == 0 )
1314
    {
1315
        VSILFILE* fpVSIL = VSIFOpenL(path, "wb+");
1316
        if( fpVSIL )
1317
        {
1318
            ret = VSIFTruncateL(fpVSIL, length);
1319
            VSIFCloseL(fpVSIL);
1320
        }
1321
        else
1322
            ret = -1;
1323
    }
1324
    else
1325
        ret = pfntruncate(path, length);
1326
    return ret;
1327
}
1328

    
1329
/************************************************************************/
1330
/*                           ftruncate()                                */
1331
/************************************************************************/
1332

    
1333
int ftruncate(int fd, off_t length)
1334
{
1335
    myinit();
1336
    int ret;
1337
    VSILFILE* fpVSIL = getVSILFILE(fd);
1338
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
1339
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "ftruncate(fd=%d)\n", fd);
1340
    if( fpVSIL != NULL )
1341
    {
1342
        ret = VSIFTruncateL(fpVSIL, length);
1343
    }
1344
    else
1345
        ret = pfnftruncate(fd, length);
1346
    return ret;
1347
}
1348

    
1349
/************************************************************************/
1350
/*                             opendir()                                */
1351
/************************************************************************/
1352

    
1353
DIR *opendir(const char *name)
1354
{
1355
    myinit();
1356
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(name);
1357
    if( DEBUG_VSIPRELOAD && osCurDir.size() != 0 )
1358
        DEBUG_VSIPRELOAD_COND = 1;
1359
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "opendir(%s)\n", name);
1360

    
1361
    DIR * ret;
1362
    if( osCurDir.size() != 0 || strncmp(name, "/vsi", 4) == 0 )
1363
    {
1364
        char** papszDir;
1365
        if( osCurDir.size() != 0 && name[0] != '/' )
1366
            name = CPLFormFilename(osCurDir.c_str(), name, NULL);
1367
        papszDir = VSIReadDir(name);
1368
        if( papszDir == NULL )
1369
        {
1370
            VSIStatBufL sStatBufL;
1371
            if( VSIStatL(name, &sStatBufL) == 0 && S_ISDIR(sStatBufL.st_mode) )
1372
            {
1373
                papszDir = (char**) CPLMalloc(sizeof(char*));
1374
                papszDir[0] = NULL;
1375
            }
1376
        }
1377
        if( papszDir == NULL )
1378
            ret = NULL;
1379
        else
1380
        {
1381
            VSIDIR* mydir = (VSIDIR*)malloc(sizeof(VSIDIR));
1382
            mydir->pszDirname = CPLStrdup(name);
1383
            mydir->papszDir = papszDir;
1384
            mydir->nIter = 0;
1385
            mydir->fd = -1;
1386
            ret = (DIR*)mydir;
1387
            CPLMutexHolderD(&hMutex);
1388
            oSetVSIDIR.insert(mydir);
1389
        }
1390
    }
1391
    else
1392
        ret = pfnopendir(name);
1393
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "opendir(%s) -> %p\n", name, ret);
1394
    return ret;
1395
}
1396

    
1397
/************************************************************************/
1398
/*                             readdir()                                */
1399
/************************************************************************/
1400

    
1401
struct dirent *readdir(DIR *dirp)
1402
{
1403
    myinit();
1404
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND((VSIDIR*)dirp);
1405
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "readdir(%p)\n", dirp);
1406
    if( oSetVSIDIR.find((VSIDIR*)dirp) != oSetVSIDIR.end() )
1407
    {
1408
        VSIDIR* mydir = (VSIDIR*)dirp;
1409
        char* pszName = mydir->papszDir[mydir->nIter++];
1410
        if( pszName == NULL )
1411
            return NULL;
1412
        mydir->ent.d_ino = 0;
1413
        mydir->ent.d_off = 0;
1414
        mydir->ent.d_reclen = sizeof(mydir->ent);
1415
        VSIStatBufL sStatBufL;
1416
        VSIStatL(CPLFormFilename(mydir->pszDirname, pszName, NULL), &sStatBufL);
1417
        if( DEBUG_VSIPRELOAD_COND && S_ISDIR(sStatBufL.st_mode) )
1418
            fprintf(stderr, "%s is dir\n", pszName);
1419
        mydir->ent.d_type = S_ISDIR(sStatBufL.st_mode) ? DT_DIR :
1420
                            S_ISREG(sStatBufL.st_mode) ? DT_REG :
1421
                            S_ISLNK(sStatBufL.st_mode) ? DT_LNK :
1422
                            DT_UNKNOWN;
1423
        strncpy(mydir->ent.d_name, pszName, 256);
1424
        mydir->ent.d_name[255] = '\0';
1425
        return &(mydir->ent);
1426
    }
1427
    else
1428
        return pfnreaddir(dirp);
1429
}
1430

    
1431
/************************************************************************/
1432
/*                             closedir()                               */
1433
/************************************************************************/
1434

    
1435
int closedir(DIR *dirp)
1436
{
1437
    myinit();
1438
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND((VSIDIR*)dirp);
1439
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "closedir(%p)\n", dirp);
1440
    if( oSetVSIDIR.find((VSIDIR*)dirp) != oSetVSIDIR.end() )
1441
    {
1442
        VSIDIR* mydir = (VSIDIR*)dirp;
1443
        CPLFree(mydir->pszDirname);
1444
        CSLDestroy(mydir->papszDir);
1445
        CPLMutexHolderD(&hMutex);
1446
        if( mydir->fd >= 0 )
1447
        {
1448
            oMapfdToVSIDIR.erase(mydir->fd);
1449
            close(mydir->fd);
1450
        }
1451
        oSetVSIDIR.erase(mydir);
1452
        free(mydir);
1453
        return 0;
1454
    }
1455
    else
1456
        return pfnclosedir(dirp);
1457
}
1458

    
1459
/************************************************************************/
1460
/*                               dirfd()                                */
1461
/************************************************************************/
1462

    
1463
int dirfd(DIR *dirp)
1464
{
1465
    myinit();
1466
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND((VSIDIR*)dirp);
1467
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "dirfd(%p)\n", dirp);
1468
    int ret;
1469
    if( oSetVSIDIR.find((VSIDIR*)dirp) != oSetVSIDIR.end() )
1470
    {
1471
        VSIDIR* mydir = (VSIDIR*)dirp;
1472
        if( mydir->fd < 0 )
1473
        {
1474
            mydir->fd = open("/dev/zero", O_RDONLY);
1475
            CPLMutexHolderD(&hMutex);
1476
            oMapfdToVSIDIR[mydir->fd] = mydir;
1477
        }
1478
        ret = mydir->fd;
1479
    }
1480
    else
1481
        ret = pfndirfd(dirp);
1482
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "dirfd(%p) -> %d\n", dirp, ret);
1483
    return ret;
1484
}
1485

    
1486
/************************************************************************/
1487
/*                              fchdir()                                */
1488
/************************************************************************/
1489

    
1490
int fchdir(int fd)
1491
{
1492
    VSIDIR* mydir = NULL;
1493
    {
1494
        CPLMutexHolderD(&hMutex);
1495
        if( oMapfdToVSIDIR.find(fd) != oMapfdToVSIDIR.end() )
1496
            mydir = oMapfdToVSIDIR[fd];
1497
    }
1498
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(mydir);
1499
    std::string name;
1500
    {
1501
        CPLMutexHolderD(&hMutex)
1502
        if( oMapDirFdToName.find(fd) != oMapDirFdToName.end())
1503
        {
1504
            name = oMapDirFdToName[fd];
1505
            if( DEBUG_VSIPRELOAD )
1506
                DEBUG_VSIPRELOAD_COND = 1;
1507
        }
1508
    }
1509
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fchdir(%d)\n", fd);
1510
    if( name.size() )
1511
    {
1512
        osCurDir = name;
1513
        if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fchdir(%d) -> %s\n", fd, osCurDir.c_str());
1514
        return 0;
1515
    }
1516
    else if( mydir != NULL )
1517
    {
1518
        osCurDir = mydir->pszDirname;
1519
        if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fchdir(%d) -> %s\n", fd, osCurDir.c_str());
1520
        return 0;
1521
    }
1522
    else
1523
    {
1524
        osCurDir = "";
1525
        if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fchdir(%d) -> %s\n", fd, osCurDir.c_str());
1526
        return pfnfchdir(fd);
1527
    }
1528
}
1529

    
1530
/************************************************************************/
1531
/*                        acl_extended_file()                           */
1532
/************************************************************************/
1533

    
1534
// #include <acl/acl.h>
1535
extern "C" int acl_extended_file(const char *name);
1536
DECLARE_SYMBOL(acl_extended_file, int, (const char *name));
1537

    
1538
int acl_extended_file(const char *path)
1539
{
1540
    myinit();
1541
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
1542
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "acl_extended_file(%s)\n", path);
1543
    int ret;
1544
    if( strncmp(path, "/vsi", 4) == 0 )
1545
        ret = -1;
1546
    else
1547
    {
1548
        if( pfnacl_extended_file == NULL )
1549
            pfnacl_extended_file = (fnacl_extended_fileType) dlsym(RTLD_NEXT, "acl_extended_file");
1550
        if( pfnacl_extended_file == NULL )
1551
            ret = -1;
1552
        else
1553
            ret = pfnacl_extended_file(path);
1554
    }
1555
    return ret;
1556
}
1557

    
1558
/************************************************************************/
1559
/*                          getfilecon()                                */
1560
/************************************************************************/
1561

    
1562
// #include <selinux/selinux.h>
1563
extern "C" int getfilecon(const char *name, void* con);
1564
DECLARE_SYMBOL(getfilecon, int, (const char *name, void* con));
1565

    
1566
int getfilecon(const char *path, /*security_context_t **/ void* con)
1567
{
1568
    myinit();
1569
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
1570
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "getfilecon(%s)\n", path);
1571
    int ret;
1572
    if( strncmp(path, "/vsi", 4) == 0 )
1573
    {
1574
        errno = ENOTSUP;
1575
        ret = -1;
1576
    }
1577
    else
1578
    {
1579
        if( pfngetfilecon == NULL )
1580
            pfngetfilecon = (fngetfileconType) dlsym(RTLD_NEXT, "getfilecon");
1581
        if( pfngetfilecon == NULL )
1582
            ret = -1;
1583
        else
1584
            ret = pfngetfilecon(path, con);
1585
    }
1586
    return ret;
1587
}
1588

    
1589
/************************************************************************/
1590
/*                          lgetfilecon()                                */
1591
/************************************************************************/
1592

    
1593
// #include <selinux/selinux.h>
1594
extern "C" int lgetfilecon(const char *name, void* con);
1595
DECLARE_SYMBOL(lgetfilecon, int, (const char *name, void* con));
1596

    
1597
int lgetfilecon(const char *path, /*security_context_t **/ void* con)
1598
{
1599
    myinit();
1600
    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(path);
1601
    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "lgetfilecon(%s)\n", path);
1602
    int ret;
1603
    if( strncmp(path, "/vsi", 4) == 0 )
1604
    {
1605
        errno = ENOTSUP;
1606
        ret = -1;
1607
    }
1608
    else
1609
    {
1610
        if( pfnlgetfilecon == NULL )
1611
            pfnlgetfilecon = (fnlgetfileconType) dlsym(RTLD_NEXT, "lgetfilecon");
1612
        if( pfnlgetfilecon == NULL )
1613
            ret = -1;
1614
        else
1615
            ret = pfnlgetfilecon(path, con);
1616
    }
1617
    return ret;
1618
}