]> git.sesse.net Git - vlc/blob - src/win32/filesystem.c
udp: fix locking (fixes #14234) and cancellation
[vlc] / src / win32 / filesystem.c
1 /*****************************************************************************
2  * filesystem.c: Windows file system helpers
3  *****************************************************************************
4  * Copyright (C) 2005-2006 VLC authors and VideoLAN
5  * Copyright © 2005-2008 Rémi Denis-Courmont
6  *
7  * Authors: Rémi Denis-Courmont <rem # videolan.org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <assert.h>
32
33 #include <stdio.h>
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <dirent.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <winsock2.h>
40 #include <direct.h>
41
42 #include <vlc_common.h>
43 #include <vlc_charset.h>
44 #include <vlc_fs.h>
45 #include "libvlc.h" /* vlc_mkdir */
46
47 #ifdef _MSC_VER
48 # define __STDC__ 1
49 # include <io.h> /* _pipe */
50 #endif
51
52 static wchar_t *widen_path (const char *path)
53 {
54     wchar_t *wpath;
55
56     errno = 0;
57     wpath = ToWide (path);
58     if (wpath == NULL)
59     {
60         if (errno == 0)
61             errno = ENOENT;
62         return NULL;
63     }
64     return wpath;
65 }
66
67 #define CONVERT_PATH(path, wpath, err) \
68     wchar_t *wpath = wide_path(path); \
69     if (wpath == NULL) return (err)
70
71
72 int vlc_open (const char *filename, int flags, ...)
73 {
74     int mode = 0;
75     va_list ap;
76
77     flags |= O_NOINHERIT; /* O_CLOEXEC */
78     /* Defaults to binary mode */
79     if ((flags & O_TEXT) == 0)
80         flags |= O_BINARY;
81
82     va_start (ap, flags);
83     if (flags & O_CREAT)
84         mode = va_arg (ap, int);
85     va_end (ap);
86
87     /*
88      * open() cannot open files with non-“ANSI” characters on Windows.
89      * We use _wopen() instead. Same thing for mkdir() and stat().
90      */
91     wchar_t *wpath = widen_path (filename);
92     if (wpath == NULL)
93         return -1;
94
95     int fd = _wopen (wpath, flags, mode);
96     free (wpath);
97     return fd;
98 }
99
100 int vlc_openat (int dir, const char *filename, int flags, ...)
101 {
102     (void) dir; (void) filename; (void) flags;
103     errno = ENOSYS;
104     return -1;
105 }
106
107 int vlc_mkdir( const char *dirname, mode_t mode )
108 {
109     wchar_t *wpath = widen_path (dirname);
110     if (wpath == NULL)
111         return -1;
112
113     int ret = _wmkdir (wpath);
114     free (wpath);
115     (void) mode;
116     return ret;
117 }
118
119 char *vlc_getcwd (void)
120 {
121     wchar_t *wdir = _wgetcwd (NULL, 0);
122     if (wdir == NULL)
123         return NULL;
124
125     char *dir = FromWide (wdir);
126     free (wdir);
127     return dir;
128 }
129
130 /* Under Windows, these wrappers return the list of drive letters
131  * when called with an empty argument or just '\'. */
132 DIR *vlc_opendir (const char *dirname)
133 {
134     wchar_t *wpath = widen_path (dirname);
135     if (wpath == NULL)
136         return NULL;
137
138     vlc_DIR *p_dir = malloc (sizeof (*p_dir));
139     if (unlikely(p_dir == NULL))
140     {
141         free(wpath);
142         return NULL;
143     }
144
145 #if !VLC_WINSTORE_APP
146     /* Special mode to list drive letters */
147     if (wpath[0] == L'\0' || (wcscmp (wpath, L"\\") == 0))
148     {
149         free (wpath);
150         p_dir->wdir = NULL;
151         p_dir->u.drives = GetLogicalDrives ();
152         p_dir->entry = NULL;
153         return (void *)p_dir;
154     }
155 #endif
156
157     assert (wpath[0]); // wpath[1] is defined
158     p_dir->u.insert_dot_dot = !wcscmp (wpath + 1, L":\\");
159
160     _WDIR *wdir = _wopendir (wpath);
161     free (wpath);
162     if (wdir == NULL)
163     {
164         free (p_dir);
165         return NULL;
166     }
167     p_dir->wdir = wdir;
168     p_dir->entry = NULL;
169     return (void *)p_dir;
170 }
171
172 char *vlc_readdir (DIR *dir)
173 {
174     vlc_DIR *p_dir = (vlc_DIR *)dir;
175
176     free(p_dir->entry);
177
178 #if !VLC_WINSTORE_APP
179     /* Drive letters mode */
180     if (p_dir->wdir == NULL)
181     {
182         DWORD drives = p_dir->u.drives;
183         if (drives == 0)
184         {
185             p_dir->entry = NULL;
186             return NULL; /* end */
187         }
188
189         unsigned int i;
190         for (i = 0; !(drives & 1); i++)
191             drives >>= 1;
192         p_dir->u.drives &= ~(1UL << i);
193         assert (i < 26);
194
195         if (asprintf (&p_dir->entry, "%c:\\", 'A' + i) == -1)
196             p_dir->entry = NULL;
197     }
198     else
199 #endif
200     if (p_dir->u.insert_dot_dot)
201     {
202         /* Adds "..", gruik! */
203         p_dir->u.insert_dot_dot = false;
204         p_dir->entry = strdup ("..");
205     }
206     else
207     {
208         struct _wdirent *ent = _wreaddir (p_dir->wdir);
209         p_dir->entry = (ent != NULL) ? FromWide (ent->d_name) : NULL;
210     }
211     return p_dir->entry;
212 }
213
214 int vlc_stat (const char *filename, struct stat *buf)
215 {
216     wchar_t *wpath = widen_path (filename);
217     if (wpath == NULL)
218         return -1;
219
220     static_assert (sizeof (*buf) == sizeof (struct _stati64),
221                    "Mismatched struct stat definition.");
222
223     int ret = _wstati64 (wpath, buf);
224     free (wpath);
225     return ret;
226 }
227
228 int vlc_lstat (const char *filename, struct stat *buf)
229 {
230     return vlc_stat (filename, buf);
231 }
232
233 int vlc_unlink (const char *filename)
234 {
235     wchar_t *wpath = widen_path (filename);
236     if (wpath == NULL)
237         return -1;
238
239     int ret = _wunlink (wpath);
240     free (wpath);
241     return ret;
242 }
243
244 int vlc_rename (const char *oldpath, const char *newpath)
245 {
246     int ret = -1;
247
248     wchar_t *wold = widen_path (oldpath), *wnew = widen_path (newpath);
249     if (wold == NULL || wnew == NULL)
250         goto out;
251
252     if (_wrename (wold, wnew) && (errno == EACCES || errno == EEXIST))
253     {   /* Windows does not allow atomic file replacement */
254         if (_wremove (wnew))
255         {
256             errno = EACCES; /* restore errno */
257             goto out;
258         }
259         if (_wrename (wold, wnew))
260             goto out;
261     }
262     ret = 0;
263 out:
264     free (wnew);
265     free (wold);
266     return ret;
267 }
268
269 int vlc_dup (int oldfd)
270 {
271     int fd = dup (oldfd);
272     if (fd != -1)
273         setmode (fd, O_BINARY);
274     return fd;
275 }
276
277 int vlc_pipe (int fds[2])
278 {
279 #if VLC_WINSTORE_APP
280     _set_errno(EPERM);
281     return -1;
282 #else
283     return _pipe (fds, 32768, O_NOINHERIT | O_BINARY);
284 #endif
285 }
286
287 #include <vlc_network.h>
288
289 int vlc_socket (int pf, int type, int proto, bool nonblock)
290 {
291     int fd = socket (pf, type, proto);
292     if (fd == -1)
293         return -1;
294
295     if (nonblock)
296         ioctlsocket (fd, FIONBIO, &(unsigned long){ 1 });
297     return fd;
298 }
299
300 int vlc_accept (int lfd, struct sockaddr *addr, socklen_t *alen, bool nonblock)
301 {
302     int fd = accept (lfd, addr, alen);
303     if (fd != -1 && nonblock)
304         ioctlsocket (fd, FIONBIO, &(unsigned long){ 1 });
305     return fd;
306 }
307
308 #if !VLC_WINSTORE_APP
309 FILE *vlc_win32_tmpfile(void)
310 {
311     TCHAR tmp_path[MAX_PATH-14];
312     int i_ret = GetTempPath (MAX_PATH-14, tmp_path);
313     if (i_ret == 0)
314         return NULL;
315
316     TCHAR tmp_name[MAX_PATH];
317     i_ret = GetTempFileName(tmp_path, TEXT("VLC"), 0, tmp_name);
318     if (i_ret == 0)
319         return NULL;
320
321     HANDLE hFile = CreateFile(tmp_name,
322             GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS,
323             FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL);
324     if (hFile == INVALID_HANDLE_VALUE)
325         return NULL;
326
327     int fd = _open_osfhandle((intptr_t)hFile, 0);
328     if (fd == -1) {
329         CloseHandle(hFile);
330         return NULL;
331     }
332
333     FILE *stream = _fdopen(fd, "w+b");
334     if (stream == NULL) {
335         _close(fd);
336         return NULL;
337     }
338     return stream;
339 }
340 #else
341 FILE *vlc_win32_tmpfile(void)
342 {
343     return NULL;
344 }
345 #endif
346