librazor/atomic-none.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Nov 13 11:30:27 2014 +0000 (2014-11-13)
changeset 463 1ca7a49838e9
parent 441 cf499fd51df7
child 475 008c75a5e08d
permissions -rw-r--r--
Switch from 0.5.7 to 0.6 and update libtool versioning to note incompatibilty
     1 /*
     2  * Copyright (C) 2011, 2012, 2014  J. Ali Harlow <ali@juiblex.co.uk>
     3  *
     4  * This program is free software; you can redistribute it and/or modify
     5  * it under the terms of the GNU General Public License as published by
     6  * the Free Software Foundation; either version 2 of the License, or
     7  * (at your option) any later version.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License along
    15  * with this program; if not, write to the Free Software Foundation, Inc.,
    16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    17  */
    18 
    19 #include "config.h"
    20 
    21 #if !ENABLE_ATOMIC
    22 
    23 #include <stdlib.h>
    24 #ifdef MSWIN_API
    25 #include <windows.h>
    26 #endif
    27 #include <stdio.h>
    28 #include <limits.h>
    29 #include <errno.h>
    30 #include <unistd.h>
    31 #include <fcntl.h>
    32 #include <sys/stat.h>
    33 #include <string.h>
    34 #include <assert.h>
    35 
    36 #include "razor.h"
    37 #include "razor-internal.h"
    38 
    39 #ifndef O_BINARY
    40 #define O_BINARY	0
    41 #endif
    42 
    43 RAZOR_EXPORT struct razor_atomic *
    44 razor_atomic_open(const char *description)
    45 {
    46 	struct razor_atomic *atomic;
    47 
    48 	atomic = zalloc(sizeof *atomic);
    49 
    50 	return atomic;
    51 }
    52 
    53 RAZOR_EXPORT int
    54 razor_atomic_commit(struct razor_atomic *atomic)
    55 {
    56 	return razor_atomic_in_error_state(atomic);
    57 }
    58 
    59 RAZOR_EXPORT void
    60 razor_atomic_destroy(struct razor_atomic *atomic)
    61 {
    62 	if (atomic->error)
    63 		razor_error_free(atomic->error);
    64 
    65 	free(atomic);
    66 }
    67 
    68 RAZOR_EXPORT int
    69 razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
    70 		       const char *path)
    71 {
    72 	char buffer[PATH_MAX], *p;
    73 	const char *slash, *next;
    74 	struct stat buf;
    75 
    76 	if (razor_atomic_in_error_state(atomic))
    77 		return -1;
    78 
    79 	strcpy(buffer, root);
    80 	p = buffer + strlen(buffer);
    81 	slash = (p > buffer) ? SKIP_DRIVE_PATH(path) : path;
    82 
    83 	for (slash = path; *slash != '\0'; slash = next) {
    84 #ifdef MSWIN_API
    85 		next = strpbrk(slash + 1, "/\\");
    86 #else
    87 		next = strchr(slash + 1, '/');
    88 #endif
    89 		if (next == NULL)
    90 			break;
    91 
    92 		memcpy(p, slash, next - slash);
    93 		p += next - slash;
    94 		*p = '\0';
    95 
    96 		if (razor_valid_root_name(buffer))
    97 			continue;
    98 
    99 		if (stat(buffer, &buf) == 0) {
   100 			if (!S_ISDIR(buf.st_mode)) {
   101 				atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR,
   102 								    EEXIST,
   103 								    buffer,
   104 								    "Not a directory");
   105 				return -1;
   106 			}
   107 		} else if (mkdir(buffer, 0777) < 0) {
   108 			atomic->error = razor_error_new_posix(buffer);
   109 			return -1;
   110 		}
   111 	}
   112 
   113 	return 0;
   114 }
   115 
   116 RAZOR_EXPORT int
   117 razor_atomic_remove(struct razor_atomic *atomic, const char *path)
   118 {
   119 #ifdef MSWIN_API
   120 	wchar_t *buf;
   121 	DWORD err;
   122 #endif
   123 
   124 	if (razor_atomic_in_error_state(atomic))
   125 		return -1;
   126 
   127 #ifdef MSWIN_API
   128 	buf = razor_utf8_to_utf16(path, -1);
   129 
   130 	if (!DeleteFileW(buf)) {
   131 		err = GetLastError();
   132 		if (err != ERROR_FILE_NOT_FOUND &&
   133 		    err != ERROR_PATH_NOT_FOUND &&
   134 		    !(SetFileAttributesW(buf, FILE_ATTRIBUTE_NORMAL) &&
   135 		      DeleteFileW(buf)) &&
   136 		    !RemoveDirectoryW(buf) &&
   137 		    GetLastError() != ERROR_DIR_NOT_EMPTY)
   138 			atomic->error = razor_error_new_mswin(buf, err);
   139 	}
   140 
   141 	free(buf);
   142 #else
   143 	if (remove(path))
   144 		atomic->error = razor_error_new_posix(path);
   145 #endif
   146 
   147 	return razor_atomic_in_error_state(atomic);
   148 }
   149 
   150 RAZOR_EXPORT int
   151 razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
   152 			 const char *newpath)
   153 {
   154 #ifdef MSWIN_API
   155 	wchar_t *oldbuf, *newbuf;
   156 	const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
   157 #endif
   158 
   159 	if (razor_atomic_in_error_state(atomic))
   160 		return -1;
   161 
   162 #ifdef MSWIN_API
   163 	newbuf = razor_utf8_to_utf16(newpath, -1);
   164 	oldbuf = razor_utf8_to_utf16(oldpath, -1);
   165 
   166 	/*
   167 	 * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will
   168 	 * cover every case we care about _except_ replacing an empty
   169 	 * directory with a file. Calling RemoveDirectory() will deal
   170 	 * with this case while having no effect in all other cases.
   171 	 */
   172 	(void)RemoveDirectoryW(newbuf);
   173 
   174 	if (!MoveFileExW(oldbuf, newbuf, flags))
   175 		atomic->error = razor_error_new_mswin(newbuf, GetLastError());
   176 
   177 	free(newbuf);
   178 	free(oldbuf);
   179 #else
   180 	if (rename(oldpath, newpath))
   181 		atomic->error = razor_error_new_posix(newpath);
   182 #endif
   183 
   184 	return razor_atomic_in_error_state(atomic);
   185 }
   186 
   187 RAZOR_EXPORT int
   188 razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
   189 			mode_t mode)
   190 {
   191 	struct stat buf;
   192 
   193 	if (razor_atomic_in_error_state(atomic))
   194 		return -1;
   195 
   196 	if (!mkdir(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)))
   197 		return 0;
   198 
   199 	if (errno != EEXIST || stat(dirname, &buf)) {
   200 		atomic->error = razor_error_new_posix(dirname);
   201 		return -1;
   202 	}
   203 
   204 	if (!S_ISDIR(buf.st_mode)) {
   205 		atomic->error = razor_error_new_str(RAZOR_POSIX_ERROR, EEXIST,
   206 						    action->args.path,
   207 						    "Not a directory");
   208 		return -1;
   209 	}
   210 
   211 	return 0;
   212 }
   213 
   214 RAZOR_EXPORT int
   215 razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
   216 			    const char *path)
   217 {
   218 	if (razor_atomic_in_error_state(atomic))
   219 		return -1;
   220 
   221 #if HAVE_SYMLINK
   222 	if (symlink(target, path) < 0) {
   223 		atomic->error = razor_error_new_posix(path);
   224 		return -1;
   225 	}
   226 
   227 	return 0;
   228 #else
   229 	atomic->error = razor_error_new_str(RAZOR_GENERAL_ERROR,
   230 					    RAZOR_GENERAL_ERROR_FAILED, NULL,
   231 					    "Symbolic links not supported "
   232 					    "on this platform");
   233 
   234 	return -1;
   235 #endif
   236 }
   237 
   238 RAZOR_EXPORT int
   239 razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
   240 			 mode_t mode)
   241 {
   242 	int fd;
   243 
   244 	if (razor_atomic_in_error_state(atomic))
   245 		return -1;
   246 
   247 	fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
   248 		  mode & (S_IRWXU | S_IRWXG | S_IRWXO));
   249 
   250 	if (fd == -1)
   251 		atomic->error = razor_error_new_posix(filename);
   252 
   253 	return fd;
   254 }
   255 
   256 #endif	/* !ENABLE_ATOMIC */