Initial integration, lots of broken stuff
[supertux.git] / src / unison / physfs-1.1.1 / platform / posix.c
1 /*
2  * Posix-esque 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_POSIX
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <ctype.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <pwd.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <fcntl.h>
25
26 #ifdef PHYSFS_HAVE_LLSEEK
27 #include <linux/unistd.h>
28 #endif
29
30 #include "physfs_internal.h"
31
32
33 const char *__PHYSFS_platformDirSeparator = "/";
34
35
36 char *__PHYSFS_platformCopyEnvironmentVariable(const char *varname)
37 {
38     const char *envr = getenv(varname);
39     char *retval = NULL;
40
41     if (envr != NULL)
42     {
43         retval = (char *) allocator.Malloc(strlen(envr) + 1);
44         if (retval != NULL)
45             strcpy(retval, envr);
46     } /* if */
47
48     return(retval);
49 } /* __PHYSFS_platformCopyEnvironmentVariable */
50
51
52 static char *getUserNameByUID(void)
53 {
54     uid_t uid = getuid();
55     struct passwd *pw;
56     char *retval = NULL;
57
58     pw = getpwuid(uid);
59     if ((pw != NULL) && (pw->pw_name != NULL))
60     {
61         retval = (char *) allocator.Malloc(strlen(pw->pw_name) + 1);
62         if (retval != NULL)
63             strcpy(retval, pw->pw_name);
64     } /* if */
65     
66     return(retval);
67 } /* getUserNameByUID */
68
69
70 static char *getUserDirByUID(void)
71 {
72     uid_t uid = getuid();
73     struct passwd *pw;
74     char *retval = NULL;
75
76     pw = getpwuid(uid);
77     if ((pw != NULL) && (pw->pw_dir != NULL))
78     {
79         retval = (char *) allocator.Malloc(strlen(pw->pw_dir) + 1);
80         if (retval != NULL)
81             strcpy(retval, pw->pw_dir);
82     } /* if */
83     
84     return(retval);
85 } /* getUserDirByUID */
86
87
88 char *__PHYSFS_platformGetUserName(void)
89 {
90     char *retval = getUserNameByUID();
91     if (retval == NULL)
92         retval = __PHYSFS_platformCopyEnvironmentVariable("USER");
93     return(retval);
94 } /* __PHYSFS_platformGetUserName */
95
96
97 char *__PHYSFS_platformGetUserDir(void)
98 {
99     char *retval = __PHYSFS_platformCopyEnvironmentVariable("HOME");
100     if (retval == NULL)
101         retval = getUserDirByUID();
102     return(retval);
103 } /* __PHYSFS_platformGetUserDir */
104
105
106 int __PHYSFS_platformExists(const char *fname)
107 {
108     struct stat statbuf;
109     BAIL_IF_MACRO(lstat(fname, &statbuf) == -1, strerror(errno), 0);
110     return(1);
111 } /* __PHYSFS_platformExists */
112
113
114 int __PHYSFS_platformIsSymLink(const char *fname)
115 {
116     struct stat statbuf;
117     BAIL_IF_MACRO(lstat(fname, &statbuf) == -1, strerror(errno), 0);
118     return( (S_ISLNK(statbuf.st_mode)) ? 1 : 0 );
119 } /* __PHYSFS_platformIsSymlink */
120
121
122 int __PHYSFS_platformIsDirectory(const char *fname)
123 {
124     struct stat statbuf;
125     BAIL_IF_MACRO(stat(fname, &statbuf) == -1, strerror(errno), 0);
126     return( (S_ISDIR(statbuf.st_mode)) ? 1 : 0 );
127 } /* __PHYSFS_platformIsDirectory */
128
129
130 char *__PHYSFS_platformCvtToDependent(const char *prepend,
131                                       const char *dirName,
132                                       const char *append)
133 {
134     int len = ((prepend) ? strlen(prepend) : 0) +
135               ((append) ? strlen(append) : 0) +
136               strlen(dirName) + 1;
137     char *retval = (char *) allocator.Malloc(len);
138
139     BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
140
141     /* platform-independent notation is Unix-style already.  :)  */
142
143     if (prepend)
144         strcpy(retval, prepend);
145     else
146         retval[0] = '\0';
147
148     strcat(retval, dirName);
149
150     if (append)
151         strcat(retval, append);
152
153     return(retval);
154 } /* __PHYSFS_platformCvtToDependent */
155
156
157
158 void __PHYSFS_platformEnumerateFiles(const char *dirname,
159                                      int omitSymLinks,
160                                      PHYSFS_EnumFilesCallback callback,
161                                      const char *origdir,
162                                      void *callbackdata)
163 {
164     DIR *dir;
165     struct dirent *ent;
166     int bufsize = 0;
167     char *buf = NULL;
168     int dlen = 0;
169
170     if (omitSymLinks)  /* !!! FIXME: this malloc sucks. */
171     {
172         dlen = strlen(dirname);
173         bufsize = dlen + 256;
174         buf = (char *) allocator.Malloc(bufsize);
175         if (buf == NULL)
176             return;
177         strcpy(buf, dirname);
178         if (buf[dlen - 1] != '/')
179         {
180             buf[dlen++] = '/';
181             buf[dlen] = '\0';
182         } /* if */
183     } /* if */
184
185     errno = 0;
186     dir = opendir(dirname);
187     if (dir == NULL)
188     {
189         allocator.Free(buf);
190         return;
191     } /* if */
192
193     while ((ent = readdir(dir)) != NULL)
194     {
195         if (strcmp(ent->d_name, ".") == 0)
196             continue;
197
198         if (strcmp(ent->d_name, "..") == 0)
199             continue;
200
201         if (omitSymLinks)
202         {
203             char *p;
204             int len = strlen(ent->d_name) + dlen + 1;
205             if (len > bufsize)
206             {
207                 p = (char *) allocator.Realloc(buf, len);
208                 if (p == NULL)
209                     continue;
210                 buf = p;
211                 bufsize = len;
212             } /* if */
213
214             strcpy(buf + dlen, ent->d_name);
215             if (__PHYSFS_platformIsSymLink(buf))
216                 continue;
217         } /* if */
218
219         callback(callbackdata, origdir, ent->d_name);
220     } /* while */
221
222     allocator.Free(buf);
223     closedir(dir);
224 } /* __PHYSFS_platformEnumerateFiles */
225
226
227 int __PHYSFS_platformMkDir(const char *path)
228 {
229     int rc;
230     errno = 0;
231     rc = mkdir(path, S_IRWXU);
232     BAIL_IF_MACRO(rc == -1, strerror(errno), 0);
233     return(1);
234 } /* __PHYSFS_platformMkDir */
235
236
237 static void *doOpen(const char *filename, int mode)
238 {
239     int fd;
240     int *retval;
241     errno = 0;
242
243     fd = open(filename, mode, S_IRUSR | S_IWUSR);
244     BAIL_IF_MACRO(fd < 0, strerror(errno), NULL);
245
246     retval = (int *) allocator.Malloc(sizeof (int));
247     if (retval == NULL)
248     {
249         close(fd);
250         BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
251     } /* if */
252
253     *retval = fd;
254     return((void *) retval);
255 } /* doOpen */
256
257
258 void *__PHYSFS_platformOpenRead(const char *filename)
259 {
260     return(doOpen(filename, O_RDONLY));
261 } /* __PHYSFS_platformOpenRead */
262
263
264 void *__PHYSFS_platformOpenWrite(const char *filename)
265 {
266     return(doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC));
267 } /* __PHYSFS_platformOpenWrite */
268
269
270 void *__PHYSFS_platformOpenAppend(const char *filename)
271 {
272     return(doOpen(filename, O_WRONLY | O_CREAT | O_APPEND));
273 } /* __PHYSFS_platformOpenAppend */
274
275
276 PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
277                                     PHYSFS_uint32 size, PHYSFS_uint32 count)
278 {
279     int fd = *((int *) opaque);
280     int max = size * count;
281     int rc = read(fd, buffer, max);
282
283     BAIL_IF_MACRO(rc == -1, strerror(errno), rc);
284     assert(rc <= max);
285
286     if ((rc < max) && (size > 1))
287         lseek(fd, -(rc % size), SEEK_CUR); /* rollback to object boundary. */
288
289     return(rc / size);
290 } /* __PHYSFS_platformRead */
291
292
293 PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
294                                      PHYSFS_uint32 size, PHYSFS_uint32 count)
295 {
296     int fd = *((int *) opaque);
297     int max = size * count;
298     int rc = write(fd, (void *) buffer, max);
299
300     BAIL_IF_MACRO(rc == -1, strerror(errno), rc);
301     assert(rc <= max);
302
303     if ((rc < max) && (size > 1))
304         lseek(fd, -(rc % size), SEEK_CUR); /* rollback to object boundary. */
305
306     return(rc / size);
307 } /* __PHYSFS_platformWrite */
308
309
310 int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
311 {
312     int fd = *((int *) opaque);
313
314     #ifdef PHYSFS_HAVE_LLSEEK
315       unsigned long offset_high = ((pos >> 32) & 0xFFFFFFFF);
316       unsigned long offset_low = (pos & 0xFFFFFFFF);
317       loff_t retoffset;
318       int rc = llseek(fd, offset_high, offset_low, &retoffset, SEEK_SET);
319       BAIL_IF_MACRO(rc == -1, strerror(errno), 0);
320     #else
321       BAIL_IF_MACRO(lseek(fd, (int) pos, SEEK_SET) == -1, strerror(errno), 0);
322     #endif
323
324     return(1);
325 } /* __PHYSFS_platformSeek */
326
327
328 PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
329 {
330     int fd = *((int *) opaque);
331     PHYSFS_sint64 retval;
332
333     #ifdef PHYSFS_HAVE_LLSEEK
334       loff_t retoffset;
335       int rc = llseek(fd, 0, &retoffset, SEEK_CUR);
336       BAIL_IF_MACRO(rc == -1, strerror(errno), -1);
337       retval = (PHYSFS_sint64) retoffset;
338     #else
339       retval = (PHYSFS_sint64) lseek(fd, 0, SEEK_CUR);
340       BAIL_IF_MACRO(retval == -1, strerror(errno), -1);
341     #endif
342
343     return(retval);
344 } /* __PHYSFS_platformTell */
345
346
347 PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
348 {
349     int fd = *((int *) opaque);
350     struct stat statbuf;
351     BAIL_IF_MACRO(fstat(fd, &statbuf) == -1, strerror(errno), -1);
352     return((PHYSFS_sint64) statbuf.st_size);
353 } /* __PHYSFS_platformFileLength */
354
355
356 int __PHYSFS_platformEOF(void *opaque)
357 {
358     PHYSFS_sint64 pos = __PHYSFS_platformTell(opaque);
359     PHYSFS_sint64 len = __PHYSFS_platformFileLength(opaque);
360     return(pos >= len);
361 } /* __PHYSFS_platformEOF */
362
363
364 int __PHYSFS_platformFlush(void *opaque)
365 {
366     int fd = *((int *) opaque);
367     BAIL_IF_MACRO(fsync(fd) == -1, strerror(errno), 0);
368     return(1);
369 } /* __PHYSFS_platformFlush */
370
371
372 int __PHYSFS_platformClose(void *opaque)
373 {
374     int fd = *((int *) opaque);
375     BAIL_IF_MACRO(close(fd) == -1, strerror(errno), 0);
376     allocator.Free(opaque);
377     return(1);
378 } /* __PHYSFS_platformClose */
379
380
381 int __PHYSFS_platformDelete(const char *path)
382 {
383     BAIL_IF_MACRO(remove(path) == -1, strerror(errno), 0);
384     return(1);
385 } /* __PHYSFS_platformDelete */
386
387
388 PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
389 {
390     struct stat statbuf;
391     BAIL_IF_MACRO(stat(fname, &statbuf) < 0, strerror(errno), -1);
392     return statbuf.st_mtime;
393 } /* __PHYSFS_platformGetLastModTime */
394
395 #endif  /* PHYSFS_PLATFORM_POSIX */
396
397 /* end of posix.c ... */
398