• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

proftpd / proftpd / 26127302613

19 May 2026 09:51PM UTC coverage: 93.024% (+0.4%) from 92.635%
26127302613

push

github

51329 of 55178 relevant lines covered (93.02%)

215.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.94
/src/sets.c
1
/*
2
 * ProFTPD - FTP server daemon
3
 * Copyright (c) 1997, 1998 Public Flood Software
4
 * Copyright (c) 2001-2026 The ProFTPD Project team
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
18
 *
19
 * As a special exemption, Public Flood Software/MacGyver aka Habeeb J. Dihu
20
 * and other respective copyright holders give permission to link this program
21
 * with OpenSSL, and distribute the resulting executable, without including
22
 * the source code for OpenSSL in the source distribution.
23
 */
24

25
/* Generic set manipulation */
26

27
#include "conf.h"
28

29
/* Create a new set, cmpfunc is a pointer to the function used to to compare
30
 * members of the set ... it should return 1, 0, or -1 after the fashion of
31
 * strcmp.  Returns NULL if memory allocation fails.
32
 */
33

34
xaset_t *xaset_create(pool *p, XASET_COMPARE cmpfunc) {
35
  xaset_t *new_set;
671✔
36

671✔
37
  if (p == NULL &&
38
      permanent_pool == NULL) {
671✔
39
    errno = EPERM;
8✔
40
    return NULL;
1✔
41
  }
1✔
42

43
  p = p ? p : permanent_pool;
44

670✔
45
  new_set = palloc(p, sizeof(xaset_t));
46
  if (new_set == NULL) {
670✔
47
    return NULL;
670✔
48
  }
49

50
  new_set->xas_list = NULL;
51
  new_set->pool = p;
670✔
52
  new_set->xas_compare = cmpfunc;
670✔
53

670✔
54
  return new_set;
55
}
670✔
56

57
/* Inserts a new member into an existing set.  The member is inserted
58
 * at the beginning of the set.  Returns 0 if successful, -1 otherwise (with
59
 * errno set appropriately).
60
 */
61
int xaset_insert(xaset_t *set, xasetmember_t *member) {
62
  if (set == NULL ||
57✔
63
      member == NULL) {
57✔
64
    errno = EINVAL;
57✔
65
    return -1;
3✔
66
  }
3✔
67

68
  member->next = set->xas_list;
69

54✔
70
  if (set->xas_list != NULL) {
71
    set->xas_list->prev = member;
54✔
72
  }
5✔
73

74
  set->xas_list = member;
75
  return 0;
54✔
76
}
54✔
77

78
/* Inserts a new member into an existing set at the end of the list.
79
 */
80
int xaset_insert_end(xaset_t *set, xasetmember_t *member) {
81
  xasetmember_t **tmp, *prev = NULL;
192✔
82

192✔
83
  if (set == NULL ||
84
      member == NULL) {
192✔
85
    errno = EINVAL;
192✔
86
    return -1;
14✔
87
  }
14✔
88

89
  for (tmp = &set->xas_list; *tmp; prev = *tmp, tmp = &(*tmp)->next) {
90
  }
360✔
91

182✔
92
  *tmp = member;
93
  member->prev = prev;
178✔
94
  member->next = NULL;
178✔
95

178✔
96
  if (prev != NULL) {
97
    prev->next = member;
178✔
98
  }
95✔
99

100
  return 0;
101
}
102

103
/* Inserts a new member into an existing set, sorted using the set's compare
104
 * callback.  If dups_allowed is non-0, returns 0 and the member is not added
105
 * to the set.  Otherwise, it is added immediately before the first duplicate.
106
 * If the set is not empty and not pre-sorted, results are undefined.
107
 * Returns 0 if successful, -1 otherwise (with errno set appropriately).
108
 */
