default_blockinput.c 4.1 KB
Newer Older
Petri Hintukainen's avatar
Petri Hintukainen committed
1 2
/*
 * This file is part of libudfread
Petri Hintukainen's avatar
Petri Hintukainen committed
3
 * Copyright (C) 2014-2017 VLC authors and VideoLAN
Petri Hintukainen's avatar
Petri Hintukainen committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 *
 * Authors: Petri Hintukainen <phintuka@users.sourceforge.net>
 *
 * This library 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 library 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 library. If not, see
 * <http://www.gnu.org/licenses/>.
 */

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

#include "default_blockinput.h"
#include "blockinput.h"

29
#include <errno.h>
Petri Hintukainen's avatar
Petri Hintukainen committed
30 31 32 33 34 35 36 37 38 39
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif

#ifdef _WIN32
#include <windows.h>
40 41 42
#ifndef HAVE_UNISTD_H
#include <stdio.h>
#endif
Petri Hintukainen's avatar
Petri Hintukainen committed
43
#include <io.h>
44 45 46 47
# undef  lseek
# define lseek _lseeki64
# undef  off_t
# define off_t int64_t
Petri Hintukainen's avatar
Petri Hintukainen committed
48 49
#endif

Petri Hintukainen's avatar
Petri Hintukainen committed
50 51 52 53 54 55
#ifdef __ANDROID__
# undef  lseek
# define lseek lseek64
# undef  off_t
# define off_t off64_t
#endif
Petri Hintukainen's avatar
Petri Hintukainen committed
56 57 58 59 60 61 62 63 64 65 66 67 68

#ifdef _WIN32
static ssize_t pread(int fd, void *buf, size_t count, off_t offset)
{
    OVERLAPPED ov;
    DWORD      got;
    HANDLE     handle;

    handle = (HANDLE)(intptr_t)_get_osfhandle(fd);
    if (handle == INVALID_HANDLE_VALUE) {
        return -1;
    }

69
    memset(&ov, 0, sizeof(ov));
70
    ov.Offset     = (DWORD)offset;
Petri Hintukainen's avatar
Petri Hintukainen committed
71 72 73 74 75 76
    ov.OffsetHigh = (offset >> 32);
    if (!ReadFile(handle, buf, count, &got, &ov)) {
        return -1;
    }
    return got;
}
Petri Hintukainen's avatar
Petri Hintukainen committed
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

#elif defined (NEED_PREAD_IMPL)

#include <pthread.h>
static ssize_t pread_impl(int fd, void *buf, size_t count, off_t offset)
{
    static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    ssize_t result;

    pthread_mutex_lock(&lock);

    if (lseek(fd, offset, SEEK_SET) != offset) {
        result = -1;
    } else {
        result = read(fd, buf, count);
    }

    pthread_mutex_unlock(&lock);
    return result;
}

#define pread(a,b,c,d) pread_impl(a,b,c,d)

#endif /* _WIN32 || NEED_PREAD_IMPL */
Petri Hintukainen's avatar
Petri Hintukainen committed
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142


typedef struct default_block_input {
    udfread_block_input input;
    int                 fd;
} default_block_input;


static int _def_close(udfread_block_input *p_gen)
{
    default_block_input *p = (default_block_input *)p_gen;
    int result = -1;

    if (p) {
        if (p->fd >= 0) {
            result = close(p->fd);
        }
        free(p);
    }

    return result;
}

static uint32_t _def_size(udfread_block_input *p_gen)
{
    default_block_input *p = (default_block_input *)p_gen;
    off_t pos;

    pos = lseek(p->fd, 0, SEEK_END);
    if (pos < 0) {
        return 0;
    }

    return (uint32_t)(pos / UDF_BLOCK_SIZE);
}

static int _def_read(udfread_block_input *p_gen, uint32_t lba, void *buf, uint32_t nblocks, int flags)
{
    default_block_input *p = (default_block_input *)p_gen;
    size_t bytes, got;
    off_t  pos;

Petri Hintukainen's avatar
Petri Hintukainen committed
143 144
    (void)flags;

Petri Hintukainen's avatar
Petri Hintukainen committed
145 146 147 148 149
    bytes = (size_t)nblocks * UDF_BLOCK_SIZE;
    got   = 0;
    pos   = (off_t)lba * UDF_BLOCK_SIZE;

    while (got < bytes) {
Petri Hintukainen's avatar
Petri Hintukainen committed
150
        ssize_t ret = pread(p->fd, ((char*)buf) + got, bytes - got, pos + (off_t)got);
Petri Hintukainen's avatar
Petri Hintukainen committed
151 152

        if (ret <= 0) {
153 154 155
            if (ret < 0 && errno == EINTR) {
                continue;
            }
Petri Hintukainen's avatar
Petri Hintukainen committed
156 157 158 159 160
            if (got < UDF_BLOCK_SIZE) {
                return ret;
            }
            break;
        }
Petri Hintukainen's avatar
Petri Hintukainen committed
161
        got += (size_t)ret;
Petri Hintukainen's avatar
Petri Hintukainen committed
162 163 164 165 166 167 168
    }

    return got / UDF_BLOCK_SIZE;
}

udfread_block_input *block_input_new(const char *path)
{
169
    default_block_input *p = (default_block_input*)calloc(1, sizeof(default_block_input));
Petri Hintukainen's avatar
Petri Hintukainen committed
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
    if (!p) {
        return NULL;
    }

#ifdef _WIN32
    p->fd = open(path, O_RDONLY | O_BINARY);
#else
    p->fd = open(path, O_RDONLY);
#endif
    if(p->fd < 0) {
        free(p);
        return NULL;
    }

    p->input.close = _def_close;
    p->input.read  = _def_read;
    p->input.size  = _def_size;

    return &p->input;
}