WinCE: tentative compile fix
[vlc.git] / src / win32 / filesystem.c
1 /*****************************************************************************
2  * filesystem.c: Windows file system helpers
3  *****************************************************************************
4  * Copyright (C) 2005-2006 the VideoLAN team
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
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, 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 <vlc_common.h>
32 #include <vlc_charset.h>
33 #include <vlc_fs.h>
34 #include "libvlc.h" /* vlc_mkdir */
35
36 #include <assert.h>
37
38 #include <stdio.h>
39 #include <errno.h>
40 #include <sys/types.h>
41 #include <dirent.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #include <winsock2.h>
45 #ifndef UNDER_CE
46 # include <direct.h>
47 #else
48 # include <tchar.h>
49 #endif
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 #ifdef UNDER_CE
82     /*_open translates to wchar internally on WinCE*/
83     return _open (filename, flags, mode);
84 #else
85     /*
86      * open() cannot open files with non-“ANSI” characters on Windows.
87      * We use _wopen() instead. Same thing for mkdir() and stat().
88      */
89     wchar_t *wpath = widen_path (filename);
90     if (wpath == NULL)
91         return -1;
92
93     int fd = _wopen (wpath, flags, mode);
94     free (wpath);
95     return fd;
96 #endif
97 }
98
99 int vlc_openat (int dir, const char *filename, int flags, ...)
100 {
101     (void) dir; (void) filename; (void) flags;
102     errno = ENOSYS;
103     return -1;
104 }
105
106 int vlc_mkdir( const char *dirname, mode_t mode )
107 {
108 #if defined (UNDER_CE)
109     (void) mode;
110     /* mkdir converts internally to wchar */
111     return _mkdir(dirname);
112 #else
113     wchar_t *wpath = widen_path (dirname);
114     if (wpath == NULL)
115         return -1;
116
117     int ret = _wmkdir (wpath);
118     free (wpath);
119     (void) mode;
120     return ret;
121 #endif
122 }
123
124 char *vlc_getcwd (void)
125 {
126 #ifndef UNDER_CE
127     wchar_t *wdir = _wgetcwd (NULL, 0);
128     if (wdir == NULL)
129         return NULL;
130
131     char *dir = FromWide (wdir);
132     free (wdir);
133     return dir;
134 #else
135     return NULL;
136 #endif
137 }
138
139 /* Under Windows, these wrappers return the list of drive letters
140  * when called with an empty argument or just '\'. */
141 typedef struct vlc_DIR
142 {
143     _WDIR *wdir; /* MUST be first, see <vlc_fs.h> */
144     union
145     {
146         DWORD drives;
147         bool insert_dot_dot;
148     } u;
149 } vlc_DIR;
150
151
152 DIR *vlc_opendir (const char *dirname)
153 {
154     wchar_t *wpath = widen_path (dirname);
155     if (wpath == NULL)
156         return NULL;
157
158     vlc_DIR *p_dir = malloc (sizeof (*p_dir));
159     if (unlikely(p_dir == NULL))
160     {
161         free(wpath);
162         return NULL;
163     }
164
165     if (wpath[0] == L'\0' || (wcscmp (wpath, L"\\") == 0))
166     {
167         free (wpath);
168         /* Special mode to list drive letters */
169         p_dir->wdir = NULL;
170 #ifdef UNDER_CE
171         p_dir->u.drives = 1;
172 #else
173         p_dir->u.drives = GetLogicalDrives ();
174 #endif
175         return (void *)p_dir;
176     }
177
178     assert (wpath[0]); // wpath[1] is defined
179     p_dir->u.insert_dot_dot = !wcscmp (wpath + 1, L":\\");
180
181     _WDIR *wdir = _wopendir (wpath);
182     free (wpath);
183     if (wdir == NULL)
184     {
185         free (p_dir);
186         return NULL;
187     }
188     p_dir->wdir = wdir;
189     return (void *)p_dir;
190 }
191
192 char *vlc_readdir (DIR *dir)
193 {
194     vlc_DIR *p_dir = (vlc_DIR *)dir;
195
196     if (p_dir->wdir == NULL)
197     {
198         /* Drive letters mode */
199         DWORD drives = p_dir->u.drives;
200         if (drives == 0)
201             return NULL; /* end */
202 #ifdef UNDER_CE
203         p_dir->u.drives = 0;
204         return strdup ("\\");
205 #else
206         unsigned int i;
207         for (i = 0; !(drives & 1); i++)
208             drives >>= 1;
209         p_dir->u.drives &= ~(1UL << i);
210         assert (i < 26);
211
212         char *ret;
213         if (asprintf (&ret, "%c:\\", 'A' + i) == -1)
214             return NULL;
215         return ret;
216 #endif
217     }
218
219     if (p_dir->u.insert_dot_dot)
220     {
221         /* Adds "..", gruik! */
222         p_dir->u.insert_dot_dot = false;
223         return strdup ("..");
224     }
225
226     struct _wdirent *ent = _wreaddir (p_dir->wdir);
227     if (ent == NULL)
228         return NULL;
229     return FromWide (ent->d_name);
230 }
231
232 int vlc_stat (const char *filename, struct stat *buf)
233 {
234 #ifdef UNDER_CE
235     /* _stat translates to wchar internally on WinCE */
236     return _stat (filename, buf);
237 #else
238     wchar_t *wpath = widen_path (filename);
239     if (wpath == NULL)
240         return -1;
241
242     int ret = _wstati64 (wpath, buf);
243     free (wpath);
244     return ret;
245 #endif
246 }
247
248 int vlc_lstat (const char *filename, struct stat *buf)
249 {
250     return vlc_stat (filename, buf);
251 }
252
253 int vlc_unlink (const char *filename)
254 {
255 #ifdef UNDER_CE
256     /*_open translates to wchar internally on WinCE*/
257     return _unlink( filename );
258 #else
259     wchar_t *wpath = widen_path (filename);
260     if (wpath == NULL)
261         return -1;
262
263     int ret = _wunlink (wpath);
264     free (wpath);
265     return ret;
266 #endif
267 }
268
269 int vlc_rename (const char *oldpath, const char *newpath)
270 {
271     int ret = -1;
272
273     wchar_t *wold = widen_path (oldpath), *wnew = widen_path (newpath);
274     if (wold == NULL || wnew == NULL)
275         goto out;
276
277 # ifdef UNDER_CE
278     /* FIXME: errno support */
279     if (MoveFileW (wold, wnew))
280         ret = 0;
281 #else
282     if (_wrename (wold, wnew) && (errno == EACCES || errno == EEXIST))
283     {   /* Windows does not allow atomic file replacement */
284         if (_wremove (wnew))
285         {
286             errno = EACCES; /* restore errno */
287             goto out;
288         }
289         if (_wrename (wold, wnew))
290             goto out;
291     }
292     ret = 0;
293 #endif
294 out:
295     free (wnew);
296     free (wold);
297     return ret;
298 }
299
300 int vlc_dup (int oldfd)
301 {
302 #ifdef UNDER_CE
303     (void) oldfd;
304     errno = ENOSYS;
305     return -1;
306 #else
307     return dup (oldfd);
308 #endif
309 }
310
311 int vlc_pipe (int fds[2])
312 {
313 #ifdef UNDER_CE
314     (void) fds;
315     errno = ENOSYS;
316     return -1;
317 #else
318     return _pipe (fds, 32768, O_BINARY);
319 #endif
320 }
321
322 #include <vlc_network.h>
323
324 int vlc_socket (int pf, int type, int proto, bool nonblock)
325 {
326     int fd = socket (pf, type, proto);
327     if (fd == -1)
328         return -1;
329
330     if (nonblock)
331         ioctlsocket (fd, FIONBIO, &(unsigned long){ 1 });
332     return fd;
333 }
334
335 int vlc_accept (int lfd, struct sockaddr *addr, socklen_t *alen, bool nonblock)
336 {
337     int fd = accept (lfd, addr, alen);
338     if (fd != -1 && nonblock)
339         ioctlsocket (fd, FIONBIO, &(unsigned long){ 1 });
340     return fd;
341 }