1 /*
2 * This file is part of libudfread
3 * Copyright (C) 2014-2017 VLC authors and VideoLAN
4 *
5 * Authors: Petri Hintukainen <phintuka@users.sourceforge.net>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see
19 * <http://www.gnu.org/licenses/>.
20 */
21
22 #if HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "default_blockinput.h"
27 #include "blockinput.h"
28
29 #include <errno.h>
30 #include <stdlib.h>
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34 #ifdef HAVE_FCNTL_H
35 #include <fcntl.h>
36 #endif
37
38 #ifdef _WIN32
39 #include <windows.h>
40 #ifndef HAVE_UNISTD_H
41 #include <stdio.h>
42 #endif
43 #include <io.h>
44 # undef lseek
45 # define lseek _lseeki64
46 # undef off_t
47 # define off_t int64_t
48 #endif
49
50 #ifdef __ANDROID__
51 # undef lseek
52 # define lseek lseek64
53 # undef off_t
54 # define off_t off64_t
55 #endif
56
57 #ifdef _WIN32
pread(int fd,void * buf,size_t count,off_t offset)58 static ssize_t pread(int fd, void *buf, size_t count, off_t offset)
59 {
60 OVERLAPPED ov;
61 DWORD got;
62 HANDLE handle;
63
64 handle = (HANDLE)(intptr_t)_get_osfhandle(fd);
65 if (handle == INVALID_HANDLE_VALUE) {
66 return -1;
67 }
68
69 memset(&ov, 0, sizeof(ov));
70 ov.Offset = (DWORD)offset;
71 ov.OffsetHigh = (offset >> 32);
72 if (!ReadFile(handle, buf, count, &got, &ov)) {
73 return -1;
74 }
75 return got;
76 }
77
78 #elif defined (NEED_PREAD_IMPL)
79
80 #include <pthread.h>
pread_impl(int fd,void * buf,size_t count,off_t offset)81 static ssize_t pread_impl(int fd, void *buf, size_t count, off_t offset)
82 {
83 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
84 ssize_t result;
85
86 pthread_mutex_lock(&lock);
87
88 if (lseek(fd, offset, SEEK_SET) != offset) {
89 result = -1;
90 } else {
91 result = read(fd, buf, count);
92 }
93
94 pthread_mutex_unlock(&lock);
95 return result;
96 }
97
98 #define pread(a,b,c,d) pread_impl(a,b,c,d)
99
100 #endif /* _WIN32 || NEED_PREAD_IMPL */
101
102
103 typedef struct default_block_input {
104 udfread_block_input input;
105 int fd;
106 } default_block_input;
107
108
_def_close(udfread_block_input * p_gen)109 static int _def_close(udfread_block_input *p_gen)
110 {
111 default_block_input *p = (default_block_input *)p_gen;
112 int result = -1;
113
114 if (p) {
115 if (p->fd >= 0) {
116 result = close(p->fd);
117 }
118 free(p);
119 }
120
121 return result;
122 }
123
_def_size(udfread_block_input * p_gen)124 static uint32_t _def_size(udfread_block_input *p_gen)
125 {
126 default_block_input *p = (default_block_input *)p_gen;
127 off_t pos;
128
129 pos = lseek(p->fd, 0, SEEK_END);
130 if (pos < 0) {
131 return 0;
132 }
133
134 return (uint32_t)(pos / UDF_BLOCK_SIZE);
135 }
136
_def_read(udfread_block_input * p_gen,uint32_t lba,void * buf,uint32_t nblocks,int flags)137 static int _def_read(udfread_block_input *p_gen, uint32_t lba, void *buf, uint32_t nblocks, int flags)
138 {
139 default_block_input *p = (default_block_input *)p_gen;
140 size_t bytes, got;
141 off_t pos;
142
143 (void)flags;
144
145 bytes = (size_t)nblocks * UDF_BLOCK_SIZE;
146 got = 0;
147 pos = (off_t)lba * UDF_BLOCK_SIZE;
148
149 while (got < bytes) {
150 ssize_t ret = pread(p->fd, ((char*)buf) + got, bytes - got, pos + (off_t)got);
151
152 if (ret <= 0) {
153 if (ret < 0 && errno == EINTR) {
154 continue;
155 }
156 if (got < UDF_BLOCK_SIZE) {
157 return ret;
158 }
159 break;
160 }
161 got += (size_t)ret;
162 }
163
164 return got / UDF_BLOCK_SIZE;
165 }
166
167 #ifdef _WIN32
_open_win32(const char * path,int flags)168 static int _open_win32(const char *path, int flags)
169 {
170 wchar_t *wpath;
171 int wlen, fd;
172
173 wlen = MultiByteToWideChar (CP_UTF8, 0, path, -1, NULL, 0);
174 if (wlen < 1) {
175 return -1;
176 }
177 wpath = (wchar_t*)malloc(sizeof(wchar_t) * wlen);
178 if (!wpath) {
179 return -1;
180 }
181 if (!MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, wlen)) {
182 free(wpath);
183 return -1;
184 }
185 fd = _wopen(wpath, flags);
186 free(wpath);
187 return fd;
188 }
189 #endif
190
block_input_new(const char * path)191 udfread_block_input *block_input_new(const char *path)
192 {
193 default_block_input *p = (default_block_input*)calloc(1, sizeof(default_block_input));
194 if (!p) {
195 return NULL;
196 }
197
198 #ifdef _WIN32
199 p->fd = _open_win32(path, O_RDONLY | O_BINARY);
200 #else
201 p->fd = open(path, O_RDONLY);
202 #endif
203 if(p->fd < 0) {
204 free(p);
205 return NULL;
206 }
207
208 p->input.close = _def_close;
209 p->input.read = _def_read;
210 p->input.size = _def_size;
211
212 return &p->input;
213 }
214