2 * Copyright 2007-2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
6 #include "compatibility.h"
8 #include "fssh_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__))
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>
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>
39 // the (POSIX) correct place of definition for ioctl()
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
);
54 #ifdef HAIKU_HOST_PLATFORM_LINUX
57 test_size(int fd
, off_t size
)
64 if (lseek(fd
, size
- 1, SEEK_SET
) < 0)
67 return (read(fd
, &buffer
, 1) == 1);
72 get_partition_size(int fd
, off_t maxSize
)
76 off_t upper
= maxSize
;
77 while (lower
< upper
) {
78 off_t mid
= (lower
+ upper
+ 1) / 2;
79 if (test_size(fd
, mid
))
88 #endif // HAIKU_HOST_PLATFORM_LINUX
94 // Use the _kern_dup() defined in libroot on BeOS incompatible systems.
95 // Required for proper attribute emulation support.
97 #if (defined(__BEOS__) || defined(__HAIKU__))
100 newFD
= _kern_dup(fd
);
102 fssh_set_errno(newFD
);
107 FSShell::restricted_file_duped(fd
, newFD
);
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__))
123 return _kern_close(fd
);
129 fssh_unlink(const char *name
)
136 fssh_ioctl(int fd
, unsigned long op
, ...)
138 status_t error
= B_BAD_VALUE
;
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
;
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
;
175 if (ioctl(fd
, BLKGETSIZE64
, &size
) == 0 && size
> 0) {
176 off_t blocks
= size
/ blockSize
;
177 uint32_t heads
= (blocks
+ ULONG_MAX
- 1)
182 geometry
->head_count
= heads
;
183 geometry
->cylinder_count
= blocks
/ heads
;
184 geometry
->sectors_per_track
= 1;
186 } else if (ioctl(fd
, HDIO_GETGEO
, &hdGeometry
) == 0) {
187 if (hdGeometry
.heads
== 0) {
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
;
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
218 if (fstat(fd
, &status
) == 0) {
219 // Do nothing for a regular file
220 if (S_ISREG(status
.st_mode
))
223 struct disklabel disklabel
;
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;
255 geometry
->read_only
= false;
256 // FreeBSD does not support write_once flag.
257 geometry
->write_once
= false;
262 #elif HAIKU_HOST_PLATFORM_DARWIN
264 // Darwin does not seems to provide a way to access disk
269 if (fstat(fd
, &status
) == 0) {
270 // Do nothing for a regular file
271 if (S_ISREG(status
.st_mode
))
276 if (ioctl(fd
, DKIOCGETBLOCKCOUNT
, &mediaSize
) != 0) {
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) {
306 if (ioctl(fd
, DKIOCISWRITABLE
, &isWritable
) != 0) {
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;
323 // Not implemented for this platform, i.e. we won't be able to
324 // deal with disk devices.
330 case FSSH_B_FLUSH_DRIVE_CACHE
:
332 #if (defined(__BEOS__) || defined(__HAIKU__))
333 if (ioctl(fd
, B_FLUSH_DRIVE_CACHE
) == 0)
344 case 10000: // IOCTL_FILE_UNCACHED_IO
346 #if (defined(__BEOS__) || defined(__HAIKU__))
347 if (ioctl(fd
, 10000) == 0)
362 fssh_set_errno(error
);
370 fssh_read(int fd
, void *buffer
, fssh_size_t count
)
372 #if !defined(HAIKU_HOST_PLATFORM_FREEBSD)
374 if (FSShell::restricted_file_restrict_io(fd
, pos
, count
) < 0)
376 return read(fd
, buffer
, count
);
378 fssh_ssize_t bytesRead
= read_pos(fd
, fssh_lseek(fd
, 0, FSSH_SEEK_CUR
),
381 fssh_lseek(fd
, bytesRead
, FSSH_SEEK_CUR
);
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)
392 return read_pos(fd
, pos
, buffer
, count
);
397 fssh_write(int fd
, const void *buffer
, fssh_size_t count
)
399 #if !defined(HAIKU_HOST_PLATFORM_FREEBSD)
401 if (FSShell::restricted_file_restrict_io(fd
, pos
, count
) < 0)
403 return write(fd
, buffer
, count
);
405 fssh_ssize_t written
= write_pos(fd
, fssh_lseek(fd
, 0, FSSH_SEEK_CUR
),
408 fssh_lseek(fd
, written
, FSSH_SEEK_CUR
);
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)
419 return write_pos(fd
, pos
, buffer
, count
);
423 // fssh_lseek() -- implemented in partition_support.cpp
449 fssh_getgroups(int groupSize
, fssh_gid_t groupList
[])