1/*	$NetBSD: file.h,v 1.7 2024/02/21 22:52:30 christos Exp $	*/
2
3/*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16#pragma once
17
18/*! \file isc/file.h */
19
20#include <stdbool.h>
21#include <stdio.h>
22
23#include <isc/lang.h>
24#include <isc/stat.h>
25#include <isc/types.h>
26
27ISC_LANG_BEGINDECLS
28
29isc_result_t
30isc_file_settime(const char *file, isc_time_t *time);
31
32isc_result_t
33isc_file_mode(const char *file, mode_t *modep);
34
35isc_result_t
36isc_file_getmodtime(const char *file, isc_time_t *time);
37/*!<
38 * \brief Get the time of last modification of a file.
39 *
40 * Notes:
41 *\li	The time that is set is relative to the (OS-specific) epoch, as are
42 *	all isc_time_t structures.
43 *
44 * Requires:
45 *\li	file != NULL.
46 *\li	time != NULL.
47 *
48 * Ensures:
49 *\li	If the file could not be accessed, 'time' is unchanged.
50 *
51 * Returns:
52 *\li	#ISC_R_SUCCESS
53 *		Success.
54 *\li	#ISC_R_NOTFOUND
55 *		No such file exists.
56 *\li	#ISC_R_INVALIDFILE
57 *		The path specified was not usable by the operating system.
58 *\li	#ISC_R_NOPERM
59 *		The file's metainformation could not be retrieved because
60 *		permission was denied to some part of the file's path.
61 *\li	#ISC_R_IOERROR
62 *		Hardware error interacting with the filesystem.
63 *\li	#ISC_R_UNEXPECTED
64 *		Something totally unexpected happened.
65 *
66 */
67
68isc_result_t
69isc_file_mktemplate(const char *path, char *buf, size_t buflen);
70/*!<
71 * \brief Generate a template string suitable for use with
72 * isc_file_openunique().
73 *
74 * Notes:
75 *\li	This function is intended to make creating temporary files
76 *	portable between different operating systems.
77 *
78 *\li	The path is prepended to an implementation-defined string and
79 *	placed into buf.  The string has no path characters in it,
80 *	and its maximum length is 14 characters plus a NUL.  Thus
81 *	buflen should be at least strlen(path) + 15 characters or
82 *	an error will be returned.
83 *
84 * Requires:
85 *\li	buf != NULL.
86 *
87 * Ensures:
88 *\li	If result == #ISC_R_SUCCESS:
89 *		buf contains a string suitable for use as the template argument
90 *		to isc_file_openunique().
91 *
92 *\li	If result != #ISC_R_SUCCESS:
93 *		buf is unchanged.
94 *
95 * Returns:
96 *\li	#ISC_R_SUCCESS 	Success.
97 *\li	#ISC_R_NOSPACE	buflen indicates buf is too small for the catenation
98 *				of the path with the internal template string.
99 */
100
101isc_result_t
102isc_file_openunique(char *templet, FILE **fp);
103isc_result_t
104isc_file_openuniqueprivate(char *templet, FILE **fp);
105isc_result_t
106isc_file_openuniquemode(char *templet, int mode, FILE **fp);
107isc_result_t
108isc_file_bopenunique(char *templet, FILE **fp);
109isc_result_t
110isc_file_bopenuniqueprivate(char *templet, FILE **fp);
111isc_result_t
112isc_file_bopenuniquemode(char *templet, int mode, FILE **fp);
113/*!<
114 * \brief Create and open a file with a unique name based on 'templet'.
115 *	isc_file_bopen*() open the file in binary mode in Windows.
116 *	isc_file_open*() open the file in text mode in Windows.
117 *
118 * Notes:
119 *\li	'template' is a reserved work in C++.  If you want to complain
120 *	about the spelling of 'templet', first look it up in the
121 *	Merriam-Webster English dictionary. (http://www.m-w.com/)
122 *
123 *\li	This function works by using the template to generate file names.
124 *	The template must be a writable string, as it is modified in place.
125 *	Trailing X characters in the file name (full file name on Unix,
126 *	basename on Win32 -- eg, tmp-XXXXXX vs XXXXXX.tmp, respectively)
127 *	are replaced with ASCII characters until a non-existent filename
128 *	is found.  If the template does not include pathname information,
129 *	the files in the working directory of the program are searched.
130 *
131 *\li	isc_file_mktemplate is a good, portable way to get a template.
132 *
133 * Requires:
134 *\li	'fp' is non-NULL and '*fp' is NULL.
135 *
136 *\li	'template' is non-NULL, and of a form suitable for use by
137 *	the system as described above.
138 *
139 * Ensures:
140 *\li	If result is #ISC_R_SUCCESS:
141 *		*fp points to an stream opening in stdio's "w+" mode.
142 *
143 *\li	If result is not #ISC_R_SUCCESS:
144 *		*fp is NULL.
145 *
146 *		No file is open.  Even if one was created (but unable
147 *		to be reopened as a stdio FILE pointer) then it has been
148 *		removed.
149 *
150 *\li	This function does *not* ensure that the template string has not been
151 *	modified, even if the operation was unsuccessful.
152 *
153 * Returns:
154 *\li	#ISC_R_SUCCESS
155 *		Success.
156 *\li	#ISC_R_EXISTS
157 *		No file with a unique name could be created based on the
158 *		template.
159 *\li	#ISC_R_INVALIDFILE
160 *		The path specified was not usable by the operating system.
161 *\li	#ISC_R_NOPERM
162 *		The file could not be created because permission was denied
163 *		to some part of the file's path.
164 *\li	#ISC_R_IOERROR
165 *		Hardware error interacting with the filesystem.
166 *\li	#ISC_R_UNEXPECTED
167 *		Something totally unexpected happened.
168 */
169
170isc_result_t
171isc_file_remove(const char *filename);
172/*!<
173 * \brief Remove the file named by 'filename'.
174 */
175
176isc_result_t
177isc_file_rename(const char *oldname, const char *newname);
178/*!<
179 * \brief Rename the file 'oldname' to 'newname'.
180 */
181
182bool
183isc_file_exists(const char *pathname);
184/*!<
185 * \brief Return #true if the calling process can tell that the given file
186 * exists. Will not return true if the calling process has insufficient
187 * privileges to search the entire path.
188 */
189
190bool
191isc_file_isabsolute(const char *filename);
192/*!<
193 * \brief Return #true if the given file name is absolute.
194 */
195
196isc_result_t
197isc_file_isplainfile(const char *name);
198
199isc_result_t
200isc_file_isplainfilefd(int fd);
201/*!<
202 * \brief Check that the file is a plain file
203 *
204 * Returns:
205 *\li	#ISC_R_SUCCESS
206 *		Success. The file is a plain file.
207 *\li	#ISC_R_INVALIDFILE
208 *		The path specified was not usable by the operating system.
209 *\li	#ISC_R_FILENOTFOUND
210 *		The file does not exist. This return code comes from
211 *		errno=ENOENT when stat returns -1. This code is mentioned
212 *		here, because in logconf.c, it is the one rcode that is
213 *		permitted in addition to ISC_R_SUCCESS. This is done since
214 *		the next call in logconf.c is to isc_stdio_open(), which
215 *		will create the file if it can.
216 *\li	other ISC_R_* errors translated from errno
217 *		These occur when stat returns -1 and an errno.
218 */
219
220isc_result_t
221isc_file_isdirectory(const char *name);
222/*!<
223 * \brief Check that 'name' exists and is a directory.
224 *
225 * Returns:
226 *\li	#ISC_R_SUCCESS
227 *		Success, file is a directory.
228 *\li	#ISC_R_INVALIDFILE
229 *		File is not a directory.
230 *\li	#ISC_R_FILENOTFOUND
231 *		File does not exist.
232 *\li	other ISC_R_* errors translated from errno
233 *		These occur when stat returns -1 and an errno.
234 */
235
236bool
237isc_file_iscurrentdir(const char *filename);
238/*!<
239 * \brief Return #true if the given file name is the current directory (".").
240 */
241
242bool
243isc_file_ischdiridempotent(const char *filename);
244/*%<
245 * Return #true if calling chdir(filename) multiple times will give
246 * the same result as calling it once.
247 */
248
249const char *
250isc_file_basename(const char *filename);
251/*%<
252 * Return the final component of the path in the file name.
253 */
254
255isc_result_t
256isc_file_progname(const char *filename, char *buf, size_t buflen);
257/*!<
258 * \brief Given an operating system specific file name "filename"
259 * referring to a program, return the canonical program name.
260 *
261 * Any directory prefix or executable file name extension (if
262 * used on the OS in case) is stripped.  On systems where program
263 * names are case insensitive, the name is canonicalized to all
264 * lower case.  The name is written to 'buf', an array of 'buflen'
265 * chars, and null terminated.
266 *
267 * Returns:
268 *\li	#ISC_R_SUCCESS
269 *\li	#ISC_R_NOSPACE 	The name did not fit in 'buf'.
270 */
271
272isc_result_t
273isc_file_template(const char *path, const char *templet, char *buf,
274		  size_t buflen);
275/*%<
276 * Create an OS specific template using 'path' to define the directory
277 * 'templet' to describe the filename and store the result in 'buf'
278 * such that path can be renamed to buf atomically.
279 */
280
281isc_result_t
282isc_file_renameunique(const char *file, char *templet);
283/*%<
284 * Rename 'file' using 'templet' as a template for the new file name.
285 */
286
287isc_result_t
288isc_file_absolutepath(const char *filename, char *path, size_t pathlen);
289/*%<
290 * Given a file name, return the fully qualified path to the file.
291 */
292
293/*
294 * XXX We should also have a isc_file_writeeopen() function
295 * for safely open a file in a publicly writable directory
296 * (see write_open() in BIND 8's ns_config.c).
297 */
298
299isc_result_t
300isc_file_truncate(const char *filename, isc_offset_t size);
301/*%<
302 * Truncate/extend the file specified to 'size' bytes.
303 */
304
305isc_result_t
306isc_file_safecreate(const char *filename, FILE **fp);
307/*%<
308 * Open 'filename' for writing, truncating if necessary.  Ensure that
309 * if it existed it was a normal file.  If creating the file, ensure
310 * that only the owner can read/write it.
311 */
312
313isc_result_t
314isc_file_splitpath(isc_mem_t *mctx, const char *path, char **dirname,
315		   char const **basename);
316/*%<
317 * Split a path into dirname and basename.  If 'path' contains no slash
318 * (or, on windows, backslash), then '*dirname' is set to ".".
319 *
320 * Allocates memory for '*dirname', which can be freed with isc_mem_free().
321 *
322 * Returns:
323 * - ISC_R_SUCCESS on success
324 * - ISC_R_INVALIDFILE if 'path' is empty or ends with '/'
325 * - ISC_R_NOMEMORY if unable to allocate memory
326 */
327
328isc_result_t
329isc_file_getsize(const char *file, off_t *size);
330/*%<
331 * Return the size of the file (stored in the parameter pointed
332 * to by 'size') in bytes.
333 *
334 * Returns:
335 * - ISC_R_SUCCESS on success
336 */
337
338isc_result_t
339isc_file_getsizefd(int fd, off_t *size);
340/*%<
341 * Return the size of the file (stored in the parameter pointed
342 * to by 'size') in bytes.
343 *
344 * Returns:
345 * - ISC_R_SUCCESS on success
346 */
347
348isc_result_t
349isc_file_sanitize(const char *dir, const char *base, const char *ext,
350		  char *path, size_t length);
351/*%<
352 * Generate a sanitized filename, such as for MKEYS or NZF files.
353 *
354 * Historically, MKEYS and NZF files used SHA256 hashes of the view
355 * name for the filename; this was to deal with the possibility of
356 * forbidden characters such as "/" being in a view name, and to
357 * avoid problems with case-insensitive file systems.
358 *
359 * Given a basename 'base' and an extension 'ext', this function checks
360 * for the existence of file using the old-style name format in directory
361 * 'dir'. If found, it returns the path to that file.  If there is no
362 * file already in place, a new pathname is generated; if the basename
363 * contains any excluded characters, then a truncated SHA256 hash is
364 * used, otherwise the basename is used.  The path name is copied
365 * into 'path', which must point to a buffer of at least 'length'
366 * bytes.
367 *
368 * Requires:
369 * - base != NULL
370 * - path != NULL
371 *
372 * Returns:
373 * - ISC_R_SUCCESS on success
374 * - ISC_R_NOSPACE if the resulting path would be longer than 'length'
375 */
376
377bool
378isc_file_isdirwritable(const char *path);
379/*%<
380 *	Return true if the path is a directory and is writable
381 */
382
383ISC_LANG_ENDDECLS
384