file.c revision b05a50c852608a40d1a06d6124bafb9b500c10c1
7e4d75a5daeaaf8a7f559f9bd7fbf540184e235cMark Andrews * Copyright (C) 2004, 2007, 2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC")
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * Copyright (C) 2000-2002 Internet Software Consortium.
7e4d75a5daeaaf8a7f559f9bd7fbf540184e235cMark Andrews * Permission to use, copy, modify, and/or distribute this software for any
7e4d75a5daeaaf8a7f559f9bd7fbf540184e235cMark Andrews * purpose with or without fee is hereby granted, provided that the above
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * copyright notice and this permission notice appear in all copies.
15a44745412679c30a6d022733925af70a38b715David Lawrence * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
15a44745412679c30a6d022733925af70a38b715David Lawrence * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15a44745412679c30a6d022733925af70a38b715David Lawrence * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
15a44745412679c30a6d022733925af70a38b715David Lawrence * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15a44745412679c30a6d022733925af70a38b715David Lawrence * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15a44745412679c30a6d022733925af70a38b715David Lawrence * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15a44745412679c30a6d022733925af70a38b715David Lawrence * PERFORMANCE OF THIS SOFTWARE.
ed71ea51c6ecb5d7d659b6e6a20f6b3f5c2678c6David Lawrencestatic const char alphnum[] =
ed71ea51c6ecb5d7d659b6e6a20f6b3f5c2678c6David Lawrence "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Emulate UNIX mkstemp, which returns an open FD to the new file
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsgettemp(char *path, isc_boolean_t binary, int *doopen) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /* extra X's get set to 0's */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * check the target directory; if you have six X's and it
ca81c3971cd0c9cfd830c0a18289d4d1b0f9de01David Lawrence * doesn't exist this runs for a *very* long time.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /* tricky little algorithm for backward compatibility */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /*NOTREACHED*/
ca81c3971cd0c9cfd830c0a18289d4d1b0f9de01David Lawrence * XXXDCL As the API for accessing file statistics undoubtedly gets expanded,
ca81c3971cd0c9cfd830c0a18289d4d1b0f9de01David Lawrence * it might be good to provide a mechanism that allows for the results
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * of a previous stat() to be used again without having to do another stat,
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * such as perl's mechanism of using "_" in place of a file name to indicate
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * that the results of the last stat should be used. But then you get into
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * annoying MP issues. BTW, Win32 has stat().
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsfile_stats(const char *file, struct stat *stats) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsisc_file_mode(const char *file, mode_t *modep) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * isc_file_safemovefile is needed to be defined here to ensure that
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * any file with the new name is renamed to a backup name and then the
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * rename is done. If all goes well then the backup can be deleted,
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * otherwise it gets renamed back.
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrewsisc_file_safemovefile(const char *oldname, const char *newname) {
171d0db7f93bf796f870713d6208b21893401cfcBrian Wellington * Make sure we have something to do
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (-1);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Rename to a backup the new file if it still exists
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /* Now rename the file to the new name
ed71ea51c6ecb5d7d659b6e6a20f6b3f5c2678c6David Lawrence * Try to rename the backup back to the original name
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * if the backup got created
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (-1);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Delete the backup file if it got created
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsisc_file_getmodtime(const char *file, isc_time_t *time) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if ((fh = open(file, _O_RDONLY | _O_BINARY)) < 0)
ed71ea51c6ecb5d7d659b6e6a20f6b3f5c2678c6David Lawrence if (!GetFileTime((HANDLE) _get_osfhandle(fh),
ed71ea51c6ecb5d7d659b6e6a20f6b3f5c2678c6David Lawrenceisc_file_getsize(const char *file, off_t *size) {
171d0db7f93bf796f870713d6208b21893401cfcBrian Wellingtonisc_file_settime(const char *file, isc_time_t *time) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if ((fh = open(file, _O_RDWR | _O_BINARY)) < 0)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Set the date via the filedate system call and return. Failing
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * this call implies the new file times are not supported by the
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * underlying file system.
ca81c3971cd0c9cfd830c0a18289d4d1b0f9de01David Lawrence if (!SetFileTime((HANDLE) _get_osfhandle(fh),
ed71ea51c6ecb5d7d659b6e6a20f6b3f5c2678c6David Lawrence#define TEMPLATE "XXXXXXXXXX.tmp" /* 14 characters. */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsisc_file_mktemplate(const char *path, char *buf, size_t buflen) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (isc_file_template(path, TEMPLATE, buf, buflen));
347ccc2716b45b8c72a1021d7a74faab49d3eefaBrian Wellingtonisc_file_template(const char *path, const char *templet, char *buf,
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if ((s - path + 1 + strlen(templet) + 1) > (ssize_t)buflen)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsisc_file_renameunique(const char *file, char *templet) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsopenuniquemode(char *templet, int mode, isc_boolean_t binary, FILE **fp) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Win32 does not have mkstemp. Using emulation above.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsisc_file_openuniqueprivate(char *templet, FILE **fp) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (openuniquemode(templet, mode, ISC_FALSE, fp));
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (openuniquemode(templet, mode, ISC_FALSE, fp));
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsisc_file_openuniquemode(char *templet, int mode, FILE **fp) {
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence return (openuniquemode(templet, mode, ISC_FALSE, fp));
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsisc_file_bopenuniqueprivate(char *templet, FILE **fp) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (openuniquemode(templet, mode, ISC_TRUE, fp));
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsisc_file_bopenunique(char *templet, FILE **fp) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (openuniquemode(templet, mode, ISC_TRUE, fp));
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsisc_file_bopenuniquemode(char *templet, int mode, FILE **fp) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (openuniquemode(templet, mode, ISC_TRUE, fp));
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsisc_file_rename(const char *oldname, const char *newname) {
ed019cabc1cc75d4412010c331876e4ae5080a4dDavid Lawrence return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS));
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * This function returns success if filename is a plain file.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * This function returns success if filename is a plain file.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * This function returns success if filename is a directory.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Look for c:\path\... style, c:/path/... or \\computer\shar\path...
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * the UNC style file specs
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if ((filename[0] == '\\') && (filename[1] == '\\'))
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '\\')
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '/')
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (ISC_TF(filename[0] == '.' && filename[1] == '\0'));
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsisc_file_ischdiridempotent(const char *filename) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews return (s + 1);
1a03b5e68553c37e9cc0097368909dfc37fb8cefMark Andrewsisc_file_progname(const char *filename, char *progname, size_t namelen) {
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews const char *s;
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Strip the path from the name
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Strip any and all suffixes
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * Copy the result to the buffer
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsisc_file_absolutepath(const char *filename, char *path, size_t pathlen) {
ca81c3971cd0c9cfd830c0a18289d4d1b0f9de01David Lawrence retval = GetFullPathName(filename, (DWORD) pathlen, path, &ptrname);
ca81c3971cd0c9cfd830c0a18289d4d1b0f9de01David Lawrence /* Something went wrong in getting the path */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /* Caller needs to provide a larger buffer to contain the string */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsisc_file_truncate(const char *filename, isc_offset_t size) {
ca81c3971cd0c9cfd830c0a18289d4d1b0f9de01David Lawrence if ((fh = open(filename, _O_RDWR | _O_BINARY)) < 0)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrewsisc_file_safecreate(const char *filename, FILE **fp) {
ca81c3971cd0c9cfd830c0a18289d4d1b0f9de01David Lawrenceisc_file_splitpath(isc_mem_t *mctx, char *path, char **dirname, char **basename)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews if ((slash != NULL && backslash != NULL && backslash > slash) ||
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews#define DISALLOW "\\/:ABCDEFGHIJKLMNOPQRSTUVWXYZ"
ca81c3971cd0c9cfd830c0a18289d4d1b0f9de01David Lawrenceisc_file_sanitize(const char *dir, const char *base, const char *ext,
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * allow room for a full sha256 hash (64 chars
ca81c3971cd0c9cfd830c0a18289d4d1b0f9de01David Lawrence * plus null terminator)
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews /* Check whether the full-length SHA256 hash filename exists */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews isc_sha256_data((const void *) base, strlen(base), hash);
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dir != NULL ? dir : "", dir != NULL ? "/" : "",
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews hash, ext != NULL ? "." : "", ext != NULL ? ext : "");
d736db6dc53e615e3f2d66d1ddbe28473694d107Michael Graff /* Check for a truncated SHA256 hash filename */
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dir != NULL ? dir : "", dir != NULL ? "/" : "",
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews hash, ext != NULL ? "." : "", ext != NULL ? ext : "");
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * If neither hash filename already exists, then we'll use
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * the original base name if it has no disallowed characters,
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews * or the truncated hash name if it does.
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews dir != NULL ? dir : "", dir != NULL ? "/" : "",
7d2b275f7e9238e2c709737601f6260b5a9a4ee1Mark Andrews base, ext != NULL ? "." : "", ext != NULL ? ext : "");