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>
66 #include <vlc_interrupt.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
Read (access_t
*, void *, size_t);
132 static int FileSeek (access_t
*, uint64_t);
133 static int NoSeek (access_t
*, uint64_t);
134 static int FileControl (access_t
*, int, va_list);
136 /*****************************************************************************
137 * FileOpen: open the file
138 *****************************************************************************/
139 int FileOpen( vlc_object_t
*p_this
)
141 access_t
*p_access
= (access_t
*)p_this
;
146 if (!strcasecmp (p_access
->psz_name
, "fd"))
149 int oldfd
= strtol (p_access
->psz_location
, &end
, 10);
152 fd
= vlc_dup (oldfd
);
153 else if (*end
== '/' && end
> p_access
->psz_location
)
155 char *name
= vlc_uri_decode_duplicate (end
- 1);
159 fd
= vlc_openat (oldfd
, name
, O_RDONLY
| O_NONBLOCK
);
166 if (unlikely(p_access
->psz_filepath
== NULL
))
168 fd
= vlc_open (p_access
->psz_filepath
, O_RDONLY
| O_NONBLOCK
);
173 msg_Err (p_access
, "cannot open file %s (%s)",
174 p_access
->psz_filepath
? p_access
->psz_filepath
175 : p_access
->psz_location
,
176 vlc_strerror_c(errno
));
177 vlc_dialog_display_error (p_access
, _("File reading failed"),
178 _("VLC could not open the file \"%s\" (%s)."),
179 p_access
->psz_filepath
? p_access
->psz_filepath
180 : p_access
->psz_location
,
181 vlc_strerror(errno
));
188 msg_Err (p_access
, "read error: %s", vlc_strerror_c(errno
));
193 /* Force blocking mode back */
194 fcntl (fd
, F_SETFL
, fcntl (fd
, F_GETFL
) & ~O_NONBLOCK
);
197 /* Directories can be opened and read from, but only readdir() knows
198 * how to parse the data. The directory plugin will do it. */
199 if (S_ISDIR (st
.st_mode
))
201 #ifdef HAVE_FDOPENDIR
202 DIR *p_dir
= fdopendir(fd
);
204 msg_Err (p_access
, "fdopendir error: %s", vlc_strerror_c(errno
));
207 return DirInit (p_access
, p_dir
);
209 msg_Dbg (p_access
, "ignoring directory");
214 access_sys_t
*p_sys
= vlc_malloc(p_this
, sizeof (*p_sys
));
215 if (unlikely(p_sys
== NULL
))
217 p_access
->pf_read
= Read
;
218 p_access
->pf_block
= NULL
;
219 p_access
->pf_control
= FileControl
;
220 p_access
->p_sys
= p_sys
;
223 if (S_ISREG (st
.st_mode
) || S_ISBLK (st
.st_mode
))
225 p_access
->pf_seek
= FileSeek
;
226 p_sys
->b_pace_control
= true;
228 /* Demuxers will need the beginning of the file for probing. */
229 posix_fadvise (fd
, 0, 4096, POSIX_FADV_WILLNEED
);
230 /* In most cases, we only read the file once. */
231 posix_fadvise (fd
, 0, 0, POSIX_FADV_NOREUSE
);
233 fcntl (fd
, F_NOCACHE
, 0);
236 if (IsRemote(fd
, p_access
->psz_filepath
))
237 fcntl (fd
, F_RDAHEAD
, 0);
239 fcntl (fd
, F_RDAHEAD
, 1);
244 p_access
->pf_seek
= NoSeek
;
245 p_sys
->b_pace_control
= strcasecmp (p_access
->psz_name
, "stream");
255 /*****************************************************************************
256 * FileClose: close the target
257 *****************************************************************************/
258 void FileClose (vlc_object_t
* p_this
)
260 access_t
*p_access
= (access_t
*)p_this
;
262 if (p_access
->pf_read
== NULL
)
268 access_sys_t
*p_sys
= p_access
->p_sys
;
270 vlc_close (p_sys
->fd
);
274 static ssize_t
Read (access_t
*p_access
, void *p_buffer
, size_t i_len
)
276 access_sys_t
*p_sys
= p_access
->p_sys
;
279 ssize_t val
= vlc_read_i11e (fd
, p_buffer
, i_len
);
289 msg_Err (p_access
, "read error: %s", vlc_strerror_c(errno
));
290 vlc_dialog_display_error (p_access
, _("File reading failed"),
291 _("VLC could not read the file (%s)."),
292 vlc_strerror(errno
));
299 /*****************************************************************************
300 * Seek: seek to a specific location in a file
301 *****************************************************************************/
302 static int FileSeek (access_t
*p_access
, uint64_t i_pos
)
304 access_sys_t
*sys
= p_access
->p_sys
;
306 if (lseek(sys
->fd
, i_pos
, SEEK_SET
) == (off_t
)-1)
311 static int NoSeek (access_t
*p_access
, uint64_t i_pos
)
313 /* vlc_assert_unreachable(); ?? */
314 (void) p_access
; (void) i_pos
;
318 /*****************************************************************************
320 *****************************************************************************/
321 static int FileControl( access_t
*p_access
, int i_query
, va_list args
)
323 access_sys_t
*p_sys
= p_access
->p_sys
;
329 case STREAM_CAN_SEEK
:
330 case STREAM_CAN_FASTSEEK
:
331 pb_bool
= va_arg( args
, bool * );
332 *pb_bool
= (p_access
->pf_seek
!= NoSeek
);
335 case STREAM_CAN_PAUSE
:
336 case STREAM_CAN_CONTROL_PACE
:
337 pb_bool
= va_arg( args
, bool * );
338 *pb_bool
= p_sys
->b_pace_control
;
341 case STREAM_GET_SIZE
:
345 if (fstat (p_sys
->fd
, &st
) || !S_ISREG(st
.st_mode
))
347 *va_arg( args
, uint64_t * ) = st
.st_size
;
351 case STREAM_GET_PTS_DELAY
:
352 pi_64
= va_arg( args
, int64_t * );
353 if (IsRemote (p_sys
->fd
, p_access
->psz_filepath
))
354 *pi_64
= var_InheritInteger (p_access
, "network-caching");
356 *pi_64
= var_InheritInteger (p_access
, "file-caching");
360 case STREAM_SET_PAUSE_STATE
: