Fix FreeBSD build.
[haiku.git] / src / tools / fs_shell / unistd.cpp
blobec9b4f49599ace93e36a01f1305d6de0e1f99a5c
1 /*
2 * Copyright 2007-2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
6 #include "compatibility.h"
8 #include "fssh_unistd.h"
10 #include <errno.h>
11 #include <stdarg.h>
12 #include <unistd.h>
14 #include <SupportDefs.h>
16 #include "fssh_drivers.h"
17 #include "fssh_errno.h"
18 #include "partition_support.h"
20 #if (defined(__BEOS__) || defined(__HAIKU__))
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 # elif defined(HAIKU_HOST_PLATFORM_LINUX)
35 # include <linux/hdreg.h>
36 # include <linux/fs.h>
37 # include <sys/ioctl.h>
38 # else
39 // the (POSIX) correct place of definition for ioctl()
40 # include <stropts.h>
41 # endif
42 #endif
45 #if (!defined(__BEOS__) && !defined(__HAIKU__))
46 // Defined in libroot_build.so.
47 # define _kern_dup _kernbuild_dup
48 # define _kern_close _kernbuild_close
49 extern "C" int _kern_dup(int fd);
50 extern "C" status_t _kern_close(int fd);
51 #endif
54 #ifdef HAIKU_HOST_PLATFORM_LINUX
56 static bool
57 test_size(int fd, off_t size)
59 char buffer[1];
61 if (size == 0)
62 return true;
64 if (lseek(fd, size - 1, SEEK_SET) < 0)
65 return false;
67 return (read(fd, &buffer, 1) == 1);
71 static off_t
72 get_partition_size(int fd, off_t maxSize)
74 // binary search
75 off_t lower = 0;
76 off_t upper = maxSize;
77 while (lower < upper) {
78 off_t mid = (lower + upper + 1) / 2;
79 if (test_size(fd, mid))
80 lower = mid;
81 else
82 upper = mid - 1;
85 return lower;
88 #endif // HAIKU_HOST_PLATFORM_LINUX
91 int
92 fssh_dup(int fd)
94 // Use the _kern_dup() defined in libroot on BeOS incompatible systems.
95 // Required for proper attribute emulation support.
96 int newFD;
97 #if (defined(__BEOS__) || defined(__HAIKU__))
98 newFD = dup(fd);
99 #else
100 newFD = _kern_dup(fd);
101 if (newFD < 0) {
102 fssh_set_errno(newFD);
103 newFD = -1;
105 #endif
107 FSShell::restricted_file_duped(fd, newFD);
109 return newFD;
114 fssh_close(int fd)
116 FSShell::restricted_file_closed(fd);
118 // Use the _kern_close() defined in libroot on BeOS incompatible systems.
119 // Required for proper attribute emulation support.
120 #if (defined(__BEOS__) || defined(__HAIKU__))
121 return close(fd);
122 #else
123 return _kern_close(fd);
124 #endif
129 fssh_unlink(const char *name)
131 return unlink(name);
136 fssh_ioctl(int fd, unsigned long op, ...)
138 status_t error = B_BAD_VALUE;
139 va_list list;
141 // count arguments
143 va_start(list, op);
145 switch (op) {
146 case FSSH_B_GET_GEOMETRY:
148 fssh_device_geometry *geometry
149 = va_arg(list, fssh_device_geometry*);
151 #if (defined(__BEOS__) || defined(__HAIKU__))
152 device_geometry systemGeometry;
153 if (ioctl(fd, B_GET_GEOMETRY, &systemGeometry) == 0) {
154 geometry->bytes_per_sector
155 = systemGeometry.bytes_per_sector;
156 geometry->sectors_per_track
157 = systemGeometry.sectors_per_track;
158 geometry->cylinder_count = systemGeometry.cylinder_count;
159 geometry->head_count = systemGeometry.head_count;
160 geometry->device_type = systemGeometry.device_type;
161 geometry->removable = systemGeometry.removable;
162 geometry->read_only = systemGeometry.read_only;
163 geometry->write_once = systemGeometry.write_once;
164 error = B_OK;
165 } else
166 error = errno;
168 #elif defined(HAIKU_HOST_PLATFORM_LINUX)
169 // If BLKGETSIZE64 don't work for us, we will fall back to
170 // HDIO_GETGEO (which is kind of obsolete, BTW), and
171 // get the partition size via binary search.
172 struct hd_geometry hdGeometry;
173 int blockSize = 512;
174 off_t size;
175 if (ioctl(fd, BLKGETSIZE64, &size) == 0 && size > 0) {
176 off_t blocks = size / blockSize;
177 uint32_t heads = (blocks + ULONG_MAX - 1)
178 / ULONG_MAX;
179 if (heads == 0)
180 heads = 1;
182 geometry->head_count = heads;
183 geometry->cylinder_count = blocks / heads;
184 geometry->sectors_per_track = 1;
185 error = B_OK;
186 } else if (ioctl(fd, HDIO_GETGEO, &hdGeometry) == 0) {
187 if (hdGeometry.heads == 0) {
188 error = B_ERROR;
189 } else {
190 off_t bytesPerCylinder = (off_t)hdGeometry.heads
191 * hdGeometry.sectors * 512;
192 off_t deviceSize = bytesPerCylinder * hdGeometry.cylinders;
193 off_t partitionSize = get_partition_size(fd, deviceSize);
195 geometry->head_count = hdGeometry.heads;
196 geometry->cylinder_count = partitionSize / bytesPerCylinder;
197 geometry->sectors_per_track = hdGeometry.sectors;
198 error = B_OK;
200 } else
201 error = errno;
203 if (error == B_OK) {
204 // TODO: Get the real values...
205 geometry->bytes_per_sector = blockSize;
206 geometry->device_type = FSSH_B_DISK;
207 geometry->removable = false;
208 geometry->read_only = false;
209 geometry->write_once = false;
212 #elif HAIKU_HOST_PLATFORM_FREEBSD
214 // FreeBSD has not block devices
216 struct stat status;
218 if (fstat(fd, &status) == 0) {
219 // Do nothing for a regular file
220 if (S_ISREG(status.st_mode))
221 break;
223 struct disklabel disklabel;
224 off_t mediaSize;
226 memset(&disklabel,0,sizeof disklabel);
228 // Ignore errors, this way we can use memory devices (md%d)
229 ioctl(fd, DIOCGSECTORSIZE, &disklabel.d_secsize);
230 ioctl(fd, DIOCGFWSECTORS, &disklabel.d_nsectors);
231 ioctl(fd, DIOCGFWHEADS, &disklabel.d_ntracks);
232 ioctl(fd, DIOCGMEDIASIZE, &mediaSize);
234 if (disklabel.d_nsectors == 0) {
235 // Seems to be a md device, then ioctls returns lots of
236 // zeroes and hardcode some defaults
237 disklabel.d_nsectors = 64;
238 disklabel.d_ntracks = 16;
241 disklabel.d_secperunit = mediaSize / disklabel.d_secsize;
242 disklabel.d_ncylinders = mediaSize / disklabel.d_secsize
243 / disklabel.d_nsectors / disklabel.d_ntracks;
245 geometry->head_count = disklabel.d_ntracks;
246 geometry->cylinder_count = disklabel.d_ncylinders;
247 geometry->sectors_per_track = disklabel.d_nsectors;
249 geometry->bytes_per_sector = disklabel.d_secsize;
250 // FreeBSD supports device_type flag as disklabel.d_type,
251 // for now we harcod it to B_DISK.
252 geometry->device_type = FSSH_B_DISK;
253 geometry->removable = disklabel.d_flags & D_REMOVABLE > 0;
254 // read_only?
255 geometry->read_only = false;
256 // FreeBSD does not support write_once flag.
257 geometry->write_once = false;
258 error = B_OK;
259 } else
260 error = errno;
262 #elif HAIKU_HOST_PLATFORM_DARWIN
264 // Darwin does not seems to provide a way to access disk
265 // geometry directly
267 struct stat status;
269 if (fstat(fd, &status) == 0) {
270 // Do nothing for a regular file
271 if (S_ISREG(status.st_mode))
272 break;
274 off_t mediaSize;
276 if (ioctl(fd, DKIOCGETBLOCKCOUNT, &mediaSize) != 0) {
277 error = errno;
278 break;
281 geometry->head_count = 4;
282 geometry->sectors_per_track = 63;
283 geometry->cylinder_count = mediaSize / geometry->head_count
284 / geometry->sectors_per_track;
286 while (geometry->cylinder_count > 1024
287 && geometry->head_count < 256) {
288 geometry->head_count *= 2;
289 geometry->cylinder_count /= 2;
292 if (geometry->head_count == 256) {
293 geometry->head_count = 255;
294 geometry->cylinder_count = mediaSize
295 / geometry->head_count
296 / geometry->sectors_per_track;
299 if (ioctl(fd, DKIOCGETBLOCKSIZE,
300 &geometry->bytes_per_sector) != 0) {
301 error = errno;
302 break;
305 uint32_t isWritable;
306 if (ioctl(fd, DKIOCISWRITABLE, &isWritable) != 0) {
307 error = errno;
308 break;
311 geometry->read_only = !isWritable;
313 // TODO: Get the real values...
314 geometry->device_type = FSSH_B_DISK;
315 geometry->removable = false;
316 geometry->write_once = false;
318 error = B_OK;
319 } else
320 error = errno;
322 #else
323 // Not implemented for this platform, i.e. we won't be able to
324 // deal with disk devices.
325 #endif
327 break;
330 case FSSH_B_FLUSH_DRIVE_CACHE:
332 #if (defined(__BEOS__) || defined(__HAIKU__))
333 if (ioctl(fd, B_FLUSH_DRIVE_CACHE) == 0)
334 error = B_OK;
335 else
336 error = errno;
337 #else
338 error = B_OK;
339 #endif
341 break;
344 case 10000: // IOCTL_FILE_UNCACHED_IO
346 #if (defined(__BEOS__) || defined(__HAIKU__))
347 if (ioctl(fd, 10000) == 0)
348 error = B_OK;
349 else
350 error = errno;
351 #else
352 error = B_OK;
353 #endif
355 break;
359 va_end(list);
361 if (error != B_OK) {
362 fssh_set_errno(error);
363 return -1;
365 return 0;
369 fssh_ssize_t
370 fssh_read(int fd, void *buffer, fssh_size_t count)
372 #if !defined(HAIKU_HOST_PLATFORM_FREEBSD)
373 fssh_off_t pos = -1;
374 if (FSShell::restricted_file_restrict_io(fd, pos, count) < 0)
375 return -1;
376 return read(fd, buffer, count);
377 #else
378 fssh_ssize_t bytesRead = read_pos(fd, fssh_lseek(fd, 0, FSSH_SEEK_CUR),
379 buffer, count);
380 if (bytesRead > 0)
381 fssh_lseek(fd, bytesRead, FSSH_SEEK_CUR);
382 return bytesRead;
383 #endif
387 fssh_ssize_t
388 fssh_read_pos(int fd, fssh_off_t pos, void *buffer, fssh_size_t count)
390 if (FSShell::restricted_file_restrict_io(fd, pos, count) < 0)
391 return -1;
392 return read_pos(fd, pos, buffer, count);
396 fssh_ssize_t
397 fssh_write(int fd, const void *buffer, fssh_size_t count)
399 #if !defined(HAIKU_HOST_PLATFORM_FREEBSD)
400 fssh_off_t pos = -1;
401 if (FSShell::restricted_file_restrict_io(fd, pos, count) < 0)
402 return -1;
403 return write(fd, buffer, count);
404 #else
405 fssh_ssize_t written = write_pos(fd, fssh_lseek(fd, 0, FSSH_SEEK_CUR),
406 buffer, count);
407 if (written > 0)
408 fssh_lseek(fd, written, FSSH_SEEK_CUR);
409 return written;
410 #endif
414 fssh_ssize_t
415 fssh_write_pos(int fd, fssh_off_t pos, const void *buffer, fssh_size_t count)
417 if (FSShell::restricted_file_restrict_io(fd, pos, count) < 0)
418 return -1;
419 return write_pos(fd, pos, buffer, count);
423 // fssh_lseek() -- implemented in partition_support.cpp
426 fssh_gid_t
427 fssh_getegid(void)
429 return 0;
433 fssh_uid_t
434 fssh_geteuid(void)
436 return 0;
440 fssh_gid_t
441 fssh_getgid(void)
443 return 0;
447 #if 0
449 fssh_getgroups(int groupSize, fssh_gid_t groupList[])
452 #endif // 0
455 fssh_uid_t
456 fssh_getuid(void)
458 return 0;