forked from premiere/premiere-libtorrent
fixed bug in fallocate usage and avoid trying to allocate and truncate files that don't need it to not update their modification time for no good reason
This commit is contained in:
parent
ae8e86e74a
commit
247bd9256d
59
src/file.cpp
59
src/file.cpp
|
@ -82,9 +82,14 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
static int my_fallocate(int fd, int mode, loff_t offset, loff_t len)
|
static int my_fallocate(int fd, int mode, loff_t offset, loff_t len)
|
||||||
{
|
{
|
||||||
#ifdef __NR_fallocate
|
#ifdef __NR_fallocate
|
||||||
|
// the man page on fallocate differes between versions of linux.
|
||||||
|
// it appears that fallocate in fact sets errno and returns -1
|
||||||
|
// on failure.
|
||||||
return syscall(__NR_fallocate, fd, mode, offset, len);
|
return syscall(__NR_fallocate, fd, mode, offset, len);
|
||||||
#else
|
#else
|
||||||
return EOPNOTSUPP;
|
// pretend that the system call doesn't exist
|
||||||
|
errno = ENOSYS;
|
||||||
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1464,14 +1469,33 @@ namespace libtorrent
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (ftruncate(m_fd, s) < 0)
|
struct stat st;
|
||||||
|
if (fstat(m_fd, &st) != 0)
|
||||||
{
|
{
|
||||||
ec.assign(errno, get_posix_category());
|
ec.assign(errno, get_posix_category());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((m_open_mode & sparse) == 0)
|
|
||||||
|
// only truncate the file if it doesn't already
|
||||||
|
// have the right size. We don't want to update
|
||||||
|
if (st.st_size != s && ftruncate(m_fd, s) < 0)
|
||||||
{
|
{
|
||||||
// if we're not in sparse mode, allocate the storage
|
ec.assign(errno, get_posix_category());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're not in sparse mode, allocate the storage
|
||||||
|
// but only if the number of allocated blocks for the file
|
||||||
|
// is less than the file size. Otherwise we would just
|
||||||
|
// update the modification time of the file for no good
|
||||||
|
// reason.
|
||||||
|
if ((m_open_mode & sparse) == 0
|
||||||
|
&& st.st_blocks < (s + st.st_blksize - 1) / st.st_blksize)
|
||||||
|
{
|
||||||
|
// How do we know that the file is already allocated?
|
||||||
|
// if we always try to allocate the space, we'll update
|
||||||
|
// the modification time without actually changing the file
|
||||||
|
// but if we don't do anything if the file size is
|
||||||
#ifdef F_PREALLOCATE
|
#ifdef F_PREALLOCATE
|
||||||
fstore_t f = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, s, 0};
|
fstore_t f = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, s, 0};
|
||||||
if (fcntl(m_fd, F_PREALLOCATE, &f) < 0)
|
if (fcntl(m_fd, F_PREALLOCATE, &f) < 0)
|
||||||
|
@ -1481,24 +1505,21 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
#elif defined TORRENT_LINUX
|
#elif defined TORRENT_LINUX
|
||||||
int ret = my_fallocate(m_fd, 0, 0, s);
|
int ret = my_fallocate(m_fd, 0, 0, s);
|
||||||
if (ret == 0 && errno != ENOSYS) return true;
|
// if we return 0, everything went fine
|
||||||
if (ret != EOPNOTSUPP) ec.assign(ret, get_posix_category());
|
// the fallocate call succeeded
|
||||||
// if fallocate failed, we have to use posix_fallocate
|
if (ret == 0) return true;
|
||||||
// which can be painfully slow, so only use it if we really
|
// otherwise, something went wrong. If the error
|
||||||
// have to
|
// is ENOSYS, just keep going and do it the old-fashioned
|
||||||
struct stat st;
|
// way. If fallocate failed with some other error, it
|
||||||
if (fstat(m_fd, &st) != 0)
|
// probably means the user should know about it, error out
|
||||||
|
// and report it.
|
||||||
|
if (errno != ENOSYS)
|
||||||
{
|
{
|
||||||
ec.assign(errno, get_posix_category());
|
ec.assign(ret, get_posix_category());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// if the number of allocated blocks already matches
|
// if fallocate failed, we have to use posix_fallocate
|
||||||
// the size of the file. No need to allocate it
|
// which can be painfully slow
|
||||||
if (st.st_blocks >= (s + st.st_blksize - 1) / st.st_blksize)
|
|
||||||
{
|
|
||||||
ec.clear();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ret = posix_fallocate(m_fd, 0, s);
|
ret = posix_fallocate(m_fd, 0, s);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -545,12 +545,11 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
ec.clear();
|
ec.clear();
|
||||||
boost::shared_ptr<file> f = open_file(*file_iter, file::read_write, ec);
|
boost::shared_ptr<file> f = open_file(*file_iter, file::read_write, ec);
|
||||||
std::string path = combine_path(m_save_path, file_iter->path);
|
if (ec) set_error(file_path, ec);
|
||||||
if (ec) set_error(path, ec);
|
|
||||||
else if (f)
|
else if (f)
|
||||||
{
|
{
|
||||||
f->set_size(file_iter->size, ec);
|
f->set_size(file_iter->size, ec);
|
||||||
if (ec) set_error(path, ec);
|
if (ec) set_error(file_path, ec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue