File: quotas.c

package info (click to toggle)
pure-ftpd 1.0.47-3
  • links: PTS
  • area: main
  • in suites: buster
  • size: 3,212 kB
  • sloc: ansic: 29,132; sh: 1,632; makefile: 500; perl: 280
file content (165 lines) | stat: -rw-r--r-- 4,313 bytes parent folder | download | duplicates (5)
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
#include <config.h>

#ifdef QUOTAS
# include "ftpd.h"
# include "dynamic.h"
# include "ftpwho-update.h"
# include "globals.h"
# include "messages.h"
# include "quotas.h"
# include "safe_rw.h"

# ifdef WITH_DMALLOC
#  include <dmalloc.h>
# endif

int hasquota(void)
{
    if (guest != 0 ||
        (user_quota_files >= ULONG_LONG_MAX &&
         user_quota_size >= ULONG_LONG_MAX)) {
        return -1;
    }
    return 0;
}

int quota_update(Quota *quota,
                 const long long files_add,
                 const long long size_add,
                 int *overflow)
{
    int fd;
    Quota old_quota = { 0ULL, 0ULL };
    Quota dummy_quota;
    struct flock lock;
    ssize_t readnb;
    int err = -1;
    char buf[84];
    char *bufpnt = buf;
    int dummy_overflow;
    ssize_t left = (ssize_t) (sizeof buf - 1U);
    size_t buf_len;

    if (hasquota() != 0 || chrooted == 0) {
        return -2;
    }
    if (overflow == NULL) {
        overflow = &dummy_overflow;
    }
    if (quota == NULL) {
        quota = &dummy_quota;
    }
    *overflow = 0;
    *quota = old_quota;
    if ((fd = open("/" QUOTA_FILE, O_RDWR | O_CREAT | O_NOFOLLOW,
                   (mode_t) 0600)) == -1) {
        return -1;
    }
    lock.l_whence = SEEK_SET;
    lock.l_start = (off_t) 0;
    lock.l_len = (off_t) 0;
    lock.l_pid = getpid();
    lock.l_type = F_WRLCK;
    while (fcntl(fd, F_SETLKW, &lock) < 0) {
        if (errno != EINTR) {
            goto byenounlock;
        }
    }
    do {
        while ((readnb = read(fd, bufpnt, left)) < (ssize_t) 0 &&
               errno == EINTR);
        if (readnb < (ssize_t) 0) {
            goto bye;
        }
        bufpnt += readnb;
        left -= readnb;
    } while (left > (ssize_t) 0 && readnb != (ssize_t) 0);
    *bufpnt = 0;
    if ((bufpnt = strchr(buf, ' ')) == NULL) {
        goto skipparse;
    }
    *bufpnt = 0;
    old_quota.files = quota->files = strtoull(buf, NULL, 10);
    old_quota.size = quota->size = strtoull(bufpnt + 1, NULL, 10);
    skipparse:
    if ((files_add | size_add) == 0LL) {
        goto okbye;
    }
    if (files_add < 0LL) {
        if (quota->files > (unsigned long long) -files_add) {
            quota->files -= (unsigned long long) (-files_add);
        } else {
            quota->files = 0ULL;
        }
    } else if (files_add >= 0LL) {
        quota->files += (unsigned long long) files_add;
        if (quota->files > user_quota_files) {
            *overflow = 1;
        }
    }
    if (size_add < 0LL) {
        if (quota->size > (unsigned long long) -size_add) {
            quota->size -= (unsigned long long) (-size_add);
        } else {
            quota->size = 0ULL;
        }
    } else if (size_add >= 0LL) {
        quota->size += size_add;
        if (quota->size > user_quota_size) {
            *overflow = 2;
        }
    }
    if ((old_quota.size != quota->size || old_quota.files != quota->files) &&
        !SNCHECK(snprintf(buf, sizeof buf, "%llu %llu\n",
                          quota->files, quota->size), sizeof buf) &&
        lseek(fd, (off_t) 0, SEEK_SET) != (off_t) -1 &&
        ftruncate(fd, (off_t) 0) == 0) {

        buf_len = strlen(buf);
        if (safe_write(fd, buf, buf_len, -1) != (ssize_t) buf_len) {
            (void) ftruncate(fd, (off_t) 0);
            goto bye;
        }
    }
    okbye:
    err = 0;

    bye:
    lock.l_type = F_UNLCK;
    while (fcntl(fd, F_SETLK, &lock) < 0 && errno == EINTR);
    byenounlock:
    close(fd);

    return err;
}

void displayquota(Quota * const quota_)
{
    Quota quota;
    double pct;

    if (hasquota() != 0) {
        return;
    }
    if (quota_ == NULL) {
        if (quota_update(&quota, 0LL, 0LL, NULL) != 0) {
            return;
        }
    } else {
        quota = *quota_;
    }
    if (user_quota_files < ULONG_LONG_MAX) {
        pct = (double) quota.files * 100.0 / (double) user_quota_files;
        addreply(0, MSG_QUOTA_FILES, quota.files, (int) pct,
                 (unsigned long long) user_quota_files);
    }
    if (user_quota_size < ULONG_LONG_MAX) {
        pct = (double) quota.size * 100.0 / (double) user_quota_size;
        addreply(0, MSG_QUOTA_SIZE,
                 quota.size / 1024ULL, (int) pct,
                 (unsigned long long) user_quota_size / 1024ULL);
    }
}

#endif