<commit_before>/*****************************************************************************
 * file.c
 *****************************************************************************
 * Copyright (C) 2001, 2002 VLC authors and VideoLAN
 * $Id$
 *
 * Authors: <NAME> <<EMAIL>>
 *          <NAME> <<EMAIL>>
 *
 * 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 Lesser General Public License for more details.
 *
 * 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.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <assert.h>
#include <signal.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_sout.h>
#include <vlc_block.h>
#include <vlc_fs.h>
#include <vlc_network.h>
#include <vlc_strings.h>
#include <vlc_dialog.h>

#ifndef O_LARGEFILE
#   define O_LARGEFILE 0
#endif

#define SOUT_CFG_PREFIX "sout-file-"

/*****************************************************************************
 * Read: standard read on a file descriptor.
 *****************************************************************************/
static ssize_t Read( sout_access_out_t *p_access, block_t *p_buffer )
{
    ssize_t val;

    do
        val = read( (intptr_t)p_access->p_sys, p_buffer->p_buffer,
                    p_buffer->i_buffer );
    while (val == -1 && errno == EINTR);
    return val;
}

/*****************************************************************************
 * Write: standard write on a file descriptor.
 *****************************************************************************/
static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
{
    size_t i_write = 0;

    while( p_buffer )
    {
        ssize_t val = write ((intptr_t)p_access->p_sys,
                             p_buffer->p_buffer, p_buffer->i_buffer);
        if (val <= 0)
        {
            if (errno == EINTR)
                continue;
            block_ChainRelease (p_buffer);
            msg_Err( p_access, "cannot write: %s", vlc_strerror_c(errno) );
            return -1;
        }

        if ((size_t)val >= p_buffer->i_buffer)
        {
            block_t *p_next = p_buffer->p_next;
            block_Release (p_buffer);
            p_buffer = p_next;
        }
        else
        {
            p_buffer->p_buffer += val;
            p_buffer->i_buffer -= val;
        }
        i_write += val;
    }
    return i_write;
}

#ifdef S_ISSOCK
static ssize_t WritePipe(sout_access_out_t *access, block_t *block)
{
    int fd = (intptr_t)access->p_sys;
    ssize_t total = 0;
    sigset_t set, oldset;

    sigemptyset(&set);
    sigaddset(&set, SIGPIPE);
    pthread_sigmask(SIG_BLOCK, &set, &oldset);

    while (block != NULL)
    {
        if (block->i_buffer == 0)
        {
            block_t *next = block->p_next;
            block_Release(block);
            block = next;
            continue;
        }

        /* TODO: vectorized I/O with writev() */
        ssize_t val = write(fd, block->p_buffer, block->i_buffer);
        if (val < 0)
        {
            if (errno == EINTR)
                continue;

            if (errno == EPIPE)
            {
                siginfo_t info;
                struct timespec ts = { 0, 0 };
                while (sigtimedwait(&set, &info, &ts) > 0);
            }

            block_ChainRelease(block);
            msg_Err(access, "cannot write: %s", vlc_strerror_c(errno));
            total = -1;
            break;
        }

        total += val;

        assert((size_t)val <= block->i_buffer);
        block->p_buffer += val;
        block->i_buffer -= val;
    }

    if (!sigismember(&oldset, SIGPIPE))
        pthread_sigmask(SIG_SETMASK, &oldset, NULL);

    return total;
}

static ssize_t Send(sout_access_out_t *access, block_t *block)
{
    int fd = (intptr_t)access->p_sys;
    size_t total = 0;

    while (block != NULL)
    {
        if (block->i_buffer == 0)
        {
            block_t *next = block->p_next;
            block_Release(block);
            block = next;
            continue;
        }

        /* TODO: vectorized I/O with sendmsg() */
        ssize_t val = send(fd, block->p_buffer, block->i_buffer, MSG_NOSIGNAL);
        if (val <= 0)
        {   /* FIXME: errno is meaningless if val is zero */
            if (errno == EINTR)
                continue;
            block_ChainRelease(block);
            msg_Err(access, "cannot write: %s", vlc_strerror_c(errno));
            return -1;
        }

        total += val;

        assert((size_t)val <= block->i_buffer);
        block->p_buffer += val;
        block->i_buffer -= val;
    }
    return total;
}
#else
# define WritePipe Write
#endif

/*****************************************************************************
 * Seek: seek to a specific location in a file
 *****************************************************************************/
static int Seek( sout_access_out_t *p_access, off_t i_pos )
{
    return lseek( (intptr_t)p_access->p_sys, i_pos, SEEK_SET );
}

static int NoSeek(sout_access_out_t *access, off_t pos)
{
    (void) access; (void) pos;
    return -1;
}

