1 /*****************************************************************************
2 * filesystem.c: POSIX file system helpers
3 *****************************************************************************
4 * Copyright (C) 2005-2006 VLC authors and VideoLAN
5 * Copyright © 2005-2008 Rémi Denis-Courmont
7 * Authors: Rémi Denis-Courmont <rem # videolan.org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
31 #include <limits.h> /* NAME_MAX */
35 #include <sys/types.h>
41 # define lstat(a, b) stat(a, b)
44 #include <sys/socket.h>
49 #include <vlc_common.h>
52 #if !defined(HAVE_ACCEPT4) || !defined HAVE_MKOSTEMP
53 static inline void vlc_cloexec(int fd
)
55 fcntl(fd
, F_SETFD
, FD_CLOEXEC
| fcntl(fd
, F_GETFD
));
59 int vlc_open (const char *filename
, int flags
, ...)
61 unsigned int mode
= 0;
65 if (flags
& (O_CREAT
|O_TMPFILE
))
66 mode
= va_arg (ap
, unsigned int);
70 return open(filename
, flags
, mode
| O_CLOEXEC
);
72 int fd
= open(filename
, flags
, mode
);
79 int vlc_openat (int dir
, const char *filename
, int flags
, ...)
81 unsigned int mode
= 0;
85 if (flags
& (O_CREAT
|O_TMPFILE
))
86 mode
= va_arg (ap
, unsigned int);
90 return openat(dir
, filename
, flags
, mode
| O_CLOEXEC
);
93 VLC_UNUSED (filename
);
100 int vlc_mkstemp (char *template)
102 #if defined (HAVE_MKOSTEMP) && defined (O_CLOEXEC)
103 return mkostemp(template, O_CLOEXEC
);
105 int fd
= mkstemp(template);
116 fd
= vlc_open ("/tmp", O_RDWR
|O_TMPFILE
, S_IRUSR
|S_IWUSR
);
119 /* ENOENT means either /tmp is missing (!) or the kernel does not support
120 * O_TMPFILE. EISDIR means /tmp exists but the kernel does not support
121 * O_TMPFILE. EOPNOTSUPP means the kernel supports O_TMPFILE but the /tmp
122 * filesystem does not. Do not fallback on other errors. */
123 if (errno
!= ENOENT
&& errno
!= EISDIR
&& errno
!= EOPNOTSUPP
)
127 char bufpath
[] = "/tmp/"PACKAGE_NAME
"XXXXXX";
129 fd
= vlc_mkstemp (bufpath
);
135 int vlc_close (int fd
)
138 #ifdef POSIX_CLOSE_RESTART
139 ret
= posix_close(fd
, 0);
142 /* POSIX.2008 (and earlier) does not specify if the file descriptor is
143 * closed on failure. Assume it is as on Linux and most other common OSes.
144 * Also emulate the correct error code as per newer POSIX versions. */
145 if (unlikely(ret
!= 0) && unlikely(errno
== EINTR
))
148 assert(ret
== 0 || errno
!= EBADF
); /* something is corrupt? */
152 int vlc_mkdir (const char *dirname
, mode_t mode
)
154 return mkdir (dirname
, mode
);
157 DIR *vlc_opendir (const char *dirname
)
159 return opendir (dirname
);
162 const char *vlc_readdir(DIR *dir
)
164 struct dirent
*ent
= readdir (dir
);
165 return (ent
!= NULL
) ? ent
->d_name
: NULL
;
168 int vlc_stat (const char *filename
, struct stat
*buf
)
170 return stat (filename
, buf
);
173 int vlc_lstat (const char *filename
, struct stat
*buf
)
175 return lstat (filename
, buf
);
178 int vlc_unlink (const char *filename
)
180 return unlink (filename
);
183 int vlc_rename (const char *oldpath
, const char *newpath
)
185 return rename (oldpath
, newpath
);
188 char *vlc_getcwd (void)
190 long path_max
= pathconf (".", _PC_PATH_MAX
);
191 size_t size
= (path_max
== -1 || path_max
> 4096) ? 4096 : path_max
;
195 char *buf
= malloc (size
);
196 if (unlikely(buf
== NULL
))
199 if (getcwd (buf
, size
) != NULL
)
209 int vlc_dup (int oldfd
)
211 #ifdef F_DUPFD_CLOEXEC
212 return fcntl (oldfd
, F_DUPFD_CLOEXEC
, 0);
214 int newfd
= dup (oldfd
);
221 int vlc_pipe (int fds
[2])
224 return pipe2(fds
, O_CLOEXEC
);
236 ssize_t
vlc_write(int fd
, const void *buf
, size_t len
)
238 struct iovec iov
= { .iov_base
= (void *)buf
, .iov_len
= len
};
240 return vlc_writev(fd
, &iov
, 1);
243 ssize_t
vlc_writev(int fd
, const struct iovec
*iov
, int count
)
248 sigaddset(&set
, SIGPIPE
);
249 pthread_sigmask(SIG_BLOCK
, &set
, &oset
);
251 ssize_t val
= writev(fd
, iov
, count
);
252 if (val
< 0 && errno
== EPIPE
)
254 #if (_POSIX_REALTIME_SIGNALS > 0)
256 struct timespec ts
= { 0, 0 };
258 while (sigtimedwait(&set
, &info
, &ts
) >= 0 || errno
!= EAGAIN
);
266 if (!sigismember(&s
, SIGPIPE
))
270 assert(num
== SIGPIPE
);
275 if (!sigismember(&oset
, SIGPIPE
)) /* Restore the signal mask if changed */
276 pthread_sigmask(SIG_SETMASK
, &oset
, NULL
);
280 #include <vlc_network.h>
283 static void vlc_socket_setup(int fd
, bool nonblock
)
288 fcntl(fd
, F_SETFL
, fcntl(fd
, F_GETFL
, 0) | O_NONBLOCK
);
291 setsockopt(fd
, SOL_SOCKET
, SO_NOSIGPIPE
, &(int){ 1 }, sizeof (int));
296 int vlc_socket (int pf
, int type
, int proto
, bool nonblock
)
300 type
|= SOCK_NONBLOCK
;
302 int fd
= socket(pf
, type
| SOCK_CLOEXEC
, proto
);
305 setsockopt(fd
, SOL_SOCKET
, SO_NOSIGPIPE
, &(int){ 1 }, sizeof (int));
308 int fd
= socket (pf
, type
, proto
);
310 vlc_socket_setup(fd
, nonblock
);
315 int vlc_socketpair(int pf
, int type
, int proto
, int fds
[2], bool nonblock
)
319 type
|= SOCK_NONBLOCK
;
321 int ret
= socketpair(pf
, type
| SOCK_CLOEXEC
, proto
, fds
);
327 setsockopt(fds
[0], SOL_SOCKET
, SO_NOSIGPIPE
, &val
, sizeof (val
));
328 setsockopt(fds
[1], SOL_SOCKET
, SO_NOSIGPIPE
, &val
, sizeof (val
));
332 int ret
= socketpair(pf
, type
, proto
, fds
);
335 vlc_socket_setup(fds
[0], nonblock
);
336 vlc_socket_setup(fds
[1], nonblock
);
342 int vlc_accept (int lfd
, struct sockaddr
*addr
, socklen_t
*alen
, bool nonblock
)
345 int flags
= SOCK_CLOEXEC
;
347 flags
|= SOCK_NONBLOCK
;
349 int fd
= accept4(lfd
, addr
, alen
, flags
);
352 setsockopt(fd
, SOL_SOCKET
, SO_NOSIGPIPE
, &(int){ 1 }, sizeof (int));
355 int fd
= accept(lfd
, addr
, alen
);
357 vlc_socket_setup(fd
, nonblock
);