X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Ffile.c;h=1b5d435078a0e3f052ba1c4fe89ede54fe7619ad;hb=339f955e7d0735bc74ed25e14b975e1b7a276855;hp=487c146d82ca9e6a9071f0bcdf25c7b041121806;hpb=75d005cf30df98d75e6748e168bbfc22763b5a09;p=vlc diff --git a/modules/access/file.c b/modules/access/file.c index 487c146d82..1b5d435078 100644 --- a/modules/access/file.c +++ b/modules/access/file.c @@ -1,26 +1,26 @@ /***************************************************************************** * file.c: file input (file: access plug-in) ***************************************************************************** - * Copyright (C) 2001-2006 the VideoLAN team + * Copyright (C) 2001-2006 VLC authors and VideoLAN * Copyright © 2006-2007 Rémi Denis-Courmont * $Id$ * * Authors: Christophe Massiot * Rémi Denis-Courmont * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ #ifdef HAVE_CONFIG_H @@ -44,7 +44,7 @@ # include #endif -#if defined( WIN32 ) +#if defined( _WIN32 ) # include # include # include @@ -53,19 +53,12 @@ #endif #include -#if defined( WIN32 ) && !defined( UNDER_CE ) -# ifdef lseek -# undef lseek -# endif -# define lseek _lseeki64 -#endif - #include #include "fs.h" #include #include #include -#ifdef WIN32 +#ifdef _WIN32 # include #endif #include @@ -73,15 +66,13 @@ struct access_sys_t { - unsigned int i_nb_reads; - int fd; - /* */ bool b_pace_control; + uint64_t size; }; -#if !defined (WIN32) && !defined (__OS2__) +#if !defined (_WIN32) && !defined (__OS2__) static bool IsRemote (int fd) { #if defined (HAVE_FSTATVFS) && defined (MNT_LOCAL) @@ -118,10 +109,10 @@ static bool IsRemote (int fd) } # define IsRemote(fd,path) IsRemote(fd) -#else /* WIN32 || __OS2__ */ +#else /* _WIN32 || __OS2__ */ static bool IsRemote (const char *path) { -# if !defined(UNDER_CE) && !defined(__OS2__) +# if !defined(__OS2__) && !VLC_WINSTORE_APP wchar_t *wpath = ToWide (path); bool is_remote = (wpath != NULL && PathIsNetworkPathW (wpath)); free (wpath); @@ -137,6 +128,12 @@ static bool IsRemote (const char *path) # define posix_fadvise(fd, off, len, adv) #endif +static ssize_t FileRead (access_t *, uint8_t *, size_t); +static int FileSeek (access_t *, uint64_t); +static ssize_t StreamRead (access_t *, uint8_t *, size_t); +static int NoSeek (access_t *, uint64_t); +static int FileControl (access_t *, int, va_list); + /***************************************************************************** * FileOpen: open the file *****************************************************************************/ @@ -169,13 +166,17 @@ int FileOpen( vlc_object_t *p_this ) { const char *path = p_access->psz_filepath; + if (unlikely(path == NULL)) + return VLC_EGENERIC; msg_Dbg (p_access, "opening file `%s'", path); fd = vlc_open (path, O_RDONLY | O_NONBLOCK); if (fd == -1) { - msg_Err (p_access, "cannot open file %s (%m)", path); + msg_Err (p_access, "cannot open file %s (%s)", path, + vlc_strerror_c(errno)); dialog_Fatal (p_access, _("File reading failed"), - _("VLC could not open the file \"%s\". (%m)"), path); + _("VLC could not open the file \"%s\" (%s)."), path, + vlc_strerror(errno)); } } if (fd == -1) @@ -184,9 +185,21 @@ int FileOpen( vlc_object_t *p_this ) struct stat st; if (fstat (fd, &st)) { - msg_Err (p_access, "failed to read (%m)"); + msg_Err (p_access, "read error: %s", vlc_strerror_c(errno)); goto error; } + +#if O_NONBLOCK + int flags = fcntl (fd, F_GETFL); + if (S_ISFIFO (st.st_mode) || S_ISSOCK (st.st_mode)) + /* Force non-blocking mode where applicable (fd://) */ + flags |= O_NONBLOCK; + else + /* Force blocking mode when not useful or not specified */ + flags &= ~O_NONBLOCK; + fcntl (fd, F_SETFL, flags); +#endif + /* Directories can be opened and read from, but only readdir() knows * how to parse the data. The directory plugin will do it. */ if (S_ISDIR (st.st_mode)) @@ -206,40 +219,40 @@ int FileOpen( vlc_object_t *p_this ) if (unlikely(p_sys == NULL)) goto error; access_InitFields (p_access); - p_access->pf_read = FileRead; p_access->pf_block = NULL; p_access->pf_control = FileControl; - p_access->pf_seek = FileSeek; p_access->p_sys = p_sys; - p_sys->i_nb_reads = 0; p_sys->fd = fd; - p_sys->b_pace_control = true; - if (S_ISREG (st.st_mode)) - p_access->info.i_size = st.st_size; - else if (!S_ISBLK (st.st_mode)) + if (S_ISREG (st.st_mode) || S_ISBLK (st.st_mode)) { - p_access->pf_seek = NoSeek; - p_sys->b_pace_control = strcasecmp (p_access->psz_access, "stream"); - } + p_access->pf_read = FileRead; + p_access->pf_seek = FileSeek; + p_sys->b_pace_control = true; + p_sys->size = st.st_size; - if (p_access->pf_seek != NoSeek) - { /* Demuxers will need the beginning of the file for probing. */ posix_fadvise (fd, 0, 4096, POSIX_FADV_WILLNEED); /* In most cases, we only read the file once. */ posix_fadvise (fd, 0, 0, POSIX_FADV_NOREUSE); -#if defined(HAVE_FCNTL) - /* We'd rather use any available memory for reading ahead - * than for caching what we've already seen/heard */ -# if defined(F_RDAHEAD) - fcntl (fd, F_RDAHEAD, 1); -# endif -# if defined(F_NOCACHE) - fcntl (fd, F_NOCACHE, 1); -# endif +#ifdef F_NOCACHE + fcntl (fd, F_NOCACHE, 0); +#endif +#ifdef F_RDAHEAD + if (IsRemote(fd, p_access->psz_filepath)) + fcntl (fd, F_RDAHEAD, 0); + else + fcntl (fd, F_RDAHEAD, 1); #endif } + else + { + p_access->pf_read = StreamRead; + p_access->pf_seek = NoSeek; + p_sys->b_pace_control = strcasecmp (p_access->psz_access, "stream"); + p_sys->size = 0; + } + return VLC_SUCCESS; error: @@ -269,74 +282,89 @@ void FileClose (vlc_object_t * p_this) #include -/***************************************************************************** - * Read: standard read on a file descriptor. - *****************************************************************************/ -ssize_t FileRead( access_t *p_access, uint8_t *p_buffer, size_t i_len ) +/** + * Reads from a regular file. + */ +static ssize_t FileRead (access_t *p_access, uint8_t *p_buffer, size_t i_len) { access_sys_t *p_sys = p_access->p_sys; int fd = p_sys->fd; - ssize_t i_ret; + ssize_t val = read (fd, p_buffer, i_len); -#if !defined (WIN32) && !defined (__OS2__) - if (p_access->pf_seek == NoSeek) - i_ret = net_Read (p_access, fd, NULL, p_buffer, i_len, false); - else -#endif - i_ret = read (fd, p_buffer, i_len); - - if( i_ret < 0 ) + if (val < 0) { switch (errno) { case EINTR: case EAGAIN: - break; - - default: - msg_Err (p_access, "failed to read (%m)"); - dialog_Fatal (p_access, _("File reading failed"), - _("VLC could not read the file (%m).")); - p_access->info.b_eof = true; - return 0; + return -1; } - } - else if( i_ret > 0 ) - p_access->info.i_pos += i_ret; - else - p_access->info.b_eof = true; - p_sys->i_nb_reads++; + msg_Err (p_access, "read error: %s", vlc_strerror_c(errno)); + dialog_Fatal (p_access, _("File reading failed"), + _("VLC could not read the file (%s)."), + vlc_strerror(errno)); + val = 0; + } - if ((p_access->info.i_size && !(p_sys->i_nb_reads % INPUT_FSTAT_NB_READS)) - || (p_access->info.i_pos > p_access->info.i_size)) + p_access->info.i_pos += val; + p_access->info.b_eof = !val; + if (p_access->info.i_pos >= p_sys->size) { struct stat st; - if ((fstat (fd, &st) == 0) - && (p_access->info.i_size != (uint64_t)st.st_size)) - { - p_access->info.i_size = st.st_size; - p_access->info.i_update |= INPUT_UPDATE_SIZE; - } + if (fstat (fd, &st) == 0) + p_sys->size = st.st_size; } - return i_ret; + return val; } /***************************************************************************** * Seek: seek to a specific location in a file *****************************************************************************/ -int FileSeek (access_t *p_access, uint64_t i_pos) +static int FileSeek (access_t *p_access, uint64_t i_pos) { p_access->info.i_pos = i_pos; p_access->info.b_eof = false; - lseek (p_access->p_sys->fd, i_pos, SEEK_SET); + if (lseek (p_access->p_sys->fd, i_pos, SEEK_SET) == (off_t)-1) + return VLC_EGENERIC; return VLC_SUCCESS; } -int NoSeek (access_t *p_access, uint64_t i_pos) +/** + * Reads from a non-seekable file. + */ +static ssize_t StreamRead (access_t *p_access, uint8_t *p_buffer, size_t i_len) +{ + access_sys_t *p_sys = p_access->p_sys; + int fd = p_sys->fd; + +#if !defined (_WIN32) && !defined (__OS2__) + ssize_t val = net_Read (p_access, fd, NULL, p_buffer, i_len, false); +#else + ssize_t val = read (fd, p_buffer, i_len); +#endif + + if (val < 0) + { + switch (errno) + { + case EINTR: + case EAGAIN: + return -1; + } + msg_Err (p_access, "read error: %s", vlc_strerror_c(errno)); + val = 0; + } + + p_access->info.i_pos += val; + p_access->info.b_eof = !val; + return val; +} + +static int NoSeek (access_t *p_access, uint64_t i_pos) { /* assert(0); ?? */ (void) p_access; (void) i_pos; @@ -346,7 +374,7 @@ int NoSeek (access_t *p_access, uint64_t i_pos) /***************************************************************************** * Control: *****************************************************************************/ -int FileControl( access_t *p_access, int i_query, va_list args ) +static int FileControl( access_t *p_access, int i_query, va_list args ) { access_sys_t *p_sys = p_access->p_sys; bool *pb_bool; @@ -354,7 +382,6 @@ int FileControl( access_t *p_access, int i_query, va_list args ) switch( i_query ) { - /* */ case ACCESS_CAN_SEEK: case ACCESS_CAN_FASTSEEK: pb_bool = (bool*)va_arg( args, bool* ); @@ -367,7 +394,16 @@ int FileControl( access_t *p_access, int i_query, va_list args ) *pb_bool = p_sys->b_pace_control; break; - /* */ + case ACCESS_GET_SIZE: + { + struct stat st; + + if (fstat (p_sys->fd, &st) == 0) + p_sys->size = st.st_size; + *va_arg( args, uint64_t * ) = p_sys->size; + break; + } + case ACCESS_GET_PTS_DELAY: pi_64 = (int64_t*)va_arg( args, int64_t * ); if (IsRemote (p_sys->fd, p_access->psz_filepath)) @@ -377,22 +413,11 @@ int FileControl( access_t *p_access, int i_query, va_list args ) *pi_64 *= 1000; break; - /* */ case ACCESS_SET_PAUSE_STATE: /* Nothing to do */ break; - case ACCESS_GET_TITLE_INFO: - case ACCESS_SET_TITLE: - case ACCESS_SET_SEEKPOINT: - case ACCESS_SET_PRIVATE_ID_STATE: - case ACCESS_GET_META: - case ACCESS_GET_PRIVATE_ID_STATE: - case ACCESS_GET_CONTENT_TYPE: - return VLC_EGENERIC; - default: - msg_Warn( p_access, "unimplemented query %d in control", i_query ); return VLC_EGENERIC; }