1 /* mz_strm_posix.c -- Stream for filesystem access for posix/linux
2    Version 2.8.1, December 1, 2018
3    part of the MiniZip project
4 
5    Copyright (C) 2010-2018 Nathan Moinvaziri
6      https://github.com/nmoinvaz/minizip
7    Modifications for Zip64 support
8      Copyright (C) 2009-2010 Mathias Svensson
9      http://result42.com
10    Copyright (C) 1998-2010 Gilles Vollant
11      https://www.winimage.com/zLibDll/minizip.html
12 
13    This program is distributed under the terms of the same license as zlib.
14    See the accompanying LICENSE file for the full text of the license.
15 */
16 
17 
18 #include "mz.h"
19 #include "mz_strm.h"
20 #include "mz_strm_os.h"
21 
22 #include <stdio.h> /* fopen, fread.. */
23 #include <errno.h>
24 
25 /***************************************************************************/
26 
27 #define fopen64 fopen
28 #ifndef MZ_FILE32_API
29 #  ifndef NO_FSEEKO
30 #    define ftello64 ftello
31 #    define fseeko64 fseeko
32 #  elif defined(_MSC_VER) && (_MSC_VER >= 1400)
33 #    define ftello64 _ftelli64
34 #    define fseeko64 _fseeki64
35 #  endif
36 #endif
37 #ifndef ftello64
38 #  define ftello64 ftell
39 #endif
40 #ifndef fseeko64
41 #  define fseeko64 fseek
42 #endif
43 
44 /***************************************************************************/
45 
46 static mz_stream_vtbl mz_stream_os_vtbl = {
47     mz_stream_os_open,
48     mz_stream_os_is_open,
49     mz_stream_os_read,
50     mz_stream_os_write,
51     mz_stream_os_tell,
52     mz_stream_os_seek,
53     mz_stream_os_close,
54     mz_stream_os_error,
55     mz_stream_os_create,
56     mz_stream_os_delete,
57     NULL,
58     NULL
59 };
60 
61 /***************************************************************************/
62 
63 typedef struct mz_stream_posix_s
64 {
65     mz_stream   stream;
66     int32_t     error;
67     FILE        *handle;
68 } mz_stream_posix;
69 
70 /***************************************************************************/
71 
mz_stream_os_open(void * stream,const char * path,int32_t mode)72 int32_t mz_stream_os_open(void *stream, const char *path, int32_t mode)
73 {
74     mz_stream_posix *posix = (mz_stream_posix *)stream;
75     const char *mode_fopen = NULL;
76 
77     if (path == NULL)
78         return MZ_PARAM_ERROR;
79 
80     if ((mode & MZ_OPEN_MODE_READWRITE) == MZ_OPEN_MODE_READ)
81         mode_fopen = "rb";
82     else if (mode & MZ_OPEN_MODE_APPEND)
83         mode_fopen = "r+b";
84     else if (mode & MZ_OPEN_MODE_CREATE)
85         mode_fopen = "wb";
86     else
87         return MZ_OPEN_ERROR;
88 
89     posix->handle = fopen64(path, mode_fopen);
90     if (posix->handle == NULL)
91     {
92         posix->error = errno;
93         return MZ_OPEN_ERROR;
94     }
95 
96     if (mode & MZ_OPEN_MODE_APPEND)
97         return mz_stream_os_seek(stream, 0, MZ_SEEK_END);
98 
99     return MZ_OK;
100 }
101 
mz_stream_os_is_open(void * stream)102 int32_t mz_stream_os_is_open(void *stream)
103 {
104     mz_stream_posix *posix = (mz_stream_posix*)stream;
105     if (posix->handle == NULL)
106         return MZ_OPEN_ERROR;
107     return MZ_OK;
108 }
109 
mz_stream_os_read(void * stream,void * buf,int32_t size)110 int32_t mz_stream_os_read(void *stream, void *buf, int32_t size)
111 {
112     mz_stream_posix *posix = (mz_stream_posix*)stream;
113     int32_t read = (int32_t)fread(buf, 1, (size_t)size, posix->handle);
114     if (read < size && ferror(posix->handle))
115     {
116         posix->error = errno;
117         return MZ_READ_ERROR;
118     }
119     return read;
120 }
121 
mz_stream_os_write(void * stream,const void * buf,int32_t size)122 int32_t mz_stream_os_write(void *stream, const void *buf, int32_t size)
123 {
124     mz_stream_posix *posix = (mz_stream_posix*)stream;
125     int32_t written = (int32_t)fwrite(buf, 1, (size_t)size, posix->handle);
126     if (written < size && ferror(posix->handle))
127     {
128         posix->error = errno;
129         return MZ_WRITE_ERROR;
130     }
131     return written;
132 }
133 
mz_stream_os_tell(void * stream)134 int64_t mz_stream_os_tell(void *stream)
135 {
136     mz_stream_posix *posix = (mz_stream_posix*)stream;
137     int64_t position = ftello64(posix->handle);
138     if (position == -1)
139     {
140         posix->error = errno;
141         return MZ_TELL_ERROR;
142     }
143     return position;
144 }
145 
mz_stream_os_seek(void * stream,int64_t offset,int32_t origin)146 int32_t mz_stream_os_seek(void *stream, int64_t offset, int32_t origin)
147 {
148     mz_stream_posix *posix = (mz_stream_posix*)stream;
149     int32_t fseek_origin = 0;
150 
151     switch (origin)
152     {
153         case MZ_SEEK_CUR:
154             fseek_origin = SEEK_CUR;
155             break;
156         case MZ_SEEK_END:
157             fseek_origin = SEEK_END;
158             break;
159         case MZ_SEEK_SET:
160             fseek_origin = SEEK_SET;
161             break;
162         default:
163             return MZ_SEEK_ERROR;
164     }
165 
166     if (fseeko64(posix->handle, offset, fseek_origin) != 0)
167     {
168         posix->error = errno;
169         return MZ_SEEK_ERROR;
170     }
171 
172     return MZ_OK;
173 }
174 
mz_stream_os_close(void * stream)175 int32_t mz_stream_os_close(void *stream)
176 {
177     mz_stream_posix *posix = (mz_stream_posix*)stream;
178     int32_t closed = 0;
179     if (posix->handle != NULL)
180     {
181         closed = fclose(posix->handle);
182         posix->handle = NULL;
183     }
184     if (closed != 0)
185     {
186         posix->error = errno;
187         return MZ_CLOSE_ERROR;
188     }
189     return MZ_OK;
190 }
191 
mz_stream_os_error(void * stream)192 int32_t mz_stream_os_error(void *stream)
193 {
194     mz_stream_posix *posix = (mz_stream_posix*)stream;
195     return posix->error;
196 }
197 
mz_stream_os_create(void ** stream)198 void *mz_stream_os_create(void **stream)
199 {
200     mz_stream_posix *posix = NULL;
201 
202     posix = (mz_stream_posix *)MZ_ALLOC(sizeof(mz_stream_posix));
203     if (posix != NULL)
204     {
205         memset(posix, 0, sizeof(mz_stream_posix));
206         posix->stream.vtbl = &mz_stream_os_vtbl;
207     }
208     if (stream != NULL)
209         *stream = posix;
210 
211     return posix;
212 }
213 
mz_stream_os_delete(void ** stream)214 void mz_stream_os_delete(void **stream)
215 {
216     mz_stream_posix *posix = NULL;
217     if (stream == NULL)
218         return;
219     posix = (mz_stream_posix *)*stream;
220     if (posix != NULL)
221         MZ_FREE(posix);
222     *stream = NULL;
223 }
224 
mz_stream_os_get_interface(void)225 void *mz_stream_os_get_interface(void)
226 {
227     return (void *)&mz_stream_os_vtbl;
228 }
229