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