Annotation of embedaddon/ntp/lib/isc/unix/file.c, revision 1.1.1.1
1.1 misho 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.332.2 2009/02/16 23:47:15 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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>