]> git.sesse.net Git - vlc/blob - src/text/filesystem.c
decoder: fix data race in sout
[vlc] / src / text / filesystem.c
1 /*****************************************************************************
2  * filesystem.c: Common 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 <vlc_common.h>
32 #include <vlc_fs.h>
33 #include <vlc_rand.h>
34
35 #include <assert.h>
36
37 #include <stdio.h>
38 #include <errno.h>
39 #include <sys/types.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42
43 /**
44  * Opens a FILE pointer.
45  * @param filename file path, using UTF-8 encoding
46  * @param mode fopen file open mode
47  * @return NULL on error, an open FILE pointer on success.
48  */
49 FILE *vlc_fopen (const char *filename, const char *mode)
50 {
51     int rwflags = 0, oflags = 0;
52
53     for (const char *ptr = mode; *ptr; ptr++)
54     {
55         switch (*ptr)
56         {
57             case 'r':
58                 rwflags = O_RDONLY;
59                 break;
60
61             case 'a':
62                 rwflags = O_WRONLY;
63                 oflags |= O_CREAT | O_APPEND;
64                 break;
65
66             case 'w':
67                 rwflags = O_WRONLY;
68                 oflags |= O_CREAT | O_TRUNC;
69                 break;
70
71             case 'x':
72                 oflags |= O_EXCL;
73                 break;
74
75             case '+':
76                 rwflags = O_RDWR;
77                 break;
78
79 #ifdef O_BINARY
80             case 'b':
81                 oflags = (oflags & ~O_TEXT) | O_BINARY;
82                 break;
83
84             case 't':
85                 oflags = (oflags & ~O_BINARY) | O_TEXT;
86                 break;
87 #endif
88         }
89     }
90
91     int fd = vlc_open (filename, rwflags | oflags, 0666);
92     if (fd == -1)
93         return NULL;
94
95     FILE *stream = fdopen (fd, mode);
96     if (stream == NULL)
97         close (fd);
98
99     return stream;
100 }
101
102
103 static int dummy_select( const char *str )
104 {
105     (void)str;
106     return 1;
107 }
108
109 /**
110  * Does the same as vlc_scandir(), but takes an open directory pointer
111  * instead of a directory path.
112  */
113 int vlc_loaddir( DIR *dir, char ***namelist,
114                   int (*select)( const char * ),
115                   int (*compar)( const char **, const char ** ) )
116 {
117     assert (dir);
118
119     if (select == NULL)
120         select = dummy_select;
121
122     char **tab = NULL;
123     unsigned num = 0;
124
125     rewinddir (dir);
126
127     for (unsigned size = 0;;)
128     {
129         errno = 0;
130         const char *entry = vlc_readdir (dir);
131         if (entry == NULL)
132         {
133             if (errno)
134                 goto error;
135             break;
136         }
137
138         if (!select (entry))
139             continue;
140
141         if (num >= size)
142         {
143             size = size ? (2 * size) : 16;
144             char **newtab = realloc (tab, sizeof (*tab) * (size));
145
146             if (unlikely(newtab == NULL))
147                 goto error;
148             tab = newtab;
149         }
150
151         tab[num] = strdup(entry);
152         if (likely(tab[num] != NULL))
153             num++;
154     }
155
156     if (compar != NULL && num > 0)
157         qsort (tab, num, sizeof (*tab),
158                (int (*)( const void *, const void *))compar);
159     *namelist = tab;
160     return num;
161
162 error:
163     for (unsigned i = 0; i < num; i++)
164         free (tab[i]);
165     free (tab);
166     return -1;
167 }
168
169 /**
170  * Selects file entries from a directory, as GNU C scandir().
171  *
172  * @param dirname UTF-8 diretory path
173  * @param pointer [OUT] pointer set, on successful completion, to the address
174  * of a table of UTF-8 filenames. All filenames must be freed with free().
175  * The table itself must be freed with free() as well.
176  *
177  * @return How many file names were selected (possibly 0),
178  * or -1 in case of error.
179  */
180 int vlc_scandir( const char *dirname, char ***namelist,
181                   int (*select)( const char * ),
182                   int (*compar)( const char **, const char ** ) )
183 {
184     DIR *dir = vlc_opendir (dirname);
185     int val = -1;
186
187     if (dir != NULL)
188     {
189         val = vlc_loaddir (dir, namelist, select, compar);
190         closedir (dir);
191     }
192     return val;
193 }
194
195 int vlc_mkstemp( char *template )
196 {
197     static const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
198     static const int i_digits = sizeof(digits)/sizeof(*digits) - 1;
199
200     /* */
201     assert( template );
202
203     /* Check template validity */
204     const size_t i_length = strlen( template );
205     char *psz_rand = &template[i_length-6];
206
207     if( i_length < 6 || strcmp( psz_rand, "XXXXXX" ) )
208     {
209         errno = EINVAL;
210         return -1;
211     }
212
213     /* */
214     for( int i = 0; i < 256; i++ )
215     {
216         /* Create a pseudo random file name */
217         uint8_t pi_rand[6];
218
219         vlc_rand_bytes( pi_rand, sizeof(pi_rand) );
220         for( int j = 0; j < 6; j++ )
221             psz_rand[j] = digits[pi_rand[j] % i_digits];
222
223         /* */
224         int fd = vlc_open( template, O_CREAT | O_EXCL | O_RDWR, 0600 );
225         if( fd >= 0 )
226             return fd;
227         if( errno != EEXIST )
228             return -1;
229     }
230
231     errno = EEXIST;
232     return -1;
233 }