X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Ffile.c;h=eac81228ceb109c08fe783b27f9cb6aa511cf620;hb=189bc59e7b442c9d898f2d460f4f780d8a079461;hp=183a6c8a0c3dc0e09bdc030c0e36b2701b545660;hpb=529cbee57099f4a1dc305a7a23e8d704ca746be3;p=vlc diff --git a/modules/access/file.c b/modules/access/file.c index 183a6c8a0c..eac81228ce 100644 --- a/modules/access/file.c +++ b/modules/access/file.c @@ -106,14 +106,17 @@ vlc_module_end(); * Exported prototypes *****************************************************************************/ static int Seek( access_t *, int64_t ); -static int Read( access_t *, uint8_t *, int ); +static ssize_t Read( access_t *, uint8_t *, size_t ); static int Control( access_t *, int, va_list ); +#ifdef HAVE_MMAP static block_t *mmapBlock( access_t * ); +#endif static int open_file( access_t *, const char * ); struct access_sys_t { + uint64_t pagemask; unsigned int i_nb_reads; vlc_bool_t b_kfir; @@ -200,11 +203,25 @@ static int Open( vlc_object_t *p_this ) p_sys->b_seekable = VLC_FALSE; # ifdef HAVE_MMAP - if (p_sys->b_pace_control && S_ISREG (st.st_mode)) + p_sys->pagemask = sysconf (_SC_PAGE_SIZE) - 1; + + /* Autodetect mmap() support */ + if (p_sys->b_pace_control && S_ISREG (st.st_mode) && (st.st_size > 0)) { - p_access->pf_read = NULL; - p_access->pf_block = mmapBlock; + void *addr = mmap (NULL, 1, PROT_READ, MAP_PRIVATE, fd, 0); + if (addr != MAP_FAILED) + { + /* Does the file system support mmap? */ + munmap (addr, 1); + p_access->pf_read = NULL; + p_access->pf_block = mmapBlock; + msg_Dbg (p_this, "mmap enabled"); + } + else + msg_Dbg (p_this, "mmap disabled (%m)"); } + else + msg_Dbg (p_this, "mmap disabled (non regular file)"); # endif #else p_sys->b_seekable = !b_stdin; @@ -237,10 +254,10 @@ static void Close (vlc_object_t * p_this) /***************************************************************************** * Read: standard read on a file descriptor. *****************************************************************************/ -static int Read( access_t *p_access, uint8_t *p_buffer, int i_len ) +static ssize_t Read( access_t *p_access, uint8_t *p_buffer, size_t i_len ) { access_sys_t *p_sys = p_access->p_sys; - int i_ret; + ssize_t i_ret; int fd = p_sys->fd; #if !defined(WIN32) && !defined(UNDER_CE) @@ -326,39 +343,28 @@ static int Read( access_t *p_access, uint8_t *p_buffer, int i_len ) } #ifdef HAVE_MMAP -# define MMAP_SIZE (1 << 18) - -struct block_sys_t -{ - block_t self; - //vlc_object_t *owner; - void *base_addr; - size_t length; -}; - -static void mmapRelease (block_t *block) -{ - block_sys_t *p_sys = (block_sys_t *)block; - - munmap (p_sys->base_addr, p_sys->length); - //vlc_object_release (p_sys->owner); - free (p_sys); -} +# define MMAP_SIZE (1 << 20) static block_t *mmapBlock (access_t *p_access) { access_sys_t *p_sys = p_access->p_sys; const int flags = MAP_SHARED; - const size_t pagesize = sysconf (_SC_PAGE_SIZE); - off_t offset = p_access->info.i_pos & ~(pagesize - 1); - size_t align = p_access->info.i_pos & (pagesize - 1); - size_t length = (MMAP_SIZE > pagesize) ? MMAP_SIZE : pagesize; + off_t offset = p_access->info.i_pos & ~p_sys->pagemask; + size_t align = p_access->info.i_pos & p_sys->pagemask; + size_t length = (MMAP_SIZE > p_sys->pagemask) ? MMAP_SIZE : (p_sys->pagemask + 1); void *addr; +#ifndef NDEBUG + int64_t dbgpos = lseek (p_sys->fd, 0, SEEK_CUR); + if (dbgpos != p_access->info.i_pos) + msg_Err (p_access, "position: 0x%08llx instead of 0x%08llx", + p_access->info.i_pos, dbgpos); +#endif + if (p_access->info.i_pos >= p_access->info.i_size) { - /* End of file - check that file size hasn't change... */ + /* End of file - check if file size changed... */ struct stat st; if ((fstat (p_sys->fd, &st) == 0) @@ -378,7 +384,7 @@ static block_t *mmapBlock (access_t *p_access) } if (offset + length > p_access->info.i_size) - /* Don't mmap paste end of file */ + /* Don't mmap beyond end of file */ length = p_access->info.i_size - offset; assert (offset <= p_access->info.i_pos); /* and */ @@ -389,29 +395,39 @@ static block_t *mmapBlock (access_t *p_access) addr = mmap (NULL, length, PROT_READ, flags, p_sys->fd, offset); if (addr == MAP_FAILED) { - msg_Err (p_access, "memory mapping failed: %m"); + msg_Err (p_access, "memory mapping failed (%m)"); + intf_UserFatal (p_access, VLC_FALSE, _("File reading failed"), + _("VLC could not read the file.")); msleep( INPUT_ERROR_SLEEP ); return NULL; } p_access->info.i_pos = offset + length; - msg_Dbg (p_access, "mapped %lu bytes at %p from offset %lu", - (unsigned long)length, addr, (unsigned long)offset); - block_sys_t *block = malloc (sizeof (*block)); + block_t *block = block_mmap_Alloc (addr, length); if (block == NULL) - { - munmap (addr, length); return NULL; - } - block_Init (&block->self, ((uint8_t *)addr) + align, length - align); - block->self.pf_release = mmapRelease; - block->base_addr = addr; - block->length = length; - //vlc_object_yield (block->owner = VLC_OBJECT (p_access)); + block->p_buffer += align; + block->i_buffer -= align; + +#ifndef NDEBUG + msg_Dbg (p_access, "mapped 0x%lx bytes at %p from offset 0x%lx", + (unsigned long)length, addr, (unsigned long)offset); + + /* Compare normal I/O with memory mapping */ + char *buf = malloc (block->i_buffer); + ssize_t i_read = read (p_sys->fd, buf, block->i_buffer); - return &block->self; + if (i_read != (ssize_t)block->i_buffer) + msg_Err (p_access, "read %u instead of %u bytes", (unsigned)i_read, + (unsigned)block->i_buffer); + if (memcmp (buf, block->p_buffer, block->i_buffer)) + msg_Err (p_access, "inconsistent data buffer"); + free (buf); +#endif + + return block; } #endif @@ -420,24 +436,23 @@ static block_t *mmapBlock (access_t *p_access) *****************************************************************************/ static int Seek (access_t *p_access, int64_t i_pos) { - if (i_pos > p_access->info.i_size) + /* FIXME: i_size should really be unsigned */ + if ((uint64_t)i_pos > (uint64_t)p_access->info.i_size) { - msg_Err (p_access, "seeking too far"); + /* This should only happen with corrupted files. + * But it also seems to happen with buggy demuxes (ASF) */ + msg_Err (p_access, "seeking too far (0x"I64Fx" / 0x"I64Fx")", + i_pos, p_access->info.i_size); i_pos = p_access->info.i_size; } - else if (i_pos < 0) - { - msg_Err (p_access, "seeking too early"); - i_pos = 0; - } p_access->info.i_pos = i_pos; p_access->info.b_eof = VLC_FALSE; -#ifdef HAVE_MMAP +#if defined (HAVE_MMAP) && defined (NDEBUG) if (p_access->pf_block == NULL) - lseek (p_access->p_sys->fd, i_pos, SEEK_SET); #endif + lseek (p_access->p_sys->fd, i_pos, SEEK_SET); return VLC_SUCCESS; }