]>
Commit | Line | Data |
---|---|---|
6b79eb38 SK |
1 | /* |
2 | * Copyright (C) 2012 Sami Kerola <kerolasa@iki.fi> | |
3 | */ | |
4 | ||
5 | #include <stdio.h> | |
6 | #include <stdlib.h> | |
7 | #include <sys/stat.h> | |
8 | #include <unistd.h> | |
be92327e KZ |
9 | #include <sys/time.h> |
10 | #include <sys/resource.h> | |
6b79eb38 SK |
11 | |
12 | #include "c.h" | |
7961acce | 13 | #include "fileutils.h" |
6b79eb38 SK |
14 | #include "pathnames.h" |
15 | ||
4d751c00 RM |
16 | int mkstemp_cloexec(char *template) |
17 | { | |
18 | #ifdef HAVE_MKOSTEMP | |
19 | return mkostemp(template, O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC); | |
20 | #else | |
21 | int fd, old_flags, errno_save; | |
22 | ||
23 | fd = mkstemp(template); | |
24 | if (fd < 0) | |
25 | return fd; | |
26 | ||
27 | old_flags = fcntl(fd, F_GETFD, 0); | |
28 | if (old_flags < 0) | |
29 | goto unwind; | |
30 | if (fcntl(fd, F_SETFD, old_flags | O_CLOEXEC) < 0) | |
31 | goto unwind; | |
32 | ||
33 | return fd; | |
34 | ||
35 | unwind: | |
36 | errno_save = errno; | |
37 | unlink(template); | |
38 | close(fd); | |
39 | errno = errno_save; | |
40 | ||
41 | return -1; | |
42 | #endif | |
43 | } | |
44 | ||
6b79eb38 SK |
45 | /* Create open temporary file in safe way. Please notice that the |
46 | * file permissions are -rw------- by default. */ | |
bde91c85 | 47 | int xmkstemp(char **tmpname, const char *dir, const char *prefix) |
6b79eb38 SK |
48 | { |
49 | char *localtmp; | |
bde91c85 | 50 | const char *tmpenv; |
6b79eb38 | 51 | mode_t old_mode; |
f272b32c | 52 | int fd, rc; |
6b79eb38 | 53 | |
3c4fed09 DR |
54 | /* Some use cases must be capable of being moved atomically |
55 | * with rename(2), which is the reason why dir is here. */ | |
bde91c85 KZ |
56 | tmpenv = dir ? dir : getenv("TMPDIR"); |
57 | if (!tmpenv) | |
58 | tmpenv = _PATH_TMP; | |
f272b32c | 59 | |
bde91c85 | 60 | rc = asprintf(&localtmp, "%s/%s.XXXXXX", tmpenv, prefix); |
f272b32c KZ |
61 | if (rc < 0) |
62 | return -1; | |
63 | ||
6b79eb38 | 64 | old_mode = umask(077); |
4d751c00 | 65 | fd = mkstemp_cloexec(localtmp); |
6b79eb38 | 66 | umask(old_mode); |
7961acce SK |
67 | if (fd == -1) { |
68 | free(localtmp); | |
69 | localtmp = NULL; | |
70 | } | |
6b79eb38 | 71 | *tmpname = localtmp; |
7961acce | 72 | return fd; |
6b79eb38 SK |
73 | } |
74 | ||
8e86d93d GJ |
75 | int dup_fd_cloexec(int oldfd, int lowfd) |
76 | { | |
77 | int fd, flags, errno_save; | |
78 | ||
79 | #ifdef F_DUPFD_CLOEXEC | |
80 | fd = fcntl(oldfd, F_DUPFD_CLOEXEC, lowfd); | |
81 | if (fd >= 0) | |
82 | return fd; | |
83 | #endif | |
84 | ||
85 | fd = dup(oldfd); | |
86 | if (fd < 0) | |
87 | return fd; | |
88 | ||
89 | flags = fcntl(fd, F_GETFD); | |
90 | if (flags < 0) | |
91 | goto unwind; | |
92 | if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) | |
93 | goto unwind; | |
94 | ||
95 | return fd; | |
96 | ||
97 | unwind: | |
98 | errno_save = errno; | |
99 | close(fd); | |
100 | errno = errno_save; | |
101 | ||
102 | return -1; | |
103 | } | |
104 | ||
be92327e KZ |
105 | /* |
106 | * portable getdtablesize() | |
107 | */ | |
108 | int get_fd_tabsize(void) | |
109 | { | |
110 | int m; | |
111 | ||
112 | #if defined(HAVE_GETDTABLESIZE) | |
113 | m = getdtablesize(); | |
114 | #elif defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) | |
115 | struct rlimit rl; | |
116 | ||
117 | getrlimit(RLIMIT_NOFILE, &rl); | |
118 | m = rl.rlim_cur; | |
119 | #elif defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) | |
120 | m = sysconf(_SC_OPEN_MAX); | |
121 | #else | |
122 | m = OPEN_MAX; | |
123 | #endif | |
124 | return m; | |
125 | } | |
126 | ||
e8f7acb0 | 127 | #ifdef TEST_PROGRAM_FILEUTILS |
6b79eb38 SK |
128 | int main(void) |
129 | { | |
130 | FILE *f; | |
131 | char *tmpname; | |
bde91c85 | 132 | f = xfmkstemp(&tmpname, NULL, "test"); |
6b79eb38 SK |
133 | unlink(tmpname); |
134 | free(tmpname); | |
135 | fclose(f); | |
136 | return EXIT_FAILURE; | |
137 | } | |
138 | #endif | |
934530c7 KZ |
139 | |
140 | ||
141 | int mkdir_p(const char *path, mode_t mode) | |
142 | { | |
143 | char *p, *dir; | |
144 | int rc = 0; | |
145 | ||
146 | if (!path || !*path) | |
147 | return -EINVAL; | |
148 | ||
149 | dir = p = strdup(path); | |
150 | if (!dir) | |
151 | return -ENOMEM; | |
152 | ||
153 | if (*p == '/') | |
154 | p++; | |
155 | ||
156 | while (p && *p) { | |
157 | char *e = strchr(p, '/'); | |
158 | if (e) | |
159 | *e = '\0'; | |
160 | if (*p) { | |
161 | rc = mkdir(dir, mode); | |
162 | if (rc && errno != EEXIST) | |
163 | break; | |
164 | rc = 0; | |
165 | } | |
166 | if (!e) | |
167 | break; | |
168 | *e = '/'; | |
169 | p = e + 1; | |
170 | } | |
171 | ||
172 | free(dir); | |
173 | return rc; | |
174 | } | |
d4eaabc8 KZ |
175 | |
176 | /* returns basename and keeps dirname in the @path, if @path is "/" (root) | |
177 | * then returns empty string */ | |
178 | char *stripoff_last_component(char *path) | |
179 | { | |
180 | char *p = path ? strrchr(path, '/') : NULL; | |
181 | ||
182 | if (!p) | |
183 | return NULL; | |
184 | *p = '\0'; | |
185 | return p + 1; | |
186 | } |