281
int file::pos_alignment() const
283
// on linux and windows, file offsets needs
284
// to be aligned to the disk sector size
285
#if defined TORRENT_LINUX
286
if (m_sector_size == 0)
289
if (fstatvfs(m_fd, &fs) == 0)
290
m_sector_size = fs.f_bsize;
292
m_sector_size = 4096;
294
return m_sector_size;
295
#elif defined TORRENT_WINDOWS
296
if (m_sector_size == 0)
298
DWORD sectors_per_cluster;
299
DWORD bytes_per_sector;
301
DWORD total_clusters;
302
#if TORRENT_USE_WPATH
303
#define GetDiskFreeSpace_ GetDiskFreeSpaceW
304
wchar_t backslash = L'\\';
306
#define GetDiskFreeSpace_ GetDiskFreeSpaceA
307
char backslash = '\\';
309
if (GetDiskFreeSpace_(m_path.substr(0, m_path.find_first_of(backslash)+1).c_str()
310
, §ors_per_cluster, &bytes_per_sector
311
, &free_clusters, &total_clusters))
313
m_sector_size = bytes_per_sector;
314
m_cluster_size = sectors_per_cluster * bytes_per_sector;
318
// make a conservative guess
320
m_cluster_size = 4096;
323
return m_sector_size;
329
int file::buf_alignment() const
331
#if defined TORRENT_WINDOWS
335
return pos_alignment();
339
int file::size_alignment() const
341
#if defined TORRENT_WINDOWS
345
return pos_alignment();
235
349
void file::close()
351
#if defined TORRENT_WINDOWS || defined TORRENT_LINUX
237
355
#ifdef TORRENT_WINDOWS
238
356
if (m_file_handle == INVALID_HANDLE_VALUE) return;
239
357
CloseHandle(m_file_handle);
240
358
m_file_handle = INVALID_HANDLE_VALUE;
242
361
if (m_fd == -1) return;
251
size_type file::read(char* buf, size_type num_bytes, error_code& ec)
253
TORRENT_ASSERT((m_open_mode & in) == in);
255
TORRENT_ASSERT(num_bytes >= 0);
256
TORRENT_ASSERT(is_open());
258
#ifdef TORRENT_WINDOWS
260
TORRENT_ASSERT(DWORD(num_bytes) == num_bytes);
264
if (ReadFile(m_file_handle, buf, (DWORD)num_bytes, &ret, 0) == FALSE)
266
ec = error_code(GetLastError(), get_system_category());
271
size_type ret = ::read(m_fd, buf, num_bytes);
272
if (ret == -1) ec = error_code(errno, get_posix_category());
277
size_type file::write(const char* buf, size_type num_bytes, error_code& ec)
279
TORRENT_ASSERT((m_open_mode & out) == out);
281
TORRENT_ASSERT(num_bytes >= 0);
282
TORRENT_ASSERT(is_open());
284
#ifdef TORRENT_WINDOWS
289
if (WriteFile(m_file_handle, buf, (DWORD)num_bytes, &ret, 0) == FALSE)
291
ec = error_code(GetLastError(), get_system_category());
296
size_type ret = ::write(m_fd, buf, num_bytes);
297
if (ret == -1) ec = error_code(errno, get_posix_category());
368
// defined in storage.cpp
369
int bufs_size(file::iovec_t const* bufs, int num_bufs);
371
#if defined TORRENT_WINDOWS || defined TORRENT_LINUX || defined TORRENT_DEBUG
373
int file::m_page_size = 0;
375
void file::init_file()
377
if (m_page_size != 0) return;
379
m_page_size = page_size();
384
size_type file::readv(size_type file_offset, iovec_t const* bufs, int num_bufs, error_code& ec)
386
TORRENT_ASSERT((m_open_mode & rw_mask) == read_only || (m_open_mode & rw_mask) == read_write);
387
TORRENT_ASSERT(bufs);
388
TORRENT_ASSERT(num_bufs > 0);
389
TORRENT_ASSERT(is_open());
391
#if defined TORRENT_WINDOWS || defined TORRENT_LINUX || defined TORRENT_DEBUG
392
// make sure m_page_size is initialized
397
if (m_open_mode & no_buffer)
401
// when opened in no_buffer mode, the file_offset must
402
// be aligned to pos_alignment()
403
TORRENT_ASSERT((file_offset & (pos_alignment()-1)) == 0);
404
for (file::iovec_t const* i = bufs, *end(bufs + num_bufs); i < end; ++i)
406
TORRENT_ASSERT((uintptr_t(i->iov_base) & (buf_alignment()-1)) == 0);
407
// every buffer must be a multiple of the page size
408
// except for the last one
409
TORRENT_ASSERT((i->iov_len & (size_alignment()-1)) == 0 || i == end-1);
410
if ((i->iov_len & (size_alignment()-1)) != 0) eof = true;
414
if (eof) TORRENT_ASSERT(file_offset + size >= get_size(code));
418
#ifdef TORRENT_WINDOWS
422
// since the ReadFileScatter requires the file to be opened
423
// with no buffering, and no buffering requires page aligned
424
// buffers, open the file in non-buffered mode in case the
425
// buffer is not aligned. Most of the times the buffer should
428
if ((m_open_mode & no_buffer) == 0)
430
// this means the buffer base or the buffer size is not aligned
431
// to the page size. Use a regular file for this operation.
434
offs.QuadPart = file_offset;
435
if (SetFilePointerEx(m_file_handle, offs, &offs, FILE_BEGIN) == FALSE)
437
ec = error_code(GetLastError(), get_system_category());
441
for (file::iovec_t const* i = bufs, *end(bufs + num_bufs); i < end; ++i)
443
DWORD intermediate = 0;
444
if (ReadFile(m_file_handle, (char*)i->iov_base
445
, (DWORD)i->iov_len, &intermediate, 0) == FALSE)
447
ec = error_code(GetLastError(), get_system_category());
455
int size = bufs_size(bufs, num_bufs);
456
// number of pages for the read. round up
457
int num_pages = (size + m_page_size - 1) / m_page_size;
458
// allocate array of FILE_SEGMENT_ELEMENT for ReadFileScatter
459
FILE_SEGMENT_ELEMENT* segment_array = TORRENT_ALLOCA(FILE_SEGMENT_ELEMENT, num_pages + 1);
460
FILE_SEGMENT_ELEMENT* cur_seg = segment_array;
462
for (file::iovec_t const* i = bufs, *end(bufs + num_bufs); i < end; ++i)
464
for (int k = 0; k < i->iov_len; k += m_page_size)
466
cur_seg->Buffer = ((char*)i->iov_base) + k;
470
// terminate the array
476
ol.OffsetHigh = file_offset >> 32;
477
ol.Offset = file_offset & 0xffffffff;
478
ol.hEvent = CreateEvent(0, true, false, 0);
481
size = num_pages * m_page_size;
482
if (ReadFileScatter(m_file_handle, segment_array, size, 0, &ol) == 0)
484
DWORD last_error = GetLastError();
485
if (last_error != ERROR_IO_PENDING)
487
ec = error_code(GetLastError(), get_system_category());
488
CloseHandle(ol.hEvent);
491
if (GetOverlappedResult(m_file_handle, &ol, &ret, true) == 0)
493
ec = error_code(GetLastError(), get_system_category());
494
CloseHandle(ol.hEvent);
498
CloseHandle(ol.hEvent);
501
#else // TORRENT_WINDOWS
503
size_type ret = lseek(m_fd, file_offset, SEEK_SET);
506
ec = error_code(errno, get_posix_category());
509
#if TORRENT_USE_READV
512
bool aligned = false;
514
// if we're not opened in no-buffer mode, we don't need alignment
515
if ((m_open_mode & no_buffer) == 0) aligned = true;
518
size = bufs_size(bufs, num_bufs);
519
if ((size & (size_alignment()-1)) == 0) aligned = true;
522
#endif // TORRENT_LINUX
524
ret = ::readv(m_fd, bufs, num_bufs);
527
ec = error_code(errno, get_posix_category());
533
file::iovec_t* temp_bufs = TORRENT_ALLOCA(file::iovec_t, num_bufs);
534
memcpy(temp_bufs, bufs, sizeof(file::iovec_t) * num_bufs);
535
iovec_t& last = temp_bufs[num_bufs-1];
536
last.iov_len = (last.iov_len & ~(size_alignment()-1)) + m_page_size;
537
ret = ::readv(m_fd, temp_bufs, num_bufs);
540
ec = error_code(errno, get_posix_category());
543
return (std::min)(ret, size_type(size));
544
#endif // TORRENT_LINUX
546
#else // TORRENT_USE_READV
549
for (file::iovec_t const* i = bufs, *end(bufs + num_bufs); i < end; ++i)
551
int tmp = read(m_fd, i->iov_base, i->iov_len);
554
ec = error_code(errno, get_posix_category());
558
if (tmp < i->iov_len) break;
562
#endif // TORRENT_USE_READV
564
#endif // TORRENT_WINDOWS
567
size_type file::writev(size_type file_offset, iovec_t const* bufs, int num_bufs, error_code& ec)
569
TORRENT_ASSERT((m_open_mode & rw_mask) == write_only || (m_open_mode & rw_mask) == read_write);
570
TORRENT_ASSERT(bufs);
571
TORRENT_ASSERT(num_bufs > 0);
572
TORRENT_ASSERT(is_open());
574
#if defined TORRENT_WINDOWS || defined TORRENT_LINUX || defined TORRENT_DEBUG
575
// make sure m_page_size is initialized
580
if (m_open_mode & no_buffer)
584
// when opened in no_buffer mode, the file_offset must
585
// be aligned to pos_alignment()
586
TORRENT_ASSERT((file_offset & (pos_alignment()-1)) == 0);
587
for (file::iovec_t const* i = bufs, *end(bufs + num_bufs); i < end; ++i)
589
TORRENT_ASSERT((uintptr_t(i->iov_base) & (buf_alignment()-1)) == 0);
590
// every buffer must be a multiple of the page size
591
// except for the last one
592
TORRENT_ASSERT((i->iov_len & (size_alignment()-1)) == 0 || i == end-1);
593
if ((i->iov_len & (size_alignment()-1)) != 0) eof = true;
597
if (eof) TORRENT_ASSERT(file_offset + size >= get_size(code));
601
#ifdef TORRENT_WINDOWS
605
// since the ReadFileScatter requires the file to be opened
606
// with no buffering, and no buffering requires page aligned
607
// buffers, open the file in non-buffered mode in case the
608
// buffer is not aligned. Most of the times the buffer should
611
if ((m_open_mode & no_buffer) == 0)
613
// this means the buffer base or the buffer size is not aligned
614
// to the page size. Use a regular file for this operation.
617
offs.QuadPart = file_offset;
618
if (SetFilePointerEx(m_file_handle, offs, &offs, FILE_BEGIN) == FALSE)
620
ec = error_code(GetLastError(), get_system_category());
624
for (file::iovec_t const* i = bufs, *end(bufs + num_bufs); i < end; ++i)
626
DWORD intermediate = 0;
627
if (WriteFile(m_file_handle, (char const*)i->iov_base
628
, (DWORD)i->iov_len, &intermediate, 0) == FALSE)
630
ec = error_code(GetLastError(), get_system_category());
638
int size = bufs_size(bufs, num_bufs);
639
// number of pages for the write. round up
640
int num_pages = (size + m_page_size - 1) / m_page_size;
641
// allocate array of FILE_SEGMENT_ELEMENT for WriteFileGather
642
FILE_SEGMENT_ELEMENT* segment_array = TORRENT_ALLOCA(FILE_SEGMENT_ELEMENT, num_pages + 1);
643
FILE_SEGMENT_ELEMENT* cur_seg = segment_array;
645
for (file::iovec_t const* i = bufs, *end(bufs + num_bufs); i < end; ++i)
647
for (int k = 0; k < i->iov_len; k += m_page_size)
649
cur_seg->Buffer = ((char*)i->iov_base) + k;
653
// terminate the array
659
ol.OffsetHigh = file_offset >> 32;
660
ol.Offset = file_offset & 0xffffffff;
661
ol.hEvent = CreateEvent(0, true, false, 0);
664
// if file_size is > 0, the file will be opened in unbuffered
665
// mode after the write completes, and truncate the file to
667
size_type file_size = 0;
669
if ((size & (m_page_size-1)) != 0)
671
// if size is not an even multiple, this must be the tail
672
// of the file. Write the whole page and then open a new
673
// file without FILE_FLAG_NO_BUFFERING and set the
674
// file size to file_offset + size
676
file_size = file_offset + size;
677
size = num_pages * m_page_size;
680
if (WriteFileGather(m_file_handle, segment_array, size, 0, &ol) == 0)
682
if (GetLastError() != ERROR_IO_PENDING)
684
ec = error_code(GetLastError(), get_system_category());
685
CloseHandle(ol.hEvent);
689
if (GetOverlappedResult(m_file_handle, &ol, &tmp, true) == 0)
691
ec = error_code(GetLastError(), get_system_category());
692
CloseHandle(ol.hEvent);
695
if (tmp < ret) ret = tmp;
697
CloseHandle(ol.hEvent);
701
#if TORRENT_USE_WPATH
702
#define CreateFile_ CreateFileW
704
#define CreateFile_ CreateFileA
706
HANDLE f = CreateFile_(m_path.c_str(), GENERIC_WRITE
707
, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING
708
, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, 0);
710
if (f == INVALID_HANDLE_VALUE)
712
ec = error_code(GetLastError(), get_system_category());
717
offs.QuadPart = file_size;
718
if (SetFilePointerEx(f, offs, &offs, FILE_BEGIN) == FALSE)
721
ec = error_code(GetLastError(), get_system_category());
724
if (::SetEndOfFile(f) == FALSE)
726
ec = error_code(GetLastError(), get_system_category());
735
size_type ret = lseek(m_fd, file_offset, SEEK_SET);
738
ec = error_code(errno, get_posix_category());
742
#if TORRENT_USE_WRITEV
745
bool aligned = false;
747
// if we're not opened in no-buffer mode, we don't need alignment
748
if ((m_open_mode & no_buffer) == 0) aligned = true;
751
size = bufs_size(bufs, num_bufs);
752
if ((size & (size_alignment()-1)) == 0) aligned = true;
757
ret = ::writev(m_fd, bufs, num_bufs);
760
ec = error_code(errno, get_posix_category());
766
file::iovec_t* temp_bufs = TORRENT_ALLOCA(file::iovec_t, num_bufs);
767
memcpy(temp_bufs, bufs, sizeof(file::iovec_t) * num_bufs);
768
iovec_t& last = temp_bufs[num_bufs-1];
769
last.iov_len = (last.iov_len & ~(size_alignment()-1)) + size_alignment();
770
ret = ::writev(m_fd, temp_bufs, num_bufs);
773
ec = error_code(errno, get_posix_category());
776
if (ftruncate(m_fd, file_offset + size) < 0)
778
ec = error_code(errno, get_posix_category());
781
return (std::min)(ret, size_type(size));
782
#endif // TORRENT_LINUX
784
#else // TORRENT_USE_WRITEV
787
for (file::iovec_t const* i = bufs, *end(bufs + num_bufs); i < end; ++i)
789
int tmp = write(m_fd, i->iov_base, i->iov_len);
792
ec = error_code(errno, get_posix_category());
796
if (tmp < i->iov_len) break;
800
#endif // TORRENT_USE_WRITEV
802
#endif // TORRENT_WINDOWS
805
size_type file::phys_offset(size_type offset)
808
// for documentation of this feature
809
// http://lwn.net/Articles/297696/
812
struct fiemap fiemap;
813
struct fiemap_extent extent;
816
memset(&fm, 0, sizeof(fm));
817
fm.fiemap.fm_start = offset;
818
fm.fiemap.fm_length = size_alignment();
819
// this sounds expensive
820
fm.fiemap.fm_flags = FIEMAP_FLAG_SYNC;
821
fm.fiemap.fm_extent_count = 1;
823
if (ioctl(m_fd, FS_IOC_FIEMAP, &fm) == -1)
826
if (fm.fiemap.fm_extents[0].fe_flags & FIEMAP_EXTENT_UNKNOWN)
829
// the returned extent is not guaranteed to start
830
// at the requested offset, adjust for that in
832
TORRENT_ASSERT(offset >= fm.fiemap.fm_extents[0].fe_logical);
833
return fm.fiemap.fm_extents[0].fe_physical + (offset - fm.fiemap.fm_extents[0].fe_logical);
835
#elif defined F_LOG2PHYS
836
// for documentation of this feature
837
// http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man2/fcntl.2.html
840
size_type ret = lseek(m_fd, offset, SEEK_SET);
841
if (ret < 0) return 0;
842
if (fcntl(m_fd, F_LOG2PHYS, &l) == -1) return 0;
843
return l.l2p_devoffset;
844
#elif defined TORRENT_WINDOWS
845
// for documentation of this feature
846
// http://msdn.microsoft.com/en-us/library/aa364572(VS.85).aspx
847
STARTING_VCN_INPUT_BUFFER in;
848
RETRIEVAL_POINTERS_BUFFER out;
851
// query cluster size
853
in.StartingVcn.QuadPart = offset / m_cluster_size;
854
int cluster_offset = in.StartingVcn.QuadPart % m_cluster_size;
856
if (DeviceIoControl(m_file_handle, FSCTL_GET_RETRIEVAL_POINTERS, &in
857
, sizeof(in), &out, sizeof(out), &out_bytes, 0) == 0)
859
DWORD error = GetLastError();
860
TORRENT_ASSERT(error != ERROR_INVALID_PARAMETER);
862
// insufficient buffer error is expected, but we're
863
// only interested in the first extent anyway
864
if (error != ERROR_MORE_DATA) return 0;
866
if (out_bytes < sizeof(out)) return 0;
867
if (out.ExtentCount == 0) return 0;
868
if (out.Extents[0].Lcn.QuadPart == (LONGLONG)-1) return 0;
869
TORRENT_ASSERT(in.StartingVcn.QuadPart >= out.StartingVcn.QuadPart);
870
return (out.Extents[0].Lcn.QuadPart
871
+ (in.StartingVcn.QuadPart - out.StartingVcn.QuadPart))
872
* m_cluster_size + cluster_offset;
302
877
bool file::set_size(size_type s, error_code& ec)
305
880
TORRENT_ASSERT(s >= 0);
307
882
#ifdef TORRENT_WINDOWS
308
size_type pos = tell(ec);
309
if (ec) return false;
311
if (ec) return false;
884
LARGE_INTEGER cur_size;
885
if (GetFileSizeEx(m_file_handle, &cur_size) == FALSE)
887
ec = error_code(GetLastError(), get_system_category());
891
// only set the file size if it's not already at
892
// the right size. We don't want to update the
893
// modification time if we don't have to
894
if (cur_size.QuadPart != s)
896
if (SetFilePointerEx(m_file_handle, offs, &offs, FILE_BEGIN) == FALSE)
898
ec.assign(GetLastError(), get_system_category());
901
if (::SetEndOfFile(m_file_handle) == FALSE)
903
ec.assign(GetLastError(), get_system_category());
907
#if _WIN32_WINNT >= 0x501
908
if ((m_open_mode & sparse) == 0)
910
// only allocate the space if the file
911
// is not fully allocated
912
offs.LowPart = GetCompressedFileSize(m_path.c_str(), &offs.HighPart);
913
ec.assign(GetLastError(), get_system_category());
914
if (ec) return false;
915
if (offs.QuadPart != s)
917
// if the user has permissions, avoid filling
918
// the file with zeroes, but just fill it with
920
SetFileValidData(m_file_handle, offs.QuadPart);
312
924
if (::SetEndOfFile(m_file_handle) == FALSE)
314
926
ec = error_code(GetLastError(), get_system_category());
318
if (ftruncate(m_fd, s) < 0)
931
if (fstat(m_fd, &st) != 0)
933
ec.assign(errno, get_posix_category());
937
// only truncate the file if it doesn't already
938
// have the right size. We don't want to update
939
if (st.st_size != s && ftruncate(m_fd, s) < 0)
941
ec.assign(errno, get_posix_category());
945
// if we're not in sparse mode, allocate the storage
946
// but only if the number of allocated blocks for the file
947
// is less than the file size. Otherwise we would just
948
// update the modification time of the file for no good
950
if ((m_open_mode & sparse) == 0
951
&& st.st_blocks < (s + st.st_blksize - 1) / st.st_blksize)
953
// How do we know that the file is already allocated?
954
// if we always try to allocate the space, we'll update
955
// the modification time without actually changing the file
956
// but if we don't do anything if the file size is
958
fstore_t f = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, s, 0};
959
if (fcntl(m_fd, F_PREALLOCATE, &f) < 0)
961
ec = error_code(errno, get_posix_category());
964
#elif defined TORRENT_LINUX
965
int ret = my_fallocate(m_fd, 0, 0, s);
966
// if we return 0, everything went fine
967
// the fallocate call succeeded
968
if (ret == 0) return true;
969
// otherwise, something went wrong. If the error
970
// is ENOSYS, just keep going and do it the old-fashioned
971
// way. If fallocate failed with some other error, it
972
// probably means the user should know about it, error out
976
ec.assign(ret, get_posix_category());
979
// if fallocate failed, we have to use posix_fallocate
980
// which can be painfully slow
981
ret = posix_fallocate(m_fd, 0, s);
984
ec = error_code(ret, get_posix_category());
987
#elif TORRENT_HAS_FALLOCATE
988
int ret = posix_fallocate(m_fd, 0, s);
991
ec = error_code(ret, get_posix_category());
1000
size_type file::get_size(error_code& ec) const
1002
#ifdef TORRENT_WINDOWS
1003
LARGE_INTEGER file_size;
1004
if (!GetFileSizeEx(m_file_handle, &file_size))
1006
ec = error_code(GetLastError(), get_system_category());
1009
return file_size.QuadPart;
1012
if (fstat(m_fd, &fs) != 0)
320
1014
ec = error_code(errno, get_posix_category());
327
size_type file::seek(size_type offset, seek_mode m, error_code& ec)
329
TORRENT_ASSERT(is_open());
331
#ifdef TORRENT_WINDOWS
333
offs.QuadPart = offset;
334
if (SetFilePointerEx(m_file_handle, offs, &offs, m.m_val) == FALSE)
336
ec = error_code(GetLastError(), get_system_category());
339
return offs.QuadPart;
341
size_type ret = lseek(m_fd, offset, m.m_val);
342
if (ret < 0) ec = error_code(errno, get_posix_category());
347
size_type file::tell(error_code& ec)
349
TORRENT_ASSERT(is_open());
351
#ifdef TORRENT_WINDOWS
355
// is there any other way to get offset?
356
if (SetFilePointerEx(m_file_handle, offs, &offs
357
, FILE_CURRENT) == FALSE)
359
ec = error_code(GetLastError(), get_system_category());
363
return offs.QuadPart;
366
ret = lseek(m_fd, 0, SEEK_CUR);
367
if (ret < 0) ec = error_code(errno, get_posix_category());
1021
size_type file::sparse_end(size_type start) const
1023
#ifdef TORRENT_WINDOWS
1024
#ifdef TORRENT_MINGW
1025
typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
1026
LARGE_INTEGER FileOffset;
1027
LARGE_INTEGER Length;
1028
} FILE_ALLOCATED_RANGE_BUFFER, *PFILE_ALLOCATED_RANGE_BUFFER;
1029
#define FSCTL_QUERY_ALLOCATED_RANGES ((0x9 << 16) | (1 << 14) | (51 << 2) | 3)
1031
FILE_ALLOCATED_RANGE_BUFFER buffer;
1032
DWORD bytes_returned = 0;
1033
FILE_ALLOCATED_RANGE_BUFFER in;
1035
size_type file_size = get_size(ec);
1036
if (ec) return start;
1037
in.FileOffset.QuadPart = start;
1038
in.Length.QuadPart = file_size - start;
1039
if (!DeviceIoControl(m_file_handle, FSCTL_QUERY_ALLOCATED_RANGES
1040
, &in, sizeof(FILE_ALLOCATED_RANGE_BUFFER)
1041
, &buffer, sizeof(FILE_ALLOCATED_RANGE_BUFFER), &bytes_returned, 0))
1043
int err = GetLastError();
1044
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return start;
1047
// if there are no allocated regions within the rest
1048
// of the file, return the end of the file
1049
if (bytes_returned == 0) return file_size;
1051
// assume that this range overlaps the start of the
1052
// region we were interested in, and that start actually
1053
// resides in an allocated region.
1054
if (buffer.FileOffset.QuadPart < start) return start;
1056
// return the offset to the next allocated region
1057
return buffer.FileOffset.QuadPart;
1059
#elif defined SEEK_DATA
1060
// this is supported on solaris
1061
size_type ret = lseek(m_fd, start, SEEK_DATA);
1062
if (ret < 0) return start;