]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - fs.c
Fix userdir detection on Unix systems.
[xonotic/darkplaces.git] / fs.c
diff --git a/fs.c b/fs.c
index 45406637b56dec01d267e33a952a4166ac4fd3f4..0941916ba64471a6ea92b873533e7b2117e7c75a 100644 (file)
--- a/fs.c
+++ b/fs.c
                Boston, MA  02111-1307, USA
 */
 
-#ifdef __APPLE__
-// include SDL for IPHONEOS code
-# include <TargetConditionals.h>
-# if TARGET_OS_IPHONE
-#  include <SDL.h>
-# endif
-#endif
-
 #include <limits.h>
 #include <fcntl.h>
 
 #endif
 
 #include "quakedef.h"
+
+#if TARGET_OS_IPHONE
+// include SDL for IPHONEOS code
+# include <SDL.h>
+#endif
+
 #include "thread.h"
 
 #include "fs.h"
@@ -588,6 +586,16 @@ static qboolean PK3_GetEndOfCentralDir (const char *packfile, int packhandle, pk
 
        Mem_Free (buffer);
 
+       if (
+                       eocd->cdir_size < 0 || eocd->cdir_size > filesize ||
+                       eocd->cdir_offset < 0 || eocd->cdir_offset >= filesize ||
+                       eocd->cdir_offset + eocd->cdir_size > filesize
+          )
+       {
+               // Obviously invalid central directory.
+               return false;
+       }
+
        return true;
 }
 
@@ -607,7 +615,11 @@ static int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd)
 
        // Load the central directory in memory
        central_dir = (unsigned char *)Mem_Alloc (tempmempool, eocd->cdir_size);
