Detect FPU by checking CPUID features.
[dragonfly.git] / contrib / bind-9.5.2 / lib / isc / unix / file.c
1 /*
2  * Copyright (C) 2004, 2005, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000-2002  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 /*
19  * Portions Copyright (c) 1987, 1993
20  *      The Regents of the University of California.  All rights reserved.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the above copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  *    must display the following acknowledgement:
32  *      This product includes software developed by the University of
33  *      California, Berkeley and its contributors.
34  * 4. Neither the name of the University nor the names of its contributors
35  *    may be used to endorse or promote products derived from this software
36  *    without specific prior written permission.
37  *
38  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
39  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
42  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  */
50
51 /* $Id: file.c,v 1.51.128.2 2009/02/16 23:46:44 tbox Exp $ */
52
53 /*! \file */
54
55 #include <config.h>
56
57 #include <errno.h>
58 #include <fcntl.h>
59 #include <limits.h>
60 #include <stdlib.h>
61 #include <time.h>               /* Required for utimes on some platforms. */
62 #include <unistd.h>             /* Required for mkstemp on NetBSD. */
63
64
65 #include <sys/stat.h>
66 #include <sys/time.h>
67
68 #include <isc/dir.h>
69 #include <isc/file.h>
70 #include <isc/log.h>
71 #include <isc/random.h>
72 #include <isc/string.h>
73 #include <isc/time.h>
74 #include <isc/util.h>
75
76 #include "errno2result.h"
77
78 /*
79  * XXXDCL As the API for accessing file statistics undoubtedly gets expanded,
80  * it might be good to provide a mechanism that allows for the results
81  * of a previous stat() to be used again without having to do another stat,
82  * such as perl's mechanism of using "_" in place of a file name to indicate
83  * that the results of the last stat should be used.  But then you get into
84  * annoying MP issues.   BTW, Win32 has stat().
85  */
86 static isc_result_t
87 file_stats(const char *file, struct stat *stats) {
88         isc_result_t result = ISC_R_SUCCESS;
89
90         REQUIRE(file != NULL);
91         REQUIRE(stats != NULL);
92
93         if (stat(file, stats) != 0)
94                 result = isc__errno2result(errno);
95
96         return (result);
97 }
98
99 isc_result_t
100 isc_file_getmodtime(const char *file, isc_time_t *time) {
101         isc_result_t result;
102         struct stat stats;
103
104         REQUIRE(file != NULL);
105         REQUIRE(time != NULL);
106
107         result = file_stats(file, &stats);
108
109         if (result == ISC_R_SUCCESS)
110                 /*
111                  * XXXDCL some operating systems provide nanoseconds, too,
112                  * such as BSD/OS via st_mtimespec.
113                  */
114                 isc_time_set(time, stats.st_mtime, 0);
115
116         return (result);
117 }
118
119 isc_result_t
120 isc_file_settime(const char *file, isc_time_t *time) {
121         struct timeval times[2];
122
123         REQUIRE(file != NULL && time != NULL);
124
125         /*
126          * tv_sec is at least a 32 bit quantity on all platforms we're
127          * dealing with, but it is signed on most (all?) of them,
128          * so we need to make sure the high bit isn't set.  This unfortunately
129          * loses when either:
130          *   * tv_sec becomes a signed 64 bit integer but long is 32 bits
131          *      and isc_time_seconds > LONG_MAX, or
132          *   * isc_time_seconds is changed to be > 32 bits but long is 32 bits
133          *      and isc_time_seconds has at least 33 significant bits.
134          */
135         times[0].tv_sec = times[1].tv_sec = (long)isc_time_seconds(time);
136
137         /*
138          * Here is the real check for the high bit being set.
139          */
140         if ((times[0].tv_sec &
141              (1ULL << (sizeof(times[0].tv_sec) * CHAR_BIT - 1))) != 0)
142                 return (ISC_R_RANGE);
143
144         /*
145          * isc_time_nanoseconds guarantees a value that divided by 1000 will
146          * fit into the minimum possible size tv_usec field.  Unfortunately,
147          * we don't know what that type is so can't cast directly ... but
148          * we can at least cast to signed so the IRIX compiler shuts up.
149          */
150         times[0].tv_usec = times[1].tv_usec =
151                 (isc_int32_t)(isc_time_nanoseconds(time) / 1000);
152
153         if (utimes(file, times) < 0)
154                 return (isc__errno2result(errno));
155
156         return (ISC_R_SUCCESS);
157 }
158
159 #undef TEMPLATE
160 #define TEMPLATE "tmp-XXXXXXXXXX" /*%< 14 characters. */
161
162 isc_result_t
163 isc_file_mktemplate(const char *path, char *buf, size_t buflen) {
164         return (isc_file_template(path, TEMPLATE, buf, buflen));
165 }
166
167 isc_result_t
168 isc_file_template(const char *path, const char *templet, char *buf,
169                         size_t buflen) {
170         char *s;
171
172         REQUIRE(path != NULL);
173         REQUIRE(templet != NULL);
174         REQUIRE(buf != NULL);
175
176         s = strrchr(templet, '/');
177         if (s != NULL)
178                 templet = s + 1;
179
180         s = strrchr(path, '/');
181
182         if (s != NULL) {
183                 if ((s - path + 1 + strlen(templet) + 1) > buflen)
184                         return (ISC_R_NOSPACE);
185
186                 strncpy(buf, path, s - path + 1);
187                 buf[s - path + 1] = '\0';
188                 strcat(buf, templet);
189         } else {
190                 if ((strlen(templet) + 1) > buflen)
191                         return (ISC_R_NOSPACE);
192
193                 strcpy(buf, templet);
194         }
195
196         return (ISC_R_SUCCESS);
197 }
198
199 static char alphnum[] =
200         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
201
202 isc_result_t
203 isc_file_renameunique(const char *file, char *templet) {
204         char *x;
205         char *cp;
206         isc_uint32_t which;
207
208         REQUIRE(file != NULL);
209         REQUIRE(templet != NULL);
210
211         cp = templet;
212         while (*cp != '\0')
213                 cp++;
214         if (cp == templet)
215                 return (ISC_R_FAILURE);
216
217         x = cp--;
218         while (cp >= templet && *cp == 'X') {
219                 isc_random_get(&which);
220                 *cp = alphnum[which % (sizeof(alphnum) - 1)];
221                 x = cp--;
222         }
223         while (link(file, templet) == -1) {
224                 if (errno != EEXIST)
225                         return (isc__errno2result(errno));
226                 for (cp = x;;) {
227                         char *t;
228                         if (*cp == '\0')
229                                 return (ISC_R_FAILURE);
230                         t = strchr(alphnum, *cp);
231                         if (t == NULL || *++t == '\0')
232                                 *cp++ = alphnum[0];
233                         else {
234                                 *cp = *t;
235                                 break;
236                         }
237                 }
238         }
239         if (unlink(file) < 0)
240                 if (errno != ENOENT)
241                         return (isc__errno2result(errno));
242         return (ISC_R_SUCCESS);
243 }
244
245
246 isc_result_t
247 isc_file_openunique(char *templet, FILE **fp) {
248         int fd;
249         FILE *f;
250         isc_result_t result = ISC_R_SUCCESS;
251         char *x;
252         char *cp;
253         isc_uint32_t which;
254         int mode;
255
256         REQUIRE(templet != NULL);
257         REQUIRE(fp != NULL && *fp == NULL);
258
259         cp = templet;
260         while (*cp != '\0')
261                 cp++;
262         if (cp == templet)
263                 return (ISC_R_FAILURE);
264
265         x = cp--;
266         while (cp >= templet && *cp == 'X') {
267                 isc_random_get(&which);
268                 *cp = alphnum[which % (sizeof(alphnum) - 1)];
269                 x = cp--;
270         }
271
272         mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
273
274         while ((fd = open(templet, O_RDWR|O_CREAT|O_EXCL, mode)) == -1) {
275                 if (errno != EEXIST)
276                         return (isc__errno2result(errno));
277                 for (cp = x;;) {
278                         char *t;
279                         if (*cp == '\0')
280                                 return (ISC_R_FAILURE);
281                         t = strchr(alphnum, *cp);
282                         if (t == NULL || *++t == '\0')
283                                 *cp++ = alphnum[0];
284                         else {
285                                 *cp = *t;
286                                 break;
287                         }
288                 }
289         }
290         f = fdopen(fd, "w+");
291         if (f == NULL) {
292                 result = isc__errno2result(errno);
293                 if (remove(templet) < 0) {
294                         isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
295                                       ISC_LOGMODULE_FILE, ISC_LOG_ERROR,
296                                       "remove '%s': failed", templet);
297                 }
298                 (void)close(fd);
299         } else
300                 *fp = f;
301
302         return (result);
303 }
304
305 isc_result_t
306 isc_file_remove(const char *filename) {
307         int r;
308
309         REQUIRE(filename != NULL);
310
311         r = unlink(filename);
312         if (r == 0)
313                 return (ISC_R_SUCCESS);
314         else
315                 return (isc__errno2result(errno));
316 }
317
318 isc_result_t
319 isc_file_rename(const char *oldname, const char *newname) {
320         int r;
321
322         REQUIRE(oldname != NULL);
323         REQUIRE(newname != NULL);
324
325         r = rename(oldname, newname);
326         if (r == 0)
327                 return (ISC_R_SUCCESS);
328         else
329                 return (isc__errno2result(errno));
330 }
331
332 isc_boolean_t
333 isc_file_exists(const char *pathname) {
334         struct stat stats;
335
336         REQUIRE(pathname != NULL);
337
338         return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS));
339 }
340
341 isc_boolean_t
342 isc_file_isabsolute(const char *filename) {
343         REQUIRE(filename != NULL);
344         return (ISC_TF(filename[0] == '/'));
345 }
346
347 isc_boolean_t
348 isc_file_iscurrentdir(const char *filename) {
349         REQUIRE(filename != NULL);
350         return (ISC_TF(filename[0] == '.' && filename[1] == '\0'));
351 }
352
353 isc_boolean_t
354 isc_file_ischdiridempotent(const char *filename) {
355         REQUIRE(filename != NULL);
356         if (isc_file_isabsolute(filename))
357                 return (ISC_TRUE);
358         if (isc_file_iscurrentdir(filename))
359                 return (ISC_TRUE);
360         return (ISC_FALSE);
361 }
362
363 const char *
364 isc_file_basename(const char *filename) {
365         char *s;
366
367         REQUIRE(filename != NULL);
368
369         s = strrchr(filename, '/');
370         if (s == NULL)
371                 return (filename);
372
373         return (s + 1);
374 }
375
376 isc_result_t
377 isc_file_progname(const char *filename, char *buf, size_t buflen) {
378         const char *base;
379         size_t len;
380
381         REQUIRE(filename != NULL);
382         REQUIRE(buf != NULL);
383
384         base = isc_file_basename(filename);
385         len = strlen(base) + 1;
386
387         if (len > buflen)
388                 return (ISC_R_NOSPACE);
389         memcpy(buf, base, len);
390
391         return (ISC_R_SUCCESS);
392 }
393
394 /*
395  * Put the absolute name of the current directory into 'dirname', which is
396  * a buffer of at least 'length' characters.  End the string with the
397  * appropriate path separator, such that the final product could be
398  * concatenated with a relative pathname to make a valid pathname string.
399  */
400 static isc_result_t
401 dir_current(char *dirname, size_t length) {
402         char *cwd;
403         isc_result_t result = ISC_R_SUCCESS;
404
405         REQUIRE(dirname != NULL);
406         REQUIRE(length > 0U);
407
408         cwd = getcwd(dirname, length);
409
410         if (cwd == NULL) {
411                 if (errno == ERANGE)
412                         result = ISC_R_NOSPACE;
413                 else
414                         result = isc__errno2result(errno);
415         } else {
416                 if (strlen(dirname) + 1 == length)
417                         result = ISC_R_NOSPACE;
418                 else if (dirname[1] != '\0')
419                         strcat(dirname, "/");
420         }
421
422         return (result);
423 }
424
425 isc_result_t
426 isc_file_absolutepath(const char *filename, char *path, size_t pathlen) {
427         isc_result_t result;
428         result = dir_current(path, pathlen);
429         if (result != ISC_R_SUCCESS)
430                 return (result);
431         if (strlen(path) + strlen(filename) + 1 > pathlen)
432                 return (ISC_R_NOSPACE);
433         strcat(path, filename);
434         return (ISC_R_SUCCESS);
435 }
436
437 isc_result_t
438 isc_file_truncate(const char *filename, isc_offset_t size) {
439         isc_result_t result = ISC_R_SUCCESS;
440
441         if (truncate(filename, size) < 0)
442                 result = isc__errno2result(errno);
443         return (result);
444 }