1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 //============================================================
4 //
5 // minifile.c - Minimal core file access functions
6 //
7 //============================================================
8
9 #include "osdcore.h"
10
11 #include <cassert>
12 #include <cstdint>
13 #include <cstdio>
14 #include <cstdlib>
15 #include <string>
16
17 #include <cstdio> // for fileno
18 #include <unistd.h> // for ftruncate
19
20
21 namespace {
22 class std_osd_file : public osd_file
23 {
24 public:
25
std_osd_file(FILE * f)26 std_osd_file(FILE *f) : m_file(f) { assert(m_file); }
27
28 //============================================================
29 // osd_close
30 //============================================================
31
~std_osd_file()32 virtual ~std_osd_file() override
33 {
34 // close the file handle
35 if (m_file) std::fclose(m_file);
36 }
37
38 //============================================================
39 // osd_read
40 //============================================================
41
read(void * buffer,std::uint64_t offset,std::uint32_t length,std::uint32_t & actual)42 virtual error read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override
43 {
44 // seek to the new location; note that most fseek implementations are limited to 32 bits
45 if (std::fseek(m_file, offset, SEEK_SET) < 0)
46 return error::FAILURE;
47
48 // perform the read
49 std::size_t const count = std::fread(buffer, 1, length, m_file);
50 actual = count;
51
52 return error::NONE;
53 }
54
55 //============================================================
56 // osd_write
57 //============================================================
58
write(const void * buffer,std::uint64_t offset,std::uint32_t length,std::uint32_t & actual)59 virtual error write(const void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override
60 {
61 // seek to the new location; note that most fseek implementations are limited to 32 bits
62 if (std::fseek(m_file, offset, SEEK_SET) < 0)
63 return error::FAILURE;
64
65 // perform the write
66 std::size_t const count = std::fwrite(buffer, 1, length, m_file);
67 actual = count;
68
69 return error::NONE;
70 }
71
72 //============================================================
73 // osd_truncate
74 //============================================================
75
truncate(std::uint64_t offset)76 error truncate(std::uint64_t offset) override
77 {
78 return (ftruncate(fileno(m_file), offset) < 0) ? error::FAILURE : error::NONE;
79 }
80
81 //============================================================
82 // osd_fflush
83 //============================================================
84
flush()85 virtual error flush() override
86 {
87 return (std::fflush(m_file) == EOF) ? error::FAILURE : error::NONE;
88 }
89
90 private:
91 FILE *m_file;
92 };
93
94 } // anonymous namespace
95
96
97 //============================================================
98 // osd_open
99 //============================================================
100
open(std::string const & path,std::uint32_t openflags,ptr & file,std::uint64_t & filesize)101 osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, ptr &file, std::uint64_t &filesize)
102 {
103 // based on the flags, choose a mode
104 const char *mode;
105 if (openflags & OPEN_FLAG_WRITE)
106 {
107 if (openflags & OPEN_FLAG_READ)
108 mode = (openflags & OPEN_FLAG_CREATE) ? "w+b" : "r+b";
109 else
110 mode = "wb";
111 }
112 else if (openflags & OPEN_FLAG_READ)
113 mode = "rb";
114 else
115 return error::INVALID_ACCESS;
116
117 // open the file
118 FILE *const fileptr = std::fopen(path.c_str(), mode);
119 if (!fileptr)
120 return error::NOT_FOUND;
121
122 // get the size -- note that most fseek/ftell implementations are limited to 32 bits
123 long length;
124 if ((std::fseek(fileptr, 0, SEEK_END) < 0) ||
125 ((length = std::ftell(fileptr)) < 0) ||
126 (std::fseek(fileptr, 0, SEEK_SET) < 0))
127 {
128 std::fclose(fileptr);
129 return error::FAILURE;
130 }
131
132 try
133 {
134 file = std::make_unique<std_osd_file>(fileptr);
135 filesize = std::int64_t(length);
136 return error::NONE;
137 }
138 catch (...)
139 {
140 std::fclose(fileptr);
141 return error::OUT_OF_MEMORY;
142 }
143 }
144
145
146 //============================================================
147 // osd_openpty
148 //============================================================
149
openpty(ptr & file,std::string & name)150 osd_file::error osd_file::openpty(ptr &file, std::string &name)
151 {
152 return error::FAILURE;
153 }
154
155
156 //============================================================
157 // osd_rmfile
158 //============================================================
159
remove(std::string const & filename)160 osd_file::error osd_file::remove(std::string const &filename)
161 {
162 return (std::remove(filename.c_str()) < 0) ? error::FAILURE : error::NONE;
163 }
164
165
166 //============================================================
167 // osd_get_physical_drive_geometry
168 //============================================================
169
osd_get_physical_drive_geometry(const char * filename,uint32_t * cylinders,uint32_t * heads,uint32_t * sectors,uint32_t * bps)170 bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors, uint32_t *bps)
171 {
172 // there is no standard way of doing this, so we always return false, indicating
173 // that a given path is not a physical drive
174 return false;
175 }
176
177
178 //============================================================
179 // osd_uchar_from_osdchar
180 //============================================================
181
osd_uchar_from_osdchar(char32_t * uchar,const char * osdchar,size_t count)182 int osd_uchar_from_osdchar(char32_t *uchar, const char *osdchar, size_t count)
183 {
184 // we assume a standard 1:1 mapping of characters to the first 256 unicode characters
185 *uchar = (uint8_t)*osdchar;
186 return 1;
187 }
188
189
190 //============================================================
191 // osd_stat
192 //============================================================
193
osd_stat(const std::string & path)194 osd_directory_entry *osd_stat(const std::string &path)
195 {
196 osd_directory_entry *result = nullptr;
197
198 // create an osd_directory_entry; be sure to make sure that the caller can
199 // free all resources by just freeing the resulting osd_directory_entry
200 result = (osd_directory_entry *)malloc(sizeof(*result) + path.length() + 1);
201 strcpy((char *)(result + 1), path.c_str());
202 result->name = (char *)(result + 1);
203 result->type = ENTTYPE_NONE;
204 result->size = 0;
205
206 FILE *f = std::fopen(path.c_str(), "rb");
207 if (f != nullptr)
208 {
209 std::fseek(f, 0, SEEK_END);
210 result->type = ENTTYPE_FILE;
211 result->size = std::ftell(f);
212 std::fclose(f);
213 }
214 return result;
215 }
216
217
218 //============================================================
219 // osd_get_full_path
220 //============================================================
221
osd_get_full_path(std::string & dst,std::string const & path)222 osd_file::error osd_get_full_path(std::string &dst, std::string const &path)
223 {
224 // derive the full path of the file in an allocated string
225 // for now just fake it since we don't presume any underlying file system
226 dst = path;
227
228 return osd_file::error::NONE;
229 }
230
231
232 //============================================================
233 // osd_is_absolute_path
234 //============================================================
235
osd_is_absolute_path(std::string const & path)236 bool osd_is_absolute_path(std::string const &path)
237 {
238 // assume no for everything
239 return false;
240 }
241
242
243 //============================================================
244 // osd_get_volume_name
245 //============================================================
246
osd_get_volume_name(int idx)247 const char *osd_get_volume_name(int idx)
248 {
249 // we don't expose volumes
250 return nullptr;
251 }
252