]> git.sesse.net Git - vlc/blob - src/win32/filesystem.c
Win32: put duplicated file handles to binary mode
[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 static wchar_t *widen_path (const char *path)
48 {
49     wchar_t *wpath;
50
51     errno = 0;
52     wpath = ToWide (path);
53     if (wpath == NULL)
54     {
55         if (errno == 0)
56             errno = ENOENT;
57         return NULL;
58     }
59     return wpath;
60 }
61
62 #define CONVERT_PATH(path, wpath, err) \
63     wchar_t *wpath = wide_path(path); \
64     if (wpath == NULL) return (err)
65
66
67 int vlc_open (const char *filename, int flags, ...)
68 {
69     unsigned int mode = 0;
70     va_list ap;
71
72     va_start (ap, flags);
73     if (flags & O_CREAT)
74         mode = va_arg (ap, unsigned int);
75     va_end (ap);
76
77     /* Defaults to binary mode */
78     if ((flags & O_TEXT) == 0)
79         flags |= O_BINARY;
80
81     /*
82      * open() cannot open files with non-“ANSI” characters on Windows.
83      * We use _wopen() instead. Same thing for mkdir() and stat().
84      */
85     wchar_t *wpath = widen_path (filename);
86     if (wpath == NULL)
87         return -1;
88
89     int fd = _wopen (wpath, flags, mode);
90     free (wpath);
91     return fd;
92 }
93
94 int vlc_openat (int dir, const char *filename, int flags, ...)
95 {
96     (void) dir; (void) filename; (void) flags;
97     errno = ENOSYS;
98     return -1;
99 }
100
101 int vlc_mkdir( const char *dirname, mode_t mode )
102 {
103     wchar_t *wpath = widen_path (dirname);
104     if (wpath == NULL)
105         return -1;
106
107     int ret = _wmkdir (wpath);
108     free (wpath);
109     (void) mode;
110     return ret;
111 }
112
113 char *vlc_getcwd (void)
114 {
115     wchar_t *wdir = _wgetcwd (NULL, 0);
116     if (wdir == NULL)
117         return NULL;
118
119     char *dir = FromWide (wdir);
120     free (wdir);
121     return dir;
122 }
123
124 /* Under Windows, these wrappers return the list of drive letters
125  * when called with an empty argument or just '\'. */
126 typedef struct vlc_DIR
127 {
128     _WDIR *wdir; /* MUST be first, see <vlc_fs.h> */
129     union
130     {
131         DWORD drives;
132         bool insert_dot_dot;
133     } u;
134 } vlc_DIR;
135
136
137 DIR *vlc_opendir (const char *dirname)
138 {
139     wchar_t *wpath = widen_path (dirname);
140     if (wpath == NULL)
141         return NULL;
142
143     vlc_DIR *p_dir = malloc (sizeof (*p_dir));
144     if (unlikely(p_dir == NULL))
145     {
146         free(wpath);
147         return NULL;
148     }
149
150     if (wpath[0] == L'\0' || (wcscmp (wpath, L"\\") == 0))
151     {
152         free (wpath);
153         /* Special mode to list drive letters */
154         p_dir->wdir = NULL;
155         p_dir->u.drives = GetLogicalDrives ();
156         return (void *)p_dir;
157     }
158
159     assert (wpath[0]); // wpath[1] is defined
160     p_dir->u.insert_dot_dot = !wcscmp (wpath + 1, L":\\");
161
162     _WDIR *wdir = _wopendir (wpath);
163     free (wpath);
164     if (wdir == NULL)
165     {
166         free (p_dir);
167         return NULL;
168     }
169     p_dir->wdir = wdir;
170     return (void *)p_dir;
171 }
172
173 char *vlc_readdir (DIR *dir)
174 {
175     vlc_DIR *p_dir = (vlc_DIR *)dir;
176
177     if (p_dir->wdir == NULL)
178     {
179         /* Drive letters mode */
180         DWORD drives = p_dir->u.drives;
181         if (drives == 0)
182             return NULL; /* end */
183
184         unsigned int i;
185         for (i = 0; !(drives & 1); i++)
186             drives >>= 1;
187         p_dir->u.drives &= ~(1UL << i);
188         assert (i < 26);
189
190         char *ret;
191         if (asprintf (&ret, "%c:\\", 'A' + i) == -1)
192             return NULL;
193         return ret;
194     }
195
196     if (p_dir->u.insert_dot_dot)
197     {
198         /* Adds "..", gruik! */
199         p_dir->u.insert_dot_dot = false;
200         return strdup ("..");
201     }
202
203     struct _wdirent *ent = _wreaddir (p_dir->wdir);
204     if (ent == NULL)
205         return NULL;
206     return FromWide (ent->d_name);
207 }
208
209 int vlc_stat (const char *filename, struct stat *buf)
210 {
211     wchar_t *wpath = widen_path (filename);
212     if (wpath == NULL)
213         return -1;
214
215     static_assert (sizeof (*buf) == sizeof (struct _stati64),
216                    "Mismatched struct stat definition.");
217
218     int ret = _wstati64 (wpath, buf);
219     free (wpath);
220     return ret;
221 }
222
223 int vlc_lstat (const char *filename, struct stat *buf)
224 {
225     return vlc_stat (filename, buf);
226 }
227
228 int vlc_unlink (const char *filename)
229 {
230     wchar_t *wpath = widen_path (filename);
231     if (wpath == NULL)
232         return -1;
233
234     int ret = _wunlink (wpath);
235     free (wpath);
236     return ret;
237 }
238
239 int vlc_rename (const char *oldpath, const char *newpath)
240 {
241     int ret = -1;
242
243     wchar_t *wold = widen_path (oldpath), *wnew = widen_path (newpath);
244     if (wold == NULL || wnew == NULL)
245         goto out;
246
247     if (_wrename (wold, wnew) && (errno == EACCES || errno == EEXIST))
248     {   /* Windows does not allow atomic file replacement */
249         if (_wremove (wnew))
250         {
251             errno = EACCES; /* restore errno */
252             goto out;
253         }
254         if (_wrename (wold, wnew))
255             goto out;
256     }
257     ret = 0;
258 out:
259     free (wnew);
260     free (wold);
261     return ret;
262 }
263
264 int vlc_dup (int oldfd)
265 {
266     int fd = dup (oldfd);
267     if (fd != -1)
268         setmode (fd, O_BINARY);
269     return fd;
270 }
271
272 int vlc_pipe (int fds[2])
273 {
274     return _pipe (fds, 32768, O_BINARY);
275 }
276
277 #include <vlc_network.h>
278
279 int vlc_socket (int pf, int type, int proto, bool nonblock)
280 {
281     int fd = socket (pf, type, proto);
282     if (fd == -1)
283         return -1;
284
285     if (nonblock)
286         ioctlsocket (fd, FIONBIO, &(unsigned long){ 1 });
287     return fd;
288 }
289
290 int vlc_accept (int lfd, struct sockaddr *addr, socklen_t *alen, bool nonblock)
291 {
292     int fd = accept (lfd, addr, alen);
293     if (fd != -1 && nonblock)
294         ioctlsocket (fd, FIONBIO, &(unsigned long){ 1 });
295     return fd;
296 }