forked from foobaz/gdal
-
Notifications
You must be signed in to change notification settings - Fork 1
/
vsi.go
467 lines (421 loc) · 16.8 KB
/
vsi.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
package gdal
/*
#include <cpl_vsi.h>
//#include "go_gdal.h"
//#include "gdal_version.h"
#cgo linux CFLAGS: -I/usr/include/gdal
#cgo linux LDFLAGS: -lgdal
#cgo darwin pkg-config: gdal
#cgo windows LDFLAGS: -lgdal.dll
*/
import "C"
import (
"unsafe"
)
type VSILFile *C.VSILFILE
type VSIStatBufL C.VSIStatBufL
// Open file.
//
// This function opens a file with the desired access. Large files (larger than 2GB) should be supported. Binary access is always implied and the "b" does not need to be included in the pszAccess string.
//
// On windows it is possible to define the configuration option GDAL_FILE_IS_UTF8 to have pszFilename treated as being in the local encoding instead of UTF-8, retoring the pre-1.8.0 behavior of VSIFOpenL().
//
// This method goes through the VSIFileHandler virtualization and may work on unusual filesystems such as in memory.
//
// Analog of the POSIX fopen() function.
//
// Parameters:
// filename the file to open. UTF-8 encoded.
// access access requested (ie. "r", "r+", "w".
//
// Returns:
// NULL on failure, or the file handle.
func VSIFOpenL(filename, access string) VSILFile {
pszFilename := C.CString(filename)
defer C.free(unsafe.Pointer(pszFilename))
pszAccess := C.CString(access)
defer C.free(unsafe.Pointer(pszAccess))
fp := C.VSIFOpenL(pszFilename, pszAccess)
return VSILFile(fp)
}
// Close file.
//
// This function closes the indicated file.
//
// This method goes through the VSIFileHandler virtualization and may work on unusual filesystems such as in memory.
//
// Analog of the POSIX fclose() function.
//
// Parameters:
// fp file handle opened with VSIFOpenL().
//
// Returns:
// True on success or false on failure.
func VSIFCloseL(fp VSILFile) bool {
err := C.VSIFCloseL((*C.VSILFILE)(fp))
return err == 0
}
// Seek to requested offset.
//
// Seek to the desired offset (nOffset) in the indicated file.
//
// This method goes through the VSIFileHandler virtualization and may work on unusual filesystems such as in memory.
//
// Analog of the POSIX fseek() call.
//
// Parameters:
// fp file handle opened with VSIFOpenL().
// offset offset in bytes.
// whence one of SEEK_SET, SEEK_CUR or SEEK_END.
//
// Returns:
// True on success or false on failure.
func VSIFSeekL(fp VSILFile, offset, whence int) bool {
err := C.VSIFSeekL((*C.VSILFILE)(fp), C.vsi_l_offset(offset), C.int(whence))
return err == 0
}
// Tell current file offset.
//
// Returns the current file read/write offset in bytes from the beginning of the file.
//
// This method goes through the VSIFileHandler virtualization and may work on unusual filesystems such as in memory.
//
// Analog of the POSIX ftell() call.
//
// Parameters:
// fp file handle opened with VSIFOpenL().
//
// Returns:
// file offset in bytes.
func VSIFTellL(fp VSILFile) int {
offset := C.VSIFTellL((*C.VSILFILE)(fp))
return int(offset)
}
// Analog of the POSIX rewind() call.
func VSIRewindL(fp VSILFile) {
C.VSIRewindL((*C.VSILFILE)(fp))
}
// Read bytes from file.
//
// Reads nCount objects of nSize bytes from the indicated file at the current offset into the indicated buffer.
//
// This method goes through the VSIFileHandler virtualization and may work on unusual filesystems such as in memory.
//
// Analog of the POSIX fread() call.
//
// Parameters:
// buffer the buffer into which the data should be read (at least nCount * nSize bytes in size.
// size size of objects to read in bytes.
// count number of objects to read.
// fp file handle opened with VSIFOpenL().
//
// Returns:
// number of objects successfully read.
func VSIFReadL(buffer []byte, size, count int, fp VSILFile) int {
nRead := C.VSIFReadL(unsafe.Pointer(&buffer[0]), C.size_t(size), C.size_t(count), (*C.VSILFILE)(fp))
return int(nRead)
}
// Write bytes to file.
//
// Writes nCount objects of nSize bytes to the indicated file at the current offset into the indicated buffer.
//
// This method goes through the VSIFileHandler virtualization and may work on unusual filesystems such as in memory.
//
// Analog of the POSIX fwrite() call.
//
// Parameters:
// buffer the buffer from which the data should be written (at least nCount * nSize bytes in size.
// size size of objects to read in bytes.
// count number of objects to read.
// fp file handle opened with VSIFOpenL().
//
// Returns:
// number of objects successfully written.
func VSIFWriteL(buffer []byte, size, count int, fp VSILFile) int {
nWritten := C.VSIFWriteL(unsafe.Pointer(&buffer[0]), C.size_t(size), C.size_t(count), (*C.VSILFILE)(fp))
return int(nWritten)
}
// Test for end of file.
//
// Returns true if an end-of-file condition occured during the previous read operation. The end-of-file flag is cleared by a successfull VSIFSeekL() call.
//
// This method goes through the VSIFileHandler virtualization and may work on unusual filesystems such as in memory.
//
// Analog of the POSIX feof() call.
//
// Parameters:
// fp file handle opened with VSIFOpenL().
//
// Returns:
// True if at EOF else false.
func VSIFEofL(fp VSILFile) bool {
bEnd := C.VSIFEofL((*C.VSILFILE)(fp))
return bEnd != C.FALSE
}
// Truncate/expand the file to the specified size.
//
// This method goes through the VSIFileHandler virtualization and may work on unusual filesystems such as in memory.
//
// Analog of the POSIX ftruncate() call.
//
// Parameters:
// fp file handle opened with VSIFOpenL().
// newSize new size in bytes.
//
// Returns:
// True on success or false on error.
func VSIFTruncateL(fp VSILFile, newSize int) bool {
err := C.VSIFTruncateL((*C.VSILFILE)(fp), C.vsi_l_offset(newSize))
return err == 0
}
// Flush pending writes to disk.
//
// For files in write or update mode and on filesystem types where it is applicable, all pending output on the file is flushed to the physical disk.
//
// This method goes through the VSIFileHandler virtualization and may work on unusual filesystems such as in memory.
//
// Analog of the POSIX fflush() call.
//
// Parameters:
// fp file handle opened with VSIFOpenL().
//
// Returns:
// True on success or false on error.
func VSIFFlushL(fp VSILFile) bool {
err := C.VSIFFlushL((*C.VSILFILE)(fp))
return err == 0
}
// Analog of the POSIX putc() call.
//
// Parameters:
// fp file handle opened with VSIFOpenL().
//
// Returns:
// True on success or false on error.
func VSIFPutcL(c int, fp VSILFile) bool {
nWritten := C.VSIFPutcL(C.int(c), (*C.VSILFILE)(fp))
return nWritten > 0
}
// Get filesystem object info.
//
// Fetches status information about a filesystem object (file, directory, etc). The returned information is placed in the VSIStatBufL structure. For portability only the st_size (size in bytes), and st_mode (file type). This method is similar to VSIStat(), but will work on large files on systems where this requires special calls.
//
// This method goes through the VSIFileHandler virtualization and may work on unusual filesystems such as in memory.
//
// Analog of the POSIX stat() function.
//
// Parameters:
// filename the path of the filesystem object to be queried. UTF-8 encoded.
//
// Returns:
// statBuf the structure with information.
// success True on success or false on an error.
func VSIStatL(filename string) (statBuf VSIStatBufL, success bool) {
pszFilename := C.CString(filename)
defer C.free(unsafe.Pointer(pszFilename))
err := C.VSIStatL(pszFilename, (*C.VSIStatBufL)(&statBuf))
success = err == 0
return statBuf, success
}
// Get filesystem object info.
//
// Fetches status information about a filesystem object (file, directory, etc). The returned information is placed in the VSIStatBufL structure. For portability only the st_size (size in bytes), and st_mode (file type). This method is similar to VSIStat(), but will work on large files on systems where this requires special calls.
//
// This method goes through the VSIFileHandler virtualization and may work on unusual filesystems such as in memory.
//
// Analog of the POSIX stat() function, with an extra parameter to specify which information is needed, which offers a potential for speed optimizations on specialized and potentially slow virtual filesystem objects (/vsigzip/, /vsicurl/)
//
// Parameters:
// filename the path of the filesystem object to be queried. UTF-8 encoded.
// flags 0 to get all information, or VSI_STAT_EXISTS_FLAG, VSI_STAT_NATURE_FLAG or VSI_STAT_SIZE_FLAG, or a combination of those to get partial info.
//
// Returns:
// statBuf the structure with information.
// success True on success or false on an error.
func VSIStatExL(filename string, flags int) (statBuf VSIStatBufL, success bool) {
pszFilename := C.CString(filename)
defer C.free(unsafe.Pointer(pszFilename))
err := C.VSIStatExL(pszFilename, (*C.VSIStatBufL)(&statBuf), C.int(flags))
success = err == 0
return statBuf, success
}
// Returns if the filenames of the filesystem are case sensitive.
//
// This method retrieves to which filesystem belongs the passed filename and return TRUE if the filenames of that filesystem are case sensitive.
//
// Currently, this will return FALSE only for Windows real filenames. Other VSI virtual filesystems are case sensitive.
//
// This methods avoid ugly ifndef WIN32 / endif code, that is wrong when dealing with virtual filenames.
//
// Parameters:
// filename the path of the filesystem object to be tested. UTF-8 encoded.
//
// Returns:
// True if the filenames of the filesystem are case sensitive.
func VSIIsCaseSensitiveFS(filename string) bool {
pszFilename := C.CString(filename)
defer C.free(unsafe.Pointer(pszFilename))
bSensitive := C.VSIIsCaseSensitiveFS(pszFilename)
return (bSensitive != 0)
}
// Create a directory.
//
// Create a new directory with the indicated mode. The mode is ignored on some platforms. A reasonable default mode value would be 0666. This method goes through the VSIFileHandler virtualization and may work on unusual filesystems such as in memory.
//
// Analog of the POSIX mkdir() function.
//
// Parameters:
// pszPathname the path to the directory to create. UTF-8 encoded.
// mode the permissions mode.
func VSIMkdir(path string, mode int) bool {
pszPath := C.CString(path)
defer C.free(unsafe.Pointer(pszPath))
err := C.VSIMkdir(pszPath, C.long(mode))
return err == 0
}
// Delete a directory.
//
// Deletes a directory object from the file system. On some systems the directory must be empty before it can be deleted.
//
// This method goes through the VSIFileHandler virtualization and may work on unusual filesystems such as in memory.
//
// Analog of the POSIX rmdir() function.
//
// Parameters:
// pszDirname the path of the directory to be deleted. UTF-8 encoded.
//
// Returns:
// True on success or false on an error.
func VSIRmdir(path string) bool {
pszPath := C.CString(path)
defer C.free(unsafe.Pointer(pszPath))
err := C.VSIRmdir(pszPath)
return err == 0
}
// Delete a file.
//
// Deletes a file object from the file system.
//
// This method goes through the VSIFileHandler virtualization and may work on unusual filesystems such as in memory.
//
// Analog of the POSIX unlink() function.
//
// Parameters:
// pszFilename the path of the file to be deleted. UTF-8 encoded.
//
// Returns:
// 0 on success or -1 on an error.
func VSIUnlink(path string) bool {
pszPath := C.CString(path)
defer C.free(unsafe.Pointer(pszPath))
err := C.VSIUnlink(pszPath)
return err == 0
}
// Rename a file.
//
// Renames a file object in the file system. It should be possible to rename a file onto a new filesystem, but it is safest if this function is only used to rename files that remain in the same directory.
//
// This method goes through the VSIFileHandler virtualization and may work on unusual filesystems such as in memory.
//
// Analog of the POSIX rename() function.
//
// Parameters:
// oldpath the name of the file to be renamed. UTF-8 encoded.
// newpath the name the file should be given. UTF-8 encoded.
//
// Returns:
// 0 on success or -1 on an error.
func VSIRename(oldPath, newPath string) bool {
pszOldPath := C.CString(oldPath)
defer C.free(unsafe.Pointer(pszOldPath))
pszNewPath := C.CString(newPath)
defer C.free(unsafe.Pointer(pszNewPath))
err := C.VSIRename(pszOldPath, pszNewPath)
return err == 0
}
func VSIStrerror(errno int) string {
pszErr := C.VSIStrerror(C.int(errno))
return C.GoString(pszErr)
}
// Install "memory" file system handler.
//
// A special file handler is installed that allows block of memory to be treated as files. All portions of the file system underneath the base path "/vsimem/" will be handled by this driver.
//
// Normal VSI*L functions can be used freely to create and destroy memory arrays treating them as if they were real file system objects. Some additional methods exist to efficient create memory file system objects without duplicating original copies of the data or to "steal" the block of memory associated with a memory file.
//
// At this time the memory handler does not properly handle directory semantics for the memory portion of the filesystem. The VSIReadDir() function is not supported though this will be corrected in the future.
//
// Calling this function repeatedly should do no harm, though it is not necessary. It is already called the first time a virtualizable file access function (ie. VSIFOpenL(), VSIMkDir(), etc) is called.
func VSIInstallMemFileHandler() {
C.VSIInstallMemFileHandler()
}
func VSIInstallLargeFileHandler() {
C.VSIInstallLargeFileHandler()
}
// Install /vsisubfile/ virtual file handler.
//
// This virtual file system handler allows access to subregions of files, treating them as a file on their own to the virtual file system functions (VSIFOpenL(), etc).
//
// A special form of the filename is used to indicate a subportion of another file:
//
// /vsisubfile/<offset>[_<size>],<filename>
//
// The size parameter is optional. Without it the remainder of the file from the start offset as treated as part of the subfile. Otherwise only <size> bytes from <offset> are treated as part of the subfile. The <filename> portion may be a relative or absolute path using normal rules. The <offset> and <size> values are in bytes.
//
// e.g. /vsisubfile/1000_3000,/data/abc.ntf /vsisubfile/5000,../xyz/raw.dat
//
// Unlike the /vsimem/ or conventional file system handlers, there is no meaningful support for filesystem operations for creating new files, traversing directories, and deleting files within the /vsisubfile/ area. Only the VSIStatL(), VSIFOpenL() and operations based on the file handle returned by VSIFOpenL() operate properly.
func VSIInstallSubFileHandler() {
C.VSIInstallSubFileHandler()
}
// Install /vsisparse/ virtual file handler.
//
// The sparse virtual file handler allows a virtual file to be composed from chunks of data in other files, potentially with large spaces in the virtual file set to a constant value. This can make it possible to test some sorts of operations on what seems to be a large file with image data set to a constant value. It is also helpful when wanting to add test files to the test suite that are too large, but for which most of the data can be ignored. It could, in theory, also be used to treat several files on different file systems as one large virtual file.
func VSIInstallSparseFileHandler() {
C.VSIInstallSparseFileHandler()
}
func VSICleanupFileManager() {
C.VSICleanupFileManager()
}
// Create memory "file" from a buffer.
//
// A virtual memory file is created from the passed buffer with the indicated filename. Under normal conditions the filename would need to be absolute and within the /vsimem/ portion of the filesystem.
//
// The buffer remains the responsibility of the caller, and should not go out of scope as long as it might be accessed as a file. In no circumstances does this function take a copy of the data contents.
func VSIFileFromMemBuffer(filename string, data []byte) VSILFile {
pszFilename := C.CString(filename)
defer C.free(unsafe.Pointer(pszFilename))
fp := C.VSIFileFromMemBuffer(pszFilename, (*C.GByte)(&data[0]), C.vsi_l_offset(len(data)), C.FALSE)
return VSILFile(fp)
}
// Fetch buffer underlying memory file.
//
// This function returns a pointer to the memory buffer underlying a virtual "in memory" file. If bUnlinkAndSeize is TRUE the filesystem object will be deleted, and ownership of the buffer will pass to the caller otherwise the underlying file will remain in existance.
//
// Parameters:
// pszFilename the name of the file to grab the buffer of.
// pnDataLength (file) length returned in this variable.
// bUnlinkAndSeize TRUE to remove the file, or FALSE to leave unaltered.
//
// Returns:
// pointer to memory buffer or NULL on failure.
func VSIGetMemFileBuffer(filename string, unlinkAndSeize bool) []byte {
pszFilename := C.CString(filename)
defer C.free(unsafe.Pointer(pszFilename))
var bUnlinkAndSeize C.int
if unlinkAndSeize {
bUnlinkAndSeize = C.TRUE
} else {
bUnlinkAndSeize = C.FALSE
}
var pnDataLength C.vsi_l_offset
pabyData := C.VSIGetMemFileBuffer(pszFilename, &pnDataLength, bUnlinkAndSeize)
if pabyData == nil {
return nil
}
data := C.GoBytes(unsafe.Pointer(pabyData), C.int(pnDataLength))
if unlinkAndSeize {
C.VSIFree(unsafe.Pointer(pabyData))
}
return data
}