source: trunk/libtransmission/platform-quota.c @ 14382

Last change on this file since 14382 was 14382, checked in by mikedld, 8 years ago

Fix compilation on Windows

This should not affect non-Win32 platforms in any way.
As for Win32 (both MinGW and MSVC), this should hopefully allow for
unpatched compilation. Correct functioning is not yet guaranteed though.

  • Property svn:keywords set to Date Rev Author Id
File size: 8.4 KB
Line 
1/*
2 * This file Copyright (C) 2013-2014 Mnemosyne LLC
3 *
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
6 *
7 * $Id: platform-quota.c 14382 2014-12-13 15:22:39Z mikedld $
8 */
9
10#include <errno.h>
11#include <stdlib.h>
12#include <string.h>
13
14#include <event2/util.h> /* evutil_ascii_strcasecmp () */
15
16#ifndef _WIN32
17 #include <unistd.h> /* getuid() */
18 #include <sys/types.h> /* types needed by quota.h */
19 #if defined(__FreeBSD__) || defined(__OpenBSD__)
20  #include <ufs/ufs/quota.h> /* quotactl() */
21 #elif defined (__NetBSD__)
22  #include <sys/param.h>
23  #ifndef statfs
24   #define statfs statvfs
25  #endif
26 #elif defined (__sun)
27  #include <sys/fs/ufs_quota.h> /* quotactl */
28 #else
29  #include <sys/quota.h> /* quotactl() */
30 #endif
31 #ifdef HAVE_GETMNTENT
32  #ifdef __sun
33   #include <fcntl.h>
34   #include <stdio.h>
35   #include <sys/mntent.h>
36   #include <sys/mnttab.h>
37   #define _PATH_MOUNTED MNTTAB
38  #else
39   #include <mntent.h>
40   #include <paths.h> /* _PATH_MOUNTED */
41  #endif
42 #else /* BSD derived systems */
43  #include <sys/param.h>
44  #include <sys/ucred.h>
45  #include <sys/mount.h>
46 #endif
47#endif
48
49#ifdef __APPLE__
50 #ifndef HAVE_SYS_STATVFS_H
51  #define HAVE_SYS_STATVFS_H
52 #endif
53 #ifndef HAVE_STATVFS
54  #define HAVE_STATVFS
55 #endif
56#endif
57
58#ifdef HAVE_SYS_STATVFS_H
59 #include <sys/statvfs.h>
60#endif
61
62#ifdef HAVE_XFS_XFS_H
63 #define HAVE_XQM
64 #include <xfs/xqm.h>
65#endif
66
67#include "transmission.h"
68#include "utils.h"
69#include "platform-quota.h"
70
71/***
72****
73***/
74
75#ifndef _WIN32
76static const char *
77getdev (const char * path)
78{
79#ifdef HAVE_GETMNTENT
80
81  FILE * fp;
82
83#ifdef __sun
84  struct mnttab mnt;
85  fp = fopen(_PATH_MOUNTED, "r");
86  if (fp == NULL)
87    return NULL;
88
89  while (getmntent(fp, &mnt))
90    if (!tr_strcmp0 (path, mnt.mnt_mountp))
91      break;
92  fclose(fp);
93  return mnt.mnt_special;
94#else
95  struct mntent * mnt;
96
97  fp = setmntent(_PATH_MOUNTED, "r");
98  if (fp == NULL)
99    return NULL;
100
101  while ((mnt = getmntent(fp)) != NULL)
102    if (!tr_strcmp0 (path, mnt->mnt_dir))
103      break;
104
105  endmntent(fp);
106  return mnt ? mnt->mnt_fsname : NULL;
107#endif
108#else /* BSD derived systems */
109
110  int i;
111  int n;
112  struct statfs * mnt;
113
114  n = getmntinfo(&mnt, MNT_WAIT);
115  if (!n)
116    return NULL;
117
118  for (i=0; i<n; i++)
119    if (!tr_strcmp0 (path, mnt[i].f_mntonname))
120      break;
121
122  return (i < n) ? mnt[i].f_mntfromname : NULL;
123
124#endif
125}
126
127static const char *
128getfstype (const char * device)
129{
130
131#ifdef HAVE_GETMNTENT
132
133  FILE * fp;
134#ifdef __sun
135  struct mnttab mnt;
136  fp = fopen(_PATH_MOUNTED, "r");
137  if (fp == NULL)
138    return NULL;
139  while (getmntent(fp, &mnt))
140    if (!tr_strcmp0 (device, mnt.mnt_mountp))
141      break;
142  fclose(fp);
143  return mnt.mnt_fstype;
144#else
145  struct mntent *mnt;
146
147  fp = setmntent (_PATH_MOUNTED, "r");
148  if (fp == NULL)
149    return NULL;
150
151  while ((mnt = getmntent (fp)) != NULL)
152    if (!tr_strcmp0 (device, mnt->mnt_fsname))
153      break;
154
155  endmntent(fp);
156  return mnt ? mnt->mnt_type : NULL;
157#endif
158#else /* BSD derived systems */
159
160  int i;
161  int n;
162  struct statfs *mnt;
163
164  n = getmntinfo(&mnt, MNT_WAIT);
165  if (!n)
166    return NULL;
167
168  for (i=0; i<n; i++)
169    if (!tr_strcmp0 (device, mnt[i].f_mntfromname))
170      break;
171
172  return (i < n) ? mnt[i].f_fstypename : NULL;
173
174#endif
175}
176
177static const char *
178getblkdev (const char * path)
179{
180  char * c;
181  char * dir;
182  const char * device;
183
184  dir = tr_strdup(path);
185
186  for (;;)
187    {
188      device = getdev (dir);
189      if (device != NULL)
190        break;
191
192      c = strrchr (dir, '/');
193      if (c != NULL)
194        *c = '\0';
195      else
196         break;
197    }
198
199  tr_free (dir);
200  return device;
201}
202
203#if defined(__NetBSD__) && (__NetBSD_Version__ >= 600000000)
204#include <quota.h>
205
206static int64_t
207getquota (const char * device)
208{
209  struct quotahandle *qh;
210  struct quotakey qk;
211  struct quotaval qv;
212  int64_t limit;
213  int64_t freespace;
214  int64_t spaceused;
215
216  qh = quota_open(device);
217  if (qh == NULL) {
218    return -1;
219  }
220  qk.qk_idtype = QUOTA_IDTYPE_USER;
221  qk.qk_id = getuid();
222  qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
223  if (quota_get(qh, &qk, &qv) == -1) {
224    quota_close(qh);
225    return -1;
226  }
227  if (qv.qv_softlimit > 0) {
228    limit = qv.qv_softlimit;
229  }
230  else if (qv.qv_hardlimit > 0) {
231    limit = qv.qv_hardlimit;
232  }
233  else {
234    quota_close(qh);
235    return -1;
236  }
237  spaceused = qv.qv_usage;
238  quota_close(qh);
239
240  freespace = limit - spaceused;
241  return (freespace < 0) ? 0 : freespace;
242}
243#else
244static int64_t
245getquota (const char * device)
246{
247  struct dqblk dq;
248  int64_t limit;
249  int64_t freespace;
250  int64_t spaceused;
251
252#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
253  if (quotactl(device, QCMD(Q_GETQUOTA, USRQUOTA), getuid(), (caddr_t) &dq) == 0)
254    {
255#elif defined(__sun)
256  struct quotctl  op; 
257  int fd = open(device, O_RDONLY); 
258  if (fd < 0) 
259    return -1; 
260  op.op = Q_GETQUOTA; 
261  op.uid = getuid(); 
262  op.addr = (caddr_t) &dq; 
263  if (ioctl(fd, Q_QUOTACTL, &op) == 0)
264    {
265      close(fd);
266#else
267  if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device, getuid(), (caddr_t) &dq) == 0)
268    {
269#endif
270      if (dq.dqb_bsoftlimit > 0)
271        {
272          /* Use soft limit first */
273          limit = dq.dqb_bsoftlimit;
274        }
275      else if (dq.dqb_bhardlimit > 0)
276        {
277          limit = dq.dqb_bhardlimit;
278        }
279      else
280        {
281          /* No quota enabled for this user */
282          return -1;
283        }
284#if defined(__FreeBSD__) || defined(__OpenBSD__)
285      spaceused = (int64_t) dq.dqb_curblocks >> 1;
286#elif defined(__APPLE__)
287      spaceused = (int64_t) dq.dqb_curbytes;
288#elif defined(__UCLIBC__)
289      spaceused = (int64_t) btodb(dq.dqb_curblocks);
290#elif defined(__sun) || (defined(_LINUX_QUOTA_VERSION) && _LINUX_QUOTA_VERSION < 2)
291      spaceused = (int64_t) dq.dqb_curblocks >> 1;
292#else
293      spaceused = btodb(dq.dqb_curspace);
294#endif
295      freespace = limit - spaceused;
296#ifdef __APPLE__
297      return (freespace < 0) ? 0 : freespace;
298#else
299      return (freespace < 0) ? 0 : freespace * 1024;
300#endif
301    }
302#if defined(__sun)
303  close(fd);
304#endif
305  /* something went wrong */
306  return -1;
307}
308#endif
309
310#ifdef HAVE_XQM
311static int64_t
312getxfsquota (char * device)
313{
314  int64_t limit;
315  int64_t freespace;
316  struct fs_disk_quota dq;
317
318  if (quotactl(QCMD(Q_XGETQUOTA, USRQUOTA), device, getuid(), (caddr_t) &dq) == 0)
319    {
320      if (dq.d_blk_softlimit > 0)
321        {
322          /* Use soft limit first */
323          limit = dq.d_blk_softlimit >> 1;
324        }
325      else if (dq.d_blk_hardlimit > 0)
326        {
327          limit = dq.d_blk_hardlimit >> 1;
328        }
329      else
330        {
331          /* No quota enabled for this user */
332          return -1;
333        }
334
335      freespace = limit - (dq.d_bcount >> 1);
336      return (freespace < 0) ? 0 : freespace * 1024;
337    }
338
339  /* something went wrong */
340  return -1;
341}
342#endif /* HAVE_XQM */
343#endif /* _WIN32 */
344
345static int64_t
346tr_getQuotaFreeSpace (const struct tr_device_info * info)
347{
348  int64_t ret = -1;
349
350#ifndef _WIN32
351
352  if (info->fstype && !evutil_ascii_strcasecmp(info->fstype, "xfs"))
353    {
354#ifdef HAVE_XQM
355      ret = getxfsquota (info->device);
356#endif
357    }
358  else
359    {
360      ret = getquota (info->device);
361    }
362#endif /* _WIN32 */
363
364  return ret;
365}
366
367static int64_t
368tr_getDiskFreeSpace (const char * path)
369{
370#ifdef _WIN32
371
372  int64_t ret = -1;
373  wchar_t * wide_path;
374
375  wide_path = tr_win32_utf8_to_native (path, -1);
376
377  if (wide_path != NULL)
378    {
379      ULARGE_INTEGER freeBytesAvailable;
380      if (GetDiskFreeSpaceExW (wide_path, &freeBytesAvailable, NULL, NULL))
381        ret = freeBytesAvailable.QuadPart;
382
383      tr_free (wide_path);
384    }
385
386  return ret;
387
388#elif defined(HAVE_STATVFS)
389
390  struct statvfs buf;
391  return statvfs(path, &buf) ? -1 : (int64_t)buf.f_bavail * (int64_t)buf.f_frsize;
392
393#else
394
395  #warning FIXME: not implemented
396  return -1;
397
398#endif
399}
400
401struct tr_device_info *
402tr_device_info_create (const char * path)
403{
404  struct tr_device_info * info;
405
406  info = tr_new0 (struct tr_device_info, 1);
407  info->path = tr_strdup (path);
408#ifndef _WIN32
409  info->device = tr_strdup (getblkdev (path));
410  info->fstype = tr_strdup (getfstype (path));
411#endif
412
413  return info;
414}
415
416void
417tr_device_info_free (struct tr_device_info * info)
418{
419  if (info != NULL)
420    {
421      tr_free (info->fstype);
422      tr_free (info->device);
423      tr_free (info->path);
424      tr_free (info);
425    }
426}
427
428int64_t
429tr_device_info_get_free_space (const struct tr_device_info * info)
430{
431  int64_t free_space;
432
433  if ((info == NULL) || (info->path == NULL))
434    {
435      errno = EINVAL;
436      free_space = -1;
437    }
438  else
439    {
440      free_space = tr_getQuotaFreeSpace (info);
441
442      if (free_space < 0)
443        free_space = tr_getDiskFreeSpace (info->path);
444    }
445
446  return free_space;
447}
448
449/***
450****
451***/
Note: See TracBrowser for help on using the repository browser.