1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2004-2009 Marcel Holtmann <marcel (at) holtmann.org> 6 * 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24 #ifdef HAVE_CONFIG_H 25 #include <config.h> 26 #endif 27 28 #define _GNU_SOURCE 29 #include <stdio.h> 30 #include <errno.h> 31 #include <ctype.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <sys/file.h> 37 #include <sys/stat.h> 38 #include <sys/mman.h> 39 #include <sys/param.h> 40 41 #include "textfile.h" 42 43 #ifndef HAVE_FDATASYNC 44 #define fdatasync fsync 45 #endif 46 47 int create_dirs(const char *filename, const mode_t mode) 48 { 49 struct stat st; 50 char dir[PATH_MAX + 1], *prev, *next; 51 int err; 52 53 err = stat(filename, &st); 54 if (!err && S_ISREG(st.st_mode)) 55 return 0; 56 57 memset(dir, 0, PATH_MAX + 1); 58 strcat(dir, "/"); 59 60 prev = strchr(filename, '/'); 61 62 while (prev) { 63 next = strchr(prev + 1, '/'); 64 if (!next) 65 break; 66 67 if (next - prev == 1) { 68 prev = next; 69 continue; 70 } 71 72 strncat(dir, prev + 1, next - prev); 73 mkdir(dir, mode); 74 75 prev = next; 76 } 77 78 return 0; 79 } 80 81 int create_file(const char *filename, const mode_t mode) 82 { 83 int fd; 84 85 umask(S_IWGRP | S_IWOTH); 86 create_dirs(filename, S_IRUSR | S_IWUSR | S_IXUSR | 87 S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 88 89 fd = open(filename, O_RDWR | O_CREAT, mode); 90 if (fd < 0) 91 return fd; 92 93 close(fd); 94 95 return 0; 96 } 97 98 int create_name(char *buf, size_t size, const char *path, const char *address, const char *name) 99 { 100 return snprintf(buf, size, "%s/%s/%s", path, address, name); 101 } 102 103 static inline char *find_key(char *map, size_t size, const char *key, size_t len, int icase) 104 { 105 char *ptr = map; 106 size_t ptrlen = size; 107 108 while (ptrlen > len + 1) { 109 int cmp = (icase) ? strncasecmp(ptr, key, len) : strncmp(ptr, key, len); 110 if (cmp == 0) { 111 if (ptr == map) 112 return ptr; 113 114 if ((*(ptr - 1) == '\r' || *(ptr - 1) == '\n') && 115 *(ptr + len) == ' ') 116 return ptr; 117 } 118 119 if (icase) { 120 char *p1 = memchr(ptr + 1, tolower(*key), ptrlen - 1); 121 char *p2 = memchr(ptr + 1, toupper(*key), ptrlen - 1); 122 123 if (!p1) 124 ptr = p2; 125 else if (!p2) 126 ptr = p1; 127 else 128 ptr = (p1 < p2) ? p1 : p2; 129 } else 130 ptr = memchr(ptr + 1, *key, ptrlen - 1); 131 132 if (!ptr) 133 return NULL; 134 135 ptrlen = size - (ptr - map); 136 } 137 138 return NULL; 139 } 140 141 static inline int write_key_value(int fd, const char *key, const char *value) 142 { 143 char *str; 144 size_t size; 145 int err = 0; 146 147 size = strlen(key) + strlen(value) + 2; 148 149 str = malloc(size + 1); 150 if (!str) 151 return ENOMEM; 152 153 sprintf(str, "%s %s\n", key, value); 154 155 if (write(fd, str, size) < 0) 156 err = errno; 157 158 free(str); 159 160 return err; 161 } 162 163 static int write_key(const char *pathname, const char *key, const char *value, int icase) 164 { 165 struct stat st; 166 char *map, *off, *end, *str; 167 off_t size, pos; size_t base; 168 int fd, len, err = 0; 169 170 fd = open(pathname, O_RDWR); 171 if (fd < 0) 172 return -errno; 173 174 if (flock(fd, LOCK_EX) < 0) { 175 err = errno; 176 goto close; 177 } 178 179 if (fstat(fd, &st) < 0) { 180 err = errno; 181 goto unlock; 182 } 183 184 size = st.st_size; 185 186 if (!size) { 187 if (value) { 188 pos = lseek(fd, size, SEEK_SET); 189 err = write_key_value(fd, key, value); 190 } 191 goto unlock; 192 } 193 194 map = mmap(NULL, size, PROT_READ | PROT_WRITE, 195 MAP_PRIVATE | MAP_LOCKED, fd, 0); 196 if (!map || map == MAP_FAILED) { 197 err = errno; 198 goto unlock; 199 } 200 201 len = strlen(key); 202 off = find_key(map, size, key, len, icase); 203 if (!off) { 204 if (value) { 205 munmap(map, size); 206 pos = lseek(fd, size, SEEK_SET); 207 err = write_key_value(fd, key, value); 208 } 209 goto unlock; 210 } 211 212 base = off - map; 213 214 end = strpbrk(off, "\r\n"); 215 if (!end) { 216 err = EILSEQ; 217 goto unmap; 218 } 219 220 if (value && ((ssize_t) strlen(value) == end - off - len - 1) && 221 !strncmp(off + len + 1, value, end - off - len - 1)) 222 goto unmap; 223 224 len = strspn(end, "\r\n"); 225 end += len; 226 227 len = size - (end - map); 228 if (!len) { 229 munmap(map, size); 230 if (ftruncate(fd, base) < 0) { 231 err = errno; 232 goto unlock; 233 } 234 pos = lseek(fd, base, SEEK_SET); 235 if (value) 236 err = write_key_value(fd, key, value); 237 238 goto unlock; 239 } 240 241 if (len < 0 || len > size) { 242 err = EILSEQ; 243 goto unmap; 244 } 245 246 str = malloc(len); 247 if (!str) { 248 err = errno; 249 goto unmap; 250 } 251 252 memcpy(str, end, len); 253 254 munmap(map, size); 255 if (ftruncate(fd, base) < 0) { 256 err = errno; 257 free(str); 258 goto unlock; 259 } 260 pos = lseek(fd, base, SEEK_SET); 261 if (value) 262 err = write_key_value(fd, key, value); 263 264 if (write(fd, str, len) < 0) 265 err = errno; 266 267 free(str); 268 269 goto unlock; 270 271 unmap: 272 munmap(map, size); 273 274 unlock: 275 flock(fd, LOCK_UN); 276 277 close: 278 fdatasync(fd); 279 280 close(fd); 281 errno = err; 282 283 return -err; 284 } 285 286 static char *read_key(const char *pathname, const char *key, int icase) 287 { 288 struct stat st; 289 char *map, *off, *end, *str = NULL; 290 off_t size; size_t len; 291 int fd, err = 0; 292 293 fd = open(pathname, O_RDONLY); 294 if (fd < 0) 295 return NULL; 296 297 if (flock(fd, LOCK_SH) < 0) { 298 err = errno; 299 goto close; 300 } 301 302 if (fstat(fd, &st) < 0) { 303 err = errno; 304 goto unlock; 305 } 306 307 size = st.st_size; 308 309 map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); 310 if (!map || map == MAP_FAILED) { 311 err = errno; 312 goto unlock; 313 } 314 315 len = strlen(key); 316 off = find_key(map, size, key, len, icase); 317 if (!off) { 318 err = EILSEQ; 319 goto unmap; 320 } 321 322 end = strpbrk(off, "\r\n"); 323 if (!end) { 324 err = EILSEQ; 325 goto unmap; 326 } 327 328 str = malloc(end - off - len); 329 if (!str) { 330 err = EILSEQ; 331 goto unmap; 332 } 333 334 memset(str, 0, end - off - len); 335 strncpy(str, off + len + 1, end - off - len - 1); 336 337 unmap: 338 munmap(map, size); 339 340 unlock: 341 flock(fd, LOCK_UN); 342 343 close: 344 close(fd); 345 errno = err; 346 347 return str; 348 } 349 350 int textfile_put(const char *pathname, const char *key, const char *value) 351 { 352 return write_key(pathname, key, value, 0); 353 } 354 355 int textfile_caseput(const char *pathname, const char *key, const char *value) 356 { 357 return write_key(pathname, key, value, 1); 358 } 359 360 int textfile_del(const char *pathname, const char *key) 361 { 362 return write_key(pathname, key, NULL, 0); 363 } 364 365 int textfile_casedel(const char *pathname, const char *key) 366 { 367 return write_key(pathname, key, NULL, 1); 368 } 369 370 char *textfile_get(const char *pathname, const char *key) 371 { 372 return read_key(pathname, key, 0); 373 } 374 375 char *textfile_caseget(const char *pathname, const char *key) 376 { 377 return read_key(pathname, key, 1); 378 } 379 380 int textfile_foreach(const char *pathname, 381 void (*func)(char *key, char *value, void *data), void *data) 382 { 383 struct stat st; 384 char *map, *off, *end, *key, *value; 385 off_t size; size_t len; 386 int fd, err = 0; 387 388 fd = open(pathname, O_RDONLY); 389 if (fd < 0) 390 return -errno; 391 392 if (flock(fd, LOCK_SH) < 0) { 393 err = errno; 394 goto close; 395 } 396 397 if (fstat(fd, &st) < 0) { 398 err = errno; 399 goto unlock; 400 } 401 402 size = st.st_size; 403 404 map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); 405 if (!map || map == MAP_FAILED) { 406 err = errno; 407 goto unlock; 408 } 409 410 off = map; 411 412 while (1) { 413 end = strpbrk(off, " "); 414 if (!end) { 415 err = EILSEQ; 416 break; 417 } 418 419 len = end - off; 420 421 key = malloc(len + 1); 422 if (!key) { 423 err = errno; 424 break; 425 } 426 427 memset(key, 0, len + 1); 428 memcpy(key, off, len); 429 430 off = end + 1; 431 432 end = strpbrk(off, "\r\n"); 433 if (!end) { 434 err = EILSEQ; 435 free(key); 436 break; 437 } 438 439 len = end - off; 440 441 value = malloc(len + 1); 442 if (!value) { 443 err = errno; 444 free(key); 445 break; 446 } 447 448 memset(value, 0, len + 1); 449 memcpy(value, off, len); 450 451 func(key, value, data); 452 453 free(key); 454 free(value); 455 456 off = end + 1; 457 } 458 459 munmap(map, size); 460 461 unlock: 462 flock(fd, LOCK_UN); 463 464 close: 465 close(fd); 466 errno = err; 467 468 return 0; 469 } 470