-       lseek (pack->handle, eocd->cdir_offset, SEEK_SET);
+       if (lseek (pack->handle, eocd->cdir_offset, SEEK_SET) == -1)
+       {
+               Mem_Free (central_dir);
+               return -1;
+       }
        if(read (pack->handle, central_dir, eocd->cdir_size) != (fs_offset_t) eocd->cdir_size)
        {
                Mem_Free (central_dir);
@@ -656,7 +668,7 @@ static int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd)
                if ((ptr[8] & 0x21) == 0 && (ptr[38] & 0x18) == 0)
                {
                        // Still enough bytes for the name?
-                       if (remaining < namesize || namesize >= (int)sizeof (*pack->files))
+                       if (namesize < 0 || remaining < namesize || namesize >= (int)sizeof (*pack->files))
                        {
                                Mem_Free (central_dir);
                                return -1;
@@ -799,7 +811,11 @@ static qboolean PK3_GetTrueFileOffset (packfile_t *pfile, pack_t *pack)
                return true;
 
        // Load the local file description
-       lseek (pack->handle, pfile->offset, SEEK_SET);
+       if (lseek (pack->handle, pfile->offset, SEEK_SET) == -1)
+       {
+               Con_Printf ("Can't seek in package %s\n", pack->filename);
+               return false;
+       }
        count = read (pack->handle, buffer, ZIP_LOCAL_CHUNK_BASE_SIZE);
        if (count != ZIP_LOCAL_CHUNK_BASE_SIZE || BuffBigLong (buffer) != ZIP_DATA_HEADER)
        {
@@ -877,6 +893,25 @@ static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack,
 }
 
 
+static void FS_mkdir (const char *path)
+{
+       if(COM_CheckParm("-readonly"))
+               return;
+
+#if WIN32
+       if (_mkdir (path) == -1)
+#else
+       if (mkdir (path, 0777) == -1)
+#endif
+       {
+               // No logging for this. The only caller is FS_CreatePath (which
+               // calls it in ways that will intentionally produce EEXIST),
+               // and its own callers always use the directory afterwards and
+               // thus will detect failure that way.
+       }
+}
+
+
 /*
 ============
 FS_CreatePath
@@ -972,7 +1007,7 @@ static pack_t *FS_LoadPackPAK (const char *packfile)
 
        numpackfiles = header.dirlen / sizeof(dpackfile_t);
 
-       if (numpackfiles > MAX_FILES_IN_PACK)
+       if (numpackfiles < 0 || numpackfiles > MAX_FILES_IN_PACK)
        {
                Con_Printf ("%s has %i files\n", packfile, numpackfiles);
                close(packhandle);
@@ -990,7 +1025,7 @@ static pack_t *FS_LoadPackPAK (const char *packfile)
        }
 
        pack = (pack_t *)Mem_Alloc(fs_mempool, sizeof (pack_t));
-       pack->ignorecase = false; // PAK is case sensitive
+       pack->ignorecase = true; // PAK is sensitive in Quake1 but insensitive in Quake2
        strlcpy (pack->filename, packfile, sizeof (pack->filename));
        pack->handle = packhandle;
        pack->numfiles = 0;
@@ -1002,6 +1037,9 @@ static pack_t *FS_LoadPackPAK (const char *packfile)
                fs_offset_t offset = (unsigned int)LittleLong (info[i].filepos);
                fs_offset_t size = (unsigned int)LittleLong (info[i].filelen);
 
+               // Ensure a zero terminated file name (required by format).
+               info[i].name[sizeof(info[i].name) - 1] = 0;
+
                FS_AddFileToPack (info[i].name, pack, offset, size, size, PACKFILE_FLAG_TRUEOFFS);
        }
 
@@ -1896,7 +1934,7 @@ static int FS_ChooseUserDir(userdirmode_t userdirmode, char *userdir, size_t use
        if(access(va(vabuf, sizeof(vabuf), "%s%s/", userdir, gamedirname1), W_OK | X_OK) >= 0)
                fd = 1;
        else
-               fd = 0;
+               fd = -1;
 #endif
        if(fd >= 0)
        {
@@ -2706,25 +2744,41 @@ Write "datasize" bytes into a file
 */
 fs_offset_t FS_Write (qfile_t* file, const void* data, size_t datasize)
 {
-       fs_offset_t result;
+       fs_offset_t written = 0;
 
        // If necessary, seek to the exact file position we're supposed to be
        if (file->buff_ind != file->buff_len)
-               lseek (file->handle, file->buff_ind - file->buff_len, SEEK_CUR);
+       {
+               if (lseek (file->handle, file->buff_ind - file->buff_len, SEEK_CUR) == -1)
+               {
+                       Con_Printf("WARNING: could not seek in %s.\n");
+               }
+       }
 
        // Purge cached data
        FS_Purge (file);
 
        // Write the buffer and update the position
-       result = write (file->handle, data, (fs_offset_t)datasize);
+       // LordHavoc: to hush a warning about passing size_t to an unsigned int parameter on Win64 we do this as multiple writes if the size would be too big for an integer (we never write that big in one go, but it's a theory)
+       while (written < (fs_offset_t)datasize)
+       {
+               // figure out how much to write in one chunk
+               fs_offset_t maxchunk = 1<<30; // 1 GiB
+               int chunk = (int)min((fs_offset_t)datasize - written, maxchunk);
+               int result = (int)write (file->handle, (const unsigned char *)data + written, chunk);
+               // if at least some was written, add it to our accumulator
+               if (result > 0)
+                       written += result;
+               // if the result is not what we expected, consider the write to be incomplete
+               if (result != chunk)
+                       break;
+       }
        file->position = lseek (file->handle, 0, SEEK_CUR);
        if (file->real_length < file->position)
                file->real_length = file->position;
 
-       if (result < 0)
-               return 0;
-
-       return result;
+       // note that this will never be less than 0 even if the write failed
+       return written;
 }
 
 
@@ -2792,7 +2846,12 @@ fs_offset_t FS_Read (qfile_t* file, void* buffer, size_t buffersize)
                {
                        if (count > (fs_offset_t)buffersize)
                                count = (fs_offset_t)buffersize;
-                       lseek (file->handle, file->offset + file->position, SEEK_SET);
+                       if (lseek (file->handle, file->offset + file->position, SEEK_SET) == -1)
+                       {
+                               // Seek failed. When reading from a pipe, and
+                               // the caller never called FS_Seek, this still
+                               // works fine.  So no reporting this error.
+                       }
                        nb = read (file->handle, &((unsigned char*)buffer)[done], count);
                        if (nb > 0)
                        {
@@ -2807,7 +2866,12 @@ fs_offset_t FS_Read (qfile_t* file, void* buffer, size_t buffersize)
                {
                        if (count > (fs_offset_t)sizeof (file->buff))
                                count = (fs_offset_t)sizeof (file->buff);
-                       lseek (file->handle, file->offset + file->position, SEEK_SET);
+                       if (lseek (file->handle, file->offset + file->position, SEEK_SET) == -1)
+                       {
+                               // Seek failed. When reading from a pipe, and
+                               // the caller never called FS_Seek, this still
+                               // works fine.  So no reporting this error.
+                       }
                        nb = read (file->handle, file->buff, count);
                        if (nb > 0)
                        {
@@ -3080,7 +3144,8 @@ int FS_Seek (qfile_t* file, fs_offset_t offset, int whence)
                ztk->in_len = 0;
                ztk->in_position = 0;
                file->position = 0;
-               lseek (file->handle, file->offset, SEEK_SET);
+               if (lseek (file->handle, file->offset, SEEK_SET) == -1)
+                       Con_Printf("IMPOSSIBLE: couldn't seek in already opened pk3 file.\n");
 
                // Reset the Zlib stream
                ztk->zstream.next_in = ztk->input;
@@ -3372,18 +3437,6 @@ qboolean FS_SysFileExists (const char *path)
        return FS_SysFileType (path) != FS_FILETYPE_NONE;
 }
 
-void FS_mkdir (const char *path)
-{
-       if(COM_CheckParm("-readonly"))
-               return;
-
-#if WIN32
-       _mkdir (path);
-#else
-       mkdir (path, 0777);
-#endif
-}
-
 /*
 ===========
 FS_Search
@@ -3831,7 +3884,7 @@ unsigned char *FS_Deflate(const unsigned char *data, size_t size, size_t *deflat
        }
 
        strm.next_in = (unsigned char*)data;
-       strm.avail_in = size;
+       strm.avail_in = (unsigned int)size;
 
        tmp = (unsigned char *) Mem_Alloc(tempmempool, size);
        if(!tmp)
@@ -3842,7 +3895,7 @@ unsigned char *FS_Deflate(const unsigned char *data, size_t size, size_t *deflat
        }
 
        strm.next_out = tmp;
-       strm.avail_out = size;
+       strm.avail_out = (unsigned int)size;
 
        if(qz_deflate(&strm, Z_FINISH) != Z_STREAM_END)
        {
@@ -3932,7 +3985,7 @@ unsigned char *FS_Inflate(const unsigned char *data, size_t size, size_t *inflat
        }
 
        strm.next_in = (unsigned char*)data;
-       strm.avail_in = size;
+       strm.avail_in = (unsigned int)size;
 
        do
        {