xref: /minix/external/bsd/bind/dist/lib/isc/win32/file.c (revision 00b67f09)
1 /*	$NetBSD: file.c,v 1.9 2014/12/10 04:38:01 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004, 2007, 2009, 2011-2013  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 2000-2002  Internet Software Consortium.
6  *
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.
10  *
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.
18  */
19 
20 /* Id */
21 
22 #include <config.h>
23 
24 #undef rename
25 #include <errno.h>
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <io.h>
29 #include <process.h>
30 
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <sys/utime.h>
34 
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>
42 
43 #include "errno2result.h"
44 
45 /*
46  * Emulate UNIX mkstemp, which returns an open FD to the new file
47  *
48  */
49 static int
gettemp(char * path,isc_boolean_t binary,int * doopen)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;
55 
56 	if (binary)
57 		flags |= _O_BINARY;
58 
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;
66 	}
67 	/*
68 	 * check the target directory; if you have six X's and it
69 	 * doesn't exist this runs for a *very* long time.
70 	 */
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);
81 			}
82 			*trv = '\\';
83 			break;
84 		}
85 	}
86 
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);
96 
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;
109 			}
110 		}
111 	}
112 	/*NOTREACHED*/
113 }
114 
115 static int
mkstemp(char * path,isc_boolean_t binary)116 mkstemp(char *path, isc_boolean_t binary) {
117 	int fd;
118 
119 	return (gettemp(path, binary, &fd) ? fd : -1);
120 }
121 
122 /*
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().
129  */
130 static isc_result_t
file_stats(const char * file,struct stat * stats)131 file_stats(const char *file, struct stat *stats) {
132 	isc_result_t result = ISC_R_SUCCESS;
133 
134 	REQUIRE(file != NULL);
135 	REQUIRE(stats != NULL);
136 
137 	if (stat(file, stats) != 0)
138 		result = isc__errno2result(errno);
139 
140 	return (result);
141 }
142 
143 static isc_result_t
fd_stats(int fd,struct stat * stats)144 fd_stats(int fd, struct stat *stats) {
145 	isc_result_t result = ISC_R_SUCCESS;
146 
147 	REQUIRE(stats != NULL);
148 
149 	if (fstat(fd, stats) != 0)
150 		result = isc__errno2result(errno);
151 
152 	return (result);
153 }
154 
155 isc_result_t
isc_file_getsizefd(int fd,off_t * size)156 isc_file_getsizefd(int fd, off_t *size) {
157 	isc_result_t result;
158 	struct stat stats;
159 
160 	REQUIRE(size != NULL);
161 
162 	result = fd_stats(fd, &stats);
163 
164 	if (result == ISC_R_SUCCESS)
165 		*size = stats.st_size;
166 	return (result);
167 }
168 
169 isc_result_t
isc_file_mode(const char * file,mode_t * modep)170 isc_file_mode(const char *file, mode_t *modep) {
171 	isc_result_t result;
172 	struct stat stats;
173 
174 	REQUIRE(modep != NULL);
175 
176 	result = file_stats(file, &stats);
177 	if (result == ISC_R_SUCCESS)
178 		*modep = (stats.st_mode & 07777);
179 	return (result);
180 }
181 
182 /*
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.
187  */
188 
189 int
isc_file_safemovefile(const char * oldname,const char * newname)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;
196 
197 	/*
198 	 * Make sure we have something to do
199 	 */
200 	if (stat(oldname, &sbuf) != 0) {
201 		errno = ENOENT;
202 		return (-1);
203 	}
204 
205 	/*
206 	 * Rename to a backup the new file if it still exists
207 	 */
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);
217 
218 		filestatus = MoveFile(newname, buf);
219 	}
220 	/* Now rename the file to the new name
221 	 */
222 	_chmod(oldname, _S_IREAD | _S_IWRITE);
223 
224 	filestatus = MoveFile(oldname, newname);
225 	if (filestatus == 0) {
226 		/*
227 		 * Try to rename the backup back to the original name
228 		 * if the backup got created
229 		 */
230 		if (exists == TRUE) {
231 			filestatus = MoveFile(buf, newname);
232 			if (filestatus == 0)
233 				errno = EACCES;
234 		}
235 		return (-1);
236 	}
237 
238 	/*
239 	 * Delete the backup file if it got created
240 	 */
241 	if (exists == TRUE)
242 		(void)DeleteFile(buf);
243 	return (0);
244 }
245 
246 isc_result_t
isc_file_getmodtime(const char * file,isc_time_t * time)247 isc_file_getmodtime(const char *file, isc_time_t *time) {
248 	int fh;
249 
250 	REQUIRE(file != NULL);
251 	REQUIRE(time != NULL);
252 
253 	if ((fh = open(file, _O_RDONLY | _O_BINARY)) < 0)
254 		return (isc__errno2result(errno));
255 
256 	if (!GetFileTime((HANDLE) _get_osfhandle(fh),
257 			 NULL,
258 			 NULL,
259 			 &time->absolute))
260 	{
261 		close(fh);
262 		errno = EINVAL;
263 		return (isc__errno2result(errno));
264 	}
265 	close(fh);
266 	return (ISC_R_SUCCESS);
267 }
268 
269 isc_result_t
isc_file_getsize(const char * file,off_t * size)270 isc_file_getsize(const char *file, off_t *size) {
271 	isc_result_t result;
272 	struct stat stats;
273 
274 	REQUIRE(file != NULL);
275 	REQUIRE(size != NULL);
276 
277 	result = file_stats(file, &stats);
278 
279 	if (result == ISC_R_SUCCESS)
280 		*size = stats.st_size;
281 
282 	return (result);
283 }
284 
285 isc_result_t
isc_file_settime(const char * file,isc_time_t * time)286 isc_file_settime(const char *file, isc_time_t *time) {
287 	int fh;
288 
289 	REQUIRE(file != NULL && time != NULL);
290 
291 	if ((fh = open(file, _O_RDWR | _O_BINARY)) < 0)
292 		return (isc__errno2result(errno));
293 
294 	/*
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.
298 	 */
299 	if (!SetFileTime((HANDLE) _get_osfhandle(fh),
300 			 NULL,
301 			 &time->absolute,
302 			 &time->absolute))
303 	{
304 		close(fh);
305 		errno = EINVAL;
306 		return (isc__errno2result(errno));
307 	}
308 
309 	close(fh);
310 	return (ISC_R_SUCCESS);
311 
312 }
313 
314 #undef TEMPLATE
315 #define TEMPLATE "XXXXXXXXXX.tmp" /* 14 characters. */
316 
317 isc_result_t
isc_file_mktemplate(const char * path,char * buf,size_t buflen)318 isc_file_mktemplate(const char *path, char *buf, size_t buflen) {
319 	return (isc_file_template(path, TEMPLATE, buf, buflen));
320 }
321 
322 isc_result_t
isc_file_template(const char * path,const char * templet,char * buf,size_t buflen)323 isc_file_template(const char *path, const char *templet, char *buf,
324 			size_t buflen) {
325 	char *s;
326 
327 	REQUIRE(path != NULL);
328 	REQUIRE(templet != NULL);
329 	REQUIRE(buf != NULL);
330 
331 	s = strrchr(templet, '\\');
332 	if (s != NULL)
333 		templet = s + 1;
334 
335 	s = strrchr(path, '\\');
336 
337 	if (s != NULL) {
338 	  if ((s - path + 1 + strlen(templet) + 1) > (ssize_t)buflen)
339 			return (ISC_R_NOSPACE);
340 
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);
347 
348 		strcpy(buf, templet);
349 	}
350 
351 	return (ISC_R_SUCCESS);
352 }
353 
354 isc_result_t
isc_file_renameunique(const char * file,char * templet)355 isc_file_renameunique(const char *file, char *templet) {
356 	int fd;
357 	int res = 0;
358 	isc_result_t result = ISC_R_SUCCESS;
359 
360 	REQUIRE(file != NULL);
361 	REQUIRE(templet != NULL);
362 
363 	fd = mkstemp(templet, ISC_TRUE);
364 	if (fd == -1)
365 		result = isc__errno2result(errno);
366 	else
367 		close(fd);
368 
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);
374 		}
375 	}
376 	return (result);
377 }
378 
379 static isc_result_t
openuniquemode(char * templet,int mode,isc_boolean_t binary,FILE ** fp)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;
384 
385 	REQUIRE(templet != NULL);
386 	REQUIRE(fp != NULL && *fp == NULL);
387 
388 	/*
389 	 * Win32 does not have mkstemp. Using emulation above.
390 	 */
391 	fd = mkstemp(templet, binary);
392 
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;
408 	}
409 
410 	return (result);
411 }
412 
413 isc_result_t
isc_file_openuniqueprivate(char * templet,FILE ** fp)414 isc_file_openuniqueprivate(char *templet, FILE **fp) {
415 	int mode = _S_IREAD | _S_IWRITE;
416 	return (openuniquemode(templet, mode, ISC_FALSE, fp));
417 }
418 
419 isc_result_t
isc_file_openunique(char * templet,FILE ** fp)420 isc_file_openunique(char *templet, FILE **fp) {
421 	int mode = _S_IREAD | _S_IWRITE;
422 	return (openuniquemode(templet, mode, ISC_FALSE, fp));
423 }
424 
425 isc_result_t
isc_file_openuniquemode(char * templet,int mode,FILE ** fp)426 isc_file_openuniquemode(char *templet, int mode, FILE **fp) {
427 	return (openuniquemode(templet, mode, ISC_FALSE, fp));
428 }
429 
430 isc_result_t
isc_file_bopenuniqueprivate(char * templet,FILE ** fp)431 isc_file_bopenuniqueprivate(char *templet, FILE **fp) {
432 	int mode = _S_IREAD | _S_IWRITE;
433 	return (openuniquemode(templet, mode, ISC_TRUE, fp));
434 }
435 
436 isc_result_t
isc_file_bopenunique(char * templet,FILE ** fp)437 isc_file_bopenunique(char *templet, FILE **fp) {
438 	int mode = _S_IREAD | _S_IWRITE;
439 	return (openuniquemode(templet, mode, ISC_TRUE, fp));
440 }
441 
442 isc_result_t
isc_file_bopenuniquemode(char * templet,int mode,FILE ** fp)443 isc_file_bopenuniquemode(char *templet, int mode, FILE **fp) {
444 	return (openuniquemode(templet, mode, ISC_TRUE, fp));
445 }
446 
447 isc_result_t
isc_file_remove(const char * filename)448 isc_file_remove(const char *filename) {
449 	int r;
450 
451 	REQUIRE(filename != NULL);
452 
453 	r = unlink(filename);
454 	if (r == 0)
455 		return (ISC_R_SUCCESS);
456 	else
457 		return (isc__errno2result(errno));
458 }
459 
460 isc_result_t
isc_file_rename(const char * oldname,const char * newname)461 isc_file_rename(const char *oldname, const char *newname) {
462 	int r;
463 
464 	REQUIRE(oldname != NULL);
465 	REQUIRE(newname != NULL);
466 
467 	r = isc_file_safemovefile(oldname, newname);
468 	if (r == 0)
469 		return (ISC_R_SUCCESS);
470 	else
471 		return (isc__errno2result(errno));
472 }
473 
474 isc_boolean_t
isc_file_exists(const char * pathname)475 isc_file_exists(const char *pathname) {
476 	struct stat stats;
477 
478 	REQUIRE(pathname != NULL);
479 
480 	return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS));
481 }
482 
483 isc_result_t
isc_file_isplainfile(const char * filename)484 isc_file_isplainfile(const char *filename) {
485 	/*
486 	 * This function returns success if filename is a plain file.
487 	 */
488 	struct stat filestat;
489 	memset(&filestat,0,sizeof(struct stat));
490 
491 	if ((stat(filename, &filestat)) == -1)
492 		return(isc__errno2result(errno));
493 
494 	if(! S_ISREG(filestat.st_mode))
495 		return(ISC_R_INVALIDFILE);
496 
497 	return(ISC_R_SUCCESS);
498 }
499 
500 isc_result_t
isc_file_isplainfilefd(int fd)501 isc_file_isplainfilefd(int fd) {
502 	/*
503 	 * This function returns success if filename is a plain file.
504 	 */
505 	struct stat filestat;
506 	memset(&filestat,0,sizeof(struct stat));
507 
508 	if ((fstat(fd, &filestat)) == -1)
509 		return(isc__errno2result(errno));
510 
511 	if(! S_ISREG(filestat.st_mode))
512 		return(ISC_R_INVALIDFILE);
513 
514 	return(ISC_R_SUCCESS);
515 }
516 
517 isc_result_t
isc_file_isdirectory(const char * filename)518 isc_file_isdirectory(const char *filename) {
519 	/*
520 	 * This function returns success if filename is a directory.
521 	 */
522 	struct stat filestat;
523 	memset(&filestat,0,sizeof(struct stat));
524 
525 	if ((stat(filename, &filestat)) == -1)
526 		return(isc__errno2result(errno));
527 
528 	if(! S_ISDIR(filestat.st_mode))
529 		return(ISC_R_INVALIDFILE);
530 
531 	return(ISC_R_SUCCESS);
532 }
533 
534 
535 isc_boolean_t
isc_file_isabsolute(const char * filename)536 isc_file_isabsolute(const char *filename) {
537 	REQUIRE(filename != NULL);
538 	/*
539 	 * Look for c:\path\... style, c:/path/... or \\computer\shar\path...
540 	 * the UNC style file specs
541 	 */
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);
549 }
550 
551 isc_boolean_t
isc_file_iscurrentdir(const char * filename)552 isc_file_iscurrentdir(const char *filename) {
553 	REQUIRE(filename != NULL);
554 	return (ISC_TF(filename[0] == '.' && filename[1] == '\0'));
555 }
556 
557 isc_boolean_t
isc_file_ischdiridempotent(const char * filename)558 isc_file_ischdiridempotent(const char *filename) {
559 	REQUIRE(filename != NULL);
560 
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);
570 }
571 
572 const char *
isc_file_basename(const char * filename)573 isc_file_basename(const char *filename) {
574 	char *s;
575 
576 	REQUIRE(filename != NULL);
577 
578 	s = strrchr(filename, '\\');
579 	if (s == NULL)
580 		return (filename);
581 	return (s + 1);
582 }
583 
584 isc_result_t
isc_file_progname(const char * filename,char * progname,size_t namelen)585 isc_file_progname(const char *filename, char *progname, size_t namelen) {
586 	const char *s;
587 	char *p;
588 	size_t len;
589 
590 	REQUIRE(filename != NULL);
591 	REQUIRE(progname != NULL);
592 
593 	/*
594 	 * Strip the path from the name
595 	 */
596 	s = isc_file_basename(filename);
597 	if (s == NULL) {
598 		return (ISC_R_NOSPACE);
599 	}
600 
601 	/*
602 	 * Strip any and all suffixes
603 	 */
604 	p = strchr(s, '.');
605 	if (p == NULL) {
606 		if (namelen <= strlen(s))
607 			return (ISC_R_NOSPACE);
608 
609 		strcpy(progname, s);
610 		return (ISC_R_SUCCESS);
611 	}
612 
613 	/*
614 	 * Copy the result to the buffer
615 	 */
616 	len = p - s;
617 	if (len >= namelen)
618 		return (ISC_R_NOSPACE);
619 
620 	strncpy(progname, s, len);
621 	progname[len] = '\0';
622 	return (ISC_R_SUCCESS);
623 }
624 
625 isc_result_t
isc_file_absolutepath(const char * filename,char * path,size_t pathlen)626 isc_file_absolutepath(const char *filename, char *path, size_t pathlen) {
627 	char *ptrname;
628 	DWORD retval;
629 
630 	REQUIRE(filename != NULL);
631 	REQUIRE(path != NULL);
632 
633 	retval = GetFullPathName(filename, (DWORD) pathlen, path, &ptrname);
634 
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);
642 }
643 
644 isc_result_t
isc_file_truncate(const char * filename,isc_offset_t size)645 isc_file_truncate(const char *filename, isc_offset_t size) {
646 	int fh;
647 
648 	REQUIRE(filename != NULL && size >= 0);
649 
650 	if ((fh = open(filename, _O_RDWR | _O_BINARY)) < 0)
651 		return (isc__errno2result(errno));
652 
653 	if(_chsize(fh, size) != 0) {
654 		close(fh);
655 		return (isc__errno2result(errno));
656 	}
657 	close(fh);
658 
659 	return (ISC_R_SUCCESS);
660 }
661 
662 isc_result_t
isc_file_safecreate(const char * filename,FILE ** fp)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;
669 
670 	REQUIRE(filename != NULL);
671 	REQUIRE(fp != NULL && *fp == NULL);
672 
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);
682 
683 	fd = open(filename, flags, S_IRUSR | S_IWUSR);
684 	if (fd == -1)
685 		return (isc__errno2result(errno));
686 
687 	f = fdopen(fd, "w");
688 	if (f == NULL) {
689 		result = isc__errno2result(errno);
690 		close(fd);
691 		return (result);
692 	}
693 
694 	*fp = f;
695 	return (ISC_R_SUCCESS);
696 }
697 
698 isc_result_t
isc_file_splitpath(isc_mem_t * mctx,char * path,char ** dirname,char ** basename)699 isc_file_splitpath(isc_mem_t *mctx, char *path, char **dirname, char **basename)
700 {
701 	char *dir, *file, *slash;
702 	char *backslash;
703 
704 	slash = strrchr(path, '/');
705 
706 	backslash = strrchr(path, '\\');
707 	if ((slash != NULL && backslash != NULL && backslash > slash) ||
708 	    (slash == NULL && backslash != NULL))
709 		slash = backslash;
710 
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, ".");
722 	}
723 
724 	if (dir == NULL)
725 		return (ISC_R_NOMEMORY);
726 
727 	if (*file == '\0') {
728 		isc_mem_free(mctx, dir);
729 		return (ISC_R_INVALIDFILE);
730 	}
731 
732 	*dirname = dir;
733 	*basename = file;
734 
735 	return (ISC_R_SUCCESS);
736 }
737 
738 void *
isc_file_mmap(void * addr,size_t len,int prot,int flags,int fd,off_t offset)739 isc_file_mmap(void *addr, size_t len, int prot,
740 	      int flags, int fd, off_t offset)
741 {
742 	void *buf;
743 	ssize_t ret;
744 	off_t end;
745 
746 	UNUSED(addr);
747 	UNUSED(prot);
748 	UNUSED(flags);
749 
750 	end = lseek(fd, 0, SEEK_END);
751 	lseek(fd, offset, SEEK_SET);
752 	if (end - offset < (off_t) len)
753 		len = end - offset;
754 
755 	buf = malloc(len);
756 	ret = read(fd, buf, (unsigned int) len);
757 	if (ret != (ssize_t) len) {
758 		free(buf);
759 		buf = NULL;
760 	}
761 
762 	return (buf);
763 }
764 
765 int
isc_file_munmap(void * addr,size_t len)766 isc_file_munmap(void *addr, size_t len) {
767 	UNUSED(len);
768 	free(addr);
769 	return (0);
770 }
771