xref: /haiku/src/tools/fs_shell/unistd.cpp (revision 89755088d790ff4fe36f8aa77dacb2bd15507108)
1 /*
2  * Copyright 2007-2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "compatibility.h"
7 
8 #include "fssh_unistd.h"
9 
10 #include <errno.h>
11 #include <stdarg.h>
12 #include <unistd.h>
13 
14 #include <SupportDefs.h>
15 
16 #include "fssh_drivers.h"
17 #include "fssh_errno.h"
18 #include "partition_support.h"
19 
20 #ifdef __BEOS__
21 #	include <Drivers.h>
22 #else
23 #	if defined(HAIKU_HOST_PLATFORM_FREEBSD) \
24 		|| defined(HAIKU_HOST_PLATFORM_DARWIN)
25 #		include <sys/ioctl.h>
26 #		include <sys/stat.h>
27 #		include <sys/disk.h>
28 #		ifndef HAIKU_HOST_PLATFORM_DARWIN
29 #			include <sys/disklabel.h>
30 #		endif
31 #	else
32 		// the (POSIX) correct place of definition for ioctl()
33 #		include <stropts.h>
34 #	endif
35 
36 #	if defined(HAIKU_HOST_PLATFORM_LINUX)
37 #		include <linux/hdreg.h>
38 #		include <linux/fs.h>
39 #	endif
40 #endif
41 
42 
43 #ifndef __BEOS__
44 	// Defined in libroot_build.so.
45 	extern "C" int _kern_dup(int fd);
46 	extern "C" status_t _kern_close(int fd);
47 #endif
48 
49 
50 #ifdef HAIKU_HOST_PLATFORM_LINUX
51 
52 static bool
53 test_size(int fd, off_t size)
54 {
55 	char buffer[1];
56 
57 	if (size == 0)
58 		return true;
59 
60 	if (lseek(fd, size - 1, SEEK_SET) < 0)
61 		return false;
62 
63 	return (read(fd, &buffer, 1) == 1);
64 }
65 
66 
67 static off_t
68 get_partition_size(int fd, off_t maxSize)
69 {
70 	// binary search
71 	off_t lower = 0;
72 	off_t upper = maxSize;
73 	while (lower < upper) {
74 		off_t mid = (lower + upper + 1) / 2;
75 		if (test_size(fd, mid))
76 			lower = mid;
77 		else
78 			upper = mid - 1;
79 	}
80 
81 	return lower;
82 }
83 
84 #endif // HAIKU_HOST_PLATFORM_LINUX
85 
86 
87 int
88 fssh_dup(int fd)
89 {
90 	// Use the _kern_dup() defined in libroot on BeOS incompatible systems.
91 	// Required for proper attribute emulation support.
92 	int newFD;
93 	#if __BEOS__
94 		newFD = dup(fd);
95 	#else
96 		newFD = _kern_dup(fd);
97 		if (newFD < 0) {
98 			fssh_set_errno(newFD);
99 			newFD = -1;
100 		}
101 	#endif
102 
103 	FSShell::restricted_file_duped(fd, newFD);
104 
105 	return newFD;
106 }
107 
108 
109 int
110 fssh_close(int fd)
111 {
112 	FSShell::restricted_file_closed(fd);
113 
114 	// Use the _kern_close() defined in libroot on BeOS incompatible systems.
115 	// Required for proper attribute emulation support.
116 	#if __BEOS__
117 		return close(fd);
118 	#else
119 		return _kern_close(fd);
120 	#endif
121 }
122 
123 
124 int
125 fssh_unlink(const char *name)
126 {
127 	return unlink(name);
128 }
129 
130 
131 int
132 fssh_ioctl(int fd, unsigned long op, ...)
133 {
134 	status_t error = B_BAD_VALUE;
135 	va_list list;
136 
137 	// count arguments
138 
139 	va_start(list, op);
140 
141 	switch (op) {
142 		case FSSH_B_GET_GEOMETRY:
143 		{
144 			fssh_device_geometry *geometry
145 				= va_arg(list, fssh_device_geometry*);
146 
147 			#ifdef __BEOS__
148 				device_geometry systemGeometry;
149 				if (ioctl(fd, B_GET_GEOMETRY, &systemGeometry) == 0) {
150 					geometry->bytes_per_sector
151 						= systemGeometry.bytes_per_sector;
152 					geometry->sectors_per_track
153 						= systemGeometry.sectors_per_track;
154 					geometry->cylinder_count = systemGeometry.cylinder_count;
155 					geometry->head_count = systemGeometry.head_count;
156 					geometry->device_type = systemGeometry.device_type;
157 					geometry->removable = systemGeometry.removable;
158 					geometry->read_only = systemGeometry.read_only;
159 					geometry->write_once = systemGeometry.write_once;
160 					error = B_OK;
161 				} else
162 					error = errno;
163 
164 			#elif defined(HAIKU_HOST_PLATFORM_LINUX)
165 				struct hd_geometry hdGeometry;
166 				// BLKGETSIZE and BLKGETSIZE64 don't seem to work for
167 				// partitions. So we get the device geometry (there only seems
168 				// to be HDIO_GETGEO, which is kind of obsolete, BTW), and
169 				// get the partition size via binary search.
170 				if (ioctl(fd, HDIO_GETGEO, &hdGeometry) == 0) {
171 					int blockSize = 512;
172 					if (hdGeometry.heads == 0) {
173 						off_t size;
174 						if (ioctl(fd, BLKGETSIZE64, &size) == 0) {
175 							off_t blocks = size / blockSize;
176 							uint32_t heads = (blocks + ULONG_MAX - 1)
177 								/ ULONG_MAX;
178 							if (heads == 0)
179 								heads = 1;
180 
181 							geometry->head_count = heads;
182 							geometry->cylinder_count = blocks / heads;
183 							geometry->sectors_per_track = 1;
184 							error = B_OK;
185 						} else
186 							error = errno;
187 					} else {
188 						off_t bytesPerCylinder = (off_t)hdGeometry.heads
189 							* hdGeometry.sectors * 512;
190 						off_t deviceSize = bytesPerCylinder * hdGeometry.cylinders;
191 						off_t partitionSize = get_partition_size(fd, deviceSize);
192 
193 						geometry->head_count = hdGeometry.heads;
194 						geometry->cylinder_count = partitionSize / bytesPerCylinder;
195 						geometry->sectors_per_track = hdGeometry.sectors;
196 						error = B_OK;
197 					}
198 
199 					if (error == B_OK) {
200 						// TODO: Get the real values...
201 						geometry->bytes_per_sector = blockSize;
202 						geometry->device_type = FSSH_B_DISK;
203 						geometry->removable = false;
204 						geometry->read_only = false;
205 						geometry->write_once = false;
206 					}
207 				} else
208 					error = errno;
209 
210 			#elif HAIKU_HOST_PLATFORM_FREEBSD
211 			{
212 				// FreeBSD has not block devices
213 
214 				struct stat status;
215 
216 				if (fstat(fd, &status) == 0) {
217 					// Do nothing for a regular file
218 					if (S_ISREG(status.st_mode))
219 						break;
220 
221 					struct disklabel disklabel;
222 					off_t mediaSize;
223 
224 					memset(&disklabel,0,sizeof disklabel);
225 
226 					// Ignore errors, this way we can use memory devices (md%d)
227 					ioctl(fd, DIOCGSECTORSIZE, &disklabel.d_secsize);
228 					ioctl(fd, DIOCGFWSECTORS, &disklabel.d_nsectors);
229 					ioctl(fd, DIOCGFWHEADS, &disklabel.d_ntracks);
230 					ioctl(fd, DIOCGMEDIASIZE, &mediaSize);
231 
232 					if (disklabel.d_nsectors == 0) {
233 						// Seems to be a md device, then ioctls returns lots of
234 						// zeroes and hardcode some defaults
235 						disklabel.d_nsectors = 64;
236 						disklabel.d_ntracks = 16;
237 					}
238 
239 					disklabel.d_secperunit = mediaSize / disklabel.d_secsize;
240 					disklabel.d_ncylinders = mediaSize / disklabel.d_secsize
241 												/ disklabel.d_nsectors
242 												/ disklabel.d_ntracks;
243 
244 					geometry->head_count = disklabel.d_ntracks;
245 					geometry->cylinder_count = disklabel.d_ncylinders;
246 					geometry->sectors_per_track = disklabel.d_nsectors;
247 
248 					geometry->bytes_per_sector = disklabel.d_secsize;
249 					// FreeBSD supports device_type flag as disklabel.d_type,
250 					// for now we harcod it to B_DISK.
251 					geometry->device_type = FSSH_B_DISK;
252 					geometry->removable = disklabel.d_flags & D_REMOVABLE > 0;
253 					// read_only?
254 					geometry->read_only = false;
255 					// FreeBSD does not support write_once flag.
256 					geometry->write_once = false;
257 					error = B_OK;
258 				} else
259 					error = errno;
260 			}
261 			#else
262 				// Not implemented for this platform, i.e. we won't be able to
263 				// deal with disk devices.
264 			#endif
265 
266 			break;
267 		}
268 
269 		case FSSH_B_FLUSH_DRIVE_CACHE:
270 		{
271 			#ifdef __BEOS__
272 				if (ioctl(fd, B_FLUSH_DRIVE_CACHE) == 0)
273 					error = B_OK;
274 				else
275 					error = errno;
276 			#else
277 				error = B_OK;
278 			#endif
279 
280 			break;
281 		}
282 
283 		case 10000:	// IOCTL_FILE_UNCACHED_IO
284 		{
285 			#ifdef __BEOS__
286 				if (ioctl(fd, 10000) == 0)
287 					error = B_OK;
288 				else
289 					error = errno;
290 			#else
291 				error = B_OK;
292 			#endif
293 
294 			break;
295 		}
296 	}
297 
298 	va_end(list);
299 
300 	if (error != B_OK) {
301 		fssh_set_errno(error);
302 		return -1;
303 	}
304 	return 0;
305 }
306 
307 
308 fssh_ssize_t
309 fssh_read(int fd, void *buffer, fssh_size_t count)
310 {
311 	#if !defined(HAIKU_HOST_PLATFORM_FREEBSD)
312 		fssh_off_t pos = -1;
313 		if (FSShell::restricted_file_restrict_io(fd, pos, count) < 0)
314 			return -1;
315 		return read(fd, buffer, count);
316 	#else
317 		fssh_ssize_t bytesRead = read_pos(fd, fssh_lseek(fd, 0, FSSH_SEEK_CUR),
318 			buffer, count);
319 		if (bytesRead > 0)
320 			fssh_lseek(fd, bytesRead, FSSH_SEEK_CUR);
321 		return bytesRead;
322 	#endif
323 }
324 
325 
326 fssh_ssize_t
327 fssh_read_pos(int fd, fssh_off_t pos, void *buffer, fssh_size_t count)
328 {
329 	if (FSShell::restricted_file_restrict_io(fd, pos, count) < 0)
330 		return -1;
331 	return read_pos(fd, pos, buffer, count);
332 }
333 
334 
335 fssh_ssize_t
336 fssh_write(int fd, const void *buffer, fssh_size_t count)
337 {
338 	#if !defined(HAIKU_HOST_PLATFORM_FREEBSD)
339 		fssh_off_t pos = -1;
340 		if (FSShell::restricted_file_restrict_io(fd, pos, count) < 0)
341 			return -1;
342 		return write(fd, buffer, count);
343 	#else
344 		fssh_ssize_t written = write_pos(fd, fssh_lseek(fd, 0, FSSH_SEEK_CUR),
345 			buffer, count);
346 		if (written > 0)
347 			fssh_lseek(fd, written, FSSH_SEEK_CUR);
348 		return written;
349 	#endif
350 }
351 
352 
353 fssh_ssize_t
354 fssh_write_pos(int fd, fssh_off_t pos, const void *buffer, fssh_size_t count)
355 {
356 	if (FSShell::restricted_file_restrict_io(fd, pos, count) < 0)
357 		return -1;
358 	return write_pos(fd, pos, buffer, count);
359 }
360 
361 
362 // fssh_lseek() -- implemented in partition_support.cpp
363 
364 
365 fssh_gid_t
366 fssh_getegid(void)
367 {
368 	return 0;
369 }
370 
371 
372 fssh_uid_t
373 fssh_geteuid(void)
374 {
375 	return 0;
376 }
377 
378 
379 fssh_gid_t
380 fssh_getgid(void)
381 {
382 	return 0;
383 }
384 
385 
386 #if 0
387 int
388 fssh_getgroups(int groupSize, fssh_gid_t groupList[])
389 {
390 }
391 #endif	// 0
392 
393 
394 fssh_uid_t
395 fssh_getuid(void)
396 {
397 	return 0;
398 }
399