]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - lib/fileutils.c
2 * This code is in the public domain; do with it what you wish.
4 * Copyright (C) 2012 Sami Kerola <kerolasa@iki.fi>
5 * Copyright (C) 2012-2020 Karel Zak <kzak@redhat.com>
13 #include <sys/resource.h>
18 #include "fileutils.h"
19 #include "pathnames.h"
21 int mkstemp_cloexec(char *template)
24 return mkostemp(template, O_RDWR
|O_CREAT
|O_EXCL
|O_CLOEXEC
);
26 int fd
, old_flags
, errno_save
;
28 fd
= mkstemp(template);
32 old_flags
= fcntl(fd
, F_GETFD
, 0);
35 if (fcntl(fd
, F_SETFD
, old_flags
| O_CLOEXEC
) < 0)
50 /* Create open temporary file in safe way. Please notice that the
51 * file permissions are -rw------- by default. */
52 int xmkstemp(char **tmpname
, const char *dir
, const char *prefix
)
59 /* Some use cases must be capable of being moved atomically
60 * with rename(2), which is the reason why dir is here. */
61 tmpenv
= dir
? dir
: getenv("TMPDIR");
65 rc
= asprintf(&localtmp
, "%s/%s.XXXXXX", tmpenv
, prefix
);
69 old_mode
= umask(077);
70 fd
= mkstemp_cloexec(localtmp
);
80 int dup_fd_cloexec(int oldfd
, int lowfd
)
82 int fd
, flags
, errno_save
;
84 #ifdef F_DUPFD_CLOEXEC
85 fd
= fcntl(oldfd
, F_DUPFD_CLOEXEC
, lowfd
);
94 flags
= fcntl(fd
, F_GETFD
);
97 if (fcntl(fd
, F_SETFD
, flags
| FD_CLOEXEC
) < 0)
111 * portable getdtablesize()
113 unsigned int get_fd_tabsize(void)
117 #if defined(HAVE_GETDTABLESIZE)
119 #elif defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
122 getrlimit(RLIMIT_NOFILE
, &rl
);
124 #elif defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
125 m
= sysconf(_SC_OPEN_MAX
);
132 #ifndef HAVE_CLOSE_RANGE
133 void close_all_fds(unsigned int first
, unsigned int last
)
138 dir
= opendir(_PATH_PROC_FDDIR
);
140 while ((d
= xreaddir(dir
))) {
146 fd
= strtoul(d
->d_name
, &end
, 10);
148 if (errno
|| end
== d
->d_name
|| !end
|| *end
)
153 if ((unsigned int)dfd
== fd
)
155 if (fd
< first
|| last
< fd
)
161 unsigned fd
, tbsz
= get_fd_tabsize();
163 for (fd
= 0; fd
< tbsz
; fd
++) {
164 if (first
<= fd
&& fd
<= last
)
171 #ifdef TEST_PROGRAM_FILEUTILS
172 int main(int argc
, char *argv
[])
175 errx(EXIT_FAILURE
, "Usage %s --{mkstemp,close-fds,copy-file}", argv
[0]);
177 if (strcmp(argv
[1], "--mkstemp") == 0) {
179 char *tmpname
= NULL
;
181 f
= xfmkstemp(&tmpname
, NULL
, "test");
186 } else if (strcmp(argv
[1], "--close-fds") == 0) {
187 ignore_result( dup(STDIN_FILENO
) );
188 ignore_result( dup(STDIN_FILENO
) );
189 ignore_result( dup(STDIN_FILENO
) );
191 # ifdef HAVE_CLOSE_RANGE
192 close_range(STDERR_FILENO
+ 1, ~0U);
194 close_all_fds(STDERR_FILENO
+ 1, ~0U);
196 } else if (strcmp(argv
[1], "--copy-file") == 0) {
197 int ret
= ul_copy_file(STDIN_FILENO
, STDOUT_FILENO
);
198 if (ret
== UL_COPY_READ_ERROR
)
199 err(EXIT_FAILURE
, "read");
200 else if (ret
== UL_COPY_WRITE_ERROR
)
201 err(EXIT_FAILURE
, "write");
208 int mkdir_p(const char *path
, mode_t mode
)
216 dir
= p
= strdup(path
);
224 char *e
= strchr(p
, '/');
228 rc
= mkdir(dir
, mode
);
229 if (rc
&& errno
!= EEXIST
)
243 /* returns basename and keeps dirname in the @path, if @path is "/" (root)
244 * then returns empty string */
245 char *stripoff_last_component(char *path
)
247 char *p
= path
? strrchr(path
, '/') : NULL
;
255 static int copy_file_simple(int from
, int to
)
260 while ((nr
= read_all(from
, buf
, sizeof(buf
))) > 0)
261 if (write_all(to
, buf
, nr
) == -1)
262 return UL_COPY_WRITE_ERROR
;
264 return UL_COPY_READ_ERROR
;
265 #ifdef HAVE_EXPLICIT_BZERO
266 explicit_bzero(buf
, sizeof(buf
));
271 /* Copies the contents of a file. Returns -1 on read error, -2 on write error. */
272 int ul_copy_file(int from
, int to
)
278 if (fstat(from
, &st
) == -1)
279 return UL_COPY_READ_ERROR
;
280 if (!S_ISREG(st
.st_mode
))
281 return copy_file_simple(from
, to
);
282 if (sendfile_all(to
, from
, NULL
, st
.st_size
) < 0)
283 return copy_file_simple(from
, to
);
284 /* ensure we either get an EOF or an error */
285 while ((nw
= sendfile_all(to
, from
, NULL
, 16*1024*1024)) != 0)
287 return copy_file_simple(from
, to
);
290 return copy_file_simple(from
, to
);