1*a466cc55SCy Schubert /*
2*a466cc55SCy Schubert * Copyright (C) 2004, 2005, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC")
3*a466cc55SCy Schubert * Copyright (C) 2000-2002 Internet Software Consortium.
4*a466cc55SCy Schubert *
5*a466cc55SCy Schubert * Permission to use, copy, modify, and/or distribute this software for any
6*a466cc55SCy Schubert * purpose with or without fee is hereby granted, provided that the above
7*a466cc55SCy Schubert * copyright notice and this permission notice appear in all copies.
8*a466cc55SCy Schubert *
9*a466cc55SCy Schubert * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10*a466cc55SCy Schubert * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11*a466cc55SCy Schubert * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12*a466cc55SCy Schubert * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13*a466cc55SCy Schubert * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14*a466cc55SCy Schubert * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15*a466cc55SCy Schubert * PERFORMANCE OF THIS SOFTWARE.
16*a466cc55SCy Schubert */
17*a466cc55SCy Schubert
18*a466cc55SCy Schubert /*
19*a466cc55SCy Schubert * Portions Copyright (c) 1987, 1993
20*a466cc55SCy Schubert * The Regents of the University of California. All rights reserved.
21*a466cc55SCy Schubert *
22*a466cc55SCy Schubert * Redistribution and use in source and binary forms, with or without
23*a466cc55SCy Schubert * modification, are permitted provided that the following conditions
24*a466cc55SCy Schubert * are met:
25*a466cc55SCy Schubert * 1. Redistributions of source code must retain the above copyright
26*a466cc55SCy Schubert * notice, this list of conditions and the following disclaimer.
27*a466cc55SCy Schubert * 2. Redistributions in binary form must reproduce the above copyright
28*a466cc55SCy Schubert * notice, this list of conditions and the following disclaimer in the
29*a466cc55SCy Schubert * documentation and/or other materials provided with the distribution.
30*a466cc55SCy Schubert * 3. All advertising materials mentioning features or use of this software
31*a466cc55SCy Schubert * must display the following acknowledgement:
32*a466cc55SCy Schubert * This product includes software developed by the University of
33*a466cc55SCy Schubert * California, Berkeley and its contributors.
34*a466cc55SCy Schubert * 4. Neither the name of the University nor the names of its contributors
35*a466cc55SCy Schubert * may be used to endorse or promote products derived from this software
36*a466cc55SCy Schubert * without specific prior written permission.
37*a466cc55SCy Schubert *
38*a466cc55SCy Schubert * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
39*a466cc55SCy Schubert * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40*a466cc55SCy Schubert * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41*a466cc55SCy Schubert * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
42*a466cc55SCy Schubert * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43*a466cc55SCy Schubert * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44*a466cc55SCy Schubert * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45*a466cc55SCy Schubert * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46*a466cc55SCy Schubert * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47*a466cc55SCy Schubert * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48*a466cc55SCy Schubert * SUCH DAMAGE.
49*a466cc55SCy Schubert */
50*a466cc55SCy Schubert
51*a466cc55SCy Schubert /* $Id$ */
52*a466cc55SCy Schubert
53*a466cc55SCy Schubert /*! \file */
54*a466cc55SCy Schubert
55*a466cc55SCy Schubert #include <config.h>
56*a466cc55SCy Schubert
57*a466cc55SCy Schubert #include <errno.h>
58*a466cc55SCy Schubert #include <fcntl.h>
59*a466cc55SCy Schubert #include <limits.h>
60*a466cc55SCy Schubert #include <stdlib.h>
61*a466cc55SCy Schubert #include <time.h> /* Required for utimes on some platforms. */
62*a466cc55SCy Schubert #include <unistd.h> /* Required for mkstemp on NetBSD. */
63*a466cc55SCy Schubert
64*a466cc55SCy Schubert
65*a466cc55SCy Schubert #include <sys/stat.h>
66*a466cc55SCy Schubert #include <sys/time.h>
67*a466cc55SCy Schubert
68*a466cc55SCy Schubert #include <isc/dir.h>
69*a466cc55SCy Schubert #include <isc/file.h>
70*a466cc55SCy Schubert #include <isc/log.h>
71*a466cc55SCy Schubert #include <isc/mem.h>
72*a466cc55SCy Schubert #include <isc/random.h>
73*a466cc55SCy Schubert #include <isc/string.h>
74*a466cc55SCy Schubert #include <isc/time.h>
75*a466cc55SCy Schubert #include <isc/util.h>
76*a466cc55SCy Schubert
77*a466cc55SCy Schubert #include "errno2result.h"
78*a466cc55SCy Schubert #include "ntp_stdlib.h" /* NTP change for strlcpy, strlcat */
79*a466cc55SCy Schubert
80*a466cc55SCy Schubert /*
81*a466cc55SCy Schubert * XXXDCL As the API for accessing file statistics undoubtedly gets expanded,
82*a466cc55SCy Schubert * it might be good to provide a mechanism that allows for the results
83*a466cc55SCy Schubert * of a previous stat() to be used again without having to do another stat,
84*a466cc55SCy Schubert * such as perl's mechanism of using "_" in place of a file name to indicate
85*a466cc55SCy Schubert * that the results of the last stat should be used. But then you get into
86*a466cc55SCy Schubert * annoying MP issues. BTW, Win32 has stat().
87*a466cc55SCy Schubert */
88*a466cc55SCy Schubert static isc_result_t
file_stats(const char * file,struct stat * stats)89*a466cc55SCy Schubert file_stats(const char *file, struct stat *stats) {
90*a466cc55SCy Schubert isc_result_t result = ISC_R_SUCCESS;
91*a466cc55SCy Schubert
92*a466cc55SCy Schubert REQUIRE(file != NULL);
93*a466cc55SCy Schubert REQUIRE(stats != NULL);
94*a466cc55SCy Schubert
95*a466cc55SCy Schubert if (stat(file, stats) != 0)
96*a466cc55SCy Schubert result = isc__errno2result(errno);
97*a466cc55SCy Schubert
98*a466cc55SCy Schubert return (result);
99*a466cc55SCy Schubert }
100*a466cc55SCy Schubert
101*a466cc55SCy Schubert isc_result_t
isc_file_getmodtime(const char * file,isc_time_t * itime)102*a466cc55SCy Schubert isc_file_getmodtime(const char *file, isc_time_t *itime) {
103*a466cc55SCy Schubert isc_result_t result;
104*a466cc55SCy Schubert struct stat stats;
105*a466cc55SCy Schubert
106*a466cc55SCy Schubert REQUIRE(file != NULL);
107*a466cc55SCy Schubert REQUIRE(itime != NULL);
108*a466cc55SCy Schubert
109*a466cc55SCy Schubert result = file_stats(file, &stats);
110*a466cc55SCy Schubert
111*a466cc55SCy Schubert if (result == ISC_R_SUCCESS)
112*a466cc55SCy Schubert /*
113*a466cc55SCy Schubert * XXXDCL some operating systems provide nanoseconds, too,
114*a466cc55SCy Schubert * such as BSD/OS via st_mtimespec.
115*a466cc55SCy Schubert */
116*a466cc55SCy Schubert isc_time_set(itime, stats.st_mtime, 0);
117*a466cc55SCy Schubert
118*a466cc55SCy Schubert return (result);
119*a466cc55SCy Schubert }
120*a466cc55SCy Schubert
121*a466cc55SCy Schubert isc_result_t
isc_file_settime(const char * file,isc_time_t * itime)122*a466cc55SCy Schubert isc_file_settime(const char *file, isc_time_t *itime) {
123*a466cc55SCy Schubert struct timeval times[2];
124*a466cc55SCy Schubert
125*a466cc55SCy Schubert REQUIRE(file != NULL && itime != NULL);
126*a466cc55SCy Schubert
127*a466cc55SCy Schubert /*
128*a466cc55SCy Schubert * tv_sec is at least a 32 bit quantity on all platforms we're
129*a466cc55SCy Schubert * dealing with, but it is signed on most (all?) of them,
130*a466cc55SCy Schubert * so we need to make sure the high bit isn't set. This unfortunately
131*a466cc55SCy Schubert * loses when either:
132*a466cc55SCy Schubert * * tv_sec becomes a signed 64 bit integer but long is 32 bits
133*a466cc55SCy Schubert * and isc_time_seconds > LONG_MAX, or
134*a466cc55SCy Schubert * * isc_time_seconds is changed to be > 32 bits but long is 32 bits
135*a466cc55SCy Schubert * and isc_time_seconds has at least 33 significant bits.
136*a466cc55SCy Schubert */
137*a466cc55SCy Schubert times[0].tv_sec = times[1].tv_sec = (long)isc_time_seconds(itime);
138*a466cc55SCy Schubert
139*a466cc55SCy Schubert /*
140*a466cc55SCy Schubert * Here is the real check for the high bit being set.
141*a466cc55SCy Schubert */
142*a466cc55SCy Schubert if ((times[0].tv_sec &
143*a466cc55SCy Schubert (1ULL << (sizeof(times[0].tv_sec) * CHAR_BIT - 1))) != 0)
144*a466cc55SCy Schubert return (ISC_R_RANGE);
145*a466cc55SCy Schubert
146*a466cc55SCy Schubert /*
147*a466cc55SCy Schubert * isc_time_nanoseconds guarantees a value that divided by 1000 will
148*a466cc55SCy Schubert * fit into the minimum possible size tv_usec field. Unfortunately,
149*a466cc55SCy Schubert * we don't know what that type is so can't cast directly ... but
150*a466cc55SCy Schubert * we can at least cast to signed so the IRIX compiler shuts up.
151*a466cc55SCy Schubert */
152*a466cc55SCy Schubert times[0].tv_usec = times[1].tv_usec =
153*a466cc55SCy Schubert (isc_int32_t)(isc_time_nanoseconds(itime) / 1000);
154*a466cc55SCy Schubert
155*a466cc55SCy Schubert if (utimes(file, times) < 0)
156*a466cc55SCy Schubert return (isc__errno2result(errno));
157*a466cc55SCy Schubert
158*a466cc55SCy Schubert return (ISC_R_SUCCESS);
159*a466cc55SCy Schubert }
160*a466cc55SCy Schubert
161*a466cc55SCy Schubert #undef TEMPLATE
162*a466cc55SCy Schubert #define TEMPLATE "tmp-XXXXXXXXXX" /*%< 14 characters. */
163*a466cc55SCy Schubert
164*a466cc55SCy Schubert isc_result_t
isc_file_mktemplate(const char * path,char * buf,size_t buflen)165*a466cc55SCy Schubert isc_file_mktemplate(const char *path, char *buf, size_t buflen) {
166*a466cc55SCy Schubert return (isc_file_template(path, TEMPLATE, buf, buflen));
167*a466cc55SCy Schubert }
168*a466cc55SCy Schubert
169*a466cc55SCy Schubert isc_result_t
isc_file_template(const char * path,const char * templet,char * buf,size_t buflen)170*a466cc55SCy Schubert isc_file_template(const char *path, const char *templet, char *buf,
171*a466cc55SCy Schubert size_t buflen) {
172*a466cc55SCy Schubert char *s;
173*a466cc55SCy Schubert
174*a466cc55SCy Schubert REQUIRE(path != NULL);
175*a466cc55SCy Schubert REQUIRE(templet != NULL);
176*a466cc55SCy Schubert REQUIRE(buf != NULL);
177*a466cc55SCy Schubert
178*a466cc55SCy Schubert s = strrchr(templet, '/');
179*a466cc55SCy Schubert if (s != NULL)
180*a466cc55SCy Schubert templet = s + 1;
181*a466cc55SCy Schubert
182*a466cc55SCy Schubert s = strrchr(path, '/');
183*a466cc55SCy Schubert
184*a466cc55SCy Schubert if (s != NULL) {
185*a466cc55SCy Schubert if ((s - path + 1 + strlen(templet) + 1) > buflen)
186*a466cc55SCy Schubert return (ISC_R_NOSPACE);
187*a466cc55SCy Schubert
188*a466cc55SCy Schubert strlcpy(buf, path, buflen);
189*a466cc55SCy Schubert buf[s - path + 1] = '\0';
190*a466cc55SCy Schubert strlcat(buf, templet, buflen);
191*a466cc55SCy Schubert } else {
192*a466cc55SCy Schubert if ((strlen(templet) + 1) > buflen)
193*a466cc55SCy Schubert return (ISC_R_NOSPACE);
194*a466cc55SCy Schubert
195*a466cc55SCy Schubert strlcpy(buf, templet, buflen);
196*a466cc55SCy Schubert }
197*a466cc55SCy Schubert
198*a466cc55SCy Schubert return (ISC_R_SUCCESS);
199*a466cc55SCy Schubert }
200*a466cc55SCy Schubert
201*a466cc55SCy Schubert static char alphnum[] =
202*a466cc55SCy Schubert "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
203*a466cc55SCy Schubert
204*a466cc55SCy Schubert isc_result_t
isc_file_renameunique(const char * file,char * templet)205*a466cc55SCy Schubert isc_file_renameunique(const char *file, char *templet) {
206*a466cc55SCy Schubert char *x;
207*a466cc55SCy Schubert char *cp;
208*a466cc55SCy Schubert isc_uint32_t which;
209*a466cc55SCy Schubert
210*a466cc55SCy Schubert REQUIRE(file != NULL);
211*a466cc55SCy Schubert REQUIRE(templet != NULL);
212*a466cc55SCy Schubert
213*a466cc55SCy Schubert cp = templet;
214*a466cc55SCy Schubert while (*cp != '\0')
215*a466cc55SCy Schubert cp++;
216*a466cc55SCy Schubert if (cp == templet)
217*a466cc55SCy Schubert return (ISC_R_FAILURE);
218*a466cc55SCy Schubert
219*a466cc55SCy Schubert x = cp--;
220*a466cc55SCy Schubert while (cp >= templet && *cp == 'X') {
221*a466cc55SCy Schubert isc_random_get(&which);
222*a466cc55SCy Schubert *cp = alphnum[which % (sizeof(alphnum) - 1)];
223*a466cc55SCy Schubert x = cp--;
224*a466cc55SCy Schubert }
225*a466cc55SCy Schubert while (link(file, templet) == -1) {
226*a466cc55SCy Schubert if (errno != EEXIST)
227*a466cc55SCy Schubert return (isc__errno2result(errno));
228*a466cc55SCy Schubert for (cp = x;;) {
229*a466cc55SCy Schubert char *t;
230*a466cc55SCy Schubert if (*cp == '\0')
231*a466cc55SCy Schubert return (ISC_R_FAILURE);
232*a466cc55SCy Schubert t = strchr(alphnum, *cp);
233*a466cc55SCy Schubert if (t == NULL || *++t == '\0')
234*a466cc55SCy Schubert *cp++ = alphnum[0];
235*a466cc55SCy Schubert else {
236*a466cc55SCy Schubert *cp = *t;
237*a466cc55SCy Schubert break;
238*a466cc55SCy Schubert }
239*a466cc55SCy Schubert }
240*a466cc55SCy Schubert }
241*a466cc55SCy Schubert if (unlink(file) < 0)
242*a466cc55SCy Schubert if (errno != ENOENT)
243*a466cc55SCy Schubert return (isc__errno2result(errno));
244*a466cc55SCy Schubert return (ISC_R_SUCCESS);
245*a466cc55SCy Schubert }
246*a466cc55SCy Schubert
247*a466cc55SCy Schubert isc_result_t
isc_file_openunique(char * templet,FILE ** fp)248*a466cc55SCy Schubert isc_file_openunique(char *templet, FILE **fp) {
249*a466cc55SCy Schubert int mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
250*a466cc55SCy Schubert return (isc_file_openuniquemode(templet, mode, fp));
251*a466cc55SCy Schubert }
252*a466cc55SCy Schubert
253*a466cc55SCy Schubert isc_result_t
isc_file_openuniqueprivate(char * templet,FILE ** fp)254*a466cc55SCy Schubert isc_file_openuniqueprivate(char *templet, FILE **fp) {
255*a466cc55SCy Schubert int mode = S_IWUSR|S_IRUSR;
256*a466cc55SCy Schubert return (isc_file_openuniquemode(templet, mode, fp));
257*a466cc55SCy Schubert }
258*a466cc55SCy Schubert
259*a466cc55SCy Schubert isc_result_t
isc_file_openuniquemode(char * templet,int mode,FILE ** fp)260*a466cc55SCy Schubert isc_file_openuniquemode(char *templet, int mode, FILE **fp) {
261*a466cc55SCy Schubert int fd;
262*a466cc55SCy Schubert FILE *f;
263*a466cc55SCy Schubert isc_result_t result = ISC_R_SUCCESS;
264*a466cc55SCy Schubert char *x;
265*a466cc55SCy Schubert char *cp;
266*a466cc55SCy Schubert isc_uint32_t which;
267*a466cc55SCy Schubert
268*a466cc55SCy Schubert REQUIRE(templet != NULL);
269*a466cc55SCy Schubert REQUIRE(fp != NULL && *fp == NULL);
270*a466cc55SCy Schubert
271*a466cc55SCy Schubert cp = templet;
272*a466cc55SCy Schubert while (*cp != '\0')
273*a466cc55SCy Schubert cp++;
274*a466cc55SCy Schubert if (cp == templet)
275*a466cc55SCy Schubert return (ISC_R_FAILURE);
276*a466cc55SCy Schubert
277*a466cc55SCy Schubert x = cp--;
278*a466cc55SCy Schubert while (cp >= templet && *cp == 'X') {
279*a466cc55SCy Schubert isc_random_get(&which);
280*a466cc55SCy Schubert *cp = alphnum[which % (sizeof(alphnum) - 1)];
281*a466cc55SCy Schubert x = cp--;
282*a466cc55SCy Schubert }
283*a466cc55SCy Schubert
284*a466cc55SCy Schubert
285*a466cc55SCy Schubert while ((fd = open(templet, O_RDWR|O_CREAT|O_EXCL, mode)) == -1) {
286*a466cc55SCy Schubert if (errno != EEXIST)
287*a466cc55SCy Schubert return (isc__errno2result(errno));
288*a466cc55SCy Schubert for (cp = x;;) {
289*a466cc55SCy Schubert char *t;
290*a466cc55SCy Schubert if (*cp == '\0')
291*a466cc55SCy Schubert return (ISC_R_FAILURE);
292*a466cc55SCy Schubert t = strchr(alphnum, *cp);
293*a466cc55SCy Schubert if (t == NULL || *++t == '\0')
294*a466cc55SCy Schubert *cp++ = alphnum[0];
295*a466cc55SCy Schubert else {
296*a466cc55SCy Schubert *cp = *t;
297*a466cc55SCy Schubert break;
298*a466cc55SCy Schubert }
299*a466cc55SCy Schubert }
300*a466cc55SCy Schubert }
301*a466cc55SCy Schubert f = fdopen(fd, "w+");
302*a466cc55SCy Schubert if (f == NULL) {
303*a466cc55SCy Schubert result = isc__errno2result(errno);
304*a466cc55SCy Schubert if (remove(templet) < 0) {
305*a466cc55SCy Schubert isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
306*a466cc55SCy Schubert ISC_LOGMODULE_FILE, ISC_LOG_ERROR,
307*a466cc55SCy Schubert "remove '%s': failed", templet);
308*a466cc55SCy Schubert }
309*a466cc55SCy Schubert (void)close(fd);
310*a466cc55SCy Schubert } else
311*a466cc55SCy Schubert *fp = f;
312*a466cc55SCy Schubert
313*a466cc55SCy Schubert return (result);
314*a466cc55SCy Schubert }
315*a466cc55SCy Schubert
316*a466cc55SCy Schubert isc_result_t
isc_file_remove(const char * filename)317*a466cc55SCy Schubert isc_file_remove(const char *filename) {
318*a466cc55SCy Schubert int r;
319*a466cc55SCy Schubert
320*a466cc55SCy Schubert REQUIRE(filename != NULL);
321*a466cc55SCy Schubert
322*a466cc55SCy Schubert r = unlink(filename);
323*a466cc55SCy Schubert if (r == 0)
324*a466cc55SCy Schubert return (ISC_R_SUCCESS);
325*a466cc55SCy Schubert else
326*a466cc55SCy Schubert return (isc__errno2result(errno));
327*a466cc55SCy Schubert }
328*a466cc55SCy Schubert
329*a466cc55SCy Schubert isc_result_t
isc_file_rename(const char * oldname,const char * newname)330*a466cc55SCy Schubert isc_file_rename(const char *oldname, const char *newname) {
331*a466cc55SCy Schubert int r;
332*a466cc55SCy Schubert
333*a466cc55SCy Schubert REQUIRE(oldname != NULL);
334*a466cc55SCy Schubert REQUIRE(newname != NULL);
335*a466cc55SCy Schubert
336*a466cc55SCy Schubert r = rename(oldname, newname);
337*a466cc55SCy Schubert if (r == 0)
338*a466cc55SCy Schubert return (ISC_R_SUCCESS);
339*a466cc55SCy Schubert else
340*a466cc55SCy Schubert return (isc__errno2result(errno));
341*a466cc55SCy Schubert }
342*a466cc55SCy Schubert
343*a466cc55SCy Schubert isc_boolean_t
isc_file_exists(const char * pathname)344*a466cc55SCy Schubert isc_file_exists(const char *pathname) {
345*a466cc55SCy Schubert struct stat stats;
346*a466cc55SCy Schubert
347*a466cc55SCy Schubert REQUIRE(pathname != NULL);
348*a466cc55SCy Schubert
349*a466cc55SCy Schubert return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS));
350*a466cc55SCy Schubert }
351*a466cc55SCy Schubert
352*a466cc55SCy Schubert isc_result_t
isc_file_isplainfile(const char * filename)353*a466cc55SCy Schubert isc_file_isplainfile(const char *filename) {
354*a466cc55SCy Schubert /*
355*a466cc55SCy Schubert * This function returns success if filename is a plain file.
356*a466cc55SCy Schubert */
357*a466cc55SCy Schubert struct stat filestat;
358*a466cc55SCy Schubert memset(&filestat,0,sizeof(struct stat));
359*a466cc55SCy Schubert
360*a466cc55SCy Schubert if ((stat(filename, &filestat)) == -1)
361*a466cc55SCy Schubert return(isc__errno2result(errno));
362*a466cc55SCy Schubert
363*a466cc55SCy Schubert if(! S_ISREG(filestat.st_mode))
364*a466cc55SCy Schubert return(ISC_R_INVALIDFILE);
365*a466cc55SCy Schubert
366*a466cc55SCy Schubert return(ISC_R_SUCCESS);
367*a466cc55SCy Schubert }
368*a466cc55SCy Schubert
369*a466cc55SCy Schubert isc_boolean_t
isc_file_isabsolute(const char * filename)370*a466cc55SCy Schubert isc_file_isabsolute(const char *filename) {
371*a466cc55SCy Schubert REQUIRE(filename != NULL);
372*a466cc55SCy Schubert return (ISC_TF(filename[0] == '/'));
373*a466cc55SCy Schubert }
374*a466cc55SCy Schubert
375*a466cc55SCy Schubert isc_boolean_t
isc_file_iscurrentdir(const char * filename)376*a466cc55SCy Schubert isc_file_iscurrentdir(const char *filename) {
377*a466cc55SCy Schubert REQUIRE(filename != NULL);
378*a466cc55SCy Schubert return (ISC_TF(filename[0] == '.' && filename[1] == '\0'));
379*a466cc55SCy Schubert }
380*a466cc55SCy Schubert
381*a466cc55SCy Schubert isc_boolean_t
isc_file_ischdiridempotent(const char * filename)382*a466cc55SCy Schubert isc_file_ischdiridempotent(const char *filename) {
383*a466cc55SCy Schubert REQUIRE(filename != NULL);
384*a466cc55SCy Schubert if (isc_file_isabsolute(filename))
385*a466cc55SCy Schubert return (ISC_TRUE);
386*a466cc55SCy Schubert if (isc_file_iscurrentdir(filename))
387*a466cc55SCy Schubert return (ISC_TRUE);
388*a466cc55SCy Schubert return (ISC_FALSE);
389*a466cc55SCy Schubert }
390*a466cc55SCy Schubert
391*a466cc55SCy Schubert const char *
isc_file_basename(const char * filename)392*a466cc55SCy Schubert isc_file_basename(const char *filename) {
393*a466cc55SCy Schubert char *s;
394*a466cc55SCy Schubert
395*a466cc55SCy Schubert REQUIRE(filename != NULL);
396*a466cc55SCy Schubert
397*a466cc55SCy Schubert s = strrchr(filename, '/');
398*a466cc55SCy Schubert if (s == NULL)
399*a466cc55SCy Schubert return (filename);
400*a466cc55SCy Schubert
401*a466cc55SCy Schubert return (s + 1);
402*a466cc55SCy Schubert }
403*a466cc55SCy Schubert
404*a466cc55SCy Schubert isc_result_t
isc_file_progname(const char * filename,char * buf,size_t buflen)405*a466cc55SCy Schubert isc_file_progname(const char *filename, char *buf, size_t buflen) {
406*a466cc55SCy Schubert const char *base;
407*a466cc55SCy Schubert size_t len;
408*a466cc55SCy Schubert
409*a466cc55SCy Schubert REQUIRE(filename != NULL);
410*a466cc55SCy Schubert REQUIRE(buf != NULL);
411*a466cc55SCy Schubert
412*a466cc55SCy Schubert base = isc_file_basename(filename);
413*a466cc55SCy Schubert len = strlen(base) + 1;
414*a466cc55SCy Schubert
415*a466cc55SCy Schubert if (len > buflen)
416*a466cc55SCy Schubert return (ISC_R_NOSPACE);
417*a466cc55SCy Schubert memcpy(buf, base, len);
418*a466cc55SCy Schubert
419*a466cc55SCy Schubert return (ISC_R_SUCCESS);
420*a466cc55SCy Schubert }
421*a466cc55SCy Schubert
422*a466cc55SCy Schubert /*
423*a466cc55SCy Schubert * Put the absolute name of the current directory into 'dirname', which is
424*a466cc55SCy Schubert * a buffer of at least 'length' characters. End the string with the
425*a466cc55SCy Schubert * appropriate path separator, such that the final product could be
426*a466cc55SCy Schubert * concatenated with a relative pathname to make a valid pathname string.
427*a466cc55SCy Schubert */
428*a466cc55SCy Schubert static isc_result_t
dir_current(char * dirname,size_t length)429*a466cc55SCy Schubert dir_current(char *dirname, size_t length) {
430*a466cc55SCy Schubert char *cwd;
431*a466cc55SCy Schubert isc_result_t result = ISC_R_SUCCESS;
432*a466cc55SCy Schubert
433*a466cc55SCy Schubert REQUIRE(dirname != NULL);
434*a466cc55SCy Schubert REQUIRE(length > 0U);
435*a466cc55SCy Schubert
436*a466cc55SCy Schubert cwd = getcwd(dirname, length);
437*a466cc55SCy Schubert
438*a466cc55SCy Schubert if (cwd == NULL) {
439*a466cc55SCy Schubert if (errno == ERANGE)
440*a466cc55SCy Schubert result = ISC_R_NOSPACE;
441*a466cc55SCy Schubert else
442*a466cc55SCy Schubert result = isc__errno2result(errno);
443*a466cc55SCy Schubert } else {
444*a466cc55SCy Schubert if (strlen(dirname) + 1 == length)
445*a466cc55SCy Schubert result = ISC_R_NOSPACE;
446*a466cc55SCy Schubert else if (dirname[1] != '\0')
447*a466cc55SCy Schubert strlcat(dirname, "/", length);
448*a466cc55SCy Schubert }
449*a466cc55SCy Schubert
450*a466cc55SCy Schubert return (result);
451*a466cc55SCy Schubert }
452*a466cc55SCy Schubert
453*a466cc55SCy Schubert isc_result_t
isc_file_absolutepath(const char * filename,char * path,size_t pathlen)454*a466cc55SCy Schubert isc_file_absolutepath(const char *filename, char *path, size_t pathlen) {
455*a466cc55SCy Schubert isc_result_t result;
456*a466cc55SCy Schubert result = dir_current(path, pathlen);
457*a466cc55SCy Schubert if (result != ISC_R_SUCCESS)
458*a466cc55SCy Schubert return (result);
459*a466cc55SCy Schubert if (strlen(path) + strlen(filename) + 1 > pathlen)
460*a466cc55SCy Schubert return (ISC_R_NOSPACE);
461*a466cc55SCy Schubert strlcat(path, filename, pathlen);
462*a466cc55SCy Schubert return (ISC_R_SUCCESS);
463*a466cc55SCy Schubert }
464*a466cc55SCy Schubert
465*a466cc55SCy Schubert isc_result_t
isc_file_truncate(const char * filename,isc_offset_t size)466*a466cc55SCy Schubert isc_file_truncate(const char *filename, isc_offset_t size) {
467*a466cc55SCy Schubert isc_result_t result = ISC_R_SUCCESS;
468*a466cc55SCy Schubert
469*a466cc55SCy Schubert if (truncate(filename, size) < 0)
470*a466cc55SCy Schubert result = isc__errno2result(errno);
471*a466cc55SCy Schubert return (result);
472*a466cc55SCy Schubert }
473*a466cc55SCy Schubert
474*a466cc55SCy Schubert isc_result_t
isc_file_safecreate(const char * filename,FILE ** fp)475*a466cc55SCy Schubert isc_file_safecreate(const char *filename, FILE **fp) {
476*a466cc55SCy Schubert isc_result_t result;
477*a466cc55SCy Schubert int flags;
478*a466cc55SCy Schubert struct stat sb;
479*a466cc55SCy Schubert FILE *f;
480*a466cc55SCy Schubert int fd;
481*a466cc55SCy Schubert
482*a466cc55SCy Schubert REQUIRE(filename != NULL);
483*a466cc55SCy Schubert REQUIRE(fp != NULL && *fp == NULL);
484*a466cc55SCy Schubert
485*a466cc55SCy Schubert result = file_stats(filename, &sb);
486*a466cc55SCy Schubert if (result == ISC_R_SUCCESS) {
487*a466cc55SCy Schubert if ((sb.st_mode & S_IFREG) == 0)
488*a466cc55SCy Schubert return (ISC_R_INVALIDFILE);
489*a466cc55SCy Schubert flags = O_WRONLY | O_TRUNC;
490*a466cc55SCy Schubert } else if (result == ISC_R_FILENOTFOUND) {
491*a466cc55SCy Schubert flags = O_WRONLY | O_CREAT | O_EXCL;
492*a466cc55SCy Schubert } else
493*a466cc55SCy Schubert return (result);
494*a466cc55SCy Schubert
495*a466cc55SCy Schubert fd = open(filename, flags, S_IRUSR | S_IWUSR);
496*a466cc55SCy Schubert if (fd == -1)
497*a466cc55SCy Schubert return (isc__errno2result(errno));
498*a466cc55SCy Schubert
499*a466cc55SCy Schubert f = fdopen(fd, "w");
500*a466cc55SCy Schubert if (f == NULL) {
501*a466cc55SCy Schubert result = isc__errno2result(errno);
502*a466cc55SCy Schubert close(fd);
503*a466cc55SCy Schubert return (result);
504*a466cc55SCy Schubert }
505*a466cc55SCy Schubert
506*a466cc55SCy Schubert *fp = f;
507*a466cc55SCy Schubert return (ISC_R_SUCCESS);
508*a466cc55SCy Schubert }
509*a466cc55SCy Schubert
510*a466cc55SCy Schubert isc_result_t
isc_file_splitpath(isc_mem_t * mctx,char * path,char ** dirnam,char ** basenam)511*a466cc55SCy Schubert isc_file_splitpath(isc_mem_t *mctx, char *path, char **dirnam, char **basenam)
512*a466cc55SCy Schubert {
513*a466cc55SCy Schubert char *dir, *file, *slash;
514*a466cc55SCy Schubert
515*a466cc55SCy Schubert REQUIRE(path != NULL);
516*a466cc55SCy Schubert
517*a466cc55SCy Schubert slash = strrchr(path, '/');
518*a466cc55SCy Schubert
519*a466cc55SCy Schubert if (slash == path) {
520*a466cc55SCy Schubert file = ++slash;
521*a466cc55SCy Schubert dir = isc_mem_strdup(mctx, "/");
522*a466cc55SCy Schubert } else if (slash != NULL) {
523*a466cc55SCy Schubert file = ++slash;
524*a466cc55SCy Schubert dir = isc_mem_allocate(mctx, slash - path);
525*a466cc55SCy Schubert if (dir != NULL)
526*a466cc55SCy Schubert strlcpy(dir, path, slash - path);
527*a466cc55SCy Schubert } else {
528*a466cc55SCy Schubert file = path;
529*a466cc55SCy Schubert dir = isc_mem_strdup(mctx, ".");
530*a466cc55SCy Schubert }
531*a466cc55SCy Schubert
532*a466cc55SCy Schubert if (dir == NULL)
533*a466cc55SCy Schubert return (ISC_R_NOMEMORY);
534*a466cc55SCy Schubert
535*a466cc55SCy Schubert if (*file == '\0') {
536*a466cc55SCy Schubert isc_mem_free(mctx, dir);
537*a466cc55SCy Schubert return (ISC_R_INVALIDFILE);
538*a466cc55SCy Schubert }
539*a466cc55SCy Schubert
540*a466cc55SCy Schubert *dirnam = dir;
541*a466cc55SCy Schubert *basenam = file;
542*a466cc55SCy Schubert
543*a466cc55SCy Schubert return (ISC_R_SUCCESS);
544*a466cc55SCy Schubert }
545