/src/ntp-dev/lib/isc/unix/file.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2004, 2005, 2007, 2009, 2011, 2012 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$ */ |
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/mem.h> |
72 | | #include <isc/random.h> |
73 | | #include <isc/string.h> |
74 | | #include <isc/time.h> |
75 | | #include <isc/util.h> |
76 | | |
77 | | #include "errno2result.h" |
78 | | #include "ntp_stdlib.h" /* NTP change for strlcpy, strlcat */ |
79 | | |
80 | | /* |
81 | | * XXXDCL As the API for accessing file statistics undoubtedly gets expanded, |
82 | | * it might be good to provide a mechanism that allows for the results |
83 | | * of a previous stat() to be used again without having to do another stat, |
84 | | * such as perl's mechanism of using "_" in place of a file name to indicate |
85 | | * that the results of the last stat should be used. But then you get into |
86 | | * annoying MP issues. BTW, Win32 has stat(). |
87 | | */ |
88 | | static isc_result_t |
89 | 0 | file_stats(const char *file, struct stat *stats) { |
90 | 0 | isc_result_t result = ISC_R_SUCCESS; |
91 | |
|
92 | 0 | REQUIRE(file != NULL); |
93 | 0 | REQUIRE(stats != NULL); |
94 | | |
95 | 0 | if (stat(file, stats) != 0) |
96 | 0 | result = isc__errno2result(errno); |
97 | |
|
98 | 0 | return (result); |
99 | 0 | } |
100 | | |
101 | | isc_result_t |
102 | 0 | isc_file_getmodtime(const char *file, isc_time_t *itime) { |
103 | 0 | isc_result_t result; |
104 | 0 | struct stat stats; |
105 | |
|
106 | 0 | REQUIRE(file != NULL); |
107 | 0 | REQUIRE(itime != NULL); |
108 | | |
109 | 0 | result = file_stats(file, &stats); |
110 | |
|
111 | 0 | if (result == ISC_R_SUCCESS) |
112 | | /* |
113 | | * XXXDCL some operating systems provide nanoseconds, too, |
114 | | * such as BSD/OS via st_mtimespec. |
115 | | */ |
116 | 0 | isc_time_set(itime, stats.st_mtime, 0); |
117 | |
|
118 | 0 | return (result); |
119 | 0 | } |
120 | | |
121 | | isc_result_t |
122 | 0 | isc_file_settime(const char *file, isc_time_t *itime) { |
123 | 0 | struct timeval times[2]; |
124 | |
|
125 | 0 | REQUIRE(file != NULL && itime != NULL); |
126 | | |
127 | | /* |
128 | | * tv_sec is at least a 32 bit quantity on all platforms we're |
129 | | * dealing with, but it is signed on most (all?) of them, |
130 | | * so we need to make sure the high bit isn't set. This unfortunately |
131 | | * loses when either: |
132 | | * * tv_sec becomes a signed 64 bit integer but long is 32 bits |
133 | | * and isc_time_seconds > LONG_MAX, or |
134 | | * * isc_time_seconds is changed to be > 32 bits but long is 32 bits |
135 | | * and isc_time_seconds has at least 33 significant bits. |
136 | | */ |
137 | 0 | times[0].tv_sec = times[1].tv_sec = (long)isc_time_seconds(itime); |
138 | | |
139 | | /* |
140 | | * Here is the real check for the high bit being set. |
141 | | */ |
142 | 0 | if ((times[0].tv_sec & |
143 | 0 | (1ULL << (sizeof(times[0].tv_sec) * CHAR_BIT - 1))) != 0) |
144 | 0 | return (ISC_R_RANGE); |
145 | | |
146 | | /* |
147 | | * isc_time_nanoseconds guarantees a value that divided by 1000 will |
148 | | * fit into the minimum possible size tv_usec field. Unfortunately, |
149 | | * we don't know what that type is so can't cast directly ... but |
150 | | * we can at least cast to signed so the IRIX compiler shuts up. |
151 | | */ |
152 | 0 | times[0].tv_usec = times[1].tv_usec = |
153 | 0 | (isc_int32_t)(isc_time_nanoseconds(itime) / 1000); |
154 | |
|
155 | 0 | if (utimes(file, times) < 0) |
156 | 0 | return (isc__errno2result(errno)); |
157 | | |
158 | 0 | return (ISC_R_SUCCESS); |
159 | 0 | } |
160 | | |
161 | | #undef TEMPLATE |
162 | 0 | #define TEMPLATE "tmp-XXXXXXXXXX" /*%< 14 characters. */ |
163 | | |
164 | | isc_result_t |
165 | 0 | isc_file_mktemplate(const char *path, char *buf, size_t buflen) { |
166 | 0 | return (isc_file_template(path, TEMPLATE, buf, buflen)); |
167 | 0 | } |
168 | | |
169 | | isc_result_t |
170 | | isc_file_template(const char *path, const char *templet, char *buf, |
171 | 0 | size_t buflen) { |
172 | 0 | char *s; |
173 | |
|
174 | 0 | REQUIRE(path != NULL); |
175 | 0 | REQUIRE(templet != NULL); |
176 | 0 | REQUIRE(buf != NULL); |
177 | | |
178 | 0 | s = strrchr(templet, '/'); |
179 | 0 | if (s != NULL) |
180 | 0 | templet = s + 1; |
181 | |
|
182 | 0 | s = strrchr(path, '/'); |
183 | |
|
184 | 0 | if (s != NULL) { |
185 | 0 | if ((s - path + 1 + strlen(templet) + 1) > buflen) |
186 | 0 | return (ISC_R_NOSPACE); |
187 | | |
188 | 0 | strlcpy(buf, path, buflen); |
189 | 0 | buf[s - path + 1] = '\0'; |
190 | 0 | strlcat(buf, templet, buflen); |
191 | 0 | } else { |
192 | 0 | if ((strlen(templet) + 1) > buflen) |
193 | 0 | return (ISC_R_NOSPACE); |
194 | | |
195 | 0 | strlcpy(buf, templet, buflen); |
196 | 0 | } |
197 | | |
198 | 0 | return (ISC_R_SUCCESS); |
199 | 0 | } |
200 | | |
201 | | static char alphnum[] = |
202 | | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; |
203 | | |
204 | | isc_result_t |
205 | 0 | isc_file_renameunique(const char *file, char *templet) { |
206 | 0 | char *x; |
207 | 0 | char *cp; |
208 | 0 | isc_uint32_t which; |
209 | |
|
210 | 0 | REQUIRE(file != NULL); |
211 | 0 | REQUIRE(templet != NULL); |
212 | | |
213 | 0 | cp = templet; |
214 | 0 | while (*cp != '\0') |
215 | 0 | cp++; |
216 | 0 | if (cp == templet) |
217 | 0 | return (ISC_R_FAILURE); |
218 | | |
219 | 0 | x = cp--; |
220 | 0 | while (cp >= templet && *cp == 'X') { |
221 | 0 | isc_random_get(&which); |
222 | 0 | *cp = alphnum[which % (sizeof(alphnum) - 1)]; |
223 | 0 | x = cp--; |
224 | 0 | } |
225 | 0 | while (link(file, templet) == -1) { |
226 | 0 | if (errno != EEXIST) |
227 | 0 | return (isc__errno2result(errno)); |
228 | 0 | for (cp = x;;) { |
229 | 0 | char *t; |
230 | 0 | if (*cp == '\0') |
231 | 0 | return (ISC_R_FAILURE); |
232 | 0 | t = strchr(alphnum, *cp); |
233 | 0 | if (t == NULL || *++t == '\0') |
234 | 0 | *cp++ = alphnum[0]; |
235 | 0 | else { |
236 | 0 | *cp = *t; |
237 | 0 | break; |
238 | 0 | } |
239 | 0 | } |
240 | 0 | } |
241 | 0 | if (unlink(file) < 0) |
242 | 0 | if (errno != ENOENT) |
243 | 0 | return (isc__errno2result(errno)); |
244 | 0 | return (ISC_R_SUCCESS); |
245 | 0 | } |
246 | | |
247 | | isc_result_t |
248 | 0 | isc_file_openunique(char *templet, FILE **fp) { |
249 | 0 | int mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; |
250 | 0 | return (isc_file_openuniquemode(templet, mode, fp)); |
251 | 0 | } |
252 | | |
253 | | isc_result_t |
254 | 0 | isc_file_openuniqueprivate(char *templet, FILE **fp) { |
255 | 0 | int mode = S_IWUSR|S_IRUSR; |
256 | 0 | return (isc_file_openuniquemode(templet, mode, fp)); |
257 | 0 | } |
258 | | |
259 | | isc_result_t |
260 | 0 | isc_file_openuniquemode(char *templet, int mode, FILE **fp) { |
261 | 0 | int fd; |
262 | 0 | FILE *f; |
263 | 0 | isc_result_t result = ISC_R_SUCCESS; |
264 | 0 | char *x; |
265 | 0 | char *cp; |
266 | 0 | isc_uint32_t which; |
267 | |
|
268 | 0 | REQUIRE(templet != NULL); |
269 | 0 | REQUIRE(fp != NULL && *fp == NULL); |
270 | | |
271 | 0 | cp = templet; |
272 | 0 | while (*cp != '\0') |
273 | 0 | cp++; |
274 | 0 | if (cp == templet) |
275 | 0 | return (ISC_R_FAILURE); |
276 | | |
277 | 0 | x = cp--; |
278 | 0 | while (cp >= templet && *cp == 'X') { |
279 | 0 | isc_random_get(&which); |
280 | 0 | *cp = alphnum[which % (sizeof(alphnum) - 1)]; |
281 | 0 | x = cp--; |
282 | 0 | } |
283 | | |
284 | |
|
285 | 0 | while ((fd = open(templet, O_RDWR|O_CREAT|O_EXCL, mode)) == -1) { |
286 | 0 | if (errno != EEXIST) |
287 | 0 | return (isc__errno2result(errno)); |
288 | 0 | for (cp = x;;) { |
289 | 0 | char *t; |
290 | 0 | if (*cp == '\0') |
291 | 0 | return (ISC_R_FAILURE); |
292 | 0 | t = strchr(alphnum, *cp); |
293 | 0 | if (t == NULL || *++t == '\0') |
294 | 0 | *cp++ = alphnum[0]; |
295 | 0 | else { |
296 | 0 | *cp = *t; |
297 | 0 | break; |
298 | 0 | } |
299 | 0 | } |
300 | 0 | } |
301 | 0 | f = fdopen(fd, "w+"); |
302 | 0 | if (f == NULL) { |
303 | 0 | result = isc__errno2result(errno); |
304 | 0 | if (remove(templet) < 0) { |
305 | 0 | isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, |
306 | 0 | ISC_LOGMODULE_FILE, ISC_LOG_ERROR, |
307 | 0 | "remove '%s': failed", templet); |
308 | 0 | } |
309 | 0 | (void)close(fd); |
310 | 0 | } else |
311 | 0 | *fp = f; |
312 | |
|
313 | 0 | return (result); |
314 | 0 | } |
315 | | |
316 | | isc_result_t |
317 | 0 | isc_file_remove(const char *filename) { |
318 | 0 | int r; |
319 | |
|
320 | 0 | REQUIRE(filename != NULL); |
321 | | |
322 | 0 | r = unlink(filename); |
323 | 0 | if (r == 0) |
324 | 0 | return (ISC_R_SUCCESS); |
325 | 0 | else |
326 | 0 | return (isc__errno2result(errno)); |
327 | 0 | } |
328 | | |
329 | | isc_result_t |
330 | 0 | isc_file_rename(const char *oldname, const char *newname) { |
331 | 0 | int r; |
332 | |
|
333 | 0 | REQUIRE(oldname != NULL); |
334 | 0 | REQUIRE(newname != NULL); |
335 | | |
336 | 0 | r = rename(oldname, newname); |
337 | 0 | if (r == 0) |
338 | 0 | return (ISC_R_SUCCESS); |
339 | 0 | else |
340 | 0 | return (isc__errno2result(errno)); |
341 | 0 | } |
342 | | |
343 | | isc_boolean_t |
344 | 0 | isc_file_exists(const char *pathname) { |
345 | 0 | struct stat stats; |
346 | |
|
347 | 0 | REQUIRE(pathname != NULL); |
348 | | |
349 | 0 | return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS)); |
350 | 0 | } |
351 | | |
352 | | isc_result_t |
353 | 0 | isc_file_isplainfile(const char *filename) { |
354 | | /* |
355 | | * This function returns success if filename is a plain file. |
356 | | */ |
357 | 0 | struct stat filestat; |
358 | 0 | memset(&filestat,0,sizeof(struct stat)); |
359 | |
|
360 | 0 | if ((stat(filename, &filestat)) == -1) |
361 | 0 | return(isc__errno2result(errno)); |
362 | | |
363 | 0 | if(! S_ISREG(filestat.st_mode)) |
364 | 0 | return(ISC_R_INVALIDFILE); |
365 | | |
366 | 0 | return(ISC_R_SUCCESS); |
367 | 0 | } |
368 | | |
369 | | isc_boolean_t |
370 | 0 | isc_file_isabsolute(const char *filename) { |
371 | 0 | REQUIRE(filename != NULL); |
372 | 0 | return (ISC_TF(filename[0] == '/')); |
373 | 0 | } |
374 | | |
375 | | isc_boolean_t |
376 | 0 | isc_file_iscurrentdir(const char *filename) { |
377 | 0 | REQUIRE(filename != NULL); |
378 | 0 | return (ISC_TF(filename[0] == '.' && filename[1] == '\0')); |
379 | 0 | } |
380 | | |
381 | | isc_boolean_t |
382 | 0 | isc_file_ischdiridempotent(const char *filename) { |
383 | 0 | REQUIRE(filename != NULL); |
384 | 0 | if (isc_file_isabsolute(filename)) |
385 | 0 | return (ISC_TRUE); |
386 | 0 | if (isc_file_iscurrentdir(filename)) |
387 | 0 | return (ISC_TRUE); |
388 | 0 | return (ISC_FALSE); |
389 | 0 | } |
390 | | |
391 | | const char * |
392 | 0 | isc_file_basename(const char *filename) { |
393 | 0 | char *s; |
394 | |
|
395 | 0 | REQUIRE(filename != NULL); |
396 | | |
397 | 0 | s = strrchr(filename, '/'); |
398 | 0 | if (s == NULL) |
399 | 0 | return (filename); |
400 | | |
401 | 0 | return (s + 1); |
402 | 0 | } |
403 | | |
404 | | isc_result_t |
405 | 0 | isc_file_progname(const char *filename, char *buf, size_t buflen) { |
406 | 0 | const char *base; |
407 | 0 | size_t len; |
408 | |
|
409 | 0 | REQUIRE(filename != NULL); |
410 | 0 | REQUIRE(buf != NULL); |
411 | | |
412 | 0 | base = isc_file_basename(filename); |
413 | 0 | len = strlen(base) + 1; |
414 | |
|
415 | 0 | if (len > buflen) |
416 | 0 | return (ISC_R_NOSPACE); |
417 | 0 | memcpy(buf, base, len); |
418 | |
|
419 | 0 | return (ISC_R_SUCCESS); |
420 | 0 | } |
421 | | |
422 | | /* |
423 | | * Put the absolute name of the current directory into 'dirname', which is |
424 | | * a buffer of at least 'length' characters. End the string with the |
425 | | * appropriate path separator, such that the final product could be |
426 | | * concatenated with a relative pathname to make a valid pathname string. |
427 | | */ |
428 | | static isc_result_t |
429 | 0 | dir_current(char *dirname, size_t length) { |
430 | 0 | char *cwd; |
431 | 0 | isc_result_t result = ISC_R_SUCCESS; |
432 | |
|
433 | 0 | REQUIRE(dirname != NULL); |
434 | 0 | REQUIRE(length > 0U); |
435 | | |
436 | 0 | cwd = getcwd(dirname, length); |
437 | |
|
438 | 0 | if (cwd == NULL) { |
439 | 0 | if (errno == ERANGE) |
440 | 0 | result = ISC_R_NOSPACE; |
441 | 0 | else |
442 | 0 | result = isc__errno2result(errno); |
443 | 0 | } else { |
444 | 0 | if (strlen(dirname) + 1 == length) |
445 | 0 | result = ISC_R_NOSPACE; |
446 | 0 | else if (dirname[1] != '\0') |
447 | 0 | strlcat(dirname, "/", length); |
448 | 0 | } |
449 | |
|
450 | 0 | return (result); |
451 | 0 | } |
452 | | |
453 | | isc_result_t |
454 | 0 | isc_file_absolutepath(const char *filename, char *path, size_t pathlen) { |
455 | 0 | isc_result_t result; |
456 | 0 | result = dir_current(path, pathlen); |
457 | 0 | if (result != ISC_R_SUCCESS) |
458 | 0 | return (result); |
459 | 0 | if (strlen(path) + strlen(filename) + 1 > pathlen) |
460 | 0 | return (ISC_R_NOSPACE); |
461 | 0 | strlcat(path, filename, pathlen); |
462 | 0 | return (ISC_R_SUCCESS); |
463 | 0 | } |
464 | | |
465 | | isc_result_t |
466 | 0 | isc_file_truncate(const char *filename, isc_offset_t size) { |
467 | 0 | isc_result_t result = ISC_R_SUCCESS; |
468 | |
|
469 | 0 | if (truncate(filename, size) < 0) |
470 | 0 | result = isc__errno2result(errno); |
471 | 0 | return (result); |
472 | 0 | } |
473 | | |
474 | | isc_result_t |
475 | 0 | isc_file_safecreate(const char *filename, FILE **fp) { |
476 | 0 | isc_result_t result; |
477 | 0 | int flags; |
478 | 0 | struct stat sb; |
479 | 0 | FILE *f; |
480 | 0 | int fd; |
481 | |
|
482 | 0 | REQUIRE(filename != NULL); |
483 | 0 | REQUIRE(fp != NULL && *fp == NULL); |
484 | | |
485 | 0 | result = file_stats(filename, &sb); |
486 | 0 | if (result == ISC_R_SUCCESS) { |
487 | 0 | if ((sb.st_mode & S_IFREG) == 0) |
488 | 0 | return (ISC_R_INVALIDFILE); |
489 | 0 | flags = O_WRONLY | O_TRUNC; |
490 | 0 | } else if (result == ISC_R_FILENOTFOUND) { |
491 | 0 | flags = O_WRONLY | O_CREAT | O_EXCL; |
492 | 0 | } else |
493 | 0 | return (result); |
494 | | |
495 | 0 | fd = open(filename, flags, S_IRUSR | S_IWUSR); |
496 | 0 | if (fd == -1) |
497 | 0 | return (isc__errno2result(errno)); |
498 | | |
499 | 0 | f = fdopen(fd, "w"); |
500 | 0 | if (f == NULL) { |
501 | 0 | result = isc__errno2result(errno); |
502 | 0 | close(fd); |
503 | 0 | return (result); |
504 | 0 | } |
505 | | |
506 | 0 | *fp = f; |
507 | 0 | return (ISC_R_SUCCESS); |
508 | 0 | } |
509 | | |
510 | | isc_result_t |
511 | | isc_file_splitpath(isc_mem_t *mctx, char *path, char **dirnam, char **basenam) |
512 | 0 | { |
513 | 0 | char *dir, *file, *slash; |
514 | |
|
515 | 0 | REQUIRE(path != NULL); |
516 | | |
517 | 0 | slash = strrchr(path, '/'); |
518 | |
|
519 | 0 | if (slash == path) { |
520 | 0 | file = ++slash; |
521 | 0 | dir = isc_mem_strdup(mctx, "/"); |
522 | 0 | } else if (slash != NULL) { |
523 | 0 | file = ++slash; |
524 | 0 | dir = isc_mem_allocate(mctx, slash - path); |
525 | 0 | if (dir != NULL) |
526 | 0 | strlcpy(dir, path, slash - path); |
527 | 0 | } else { |
528 | 0 | file = path; |
529 | 0 | dir = isc_mem_strdup(mctx, "."); |
530 | 0 | } |
531 | |
|
532 | 0 | if (dir == NULL) |
533 | 0 | return (ISC_R_NOMEMORY); |
534 | | |
535 | 0 | if (*file == '\0') { |
536 | 0 | isc_mem_free(mctx, dir); |
537 | 0 | return (ISC_R_INVALIDFILE); |
538 | 0 | } |
539 | | |
540 | 0 | *dirnam = dir; |
541 | 0 | *basenam = file; |
542 | |
|
543 | 0 | return (ISC_R_SUCCESS); |
544 | 0 | } |