Annotation of embedaddon/ntp/lib/isc/win32/file.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2004, 2007 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: /* $Id: file.c,v 1.31 2007/06/19 23:47:19 tbox Exp $ */
19:
20: #include <config.h>
21:
22: #undef rename
23: #include <errno.h>
24: #include <limits.h>
25: #include <stdlib.h>
26: #include <io.h>
27: #include <process.h>
28:
29: #include <sys/stat.h>
30: #include <fcntl.h>
31: #include <sys/utime.h>
32:
33: #include <isc/file.h>
34: #include <isc/result.h>
35: #include <isc/time.h>
36: #include <isc/util.h>
37: #include <isc/stat.h>
38:
39: #include "errno2result.h"
40:
41: /*
42: * Emulate UNIX mkstemp, which returns an open FD to the new file
43: *
44: */
45: static int
46: gettemp(char *path, int *doopen) {
47: char *start, *trv;
48: struct stat sbuf;
49: int pid;
50:
51: trv = strrchr(path, 'X');
52: trv++;
53: pid = getpid();
54: /* extra X's get set to 0's */
55: while (*--trv == 'X') {
56: *trv = (pid % 10) + '0';
57: pid /= 10;
58: }
59: /*
60: * check the target directory; if you have six X's and it
61: * doesn't exist this runs for a *very* long time.
62: */
63: for (start = trv + 1;; --trv) {
64: if (trv <= path)
65: break;
66: if (*trv == '\\') {
67: *trv = '\0';
68: if (stat(path, &sbuf))
69: return (0);
70: if (!S_ISDIR(sbuf.st_mode)) {
71: errno = ENOTDIR;
72: return (0);
73: }
74: *trv = '\\';
75: break;
76: }
77: }
78:
79: for (;;) {
80: if (doopen) {
81: if ((*doopen =
82: open(path, O_CREAT|O_EXCL|O_RDWR,
83: _S_IREAD | _S_IWRITE)) >= 0)
84: return (1);
85: if (errno != EEXIST)
86: return (0);
87: } else if (stat(path, &sbuf))
88: return (errno == ENOENT ? 1 : 0);
89:
90: /* tricky little algorithm for backward compatibility */
91: for (trv = start;;) {
92: if (!*trv)
93: return (0);
94: if (*trv == 'z')
95: *trv++ = 'a';
96: else {
97: if (isdigit(*trv))
98: *trv = 'a';
99: else
100: ++*trv;
101: break;
102: }
103: }
104: }
105: /*NOTREACHED*/
106: }
107:
108: static int
109: mkstemp(char *path) {
110: int fd;
111:
112: return (gettemp(path, &fd) ? fd : -1);
113: }
114:
115: /*
116: * XXXDCL As the API for accessing file statistics undoubtedly gets expanded,
117: * it might be good to provide a mechanism that allows for the results
118: * of a previous stat() to be used again without having to do another stat,
119: * such as perl's mechanism of using "_" in place of a file name to indicate
120: * that the results of the last stat should be used. But then you get into
121: * annoying MP issues. BTW, Win32 has stat().
122: */
123: static isc_result_t
124: file_stats(const char *file, struct stat *stats) {
125: isc_result_t result = ISC_R_SUCCESS;
126:
127: REQUIRE(file != NULL);
128: REQUIRE(stats != NULL);
129:
130: if (stat(file, stats) != 0)
131: result = isc__errno2result(errno);
132:
133: return (result);
134: }
135:
136: /*
137: * isc_file_safemovefile is needed to be defined here to ensure that
138: * any file with the new name is renamed to a backup name and then the
139: * rename is done. If all goes well then the backup can be deleted,
140: * otherwise it gets renamed back.
141: */
142:
143: int
144: isc_file_safemovefile(const char *oldname, const char *newname) {
145: BOOL filestatus;
146: char buf[512];
147: struct stat sbuf;
148: BOOL exists = FALSE;
149: int tmpfd;
150:
151: /*
152: * Make sure we have something to do
153: */
154: if (stat(oldname, &sbuf) != 0) {
155: errno = ENOENT;
156: return (-1);
157: }
158:
159: /*
160: * Rename to a backup the new file if it still exists
161: */
162: if (stat(newname, &sbuf) == 0) {
163: exists = TRUE;
164: strcpy(buf, newname);
165: strcat(buf, ".XXXXX");
166: tmpfd = mkstemp(buf);
167: if (tmpfd > 0)
168: _close(tmpfd);
169: DeleteFile(buf);
170: _chmod(newname, _S_IREAD | _S_IWRITE);
171:
172: filestatus = MoveFile(newname, buf);
173: }
174: /* Now rename the file to the new name
175: */
176: _chmod(oldname, _S_IREAD | _S_IWRITE);
177:
178: filestatus = MoveFile(oldname, newname);
179: if (filestatus == 0) {
180: /*
181: * Try to rename the backup back to the original name
182: * if the backup got created
183: */
184: if (exists == TRUE) {
185: filestatus = MoveFile(buf, newname);
186: if (filestatus == 0)
187: errno = EACCES;
188: }
189: return (-1);
190: }
191:
192: /*
193: * Delete the backup file if it got created
194: */
195: if (exists == TRUE)
196: filestatus = DeleteFile(buf);
197: return (0);
198: }
199:
200: isc_result_t
201: isc_file_getmodtime(const char *file, isc_time_t *time) {
202: int fh;
203:
204: REQUIRE(file != NULL);
205: REQUIRE(time != NULL);
206:
207: if ((fh = open(file, _O_RDONLY | _O_BINARY)) < 0)
208: return (isc__errno2result(errno));
209:
210: if (!GetFileTime((HANDLE) _get_osfhandle(fh),
211: NULL,
212: NULL,
213: &time->absolute))
214: {
215: close(fh);
216: errno = EINVAL;
217: return (isc__errno2result(errno));
218: }
219: close(fh);
220: return (ISC_R_SUCCESS);
221: }
222:
223: isc_result_t
224: isc_file_settime(const char *file, isc_time_t *time) {
225: int fh;
226:
227: REQUIRE(file != NULL && time != NULL);
228:
229: if ((fh = open(file, _O_RDWR | _O_BINARY)) < 0)
230: return (isc__errno2result(errno));
231:
232: /*
233: * Set the date via the filedate system call and return. Failing
234: * this call implies the new file times are not supported by the
235: * underlying file system.
236: */
237: if (!SetFileTime((HANDLE) _get_osfhandle(fh),
238: NULL,
239: &time->absolute,
240: &time->absolute))
241: {
242: close(fh);
243: errno = EINVAL;
244: return (isc__errno2result(errno));
245: }
246:
247: close(fh);
248: return (ISC_R_SUCCESS);
249:
250: }
251:
252: #undef TEMPLATE
253: #define TEMPLATE "XXXXXXXXXX.tmp" /* 14 characters. */
254:
255: isc_result_t
256: isc_file_mktemplate(const char *path, char *buf, size_t buflen) {
257: return (isc_file_template(path, TEMPLATE, buf, buflen));
258: }
259:
260: isc_result_t
261: isc_file_template(const char *path, const char *templet, char *buf,
262: size_t buflen) {
263: char *s;
264:
265: REQUIRE(path != NULL);
266: REQUIRE(templet != NULL);
267: REQUIRE(buf != NULL);
268:
269: s = strrchr(templet, '\\');
270: if (s != NULL)
271: templet = s + 1;
272:
273: s = strrchr(path, '\\');
274:
275: if (s != NULL) {
276: if ((s - path + 1 + strlen(templet) + 1) > buflen)
277: return (ISC_R_NOSPACE);
278:
279: strncpy(buf, path, s - path + 1);
280: buf[s - path + 1] = '\0';
281: strcat(buf, templet);
282: } else {
283: if ((strlen(templet) + 1) > buflen)
284: return (ISC_R_NOSPACE);
285:
286: strcpy(buf, templet);
287: }
288:
289: return (ISC_R_SUCCESS);
290: }
291:
292: isc_result_t
293: isc_file_renameunique(const char *file, char *templet) {
294: int fd = -1;
295: int res = 0;
296: isc_result_t result = ISC_R_SUCCESS;
297:
298: REQUIRE(file != NULL);
299: REQUIRE(templet != NULL);
300:
301: fd = mkstemp(templet);
302: if (fd == -1)
303: result = isc__errno2result(errno);
304: else
305: close(fd);
306:
307: if (result == ISC_R_SUCCESS) {
308: res = isc_file_safemovefile(file, templet);
309: if (res != 0) {
310: result = isc__errno2result(errno);
311: (void)unlink(templet);
312: }
313: }
314: return (result);
315: }
316:
317: isc_result_t
318: isc_file_openunique(char *templet, FILE **fp) {
319: int fd;
320: FILE *f;
321: isc_result_t result = ISC_R_SUCCESS;
322:
323: REQUIRE(templet != NULL);
324: REQUIRE(fp != NULL && *fp == NULL);
325:
326: /*
327: * Win32 does not have mkstemp. Using emulation above.
328: */
329: fd = mkstemp(templet);
330:
331: if (fd == -1)
332: result = isc__errno2result(errno);
333: if (result == ISC_R_SUCCESS) {
334: f = fdopen(fd, "w+");
335: if (f == NULL) {
336: result = isc__errno2result(errno);
337: (void)remove(templet);
338: (void)close(fd);
339: } else
340: *fp = f;
341: }
342:
343: return (result);
344: }
345:
346: isc_result_t
347: isc_file_remove(const char *filename) {
348: int r;
349:
350: REQUIRE(filename != NULL);
351:
352: r = unlink(filename);
353: if (r == 0)
354: return (ISC_R_SUCCESS);
355: else
356: return (isc__errno2result(errno));
357: }
358:
359: isc_result_t
360: isc_file_rename(const char *oldname, const char *newname) {
361: int r;
362:
363: REQUIRE(oldname != NULL);
364: REQUIRE(newname != NULL);
365:
366: r = isc_file_safemovefile(oldname, newname);
367: if (r == 0)
368: return (ISC_R_SUCCESS);
369: else
370: return (isc__errno2result(errno));
371: }
372:
373: isc_boolean_t
374: isc_file_exists(const char *pathname) {
375: struct stat stats;
376:
377: REQUIRE(pathname != NULL);
378:
379: return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS));
380: }
381:
382: isc_boolean_t
383: isc_file_isabsolute(const char *filename) {
384: REQUIRE(filename != NULL);
385: /*
386: * Look for c:\path\... style, c:/path/... or \\computer\shar\path...
387: * the UNC style file specs
388: */
389: if ((filename[0] == '\\') && (filename[1] == '\\'))
390: return (ISC_TRUE);
391: if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '\\')
392: return (ISC_TRUE);
393: if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '/')
394: return (ISC_TRUE);
395: return (ISC_FALSE);
396: }
397:
398: isc_boolean_t
399: isc_file_iscurrentdir(const char *filename) {
400: REQUIRE(filename != NULL);
401: return (ISC_TF(filename[0] == '.' && filename[1] == '\0'));
402: }
403:
404: isc_boolean_t
405: isc_file_ischdiridempotent(const char *filename) {
406: REQUIRE(filename != NULL);
407:
408: if (isc_file_isabsolute(filename))
409: return (ISC_TRUE);
410: if (filename[0] == '\\')
411: return (ISC_TRUE);
412: if (filename[0] == '/')
413: return (ISC_TRUE);
414: if (isc_file_iscurrentdir(filename))
415: return (ISC_TRUE);
416: return (ISC_FALSE);
417: }
418:
419: const char *
420: isc_file_basename(const char *filename) {
421: char *s;
422:
423: REQUIRE(filename != NULL);
424:
425: s = strrchr(filename, '\\');
426: if (s == NULL)
427: return (filename);
428: return (s + 1);
429: }
430:
431: isc_result_t
432: isc_file_progname(const char *filename, char *progname, size_t namelen) {
433: const char *s;
434: char *p;
435: size_t len;
436:
437: REQUIRE(filename != NULL);
438: REQUIRE(progname != NULL);
439:
440: /*
441: * Strip the path from the name
442: */
443: s = isc_file_basename(filename);
444: if (s == NULL) {
445: return (ISC_R_NOSPACE);
446: }
447:
448: /*
449: * Strip any and all suffixes
450: */
451: p = strchr(s, '.');
452: if (p == NULL) {
453: if (namelen <= strlen(s))
454: return (ISC_R_NOSPACE);
455:
456: strcpy(progname, s);
457: return (ISC_R_SUCCESS);
458: }
459:
460: /*
461: * Copy the result to the buffer
462: */
463: len = p - s;
464: if (len >= namelen)
465: return (ISC_R_NOSPACE);
466:
467: strncpy(progname, s, len);
468: progname[len] = '\0';
469: return (ISC_R_SUCCESS);
470: }
471:
472: isc_result_t
473: isc_file_absolutepath(const char *filename, char *path, size_t pathlen) {
474: char *ptrname;
475: DWORD retval;
476:
477: REQUIRE(filename != NULL);
478: REQUIRE(path != NULL);
479:
480: retval = GetFullPathName(filename, pathlen, path, &ptrname);
481:
482: /* Something went wrong in getting the path */
483: if (retval == 0)
484: return (ISC_R_NOTFOUND);
485: /* Caller needs to provide a larger buffer to contain the string */
486: if (retval >= pathlen)
487: return (ISC_R_NOSPACE);
488: return (ISC_R_SUCCESS);
489: }
490:
491: isc_result_t
492: isc_file_truncate(const char *filename, isc_offset_t size) {
493: int fh;
494:
495: REQUIRE(filename != NULL && size >= 0);
496:
497: if ((fh = open(filename, _O_RDWR | _O_BINARY)) < 0)
498: return (isc__errno2result(errno));
499:
500: if(_chsize(fh, size) != 0) {
501: close(fh);
502: return (isc__errno2result(errno));
503: }
504: close(fh);
505:
506: return (ISC_R_SUCCESS);
507: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>