1 |
dpavlin |
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 |
|
|
} |