blob: 979a3811f914ca23956befd1dfc20aba82293d19 [file] [log] [blame]
Pekka Paalanen899b50b2015-02-12 12:52:21 +02001/*
2 * Copyright © 2015 Collabora, Ltd.
3 *
Bryce Harrington6c6164c2015-06-11 14:20:17 -07004 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
Pekka Paalanen899b50b2015-02-12 12:52:21 +020011 *
Bryce Harrington6c6164c2015-06-11 14:20:17 -070012 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
Pekka Paalanen899b50b2015-02-12 12:52:21 +020024 */
25
26#include "config.h"
27
28#include <stdio.h>
29#include <errno.h>
30#include <time.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34
35#include "file-util.h"
36
37static int
38current_time_str(char *str, size_t len, const char *fmt)
39{
40 time_t t;
41 struct tm *t_local;
42 int ret;
43
44 t = time(NULL);
45 t_local = localtime(&t);
46 if (!t_local) {
47 errno = ETIME;
48 return -1;
49 }
50
51 ret = strftime(str, len, fmt, t_local);
52 if (ret == 0) {
53 errno = ETIME;
54 return -1;
55 }
56
57 return ret;
58}
59
60static int
61create_file_excl(const char *fname)
62{
63 return open(fname, O_RDWR | O_CLOEXEC | O_CREAT | O_EXCL, 00666);
64}
65
66/** Create a unique file with date and time in the name
67 *
68 * \param path_prefix Path and file name prefix.
69 * \param suffix File name suffix.
70 * \param name_out[out] Buffer for the resulting file name.
71 * \param name_len Number of bytes usable in name_out.
72 * \return stdio FILE pointer, or NULL on failure.
73 *
74 * Create and open a new file with the name concatenated from
75 * path_prefix, date and time, and suffix. If a file with this name
76 * already exists, an counter number is added to the end of the
77 * date and time sub-string. The counter is increased until a free file
78 * name is found.
79 *
80 * Once creating the file succeeds, the name of the file is in name_out.
81 * On failure, the contents of name_out are undefined and errno is set.
82 */
83FILE *
84file_create_dated(const char *path_prefix, const char *suffix,
85 char *name_out, size_t name_len)
86{
87 char timestr[128];
88 int ret;
89 int fd;
90 int cnt = 0;
91
92 if (current_time_str(timestr, sizeof(timestr), "%F_%H-%M-%S") < 0)
93 return NULL;
94
95 ret = snprintf(name_out, name_len, "%s%s%s",
96 path_prefix, timestr, suffix);
97 if (ret < 0 || (size_t)ret >= name_len) {
98 errno = ENOBUFS;
99 return NULL;
100 }
101
102 fd = create_file_excl(name_out);
103
104 while (fd == -1 && errno == EEXIST) {
105 cnt++;
106
107 ret = snprintf(name_out, name_len, "%s%s-%d%s",
108 path_prefix, timestr, cnt, suffix);
109 if (ret < 0 || (size_t)ret >= name_len) {
110 errno = ENOBUFS;
111 return NULL;
112 }
113
114 fd = create_file_excl(name_out);
115 }
116
117 if (fd == -1)
118 return NULL;
119
120 return fdopen(fd, "w");
121}