Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / isc / win32 / file.c
blob369de881497812e4afb0d9a66888ad8ac2b6897e
1 /* $NetBSD: file.c,v 1.9 2014/12/10 04:38:01 christos Exp $ */
3 /*
4 * Copyright (C) 2004, 2007, 2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000-2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id */
22 #include <config.h>
24 #undef rename
25 #include <errno.h>
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <io.h>
29 #include <process.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <sys/utime.h>
35 #include <isc/file.h>
36 #include <isc/mem.h>
37 #include <isc/result.h>
38 #include <isc/time.h>
39 #include <isc/util.h>
40 #include <isc/stat.h>
41 #include <isc/string.h>
43 #include "errno2result.h"
46 * Emulate UNIX mkstemp, which returns an open FD to the new file
49 static int
50 gettemp(char *path, isc_boolean_t binary, int *doopen) {
51 char *start, *trv;
52 struct stat sbuf;
53 int pid;
54 int flags = O_CREAT|O_EXCL|O_RDWR;
56 if (binary)
57 flags |= _O_BINARY;
59 trv = strrchr(path, 'X');
60 trv++;
61 pid = getpid();
62 /* extra X's get set to 0's */
63 while (*--trv == 'X') {
64 *trv = (pid % 10) + '0';
65 pid /= 10;
68 * check the target directory; if you have six X's and it
69 * doesn't exist this runs for a *very* long time.
71 for (start = trv + 1;; --trv) {
72 if (trv <= path)
73 break;
74 if (*trv == '\\') {
75 *trv = '\0';
76 if (stat(path, &sbuf))
77 return (0);
78 if (!S_ISDIR(sbuf.st_mode)) {
79 errno = ENOTDIR;
80 return (0);
82 *trv = '\\';
83 break;
87 for (;;) {
88 if (doopen) {
89 if ((*doopen =
90 open(path, flags, _S_IREAD | _S_IWRITE)) >= 0)
91 return (1);
92 if (errno != EEXIST)
93 return (0);
94 } else if (stat(path, &sbuf))
95 return (errno == ENOENT ? 1 : 0);
97 /* tricky little algorithm for backward compatibility */
98 for (trv = start;;) {
99 if (!*trv)
100 return (0);
101 if (*trv == 'z')
102 *trv++ = 'a';
103 else {
104 if (isdigit(*trv))
105 *trv = 'a';
106 else
107 ++*trv;
108 break;
112 /*NOTREACHED*/
115 static int
116 mkstemp(char *path, isc_boolean_t binary) {
117 int fd;
119 return (gettemp(path, binary, &fd) ? fd : -1);
123 * XXXDCL As the API for accessing file statistics undoubtedly gets expanded,
124 * it might be good to provide a mechanism that allows for the results
125 * of a previous stat() to be used again without having to do another stat,
126 * such as perl's mechanism of using "_" in place of a file name to indicate
127 * that the results of the last stat should be used. But then you get into
128 * annoying MP issues. BTW, Win32 has stat().
130 static isc_result_t
131 file_stats(const char *file, struct stat *stats) {
132 isc_result_t result = ISC_R_SUCCESS;
134 REQUIRE(file != NULL);
135 REQUIRE(stats != NULL);
137 if (stat(file, stats) != 0)
138 result = isc__errno2result(errno);
140 return (result);
143 static isc_result_t
144 fd_stats(int fd, struct stat *stats) {
145 isc_result_t result = ISC_R_SUCCESS;
147 REQUIRE(stats != NULL);
149 if (fstat(fd, stats) != 0)
150 result = isc__errno2result(errno);
152 return (result);
155 isc_result_t
156 isc_file_getsizefd(int fd, off_t *size) {
157 isc_result_t result;
158 struct stat stats;
160 REQUIRE(size != NULL);
162 result = fd_stats(fd, &stats);
164 if (result == ISC_R_SUCCESS)
165 *size = stats.st_size;
166 return (result);
169 isc_result_t
170 isc_file_mode(const char *file, mode_t *modep) {
171 isc_result_t result;
172 struct stat stats;
174 REQUIRE(modep != NULL);
176 result = file_stats(file, &stats);
177 if (result == ISC_R_SUCCESS)
178 *modep = (stats.st_mode & 07777);
179 return (result);
183 * isc_file_safemovefile is needed to be defined here to ensure that
184 * any file with the new name is renamed to a backup name and then the
185 * rename is done. If all goes well then the backup can be deleted,
186 * otherwise it gets renamed back.
190 isc_file_safemovefile(const char *oldname, const char *newname) {
191 BOOL filestatus;
192 char buf[512];
193 struct stat sbuf;
194 BOOL exists = FALSE;
195 int tmpfd;
198 * Make sure we have something to do
200 if (stat(oldname, &sbuf) != 0) {
201 errno = ENOENT;
202 return (-1);
206 * Rename to a backup the new file if it still exists
208 if (stat(newname, &sbuf) == 0) {
209 exists = TRUE;
210 strcpy(buf, newname);
211 strcat(buf, ".XXXXX");
212 tmpfd = mkstemp(buf, ISC_TRUE);
213 if (tmpfd > 0)
214 _close(tmpfd);
215 (void)DeleteFile(buf);
216 _chmod(newname, _S_IREAD | _S_IWRITE);
218 filestatus = MoveFile(newname, buf);
220 /* Now rename the file to the new name
222 _chmod(oldname, _S_IREAD | _S_IWRITE);
224 filestatus = MoveFile(oldname, newname);
225 if (filestatus == 0) {
227 * Try to rename the backup back to the original name
228 * if the backup got created
230 if (exists == TRUE) {
231 filestatus = MoveFile(buf, newname);
232 if (filestatus == 0)
233 errno = EACCES;
235 return (-1);
239 * Delete the backup file if it got created
241 if (exists == TRUE)
242 (void)DeleteFile(buf);
243 return (0);
246 isc_result_t
247 isc_file_getmodtime(const char *file, isc_time_t *time) {
248 int fh;
250 REQUIRE(file != NULL);
251 REQUIRE(time != NULL);
253 if ((fh = open(file, _O_RDONLY | _O_BINARY)) < 0)
254 return (isc__errno2result(errno));
256 if (!GetFileTime((HANDLE) _get_osfhandle(fh),
257 NULL,
258 NULL,
259 &time->absolute))
261 close(fh);
262 errno = EINVAL;
263 return (isc__errno2result(errno));
265 close(fh);
266 return (ISC_R_SUCCESS);
269 isc_result_t
270 isc_file_getsize(const char *file, off_t *size) {
271 isc_result_t result;
272 struct stat stats;
274 REQUIRE(file != NULL);
275 REQUIRE(size != NULL);
277 result = file_stats(file, &stats);
279 if (result == ISC_R_SUCCESS)
280 *size = stats.st_size;
282 return (result);
285 isc_result_t
286 isc_file_settime(const char *file, isc_time_t *time) {
287 int fh;
289 REQUIRE(file != NULL && time != NULL);
291 if ((fh = open(file, _O_RDWR | _O_BINARY)) < 0)
292 return (isc__errno2result(errno));
295 * Set the date via the filedate system call and return. Failing
296 * this call implies the new file times are not supported by the
297 * underlying file system.
299 if (!SetFileTime((HANDLE) _get_osfhandle(fh),
300 NULL,
301 &time->absolute,
302 &time->absolute))
304 close(fh);
305 errno = EINVAL;
306 return (isc__errno2result(errno));
309 close(fh);
310 return (ISC_R_SUCCESS);
314 #undef TEMPLATE
315 #define TEMPLATE "XXXXXXXXXX.tmp" /* 14 characters. */
317 isc_result_t
318 isc_file_mktemplate(const char *path, char *buf, size_t buflen) {
319 return (isc_file_template(path, TEMPLATE, buf, buflen));
322 isc_result_t
323 isc_file_template(const char *path, const char *templet, char *buf,
324 size_t buflen) {
325 char *s;
327 REQUIRE(path != NULL);
328 REQUIRE(templet != NULL);
329 REQUIRE(buf != NULL);
331 s = strrchr(templet, '\\');
332 if (s != NULL)
333 templet = s + 1;
335 s = strrchr(path, '\\');
337 if (s != NULL) {
338 if ((s - path + 1 + strlen(templet) + 1) > (ssize_t)buflen)
339 return (ISC_R_NOSPACE);
341 strncpy(buf, path, s - path + 1);
342 buf[s - path + 1] = '\0';
343 strcat(buf, templet);
344 } else {
345 if ((strlen(templet) + 1) > buflen)
346 return (ISC_R_NOSPACE);
348 strcpy(buf, templet);
351 return (ISC_R_SUCCESS);
354 isc_result_t
355 isc_file_renameunique(const char *file, char *templet) {
356 int fd;
357 int res = 0;
358 isc_result_t result = ISC_R_SUCCESS;
360 REQUIRE(file != NULL);
361 REQUIRE(templet != NULL);
363 fd = mkstemp(templet, ISC_TRUE);
364 if (fd == -1)
365 result = isc__errno2result(errno);
366 else
367 close(fd);
369 if (result == ISC_R_SUCCESS) {
370 res = isc_file_safemovefile(file, templet);
371 if (res != 0) {
372 result = isc__errno2result(errno);
373 (void)unlink(templet);
376 return (result);
379 static isc_result_t
380 openuniquemode(char *templet, int mode, isc_boolean_t binary, FILE **fp) {
381 int fd;
382 FILE *f;
383 isc_result_t result = ISC_R_SUCCESS;
385 REQUIRE(templet != NULL);
386 REQUIRE(fp != NULL && *fp == NULL);
389 * Win32 does not have mkstemp. Using emulation above.
391 fd = mkstemp(templet, binary);
393 if (fd == -1)
394 result = isc__errno2result(errno);
395 if (result == ISC_R_SUCCESS) {
396 #if 1
397 UNUSED(mode);
398 #else
399 (void)fchmod(fd, mode);
400 #endif
401 f = fdopen(fd, binary ? "wb+" : "w+");
402 if (f == NULL) {
403 result = isc__errno2result(errno);
404 (void)remove(templet);
405 (void)close(fd);
406 } else
407 *fp = f;
410 return (result);
413 isc_result_t
414 isc_file_openuniqueprivate(char *templet, FILE **fp) {
415 int mode = _S_IREAD | _S_IWRITE;
416 return (openuniquemode(templet, mode, ISC_FALSE, fp));
419 isc_result_t
420 isc_file_openunique(char *templet, FILE **fp) {
421 int mode = _S_IREAD | _S_IWRITE;
422 return (openuniquemode(templet, mode, ISC_FALSE, fp));
425 isc_result_t
426 isc_file_openuniquemode(char *templet, int mode, FILE **fp) {
427 return (openuniquemode(templet, mode, ISC_FALSE, fp));
430 isc_result_t
431 isc_file_bopenuniqueprivate(char *templet, FILE **fp) {
432 int mode = _S_IREAD | _S_IWRITE;
433 return (openuniquemode(templet, mode, ISC_TRUE, fp));
436 isc_result_t
437 isc_file_bopenunique(char *templet, FILE **fp) {
438 int mode = _S_IREAD | _S_IWRITE;
439 return (openuniquemode(templet, mode, ISC_TRUE, fp));
442 isc_result_t
443 isc_file_bopenuniquemode(char *templet, int mode, FILE **fp) {
444 return (openuniquemode(templet, mode, ISC_TRUE, fp));
447 isc_result_t
448 isc_file_remove(const char *filename) {
449 int r;
451 REQUIRE(filename != NULL);
453 r = unlink(filename);
454 if (r == 0)
455 return (ISC_R_SUCCESS);
456 else
457 return (isc__errno2result(errno));
460 isc_result_t
461 isc_file_rename(const char *oldname, const char *newname) {
462 int r;
464 REQUIRE(oldname != NULL);
465 REQUIRE(newname != NULL);
467 r = isc_file_safemovefile(oldname, newname);
468 if (r == 0)
469 return (ISC_R_SUCCESS);
470 else
471 return (isc__errno2result(errno));
474 isc_boolean_t
475 isc_file_exists(const char *pathname) {
476 struct stat stats;
478 REQUIRE(pathname != NULL);
480 return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS));
483 isc_result_t
484 isc_file_isplainfile(const char *filename) {
486 * This function returns success if filename is a plain file.
488 struct stat filestat;
489 memset(&filestat,0,sizeof(struct stat));
491 if ((stat(filename, &filestat)) == -1)
492 return(isc__errno2result(errno));
494 if(! S_ISREG(filestat.st_mode))
495 return(ISC_R_INVALIDFILE);
497 return(ISC_R_SUCCESS);
500 isc_result_t
501 isc_file_isplainfilefd(int fd) {
503 * This function returns success if filename is a plain file.
505 struct stat filestat;
506 memset(&filestat,0,sizeof(struct stat));
508 if ((fstat(fd, &filestat)) == -1)
509 return(isc__errno2result(errno));
511 if(! S_ISREG(filestat.st_mode))
512 return(ISC_R_INVALIDFILE);
514 return(ISC_R_SUCCESS);
517 isc_result_t
518 isc_file_isdirectory(const char *filename) {
520 * This function returns success if filename is a directory.
522 struct stat filestat;
523 memset(&filestat,0,sizeof(struct stat));
525 if ((stat(filename, &filestat)) == -1)
526 return(isc__errno2result(errno));
528 if(! S_ISDIR(filestat.st_mode))
529 return(ISC_R_INVALIDFILE);
531 return(ISC_R_SUCCESS);
535 isc_boolean_t
536 isc_file_isabsolute(const char *filename) {
537 REQUIRE(filename != NULL);
539 * Look for c:\path\... style, c:/path/... or \\computer\shar\path...
540 * the UNC style file specs
542 if ((filename[0] == '\\') && (filename[1] == '\\'))
543 return (ISC_TRUE);
544 if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '\\')
545 return (ISC_TRUE);
546 if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '/')
547 return (ISC_TRUE);
548 return (ISC_FALSE);
551 isc_boolean_t
552 isc_file_iscurrentdir(const char *filename) {
553 REQUIRE(filename != NULL);
554 return (ISC_TF(filename[0] == '.' && filename[1] == '\0'));
557 isc_boolean_t
558 isc_file_ischdiridempotent(const char *filename) {
559 REQUIRE(filename != NULL);
561 if (isc_file_isabsolute(filename))
562 return (ISC_TRUE);
563 if (filename[0] == '\\')
564 return (ISC_TRUE);
565 if (filename[0] == '/')
566 return (ISC_TRUE);
567 if (isc_file_iscurrentdir(filename))
568 return (ISC_TRUE);
569 return (ISC_FALSE);
572 const char *
573 isc_file_basename(const char *filename) {
574 char *s;
576 REQUIRE(filename != NULL);
578 s = strrchr(filename, '\\');
579 if (s == NULL)
580 return (filename);
581 return (s + 1);
584 isc_result_t
585 isc_file_progname(const char *filename, char *progname, size_t namelen) {
586 const char *s;
587 char *p;
588 size_t len;
590 REQUIRE(filename != NULL);
591 REQUIRE(progname != NULL);
594 * Strip the path from the name
596 s = isc_file_basename(filename);
597 if (s == NULL) {
598 return (ISC_R_NOSPACE);
602 * Strip any and all suffixes
604 p = strchr(s, '.');
605 if (p == NULL) {
606 if (namelen <= strlen(s))
607 return (ISC_R_NOSPACE);
609 strcpy(progname, s);
610 return (ISC_R_SUCCESS);
614 * Copy the result to the buffer
616 len = p - s;
617 if (len >= namelen)
618 return (ISC_R_NOSPACE);
620 strncpy(progname, s, len);
621 progname[len] = '\0';
622 return (ISC_R_SUCCESS);
625 isc_result_t
626 isc_file_absolutepath(const char *filename, char *path, size_t pathlen) {
627 char *ptrname;
628 DWORD retval;
630 REQUIRE(filename != NULL);
631 REQUIRE(path != NULL);
633 retval = GetFullPathName(filename, (DWORD) pathlen, path, &ptrname);
635 /* Something went wrong in getting the path */
636 if (retval == 0)
637 return (ISC_R_NOTFOUND);
638 /* Caller needs to provide a larger buffer to contain the string */
639 if (retval >= pathlen)
640 return (ISC_R_NOSPACE);
641 return (ISC_R_SUCCESS);
644 isc_result_t
645 isc_file_truncate(const char *filename, isc_offset_t size) {
646 int fh;
648 REQUIRE(filename != NULL && size >= 0);
650 if ((fh = open(filename, _O_RDWR | _O_BINARY)) < 0)
651 return (isc__errno2result(errno));
653 if(_chsize(fh, size) != 0) {
654 close(fh);
655 return (isc__errno2result(errno));
657 close(fh);
659 return (ISC_R_SUCCESS);
662 isc_result_t
663 isc_file_safecreate(const char *filename, FILE **fp) {
664 isc_result_t result;
665 int flags;
666 struct stat sb;
667 FILE *f;
668 int fd;
670 REQUIRE(filename != NULL);
671 REQUIRE(fp != NULL && *fp == NULL);
673 result = file_stats(filename, &sb);
674 if (result == ISC_R_SUCCESS) {
675 if ((sb.st_mode & S_IFREG) == 0)
676 return (ISC_R_INVALIDFILE);
677 flags = O_WRONLY | O_TRUNC;
678 } else if (result == ISC_R_FILENOTFOUND) {
679 flags = O_WRONLY | O_CREAT | O_EXCL;
680 } else
681 return (result);
683 fd = open(filename, flags, S_IRUSR | S_IWUSR);
684 if (fd == -1)
685 return (isc__errno2result(errno));
687 f = fdopen(fd, "w");
688 if (f == NULL) {
689 result = isc__errno2result(errno);
690 close(fd);
691 return (result);
694 *fp = f;
695 return (ISC_R_SUCCESS);
698 isc_result_t
699 isc_file_splitpath(isc_mem_t *mctx, char *path, char **dirname, char **basename)
701 char *dir, *file, *slash;
702 char *backslash;
704 slash = strrchr(path, '/');
706 backslash = strrchr(path, '\\');
707 if ((slash != NULL && backslash != NULL && backslash > slash) ||
708 (slash == NULL && backslash != NULL))
709 slash = backslash;
711 if (slash == path) {
712 file = ++slash;
713 dir = isc_mem_strdup(mctx, "/");
714 } else if (slash != NULL) {
715 file = ++slash;
716 dir = isc_mem_allocate(mctx, slash - path);
717 if (dir != NULL)
718 strlcpy(dir, path, slash - path);
719 } else {
720 file = path;
721 dir = isc_mem_strdup(mctx, ".");
724 if (dir == NULL)
725 return (ISC_R_NOMEMORY);
727 if (*file == '\0') {
728 isc_mem_free(mctx, dir);
729 return (ISC_R_INVALIDFILE);
732 *dirname = dir;
733 *basename = file;
735 return (ISC_R_SUCCESS);
738 void *
739 isc_file_mmap(void *addr, size_t len, int prot,
740 int flags, int fd, off_t offset)
742 void *buf;
743 ssize_t ret;
744 off_t end;
746 UNUSED(addr);
747 UNUSED(prot);
748 UNUSED(flags);
750 end = lseek(fd, 0, SEEK_END);
751 lseek(fd, offset, SEEK_SET);
752 if (end - offset < (off_t) len)
753 len = end - offset;
755 buf = malloc(len);
756 ret = read(fd, buf, (unsigned int) len);
757 if (ret != (ssize_t) len) {
758 free(buf);
759 buf = NULL;
762 return (buf);
766 isc_file_munmap(void *addr, size_t len) {
767 UNUSED(len);
768 free(addr);
769 return (0);