1 /*****************************************************************************
2 * file.c: file input (file: access plug-in)
3 *****************************************************************************
4 * Copyright (C) 2001-2006 VLC authors and VideoLAN
5 * Copyright © 2006-2007 Rémi Denis-Courmont
8 * Authors: Christophe Massiot <massiot@via.ecp.fr>
9 * Rémi Denis-Courmont <rem # videolan # org>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
32 #include <sys/types.h>
36 # include <sys/statvfs.h>
37 # if defined (HAVE_SYS_MOUNT_H)
38 # include <sys/param.h>
39 # include <sys/mount.h>
42 #ifdef HAVE_LINUX_MAGIC_H
44 # include <linux/magic.h>
56 #include <vlc_common.h>
58 #include <vlc_input.h>
59 #include <vlc_access.h>
60 #include <vlc_dialog.h>
62 # include <vlc_charset.h>
75 #if !defined (_WIN32) && !defined (__OS2__)
76 static bool IsRemote (int fd
)
78 #if defined (HAVE_FSTATVFS) && defined (MNT_LOCAL)
81 if (fstatvfs (fd
, &stf
))
83 /* fstatvfs() is in POSIX, but MNT_LOCAL is not */
84 return !(stf
.f_flag
& MNT_LOCAL
);
86 #elif defined (HAVE_LINUX_MAGIC_H)
89 if (fstatfs (fd
, &stf
))
92 switch ((unsigned long)stf
.f_type
)
95 case CODA_SUPER_MAGIC
:
99 case 0xFF534D42 /*CIFS_MAGIC_NUMBER*/:
110 # define IsRemote(fd,path) IsRemote(fd)
112 #else /* _WIN32 || __OS2__ */
113 static bool IsRemote (const char *path
)
115 # if !defined(__OS2__) && !VLC_WINSTORE_APP
116 wchar_t *wpath
= ToWide (path
);
117 bool is_remote
= (wpath
!= NULL
&& PathIsNetworkPathW (wpath
));
121 return (! strncmp(path
, "\\\\", 2));
124 # define IsRemote(fd,path) IsRemote(path)
127 #ifndef HAVE_POSIX_FADVISE
128 # define posix_fadvise(fd, off, len, adv)
131 static ssize_t
FileRead (access_t
*, uint8_t *, size_t);
132 static int FileSeek (access_t
*, uint64_t);
133 static ssize_t
StreamRead (access_t
*, uint8_t *, size_t);
134 static int NoSeek (access_t
*, uint64_t);
135 static int FileControl (access_t
*, int, va_list);
137 /*****************************************************************************
138 * FileOpen: open the file
139 *****************************************************************************/
140 int FileOpen( vlc_object_t
*p_this
)
142 access_t
*p_access
= (access_t
*)p_this
;
147 if (!strcasecmp (p_access
->psz_access
, "fd"))
150 int oldfd
= strtol (p_access
->psz_location
, &end
, 10);
153 fd
= vlc_dup (oldfd
);
154 else if (*end
== '/' && end
> p_access
->psz_location
)
156 char *name
= decode_URI_duplicate (end
- 1);
160 fd
= vlc_openat (oldfd
, name
, O_RDONLY
| O_NONBLOCK
);
167 const char *path
= p_access
->psz_filepath
;
169 if (unlikely(path
== NULL
))
171 msg_Dbg (p_access
, "opening file `%s'", path
);
172 fd
= vlc_open (path
, O_RDONLY
| O_NONBLOCK
);
175 msg_Err (p_access
, "cannot open file %s (%s)", path
,
176 vlc_strerror_c(errno
));
177 dialog_Fatal (p_access
, _("File reading failed"),
178 _("VLC could not open the file \"%s\" (%s)."), path
,
179 vlc_strerror(errno
));
188 msg_Err (p_access
, "read error: %s", vlc_strerror_c(errno
));
193 int flags
= fcntl (fd
, F_GETFL
);
194 if (S_ISFIFO (st
.st_mode
) || S_ISSOCK (st
.st_mode
))
195 /* Force non-blocking mode where applicable (fd://) */
198 /* Force blocking mode when not useful or not specified */
199 flags
&= ~O_NONBLOCK
;
200 fcntl (fd
, F_SETFL
, flags
);
203 /* Directories can be opened and read from, but only readdir() knows
204 * how to parse the data. The directory plugin will do it. */
205 if (S_ISDIR (st
.st_mode
))
207 #ifdef HAVE_FDOPENDIR
208 DIR *handle
= fdopendir (fd
);
210 goto error
; /* Uh? */
211 return DirInit (p_access
, handle
);
213 msg_Dbg (p_access
, "ignoring directory");
218 access_sys_t
*p_sys
= malloc (sizeof (*p_sys
));
219 if (unlikely(p_sys
== NULL
))
221 access_InitFields (p_access
);
222 p_access
->pf_block
= NULL
;
223 p_access
->pf_control
= FileControl
;
224 p_access
->p_sys
= p_sys
;
227 if (S_ISREG (st
.st_mode
) || S_ISBLK (st
.st_mode
))
229 p_access
->pf_read
= FileRead
;
230 p_access
->pf_seek
= FileSeek
;
231 p_sys
->b_pace_control
= true;
232 p_sys
->size
= st
.st_size
;
234 /* Demuxers will need the beginning of the file for probing. */
235 posix_fadvise (fd
, 0, 4096, POSIX_FADV_WILLNEED
);
236 /* In most cases, we only read the file once. */
237 posix_fadvise (fd
, 0, 0, POSIX_FADV_NOREUSE
);
239 fcntl (fd
, F_NOCACHE
, 0);
242 if (IsRemote(fd
, p_access
->psz_filepath
))
243 fcntl (fd
, F_RDAHEAD
, 0);
245 fcntl (fd
, F_RDAHEAD
, 1);
250 p_access
->pf_read
= StreamRead
;
251 p_access
->pf_seek
= NoSeek
;
252 p_sys
->b_pace_control
= strcasecmp (p_access
->psz_access
, "stream");
263 /*****************************************************************************
264 * FileClose: close the target
265 *****************************************************************************/
266 void FileClose (vlc_object_t
* p_this
)
268 access_t
*p_access
= (access_t
*)p_this
;
270 if (p_access
->pf_read
== NULL
)
276 access_sys_t
*p_sys
= p_access
->p_sys
;
283 #include <vlc_network.h>
286 * Reads from a regular file.
288 static ssize_t
FileRead (access_t
*p_access
, uint8_t *p_buffer
, size_t i_len
)
290 access_sys_t
*p_sys
= p_access
->p_sys
;
292 ssize_t val
= read (fd
, p_buffer
, i_len
);
303 msg_Err (p_access
, "read error: %s", vlc_strerror_c(errno
));
304 dialog_Fatal (p_access
, _("File reading failed"),
305 _("VLC could not read the file (%s)."),
306 vlc_strerror(errno
));
310 p_access
->info
.i_pos
+= val
;
311 p_access
->info
.b_eof
= !val
;
312 if (p_access
->info
.i_pos
>= p_sys
->size
)
316 if (fstat (fd
, &st
) == 0)
317 p_sys
->size
= st
.st_size
;
323 /*****************************************************************************
324 * Seek: seek to a specific location in a file
325 *****************************************************************************/
326 static int FileSeek (access_t
*p_access
, uint64_t i_pos
)
328 p_access
->info
.i_pos
= i_pos
;
329 p_access
->info
.b_eof
= false;
331 if (lseek (p_access
->p_sys
->fd
, i_pos
, SEEK_SET
) == (off_t
)-1)
337 * Reads from a non-seekable file.
339 static ssize_t
StreamRead (access_t
*p_access
, uint8_t *p_buffer
, size_t i_len
)
341 access_sys_t
*p_sys
= p_access
->p_sys
;
344 #if !defined (_WIN32) && !defined (__OS2__)
345 ssize_t val
= net_Read (p_access
, fd
, NULL
, p_buffer
, i_len
, false);
347 ssize_t val
= read (fd
, p_buffer
, i_len
);
358 msg_Err (p_access
, "read error: %s", vlc_strerror_c(errno
));
362 p_access
->info
.i_pos
+= val
;
363 p_access
->info
.b_eof
= !val
;
367 static int NoSeek (access_t
*p_access
, uint64_t i_pos
)
370 (void) p_access
; (void) i_pos
;
374 /*****************************************************************************
376 *****************************************************************************/
377 static int FileControl( access_t
*p_access
, int i_query
, va_list args
)
379 access_sys_t
*p_sys
= p_access
->p_sys
;
385 case ACCESS_CAN_SEEK
:
386 case ACCESS_CAN_FASTSEEK
:
387 pb_bool
= (bool*)va_arg( args
, bool* );
388 *pb_bool
= (p_access
->pf_seek
!= NoSeek
);
391 case ACCESS_CAN_PAUSE
:
392 case ACCESS_CAN_CONTROL_PACE
:
393 pb_bool
= (bool*)va_arg( args
, bool* );
394 *pb_bool
= p_sys
->b_pace_control
;
397 case ACCESS_GET_SIZE
:
401 if (fstat (p_sys
->fd
, &st
) == 0)
402 p_sys
->size
= st
.st_size
;
403 *va_arg( args
, uint64_t * ) = p_sys
->size
;
407 case ACCESS_GET_PTS_DELAY
:
408 pi_64
= (int64_t*)va_arg( args
, int64_t * );
409 if (IsRemote (p_sys
->fd
, p_access
->psz_filepath
))
410 *pi_64
= var_InheritInteger (p_access
, "network-caching");
412 *pi_64
= var_InheritInteger (p_access
, "file-caching");
416 case ACCESS_SET_PAUSE_STATE
: