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