Detect FPU by checking CPUID features.
[dragonfly.git] / contrib / bind-9.5.2 / lib / isc / unix / file.c
blobd91a1c407ac6dd19772d3aa35c546322874d426b
1 /*
2 * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2002 Internet Software Consortium.
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.
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.
19 * Portions Copyright (c) 1987, 1993
20 * The Regents of the University of California. All rights reserved.
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.
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.
51 /* $Id: file.c,v 1.51.128.2 2009/02/16 23:46:44 tbox Exp $ */
53 /*! \file */
55 #include <config.h>
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. */
65 #include <sys/stat.h>
66 #include <sys/time.h>
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>
76 #include "errno2result.h"
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().
86 static isc_result_t
87 file_stats(const char *file, struct stat *stats) {
88 isc_result_t result = ISC_R_SUCCESS;
90 REQUIRE(file != NULL);
91 REQUIRE(stats != NULL);
93 if (stat(file, stats) != 0)
94 result = isc__errno2result(errno);
96 return (result);
99 isc_result_t
100 isc_file_getmodtime(const char *file, isc_time_t *time) {
101 isc_result_t result;
102 struct stat stats;
104 REQUIRE(file != NULL);
105 REQUIRE(time != NULL);
107 result = file_stats(file, &stats);
109 if (result == ISC_R_SUCCESS)
111 * XXXDCL some operating systems provide nanoseconds, too,
112 * such as BSD/OS via st_mtimespec.
114 isc_time_set(time, stats.st_mtime, 0);
116 return (result);
119 isc_result_t
120 isc_file_settime(const char *file, isc_time_t *time) {
121 struct timeval times[2];
123 REQUIRE(file != NULL && time != NULL);
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.
135 times[0].tv_sec = times[1].tv_sec = (long)isc_time_seconds(time);
138 * Here is the real check for the high bit being set.
140 if ((times[0].tv_sec &
141 (1ULL << (sizeof(times[0].tv_sec) * CHAR_BIT - 1))) != 0)
142 return (ISC_R_RANGE);
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.
150 times[0].tv_usec = times[1].tv_usec =
151 (isc_int32_t)(isc_time_nanoseconds(time) / 1000);
153 if (utimes(file, times) < 0)
154 return (isc__errno2result(errno));
156 return (ISC_R_SUCCESS);
159 #undef TEMPLATE
160 #define TEMPLATE "tmp-XXXXXXXXXX" /*%< 14 characters. */
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));
167 isc_result_t
168 isc_file_template(const char *path, const char *templet, char *buf,
169 size_t buflen) {
170 char *s;
172 REQUIRE(path != NULL);
173 REQUIRE(templet != NULL);
174 REQUIRE(buf != NULL);
176 s = strrchr(templet, '/');
177 if (s != NULL)
178 templet = s + 1;
180 s = strrchr(path, '/');
182 if (s != NULL) {
183 if ((s - path + 1 + strlen(templet) + 1) > buflen)
184 return (ISC_R_NOSPACE);
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);
193 strcpy(buf, templet);
196 return (ISC_R_SUCCESS);
199 static char alphnum[] =
200 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
202 isc_result_t
203 isc_file_renameunique(const char *file, char *templet) {
204 char *x;
205 char *cp;
206 isc_uint32_t which;
208 REQUIRE(file != NULL);
209 REQUIRE(templet != NULL);
211 cp = templet;
212 while (*cp != '\0')
213 cp++;
214 if (cp == templet)
215 return (ISC_R_FAILURE);
217 x = cp--;
218 while (cp >= templet && *cp == 'X') {
219 isc_random_get(&which);
220 *cp = alphnum[which % (sizeof(alphnum) - 1)];
221 x = cp--;
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;
239 if (unlink(file) < 0)
240 if (errno != ENOENT)
241 return (isc__errno2result(errno));
242 return (ISC_R_SUCCESS);
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;
256 REQUIRE(templet != NULL);
257 REQUIRE(fp != NULL && *fp == NULL);
259 cp = templet;
260 while (*cp != '\0')
261 cp++;
262 if (cp == templet)
263 return (ISC_R_FAILURE);
265 x = cp--;
266 while (cp >= templet && *cp == 'X') {
267 isc_random_get(&which);
268 *cp = alphnum[which % (sizeof(alphnum) - 1)];
269 x = cp--;
272 mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
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;
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);
298 (void)close(fd);
299 } else
300 *fp = f;
302 return (result);
305 isc_result_t
306 isc_file_remove(const char *filename) {
307 int r;
309 REQUIRE(filename != NULL);
311 r = unlink(filename);
312 if (r == 0)
313 return (ISC_R_SUCCESS);
314 else
315 return (isc__errno2result(errno));
318 isc_result_t
319 isc_file_rename(const char *oldname, const char *newname) {
320 int r;
322 REQUIRE(oldname != NULL);
323 REQUIRE(newname != NULL);
325 r = rename(oldname, newname);
326 if (r == 0)
327 return (ISC_R_SUCCESS);
328 else
329 return (isc__errno2result(errno));
332 isc_boolean_t
333 isc_file_exists(const char *pathname) {
334 struct stat stats;
336 REQUIRE(pathname != NULL);
338 return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS));
341 isc_boolean_t
342 isc_file_isabsolute(const char *filename) {
343 REQUIRE(filename != NULL);
344 return (ISC_TF(filename[0] == '/'));
347 isc_boolean_t
348 isc_file_iscurrentdir(const char *filename) {
349 REQUIRE(filename != NULL);
350 return (ISC_TF(filename[0] == '.' && filename[1] == '\0'));
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);
363 const char *
364 isc_file_basename(const char *filename) {
365 char *s;
367 REQUIRE(filename != NULL);
369 s = strrchr(filename, '/');
370 if (s == NULL)
371 return (filename);
373 return (s + 1);
376 isc_result_t
377 isc_file_progname(const char *filename, char *buf, size_t buflen) {
378 const char *base;
379 size_t len;
381 REQUIRE(filename != NULL);
382 REQUIRE(buf != NULL);
384 base = isc_file_basename(filename);
385 len = strlen(base) + 1;
387 if (len > buflen)
388 return (ISC_R_NOSPACE);
389 memcpy(buf, base, len);
391 return (ISC_R_SUCCESS);
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.
400 static isc_result_t
401 dir_current(char *dirname, size_t length) {
402 char *cwd;
403 isc_result_t result = ISC_R_SUCCESS;
405 REQUIRE(dirname != NULL);
406 REQUIRE(length > 0U);
408 cwd = getcwd(dirname, length);
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, "/");
422 return (result);
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);
437 isc_result_t
438 isc_file_truncate(const char *filename, isc_offset_t size) {
439 isc_result_t result = ISC_R_SUCCESS;
441 if (truncate(filename, size) < 0)
442 result = isc__errno2result(errno);
443 return (result);