1 /* sdb - MIT - Copyright 2013-2018 - pancake */
2 
3 #include <stdio.h>
4 #include <fcntl.h>
5 #include <errno.h>
6 #include <string.h>
7 #include <stdlib.h>
8 #include <sys/stat.h>
9 #include "sdb.h"
10 
11 #if __SDB_WINDOWS__
12 
13 #if UNICODE
14 
r_utf8_to_utf16_l(const char * cstring,int len)15 static wchar_t *r_utf8_to_utf16_l (const char *cstring, int len) {
16 	if (!cstring || !len || len < -1) {
17 		return NULL;
18 	}
19 	wchar_t *rutf16 = NULL;
20 	int wcsize;
21 
22 	if ((wcsize = MultiByteToWideChar (CP_UTF8, 0, cstring, len, NULL, 0))) {
23 		wcsize += 1;
24 		if ((rutf16 = (wchar_t *) calloc (wcsize, sizeof (wchar_t)))) {
25 			MultiByteToWideChar (CP_UTF8, 0, cstring, len, rutf16, wcsize);
26 			if (len != -1) {
27 				rutf16[wcsize - 1] = L'\0';
28 			}
29 		}
30 	}
31 	return rutf16;
32 }
33 
34 #define r_sys_conv_utf8_to_utf16(buf) r_utf8_to_utf16_l ((buf), -1)
35 
r_sys_mkdir(const char * path)36 static bool r_sys_mkdir(const char *path) {
37 	LPTSTR path_ = r_sys_conv_utf8_to_utf16 (path);
38 	bool ret = CreateDirectory (path_, NULL);
39 
40 	free (path_);
41 	return ret;
42 }
43 #else
44 #define r_sys_conv_utf8_to_utf16(buf) strdup (buf)
45 #define r_sys_mkdir(x) CreateDirectory (x, NULL)
46 #endif
47 #ifndef ERROR_ALREADY_EXISTS
48 #define ERROR_ALREADY_EXISTS 183
49 #endif
50 #define r_sys_mkdir_failed() (GetLastError () != 183)
51 #else
52 #define r_sys_mkdir(x) (mkdir (x,0755)!=-1)
53 #define r_sys_mkdir_failed() (errno != EEXIST)
54 #endif
55 
r_sys_mkdirp(char * dir)56 static inline int r_sys_mkdirp(char *dir) {
57 	int ret = 1;
58 	const char slash = DIRSEP;
59 	char *path = dir;
60 	char *ptr = path;
61 	if (*ptr == slash) {
62 		ptr++;
63 	}
64 #if __SDB_WINDOWS__
65 	char *p = strstr (ptr, ":\\");
66 	if (p) {
67 		ptr = p + 2;
68 	}
69 #endif
70 	while ((ptr = strchr (ptr, slash))) {
71 		*ptr = 0;
72 		if (!r_sys_mkdir (path) && r_sys_mkdir_failed ()) {
73 			eprintf ("r_sys_mkdirp: fail '%s' of '%s'\n", path, dir);
74 			*ptr = slash;
75 			return 0;
76 		}
77 		*ptr = slash;
78 		ptr++;
79 	}
80 	return ret;
81 }
82 
sdb_disk_create(Sdb * s)83 SDB_API bool sdb_disk_create(Sdb* s) {
84 	int nlen;
85 	char *str;
86 	const char *dir;
87 	if (!s || s->fdump >= 0) {
88 		return false; // cannot re-create
89 	}
90 	if (!s->dir && s->name) {
91 		s->dir = strdup (s->name);
92 	}
93 	dir = s->dir ? s->dir : "./";
94 	R_FREE (s->ndump);
95 	nlen = strlen (dir);
96 	str = malloc (nlen + 5);
97 	if (!str) {
98 		return false;
99 	}
100 	memcpy (str, dir, nlen + 1);
101 	r_sys_mkdirp (str);
102 	memcpy (str + nlen, ".tmp", 5);
103 	if (s->fdump != -1) {
104 		close (s->fdump);
105 	}
106 #if __SDB_WINDOWS__ && UNICODE
107 	wchar_t *wstr = r_sys_conv_utf8_to_utf16 (str);
108 	if (wstr) {
109 		s->fdump = _wopen (wstr, O_BINARY | O_RDWR | O_CREAT | O_TRUNC, SDB_MODE);
110 		free (wstr);
111 	} else {
112 		s->fdump = -1;
113 	}
114 #else
115 	s->fdump = open (str, O_BINARY | O_RDWR | O_CREAT | O_TRUNC, SDB_MODE);
116 #endif
117 	if (s->fdump == -1) {
118 		eprintf ("sdb: Cannot open '%s' for writing.\n", str);
119 		free (str);
120 		return false;
121 	}
122 	cdb_make_start (&s->m, s->fdump);
123 	s->ndump = str;
124 	return true;
125 }
126 
sdb_disk_insert(Sdb * s,const char * key,const char * val)127 SDB_API bool sdb_disk_insert(Sdb* s, const char *key, const char *val) {
128 	struct cdb_make *c = &s->m;
129 	if (!key || !val) {
130 		return false;
131 	}
132 	//if (!*val) return 0; //undefine variable if no value
133 	return cdb_make_add (c, key, strlen (key), val, strlen (val));
134 }
135 
136 #define IFRET(x) if (x) ret = 0
sdb_disk_finish(Sdb * s)137 SDB_API bool sdb_disk_finish (Sdb* s) {
138 	bool reopen = false, ret = true;
139 	IFRET (!cdb_make_finish (&s->m));
140 #if USE_MMAN
141 	IFRET (fsync (s->fdump));
142 #endif
143 	IFRET (close (s->fdump));
144 	s->fdump = -1;
145 	// close current fd to avoid sharing violations
146 	if (s->fd != -1) {
147 		close (s->fd);
148 		s->fd = -1;
149 		reopen = true;
150 	}
151 #if __SDB_WINDOWS__
152 	LPTSTR ndump_ = r_sys_conv_utf8_to_utf16 (s->ndump);
153 	LPTSTR dir_ = r_sys_conv_utf8_to_utf16 (s->dir);
154 
155 	if (MoveFileEx (ndump_, dir_, MOVEFILE_REPLACE_EXISTING)) {
156 		//eprintf ("Error 0x%02x\n", GetLastError ());
157 	}
158 	free (ndump_);
159 	free (dir_);
160 #else
161 	if (s->ndump && s->dir) {
162 		IFRET (rename (s->ndump, s->dir));
163 	}
164 #endif
165 	free (s->ndump);
166 	s->ndump = NULL;
167 	// reopen if was open before
168 	reopen = true; // always reopen if possible
169 	if (reopen) {
170 		int rr = sdb_open (s, s->dir);
171 		if (ret && rr < 0) {
172 			ret = false;
173 		}
174 		cdb_init (&s->db, s->fd);
175 	}
176 	return ret;
177 }
178 
sdb_disk_unlink(Sdb * s)179 SDB_API bool sdb_disk_unlink (Sdb *s) {
180 	return (s->dir && *(s->dir) && unlink (s->dir) != -1);
181 }
182