1 /* $Id: compat_mkstemps.c,v 1.1 2021/09/19 15:05:39 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2015, 2021 Ingo Schwarze <schwarze@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * Parts of the algorithm of this function are inspired by OpenBSD 18 * mkdtemp(3) by Theo de Raadt and Todd Miller, but the code differs. 19 */ 20 #include "config.h" 21 22 #include <sys/stat.h> 23 #include <errno.h> 24 #include <fcntl.h> 25 #include <limits.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 int 30 mkstemps(char *path, int suffixlen) 31 { 32 char *start, *end, *cp; 33 int fd, tries; 34 char backup; 35 36 end = strchr(path, '\0'); 37 if (suffixlen < 0 || suffixlen > end - path - 6) { 38 errno = EINVAL; 39 return -1; 40 } 41 end -= suffixlen; 42 for (start = end; start > path; start--) 43 if (start[-1] != 'X') 44 break; 45 46 backup = *end; 47 for (tries = INT_MAX; tries; tries--) { 48 *end = '\0'; 49 cp = mktemp(path); 50 *end = backup; 51 if (cp == NULL) 52 return -1; 53 fd = open(path, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR); 54 if (fd != -1) 55 return fd; 56 for (cp = start; cp < end; cp++) 57 *cp = 'X'; 58 if (errno != EEXIST) 59 return -1; 60 } 61 errno = EEXIST; 62 return -1; 63 } 64