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