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