1/*
2  This file contains some routines that are #ifdef'ed based on what
3  system you're on.  Currently it supports the BeOS and Unix. It
4  could be extended to support Windows NT but their posix support
5  is such a joke that it would probably be a real pain in the arse.
6
7  THIS CODE COPYRIGHT DOMINIC GIAMPAOLO.  NO WARRANTY IS EXPRESSED
8  OR IMPLIED.  YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
9  NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
10
11  FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO (dbg@be.com).
12
13  Dominic Giampaolo
14  dbg@be.com
15*/
16#include "compat.h"
17
18#include <stdarg.h>
19#include <stdio.h>
20#include <fcntl.h>
21#include <unistd.h>
22#include <sys/ioctl.h>
23#include <sys/stat.h>
24
25#include "stat_util.h"
26
27// Linux support
28#ifdef HAIKU_HOST_PLATFORM_LINUX
29#	include <linux/hdreg.h>
30#endif	// HAIKU_HOST_PLATFORM_LINUX
31
32
33// Let the FS think, we are the root user.
34uid_t
35geteuid()
36{
37	return 0;
38}
39
40
41gid_t
42getegid()
43{
44	return 0;
45}
46
47
48int
49device_is_read_only(const char *device)
50{
51#ifdef unix
52    return 0;   /* XXXdbg should do an ioctl or something */
53#else
54    int             fd;
55    device_geometry dg;
56
57    fd = open(device, O_RDONLY);
58    if (ioctl(fd, B_GET_GEOMETRY, &dg) < 0)
59        return 0;
60
61    close(fd);
62
63    return dg.read_only;
64#endif
65}
66
67int
68get_device_block_size(int fd)
69{
70#ifdef unix
71    return 512;   /* XXXdbg should do an ioctl or something */
72#else
73    struct stat     st;
74    device_geometry dg;
75
76    if (ioctl(fd, B_GET_GEOMETRY, &dg) < 0) {
77        if (fstat(fd, &st) < 0 || S_ISDIR(st.st_mode))
78            return 0;
79
80        return 512;   /* just assume it's a plain old file or something */
81    }
82
83    return dg.bytes_per_sector;
84#endif
85}
86
87fs_off_t
88get_num_device_blocks(int fd)
89{
90#ifdef unix
91    struct stat st;
92
93    fstat(fd, &st);    /* XXXdbg should be an ioctl or something */
94
95    return st.st_size / get_device_block_size(fd);
96#else
97    struct stat st;
98    device_geometry dg;
99
100    if (ioctl(fd, B_GET_GEOMETRY, &dg) >= 0) {
101        return (fs_off_t)dg.cylinder_count *
102               (fs_off_t)dg.sectors_per_track *
103               (fs_off_t)dg.head_count;
104    }
105
106    /* if the ioctl fails, try just stat'ing in case it's a regular file */
107    if (fstat(fd, &st) < 0)
108        return 0;
109
110    return st.st_size / get_device_block_size(fd);
111#endif
112}
113
114int
115device_is_removeable(int fd)
116{
117#ifdef unix
118    return 0;   /* XXXdbg should do an ioctl or something */
119#else
120    device_geometry dg;
121
122    if (ioctl(fd, B_GET_GEOMETRY, &dg) < 0) {
123        return 0;
124    }
125
126    return dg.removable;
127#endif
128}
129
130#if (defined(__BEOS__) || defined(__HAIKU__)) && !defined(USER)
131#include "scsi.h"
132#endif
133
134int
135lock_removeable_device(int fd, bool on_or_off)
136{
137#if defined(unix) || defined(USER)
138    return 0;   /* XXXdbg should do an ioctl or something */
139#else
140    return ioctl(fd, B_SCSI_PREVENT_ALLOW, &on_or_off);
141#endif
142}
143
144
145
146
147#if (!defined(__BEOS__) && !defined(__HAIKU__))
148ssize_t
149read_pos(int fd, fs_off_t _pos, void *data,  size_t nbytes)
150{
151    off_t  pos = (off_t)_pos;
152    size_t ret;
153
154    if (lseek(fd, pos, SEEK_SET) < 0) {
155        perror("read lseek");
156        errno = EINVAL;
157		return -1;
158    }
159
160    ret = read(fd, data, nbytes);
161
162    if (ret != nbytes) {
163        printf("read_pos: wanted %d, got %d\n", nbytes, ret);
164        return -1;
165    }
166
167    return ret;
168}
169
170ssize_t
171write_pos(int fd, fs_off_t _pos, const void *data,  size_t nbytes)
172{
173    off_t  pos = (off_t)_pos;
174    size_t ret;
175
176    if (lseek(fd, pos, SEEK_SET) < 0) {
177        perror("read lseek");
178        errno = EINVAL;
179		return -1;
180    }
181
182    ret = write(fd, data, nbytes);
183
184    if (ret != nbytes) {
185        printf("write_pos: wanted %d, got %d\n", nbytes, ret);
186        return -1;
187    }
188
189    return ret;
190}
191
192
193#ifdef sun                      /* bloody wankers */
194#include <sys/stream.h>
195#ifdef DEF_IOV_MAX
196#define MAX_IOV  DEF_IOV_MAX
197#else
198#define MAX_IOV  16
199#endif
200#else                         /* the rest of the world... */
201#define MAX_IOV  8192         /* something way bigger than we'll ever use */
202#endif
203
204ssize_t
205readv_pos(int fd, fs_off_t _pos, const struct iovec *iov, int count)
206{
207    off_t  pos = (off_t)_pos;
208    size_t amt = 0;
209    ssize_t ret;
210    const struct iovec *tmpiov;
211    int i, n;
212
213    if (lseek(fd, pos, SEEK_SET) < 0) {
214        perror("read lseek");
215        return FS_EINVAL;
216    }
217
218    i = 0;
219    tmpiov = iov;
220    while (i < count) {
221        if (i + MAX_IOV < count)
222            n = MAX_IOV;
223        else
224            n = (count - i);
225
226        ret = readv(fd, tmpiov, n);
227        amt += ret;
228
229        if (ret < 0)
230            break;
231
232        i += n;
233        tmpiov += n;
234    }
235
236    return amt;
237}
238
239ssize_t
240writev_pos(int fd, fs_off_t _pos, const struct iovec *iov,  int count)
241{
242    off_t  pos = (off_t)_pos;
243    size_t amt = 0;
244    ssize_t ret;
245    const struct iovec *tmpiov;
246    int i, n;
247
248    if (lseek(fd, pos, SEEK_SET) < 0) {
249        perror("read lseek");
250        return FS_EINVAL;
251    }
252
253    i = 0;
254    tmpiov = iov;
255    while (i < count) {
256        if (i + MAX_IOV < count)
257            n = MAX_IOV;
258        else
259            n = (count - i);
260
261        ret = writev(fd, tmpiov, n);
262        amt += ret;
263
264        if (ret < 0)
265            break;
266
267        i += n;
268        tmpiov += n;
269    }
270
271    return amt;
272}
273
274
275int build_platform_open(const char *pathname, int oflags, my_mode_t mode);
276
277int
278build_platform_open(const char *pathname, int oflags, my_mode_t mode)
279{
280	int fd = open(pathname, to_platform_open_mode(oflags),
281		to_platform_mode(mode));
282	if (fd < 0) {
283		errno = from_platform_error(errno);
284		return -1;
285	}
286
287	return fd;
288}
289
290
291int build_platform_close(int fd);
292
293int
294build_platform_close(int fd)
295{
296	if (close(fd) < 0) {
297		errno = from_platform_error(errno);
298		return -1;
299	}
300
301	return 0;
302}
303
304
305int build_platform_fstat(int fd, struct my_stat *myst);
306
307int
308build_platform_fstat(int fd, struct my_stat *myst)
309{
310	struct stat st;
311
312	if (!myst) {
313		errno = FS_EINVAL;
314		return -1;
315	}
316
317	if (fstat(fd, &st) < 0) {
318		errno = from_platform_error(errno);
319		return -1;
320	}
321
322	from_platform_stat(&st, myst);
323
324	return 0;
325}
326
327
328ssize_t build_platform_read_pos(int fd, fs_off_t pos, void *buf, size_t count);
329
330ssize_t
331build_platform_read_pos(int fd, fs_off_t pos, void *buf, size_t count)
332{
333	ssize_t result = read_pos(fd, pos, buf, count);
334	if (result < 0) {
335		errno = from_platform_error(errno);
336		return -1;
337	}
338
339	return result;
340}
341
342
343#ifdef HAIKU_HOST_PLATFORM_LINUX
344
345static bool
346test_size(int fd, off_t size)
347{
348	char buffer[1];
349
350	if (size == 0)
351		return true;
352
353	if (lseek(fd, size - 1, SEEK_SET) < 0)
354		return false;
355
356	return (read(fd, &buffer, 1) == 1);
357}
358
359
360static off_t
361get_partition_size(int fd, off_t maxSize)
362{
363	// binary search
364	off_t lower = 0;
365	off_t upper = maxSize;
366	while (lower < upper) {
367		off_t mid = (lower + upper + 1) / 2;
368		if (test_size(fd, mid))
369			lower = mid;
370		else
371			upper = mid - 1;
372	}
373
374	return lower;
375}
376
377#endif // HAIKU_HOST_PLATFORM_LINUX
378
379
380extern int build_platform_ioctl(int fd, unsigned long op, ...);
381
382int
383build_platform_ioctl(int fd, unsigned long op, ...)
384{
385	status_t error = FS_BAD_VALUE;
386	va_list list;
387
388	// count arguments
389
390	va_start(list, op);
391
392	switch (op) {
393		case 7:		// B_GET_GEOMETRY
394		{
395			#ifdef HAIKU_HOST_PLATFORM_LINUX
396			{
397				device_geometry *geometry = va_arg(list, device_geometry*);
398				struct hd_geometry hdGeometry;
399				// BLKGETSIZE and BLKGETSIZE64 don't seem to work for
400				// partitions. So we get the device geometry (there only seems
401				// to be HDIO_GETGEO, which is kind of obsolete, BTW), and
402				// get the partition size via binary search.
403				if (ioctl(fd, HDIO_GETGEO, &hdGeometry) == 0) {
404					off_t bytesPerCylinder = (off_t)hdGeometry.heads
405						* hdGeometry.sectors * 512;
406					off_t deviceSize = bytesPerCylinder * hdGeometry.cylinders;
407					off_t partitionSize = get_partition_size(fd, deviceSize);
408
409					geometry->head_count = hdGeometry.heads;
410					geometry->cylinder_count = partitionSize / bytesPerCylinder;
411					geometry->sectors_per_track = hdGeometry.sectors;
412
413					// TODO: Get the real values...
414					geometry->bytes_per_sector = 512;
415					geometry->device_type = B_DISK;
416					geometry->removable = false;
417					geometry->read_only = false;
418					geometry->write_once = false;
419					error = FS_OK;
420				} else
421					error = from_platform_error(errno);
422			}
423			#endif // HAIKU_HOST_PLATFORM_LINUX
424
425			break;
426		}
427
428		case 20:	// B_FLUSH_DRIVE_CACHE
429			error = FS_OK;
430			break;
431
432		case 10000:	// IOCTL_FILE_UNCACHED_IO
433			error = FS_OK;
434			break;
435	}
436
437	va_end(list);
438
439	if (error != FS_OK) {
440		errno = error;
441		return -1;
442	}
443	return 0;
444}
445
446
447#endif /* ! __BEOS__ */
448
449
450#include <stdarg.h>
451
452
453void
454panic(const char *format, ...)
455{
456    va_list     ap;
457
458    va_start(ap, format);
459    vfprintf(stderr, format, ap);
460    va_end(ap);
461
462    while (TRUE)
463        ;
464}
465
466
467
468#include "lock.h"
469
470int
471new_lock(lock *l, const char *name)
472{
473    l->c = 1;
474    l->s = create_sem(0, (char *)name);
475    if (l->s <= 0)
476        return l->s;
477    return 0;
478}
479
480int
481free_lock(lock *l)
482{
483    delete_sem(l->s);
484
485    return 0;
486}
487
488int
489new_mlock(mlock *l, long c, const char *name)
490{
491    l->s = create_sem(c, (char *)name);
492    if (l->s <= 0)
493        return l->s;
494    return 0;
495}
496
497int
498free_mlock(mlock *l)
499{
500    delete_sem(l->s);
501
502    return 0;
503}
504
505
506#ifdef unix
507#include <sys/time.h>
508
509bigtime_t
510system_time(void)
511{
512    bigtime_t      t;
513    struct timeval tv;
514
515    gettimeofday(&tv, NULL);
516
517    t = ((bigtime_t)tv.tv_sec * 1000000) + (bigtime_t)tv.tv_usec;
518    return t;
519}
520
521/*
522  If you're compiler/system can't deal with the version of system_time()
523  as defined above, use this one instead
524bigtime_t
525system_time(void)
526{
527    return (bigtime_t)time(NULL);
528}
529*/
530
531#endif  /* unix */
532
533#if (defined(__BEOS__) || defined(__HAIKU__))
534#include <KernelExport.h>
535
536void
537dprintf(const char *format, ...)
538{
539	va_list args;
540
541	va_start(args, format);
542	vprintf(format, args);
543	va_end(args);
544}
545
546#endif
547