librazor/atomic-none.c
author J. Ali Harlow <ali@juiblex.co.uk>
Sat Feb 11 09:30:23 2012 +0000 (2012-02-11)
changeset 420 a7a1be2fed47
child 423 6112bcc5d1cf
permissions -rw-r--r--
Start 0.5.4
     1 /*
     2  * Copyright (C) 2011-2012  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 	free(atomic->error_path);
    63 	free(atomic->error_str);
    64 	free(atomic->error_msg);
    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 = path;
    82 	for (slash = path; *slash != '\0'; slash = next) {
    83 #ifdef MSWIN_API
    84 		next = strpbrk(slash + 1, "/\\");
    85 #else
    86 		next = strchr(slash + 1, '/');
    87 #endif
    88 		if (next == NULL)
    89 			break;
    90 
    91 		memcpy(p, slash, next - slash);
    92 		p += next - slash;
    93 		*p = '\0';
    94 
    95 		if (razor_valid_root_name(buffer))
    96 			continue;
    97 
    98 		if (stat(buffer, &buf) == 0) {
    99 			if (!S_ISDIR(buf.st_mode)) {
   100 				razor_atomic_set_error_str(atomic, buffer,
   101 							   "Not a directory");
   102 				return -1;
   103 			}
   104 		} else if (mkdir(buffer, 0777) < 0) {
   105 			razor_atomic_set_error_str(atomic, buffer,
   106 						   strerror(errno));
   107 			return -1;
   108 		}
   109 	}
   110 
   111 	return 0;
   112 }
   113 
   114 RAZOR_EXPORT int
   115 razor_atomic_remove(struct razor_atomic *atomic, const char *path)
   116 {
   117 #ifdef MSWIN_API
   118 	wchar_t *buf;
   119 	DWORD err;
   120 #endif
   121 
   122 	if (razor_atomic_in_error_state(atomic))
   123 		return -1;
   124 
   125 #ifdef MSWIN_API
   126 	buf = razor_utf8_to_utf16(path, -1);
   127 
   128 	if (!DeleteFileW(buf)) {
   129 		err = GetLastError();
   130 		if (err != ERROR_FILE_NOT_FOUND &&
   131 		    err != ERROR_PATH_NOT_FOUND &&
   132 		    !(SetFileAttributesW(buf, FILE_ATTRIBUTE_NORMAL) &&
   133 		      DeleteFileW(buf)) &&
   134 		    !RemoveDirectoryW(buf) &&
   135 		    GetLastError() != ERROR_DIR_NOT_EMPTY)
   136 			razor_atomic_set_error_mswin(atomic, buf, err);
   137 	}
   138 
   139 	free(buf);
   140 #else
   141 	if (remove(path))
   142 		razor_atomic_set_error_str(atomic, path, strerror(errno));
   143 #endif
   144 
   145 	return !!atomic->error_str;
   146 }
   147 
   148 RAZOR_EXPORT int
   149 razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
   150 			 const char *newpath)
   151 {
   152 #ifdef MSWIN_API
   153 	wchar_t *oldbuf, *newbuf;
   154 	const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
   155 #endif
   156 
   157 	if (razor_atomic_in_error_state(atomic))
   158 		return -1;
   159 
   160 #ifdef MSWIN_API
   161 	newbuf = razor_utf8_to_utf16(newpath, -1);
   162 	oldbuf = razor_utf8_to_utf16(oldpath, -1);
   163 
   164 	/*
   165 	 * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will
   166 	 * cover every case we care about _except_ replacing an empty
   167 	 * directory with a file. Calling RemoveDirectory() will deal
   168 	 * with this case while having no effect in all other cases.
   169 	 */
   170 	(void)RemoveDirectoryW(newbuf);
   171 
   172 	if (!MoveFileExW(oldbuf, newbuf, flags))
   173 		razor_atomic_set_error_mswin(atomic, newbuf, GetLastError());
   174 
   175 	free(newbuf);
   176 	free(oldbuf);
   177 #else
   178 	if (rename(oldpath, newpath))
   179 		razor_atomic_set_error_str(atomic, newpath, strerror(errno));
   180 #endif
   181 
   182 	return !!atomic->error_str;
   183 }
   184 
   185 RAZOR_EXPORT int
   186 razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
   187 			mode_t mode)
   188 {
   189 	if (razor_atomic_in_error_state(atomic))
   190 		return -1;
   191 
   192 	if (!mkdir(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)))
   193 		return 0;
   194 
   195 	if (errno != EEXIST) {
   196 		razor_atomic_set_error_str(atomic, dirname, strerror(errno));
   197 		return -1;
   198 	}
   199 
   200 	if (chmod(dirname, mode & (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
   201 		razor_atomic_set_error_str(atomic, dirname, strerror(errno));
   202 		return -1;
   203 	}
   204 
   205 	return 0;
   206 }
   207 
   208 RAZOR_EXPORT int
   209 razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
   210 			    const char *path)
   211 {
   212 	if (razor_atomic_in_error_state(atomic))
   213 		return -1;
   214 
   215 #if HAVE_SYMLINK
   216 	if (symlink(target, path) < 0) {
   217 		razor_atomic_set_error_str(atomic, NULL, strerror(errno));
   218 		return -1;
   219 	}
   220 
   221 	return 0;
   222 #else
   223 	razor_atomic_set_error_str(atomic, NULL, "Symbolic links not supported "
   224 						 "on this platform");
   225 
   226 	return -1;
   227 #endif
   228 }
   229 
   230 RAZOR_EXPORT int
   231 razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
   232 			 mode_t mode)
   233 {
   234 	int fd;
   235 
   236 	if (razor_atomic_in_error_state(atomic))
   237 		return -1;
   238 
   239 	atomic->error_path = strdup(filename);
   240 	fd = open(atomic->error_path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
   241 		  mode & (S_IRWXU | S_IRWXG | S_IRWXO));
   242 
   243 	if (fd == -1)
   244 		razor_atomic_set_error_str(atomic, NULL, strerror(errno));
   245 
   246 	return fd;
   247 }
   248 
   249 #endif	/* !ENABLE_ATOMIC */