static int Control( sout_access_out_t *p_access, int i_query, va_list args )
{
    switch( i_query )
    {
        case ACCESS_OUT_CONTROLS_PACE:
        {
            bool *pb = va_arg( args, bool * );
            *pb = strcmp( p_access->psz_access, "stream" );
            break;
        }

        case ACCESS_OUT_CAN_SEEK:
        {
            bool *pb = va_arg( args, bool * );<commit_msg>file output: unfix SIGPIPE blocking if POSIX RTS is unsupported<commit_after>/*****************************************************************************
 * file.c
 *****************************************************************************
 * Copyright (C) 2001, 2002 VLC authors and VideoLAN
 * $Id$
 *
 * Authors: <NAME> <<EMAIL>>
 *          <NAME> <<EMAIL>>
 *
 * 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 Lesser General Public License for more details.
 *
 * 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.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <assert.h>
#include <signal.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_sout.h>
#include <vlc_block.h>
#include <vlc_fs.h>
#include <vlc_network.h>
#include <vlc_strings.h>
#include <vlc_dialog.h>

#ifndef O_LARGEFILE
#   define O_LARGEFILE 0
#endif
#ifndef _POSIX_REALTIME_SIGNALS
# define _POSIX_REALTIME_SIGNALS (-1)
#endif

#define SOUT_CFG_PREFIX "sout-file-"

/*****************************************************************************
 * Read: standard read on a file descriptor.
 *****************************************************************************/
static ssize_t Read( sout_access_out_t *p_access, block_t *p_buffer )
{
    ssize_t val;

    do
        val = read( (intptr_t)p_access->p_sys, p_buffer->p_buffer,
                    p_buffer->i_buffer );
    while (val == -1 && errno == EINTR);
    return val;
}

/*****************************************************************************
 * Write: standard write on a file descriptor.
 *****************************************************************************/
static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
{
    size_t i_write = 0;

    while( p_buffer )
    {
        ssize_t val = write ((intptr_t)p_access->p_sys,
                             p_buffer->p_buffer, p_buffer->i_buffer);
        if (val <= 0)
        {
            if (errno == EINTR)
                continue;
            block_ChainRelease (p_buffer);
            msg_Err( p_access, "cannot write: %s", vlc_strerror_c(errno) );
            return -1;
        }

        if ((size_t)val >= p_buffer->i_buffer)
        {
            block_t *p_next = p_buffer->p_next;
            block_Release (p_buffer);
            p_buffer = p_next;
        }
        else
        {
            p_buffer->p_buffer += val;
            p_buffer->i_buffer -= val;
        }
        i_write += val;
    }
    return i_write;
}

#if (_POSIX_REALTIME_SIGNALS > 0)
static ssize_t WritePipe(sout_access_out_t *access, block_t *block)
{
    int fd = (intptr_t)access->p_sys;
    ssize_t total = 0;
    sigset_t set, oldset;

    sigemptyset(&set);
    sigaddset(&set, SIGPIPE);
    pthread_sigmask(SIG_BLOCK, &set, &oldset);

    while (block != NULL)
    {
        if (block->i_buffer == 0)
        {
            block_t *next = block->p_next;
            block_Release(block);
            block = next;
            continue;
        }

        /* TODO: vectorized I/O with writev() */
        ssize_t val = write(fd, block->p_buffer, block->i_buffer);
        if (val < 0)
        {
            if (errno == EINTR)
                continue;

            if (errno == EPIPE)
            {
                siginfo_t info;
                struct timespec ts = { 0, 0 };
                while (sigtimedwait(&set, &info, &ts) > 0);
            }

            block_ChainRelease(block);
            msg_Err(access, "cannot write: %s", vlc_strerror_c(errno));
            total = -1;
            break;
        }

        total += val;

        assert((size_t)val <= block->i_buffer);
        block->p_buffer += val;
        block->i_buffer -= val;
    }

    if (!sigismember(&oldset, SIGPIPE))
        pthread_sigmask(SIG_SETMASK, &oldset, NULL);

    return total;
}
#else
# define WritePipe Write
#endif

#ifdef S_ISSOCK
static ssize_t Send(sout_access_out_t *access, block_t *block)
{
    int fd = (intptr_t)access->p_sys;
    size_t total = 0;

    while (block != NULL)
    {
        if (block->i_buffer == 0)
        {
            block_t *next = block->p_next;
            block_Release(block);
            block = next;
            continue;
        }

        /* TODO: vectorized I/O with sendmsg() */
        ssize_t val = send(fd, block->p_buffer, block->i_buffer, MSG_NOSIGNAL);
        if (val <= 0)
        {   /* FIXME: errno is meaningless if val is zero */
            if (errno == EINTR)
                continue;
            block_ChainRelease(block);
            msg_Err(access, "cannot write: %s", vlc_strerror_c(errno));
            return -1;
        }

        total += val;

        assert((size_t)val <= block->i_buffer);
        block->p_buffer += val;
        block->i_buffer -= val;
    }
    return total;
}
#endif

/*****************************************************************************
 * Seek: seek to a specific location in a file
 *****************************************************************************/
static int Seek( sout_access_out_t *p_access, off_t i_pos )
{
    return lseek( (intptr_t)p_access->p_sys, i_pos, SEEK_SET );
}

static int NoSeek(sout_access_out_t *access, off_t pos)
{
    (void) access; (void) pos;
    return -1;
}

static int Control( sout_access_out_t *p_access, int i_query, va_list args )
{
    switch( i_query )
    {
        case ACCESS_OUT_CONTROLS_PACE:
        {
            bool *pb = va_arg( args, bool * );
            *pb = strcmp( p_access->psz_access, "stream" );
            break;
        }

        case ACCESS_OUT_CAN_SEEK:
        {
            bool *pb = va_arg( args, bool * );
{'fraction_non_alphanumeric': 0.22894168466522677, 'fraction_numerical': 0.00601666152422092, 'mean_word_length': 2.5785260833563344, 'pattern_counts': {'":': 0, '<': 55, '<?xml version=': 0, '>': 106, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4598390', 'n_tokens_mistral': 4054, 'n_tokens_neox': 3821, 'n_words': 1019}