Add total disk space to free-space RPC request (#1682)
* Add total space to free-space endpoint * Update docs
This commit is contained in:
parent
ab82e155be
commit
04f8b82308
|
@ -679,10 +679,11 @@
|
||||||
|
|
||||||
Response arguments:
|
Response arguments:
|
||||||
|
|
||||||
string | value type & description
|
string | value type & description
|
||||||
------------+----------------------------------------------------------
|
-------------+----------------------------------------------------------
|
||||||
"path" | string same as the Request argument
|
"path" | string same as the Request argument
|
||||||
"size-bytes"| number the size, in bytes, of the free space in that directory
|
"size-bytes" | number the size, in bytes, of the free space in that directory
|
||||||
|
"total_size" | number the total capacity, in bytes, of that directory
|
||||||
|
|
||||||
|
|
||||||
5.0. Protocol Versions
|
5.0. Protocol Versions
|
||||||
|
@ -854,6 +855,7 @@
|
||||||
| | | session-get | new arg "script-torrent-added-filename"
|
| | | session-get | new arg "script-torrent-added-filename"
|
||||||
| | | torrent-get | new arg "file-count"
|
| | | torrent-get | new arg "file-count"
|
||||||
| | | torrent-get | new arg "primary-mime-type"
|
| | | torrent-get | new arg "primary-mime-type"
|
||||||
|
| | | free-space | new return arg "total-capacity"
|
||||||
|
|
||||||
|
|
||||||
5.1. Upcoming Breakage
|
5.1. Upcoming Breakage
|
||||||
|
|
|
@ -268,11 +268,12 @@ extern "C"
|
||||||
#include <quota.h>
|
#include <quota.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t getquota(char const* device)
|
struct tr_disk_space getquota(char const* device)
|
||||||
{
|
{
|
||||||
struct quotahandle* qh;
|
struct quotahandle* qh;
|
||||||
struct quotakey qk;
|
struct quotakey qk;
|
||||||
struct quotaval qv;
|
struct quotaval qv;
|
||||||
|
struct tr_disk_space disk_space = { -1, -1 };
|
||||||
int64_t limit;
|
int64_t limit;
|
||||||
int64_t freespace;
|
int64_t freespace;
|
||||||
int64_t spaceused;
|
int64_t spaceused;
|
||||||
|
@ -281,7 +282,7 @@ static int64_t getquota(char const* device)
|
||||||
|
|
||||||
if (qh == nullptr)
|
if (qh == nullptr)
|
||||||
{
|
{
|
||||||
return -1;
|
return disk_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
qk.qk_idtype = QUOTA_IDTYPE_USER;
|
qk.qk_idtype = QUOTA_IDTYPE_USER;
|
||||||
|
@ -291,7 +292,7 @@ static int64_t getquota(char const* device)
|
||||||
if (quota_get(qh, &qk, &qv) == -1)
|
if (quota_get(qh, &qk, &qv) == -1)
|
||||||
{
|
{
|
||||||
quota_close(qh);
|
quota_close(qh);
|
||||||
return -1;
|
return disk_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qv.qv_softlimit > 0)
|
if (qv.qv_softlimit > 0)
|
||||||
|
@ -305,19 +306,21 @@ static int64_t getquota(char const* device)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
quota_close(qh);
|
quota_close(qh);
|
||||||
return -1;
|
return disk_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
spaceused = qv.qv_usage;
|
spaceused = qv.qv_usage;
|
||||||
quota_close(qh);
|
quota_close(qh);
|
||||||
|
|
||||||
freespace = limit - spaceused;
|
freespace = limit - spaceused;
|
||||||
return freespace < 0 ? 0 : freespace;
|
disk_space.free = freespace < 0 ? 0 : freespace;
|
||||||
|
disk_space.total = limit;
|
||||||
|
return disk_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static int64_t getquota(char const* device)
|
static struct tr_disk_space getquota(char const* device)
|
||||||
{
|
{
|
||||||
#if defined(__DragonFly__)
|
#if defined(__DragonFly__)
|
||||||
struct ufs_dqblk dq;
|
struct ufs_dqblk dq;
|
||||||
|
@ -326,12 +329,13 @@ static int64_t getquota(char const* device)
|
||||||
#endif
|
#endif
|
||||||
int64_t limit;
|
int64_t limit;
|
||||||
int64_t freespace;
|
int64_t freespace;
|
||||||
|
struct tr_disk_space disk_space = { -1, -1 };
|
||||||
int64_t spaceused;
|
int64_t spaceused;
|
||||||
|
|
||||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
|
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
|
||||||
if (quotactl(device, QCMD(Q_GETQUOTA, USRQUOTA), getuid(), (caddr_t)&dq) != 0)
|
if (quotactl(device, QCMD(Q_GETQUOTA, USRQUOTA), getuid(), (caddr_t)&dq) != 0)
|
||||||
{
|
{
|
||||||
return -1;
|
return disk_space;
|
||||||
}
|
}
|
||||||
#elif defined(__sun)
|
#elif defined(__sun)
|
||||||
struct quotctl op;
|
struct quotctl op;
|
||||||
|
@ -339,7 +343,7 @@ static int64_t getquota(char const* device)
|
||||||
|
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
return -1;
|
return disk_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
op.op = Q_GETQUOTA;
|
op.op = Q_GETQUOTA;
|
||||||
|
@ -349,14 +353,14 @@ static int64_t getquota(char const* device)
|
||||||
if (ioctl(fd, Q_QUOTACTL, &op) != 0)
|
if (ioctl(fd, Q_QUOTACTL, &op) != 0)
|
||||||
{
|
{
|
||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
return disk_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
#else
|
#else
|
||||||
if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device, getuid(), (caddr_t)&dq) != 0)
|
if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device, getuid(), (caddr_t)&dq) != 0)
|
||||||
{
|
{
|
||||||
return -1;
|
return disk_space;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -372,7 +376,7 @@ static int64_t getquota(char const* device)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* No quota enabled for this user */
|
/* No quota enabled for this user */
|
||||||
return -1;
|
return disk_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
||||||
|
@ -390,9 +394,13 @@ static int64_t getquota(char const* device)
|
||||||
freespace = limit - spaceused;
|
freespace = limit - spaceused;
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
return freespace < 0 ? 0 : freespace;
|
disk_space.free = freespace < 0 ? 0 : freespace;
|
||||||
|
disk_space.total = limit < 0 ? 0 : limit;
|
||||||
|
return disk_space;
|
||||||
#else
|
#else
|
||||||
return freespace < 0 ? 0 : (freespace * 1024);
|
disk_space.free = freespace < 0 ? 0 : (freespace * 1024);
|
||||||
|
disk_space.total = limit < 0 ? 0 : (limit * 1024);
|
||||||
|
return disk_space;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,10 +408,11 @@ static int64_t getquota(char const* device)
|
||||||
|
|
||||||
#ifdef HAVE_XQM
|
#ifdef HAVE_XQM
|
||||||
|
|
||||||
static int64_t getxfsquota(char* device)
|
static struct tr_disk_space getxfsquota(char* device)
|
||||||
{
|
{
|
||||||
int64_t limit;
|
int64_t limit;
|
||||||
int64_t freespace;
|
int64_t freespace;
|
||||||
|
struct tr_disk_space disk_space = { -1, -1 };
|
||||||
struct fs_disk_quota dq;
|
struct fs_disk_quota dq;
|
||||||
|
|
||||||
if (quotactl(QCMD(Q_XGETQUOTA, USRQUOTA), device, getuid(), (caddr_t)&dq) == 0)
|
if (quotactl(QCMD(Q_XGETQUOTA, USRQUOTA), device, getuid(), (caddr_t)&dq) == 0)
|
||||||
|
@ -420,24 +429,28 @@ static int64_t getxfsquota(char* device)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* No quota enabled for this user */
|
/* No quota enabled for this user */
|
||||||
return -1;
|
return disk_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
freespace = limit - (dq.d_bcount >> 1);
|
freespace = limit - (dq.d_bcount >> 1);
|
||||||
return freespace < 0 ? 0 : (freespace * 1024);
|
freespace = freespace < 0 ? 0 : (freespace * 1024);
|
||||||
|
limit = limit * 1024;
|
||||||
|
disk_space.free = freespace;
|
||||||
|
disk_space.total = limit;
|
||||||
|
return disk_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* something went wrong */
|
/* something went wrong */
|
||||||
return -1;
|
return disk_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* HAVE_XQM */
|
#endif /* HAVE_XQM */
|
||||||
|
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
static int64_t tr_getQuotaFreeSpace([[maybe_unused]] struct tr_device_info const* info)
|
static struct tr_disk_space tr_getQuotaSpace([[maybe_unused]] struct tr_device_info const* info)
|
||||||
{
|
{
|
||||||
int64_t ret = -1;
|
struct tr_disk_space ret = { -1, -1 };
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
|
||||||
|
@ -457,11 +470,11 @@ static int64_t tr_getQuotaFreeSpace([[maybe_unused]] struct tr_device_info const
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t tr_getDiskFreeSpace(char const* path)
|
static struct tr_disk_space tr_getDiskSpace(char const* path)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
int64_t ret = -1;
|
struct tr_disk_space ret = { -1, -1 };
|
||||||
wchar_t* wide_path;
|
wchar_t* wide_path;
|
||||||
|
|
||||||
wide_path = tr_win32_utf8_to_native(path, -1);
|
wide_path = tr_win32_utf8_to_native(path, -1);
|
||||||
|
@ -469,10 +482,12 @@ static int64_t tr_getDiskFreeSpace(char const* path)
|
||||||
if (wide_path != nullptr)
|
if (wide_path != nullptr)
|
||||||
{
|
{
|
||||||
ULARGE_INTEGER freeBytesAvailable;
|
ULARGE_INTEGER freeBytesAvailable;
|
||||||
|
ULARGE_INTEGER totalBytesAvailable;
|
||||||
|
|
||||||
if (GetDiskFreeSpaceExW(wide_path, &freeBytesAvailable, nullptr, nullptr))
|
if (GetDiskFreeSpaceExW(wide_path, &freeBytesAvailable, &totalBytesAvailable, nullptr))
|
||||||
{
|
{
|
||||||
ret = freeBytesAvailable.QuadPart;
|
ret.free = freeBytesAvailable.QuadPart;
|
||||||
|
ret.total = totalBytesAvailable.QuadPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr_free(wide_path);
|
tr_free(wide_path);
|
||||||
|
@ -483,13 +498,15 @@ static int64_t tr_getDiskFreeSpace(char const* path)
|
||||||
#elif defined(HAVE_STATVFS)
|
#elif defined(HAVE_STATVFS)
|
||||||
|
|
||||||
struct statvfs buf;
|
struct statvfs buf;
|
||||||
return statvfs(path, &buf) ? -1 : (int64_t)buf.f_bavail * (int64_t)buf.f_frsize;
|
return statvfs(path, &buf) ?
|
||||||
|
(struct tr_disk_space){ -1, -1 } :
|
||||||
|
(struct tr_disk_space){ (int64_t)buf.f_bavail * (int64_t)buf.f_frsize, (int64_t)buf.f_blocks * (int64_t)buf.f_frsize };
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#warning FIXME: not implemented
|
#warning FIXME: not implemented
|
||||||
|
|
||||||
return -1;
|
return { -1, -1 };
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -520,26 +537,27 @@ void tr_device_info_free(struct tr_device_info* info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t tr_device_info_get_free_space(struct tr_device_info const* info)
|
struct tr_disk_space tr_device_info_get_disk_space(struct tr_device_info const* info)
|
||||||
{
|
{
|
||||||
int64_t free_space;
|
struct tr_disk_space space;
|
||||||
|
|
||||||
if (info == nullptr || info->path == nullptr)
|
if (info == nullptr || info->path == nullptr)
|
||||||
{
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
free_space = -1;
|
space.free = -1;
|
||||||
|
space.total = -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
free_space = tr_getQuotaFreeSpace(info);
|
space = tr_getQuotaSpace(info);
|
||||||
|
|
||||||
if (free_space < 0)
|
if (space.free < 0 || space.total < 0)
|
||||||
{
|
{
|
||||||
free_space = tr_getDiskFreeSpace(info->path);
|
space = tr_getDiskSpace(info->path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return free_space;
|
return space;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
|
|
|
@ -24,11 +24,18 @@ struct tr_device_info
|
||||||
char* fstype;
|
char* fstype;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct tr_disk_space
|
||||||
|
{
|
||||||
|
int64_t free;
|
||||||
|
int64_t total;
|
||||||
|
};
|
||||||
|
|
||||||
struct tr_device_info* tr_device_info_create(char const* path);
|
struct tr_device_info* tr_device_info_create(char const* path);
|
||||||
|
|
||||||
/** If the disk quota is enabled and readable, this returns how much is available in the quota.
|
/** Values represents the total space on disk.
|
||||||
Otherwise, it returns how much is available on the disk, or -1 on error. */
|
If the disk quota (free space) is enabled and readable, this returns how much is available in the quota.
|
||||||
int64_t tr_device_info_get_free_space(struct tr_device_info const* info);
|
Otherwise, it returns how much is available on the disk, or { -1, -1 } on error. */
|
||||||
|
struct tr_disk_space tr_device_info_get_disk_space(struct tr_device_info const* info);
|
||||||
|
|
||||||
void tr_device_info_free(struct tr_device_info* info);
|
void tr_device_info_free(struct tr_device_info* info);
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#include "fdlimit.h"
|
#include "fdlimit.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "platform-quota.h" /* tr_device_info_get_free_space() */
|
#include "platform-quota.h" /* tr_device_info_get_disk_space() */
|
||||||
#include "rpcimpl.h"
|
#include "rpcimpl.h"
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
#include "session-id.h"
|
#include "session-id.h"
|
||||||
|
@ -2388,7 +2388,7 @@ static void addSessionField(tr_session* s, tr_variant* d, tr_quark key)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TR_KEY_download_dir_free_space:
|
case TR_KEY_download_dir_free_space:
|
||||||
tr_variantDictAddInt(d, key, tr_device_info_get_free_space(s->downloadDir));
|
tr_variantDictAddInt(d, key, tr_device_info_get_disk_space(s->downloadDir).free);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TR_KEY_download_queue_enabled:
|
case TR_KEY_download_queue_enabled:
|
||||||
|
@ -2627,7 +2627,7 @@ static char const* freeSpace(
|
||||||
int tmperr;
|
int tmperr;
|
||||||
char const* path = nullptr;
|
char const* path = nullptr;
|
||||||
char const* err = nullptr;
|
char const* err = nullptr;
|
||||||
int64_t free_space = -1;
|
struct tr_disk_space dir_space = { -1, -1 };
|
||||||
|
|
||||||
if (!tr_variantDictFindStr(args_in, TR_KEY_path, &path, nullptr))
|
if (!tr_variantDictFindStr(args_in, TR_KEY_path, &path, nullptr))
|
||||||
{
|
{
|
||||||
|
@ -2642,9 +2642,9 @@ static char const* freeSpace(
|
||||||
/* get the free space */
|
/* get the free space */
|
||||||
tmperr = errno;
|
tmperr = errno;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
free_space = tr_sessionGetDirFreeSpace(session, path);
|
dir_space = tr_getDirSpace(path);
|
||||||
|
|
||||||
if (free_space < 0)
|
if (dir_space.free < 0 || dir_space.total < 0)
|
||||||
{
|
{
|
||||||
err = tr_strerror(errno);
|
err = tr_strerror(errno);
|
||||||
}
|
}
|
||||||
|
@ -2657,7 +2657,8 @@ static char const* freeSpace(
|
||||||
tr_variantDictAddStr(args_out, TR_KEY_path, path);
|
tr_variantDictAddStr(args_out, TR_KEY_path, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
tr_variantDictAddInt(args_out, TR_KEY_size_bytes, free_space);
|
tr_variantDictAddInt(args_out, TR_KEY_size_bytes, dir_space.free);
|
||||||
|
tr_variantDictAddInt(args_out, TR_KEY_total_size, dir_space.total);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1232,11 +1232,11 @@ int64_t tr_sessionGetDirFreeSpace(tr_session* session, char const* dir)
|
||||||
|
|
||||||
if (tr_strcmp0(dir, tr_sessionGetDownloadDir(session)) == 0)
|
if (tr_strcmp0(dir, tr_sessionGetDownloadDir(session)) == 0)
|
||||||
{
|
{
|
||||||
free_space = tr_device_info_get_free_space(session->downloadDir);
|
free_space = tr_device_info_get_disk_space(session->downloadDir).free;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
free_space = tr_getDirFreeSpace(dir);
|
free_space = tr_getDirSpace(dir).free;
|
||||||
}
|
}
|
||||||
|
|
||||||
return free_space;
|
return free_space;
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
#include "mime-types.h"
|
#include "mime-types.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "platform.h" /* tr_lockLock() */
|
#include "platform.h" /* tr_lockLock() */
|
||||||
#include "platform-quota.h" /* tr_device_info_create(), tr_device_info_get_free_space(), tr_device_info_free() */
|
#include "platform-quota.h" /* tr_device_info_create(), tr_device_info_get_disk_space(), tr_device_info_free() */
|
||||||
#include "tr-assert.h"
|
#include "tr-assert.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "variant.h"
|
#include "variant.h"
|
||||||
|
@ -390,24 +390,21 @@ char* tr_buildPath(char const* first_element, ...)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t tr_getDirFreeSpace(char const* dir)
|
struct tr_disk_space tr_getDirSpace(char const* dir)
|
||||||
{
|
{
|
||||||
int64_t free_space;
|
struct tr_disk_space disk_space = { -1, -1 };
|
||||||
|
|
||||||
if (tr_str_is_empty(dir))
|
if (tr_str_is_empty(dir))
|
||||||
{
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
free_space = -1;
|
return disk_space;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
struct tr_device_info* info;
|
|
||||||
info = tr_device_info_create(dir);
|
|
||||||
free_space = tr_device_info_get_free_space(info);
|
|
||||||
tr_device_info_free(info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return free_space;
|
struct tr_device_info* info;
|
||||||
|
info = tr_device_info_create(dir);
|
||||||
|
disk_space = tr_device_info_get_disk_space(info);
|
||||||
|
tr_device_info_free(info);
|
||||||
|
return disk_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****
|
/****
|
||||||
|
|
|
@ -27,6 +27,8 @@ struct timeval;
|
||||||
|
|
||||||
struct tr_error;
|
struct tr_error;
|
||||||
|
|
||||||
|
struct tr_disk_space;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup utils Utilities
|
* @addtogroup utils Utilities
|
||||||
* @{
|
* @{
|
||||||
|
@ -79,10 +81,10 @@ uint8_t* tr_loadFile(char const* filename, size_t* size, struct tr_error** error
|
||||||
char* tr_buildPath(char const* first_element, ...) TR_GNUC_NULL_TERMINATED TR_GNUC_MALLOC;
|
char* tr_buildPath(char const* first_element, ...) TR_GNUC_NULL_TERMINATED TR_GNUC_MALLOC;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get available disk space (in bytes) for the specified folder.
|
* @brief Get disk capacity and free disk space (in bytes) for the specified folder.
|
||||||
* @return zero or positive integer on success, -1 in case of error.
|
* @return struct with free and total as zero or positive integer on success, -1 in case of error.
|
||||||
*/
|
*/
|
||||||
int64_t tr_getDirFreeSpace(char const* path);
|
struct tr_disk_space tr_getDirSpace(char const* path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convenience wrapper around timer_add() to have a timer wake up in a number of seconds and microseconds
|
* @brief Convenience wrapper around timer_add() to have a timer wake up in a number of seconds and microseconds
|
||||||
|
|
Loading…
Reference in New Issue