1 |
/* |
2 |
* HT Editor |
3 |
* sysfile.cc - file system functions for BeOS |
4 |
* |
5 |
* Copyright (C) 1999-2002 Stefan Weyergraf |
6 |
* Copyright (C) 2004 Francois Revol (revol@free.fr) |
7 |
* |
8 |
* This program is free software; you can redistribute it and/or modify |
9 |
* it under the terms of the GNU General Public License version 2 as |
10 |
* published by the Free Software Foundation. |
11 |
* |
12 |
* This program is distributed in the hope that it will be useful, |
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
* GNU General Public License for more details. |
16 |
* |
17 |
* You should have received a copy of the GNU General Public License |
18 |
* along with this program; if not, write to the Free Software |
19 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
20 |
*/ |
21 |
|
22 |
#include <cerrno> |
23 |
#include <fcntl.h> |
24 |
#include <cstdio> |
25 |
#include <cstdlib> |
26 |
#include <cstring> |
27 |
#include <sys/stat.h> |
28 |
#include <sys/time.h> |
29 |
#include <sys/types.h> |
30 |
#include <unistd.h> |
31 |
|
32 |
#include <OS.h> |
33 |
#include <Entry.h> |
34 |
#include <Path.h> |
35 |
|
36 |
#include <limits.h> /* for PAGESIZE */ |
37 |
#ifndef PAGESIZE |
38 |
#ifdef B_PAGE_SIZE |
39 |
#define PAGESIZE B_PAGE_SIZE |
40 |
#else |
41 |
#define PAGESIZE 4096 |
42 |
#endif |
43 |
#endif |
44 |
|
45 |
|
46 |
#define USE_AREAS |
47 |
|
48 |
#ifndef HAVE_REALPATH |
49 |
char *realpath(const char *filename, char *result) |
50 |
{ |
51 |
BPath p; |
52 |
BEntry ent(filename, true); /* traverse symlinks */ |
53 |
if (ent.InitCheck()) |
54 |
return NULL; |
55 |
if (ent.GetPath(&p)) |
56 |
return NULL; |
57 |
strcpy(result, p.Path()); |
58 |
return result; |
59 |
} |
60 |
#endif |
61 |
|
62 |
#include "system/file.h" |
63 |
|
64 |
#include <dirent.h> |
65 |
|
66 |
struct posixfindstate { |
67 |
DIR *fhandle; |
68 |
}; |
69 |
|
70 |
inline bool sys_filename_is_absolute(const char *filename) |
71 |
{ |
72 |
return sys_is_path_delim(filename[0]); |
73 |
} |
74 |
|
75 |
int sys_file_mode(int mode) |
76 |
{ |
77 |
int m = 0; |
78 |
if (S_ISREG(mode)) { |
79 |
m |= HT_S_IFREG; |
80 |
} else if (S_ISBLK(mode)) { |
81 |
m |= HT_S_IFBLK; |
82 |
} else if (S_ISCHR(mode)) { |
83 |
m |= HT_S_IFCHR; |
84 |
} else if (S_ISDIR(mode)) { |
85 |
m |= HT_S_IFDIR; |
86 |
} else if (S_ISFIFO(mode)) { |
87 |
m |= HT_S_IFFIFO; |
88 |
} else if (S_ISLNK(mode)) { |
89 |
m |= HT_S_IFLNK; |
90 |
#ifdef S_ISSOCK |
91 |
} else if (S_ISSOCK(mode)) { |
92 |
m |= HT_S_IFSOCK; |
93 |
#endif |
94 |
} |
95 |
if (mode & S_IRUSR) m |= HT_S_IRUSR; |
96 |
if (mode & S_IRGRP) m |= HT_S_IRGRP; |
97 |
if (mode & S_IROTH) m |= HT_S_IROTH; |
98 |
|
99 |
if (mode & S_IWUSR) m |= HT_S_IWUSR; |
100 |
if (mode & S_IWGRP) m |= HT_S_IWGRP; |
101 |
if (mode & S_IWOTH) m |= HT_S_IWOTH; |
102 |
|
103 |
if (mode & S_IXUSR) m |= HT_S_IXUSR; |
104 |
if (mode & S_IXGRP) m |= HT_S_IXGRP; |
105 |
if (mode & S_IXOTH) m |= HT_S_IXOTH; |
106 |
return m; |
107 |
} |
108 |
|
109 |
bool sys_is_path_delim(char c) |
110 |
{ |
111 |
return c == '/'; |
112 |
} |
113 |
|
114 |
int sys_filename_cmp(const char *a, const char *b) |
115 |
{ |
116 |
while (*a && *b) { |
117 |
if (sys_is_path_delim(*a) && sys_is_path_delim(*b)) { |
118 |
} else if (*a != *b) { |
119 |
break; |
120 |
} |
121 |
a++; |
122 |
b++; |
123 |
} |
124 |
return *a - *b; |
125 |
} |
126 |
|
127 |
int sys_canonicalize(char *result, const char *filename) |
128 |
{ |
129 |
if (!sys_filename_is_absolute(filename)) return ENOENT; |
130 |
return (realpath(filename, result)==result) ? 0 : ENOENT; |
131 |
} |
132 |
|
133 |
static char sys_find_dirname[HT_NAME_MAX]; |
134 |
|
135 |
int sys_findclose(pfind_t &pfind) |
136 |
{ |
137 |
int r = closedir(((posixfindstate*)pfind.findstate)->fhandle); |
138 |
free(pfind.findstate); |
139 |
return r; |
140 |
} |
141 |
|
142 |
int sys_findfirst(pfind_t &pfind, const char *dirname) |
143 |
{ |
144 |
if (!sys_filename_is_absolute(dirname)) return ENOENT; |
145 |
int r; |
146 |
pfind.findstate = malloc(sizeof (posixfindstate)); |
147 |
posixfindstate *pfs = (posixfindstate*)pfind.findstate; |
148 |
if ((pfs->fhandle = opendir(dirname))) { |
149 |
strcpy(sys_find_dirname, dirname); |
150 |
char *s = sys_find_dirname+strlen(sys_find_dirname); |
151 |
if ((s > sys_find_dirname) && (*(s-1) != '/')) { |
152 |
*(s++) = '/'; |
153 |
*s = 0; |
154 |
} |
155 |
r = sys_findnext(pfind); |
156 |
} else r = errno ? errno : ENOENT; |
157 |
if (r) free(pfind.findstate); |
158 |
return r; |
159 |
} |
160 |
|
161 |
int sys_findnext(pfind_t &pfind) |
162 |
{ |
163 |
posixfindstate *pfs = (posixfindstate*)pfind.findstate; |
164 |
struct dirent *d; |
165 |
if ((d = readdir(pfs->fhandle))) { |
166 |
pfind.name = d->d_name; |
167 |
char *s = sys_find_dirname+strlen(sys_find_dirname); |
168 |
strcpy(s, d->d_name); |
169 |
sys_pstat(pfind.stat, sys_find_dirname); |
170 |
*s = 0; |
171 |
return 0; |
172 |
} |
173 |
return ENOENT; |
174 |
} |
175 |
|
176 |
static void stat_to_pstat_t(const struct stat &st, pstat_t &s) |
177 |
{ |
178 |
s.caps = pstat_ctime|pstat_mtime|pstat_atime|pstat_uid|pstat_gid|pstat_mode_all|pstat_size|pstat_inode; |
179 |
s.ctime = st.st_ctime; |
180 |
s.mtime = st.st_mtime; |
181 |
s.atime = st.st_atime; |
182 |
s.gid = st.st_uid; |
183 |
s.uid = st.st_gid; |
184 |
s.mode = sys_file_mode(st.st_mode); |
185 |
s.size = st.st_size; |
186 |
s.fsid = st.st_ino; |
187 |
} |
188 |
|
189 |
int sys_pstat(pstat_t &s, const char *filename) |
190 |
{ |
191 |
if (!sys_filename_is_absolute(filename)) return ENOENT; |
192 |
struct stat st; |
193 |
errno = 0; |
194 |
int e = lstat(filename, &st); |
195 |
if (e) return errno ? errno : ENOENT; |
196 |
stat_to_pstat_t(st, s); |
197 |
return 0; |
198 |
} |
199 |
|
200 |
int sys_pstat_fd(pstat_t &s, int fd) |
201 |
{ |
202 |
struct stat st; |
203 |
errno = 0; |
204 |
int e = fstat(fd, &st); |
205 |
if (e) return errno ? errno : ENOENT; |
206 |
stat_to_pstat_t(st, s); |
207 |
return 0; |
208 |
} |
209 |
|
210 |
int sys_truncate(const char *filename, FileOfs ofs) |
211 |
{ |
212 |
if (!sys_filename_is_absolute(filename)) return ENOENT; |
213 |
int fd = open(filename, O_RDWR, 0); |
214 |
if (fd < 0) return errno; |
215 |
if (ftruncate(fd, ofs) != 0) return errno; |
216 |
return close(fd); |
217 |
} |
218 |
|
219 |
int sys_deletefile(const char *filename) |
220 |
{ |
221 |
if (!sys_filename_is_absolute(filename)) return ENOENT; |
222 |
return remove(filename); |
223 |
} |
224 |
|
225 |
int sys_truncate_fd(int fd, FileOfs ofs) |
226 |
{ |
227 |
if (ftruncate(fd, ofs) != 0) return errno; |
228 |
return 0; |
229 |
} |
230 |
|
231 |
void sys_suspend() |
232 |
{ |
233 |
snooze(100LL); |
234 |
} |
235 |
|
236 |
int sys_get_free_mem() |
237 |
{ |
238 |
return 0; |
239 |
} |
240 |
|
241 |
SYS_FILE *sys_fopen(const char *filename, int openmode) |
242 |
{ |
243 |
if (openmode & SYS_OPEN_CREATE) { |
244 |
return (SYS_FILE *)fopen(filename, "w+"); |
245 |
} else { |
246 |
if (openmode & SYS_OPEN_WRITE) { |
247 |
return (SYS_FILE *)fopen(filename, "r+"); |
248 |
} else { |
249 |
return (SYS_FILE *)fopen(filename, "r"); |
250 |
} |
251 |
} |
252 |
} |
253 |
|
254 |
void sys_fclose(SYS_FILE *file) |
255 |
{ |
256 |
fclose((FILE *)file); |
257 |
} |
258 |
|
259 |
int sys_fread(SYS_FILE *file, byte *buf, int size) |
260 |
{ |
261 |
return fread(buf, 1, size, (FILE *)file); |
262 |
} |
263 |
|
264 |
int sys_fwrite(SYS_FILE *file, byte *buf, int size) |
265 |
{ |
266 |
return fwrite(buf, 1, size, (FILE *)file); |
267 |
} |
268 |
|
269 |
int sys_fseek(SYS_FILE *file, FileOfs newofs, int seekmode) |
270 |
{ |
271 |
int r; |
272 |
switch (seekmode) { |
273 |
case SYS_SEEK_SET: r = _fseek((FILE *)file, newofs, SEEK_SET); break; |
274 |
case SYS_SEEK_REL: r = _fseek((FILE *)file, newofs, SEEK_CUR); break; |
275 |
case SYS_SEEK_END: r = _fseek((FILE *)file, newofs, SEEK_END); break; |
276 |
default: return EINVAL; |
277 |
} |
278 |
return r ? errno : 0; |
279 |
} |
280 |
|
281 |
void sys_flush(SYS_FILE *file) |
282 |
{ |
283 |
fflush((FILE *)file); |
284 |
} |
285 |
|
286 |
FileOfs sys_ftell(SYS_FILE *file) |
287 |
{ |
288 |
fpos_t pos; |
289 |
int err; |
290 |
|
291 |
// BeOS *is* 64 bits :p |
292 |
// ftell and fseek use long !! whoever invented the buffered io stuff should be slapped :^) |
293 |
// _fseek does work, but not _ftell... use _fgetpos |
294 |
|
295 |
err = fgetpos((FILE *)file, &pos); |
296 |
if (err < 0) |
297 |
return err; |
298 |
return pos; |
299 |
} |
300 |
|
301 |
void *sys_alloc_read_write_execute(int size) |
302 |
{ |
303 |
#ifdef USE_AREAS |
304 |
area_id id = -1; |
305 |
void *addr; |
306 |
size = ((size + PAGESIZE-1) & ~(PAGESIZE-1)); |
307 |
/* first try full lock, if it doesn't work, then no lock */ |
308 |
|
309 |
id = create_area("PearPC rwx area", &addr, B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA|B_WRITE_AREA); |
310 |
/* |
311 |
if (id < B_OK) { |
312 |
fprintf(stderr, "warning: create_area failed with FULL_LOCK\n"); |
313 |
id = create_area("PearPC rwx area", &addr, B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA|B_WRITE_AREA); |
314 |
} |
315 |
*/ |
316 |
fprintf(stderr, "create_area(, , , %d, , ) = 0x%08lx\n", size, id); |
317 |
if (id < B_OK) |
318 |
return NULL; |
319 |
return addr; |
320 |
#else |
321 |
void *p = malloc(size+PAGESIZE-1); |
322 |
if (!p) return NULL; |
323 |
|
324 |
void *ret = (void *)(((int)p + PAGESIZE-1) & ~(PAGESIZE-1)); |
325 |
|
326 |
#ifdef HAVE_MPROTECT |
327 |
if (mprotect(ret, size, PROT_READ | PROT_WRITE | PROT_EXEC)) { |
328 |
free(p); |
329 |
return NULL; |
330 |
} |
331 |
#endif |
332 |
return ret; |
333 |
#endif |
334 |
} |
335 |
|
336 |
void sys_free_read_write_execute(void *p) |
337 |
{ |
338 |
#ifdef USE_AREAS |
339 |
fprintf(stderr, "sys_free_read_write_execute(%p)\n", p); |
340 |
area_id id; |
341 |
id = area_for(p); |
342 |
if (id < B_OK) |
343 |
return; |
344 |
fprintf(stderr, "delete_area(%08lx)\n", id); |
345 |
//delete_area(id); |
346 |
#endif |
347 |
} |