109
int xaset_insert_sort(xaset_t *set, xasetmember_t *member, int dups_allowed) {
110
  xasetmember_t **setp = NULL, *mprev = NULL;
101✔
111

101✔
112
  if (set == NULL ||
113
      member == NULL ||
101✔
114
      set->xas_compare == NULL) {
101✔
115
    errno = EINVAL;
98✔
116
    return -1;
4✔
117
  }
4✔
118

119
  for (setp = &set->xas_list; *setp; setp = &(*setp)->next) {
120
    int res;
97✔
121

16✔
122
    res = set->xas_compare(member, *setp);
123
    if (res <= 0) {
16✔
124
      if (res == 0 &&
16✔
125
          !dups_allowed) {
16✔
126
        return 0;
127
      }
128

129
      break;
130
    }
131

132
    mprev = *setp;
133
  }
×
134

135
  if (*setp) {
136
    (*setp)->prev = member;
96✔
137
  }
15✔
138

139
  member->prev = mprev;
140
  member->next = *setp;
96✔
141
  *setp = member;
96✔
142

96✔
143
  return 0;
144
}
96✔
145

146
/* Remove a member from a set.  The set need not be sorted.  Note that this
147
 * does NOT free the memory used by the member.  Returns 0 if successful,
148
 * and -1 if there was a problem (with errno set appropriately).
149
 */
150
int xaset_remove(xaset_t *set, xasetmember_t *member) {
151
  xasetmember_t *m = NULL;
145✔
152

145✔
153
  if (set == NULL ||
154
      member == NULL) {
145✔
155
    errno = EINVAL;
145✔
156
    return -1;
4✔
157
  }
4✔
158

159
  /* Check if member is actually a member of set. */
160
  for (m = set->xas_list; m; m = m->next) {
161
    if (m == member) {
170✔
162
      break;
169✔
163
    }
164
  }
165

166
  if (m == NULL) {
167
    errno = ENOENT;
141✔
168
    return -1;
1✔
169
  }
1✔
170

171
  if (member->prev != NULL) {
172
    member->prev->next = member->next;
140✔
173

19✔
174
  } else { /* assume that member is first in the list */
175
    set->xas_list = member->next;
176
  }
121✔
177

178
  if (member->next != NULL) {
179
    member->next->prev = member->prev;
140✔
180
  }
23✔
181

182
  member->next = member->prev = NULL;
183
  return 0;
140✔
184
}
140✔
185

186
/* Perform an exact copy of the entire set, returning the new set.  msize
187
 * specifies the size of each member.  If copyfunc is non-NULL, it is called
188
 * instead to copy each member.  Returns NULL if out of memory condition
189
 * occurs.
190
 */
191
xaset_t *xaset_copy(pool *p, xaset_t *set, size_t msize, XASET_MCOPY copyfunc) {
192
  xaset_t *new_set;
4✔
193
  xasetmember_t *n, *m, **pos;
4✔
194

4✔
195
  if (set == NULL) {
196
    errno = EINVAL;
4✔
197
    return NULL;
1✔
198
  }
1✔
199

200
  if (copyfunc == NULL &&
201
      msize == 0) {
3✔
202
    errno = EINVAL;
3✔
203
    return NULL;
1✔
204
  }
1✔
205

206
  p = (p ? p : set->pool);
207

2✔
208
  new_set = xaset_create(p, set->xas_compare);
209
  if (new_set == NULL) {
2✔
210
    return NULL;
2✔
211
  }
212

213
  pos = &new_set->xas_list;
214

2✔
215
  /* NOTE: xaset_insert_sort is not used here for performance reasons. */
216

217
  for (m = set->xas_list; m; m = m->next) {
218
    n = copyfunc ? copyfunc(m) : (xasetmember_t *) palloc(p, msize);
4✔
219
    if (n == NULL) {
2✔
220
      /* Note that we could clean up here. */
2✔
221
      return NULL;
222
    }
223

224
    if (copyfunc == NULL) {
225
      memcpy(n, m, msize);
2✔
226
    }
1✔
227

228
    /* Create links */
229
    n->prev = *pos;
230
    n->next = NULL;
2✔
231
    if (*pos) {
2✔
232
      pos = &(*pos)->next;
2✔
233
    }
×
234

235
    *pos = n;
236
  }
2✔
237

238
  return new_set;
239
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc