1/*
2 * Haiku platform-dependent support routines for PhysicsFS.
3 *
4 * Please see the file LICENSE.txt in the source's root directory.
5 *
6 * This file written by Ryan C. Gordon.
7 */
8
9#define __PHYSICSFS_INTERNAL__
10#include "physfs_platforms.h"
11
12#ifdef PHYSFS_PLATFORM_HAIKU
13
14#include <os/kernel/OS.h>
15#include <os/app/Roster.h>
16#include <os/storage/Volume.h>
17#include <os/storage/VolumeRoster.h>
18#include <os/storage/Directory.h>
19#include <os/storage/Entry.h>
20#include <os/storage/Path.h>
21#include <os/kernel/fs_info.h>
22#include <os/device/scsi.h>
23
24#include <errno.h>
25#include <unistd.h>
26
27#include "physfs_internal.h"
28
29int __PHYSFS_platformInit(void)
30{
31 return 1; /* always succeed. */
32} /* __PHYSFS_platformInit */
33
34
35void __PHYSFS_platformDeinit(void)
36{
37 /* no-op */
38} /* __PHYSFS_platformDeinit */
39
40
41static char *getMountPoint(const char *devname, char *buf, size_t bufsize)
42{
43 BVolumeRoster mounts;
44 BVolume vol;
45
46 mounts.Rewind();
47 while (mounts.GetNextVolume(&vol) == B_NO_ERROR)
48 {
49 fs_info fsinfo;
50 fs_stat_dev(vol.Device(), &fsinfo);
51 if (strcmp(devname, fsinfo.device_name) == 0)
52 {
53 BDirectory directory;
54 BEntry entry;
55 BPath path;
56 const char *str;
57
58 if ( (vol.GetRootDirectory(&directory) < B_OK) ||
59 (directory.GetEntry(&entry) < B_OK) ||
60 (entry.GetPath(&path) < B_OK) ||
61 ( (str = path.Path()) == NULL) )
62 return NULL;
63
64 strncpy(buf, str, bufsize-1);
65 buf[bufsize-1] = '\0';
66 return buf;
67 } /* if */
68 } /* while */
69
70 return NULL;
71} /* getMountPoint */
72
73
74 /*
75 * This function is lifted from Simple Directmedia Layer (SDL):
76 * https://www.libsdl.org/ ... this is zlib-licensed code, too.
77 */
78static void tryDir(const char *d, PHYSFS_StringCallback callback, void *data)
79{
80 BDirectory dir;
81 dir.SetTo(d);
82 if (dir.InitCheck() != B_NO_ERROR)
83 return;
84
85 dir.Rewind();
86 BEntry entry;
87 while (dir.GetNextEntry(&entry) >= 0)
88 {
89 BPath path;
90 const char *name;
91 entry_ref e;
92
93 if (entry.GetPath(&path) != B_NO_ERROR)
94 continue;
95
96 name = path.Path();
97
98 if (entry.GetRef(&e) != B_NO_ERROR)
99 continue;
100
101 if (entry.IsDirectory())
102 {
103 if (strcmp(e.name, "floppy") != 0)
104 tryDir(name, callback, data);
105 continue;
106 } /* if */
107
108 const int devfd = open(name, O_RDONLY);
109 if (devfd < 0)
110 continue;
111
112 device_geometry g;
113 const int rc = ioctl(devfd, B_GET_GEOMETRY, &g, sizeof (g));
114 close(devfd);
115 if (rc < 0)
116 continue;
117
118 if (g.device_type != B_CD)
119 continue;
120
121 char mntpnt[B_FILE_NAME_LENGTH];
122 if (getMountPoint(name, mntpnt, sizeof (mntpnt)))
123 callback(data, mntpnt);
124 } /* while */
125} /* tryDir */
126
127
128void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
129{
130 tryDir("/dev/disk", cb, data);
131} /* __PHYSFS_platformDetectAvailableCDs */
132
133
134static team_id getTeamID(void)
135{
136 thread_info info;
137 thread_id tid = find_thread(NULL);
138 get_thread_info(tid, &info);
139 return info.team;
140} /* getTeamID */
141
142
143char *__PHYSFS_platformCalcBaseDir(const char *argv0)
144{
145 image_info info;
146 int32 cookie = 0;
147
148 while (get_next_image_info(0, &cookie, &info) == B_OK)
149 {
150 if (info.type == B_APP_IMAGE)
151 break;
152 } /* while */
153
154 BEntry entry(info.name, true);
155 BPath path;
156 status_t rc = entry.GetPath(&path); /* (path) now has binary's path. */
157 assert(rc == B_OK);
158 rc = path.GetParent(&path); /* chop filename, keep directory. */
159 assert(rc == B_OK);
160 const char *str = path.Path();
161 assert(str != NULL);
162 const size_t len = strlen(str);
163 char *retval = (char *) allocator.Malloc(len + 2);
164 BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
165 strcpy(retval, str);
166 retval[len] = '/';
167 retval[len+1] = '\0';
168 return retval;
169} /* __PHYSFS_platformCalcBaseDir */
170
171
172char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
173{
174 const char *userdir = __PHYSFS_getUserDir();
175 const char *append = "config/settings/";
176 const size_t len = strlen(userdir) + strlen(append) + strlen(app) + 2;
177 char *retval = (char *) allocator.Malloc(len);
178 BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
179 snprintf(retval, len, "%s%s%s/", userdir, append, app);
180 return retval;
181} /* __PHYSFS_platformCalcPrefDir */
182
183#endif /* PHYSFS_PLATFORM_HAIKU */
184
185/* end of physfs_platform_haiku.cpp ... */
186
187