Coverage Report

Created: 2023-05-19 06:16

/src/ntp-dev/lib/isc/unix/dir.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2004, 2005, 2007-2009, 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
3
 * Copyright (C) 1999-2001  Internet Software Consortium.
4
 *
5
 * Permission to use, copy, modify, and/or distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
 * PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
/* $Id$ */
19
20
/*! \file
21
 * \author  Principal Authors: DCL */
22
23
#include <config.h>
24
25
#include <sys/types.h>
26
#include <sys/stat.h>
27
28
#include <ctype.h>
29
#include <errno.h>
30
#include <unistd.h>
31
32
#include <isc/dir.h>
33
#include <isc/magic.h>
34
#include <isc/string.h>
35
#include <isc/util.h>
36
37
#include "errno2result.h"
38
#include "ntp_stdlib.h"   /* NTP change for strlcpy, strlcat */
39
40
0
#define ISC_DIR_MAGIC   ISC_MAGIC('D', 'I', 'R', '*')
41
#define VALID_DIR(dir)    ISC_MAGIC_VALID(dir, ISC_DIR_MAGIC)
42
43
void
44
0
isc_dir_init(isc_dir_t *dir) {
45
0
  REQUIRE(dir != NULL);
46
47
0
  dir->entry.name[0] = '\0';
48
0
  dir->entry.length = 0;
49
50
0
  dir->handle = NULL;
51
52
0
  dir->magic = ISC_DIR_MAGIC;
53
0
}
54
55
/*!
56
 * \brief Allocate workspace and open directory stream. If either one fails,
57
 * NULL will be returned.
58
 */
59
isc_result_t
60
0
isc_dir_open(isc_dir_t *dir, const char *dirname) {
61
0
  char *p;
62
0
  size_t octets;
63
0
  isc_result_t result = ISC_R_SUCCESS;
64
65
0
  REQUIRE(VALID_DIR(dir));
66
0
  REQUIRE(dirname != NULL);
67
68
  /*
69
   * Copy directory name.  Need to have enough space for the name,
70
   * a possible path separator, the wildcard, and the final NUL.
71
   */
72
0
  octets = strlen(dirname) + 1;
73
0
  if (octets + 2 > sizeof(dir->dirname))
74
    /* XXXDCL ? */
75
0
    return (ISC_R_NOSPACE);
76
0
  strlcpy(dir->dirname, dirname, octets);
77
78
  /*
79
   * Append path separator, if needed, and "*".
80
   */
81
0
  p = dir->dirname + strlen(dir->dirname);
82
0
  if (dir->dirname < p && *(p - 1) != '/')
83
0
    *p++ = '/';
84
0
  *p++ = '*';
85
0
  *p = '\0';
86
87
  /*
88
   * Open stream.
89
   */
90
0
  dir->handle = opendir(dirname);
91
92
0
  if (dir->handle == NULL)
93
0
    return isc__errno2result(errno);
94
95
0
  return (result);
96
0
}
97
98
/*!
99
 * \brief Return previously retrieved file or get next one.
100
101
 * Unix's dirent has
102
 * separate open and read functions, but the Win32 and DOS interfaces open
103
 * the dir stream and reads the first file in one operation.
104
 */
105
isc_result_t
106
0
isc_dir_read(isc_dir_t *dir) {
107
0
  struct dirent *entry;
108
0
  size_t octets;
109
110
0
  REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
111
112
  /*
113
   * Fetch next file in directory.
114
   */
115
0
  entry = readdir(dir->handle);
116
117
0
  if (entry == NULL)
118
0
    return (ISC_R_NOMORE);
119
120
  /*
121
   * Make sure that the space for the name is long enough.
122
   */
123
0
  octets = strlen(entry->d_name) + 1;
124
0
  if (sizeof(dir->entry.name) < octets)
125
0
    return (ISC_R_UNEXPECTED);
126
127
0
  strlcpy(dir->entry.name, entry->d_name, octets);
128
129
  /*
130
   * Some dirents have d_namlen, but it is not portable.
131
   */
132
0
  dir->entry.length = strlen(entry->d_name);
133
134
0
  return (ISC_R_SUCCESS);
135
0
}
136
137
/*!
138
 * \brief Close directory stream.
139
 */
140
void
141
0
isc_dir_close(isc_dir_t *dir) {
142
0
       REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
143
144
0
       (void)closedir(dir->handle);
145
0
       dir->handle = NULL;
146
0
}
147
148
/*!
149
 * \brief Reposition directory stream at start.
150
 */
151
isc_result_t
152
0
isc_dir_reset(isc_dir_t *dir) {
153
0
  REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
154
155
0
  rewinddir(dir->handle);
156
157
0
  return (ISC_R_SUCCESS);
158
0
}
159
160
isc_result_t
161
0
isc_dir_chdir(const char *dirname) {
162
  /*!
163
   * \brief Change the current directory to 'dirname'.
164
   */
165
166
0
  REQUIRE(dirname != NULL);
167
168
0
  if (chdir(dirname) < 0)
169
0
    return (isc__errno2result(errno));
170
171
0
  return (ISC_R_SUCCESS);
172
0
}
173
174
isc_result_t
175
0
isc_dir_chroot(const char *dirname) {
176
177
0
  REQUIRE(dirname != NULL);
178
179
#ifdef HAVE_CHROOT
180
  if (chroot(dirname) < 0 || chdir("/") < 0)
181
    return (isc__errno2result(errno));
182
183
  return (ISC_R_SUCCESS);
184
#else
185
0
  return (ISC_R_NOTIMPLEMENTED);
186
0
#endif
187
0
}
188
189
isc_result_t
190
0
isc_dir_createunique(char *templet) {
191
0
  isc_result_t result;
192
0
  char *x;
193
0
  char *p;
194
0
  int i;
195
0
  int pid;
196
197
0
  REQUIRE(templet != NULL);
198
199
  /*!
200
   * \brief mkdtemp is not portable, so this emulates it.
201
   */
202
203
0
  pid = getpid();
204
205
  /*
206
   * Replace trailing Xs with the process-id, zero-filled.
207
   */
208
0
  for (x = templet + strlen(templet) - 1; *x == 'X' && x >= templet;
209
0
       x--, pid /= 10)
210
0
    *x = pid % 10 + '0';
211
212
0
  x++;      /* Set x to start of ex-Xs. */
213
214
0
  do {
215
0
    i = mkdir(templet, 0700);
216
0
    if (i == 0 || errno != EEXIST)
217
0
      break;
218
219
    /*
220
     * The BSD algorithm.
221
     */
222
0
    p = x;
223
0
    while (*p != '\0') {
224
0
      if (isdigit(*p & 0xff))
225
0
        *p = 'a';
226
0
      else if (*p != 'z')
227
0
        ++*p;
228
0
      else {
229
        /*
230
         * Reset character and move to next.
231
         */
232
0
        *p++ = 'a';
233
0
        continue;
234
0
      }
235
236
0
      break;
237
0
    }
238
239
0
    if (*p == '\0') {
240
      /*
241
       * Tried all combinations.  errno should already
242
       * be EEXIST, but ensure it is anyway for
243
       * isc__errno2result().
244
       */
245
0
      errno = EEXIST;
246
0
      break;
247
0
    }
248
0
  } while (1);
249
250
0
  if (i == -1)
251
0
    result = isc__errno2result(errno);
252
0
  else
253
0
    result = ISC_R_SUCCESS;
254
255
0
  return (result);
256
0
}