src/platform_posix.c
changeset 972 254427fc42ab
parent 939 684c583cb586
child 1016 957c97389257
equal deleted inserted replaced
969:0bc902336e00 972:254427fc42ab
       
     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     const int appending = (mode & O_APPEND);
       
   240     int fd;
       
   241     int *retval;
       
   242     errno = 0;
       
   243 
       
   244     /* O_APPEND doesn't actually behave as we'd like. */
       
   245     mode &= ~O_APPEND;
       
   246 
       
   247     fd = open(filename, mode, S_IRUSR | S_IWUSR);
       
   248     BAIL_IF_MACRO(fd < 0, strerror(errno), NULL);
       
   249 
       
   250     if (appending)
       
   251     {
       
   252         if (lseek(fd, 0, SEEK_END) < 0)
       
   253         {
       
   254             close(fd);
       
   255             BAIL_MACRO(strerror(errno), NULL);
       
   256         } /* if */
       
   257     } /* if */
       
   258 
       
   259     retval = (int *) allocator.Malloc(sizeof (int));
       
   260     if (retval == NULL)
       
   261     {
       
   262         close(fd);
       
   263         BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
       
   264     } /* if */
       
   265 
       
   266     *retval = fd;
       
   267     return((void *) retval);
       
   268 } /* doOpen */
       
   269 
       
   270 
       
   271 void *__PHYSFS_platformOpenRead(const char *filename)
       
   272 {
       
   273     return(doOpen(filename, O_RDONLY));
       
   274 } /* __PHYSFS_platformOpenRead */
       
   275 
       
   276 
       
   277 void *__PHYSFS_platformOpenWrite(const char *filename)
       
   278 {
       
   279     return(doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC));
       
   280 } /* __PHYSFS_platformOpenWrite */
       
   281 
       
   282 
       
   283 void *__PHYSFS_platformOpenAppend(const char *filename)
       
   284 {
       
   285     return(doOpen(filename, O_WRONLY | O_CREAT | O_APPEND));
       
   286 } /* __PHYSFS_platformOpenAppend */
       
   287 
       
   288 
       
   289 PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
       
   290                                     PHYSFS_uint32 size, PHYSFS_uint32 count)
       
   291 {
       
   292     int fd = *((int *) opaque);
       
   293     int max = size * count;
       
   294     int rc = read(fd, buffer, max);
       
   295 
       
   296     BAIL_IF_MACRO(rc == -1, strerror(errno), rc);
       
   297     assert(rc <= max);
       
   298 
       
   299     if ((rc < max) && (size > 1))
       
   300         lseek(fd, -(rc % size), SEEK_CUR); /* rollback to object boundary. */
       
   301 
       
   302     return(rc / size);
       
   303 } /* __PHYSFS_platformRead */
       
   304 
       
   305 
       
   306 PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
       
   307                                      PHYSFS_uint32 size, PHYSFS_uint32 count)
       
   308 {
       
   309     int fd = *((int *) opaque);
       
   310     int max = size * count;
       
   311     int rc = write(fd, (void *) buffer, max);
       
   312 
       
   313     BAIL_IF_MACRO(rc == -1, strerror(errno), rc);
       
   314     assert(rc <= max);
       
   315 
       
   316     if ((rc < max) && (size > 1))
       
   317         lseek(fd, -(rc % size), SEEK_CUR); /* rollback to object boundary. */
       
   318 
       
   319     return(rc / size);
       
   320 } /* __PHYSFS_platformWrite */
       
   321 
       
   322 
       
   323 int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
       
   324 {
       
   325     int fd = *((int *) opaque);
       
   326 
       
   327     #ifdef PHYSFS_HAVE_LLSEEK
       
   328       unsigned long offset_high = ((pos >> 32) & 0xFFFFFFFF);
       
   329       unsigned long offset_low = (pos & 0xFFFFFFFF);
       
   330       loff_t retoffset;
       
   331       int rc = llseek(fd, offset_high, offset_low, &retoffset, SEEK_SET);
       
   332       BAIL_IF_MACRO(rc == -1, strerror(errno), 0);
       
   333     #else
       
   334       BAIL_IF_MACRO(lseek(fd, (int) pos, SEEK_SET) == -1, strerror(errno), 0);
       
   335     #endif
       
   336 
       
   337     return(1);
       
   338 } /* __PHYSFS_platformSeek */
       
   339 
       
   340 
       
   341 PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
       
   342 {
       
   343     int fd = *((int *) opaque);
       
   344     PHYSFS_sint64 retval;
       
   345 
       
   346     #ifdef PHYSFS_HAVE_LLSEEK
       
   347       loff_t retoffset;
       
   348       int rc = llseek(fd, 0, &retoffset, SEEK_CUR);
       
   349       BAIL_IF_MACRO(rc == -1, strerror(errno), -1);
       
   350       retval = (PHYSFS_sint64) retoffset;
       
   351     #else
       
   352       retval = (PHYSFS_sint64) lseek(fd, 0, SEEK_CUR);
       
   353       BAIL_IF_MACRO(retval == -1, strerror(errno), -1);
       
   354     #endif
       
   355 
       
   356     return(retval);
       
   357 } /* __PHYSFS_platformTell */
       
   358 
       
   359 
       
   360 PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
       
   361 {
       
   362     int fd = *((int *) opaque);
       
   363     struct stat statbuf;
       
   364     BAIL_IF_MACRO(fstat(fd, &statbuf) == -1, strerror(errno), -1);
       
   365     return((PHYSFS_sint64) statbuf.st_size);
       
   366 } /* __PHYSFS_platformFileLength */
       
   367 
       
   368 
       
   369 int __PHYSFS_platformEOF(void *opaque)
       
   370 {
       
   371     PHYSFS_sint64 pos = __PHYSFS_platformTell(opaque);
       
   372     PHYSFS_sint64 len = __PHYSFS_platformFileLength(opaque);
       
   373     return(pos >= len);
       
   374 } /* __PHYSFS_platformEOF */
       
   375 
       
   376 
       
   377 int __PHYSFS_platformFlush(void *opaque)
       
   378 {
       
   379     int fd = *((int *) opaque);
       
   380     BAIL_IF_MACRO(fsync(fd) == -1, strerror(errno), 0);
       
   381     return(1);
       
   382 } /* __PHYSFS_platformFlush */
       
   383 
       
   384 
       
   385 int __PHYSFS_platformClose(void *opaque)
       
   386 {
       
   387     int fd = *((int *) opaque);
       
   388     BAIL_IF_MACRO(close(fd) == -1, strerror(errno), 0);
       
   389     allocator.Free(opaque);
       
   390     return(1);
       
   391 } /* __PHYSFS_platformClose */
       
   392 
       
   393 
       
   394 int __PHYSFS_platformDelete(const char *path)
       
   395 {
       
   396     BAIL_IF_MACRO(remove(path) == -1, strerror(errno), 0);
       
   397     return(1);
       
   398 } /* __PHYSFS_platformDelete */
       
   399 
       
   400 
       
   401 PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
       
   402 {
       
   403     struct stat statbuf;
       
   404     BAIL_IF_MACRO(stat(fname, &statbuf) < 0, strerror(errno), -1);
       
   405     return statbuf.st_mtime;
       
   406 } /* __PHYSFS_platformGetLastModTime */
       
   407 
       
   408 #endif  /* PHYSFS_PLATFORM_POSIX */
       
   409 
       
   410 /* end of posix.c ... */
       
   411