/* <2af4b> ../engine/hashpak.c:1678 */ void HPAK_CheckSize(char *pakname) { char fullname[MAX_PATH]; float maxSize; float actualSize; FileHandle_t hfile; maxSize = hpk_maxsize.value; if (!maxSize || pakname == NULL) return; if (maxSize < 0.0f) { Con_Printf("hpk_maxsize < 0, setting to 0\n"); Cvar_DirectSet(&hpk_maxsize, "0"); return; } Q_snprintf(fullname, ARRAYSIZE(fullname), "%s", pakname); #ifdef REHLDS_FIXES fullname[ARRAYSIZE(fullname) - 1] = 0; #endif // REHLDS_FIXES COM_DefaultExtension(fullname, HASHPAK_EXTENSION); COM_FixSlashes(fullname); actualSize = 0.0f; maxSize *= 1000000.0f; hfile = FS_Open(fullname, "rb"); if (hfile) { actualSize = (float)FS_Size(hfile); FS_Close(hfile); } if (actualSize >= maxSize) { Con_Printf("Server: Size of %s > %f MB, deleting.\n", fullname, hpk_maxsize.value); Log_Printf("Server: Size of %s > %f MB, deleting.\n", fullname, hpk_maxsize.value); FS_RemoveFile(fullname, 0); } }
/* <5e43> ../engine/cmd.c:347 */ void Cmd_Exec_f(void) { const char *pszFileName; const char *pszFileExt; char *pszFileData; int nAddLen; FileHandle_t hFile; if (Cmd_Argc() != 2) { Con_Printf("exec <filename> : execute a script file\n"); return; } pszFileName = Cmd_Argv(1); if (!pszFileName || pszFileName[0] == 0) { return; } if (Q_strstr(pszFileName, "\\") || Q_strstr(pszFileName, ":") || Q_strstr(pszFileName, "~") || Q_strstr(pszFileName, "..") || *pszFileName == '/') { Con_Printf("exec %s: invalid path.\n", pszFileName); return; } pszFileExt = COM_FileExtension((char *)pszFileName); if (Q_stricmp(pszFileExt, "cfg") && Q_stricmp(pszFileExt, "rc")) { Con_Printf("exec %s: not a .cfg or .rc file\n", pszFileName); return; } hFile = FS_OpenPathID(pszFileName, "rb", "GAMECONFIG"); if (!hFile) { hFile = FS_OpenPathID(pszFileName, "rb", "GAME"); } if (!hFile) { hFile = FS_Open(pszFileName, "rb"); } if (!hFile) { if (!Q_strstr(pszFileName, "autoexec.cfg") && !Q_strstr(pszFileName, "userconfig.cfg") && !Q_strstr(pszFileName, "hw/opengl.cfg") && !Q_strstr(pszFileName, "joystick.cfg") && !Q_strstr(pszFileName, "game.cfg")) { Con_Printf("couldn't exec %s\n", pszFileName); } return; } nAddLen = FS_Size(hFile); pszFileData = (char *)Mem_Malloc(nAddLen + 1); if (!pszFileData) { Con_Printf("exec: not enough space for %s", pszFileName); FS_Close(hFile); return; } FS_Read(pszFileData, nAddLen, 1, hFile); pszFileData[nAddLen] = 0; FS_Close(hFile); Con_DPrintf("execing %s\n", pszFileName); if (cmd_text.cursize + nAddLen + 2 < cmd_text.maxsize) { Cbuf_InsertTextLines(pszFileData); } else { char *pszDataPtr = pszFileData; while (true) { Cbuf_Execute(); // TODO: This doesn't obey the rule to first execute commands from the file, and then the others in the buffer pszDataPtr = COM_ParseLine(pszDataPtr); if (com_token[0] == 0) { break; } Cbuf_InsertTextLines(com_token); } } Mem_Free(pszFileData); }
/* <2a494> ../engine/hashpak.c:322 */ void HPAK_AddLump(qboolean bUseQueue, char *pakname, struct resource_s *pResource, void *pData, FileHandle_t fpSource) { FileHandle_t iRead; FileHandle_t iWrite; char name[MAX_PATH]; char szTempName[MAX_PATH]; char szOriginalName[MAX_PATH]; hash_pack_directory_t olddirectory; hash_pack_directory_t newdirectory; hash_pack_entry_t *pNewEntry; byte md5[16]; MD5Context_t ctx; byte *pDiskData; if (pakname == NULL) { Con_Printf("HPAK_AddLump called with invalid arguments: no .pak filename\n"); return; } if (!pResource) { Con_Printf("HPAK_AddLump called with invalid arguments: no lump to add\n"); return; } if (!pData && !fpSource) { Con_Printf("HPAK_AddLump called with invalid arguments: no file handle\n"); return; } if (pResource->nDownloadSize < 1024 || (unsigned int)pResource->nDownloadSize > MAX_FILE_SIZE) { Con_Printf("HPAK_AddLump called with bogus lump, size: %i\n", pResource->nDownloadSize); return; } Q_memset(&ctx, 0, sizeof(MD5Context_t)); MD5Init(&ctx); if (pData) MD5Update(&ctx, (byte *)pData, pResource->nDownloadSize); else { pDiskData = (byte *)Mem_Malloc(pResource->nDownloadSize + 1); Q_memset(pDiskData, 0, pResource->nDownloadSize); FS_Read(pDiskData, pResource->nDownloadSize, 1, fpSource); FS_Seek(fpSource, FS_Tell(fpSource), FILESYSTEM_SEEK_HEAD); MD5Update(&ctx, pDiskData, pResource->nDownloadSize); Mem_Free(pDiskData); } MD5Final(md5, &ctx); if (Q_memcmp(pResource->rgucMD5_hash, md5, sizeof(md5)) != 0) { Con_Printf("HPAK_AddLump called with bogus lump, md5 mismatch\n"); Con_Printf("Purported: %s\n", MD5_Print(pResource->rgucMD5_hash)); Con_Printf("Actual : %s\n", MD5_Print(md5)); Con_Printf("Ignoring lump addition\n"); return; } if (bUseQueue) { HPAK_AddToQueue(pakname, pResource, pData, fpSource); return; } Q_snprintf(name, ARRAYSIZE(name), "%s", pakname); #ifdef REHLDS_FIXES name[ARRAYSIZE(name) - 1] = 0; #endif // REHLDS_FIXES COM_DefaultExtension(name, HASHPAK_EXTENSION); COM_FixSlashes(name); Q_strncpy(szOriginalName, name, ARRAYSIZE(szOriginalName) - 1); szOriginalName[ARRAYSIZE(szOriginalName) - 1] = 0; iRead = FS_Open(name, "rb"); if (!iRead) { HPAK_CreatePak(pakname, pResource, pData, fpSource); return; } COM_StripExtension(name, szTempName); COM_DefaultExtension(szTempName, ".hp2"); iWrite = FS_Open(szTempName, "w+b"); if (!iWrite) { FS_Close(iRead); Con_Printf("ERROR: couldn't open %s.\n", szTempName); return; } FS_Read(&hash_pack_header, sizeof(hash_pack_header_t), 1, iRead); if (hash_pack_header.version != HASHPAK_VERSION) { FS_Close(iRead); FS_Close(iWrite); FS_Unlink(szTempName); Con_Printf("Invalid .hpk version in HPAK_AddLump\n"); return; } FS_Seek(iRead, 0, FILESYSTEM_SEEK_HEAD); COM_CopyFileChunk(iWrite, iRead, FS_Size(iRead)); FS_Seek(iRead, hash_pack_header.nDirectoryOffset, FILESYSTEM_SEEK_HEAD); FS_Read(&olddirectory.nEntries, 4, 1, iRead); if (olddirectory.nEntries < 1 || (unsigned int)olddirectory.nEntries > MAX_FILE_ENTRIES) { FS_Close(iRead); FS_Close(iWrite); FS_Unlink(szTempName); Con_Printf("ERROR: .hpk had bogus # of directory entries: %i\n", olddirectory.nEntries); return; } olddirectory.p_rgEntries = (hash_pack_entry_t *)Mem_Malloc(sizeof(hash_pack_entry_t) * olddirectory.nEntries); FS_Read(olddirectory.p_rgEntries, sizeof(hash_pack_entry_t) * olddirectory.nEntries, 1, iRead); FS_Close(iRead); if (HPAK_FindResource(&olddirectory, pResource->rgucMD5_hash, NULL) != FALSE) { FS_Close(iWrite); FS_Unlink(szTempName); Mem_Free(olddirectory.p_rgEntries); return; } newdirectory.nEntries = olddirectory.nEntries + 1; newdirectory.p_rgEntries = (hash_pack_entry_t *)Mem_Malloc(sizeof(hash_pack_entry_t) * newdirectory.nEntries); Q_memset(newdirectory.p_rgEntries, 0, sizeof(hash_pack_entry_t) * newdirectory.nEntries); Q_memcpy(newdirectory.p_rgEntries, olddirectory.p_rgEntries, sizeof(hash_pack_entry_t) * olddirectory.nEntries); pNewEntry = NULL; for (int i = 0; i < olddirectory.nEntries; i++) { if (Q_memcmp(pResource->rgucMD5_hash, olddirectory.p_rgEntries[i].resource.rgucMD5_hash, 16) >= 0) { pNewEntry = &newdirectory.p_rgEntries[i]; #ifndef REHLDS_FIXES while (i < olddirectory.nEntries) { Q_memcpy(&newdirectory.p_rgEntries[i + 1], &olddirectory.p_rgEntries[i], sizeof(hash_pack_entry_t)); i++; } #else Q_memcpy(&newdirectory.p_rgEntries[i + 1], &olddirectory.p_rgEntries[i], (olddirectory.nEntries - i) * sizeof(hash_pack_entry_t)); #endif break; } } if (pNewEntry == NULL) { pNewEntry = &newdirectory.p_rgEntries[newdirectory.nEntries - 1]; } Q_memset(pNewEntry, 0, sizeof(hash_pack_entry_t)); FS_Seek(iWrite, hash_pack_header.nDirectoryOffset, FILESYSTEM_SEEK_HEAD); Q_memcpy(&pNewEntry->resource, pResource, sizeof(resource_t)); pNewEntry->nOffset = FS_Tell(iWrite); pNewEntry->nFileLength = pResource->nDownloadSize; if (pData) FS_Write(pData, pResource->nDownloadSize, 1, iWrite); else COM_CopyFileChunk(iWrite, fpSource, pResource->nDownloadSize); hash_pack_header.nDirectoryOffset = FS_Tell(iWrite); FS_Write(&newdirectory.nEntries, 4, 1, iWrite); for (int j = 0; j < newdirectory.nEntries; j++) FS_Write(&newdirectory.p_rgEntries[j], sizeof(hash_pack_entry_t), 1, iWrite); if (newdirectory.p_rgEntries) Mem_Free(newdirectory.p_rgEntries); if (olddirectory.p_rgEntries) Mem_Free(olddirectory.p_rgEntries); FS_Seek(iWrite, 0, FILESYSTEM_SEEK_HEAD); FS_Write(&hash_pack_header, sizeof(hash_pack_header_t), 1, iWrite); FS_Close(iWrite); FS_Unlink(szOriginalName); FS_Rename(szTempName, szOriginalName); }
int Netchan_CreateFileFragments_(qboolean server, netchan_t *chan, const char *filename) #endif // REHLDS_FIXES { int chunksize; int compressedFileTime; FileHandle_t hfile; signed int filesize; int remaining; fragbufwaiting_t *p; int send; fragbuf_t *buf; char compressedfilename[MAX_PATH]; qboolean firstfragment; int bufferid; qboolean bCompressed; int pos; fragbufwaiting_t *wait; int uncompressed_size; bufferid = 1; firstfragment = TRUE; bCompressed = FALSE; chunksize = chan->pfnNetchan_Blocksize(chan->connection_status); Q_snprintf(compressedfilename, sizeof compressedfilename, "%s.ztmp", filename); compressedFileTime = FS_GetFileTime(compressedfilename); if (compressedFileTime >= FS_GetFileTime(filename) && (hfile = FS_Open(compressedfilename, "rb"))) { filesize = FS_Size(hfile); FS_Close(hfile); bCompressed = TRUE; hfile = FS_Open(filename, "rb"); if (!hfile) { Con_Printf("Warning: Unable to open %s for transfer\n", filename); return 0; } uncompressed_size = FS_Size(hfile); if (uncompressed_size > sv_filetransfermaxsize.value) { FS_Close(hfile); Con_Printf("Warning: File %s is too big to transfer from host %s\n", filename, NET_AdrToString(chan->remote_address)); return 0; } } else { hfile = FS_Open(filename, "rb"); if (!hfile) { Con_Printf("Warning: Unable to open %s for transfer\n", filename); return 0; } filesize = FS_Size(hfile); if (filesize > sv_filetransfermaxsize.value) { FS_Close(hfile); Con_Printf("Warning: File %s is too big to transfer from host %s\n", filename, NET_AdrToString(chan->remote_address)); return 0; } uncompressed_size = filesize; if (sv_filetransfercompression.value != 0.0) { unsigned char* uncompressed = (unsigned char*)Mem_Malloc(filesize); unsigned char* compressed = (unsigned char*)Mem_Malloc(filesize); unsigned int compressedSize = filesize; FS_Read(uncompressed, filesize, 1, hfile); if (BZ_OK == BZ2_bzBuffToBuffCompress((char*)compressed, &compressedSize, (char*)uncompressed, filesize, 9, 0, 30)) { FileHandle_t destFile = FS_Open(compressedfilename, "wb"); if (destFile) { Con_DPrintf("Creating compressed version of file %s (%d -> %d)\n", filename, filesize, compressedSize); FS_Write(compressed, compressedSize, 1, destFile); FS_Close(destFile); filesize = compressedSize; bCompressed = TRUE; } } Mem_Free(uncompressed); Mem_Free(compressed); } } FS_Close(hfile); wait = (fragbufwaiting_t *)Mem_ZeroMalloc(0xCu); remaining = filesize; pos = 0; while (remaining) { send = min(chunksize, remaining); buf = Netchan_AllocFragbuf(); if (!buf) { Con_Printf("Couldn't allocate fragbuf_t\n"); Mem_Free(wait); if (server) { #ifdef REHLDS_FIXES SV_DropClient(&g_psvs.clients[chan->player_slot - 1], 0, "Malloc problem"); #else // REHLDS_FIXES SV_DropClient(host_client, 0, "Malloc problem"); #endif // REHLDS_FIXES return 0; } else { rehlds_syserror("%s: Reverse clientside code", __func__); //return 0; } } buf->bufferid = bufferid++; SZ_Clear(&buf->frag_message); if (firstfragment) { firstfragment = FALSE; MSG_WriteString(&buf->frag_message, filename); MSG_WriteString(&buf->frag_message, bCompressed ? "bz2" : "uncompressed"); MSG_WriteLong(&buf->frag_message, uncompressed_size); send -= buf->frag_message.cursize; } buf->isfile = TRUE; buf->iscompressed = bCompressed; buf->size = send; buf->foffset = pos; Q_strncpy(buf->filename, filename, MAX_PATH - 1); buf->filename[MAX_PATH - 1] = 0; pos += send; remaining -= send; Netchan_AddFragbufToTail(wait, buf); } if (!chan->waitlist[FRAG_FILE_STREAM]) { chan->waitlist[FRAG_FILE_STREAM] = wait; } else { p = chan->waitlist[FRAG_FILE_STREAM]; while (p->next) p = p->next; p->next = wait; } return 1; }
/* DESCRIPTION: COM_LoadFile // LOCATION: SDK // PATH: Theoretically anywhere, since it's in the SDK. // // The args are known, the function cannot be altered. // LoadFileForMe is a wrapper for COM_LoadFile, which is ALSO // in the SDK. // // pLength can be null, for some reason (backwards compat?). // What 'usehunk' does is tell the function HOW to load the file; // I think the functions below better illustrate the types. */ HLDS_DLLEXPORT byte * COM_LoadFile(const char *path, int usehunk, int *pLength) { //pLength is a variable passed by reference we are suppossed to put //the size of our loaded file in. It is optional though. hl_file_t *file; byte *FileData = NULL; //what we end up returning const char *FileName; int len; file = FS_Open(path, "rb"); if(file == NULL) { //No file. How sad. if(pLength != NULL) { *pLength = 0; } return(NULL); } len = FS_Size(file); switch(usehunk) { case 0: //0 must be small text files, but I'm not sure it's used FileData = (byte *)Z_Malloc(len+1); break; case 1: //1 must be regular hunk FileName = strrchr(path, '/'); if(FileName == NULL) { FileName = path; } else { FileName++; } //worst case oddities, an empty string, shouldn't hurt. FileData = (byte *)Hunk_AllocName(len+1, FileName); break; case 2: //2 must be temporary file allocation FileData = (byte *)Hunk_TempAlloc(len+1); break; case 3: //3 must be caching. I still don't quite understand how that works. FileName = strrchr(path, '/'); if(FileName == NULL) { FileName = path; } else { FileName++; } FileData = (byte *)Cache_Alloc(loadcache, len+1, FileName); //loadcache = global break; case 4: //Similar to case 2. Temp allocation, or allocation to a temporary file pointer. if (len+1 > loadsize) { FileData = (byte *)Hunk_TempAlloc(len+1); } else { FileData = loadbuf; } break; case 5: //And 5 is mallocing the memory. But how is it freed? FileData = (byte *)Q_Malloc(len+1); //Freeing relies on the user. CHECK_MEMORY_MALLOC(FileData); //printf("%s: Allocating file %s (%u)\n", __FUNCTION__, path, len+1); break; //tempallocmore--case 6--doesn't exist in HL default: Sys_Error ("COM_LoadFile: \"usehunk\" is suppossed to be between 0 and 5. Fix it, modder.\n"); } if(FileData == NULL) { Sys_Error("COM_LoadFile: Couldn't load \"%s\" for some memory related reason.\n", path); FS_Close(file); //since sys_error kills us, why close? } //whoawhoawhoa, tacking on a null? I spy a pretty nasty off by one error... //And now len has been +1'd, fixing it. FS_Read(FileData, len, 1, file); FileData[len] = '\0'; FS_Close(file); if(pLength != NULL) { *pLength = len; } return(FileData); }