Home | History | Annotate | Line # | Download | only in isc
      1 /*	$NetBSD: file.h,v 1.8 2025/01/26 16:25:40 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 #include <sys/stat.h>
     23 
     24 #include <isc/lang.h>
     25 #include <isc/types.h>
     26 
     27 ISC_LANG_BEGINDECLS
     28 
     29 isc_result_t
     30 isc_file_settime(const char *file, isc_time_t *time);
     31 
     32 isc_result_t
     33 isc_file_mode(const char *file, mode_t *modep);
     34 
     35 isc_result_t
     36 isc_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 
     68 isc_result_t
     69 isc_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 
    101 isc_result_t
    102 isc_file_openunique(char *templet, FILE **fp);
    103 isc_result_t
    104 isc_file_openuniqueprivate(char *templet, FILE **fp);
    105 isc_result_t
    106 isc_file_openuniquemode(char *templet, int mode, FILE **fp);
    107 /*!<
    108  * \brief Create and open a file with a unique name based on 'templet'.
    109  *
    110  * Notes:
    111  *\li	'template' is a reserved work in C++.  If you want to complain
    112  *	about the spelling of 'templet', first look it up in the
    113  *	Merriam-Webster English dictionary. (http://www.m-w.com/)
    114  *
    115  *\li	This function works by using the template to generate file names.
    116  *	The template must be a writable string, as it is modified in place.
    117  *	Trailing X characters in the file name (full file name on Unix,
    118  *	basename on Win32 -- eg, tmp-XXXXXX vs XXXXXX.tmp, respectively)
    119  *	are replaced with ASCII characters until a non-existent filename
    120  *	is found.  If the template does not include pathname information,
    121  *	the files in the working directory of the program are searched.
    122  *
    123  *\li	isc_file_mktemplate is a good, portable way to get a template.
    124  *
    125  * Requires:
    126  *\li	'fp' is non-NULL and '*fp' is NULL.
    127  *
    128  *\li	'template' is non-NULL, and of a form suitable for use by
    129  *	the system as described above.
    130  *
    131  * Ensures:
    132  *\li	If result is #ISC_R_SUCCESS:
    133  *		*fp points to an stream opening in stdio's "w+" mode.
    134  *
    135  *\li	If result is not #ISC_R_SUCCESS:
    136  *		*fp is NULL.
    137  *
    138  *		No file is open.  Even if one was created (but unable
    139  *		to be reopened as a stdio FILE pointer) then it has been
    140  *		removed.
    141  *
    142  *\li	This function does *not* ensure that the template string has not been
    143  *	modified, even if the operation was unsuccessful.
    144  *
    145  * Returns:
    146  *\li	#ISC_R_SUCCESS
    147  *		Success.
    148  *\li	#ISC_R_EXISTS
    149  *		No file with a unique name could be created based on the
    150  *		template.
    151  *\li	#ISC_R_INVALIDFILE
    152  *		The path specified was not usable by the operating system.
    153  *\li	#ISC_R_NOPERM
    154  *		The file could not be created because permission was denied
    155  *		to some part of the file's path.
    156  *\li	#ISC_R_IOERROR
    157  *		Hardware error interacting with the filesystem.
    158  *\li	#ISC_R_UNEXPECTED
    159  *		Something totally unexpected happened.
    160  */
    161 
    162 isc_result_t
    163 isc_file_remove(const char *filename);
    164 /*!<
    165  * \brief Remove the file named by 'filename'.
    166  */
    167 
    168 isc_result_t
    169 isc_file_rename(const char *oldname, const char *newname);
    170 /*!<
    171  * \brief Rename the file 'oldname' to 'newname'.
    172  */
    173 
    174 bool
    175 isc_file_exists(const char *pathname);
    176 /*!<
    177  * \brief Return #true if the calling process can tell that the given file
    178  * exists. Will not return true if the calling process has insufficient
    179  * privileges to search the entire path.
    180  */
    181 
    182 bool
    183 isc_file_isabsolute(const char *filename);
    184 /*!<
    185  * \brief Return #true if the given file name is absolute.
    186  */
    187 
    188 isc_result_t
    189 isc_file_isplainfile(const char *name);
    190 
    191 isc_result_t
    192 isc_file_isplainfilefd(int fd);
    193 /*!<
    194  * \brief Check that the file is a plain file
    195  *
    196  * Returns:
    197  *\li	#ISC_R_SUCCESS
    198  *		Success. The file is a plain file.
    199  *\li	#ISC_R_INVALIDFILE
    200  *		The path specified was not usable by the operating system.
    201  *\li	#ISC_R_FILENOTFOUND
    202  *		The file does not exist. This return code comes from
    203  *		errno=ENOENT when stat returns -1. This code is mentioned
    204  *		here, because in logconf.c, it is the one rcode that is
    205  *		permitted in addition to ISC_R_SUCCESS. This is done since
    206  *		the next call in logconf.c is to isc_stdio_open(), which
    207  *		will create the file if it can.
    208  *\li	other ISC_R_* errors translated from errno
    209  *		These occur when stat returns -1 and an errno.
    210  */
    211 
    212 isc_result_t
    213 isc_file_isdirectory(const char *name);
    214 /*!<
    215  * \brief Check that 'name' exists and is a directory.
    216  *
    217  * Returns:
    218  *\li	#ISC_R_SUCCESS
    219  *		Success, file is a directory.
    220  *\li	#ISC_R_INVALIDFILE
    221  *		File is not a directory.
    222  *\li	#ISC_R_FILENOTFOUND
    223  *		File does not exist.
    224  *\li	other ISC_R_* errors translated from errno
    225  *		These occur when stat returns -1 and an errno.
    226  */
    227 
    228 bool
    229 isc_file_iscurrentdir(const char *filename);
    230 /*!<
    231  * \brief Return #true if the given file name is the current directory (".").
    232  */
    233 
    234 bool
    235 isc_file_ischdiridempotent(const char *filename);
    236 /*%<
    237  * Return #true if calling chdir(filename) multiple times will give
    238  * the same result as calling it once.
    239  */
    240 
    241 const char *
    242 isc_file_basename(const char *filename);
    243 /*%<
    244  * Return the final component of the path in the file name.
    245  */
    246 
    247 isc_result_t
    248 isc_file_progname(const char *filename, char *buf, size_t buflen);
    249 /*!<
    250  * \brief Given an operating system specific file name "filename"
    251  * referring to a program, return the canonical program name.
    252  *
    253  * Any directory prefix or executable file name extension (if
    254  * used on the OS in case) is stripped.  On systems where program
    255  * names are case insensitive, the name is canonicalized to all
    256  * lower case.  The name is written to 'buf', an array of 'buflen'
    257  * chars, and null terminated.
    258  *
    259  * Returns:
    260  *\li	#ISC_R_SUCCESS
    261  *\li	#ISC_R_NOSPACE 	The name did not fit in 'buf'.
    262  */
    263 
    264 isc_result_t
    265 isc_file_template(const char *path, const char *templet, char *buf,
    266 		  size_t buflen);
    267 /*%<
    268  * Create an OS specific template using 'path' to define the directory
    269  * 'templet' to describe the filename and store the result in 'buf'
    270  * such that path can be renamed to buf atomically.
    271  */
    272 
    273 isc_result_t
    274 isc_file_renameunique(const char *file, char *templet);
    275 /*%<
    276  * Rename 'file' using 'templet' as a template for the new file name.
    277  */
    278 
    279 isc_result_t
    280 isc_file_absolutepath(const char *filename, char *path, size_t pathlen);
    281 /*%<
    282  * Given a file name, return the fully qualified path to the file.
    283  */
    284 
    285 /*
    286  * XXX We should also have a isc_file_writeeopen() function
    287  * for safely open a file in a publicly writable directory
    288  * (see write_open() in BIND 8's ns_config.c).
    289  */
    290 
    291 isc_result_t
    292 isc_file_truncate(const char *filename, off_t size);
    293 /*%<
    294  * Truncate/extend the file specified to 'size' bytes.
    295  */
    296 
    297 isc_result_t
    298 isc_file_safecreate(const char *filename, FILE **fp);
    299 /*%<
    300  * Open 'filename' for writing, truncating if necessary.  Ensure that
    301  * if it existed it was a normal file.  If creating the file, ensure
    302  * that only the owner can read/write it.
    303  */
    304 
    305 isc_result_t
    306 isc_file_splitpath(isc_mem_t *mctx, const char *path, char **dirname,
    307 		   char const **basename);
    308 /*%<
    309  * Split a path into dirname and basename.  If 'path' contains no slash,
    310  * then '*dirname' is set to ".".
    311  *
    312  * Allocates memory for '*dirname', which can be freed with isc_mem_free().
    313  *
    314  * Returns:
    315  * - ISC_R_SUCCESS on success
    316  * - ISC_R_INVALIDFILE if 'path' is empty or ends with '/'
    317  * - ISC_R_NOMEMORY if unable to allocate memory
    318  */
    319 
    320 isc_result_t
    321 isc_file_getsize(const char *file, off_t *size);
    322 /*%<
    323  * Return the size of the file (stored in the parameter pointed
    324  * to by 'size') in bytes.
    325  *
    326  * Returns:
    327  * - ISC_R_SUCCESS on success
    328  */
    329 
    330 isc_result_t
    331 isc_file_getsizefd(int fd, off_t *size);
    332 /*%<
    333  * Return the size of the file (stored in the parameter pointed
    334  * to by 'size') in bytes.
    335  *
    336  * Returns:
    337  * - ISC_R_SUCCESS on success
    338  */
    339 
    340 isc_result_t
    341 isc_file_sanitize(const char *dir, const char *base, const char *ext,
    342 		  char *path, size_t length);
    343 /*%<
    344  * Generate a sanitized filename, such as for MKEYS or NZF files.
    345  *
    346  * Historically, MKEYS and NZF files used SHA256 hashes of the view
    347  * name for the filename; this was to deal with the possibility of
    348  * forbidden characters such as "/" being in a view name, and to
    349  * avoid problems with case-insensitive file systems.
    350  *
    351  * Given a basename 'base' and an extension 'ext', this function checks
    352  * for the existence of file using the old-style name format in directory
    353  * 'dir'. If found, it returns the path to that file.  If there is no
    354  * file already in place, a new pathname is generated; if the basename
    355  * contains any excluded characters, then a truncated SHA256 hash is
    356  * used, otherwise the basename is used.  The path name is copied
    357  * into 'path', which must point to a buffer of at least 'length'
    358  * bytes.
    359  *
    360  * Requires:
    361  * - base != NULL
    362  * - path != NULL
    363  *
    364  * Returns:
    365  * - ISC_R_SUCCESS on success
    366  * - ISC_R_NOSPACE if the resulting path would be longer than 'length'
    367  */
    368 
    369 bool
    370 isc_file_isdirwritable(const char *path);
    371 /*%<
    372  *	Return true if the path is a directory and is writable
    373  */
    374 
    375 ISC_LANG_ENDDECLS
    376