Quake II RTX doxygen  1.0 dev
files.c File Reference
#include "shared/shared.h"
#include "shared/list.h"
#include "common/common.h"
#include "common/cvar.h"
#include "common/error.h"
#include "common/files.h"
#include "common/prompt.h"
#include "system/system.h"
#include "client/client.h"
#include "format/pak.h"
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

Go to the source code of this file.

Classes

struct  packfile_s
 
struct  pack_t
 
struct  searchpath_s
 
struct  file_t
 
struct  symlink_t
 

Macros

#define MAX_FILE_HANDLES   32
 
#define FS_DPrintf(...)
 
#define PATH_NOT_CHECKED   -1
 
#define FOR_EACH_SYMLINK(link, list)   LIST_FOR_EACH(symlink_t, link, list, entry)
 
#define FOR_EACH_SYMLINK_SAFE(link, next, list)   LIST_FOR_EACH_SAFE(symlink_t, link, next, list, entry)
 
#define FS_COUNT_READ   (void)0
 
#define FS_COUNT_OPEN   (void)0
 
#define FS_COUNT_STRCMP   (void)0
 
#define FS_COUNT_STRLWR   (void)0
 
#define FS_ERR_READ(fp)   (ferror(fp) ? Q_Errno() : Q_ERR_UNEXPECTED_EOF)
 
#define FS_ERR_WRITE(fp)   (ferror(fp) ? Q_Errno() : Q_ERR_FAILURE)
 
#define PAK_EXT   ".pak"
 

Typedefs

typedef struct packfile_s packfile_t
 
typedef struct searchpath_s searchpath_t
 

Enumerations

enum  filetype_t { FS_FREE, FS_REAL, FS_PAK, FS_BAD }
 

Functions

static pack_tpack_get (pack_t *pack)
 
static void pack_put (pack_t *pack)
 
char * FS_ReplaceSeparators (char *s, int separator)
 
static qboolean validate_char (int c)
 
int FS_ValidatePath (const char *s)
 
void FS_SanitizeFilenameVariable (cvar_t *var)
 
size_t FS_NormalizePath (char *out, const char *in)
 
size_t FS_NormalizePathBuffer (char *out, const char *in, size_t size)
 
static file_talloc_handle (qhandle_t *f)
 
static file_tfile_for_handle (qhandle_t f)
 
static void cleanup_path (char *s)
 
static symlink_texpand_links (list_t *list, char *buffer, size_t *len_p)
 
ssize_t FS_Length (qhandle_t f)
 
ssize_t FS_Tell (qhandle_t f)
 
static qerror_t seek_pak_file (file_t *file, off_t offset)
 
qerror_t FS_Seek (qhandle_t f, off_t offset)
 
qerror_t FS_CreatePath (char *path)
 
qerror_t FS_FilterFile (qhandle_t f)
 
void FS_FCloseFile (qhandle_t f)
 
static qerror_t get_path_info (const char *path, file_info_t *info)
 
static qerror_t get_fp_info (FILE *fp, file_info_t *info)
 
static FILE * fopen_hack (const char *path, const char *mode)
 
static ssize_t open_file_write (file_t *file, const char *name)
 
static ssize_t open_from_pak (file_t *file, pack_t *pack, packfile_t *entry, qboolean unique)
 
static ssize_t open_from_disk (file_t *file, const char *fullpath)
 
qerror_t FS_LastModified (char const *file, uint64_t *last_modified)
 
static ssize_t open_file_read (file_t *file, const char *normalized, size_t namelen, qboolean unique)
 
static ssize_t expand_open_file_read (file_t *file, const char *name, qboolean unique)
 
static ssize_t read_pak_file (file_t *file, void *buf, size_t len)
 
static ssize_t read_phys_file (file_t *file, void *buf, size_t len)
 
ssize_t FS_Read (void *buf, size_t len, qhandle_t f)
 
ssize_t FS_ReadLine (qhandle_t f, char *buffer, size_t size)
 
void FS_Flush (qhandle_t f)
 
ssize_t FS_Write (const void *buf, size_t len, qhandle_t f)
 
ssize_t FS_FOpenFile (const char *name, qhandle_t *f, unsigned mode)
 
static qhandle_t easy_open_read (char *buf, size_t size, unsigned mode, const char *dir, const char *name, const char *ext)
 
static qhandle_t easy_open_write (char *buf, size_t size, unsigned mode, const char *dir, const char *name, const char *ext)
 
qhandle_t FS_EasyOpenFile (char *buf, size_t size, unsigned mode, const char *dir, const char *name, const char *ext)
 
ssize_t FS_LoadFileEx (const char *path, void **buffer, unsigned flags, memtag_t tag)
 
qerror_t FS_WriteFile (const char *path, const void *data, size_t len)
 
qboolean FS_EasyWriteFile (char *buf, size_t size, unsigned mode, const char *dir, const char *name, const char *ext, const void *data, size_t len)
 
ssize_t FS_FPrintf (qhandle_t f, const char *format,...)
 
static pack_tpack_alloc (FILE *fp, filetype_t type, const char *name, unsigned num_files, size_t names_len)
 
static void pack_hash_file (pack_t *pack, packfile_t *file)
 
static pack_tload_pak_file (const char *packfile)
 
static int pakcmp (const void *p1, const void *p2)
 
static void q_printf (2, 3)
 
file_info_t * FS_CopyInfo (const char *name, size_t size, time_t ctime, time_t mtime)
 
void ** FS_CopyList (void **list, int count)
 
qboolean FS_WildCmp (const char *filter, const char *string)
 
qboolean FS_ExtCmp (const char *ext, const char *name)
 
static int infocmp (const void *p1, const void *p2)
 
static int alphacmp (const void *p1, const void *p2)
 
void ** FS_ListFiles (const char *path, const char *filter, unsigned flags, int *count_p)
 
void FS_FreeList (void **list)
 
void FS_File_g (const char *path, const char *ext, unsigned flags, genctx_t *ctx)
 
static void print_file_list (const char *path, const char *ext, unsigned flags)
 
static void FS_FDir_f (void)
 
static void FS_Dir_f (void)
 
static void FS_WhereIs_f (void)
 
static void FS_Path_f (void)
 
static void FS_Link_g (genctx_t *ctx)
 
static void FS_Link_c (genctx_t *ctx, int argnum)
 
static void free_all_links (list_t *list)
 
static void FS_UnLink_f (void)
 
static void FS_Link_f (void)
 
static void free_search_path (searchpath_t *path)
 
static void free_all_paths (void)
 
static void free_game_paths (void)
 
static void setup_base_paths (void)
 
static void setup_game_paths (void)
 
void FS_Restart (qboolean total)
 
static void FS_Restart_f (void)
 
void FS_Shutdown (void)
 
static void fs_game_changed (cvar_t *self)
 
void FS_Init (void)
 

Variables

char fs_gamedir [MAX_OSPATH]
 
static searchpath_tfs_searchpaths
 
static searchpath_tfs_base_searchpaths
 
static list_t fs_hard_links
 
static list_t fs_soft_links
 
static file_t fs_files [MAX_FILE_HANDLES]
 
cvar_t * fs_game
 
cvar_t * fs_shareware
 
static const cmdreg_t c_fs []
 

Macro Definition Documentation

◆ FOR_EACH_SYMLINK

#define FOR_EACH_SYMLINK (   link,
  list 
)    LIST_FOR_EACH(symlink_t, link, list, entry)

Definition at line 85 of file files.c.

◆ FOR_EACH_SYMLINK_SAFE

#define FOR_EACH_SYMLINK_SAFE (   link,
  next,
  list 
)    LIST_FOR_EACH_SAFE(symlink_t, link, next, list, entry)

Definition at line 88 of file files.c.

◆ FS_COUNT_OPEN

#define FS_COUNT_OPEN   (void)0

Definition at line 193 of file files.c.

◆ FS_COUNT_READ

#define FS_COUNT_READ   (void)0

Definition at line 192 of file files.c.

◆ FS_COUNT_STRCMP

#define FS_COUNT_STRCMP   (void)0

Definition at line 194 of file files.c.

◆ FS_COUNT_STRLWR

#define FS_COUNT_STRLWR   (void)0

Definition at line 195 of file files.c.

◆ FS_DPrintf

#define FS_DPrintf (   ...)

Definition at line 80 of file files.c.

◆ FS_ERR_READ

#define FS_ERR_READ (   fp)    (ferror(fp) ? Q_Errno() : Q_ERR_UNEXPECTED_EOF)

Definition at line 648 of file files.c.

◆ FS_ERR_WRITE

#define FS_ERR_WRITE (   fp)    (ferror(fp) ? Q_Errno() : Q_ERR_FAILURE)

Definition at line 650 of file files.c.

◆ MAX_FILE_HANDLES

#define MAX_FILE_HANDLES   32

Definition at line 59 of file files.c.

◆ PAK_EXT

#define PAK_EXT   ".pak"

◆ PATH_NOT_CHECKED

#define PATH_NOT_CHECKED   -1

Definition at line 83 of file files.c.

Typedef Documentation

◆ packfile_t

typedef struct packfile_s packfile_t

◆ searchpath_t

typedef struct searchpath_s searchpath_t

Enumeration Type Documentation

◆ filetype_t

enum filetype_t
Enumerator
FS_FREE 
FS_REAL 
FS_PAK 
FS_BAD 

Definition at line 95 of file files.c.

95  {
96  FS_FREE,
97  FS_REAL,
98  FS_PAK,
99 #if USE_ZLIB
100  FS_ZIP,
101  FS_GZ,
102 #endif
103  FS_BAD
104 } filetype_t;

Function Documentation

◆ alloc_handle()

static file_t* alloc_handle ( qhandle_t *  f)
static

Definition at line 415 of file files.c.

416 {
417  file_t *file;
418  int i;
419 
420  for (i = 0, file = fs_files; i < MAX_FILE_HANDLES; i++, file++) {
421  if (file->type == FS_FREE) {
422  *f = i + 1;
423  return file;
424  }
425  }
426 
427  return NULL;
428 }

Referenced by FS_FOpenFile(), and FS_LoadFileEx().

◆ alphacmp()

static int alphacmp ( const void p1,
const void p2 
)
static

Definition at line 2703 of file files.c.

2704 {
2705  char *s1 = *(char **)p1;
2706  char *s2 = *(char **)p2;
2707 
2708  return FS_pathcmp(s1, s2);
2709 }

Referenced by FS_ListFiles(), and pakcmp().

◆ cleanup_path()

static void cleanup_path ( char *  s)
static

Definition at line 447 of file files.c.

448 {
449  for (; *s; s++) {
450  if (!validate_char(*s))
451  *s = '_';
452  }
453 }

Referenced by easy_open_write().

◆ easy_open_read()

static qhandle_t easy_open_read ( char *  buf,
size_t  size,
unsigned  mode,
const char *  dir,
const char *  name,
const char *  ext 
)
static

Definition at line 1730 of file files.c.

1732 {
1733  ssize_t len;
1734  qhandle_t f;
1735 
1736  if (*name == '/') {
1737  // full path is given, ignore directory and extension
1738  len = Q_strlcpy(buf, name + 1, size);
1739  } else {
1740  // first try without extension
1741  len = Q_concat(buf, size, dir, name, NULL);
1742  if (len >= size) {
1743  Q_PrintError("open", Q_ERR_NAMETOOLONG);
1744  return 0;
1745  }
1746 
1747  // print normalized path in case of error
1748  FS_NormalizePath(buf, buf);
1749 
1750  len = FS_FOpenFile(buf, &f, mode);
1751  if (f) {
1752  return f; // succeeded
1753  }
1754  if (len != Q_ERR_NOENT) {
1755  goto fail; // fatal error
1756  }
1757  if (!COM_CompareExtension(buf, ext)) {
1758  goto fail; // name already has the extension
1759  }
1760 
1761  // now try to append extension
1762  len = Q_strlcat(buf, ext, size);
1763  }
1764 
1765  if (len >= size) {
1766  Q_PrintError("open", Q_ERR_NAMETOOLONG);
1767  return 0;
1768  }
1769 
1770  len = FS_FOpenFile(buf, &f, mode);
1771  if (f) {
1772  return f;
1773  }
1774 
1775 fail:
1776  Com_Printf("Couldn't open %s: %s\n", buf, Q_ErrorString(len));
1777  return 0;
1778 }

Referenced by FS_EasyOpenFile().

◆ easy_open_write()

static qhandle_t easy_open_write ( char *  buf,
size_t  size,
unsigned  mode,
const char *  dir,
const char *  name,
const char *  ext 
)
static

Definition at line 1781 of file files.c.

1783 {
1784  char normalized[MAX_OSPATH];
1785  ssize_t len;
1786  qhandle_t f;
1787 
1788  // make it impossible to escape the destination directory when writing files
1789  len = FS_NormalizePathBuffer(normalized, name, sizeof(normalized));
1790  if (len >= sizeof(normalized)) {
1791  Q_PrintError("open", Q_ERR_NAMETOOLONG);
1792  return 0;
1793  }
1794 
1795  // reject empty filenames
1796  if (len == 0) {
1797  Q_PrintError("open", Q_ERR_NAMETOOSHORT);
1798  return 0;
1799  }
1800 
1801  // replace any bad characters with underscores to make automatic commands happy
1802  cleanup_path(normalized);
1803 
1804  // don't append the extension if name already has it
1805  if (!COM_CompareExtension(normalized, ext)) {
1806  ext = (mode & FS_FLAG_GZIP) ? "" : NULL;
1807  }
1808 
1809  len = Q_concat(buf, size, dir, normalized, ext,
1810  (mode & FS_FLAG_GZIP) ? ".gz" : NULL, NULL);
1811  if (len >= size) {
1812  Q_PrintError("open", Q_ERR_NAMETOOLONG);
1813  return 0;
1814  }
1815 
1816  len = FS_FOpenFile(buf, &f, mode);
1817  if (!f) {
1818  goto fail1;
1819  }
1820 
1821  if (mode & FS_FLAG_GZIP) {
1822  len = FS_FilterFile(f);
1823  if (len) {
1824  goto fail2;
1825  }
1826  }
1827 
1828  return f;
1829 
1830 fail2:
1831  FS_FCloseFile(f);
1832 fail1:
1833  Com_EPrintf("Couldn't open %s: %s\n", buf, Q_ErrorString(len));
1834  return 0;
1835 }

Referenced by FS_EasyOpenFile(), and FS_EasyWriteFile().

◆ expand_links()

static symlink_t* expand_links ( list_t *  list,
char *  buffer,
size_t *  len_p 
)
static

Definition at line 456 of file files.c.

457 {
458  symlink_t *link;
459  size_t namelen = *len_p;
460 
461  FOR_EACH_SYMLINK(link, list) {
462  if (link->namelen > namelen) {
463  continue;
464  }
465  if (!FS_pathcmpn(buffer, link->name, link->namelen)) {
466  size_t newlen = namelen - link->namelen + link->targlen;
467 
468  if (newlen < MAX_OSPATH) {
469  memmove(buffer + link->targlen, buffer + link->namelen,
470  namelen - link->namelen + 1);
471  memcpy(buffer, link->target, link->targlen);
472  }
473 
474  *len_p = newlen;
475  return link;
476  }
477  }
478 
479  return NULL;
480 }

Referenced by expand_open_file_read(), and FS_WhereIs_f().

◆ expand_open_file_read()

static ssize_t expand_open_file_read ( file_t file,
const char *  name,
qboolean  unique 
)
static

Definition at line 1468 of file files.c.

1469 {
1470  char normalized[MAX_OSPATH];
1471  ssize_t ret;
1472  size_t namelen;
1473 
1474 // normalize path
1475  namelen = FS_NormalizePathBuffer(normalized, name, MAX_OSPATH);
1476  if (namelen >= MAX_OSPATH) {
1477  return Q_ERR_NAMETOOLONG;
1478  }
1479 
1480 // expand hard symlinks
1481  if (expand_links(&fs_hard_links, normalized, &namelen) && namelen >= MAX_OSPATH) {
1482  return Q_ERR_NAMETOOLONG;
1483  }
1484 
1485 // reject empty paths
1486  if (namelen == 0) {
1487  return Q_ERR_NAMETOOSHORT;
1488  }
1489 
1490  ret = open_file_read(file, normalized, namelen, unique);
1491  if (ret == Q_ERR_NOENT) {
1492 // expand soft symlinks
1493  if (expand_links(&fs_soft_links, normalized, &namelen)) {
1494  if (namelen >= MAX_OSPATH) {
1495  return Q_ERR_NAMETOOLONG;
1496  }
1497  ret = open_file_read(file, normalized, namelen, unique);
1498  }
1499  }
1500 
1501  return ret;
1502 }

Referenced by FS_FOpenFile(), and FS_LoadFileEx().

◆ file_for_handle()

static file_t* file_for_handle ( qhandle_t  f)
static

Definition at line 430 of file files.c.

431 {
432  file_t *file;
433 
434  if (f < 1 || f > MAX_FILE_HANDLES)
435  return NULL;
436 
437  file = &fs_files[f - 1];
438  if (file->type == FS_FREE)
439  return NULL;
440 
441  if (file->type < FS_FREE || file->type >= FS_BAD)
442  Com_Error(ERR_FATAL, "%s: bad file type", __func__);
443 
444  return file;
445 }

Referenced by FS_FCloseFile(), FS_FilterFile(), FS_Flush(), FS_Length(), FS_Read(), FS_ReadLine(), FS_Seek(), FS_Tell(), and FS_Write().

◆ fopen_hack()

static FILE* fopen_hack ( const char *  path,
const char *  mode 
)
inlinestatic

Definition at line 844 of file files.c.

845 {
846 #ifndef _GNU_SOURCE
847  if (mode[0] == 'w' && mode[1] == 'x') {
848 #ifdef _WIN32
849  int flags = _O_WRONLY | _O_CREAT | _O_EXCL | _S_IREAD | _S_IWRITE;
850  int fd;
851  FILE *fp;
852 
853  if (mode[2] == 'b')
854  flags |= _O_BINARY;
855 
856  fd = _open(path, flags);
857  if (fd == -1)
858  return NULL;
859 
860  fp = _fdopen(fd, (flags & _O_BINARY) ? "wb" : "w");
861  if (fp == NULL)
862  _close(fd);
863 
864  return fp;
865 #else
866  int flags = O_WRONLY | O_CREAT | O_EXCL;
867  int perm = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
868  int fd;
869  FILE *fp;
870 
871  fd = open(path, flags, perm);
872  if (fd == -1)
873  return NULL;
874 
875  fp = fdopen(fd, "wb");
876  if (fp == NULL)
877  close(fd);
878 
879  return fp;
880 #endif
881  }
882 #endif // _GNU_SOURCE
883 
884  return fopen(path, mode);
885 }

Referenced by open_file_write().

◆ free_all_links()

static void free_all_links ( list_t *  list)
static

Definition at line 3339 of file files.c.

3340 {
3341  symlink_t *link, *next;
3342 
3343  FOR_EACH_SYMLINK_SAFE(link, next, list) {
3344  Z_Free(link->target);
3345  Z_Free(link);
3346  }
3347 
3348  List_Init(list);
3349 }

Referenced by FS_Shutdown(), and FS_UnLink_f().

◆ free_all_paths()

static void free_all_paths ( void  )
static

Definition at line 3475 of file files.c.

3476 {
3477  searchpath_t *path, *next;
3478 
3479  for (path = fs_searchpaths; path; path = next) {
3480  next = path->next;
3481  free_search_path(path);
3482  }
3483 
3484  fs_searchpaths = NULL;
3485 }

Referenced by FS_Restart(), and FS_Shutdown().

◆ free_game_paths()

static void free_game_paths ( void  )
static

Definition at line 3487 of file files.c.

3488 {
3489  searchpath_t *path, *next;
3490 
3491  for (path = fs_searchpaths; path != fs_base_searchpaths; path = next) {
3492  next = path->next;
3493  free_search_path(path);
3494  }
3495 
3497 }

Referenced by FS_Restart().

◆ free_search_path()

static void free_search_path ( searchpath_t path)
static

Definition at line 3469 of file files.c.

3470 {
3471  pack_put(path->pack);
3472  Z_Free(path);
3473 }

Referenced by free_all_paths(), and free_game_paths().

◆ FS_CopyInfo()

file_info_t* FS_CopyInfo ( const char *  name,
size_t  size,
time_t  ctime,
time_t  mtime 
)

Definition at line 2599 of file files.c.

2600 {
2601  file_info_t *out;
2602  size_t len;
2603 
2604  if (!name) {
2605  return NULL;
2606  }
2607 
2608  len = strlen(name);
2609  out = FS_Mallocz(sizeof(*out) + len);
2610  out->size = size;
2611  out->ctime = ctime;
2612  out->mtime = mtime;
2613  memcpy(out->name, name, len + 1);
2614 
2615  return out;
2616 }

Referenced by copy_info(), and FS_ListFiles().

◆ FS_CopyList()

void** FS_CopyList ( void **  list,
int  count 
)

Definition at line 2618 of file files.c.

2619 {
2620  void **out;
2621  int i;
2622 
2623  if (!count) {
2624  return NULL;
2625  }
2626 
2627  out = FS_Malloc(sizeof(void *) * (count + 1));
2628  for (i = 0; i < count; i++) {
2629  out[i] = list[i];
2630  }
2631  out[i] = NULL;
2632 
2633  return out;
2634 }

◆ FS_CreatePath()

qerror_t FS_CreatePath ( char *  path)

Definition at line 605 of file files.c.

606 {
607  char *ofs;
608  int ret;
609 
610  ofs = path;
611 
612 #ifdef _WIN32
613  // check for UNC path and skip "//computer/share/" part
614  if (*path == '/' && path[1] == '/') {
615  char *p;
616 
617  p = strchr(path + 2, '/');
618  if (p) {
619  p = strchr(p + 1, '/');
620  if (p) {
621  ofs = p + 1;
622  }
623  }
624  }
625 #endif
626 
627  // skip leading slash(es)
628  for (; *ofs == '/'; ofs++)
629  ;
630 
631  for (; *ofs; ofs++) {
632  if (*ofs == '/') {
633  // create the directory
634  *ofs = 0;
635  ret = os_mkdir(path);
636  *ofs = '/';
637  if (ret == -1) {
638  qerror_t err = Q_Errno();
639  if (err != Q_ERR_EXIST)
640  return err;
641  }
642  }
643  }
644 
645  return Q_ERR_SUCCESS;
646 }

Referenced by copy_file(), open_file_write(), and start_download().

◆ FS_Dir_f()

static void FS_Dir_f ( void  )
static

Definition at line 3029 of file files.c.

3030 {
3031  char *path, *ext;
3032 
3033  if (Cmd_Argc() < 2) {
3034  Com_Printf("Usage: %s <directory> [.extension]\n", Cmd_Argv(0));
3035  return;
3036  }
3037 
3038  path = Cmd_Argv(1);
3039  if (Cmd_Argc() > 2) {
3040  ext = Cmd_Argv(2);
3041  } else {
3042  ext = NULL;
3043  }
3044 
3045  print_file_list(path, ext, 0);
3046 }

◆ FS_EasyOpenFile()

qhandle_t FS_EasyOpenFile ( char *  buf,
size_t  size,
unsigned  mode,
const char *  dir,
const char *  name,
const char *  ext 
)

Definition at line 1846 of file files.c.

1848 {
1849  if ((mode & FS_MODE_MASK) == FS_MODE_READ) {
1850  return easy_open_read(buf, size, mode, dir, name, ext);
1851  }
1852 
1853  return easy_open_write(buf, size, mode, dir, name, ext);
1854 }

Referenced by CL_PlayDemo_f(), CL_Record_f(), CL_WriteConfig_f(), Con_Dump_f(), create_screenshot(), dummy_record_f(), IMG_List_f(), LOC_Write_f(), logfile_open(), MVD_Play_f(), MVD_StreamedRecord_f(), SCR_ScoreShot_f(), SV_MvdRecord_f(), and writeMaterialsTable().

◆ FS_EasyWriteFile()

qboolean FS_EasyWriteFile ( char *  buf,
size_t  size,
unsigned  mode,
const char *  dir,
const char *  name,
const char *  ext,
const void data,
size_t  len 
)

Definition at line 1960 of file files.c.

1963 {
1964  qhandle_t f;
1965  ssize_t write;
1966  qerror_t ret;
1967 
1968  // TODO: write to temp file perhaps?
1969  f = easy_open_write(buf, size, mode, dir, name, ext);
1970  if (!f) {
1971  return qfalse;
1972  }
1973 
1974  write = FS_Write(data, len, f);
1975  ret = write == len ? Q_ERR_SUCCESS : write < 0 ? write : Q_ERR_FAILURE;
1976 
1977  FS_FCloseFile(f);
1978 
1979  if (ret) {
1980  Com_EPrintf("Couldn't write %s: %s\n", buf, Q_ErrorString(ret));
1981  return qfalse;
1982  }
1983 
1984  return qtrue;
1985 }

Referenced by dump_program(), and SV_DumpEnts_f().

◆ FS_ExtCmp()

qboolean FS_ExtCmp ( const char *  ext,
const char *  name 
)

Definition at line 2649 of file files.c.

2650 {
2651  int c1, c2;
2652  const char *e, *n, *l;
2653 
2654  if (!name[0] || !ext[0]) {
2655  return qfalse;
2656  }
2657 
2658  for (l = name; l[1]; l++)
2659  ;
2660 
2661  for (e = ext; e[1]; e++)
2662  ;
2663 
2664 rescan:
2665  n = l;
2666  do {
2667  c1 = *e--;
2668  c2 = *n--;
2669 
2670  if (c1 == ';') {
2671  break; // matched
2672  }
2673 
2674  if (c1 != c2) {
2675  c1 = Q_tolower(c1);
2676  c2 = Q_tolower(c2);
2677  if (c1 != c2) {
2678  while (e > ext) {
2679  c1 = *e--;
2680  if (c1 == ';') {
2681  goto rescan;
2682  }
2683  }
2684  return qfalse;
2685  }
2686  }
2687  if (n < name) {
2688  return qfalse;
2689  }
2690  } while (e >= ext);
2691 
2692  return qtrue;
2693 }

Referenced by FS_ListFiles(), and Sys_ListFiles_r().

◆ FS_FCloseFile()

void FS_FCloseFile ( qhandle_t  f)

Definition at line 759 of file files.c.

760 {
761  file_t *file = file_for_handle(f);
762 
763  if (!file)
764  return;
765 
766  switch (file->type) {
767  case FS_REAL:
768  fclose(file->fp);
769  break;
770  case FS_PAK:
771  if (file->unique) {
772  fclose(file->fp);
773  pack_put(file->pack);
774  }
775  break;
776 #if USE_ZLIB
777  case FS_GZ:
778  gzclose(file->zfp);
779  fclose(file->fp);
780  break;
781  case FS_ZIP:
782  if (file->unique) {
783  close_zip_file(file);
784  pack_put(file->pack);
785  }
786  break;
787 #endif
788  default:
789  break;
790  }
791 
792  memset(file, 0, sizeof(*file));
793 }

Referenced by CL_CleanupDemos(), CL_CleanupDownloads(), CL_GetDemoInfo(), CL_HandleDownload(), CL_PlayDemo_f(), CL_Stop_f(), CL_WriteConfig(), CL_WriteConfig_f(), Con_Dump_f(), demo_destroy(), demo_play_next(), dummy_record_f(), easy_open_write(), finish_udp_download(), FS_EasyWriteFile(), FS_LoadFileEx(), FS_Shutdown(), FS_WriteFile(), get_image_dimensions(), IMG_List_f(), LOC_Write_f(), logfile_close(), logfile_write(), make_screenshot(), MVD_Play_f(), MVD_StopRecord(), Prompt_LoadHistory(), Prompt_SaveHistory(), read_binary_file(), rec_stop(), SCR_ScoreShot_f(), SCR_StopCinematic(), SV_BeginDownload_f(), SV_MvdRecord_f(), WriteCache(), and writeMaterialsTable().

◆ FS_FDir_f()

static void FS_FDir_f ( void  )
static

Definition at line 3004 of file files.c.

3005 {
3006  unsigned flags;
3007  char *filter;
3008 
3009  if (Cmd_Argc() < 2) {
3010  Com_Printf("Usage: %s <filter> [full_path]\n", Cmd_Argv(0));
3011  return;
3012  }
3013 
3014  filter = Cmd_Argv(1);
3015 
3016  flags = FS_SEARCH_BYFILTER;
3017  if (Cmd_Argc() > 2) {
3018  flags |= FS_SEARCH_SAVEPATH;
3019  }
3020 
3021  print_file_list(NULL, filter, flags);
3022 }

◆ FS_File_g()

void FS_File_g ( const char *  path,
const char *  ext,
unsigned  flags,
genctx_t *  ctx 
)

Definition at line 2954 of file files.c.

2955 {
2956  int i, numFiles;
2957  void **list;
2958  char *s;
2959 
2960  list = FS_ListFiles(path, ext, flags, &numFiles);
2961  if (!list) {
2962  return;
2963  }
2964 
2965  for (i = 0; i < numFiles; i++) {
2966  s = list[i];
2967  if (ctx->count < ctx->size && !strncmp(s, ctx->partial, ctx->length)) {
2968  ctx->matches[ctx->count++] = s;
2969  } else {
2970  Z_Free(s);
2971  }
2972  }
2973 
2974  Z_Free(list);
2975 }

Referenced by CL_Demo_c(), CL_PlaySound_c(), Cmd_Config_g(), Con_Dump_c(), MVD_File_g(), SV_Map_c(), and SV_Savegame_c().

◆ FS_FilterFile()

qerror_t FS_FilterFile ( qhandle_t  f)

Definition at line 661 of file files.c.

662 {
663 #if USE_ZLIB
664  file_t *file = file_for_handle(f);
665  unsigned mode;
666  char *modeStr;
667  void *zfp;
668  uint32_t magic;
669  size_t length;
670  int fd;
671 
672  if (!file)
673  return Q_ERR_BADF;
674 
675  switch (file->type) {
676  case FS_GZ:
677  return Q_ERR_SUCCESS;
678  case FS_REAL:
679  break;
680  default:
681  return Q_ERR_NOSYS;
682  }
683 
684  mode = file->mode & FS_MODE_MASK;
685  switch (mode) {
686  case FS_MODE_READ:
687  // should have at least 10 bytes of header and 8 bytes of trailer
688  if (file->length < 18) {
689  return Q_ERR_FILE_TOO_SMALL;
690  }
691 
692  // seek to the header
693  if (fseek(file->fp, 0, SEEK_SET) == -1) {
694  return Q_Errno();
695  }
696 
697  // read magic
698  if (fread(&magic, 1, 4, file->fp) != 4) {
699  return FS_ERR_READ(file->fp);
700  }
701 
702  // check for gzip header
703  if (!CHECK_GZIP_HEADER(magic)) {
704  return Q_ERR_INVALID_FORMAT;
705  }
706 
707  // seek to the trailer
708  if (fseek(file->fp, file->length - 4, SEEK_SET) == -1) {
709  return Q_Errno();
710  }
711 
712  // read uncompressed length
713  if (fread(&magic, 1, 4, file->fp) != 4) {
714  return FS_ERR_READ(file->fp);
715  }
716 
717  length = LittleLong(magic);
718  modeStr = "rb";
719  break;
720 
721  case FS_MODE_WRITE:
722  length = 0;
723  modeStr = "wb";
724  break;
725 
726  default:
727  return Q_ERR_NOSYS;
728  }
729 
730  // rewind back to beginning
731  if (fseek(file->fp, 0, SEEK_SET) == -1) {
732  return Q_Errno();
733  }
734 
735  fd = os_fileno(file->fp);
736  if (fd == -1)
737  return Q_Errno();
738 
739  zfp = gzdopen(fd, modeStr);
740  if (!zfp) {
741  return Q_ERR_FAILURE;
742  }
743 
744  file->length = length;
745  file->zfp = zfp;
746  file->type = FS_GZ;
747  return Q_ERR_SUCCESS;
748 #else
749  return Q_ERR_NOSYS;
750 #endif
751 }

Referenced by demo_read_first(), easy_open_write(), and read_first_message().

◆ FS_Flush()

void FS_Flush ( qhandle_t  f)

Definition at line 1617 of file files.c.

1618 {
1619  file_t *file = file_for_handle(f);
1620 
1621  if (!file)
1622  return;
1623 
1624  switch (file->type) {
1625  case FS_REAL:
1626  fflush(file->fp);
1627  break;
1628 #if USE_ZLIB
1629  case FS_GZ:
1630  gzflush(file->zfp, Z_SYNC_FLUSH);
1631  break;
1632 #endif
1633  default:
1634  break;
1635  }
1636 }

Referenced by Com_Error().

◆ FS_FOpenFile()

ssize_t FS_FOpenFile ( const char *  name,
qhandle_t *  f,
unsigned  mode 
)

Definition at line 1692 of file files.c.

1693 {
1694  file_t *file;
1695  qhandle_t handle;
1696  ssize_t ret;
1697 
1698  if (!name || !f) {
1699  Com_Error(ERR_FATAL, "%s: NULL", __func__);
1700  }
1701 
1702  *f = 0;
1703 
1704  if (!fs_searchpaths) {
1705  return Q_ERR_AGAIN; // not yet initialized
1706  }
1707 
1708  // allocate new file handle
1709  file = alloc_handle(&handle);
1710  if (!file) {
1711  return Q_ERR_MFILE;
1712  }
1713 
1714  file->mode = mode;
1715 
1716  if ((mode & FS_MODE_MASK) == FS_MODE_READ) {
1717  ret = expand_open_file_read(file, name, qtrue);
1718  } else {
1719  ret = open_file_write(file, name);
1720  }
1721 
1722  if (ret >= 0) {
1723  *f = handle;
1724  }
1725 
1726  return ret;
1727 }

Referenced by CL_GetDemoInfo(), CL_HandleDownload(), CL_WriteConfig(), create_screenshot(), demo_play_next(), easy_open_read(), easy_open_write(), FS_WriteFile(), get_image_dimensions(), Prompt_LoadHistory(), Prompt_SaveHistory(), read_binary_file(), SCR_PlayCinematic(), SCR_ScoreShot_f(), start_udp_download(), SV_BeginDownload_f(), and WriteCache().

◆ FS_FPrintf()

ssize_t FS_FPrintf ( qhandle_t  f,
const char *  format,
  ... 
)

Definition at line 2039 of file files.c.

2040 {
2041  va_list argptr;
2042  char string[MAXPRINTMSG];
2043  size_t len;
2044 
2045  va_start(argptr, format);
2046  len = Q_vsnprintf(string, sizeof(string), format, argptr);
2047  va_end(argptr);
2048 
2049  if (len >= sizeof(string)) {
2050  return Q_ERR_STRING_TRUNCATED;
2051  }
2052 
2053  return FS_Write(string, len, f);
2054 }

Referenced by CL_WriteConfig(), CL_WriteConfig_f(), Com_Error(), Con_Dump_f(), IMG_List_f(), Key_WriteBindings(), LOC_Write_f(), Prompt_SaveHistory(), WriteCache(), and writeMaterialsTable().

◆ FS_FreeList()

void FS_FreeList ( void **  list)

Definition at line 2939 of file files.c.

2940 {
2941  void **p;
2942 
2943  if (!list) {
2944  return;
2945  }
2946 
2947  for (p = list; *p; p++) {
2948  Z_Free(*p);
2949  }
2950 
2951  Z_Free(list);
2952 }

Referenced by BSP_Test_f(), BuildList(), copy_save_dir(), PlayerModel_Load(), print_file_list(), and wipe_save_dir().

◆ fs_game_changed()

static void fs_game_changed ( cvar_t *  self)
static

Definition at line 3650 of file files.c.

3651 {
3652  char *s = self->string;
3653 
3654  // validate it
3655  if (*s) {
3656  if (!Q_stricmp(s, BASEGAME)) {
3657  Cvar_Reset(self);
3658  } else if (!COM_IsPath(s)) {
3659  Com_Printf("'%s' should contain characters [A-Za-z0-9_-] only.\n", self->name);
3660  Cvar_Reset(self);
3661  }
3662  }
3663 
3664  // check for the first time startup
3665  if (!fs_base_searchpaths) {
3666  // start up with baseq2 by default
3667  setup_base_paths();
3668 
3669  // check for game override
3670  setup_game_paths();
3671 
3672  FS_Path_f();
3673 
3674  // Detect if we're running full version of the game.
3675  // Shareware version can't have multiplayer enabled for legal reasons.
3676  if (FS_FileExists("maps/base1.bsp"))
3677  Cvar_Set("fs_shareware", "0");
3678  else
3679  Cvar_Set("fs_shareware", "1");
3680 
3681  if (!FS_FileExists("pics/colormap.pcx") || !FS_FileExists("pics/conchars.pcx") || !FS_FileExists("default.cfg"))
3682  {
3683  Com_Error(ERR_FATAL, "No game data files detected. Please make sure that there are .pak files"
3684  " in the game directory: %s.\nReinstalling the game can fix the issue.", fs_gamedir);
3685  }
3686 
3687  return;
3688  }
3689 
3690  // otherwise, restart the filesystem
3691  CL_RestartFilesystem(qfalse);
3692 
3693  // FIXME: if baseq2/autoexec.cfg exists DO NOT exec default.cfg and config.cfg.
3694  // this assumes user prefers to do configuration via autoexec.cfg and doesn't
3695  // want settings and binds messed up whenever gamedir changes after startup.
3696  if (!FS_FileExistsEx(COM_AUTOEXEC_CFG, FS_TYPE_REAL | FS_PATH_BASE)) {
3697  Com_AddConfigFile(COM_DEFAULT_CFG, FS_PATH_GAME);
3698  Com_AddConfigFile(COM_Q2RTX_CFG, 0);
3699  Com_AddConfigFile(COM_CONFIG_CFG, FS_TYPE_REAL | FS_PATH_GAME);
3700  }
3701 
3702  // exec autoexec.cfg (must be a real file within the game directory)
3703  Com_AddConfigFile(COM_AUTOEXEC_CFG, FS_TYPE_REAL | FS_PATH_GAME);
3704 
3705  // exec postexec.cfg (must be a real file)
3706  Com_AddConfigFile(COM_POSTEXEC_CFG, FS_TYPE_REAL);
3707 }

Referenced by FS_Init().

◆ FS_Init()

void FS_Init ( void  )

Definition at line 3714 of file files.c.

3715 {
3716  Com_Printf("------- FS_Init -------\n");
3717 
3718  List_Init(&fs_hard_links);
3719  List_Init(&fs_soft_links);
3720 
3721  Cmd_Register(c_fs);
3722 
3723 #ifdef _DEBUG
3724  fs_debug = Cvar_Get("fs_debug", "0", 0);
3725 #endif
3726 
3727  fs_shareware = Cvar_Get("fs_shareware", "0", CVAR_ROM);
3728 
3729  // get the game cvar and start the filesystem
3730  fs_game = Cvar_Get("game", DEFGAME, CVAR_LATCH | CVAR_SERVERINFO);
3731  fs_game->changed = fs_game_changed;
3733 
3734  Com_Printf("-----------------------\n");
3735 }

Referenced by Qcommon_Init().

◆ FS_LastModified()

qerror_t FS_LastModified ( char const *  file,
uint64_t *  last_modified 
)

Definition at line 1310 of file files.c.

1311 {
1312 #ifndef NO_TEXTURE_RELOADS
1313  char fullpath[MAX_OSPATH];
1314  searchpath_t *search;
1315  int valid;
1316  size_t len;
1317 
1318  valid = PATH_NOT_CHECKED;
1319 
1320  for (search = fs_searchpaths; search; search = search->next) {
1321 
1322  // skip paks
1323  if (search->pack)
1324  continue;
1325 
1326  // don't error out immediately if the path is found to be invalid,
1327  // just stop looking for it in directory tree but continue to search
1328  // for it in packs, to give broken maps or mods a chance to work
1329  if (valid == PATH_NOT_CHECKED) {
1330  valid = FS_ValidatePath(file);
1331  }
1332  if (valid == PATH_INVALID) {
1333  continue;
1334  }
1335 
1336  // check a file in the directory tree
1337  len = Q_concat(fullpath, sizeof(fullpath), search->filename, "/", file, NULL);
1338  if (len >= sizeof(fullpath)) {
1339  return Q_ERR_NAMETOOLONG;
1340  }
1341 
1342  struct stat lstat;
1343  if (stat(fullpath, &lstat) == 0) {
1344  if (last_modified)
1345  *last_modified = lstat.st_mtime;
1346  return Q_ERR_SUCCESS;
1347  }
1348  }
1349 #else
1350  if (last_modified)
1351  *last_modified = 0;
1352 #endif
1353  return Q_ERR_INVALID_PATH;
1354 }

Referenced by _try_image_format(), find_or_load_image(), and IMG_ReloadAll().

◆ FS_Length()

ssize_t FS_Length ( qhandle_t  f)

Definition at line 487 of file files.c.

488 {
489  file_t *file = file_for_handle(f);
490 
491  if (!file)
492  return Q_ERR_BADF;
493 
494  if ((file->mode & FS_MODE_MASK) == FS_MODE_READ)
495  return file->length;
496 
497  return Q_ERR_NOSYS;
498 }

Referenced by CL_FirstDemoFrame(), and demo_play_next().

◆ FS_Link_c()

static void FS_Link_c ( genctx_t *  ctx,
int  argnum 
)
static

Definition at line 3332 of file files.c.

3333 {
3334  if (argnum == 1) {
3335  FS_Link_g(ctx);
3336  }
3337 }

◆ FS_Link_f()

static void FS_Link_f ( void  )
static

Definition at line 3403 of file files.c.

3404 {
3405  int argc, count;
3406  list_t *list;
3407  symlink_t *link;
3408  size_t namelen, targlen;
3409  char name[MAX_OSPATH];
3410  char target[MAX_OSPATH];
3411 
3412  if (!strncmp(Cmd_Argv(0), "soft", 4))
3413  list = &fs_soft_links;
3414  else
3415  list = &fs_hard_links;
3416 
3417  argc = Cmd_Argc();
3418  if (argc == 1) {
3419  count = 0;
3420  FOR_EACH_SYMLINK(link, list) {
3421  Com_Printf("%s --> %s\n", link->name, link->target);
3422  count++;
3423  }
3424  Com_Printf("------------------\n"
3425  "%d symbolic link%s listed.\n", count, count == 1 ? "" : "s");
3426  return;
3427  }
3428 
3429  if (argc != 3) {
3430  Com_Printf("Usage: %s <name> <target>\n"
3431  "Creates symbolic link to target with the specified name.\n"
3432  "Virtual quake paths are accepted.\n"
3433  "Links are effective only for reading.\n",
3434  Cmd_Argv(0));
3435  return;
3436  }
3437 
3438  namelen = FS_NormalizePathBuffer(name, Cmd_Argv(1), sizeof(name));
3439  if (namelen == 0 || namelen >= sizeof(name)) {
3440  Com_Printf("Invalid symbolic link name.\n");
3441  return;
3442  }
3443 
3444  targlen = FS_NormalizePathBuffer(target, Cmd_Argv(2), sizeof(target));
3445  if (targlen == 0 || targlen >= sizeof(target)) {
3446  Com_Printf("Invalid symbolic link target.\n");
3447  return;
3448  }
3449 
3450  // search for existing link with this name
3451  FOR_EACH_SYMLINK(link, list) {
3452  if (!FS_pathcmp(link->name, name)) {
3453  Z_Free(link->target);
3454  goto update;
3455  }
3456  }
3457 
3458  // create new link
3459  link = FS_Malloc(sizeof(*link) + namelen);
3460  memcpy(link->name, name, namelen + 1);
3461  link->namelen = namelen;
3462  List_Append(list, &link->entry);
3463 
3464 update:
3465  link->target = FS_CopyString(target);
3466  link->targlen = targlen;
3467 }

◆ FS_Link_g()

static void FS_Link_g ( genctx_t *  ctx)
static

Definition at line 3315 of file files.c.

3316 {
3317  list_t *list;
3318  symlink_t *link;
3319 
3320  if (!strncmp(Cmd_Argv(ctx->argnum - 1), "soft", 4))
3321  list = &fs_soft_links;
3322  else
3323  list = &fs_hard_links;
3324 
3325  FOR_EACH_SYMLINK(link, list) {
3326  if (!Prompt_AddMatch(ctx, link->name)) {
3327  break;
3328  }
3329  }
3330 }

Referenced by FS_Link_c().

◆ FS_ListFiles()

void** FS_ListFiles ( const char *  path,
const char *  filter,
unsigned  flags,
int count_p 
)

Definition at line 2716 of file files.c.

2720 {
2721  searchpath_t *search;
2722  packfile_t *file;
2723  void *files[MAX_LISTED_FILES], *info;
2724  int i, j, count, total;
2725  char normalized[MAX_OSPATH], buffer[MAX_OSPATH];
2726  void **list;
2727  size_t len, pathlen;
2728  char *s, *p;
2729  int valid;
2730 
2731  count = 0;
2732  valid = PATH_NOT_CHECKED;
2733 
2734  if (!path) {
2735  path = "";
2736  pathlen = 0;
2737  } else {
2738  // normalize the path
2739  pathlen = FS_NormalizePathBuffer(normalized, path, sizeof(normalized));
2740  if (pathlen >= sizeof(normalized)) {
2741  goto fail;
2742  }
2743 
2744  path = normalized;
2745  }
2746 
2747  // can't mix directory search with other flags
2748  if ((flags & FS_SEARCH_DIRSONLY) && (flags & FS_SEARCH_MASK & ~FS_SEARCH_DIRSONLY)) {
2749  goto fail;
2750  }
2751 
2752  for (search = fs_searchpaths; search; search = search->next) {
2753  if (flags & FS_PATH_MASK) {
2754  if ((flags & search->mode & FS_PATH_MASK) == 0) {
2755  continue;
2756  }
2757  }
2758  if (search->pack) {
2759  if ((flags & FS_TYPE_MASK) == FS_TYPE_REAL) {
2760  continue; // don't search in paks
2761  }
2762 
2763  for (i = 0; i < search->pack->num_files; i++) {
2764  file = &search->pack->files[i];
2765  s = file->name;
2766 
2767  // check path
2768  if (pathlen) {
2769  if (file->namelen < pathlen) {
2770  continue;
2771  }
2772  if (FS_pathcmpn(s, path, pathlen)) {
2773  continue;
2774  }
2775  if (s[pathlen] != '/') {
2776  continue; // matched prefix must be a directory
2777  }
2778  if (flags & FS_SEARCH_BYFILTER) {
2779  s += pathlen + 1;
2780  }
2781  } else if (path == normalized) {
2782  if (!(flags & FS_SEARCH_DIRSONLY) && strchr(s, '/')) {
2783  continue; // must be a file in the root directory
2784  }
2785  }
2786 
2787  // check filter
2788  if (filter) {
2789  if (flags & FS_SEARCH_BYFILTER) {
2790  if (!FS_WildCmp(filter, s)) {
2791  continue;
2792  }
2793  } else {
2794  if (!FS_ExtCmp(filter, s)) {
2795  continue;
2796  }
2797  }
2798  }
2799 
2800  // copy name off
2801  if (flags & (FS_SEARCH_DIRSONLY | FS_SEARCH_STRIPEXT)) {
2802  s = strcpy(buffer, s);
2803  }
2804 
2805  // hacky directory search support for pak files
2806  if (flags & FS_SEARCH_DIRSONLY) {
2807  p = s;
2808  if (pathlen) {
2809  p += pathlen + 1;
2810  }
2811  p = strchr(p, '/');
2812  if (!p) {
2813  continue; // does not have directory component
2814  }
2815  *p = 0;
2816  for (j = 0; j < count; j++) {
2817  if (!FS_pathcmp(files[j], s)) {
2818  break;
2819  }
2820  }
2821  if (j != count) {
2822  continue; // already listed this directory
2823  }
2824  }
2825 
2826  // strip path
2827  if (!(flags & FS_SEARCH_SAVEPATH)) {
2828  s = COM_SkipPath(s);
2829  }
2830 
2831  // strip extension
2832  if (flags & FS_SEARCH_STRIPEXT) {
2833  *COM_FileExtension(s) = 0;
2834  }
2835 
2836  if (!*s) {
2837  continue;
2838  }
2839 
2840  // copy info off
2841  if (flags & FS_SEARCH_EXTRAINFO) {
2842  info = FS_CopyInfo(s, file->filelen, 0, 0);
2843  } else {
2844  info = FS_CopyString(s);
2845  }
2846 
2847  files[count++] = info;
2848 
2849  if (count >= MAX_LISTED_FILES) {
2850  break;
2851  }
2852  }
2853  } else {
2854  if ((flags & FS_TYPE_MASK) == FS_TYPE_PAK) {
2855  continue; // don't search in filesystem
2856  }
2857 
2858  len = strlen(search->filename);
2859 
2860  if (pathlen) {
2861  if (len + pathlen + 1 >= MAX_OSPATH) {
2862  continue;
2863  }
2864  if (valid == PATH_NOT_CHECKED) {
2865  valid = FS_ValidatePath(path);
2866  }
2867  if (valid == PATH_INVALID) {
2868  continue;
2869  }
2870  s = memcpy(buffer, search->filename, len);
2871  s[len++] = '/';
2872  memcpy(s + len, path, pathlen + 1);
2873  } else {
2874  s = search->filename;
2875  }
2876 
2877  if (flags & FS_SEARCH_BYFILTER) {
2878  len += pathlen + 1;
2879  }
2880 
2881  Sys_ListFiles_r(s, filter, flags, len, &count, files, 0);
2882  }
2883 
2884  if (count >= MAX_LISTED_FILES) {
2885  break;
2886  }
2887  }
2888 
2889  if (!count) {
2890 fail:
2891  if (count_p) {
2892  *count_p = 0;
2893  }
2894  return NULL;
2895  }
2896 
2897  if (flags & FS_SEARCH_EXTRAINFO) {
2898  // TODO
2899  qsort(files, count, sizeof(files[0]), infocmp);
2900  total = count;
2901  } else {
2902  // sort alphabetically
2903  qsort(files, count, sizeof(files[0]), alphacmp);
2904 
2905  // remove duplicates
2906  total = 1;
2907  for (i = 1; i < count; i++) {
2908  if (!FS_pathcmp(files[i - 1], files[i])) {
2909  Z_Free(files[i - 1]);
2910  files[i - 1] = NULL;
2911  } else {
2912  total++;
2913  }
2914  }
2915  }
2916 
2917  list = FS_Malloc(sizeof(void *) * (total + 1));
2918 
2919  total = 0;
2920  for (i = 0; i < count; i++) {
2921  if (files[i]) {
2922  list[total++] = files[i];
2923  }
2924  }
2925  list[total] = NULL;
2926 
2927  if (count_p) {
2928  *count_p = total;
2929  }
2930 
2931  return list;
2932 }

Referenced by BSP_Test_f(), BuildList(), Com_MapList_m(), FS_File_g(), list_save_dir(), PlayerModel_Load(), and print_file_list().

◆ FS_LoadFileEx()

ssize_t FS_LoadFileEx ( const char *  path,
void **  buffer,
unsigned  flags,
memtag_t  tag 
)

Definition at line 1864 of file files.c.

1865 {
1866  file_t *file;
1867  qhandle_t f;
1868  byte *buf;
1869  ssize_t len, read;
1870 
1871  if (!path) {
1872  Com_Error(ERR_FATAL, "%s: NULL", __func__);
1873  }
1874 
1875  if (buffer) {
1876  *buffer = NULL;
1877  }
1878 
1879  if (!fs_searchpaths) {
1880  return Q_ERR_AGAIN; // not yet initialized
1881  }
1882 
1883  // allocate new file handle
1884  file = alloc_handle(&f);
1885  if (!file) {
1886  return Q_ERR_MFILE;
1887  }
1888 
1889  file->mode = (flags & ~FS_MODE_MASK) | FS_MODE_READ;
1890 
1891  // look for it in the filesystem or pack files
1892  len = expand_open_file_read(file, path, qfalse);
1893  if (len < 0) {
1894  return len;
1895  }
1896 
1897  // NULL buffer just checks for file existence
1898  if (!buffer) {
1899  goto done;
1900  }
1901 
1902  // sanity check file size
1903  if (len > MAX_LOADFILE) {
1904  len = Q_ERR_FBIG;
1905  goto done;
1906  }
1907 
1908  // allocate chunk of memory, +1 for NUL
1909  buf = Z_TagMalloc(len + 1, tag);
1910 
1911  // read entire file
1912  read = FS_Read(buf, len, f);
1913  if (read != len) {
1914  len = read < 0 ? read : Q_ERR_UNEXPECTED_EOF;
1915  Z_Free(buf);
1916  goto done;
1917  }
1918 
1919  *buffer = buf;
1920  buf[len] = 0;
1921 
1922 done:
1923  FS_FCloseFile(f);
1924  return len;
1925 }

Referenced by Cmd_ExecuteFile(), and LoadCache().

◆ FS_NormalizePath()

size_t FS_NormalizePath ( char *  out,
const char *  in 
)

Definition at line 331 of file files.c.

332 {
333  char *start = out;
334  uint32_t pre = '/';
335 
336  while (1) {
337  int c = *in++;
338 
339  if (c == '/' || c == '\\' || c == 0) {
340  if ((pre & 0xffffff) == (('/' << 16) | ('.' << 8) | '.')) {
341  out -= 4;
342  if (out < start) {
343  // can't go past root
344  out = start;
345  if (c == 0)
346  break;
347  } else {
348  while (out > start && *out != '/')
349  out--;
350  if (c == 0)
351  break;
352  if (out > start)
353  // save the slash
354  out++;
355  }
356  pre = '/';
357  continue;
358  }
359 
360  if ((pre & 0xffff) == (('/' << 8) | '.')) {
361  // eat the dot
362  out--;
363  if (c == 0) {
364  if (out > start)
365  // eat the slash
366  out--;
367  break;
368  }
369  pre = '/';
370  continue;
371  }
372 
373  if ((pre & 0xff) == '/') {
374  if (c == 0)
375  break;
376  continue;
377  }
378 
379  if (c == 0)
380  break;
381  c = '/';
382  }
383 
384  pre = (pre << 8) | c;
385  *out++ = c;
386  }
387 
388  *out = 0;
389  return out - start;
390 }

Referenced by bsp_mesh_register_textures(), check_and_queue_download(), check_file_len(), Com_TestNorm_f(), easy_open_read(), FS_NormalizePathBuffer(), GL_LoadWorld(), MOD_LoadMD2(), MOD_LoadMD2_GL(), MOD_LoadMD2_RTX(), MOD_LoadSP2(), pack_hash_file(), ProcessTexinfo(), R_RegisterImage(), R_SetSky(), R_SetSky_GL(), R_SetSky_RTX(), S_RegisterSexedSound(), S_RegisterSound(), SV_BeginDownload_f(), and vkpt_textures_prefetch().

◆ FS_NormalizePathBuffer()

size_t FS_NormalizePathBuffer ( char *  out,
const char *  in,
size_t  size 
)

Definition at line 400 of file files.c.

401 {
402  size_t len = strlen(in);
403 
404  if (len >= size) {
405  if (size)
406  *out = 0;
407  return len;
408  }
409 
410  return FS_NormalizePath(out, in);
411 }

Referenced by Cmd_Exec_f(), easy_open_write(), expand_open_file_read(), FS_Link_f(), FS_ListFiles(), FS_WhereIs_f(), open_file_write(), R_RegisterImage(), R_RegisterModel(), and S_RegisterSound().

◆ FS_Path_f()

static void FS_Path_f ( void  )
static

Definition at line 3223 of file files.c.

3224 {
3225  searchpath_t *s;
3226  int numFilesInPAK = 0;
3227 #if USE_ZLIB
3228  int numFilesInZIP = 0;
3229 #endif
3230  Com_Printf("Current search path:\n");
3231  for (s = fs_searchpaths; s; s = s->next) {
3232  if (s->pack) {
3233 #if USE_ZLIB
3234  if (s->pack->type == FS_ZIP)
3235  numFilesInZIP += s->pack->num_files;
3236  else
3237 #endif
3238  numFilesInPAK += s->pack->num_files;
3239  Com_Printf("%s (%i files)\n", s->pack->filename, s->pack->num_files);
3240  } else {
3241  Com_Printf("%s\n", s->filename);
3242  }
3243  }
3244 
3245  if (numFilesInPAK) {
3246  Com_Printf("%i files in PAK files\n", numFilesInPAK);
3247  }
3248 
3249 #if USE_ZLIB
3250  if (numFilesInZIP) {
3251  Com_Printf("%i files in PKZ files\n", numFilesInZIP);
3252  }
3253 #endif
3254 }

Referenced by fs_game_changed(), and FS_Restart().

◆ FS_Read()

ssize_t FS_Read ( void buf,
size_t  len,
qhandle_t  f 
)

Definition at line 1547 of file files.c.

1548 {
1549  file_t *file = file_for_handle(f);
1550 #if USE_ZLIB
1551  int ret;
1552 #endif
1553 
1554  if (!file)
1555  return Q_ERR_BADF;
1556 
1557  if ((file->mode & FS_MODE_MASK) != FS_MODE_READ)
1558  return Q_ERR_INVAL;
1559 
1560  // can't continue after error
1561  if (file->error)
1562  return file->error;
1563 
1564  if (len > SSIZE_MAX)
1565  return Q_ERR_INVAL;
1566 
1567  if (len == 0)
1568  return 0;
1569 
1570  switch (file->type) {
1571  case FS_REAL:
1572  return read_phys_file(file, buf, len);
1573  case FS_PAK:
1574  return read_pak_file(file, buf, len);
1575 #if USE_ZLIB
1576  case FS_GZ:
1577  ret = gzread(file->zfp, buf, len);
1578  if (ret < 0) {
1579  return Q_ERR_LIBRARY_ERROR;
1580  }
1581  return ret;
1582  case FS_ZIP:
1583  return read_zip_file(file, buf, len);
1584 #endif
1585  default:
1586  return Q_ERR_NOSYS;
1587  }
1588 }

Referenced by demo_load_message(), demo_read_first(), FS_LoadFileEx(), get_image_dimensions(), Huff1TableInit(), read_binary_file(), read_first_message(), read_next_message(), SCR_PlayCinematic(), SCR_ReadNextFrame(), and SV_BeginDownload_f().

◆ FS_ReadLine()

ssize_t FS_ReadLine ( qhandle_t  f,
char *  buffer,
size_t  size 
)

Definition at line 1590 of file files.c.

1591 {
1592  file_t *file = file_for_handle(f);
1593  char *s;
1594  size_t len;
1595 
1596  if (!file)
1597  return Q_ERR_BADF;
1598 
1599  if ((file->mode & FS_MODE_MASK) != FS_MODE_READ)
1600  return Q_ERR_INVAL;
1601 
1602  if (file->type != FS_REAL)
1603  return Q_ERR_NOSYS;
1604 
1605  do {
1606  s = fgets(buffer, size, file->fp);
1607  if (!s) {
1608  return ferror(file->fp) ? Q_Errno() : 0;
1609  }
1610  len = strlen(s);
1611  } while (len < 2);
1612 
1613  s[len - 1] = 0;
1614  return len - 1;
1615 }

Referenced by Prompt_LoadHistory().

◆ FS_ReplaceSeparators()

char* FS_ReplaceSeparators ( char *  s,
int  separator 
)

Definition at line 235 of file files.c.

236 {
237  char *p;
238 
239  p = s;
240  while (*p) {
241  if (*p == '/' || *p == '\\') {
242  *p = separator;
243  }
244  p++;
245  }
246 
247  return s;
248 }

Referenced by FS_Restart(), q_printf(), and Sys_ListFiles_r().

◆ FS_Restart()

void FS_Restart ( qboolean  total)

Definition at line 3556 of file files.c.

3557 {
3558  Com_Printf("----- FS_Restart -----\n");
3559 
3560  if (total) {
3561  // perform full reset
3562  free_all_paths();
3563  setup_base_paths();
3564  } else {
3565  // just change gamedir
3566  free_game_paths();
3567  Q_snprintf(fs_gamedir, sizeof(fs_gamedir), "%s/"BASEGAME, sys_basedir->string);
3568 #ifdef _WIN32
3570 #endif
3571  }
3572 
3573  setup_game_paths();
3574 
3575  FS_Path_f();
3576 
3577  Com_Printf("----------------------\n");
3578 }

Referenced by CL_RestartFilesystem().

◆ FS_Restart_f()

static void FS_Restart_f ( void  )
static

Definition at line 3587 of file files.c.

3588 {
3589  CL_RestartFilesystem(qtrue);
3590 }

◆ FS_SanitizeFilenameVariable()

void FS_SanitizeFilenameVariable ( cvar_t *  var)

Definition at line 294 of file files.c.

295 {
296  if (!FS_ValidatePath(var->string)) {
297  Com_Printf("'%s' contains invalid characters for a filename.\n", var->name);
298  goto reset;
299  }
300 
301  if (strchr(var->string, '/') || strchr(var->string, '\\')) {
302  Com_Printf("'%s' should be a single filename, not a path.\n", var->name);
303  goto reset;
304  }
305 
306  return;
307 
308 reset:
309  Com_Printf("...falling back to %s\n", var->default_string);
310  Cvar_Reset(var);
311 }

Referenced by QAL_Init(), and VID_Init().

◆ FS_Seek()

qerror_t FS_Seek ( qhandle_t  f,
off_t  offset 
)

Definition at line 564 of file files.c.

565 {
566  file_t *file = file_for_handle(f);
567 
568  if (!file)
569  return Q_ERR_BADF;
570 
571  if (offset > LONG_MAX)
572  return Q_ERR_INVAL;
573 
574  if (offset < 0)
575  offset = 0;
576 
577  switch (file->type) {
578  case FS_REAL:
579  if (fseek(file->fp, (long)offset, SEEK_SET) == -1) {
580  return Q_Errno();
581  }
582  return Q_ERR_SUCCESS;
583  case FS_PAK:
584  return seek_pak_file(file, offset);
585 #if USE_ZLIB
586  case FS_GZ:
587  if (gzseek(file->zfp, (z_off_t)offset, SEEK_SET) == -1) {
588  return Q_Errno();
589  }
590  return Q_ERR_SUCCESS;
591 #endif
592  default:
593  return Q_ERR_NOSYS;
594  }
595 }

Referenced by CL_Seek_f(), and MVD_Seek_f().

◆ FS_Shutdown()

void FS_Shutdown ( void  )

Definition at line 3614 of file files.c.

3615 {
3616  file_t *file;
3617  int i;
3618 
3619  if (!fs_searchpaths) {
3620  return;
3621  }
3622 
3623  // close file handles
3624  for (i = 0, file = fs_files; i < MAX_FILE_HANDLES; i++, file++) {
3625  if (file->type != FS_FREE) {
3626  Com_WPrintf("%s: closing handle %d\n", __func__, i + 1);
3627  FS_FCloseFile(i + 1);
3628  }
3629  }
3630 
3631  // free symbolic links
3634 
3635  // free search paths
3636  free_all_paths();
3637 
3638 #if USE_ZLIB
3639  inflateEnd(&fs_zipstream.stream);
3640 #endif
3641 
3642  Z_LeakTest(TAG_FILESYSTEM);
3643 
3645 }

Referenced by Com_Error(), and Com_Quit().

◆ FS_Tell()

ssize_t FS_Tell ( qhandle_t  f)

Definition at line 505 of file files.c.

506 {
507  file_t *file = file_for_handle(f);
508  long ret;
509 
510  if (!file)
511  return Q_ERR_BADF;
512 
513  switch (file->type) {
514  case FS_REAL:
515  ret = ftell(file->fp);
516  if (ret == -1) {
517  return Q_Errno();
518  }
519  return ret;
520  case FS_PAK:
521  return file->length - file->rest_out;
522 #if USE_ZLIB
523  case FS_ZIP:
524  return tell_zip_file(file);
525  case FS_GZ:
526  ret = gztell(file->zfp);
527  if (ret == -1) {
528  return Q_ERR_LIBRARY_ERROR;
529  }
530  return ret;
531 #endif
532  default:
533  return Q_ERR_NOSYS;
534  }
535 }

Referenced by CL_EmitDemoSnapshot(), CL_FirstDemoFrame(), demo_emit_snapshot(), demo_play_next(), demo_update(), format_demo_size(), list_recordings(), rec_frame(), and update_status().

◆ FS_UnLink_f()

static void FS_UnLink_f ( void  )
static

Definition at line 3351 of file files.c.

3352 {
3353  static const cmd_option_t options[] = {
3354  { "a", "all", "delete all links" },
3355  { "h", "help", "display this message" },
3356  { NULL }
3357  };
3358  list_t *list;
3359  symlink_t *link;
3360  char *name;
3361  int c;
3362 
3363  if (!strncmp(Cmd_Argv(0), "soft", 4))
3364  list = &fs_soft_links;
3365  else
3366  list = &fs_hard_links;
3367 
3368  while ((c = Cmd_ParseOptions(options)) != -1) {
3369  switch (c) {
3370  case 'h':
3371  Cmd_PrintUsage(options, "<name>");
3372  Com_Printf("Deletes a symbolic link with the specified name.");
3373  Cmd_PrintHelp(options);
3374  return;
3375  case 'a':
3376  free_all_links(list);
3377  Com_Printf("Deleted all symbolic links.\n");
3378  return;
3379  default:
3380  return;
3381  }
3382  }
3383 
3384  name = cmd_optarg;
3385  if (!name[0]) {
3386  Com_Printf("Missing name argument.\n");
3387  Cmd_PrintHint();
3388  return;
3389  }
3390 
3391  FOR_EACH_SYMLINK(link, list) {
3392  if (!FS_pathcmp(link->name, name)) {
3393  List_Remove(&link->entry);
3394  Z_Free(link->target);
3395  Z_Free(link);
3396  return;
3397  }
3398  }
3399 
3400  Com_Printf("Symbolic link '%s' does not exist.\n", name);
3401 }

◆ FS_ValidatePath()

int FS_ValidatePath ( const char *  s)

Definition at line 271 of file files.c.

272 {
273  int res = PATH_VALID;
274 
275  for (; *s; s++) {
276  if (!validate_char(*s))
277  return PATH_INVALID;
278 
279  if (Q_isupper(*s))
280  res = PATH_MIXED_CASE;
281  }
282 
283  return res;
284 }

Referenced by check_and_queue_download(), check_file_len(), FS_LastModified(), FS_ListFiles(), FS_SanitizeFilenameVariable(), FS_WhereIs_f(), open_file_read(), and open_file_write().

◆ FS_WhereIs_f()

static void FS_WhereIs_f ( void  )
static

Definition at line 3055 of file files.c.

3056 {
3057  char normalized[MAX_OSPATH], fullpath[MAX_OSPATH];
3058  searchpath_t *search;
3059  pack_t *pak;
3060  packfile_t *entry;
3061  symlink_t *link;
3062  unsigned hash;
3063  file_info_t info;
3064  qerror_t ret;
3065  int total, valid;
3066  size_t len, namelen;
3067  qboolean report_all;
3068 
3069  if (Cmd_Argc() < 2) {
3070  Com_Printf("Usage: %s <path> [all]\n", Cmd_Argv(0));
3071  return;
3072  }
3073 
3074 // normalize path
3075  namelen = FS_NormalizePathBuffer(normalized, Cmd_Argv(1), MAX_OSPATH);
3076  if (namelen >= MAX_OSPATH) {
3077  Com_Printf("Refusing to lookup oversize path.\n");
3078  return;
3079  }
3080 
3081 // expand hard symlinks
3082  link = expand_links(&fs_hard_links, normalized, &namelen);
3083  if (link) {
3084  if (namelen >= MAX_OSPATH) {
3085  Com_Printf("Oversize symbolic link ('%s --> '%s').\n",
3086  link->name, link->target);
3087  return;
3088  }
3089 
3090  Com_Printf("Symbolic link ('%s' --> '%s') in effect.\n",
3091  link->name, link->target);
3092  }
3093 
3094  report_all = Cmd_Argc() >= 3;
3095  total = 0;
3096  link = NULL;
3097 
3098 // reject empty paths
3099  if (namelen == 0) {
3100  Com_Printf("Refusing to lookup empty path.\n");
3101  return;
3102  }
3103 
3104 recheck:
3105 
3106 // warn about non-standard path length
3107  if (namelen >= MAX_QPATH) {
3108  Com_Printf("Not searching for '%s' in pack files "
3109  "since path length exceedes %d characters.\n",
3110  normalized, MAX_QPATH - 1);
3111  }
3112 
3113  hash = FS_HashPath(normalized, 0);
3114 
3115  valid = PATH_NOT_CHECKED;
3116 
3117 // search through the path, one element at a time
3118  for (search = fs_searchpaths; search; search = search->next) {
3119  // is the element a pak file?
3120  if (search->pack) {
3121  // don't bother searching in paks if length exceedes MAX_QPATH
3122  if (namelen >= MAX_QPATH) {
3123  continue;
3124  }
3125  // look through all the pak file elements
3126  pak = search->pack;
3127  entry = pak->file_hash[hash & (pak->hash_size - 1)];
3128  for (; entry; entry = entry->hash_next) {
3129  if (entry->namelen != namelen) {
3130  continue;
3131  }
3132  if (!FS_pathcmp(entry->name, normalized)) {
3133  // found it!
3134  Com_Printf("%s/%s (%"PRIz" bytes)\n", pak->filename,
3135  normalized, entry->filelen);
3136  if (!report_all) {
3137  return;
3138  }
3139  total++;
3140  }
3141  }
3142  } else {
3143  if (valid == PATH_NOT_CHECKED) {
3144  valid = FS_ValidatePath(normalized);
3145  if (valid == PATH_INVALID) {
3146  // warn about invalid path
3147  Com_Printf("Not searching for '%s' in physical file "
3148  "system since path contains invalid characters.\n",
3149  normalized);
3150  }
3151  }
3152  if (valid == PATH_INVALID) {
3153  continue;
3154  }
3155 
3156  // check a file in the directory tree
3157  len = Q_concat(fullpath, MAX_OSPATH,
3158  search->filename, "/", normalized, NULL);
3159  if (len >= MAX_OSPATH) {
3160  Com_WPrintf("Full path length '%s/%s' exceeded %d characters.\n",
3161  search->filename, normalized, MAX_OSPATH - 1);
3162  if (!report_all) {
3163  return;
3164  }
3165  continue;
3166  }
3167 
3168  ret = get_path_info(fullpath, &info);
3169 
3170 #ifndef _WIN32
3171  if (ret == Q_ERR_NOENT && valid == PATH_MIXED_CASE) {
3172  Q_strlwr(fullpath + strlen(search->filename) + 1);
3173  ret = get_path_info(fullpath, &info);
3174  if (ret == Q_ERR_SUCCESS)
3175  Com_Printf("Physical path found after converting to lower case.\n");
3176  }
3177 #endif
3178 
3179  if (ret == Q_ERR_SUCCESS) {
3180  Com_Printf("%s (%"PRIz" bytes)\n", fullpath, info.size);
3181  if (!report_all) {
3182  return;
3183  }
3184  total++;
3185  } else if (ret != Q_ERR_NOENT) {
3186  Com_EPrintf("Couldn't get info on '%s': %s\n",
3187  fullpath, Q_ErrorString(ret));
3188  if (!report_all) {
3189  return;
3190  }
3191  }
3192  }
3193  }
3194 
3195  if ((total == 0 || report_all) && link == NULL) {
3196  // expand soft symlinks
3197  link = expand_links(&fs_soft_links, normalized, &namelen);
3198  if (link) {
3199  if (namelen >= MAX_OSPATH) {
3200  Com_Printf("Oversize symbolic link ('%s --> '%s').\n",
3201  link->name, link->target);
3202  return;
3203  }
3204 
3205  Com_Printf("Symbolic link ('%s' --> '%s') in effect.\n",
3206  link->name, link->target);
3207  goto recheck;
3208  }
3209  }
3210 
3211  if (total) {
3212  Com_Printf("%d instances of %s\n", total, normalized);
3213  } else {
3214  Com_Printf("%s was not found\n", normalized);
3215  }
3216 }

◆ FS_WildCmp()

qboolean FS_WildCmp ( const char *  filter,
const char *  string 
)

Definition at line 2636 of file files.c.

2637 {
2638  do {
2639  if (Com_WildCmpEx(filter, string, ';', qtrue)) {
2640  return qtrue;
2641  }
2642  filter = strchr(filter, ';');
2643  if (filter) filter++;
2644  } while (filter);
2645 
2646  return qfalse;
2647 }

Referenced by FS_ListFiles(), and Sys_ListFiles_r().

◆ FS_Write()

ssize_t FS_Write ( const void buf,
size_t  len,
qhandle_t  f 
)

Definition at line 1643 of file files.c.

1644 {
1645  file_t *file = file_for_handle(f);
1646  size_t result;
1647 
1648  if (!file)
1649  return Q_ERR_BADF;
1650 
1651  if ((file->mode & FS_MODE_MASK) == FS_MODE_READ)
1652  return Q_ERR_INVAL;
1653 
1654  // can't continue after error
1655  if (file->error)
1656  return file->error;
1657 
1658  if (len > SSIZE_MAX)
1659  return Q_ERR_INVAL;
1660 
1661  if (len == 0)
1662  return 0;
1663 
1664  switch (file->type) {
1665  case FS_REAL:
1666  result = fwrite(buf, 1, len, file->fp);
1667  if (result != len) {
1668  file->error = FS_ERR_WRITE(file->fp);
1669  return file->error;
1670  }
1671  break;
1672 #if USE_ZLIB
1673  case FS_GZ:
1674  if (gzwrite(file->zfp, buf, len) == 0) {
1675  file->error = Q_ERR_LIBRARY_ERROR;
1676  return file->error;
1677  }
1678  break;
1679 #endif
1680  default:
1681  Com_Error(ERR_FATAL, "%s: bad file type", __func__);
1682  }
1683 
1684  return len;
1685 }

Referenced by CL_Stop_f(), CL_WriteDemoMessage(), FS_EasyWriteFile(), FS_FPrintf(), FS_WriteFile(), logfile_write(), MVD_StopRecord(), MVD_StreamedRecord_f(), MVD_WriteDemoMessage(), rec_frame(), rec_start(), rec_stop(), rec_write(), SCR_ScoreShot_f(), stbi_write(), and write_udp_download().

◆ FS_WriteFile()

qerror_t FS_WriteFile ( const char *  path,
const void data,
size_t  len 
)

Definition at line 1932 of file files.c.

1933 {
1934  qhandle_t f;
1935  ssize_t write;
1936  qerror_t ret;
1937 
1938  // TODO: write to temp file perhaps?
1939  write = FS_FOpenFile(path, &f, FS_MODE_WRITE);
1940  if (!f) {
1941  return write;
1942  }
1943 
1944  write = FS_Write(data, len, f);
1945  ret = write == len ? Q_ERR_SUCCESS : write < 0 ? write : Q_ERR_FAILURE;
1946 
1947  FS_FCloseFile(f);
1948  return ret;
1949 }

Referenced by BSP_SavePatchedPVS(), write_level_file(), and write_server_file().

◆ get_fp_info()

static qerror_t get_fp_info ( FILE *  fp,
file_info_t *  info 
)
static

Definition at line 817 of file files.c.

818 {
819  Q_STATBUF st;
820  int fd;
821 
822  fd = os_fileno(fp);
823  if (fd == -1)
824  return Q_Errno();
825 
826  if (os_fstat(fd, &st) == -1)
827  return Q_Errno();
828 
829  if (Q_ISDIR(st.st_mode))
830  return Q_ERR_ISDIR;
831 
832  if (!Q_ISREG(st.st_mode))
833  return Q_ERR_FILE_NOT_REGULAR;
834 
835  if (info) {
836  info->size = st.st_size;
837  info->ctime = st.st_ctime;
838  info->mtime = st.st_mtime;
839  }
840 
841  return Q_ERR_SUCCESS;
842 }

Referenced by open_file_write(), and open_from_disk().

◆ get_path_info()

static qerror_t get_path_info ( const char *  path,
file_info_t *  info 
)
static

Definition at line 795 of file files.c.

796 {
797  Q_STATBUF st;
798 
799  if (os_stat(path, &st) == -1)
800  return Q_Errno();
801 
802  if (Q_ISDIR(st.st_mode))
803  return Q_ERR_ISDIR;
804 
805  if (!Q_ISREG(st.st_mode))
806  return Q_ERR_FILE_NOT_REGULAR;
807 
808  if (info) {
809  info->size = st.st_size;
810  info->ctime = st.st_ctime;
811  info->mtime = st.st_mtime;
812  }
813 
814  return Q_ERR_SUCCESS;
815 }

Referenced by FS_WhereIs_f().

◆ infocmp()

static int infocmp ( const void p1,
const void p2 
)
static

Definition at line 2695 of file files.c.

2696 {
2697  file_info_t *n1 = *(file_info_t **)p1;
2698  file_info_t *n2 = *(file_info_t **)p2;
2699 
2700  return FS_pathcmp(n1->name, n2->name);
2701 }

Referenced by FS_ListFiles().

◆ load_pak_file()

static pack_t* load_pak_file ( const char *  packfile)
static

Definition at line 2123 of file files.c.

2124 {
2125  dpackheader_t header;
2126  packfile_t *file;
2127  dpackfile_t *dfile;
2128  unsigned i, num_files;
2129  char *name;
2130  size_t len, names_len;
2131  pack_t *pack;
2132  FILE *fp;
2133  dpackfile_t info[MAX_FILES_IN_PACK];
2134 
2135  fp = fopen(packfile, "rb");
2136  if (!fp) {
2137  Com_Printf("Couldn't open %s: %s\n", packfile, strerror(errno));
2138  return NULL;
2139  }
2140 
2141  if (fread(&header, 1, sizeof(header), fp) != sizeof(header)) {
2142  Com_Printf("Reading header failed on %s\n", packfile);
2143  goto fail;
2144  }
2145 
2146  if (LittleLong(header.ident) != IDPAKHEADER) {
2147  Com_Printf("%s is not a 'PACK' file\n", packfile);
2148  goto fail;
2149  }
2150 
2151  header.dirlen = LittleLong(header.dirlen);
2152  if (header.dirlen > INT_MAX || header.dirlen % sizeof(dpackfile_t)) {
2153  Com_Printf("%s has bad directory length\n", packfile);
2154  goto fail;
2155  }
2156 
2157  num_files = header.dirlen / sizeof(dpackfile_t);
2158  if (num_files < 1) {
2159  Com_Printf("%s has no files\n", packfile);
2160  goto fail;
2161  }
2162  if (num_files > MAX_FILES_IN_PACK) {
2163  Com_Printf("%s has too many files: %u > %u\n", packfile, num_files, MAX_FILES_IN_PACK);
2164  goto fail;
2165  }
2166 
2167  header.dirofs = LittleLong(header.dirofs);
2168  if (header.dirofs > LONG_MAX - header.dirlen) {
2169  Com_Printf("%s has bad directory offset\n", packfile);
2170  goto fail;
2171  }
2172  if (fseek(fp, (long)header.dirofs, SEEK_SET)) {
2173  Com_Printf("Seeking to directory failed on %s\n", packfile);
2174  goto fail;
2175  }
2176  if (fread(info, 1, header.dirlen, fp) != header.dirlen) {
2177  Com_Printf("Reading directory failed on %s\n", packfile);
2178  goto fail;
2179  }
2180 
2181  names_len = 0;
2182  for (i = 0, dfile = info; i < num_files; i++, dfile++) {
2183  dfile->filepos = LittleLong(dfile->filepos);
2184  dfile->filelen = LittleLong(dfile->filelen);
2185  if (dfile->filelen > INT_MAX || dfile->filepos > INT_MAX - dfile->filelen) {
2186  Com_Printf("%s has bad directory structure\n", packfile);
2187  goto fail;
2188  }
2189  dfile->name[sizeof(dfile->name) - 1] = 0;
2190  names_len += strlen(dfile->name) + 1;
2191  }
2192 
2193 // allocate the pack
2194  pack = pack_alloc(fp, FS_PAK, packfile, num_files, names_len);
2195 
2196 // parse the directory
2197  file = pack->files;
2198  name = pack->names;
2199  for (i = 0, dfile = info; i < num_files; i++, dfile++) {
2200  len = strlen(dfile->name) + 1;
2201 
2202  file->name = memcpy(name, dfile->name, len);
2203  name += len;
2204 
2205  file->filepos = dfile->filepos;
2206  file->filelen = dfile->filelen;
2207 #if USE_ZLIB
2208  file->coherent = qtrue;
2209 #endif
2210 
2211  pack_hash_file(pack, file);
2212  file++;
2213  }
2214 
2215  FS_DPrintf("%s: %u files, %u hash\n",
2216  packfile, pack->num_files, pack->hash_size);
2217 
2218  return pack;
2219 
2220 fail:
2221  fclose(fp);
2222  return NULL;
2223 }

Referenced by q_printf().

◆ open_file_read()

static ssize_t open_file_read ( file_t file,
const char *  normalized,
size_t  namelen,
qboolean  unique 
)
static

Definition at line 1359 of file files.c.

1360 {
1361  char fullpath[MAX_OSPATH];
1362  searchpath_t *search;
1363  pack_t *pak;
1364  unsigned hash;
1365  packfile_t *entry;
1366  ssize_t ret;
1367  int valid;
1368  size_t len;
1369 
1370  FS_COUNT_READ;
1371 
1372  hash = FS_HashPath(normalized, 0);
1373 
1374  valid = PATH_NOT_CHECKED;
1375 
1376 // search through the path, one element at a time
1377  for (search = fs_searchpaths; search; search = search->next) {
1378  if (file->mode & FS_PATH_MASK) {
1379  if ((file->mode & search->mode & FS_PATH_MASK) == 0) {
1380  continue;
1381  }
1382  }
1383 
1384  // is the element a pak file?
1385  if (search->pack) {
1386  if ((file->mode & FS_TYPE_MASK) == FS_TYPE_REAL) {
1387  continue;
1388  }
1389  // don't bother searching in paks if length exceedes MAX_QPATH
1390  if (namelen >= MAX_QPATH) {
1391  continue;
1392  }
1393  pak = search->pack;
1394 #if USE_ZLIB
1395  if ((file->mode & FS_FLAG_DEFLATE) && pak->type != FS_ZIP) {
1396  continue;
1397  }
1398 #endif
1399  // look through all the pak file elements
1400  entry = pak->file_hash[hash & (pak->hash_size - 1)];
1401  for (; entry; entry = entry->hash_next) {
1402  if (entry->namelen != namelen) {
1403  continue;
1404  }
1405 #if USE_ZLIB
1406  if ((file->mode & FS_FLAG_DEFLATE) && entry->compmtd != Z_DEFLATED) {
1407  continue;
1408  }
1409 #endif
1411  if (!FS_pathcmp(entry->name, normalized)) {
1412  // found it!
1413  return open_from_pak(file, pak, entry, unique);
1414  }
1415  }
1416  } else {
1417  if ((file->mode & FS_TYPE_MASK) == FS_TYPE_PAK) {
1418  continue;
1419  }
1420 #if USE_ZLIB
1421  if (file->mode & FS_FLAG_DEFLATE) {
1422  continue;
1423  }
1424 #endif
1425  // don't error out immediately if the path is found to be invalid,
1426  // just stop looking for it in directory tree but continue to search
1427  // for it in packs, to give broken maps or mods a chance to work
1428  if (valid == PATH_NOT_CHECKED) {
1429  valid = FS_ValidatePath(normalized);
1430  }
1431  if (valid == PATH_INVALID) {
1432  continue;
1433  }
1434  // check a file in the directory tree
1435  len = Q_concat(fullpath, sizeof(fullpath),
1436  search->filename, "/", normalized, NULL);
1437  if (len >= sizeof(fullpath)) {
1438  ret = Q_ERR_NAMETOOLONG;
1439  goto fail;
1440  }
1441 
1442  ret = open_from_disk(file, fullpath);
1443  if (ret != Q_ERR_NOENT)
1444  return ret;
1445 
1446 #ifndef _WIN32
1447  if (valid == PATH_MIXED_CASE) {
1448  // convert to lower case and retry
1450  Q_strlwr(fullpath + strlen(search->filename) + 1);
1451  ret = open_from_disk(file, fullpath);
1452  if (ret != Q_ERR_NOENT)
1453  return ret;
1454  }
1455 #endif
1456  }
1457  }
1458 
1459  // return error if path was checked and found to be invalid
1460  ret = valid ? Q_ERR_NOENT : Q_ERR_INVALID_PATH;
1461 
1462 fail:
1463  FS_DPrintf("%s: %s: %s\n", __func__, normalized, Q_ErrorString(ret));
1464  return ret;
1465 }

Referenced by expand_open_file_read().

◆ open_file_write()

static ssize_t open_file_write ( file_t file,
const char *  name 
)
static

Definition at line 887 of file files.c.

888 {
889  char normalized[MAX_OSPATH], fullpath[MAX_OSPATH];
890  FILE *fp;
891  char mode_str[8];
892  unsigned mode;
893  size_t len;
894  long pos;
895  qerror_t ret;
896 
897  // normalize the path
898  len = FS_NormalizePathBuffer(normalized, name, sizeof(normalized));
899  if (len >= sizeof(normalized)) {
900  return Q_ERR_NAMETOOLONG;
901  }
902 
903  // reject empty paths
904  if (len == 0) {
905  return Q_ERR_NAMETOOSHORT;
906  }
907 
908  // check for bad characters
909  if (!FS_ValidatePath(normalized)) {
910  ret = Q_ERR_INVALID_PATH;
911  goto fail1;
912  }
913 
914  // expand the path
915  if ((file->mode & FS_PATH_MASK) == FS_PATH_BASE) {
916  if (sys_homedir->string[0]) {
917  len = Q_concat(fullpath, sizeof(fullpath),
918  sys_homedir->string, "/" BASEGAME "/", normalized, NULL);
919  } else {
920  len = Q_concat(fullpath, sizeof(fullpath),
921  sys_basedir->string, "/" BASEGAME "/", normalized, NULL);
922  }
923  } else {
924  len = Q_concat(fullpath, sizeof(fullpath),
925  fs_gamedir, "/", normalized, NULL);
926  }
927  if (len >= sizeof(fullpath)) {
928  ret = Q_ERR_NAMETOOLONG;
929  goto fail1;
930  }
931 
932  mode = file->mode & FS_MODE_MASK;
933  switch (mode) {
934  case FS_MODE_APPEND:
935  strcpy(mode_str, "a");
936  break;
937  case FS_MODE_WRITE:
938  strcpy(mode_str, "w");
939  if (file->mode & FS_FLAG_EXCL)
940  strcat(mode_str, "x");
941  break;
942  case FS_MODE_RDWR:
943  // this mode is only used by client downloading code
944  // similar to FS_MODE_APPEND, but does not create
945  // the file if it does not exist
946  strcpy(mode_str, "r+");
947  break;
948  default:
949  ret = Q_ERR_INVAL;
950  goto fail1;
951  }
952 
953  // open in binary mode by default
954  if (!(file->mode & FS_FLAG_TEXT))
955  strcat(mode_str, "b");
956 
957  ret = FS_CreatePath(fullpath);
958  if (ret) {
959  goto fail1;
960  }
961 
962  fp = fopen_hack(fullpath, mode_str);
963  if (!fp) {
964  ret = Q_Errno();
965  goto fail1;
966  }
967 
968 #ifndef _WIN32
969  // check if this is a regular file
970  ret = get_fp_info(fp, NULL);
971  if (ret) {
972  goto fail2;
973  }
974 #endif
975 
976  switch (file->mode & FS_BUF_MASK) {
977  case FS_BUF_NONE:
978  // make it unbuffered
979  setvbuf(fp, NULL, _IONBF, BUFSIZ);
980  break;
981  case FS_BUF_LINE:
982  // make it line buffered
983  setvbuf(fp, NULL, _IOLBF, BUFSIZ);
984  break;
985  case FS_BUF_FULL:
986  // make it fully buffered
987  setvbuf(fp, NULL, _IOFBF, BUFSIZ);
988  break;
989  default:
990  // use default mode (normally fully buffered)
991  break;
992  }
993 
994  if (mode == FS_MODE_RDWR) {
995  // seek to the end of file for appending
996  if (fseek(fp, 0, SEEK_END) == -1) {
997  ret = Q_Errno();
998  goto fail2;
999  }
1000  }
1001 
1002  // return current position (non-zero for appending modes)
1003  pos = ftell(fp);
1004  if (pos == -1) {
1005  ret = Q_Errno();
1006  goto fail2;
1007  }
1008 
1009  FS_DPrintf("%s: %s: %lu bytes\n", __func__, fullpath, pos);
1010 
1011  file->type = FS_REAL;
1012  file->fp = fp;
1013  file->unique = qtrue;
1014  file->error = Q_ERR_SUCCESS;
1015  file->length = 0;
1016 
1017  return pos;
1018 
1019 fail2:
1020  fclose(fp);
1021 fail1:
1022  FS_DPrintf("%s: %s: %s\n", __func__, normalized, Q_ErrorString(ret));
1023  return ret;
1024 }

Referenced by FS_FOpenFile().

◆ open_from_disk()

static ssize_t open_from_disk ( file_t file,
const char *  fullpath 
)
static

Definition at line 1276 of file files.c.

1277 {
1278  FILE *fp;
1279  file_info_t info;
1280  qerror_t ret;
1281 
1282  FS_COUNT_OPEN;
1283 
1284  fp = fopen(fullpath, "rb");
1285  if (!fp) {
1286  ret = Q_Errno();
1287  goto fail;
1288  }
1289 
1290  ret = get_fp_info(fp, &info);
1291  if (ret) {
1292  fclose(fp);
1293  goto fail;
1294  }
1295 
1296  file->type = FS_REAL;
1297  file->fp = fp;
1298  file->unique = qtrue;
1299  file->error = Q_ERR_SUCCESS;
1300  file->length = info.size;
1301 
1302  FS_DPrintf("%s: %s: %"PRIz" bytes\n", __func__, fullpath, info.size);
1303  return info.size;
1304 
1305 fail:
1306  FS_DPrintf("%s: %s: %s\n", __func__, fullpath, Q_ErrorString(ret));
1307  return ret;
1308 }

Referenced by open_file_read().

◆ open_from_pak()

static ssize_t open_from_pak ( file_t file,
pack_t pack,
packfile_t entry,
qboolean  unique 
)
static

Definition at line 1202 of file files.c.

1203 {
1204  FILE *fp;
1205  qerror_t ret;
1206 
1207  if (unique) {
1208  fp = fopen(pack->filename, "rb");
1209  if (!fp) {
1210  ret = Q_Errno();
1211  goto fail1;
1212  }
1213  } else {
1214  fp = pack->fp;
1215  clearerr(fp);
1216  }
1217 
1218 #if USE_ZLIB
1219  if (pack->type == FS_ZIP && !entry->coherent) {
1220  ret = check_header_coherency(fp, entry);
1221  if (ret) {
1222  goto fail2;
1223  }
1224  }
1225 #endif
1226 
1227  if (fseek(fp, (long)entry->filepos, SEEK_SET) == -1) {
1228  ret = Q_Errno();
1229  goto fail2;
1230  }
1231 
1232  file->type = pack->type;
1233  file->fp = fp;
1234  file->entry = entry;
1235  file->pack = pack;
1236  file->unique = unique;
1237  file->error = Q_ERR_SUCCESS;
1238  file->rest_out = entry->filelen;
1239  file->length = entry->filelen;
1240 
1241 #if USE_ZLIB
1242  if (pack->type == FS_ZIP) {
1243  if (file->mode & FS_FLAG_DEFLATE) {
1244  // server wants raw deflated data for downloads
1245  file->type = FS_PAK;
1246  file->rest_out = entry->complen;
1247  file->length = entry->complen;
1248  } else if (entry->compmtd) {
1249  open_zip_file(file);
1250  } else {
1251  // stored, just pretend it's a packfile
1252  file->type = FS_PAK;
1253  }
1254  }
1255 #endif
1256 
1257  if (unique) {
1258  // reference source pak
1259  pack_get(pack);
1260  }
1261 
1262  FS_DPrintf("%s: %s/%s: %"PRIz" bytes\n",
1263  __func__, pack->filename, entry->name, file->length);
1264 
1265  return file->length;
1266 
1267 fail2:
1268  if (unique) {
1269  fclose(fp);
1270  }
1271 fail1:
1272  FS_DPrintf("%s: %s/%s: %s\n", __func__, pack->filename, entry->name, Q_ErrorString(ret));
1273  return ret;
1274 }

Referenced by open_file_read().

◆ pack_alloc()

static pack_t* pack_alloc ( FILE *  fp,
filetype_t  type,
const char *  name,
unsigned  num_files,
size_t  names_len 
)
static

Definition at line 2080 of file files.c.

2082 {
2083  pack_t *pack;
2084  unsigned hash_size;
2085  size_t len;
2086 
2087  hash_size = npot32(num_files / 3);
2088 
2089  len = strlen(name) + 1;
2090  pack = FS_Malloc(sizeof(pack_t) +
2091  num_files * sizeof(packfile_t) +
2092  hash_size * sizeof(packfile_t *) +
2093  len + names_len);
2094  pack->type = type;
2095  pack->refcount = 0;
2096  pack->fp = fp;
2097  pack->num_files = num_files;
2098  pack->hash_size = hash_size;
2099  pack->files = (packfile_t *)(pack + 1);
2100  pack->file_hash = (packfile_t **)(pack->files + num_files);
2101  pack->filename = (char *)(pack->file_hash + hash_size);
2102  pack->names = pack->filename + len;
2103  memcpy(pack->filename, name, len);
2104  memset(pack->file_hash, 0, hash_size * sizeof(packfile_t *));
2105 
2106  return pack;
2107 }

Referenced by load_pak_file().

◆ pack_get()

static pack_t * pack_get ( pack_t pack)
static

Definition at line 2057 of file files.c.

2058 {
2059  pack->refcount++;
2060  return pack;
2061 }

Referenced by open_from_pak(), and q_printf().

◆ pack_hash_file()

static void pack_hash_file ( pack_t pack,
packfile_t file 
)
static

Definition at line 2110 of file files.c.

2111 {
2112  unsigned hash;
2113 
2114  file->namelen = FS_NormalizePath(file->name, file->name);
2115 
2116  hash = FS_HashPath(file->name, pack->hash_size);
2117  file->hash_next = pack->file_hash[hash];
2118  pack->file_hash[hash] = file;
2119 }

Referenced by load_pak_file().

◆ pack_put()

static void pack_put ( pack_t pack)
static

Definition at line 2064 of file files.c.

2065 {
2066  if (!pack) {
2067  return;
2068  }
2069  if (!pack->refcount) {
2070  Com_Error(ERR_FATAL, "%s: refcount already zero", __func__);
2071  }
2072  if (!--pack->refcount) {
2073  FS_DPrintf("Freeing packfile %s\n", pack->filename);
2074  fclose(pack->fp);
2075  Z_Free(pack);
2076  }
2077 }

Referenced by free_search_path(), and FS_FCloseFile().

◆ pakcmp()

static int pakcmp ( const void p1,
const void p2 
)
static

Definition at line 2487 of file files.c.

2488 {
2489  char *s1 = *(char **)p1;
2490  char *s2 = *(char **)p2;
2491 
2492  if (!Q_stricmpn(s1, "pak", 3)) {
2493  if (!Q_stricmpn(s2, "pak", 3)) {
2494  unsigned long n1 = strtoul(s1 + 3, &s1, 10);
2495  unsigned long n2 = strtoul(s2 + 3, &s2, 10);
2496  if (n1 > n2) {
2497  return 1;
2498  }
2499  if (n1 < n2) {
2500  return -1;
2501  }
2502  goto alphacmp;
2503  }
2504  return -1;
2505  }
2506  if (!Q_stricmpn(s2, "pak", 3)) {
2507  return 1;
2508  }
2509 
2510 alphacmp:
2511  return Q_stricmp(s1, s2);
2512 }

Referenced by q_printf().

◆ print_file_list()

static void print_file_list ( const char *  path,
const char *  ext,
unsigned  flags 
)
static

Definition at line 2977 of file files.c.

2978 {
2979  void **list;
2980  int i, listed, total;
2981 
2982  list = FS_ListFiles(path, ext, flags, &total);
2983 
2984  // don't list too many files to avoid console spam
2985  listed = total > 128 ? 128 : total;
2986  for (i = 0; i < listed; i++) {
2987  Com_Printf("%s\n", (char *)list[i]);
2988  }
2989 
2990  FS_FreeList(list);
2991 
2992  if (listed == total) {
2993  Com_Printf("%i files listed\n", listed);
2994  } else {
2995  Com_Printf("%i files listed (%d files more)\n", listed, total - listed);
2996  }
2997 }

Referenced by FS_Dir_f(), and FS_FDir_f().

◆ q_printf()

static void q_printf ( ,
 
)
static

Definition at line 2516 of file files.c.

2517 {
2518  va_list argptr;
2519  searchpath_t *search;
2520  pack_t *pack;
2521  void *files[MAX_LISTED_FILES];
2522  int i, count;
2523  char path[MAX_OSPATH];
2524  size_t len;
2525 
2526  va_start(argptr, fmt);
2527  len = Q_vsnprintf(fs_gamedir, sizeof(fs_gamedir), fmt, argptr);
2528  va_end(argptr);
2529 
2530  if (len >= sizeof(fs_gamedir)) {
2531  Com_EPrintf("%s: refusing oversize path\n", __func__);
2532  return;
2533  }
2534 
2535 #ifdef _WIN32
2537 #endif
2538 
2539 #if USE_ZLIB
2540 #define PAK_EXT ".pak;.pkz"
2541 #else
2542 #define PAK_EXT ".pak"
2543 #endif
2544 
2545  // add any pack files
2546  count = 0;
2547  Sys_ListFiles_r(fs_gamedir, PAK_EXT, 0, 0, &count, files, 0);
2548 
2549  // Can't exit early for game directory
2550  if (!(mode & FS_PATH_GAME) && !count) {
2551  return;
2552  }
2553 
2554  qsort(files, count, sizeof(files[0]), pakcmp);
2555 
2556  for (i = 0; i < count; i++) {
2557  len = Q_concat(path, sizeof(path), fs_gamedir, "/", files[i], NULL);
2558  if (len >= sizeof(path)) {
2559  Com_EPrintf("%s: refusing oversize path\n", __func__);
2560  continue;
2561  }
2562 #if USE_ZLIB
2563  // FIXME: guess packfile type by contents instead?
2564  if (len > 4 && !Q_stricmp(path + len - 4, ".pkz"))
2565  pack = load_zip_file(path);
2566  else
2567 #endif
2568  pack = load_pak_file(path);
2569  if (!pack)
2570  continue;
2571  search = FS_Malloc(sizeof(searchpath_t));
2572  search->mode = mode;
2573  search->filename[0] = 0;
2574  search->pack = pack_get(pack);
2575  search->next = fs_searchpaths;
2576  fs_searchpaths = search;
2577  }
2578 
2579  for (i = 0; i < count; i++) {
2580  Z_Free(files[i]);
2581  }
2582 
2583  // add the directory to the search path
2584  // the directory has priority over the pak files
2585  search = FS_Malloc(sizeof(searchpath_t) + len);
2586  search->mode = mode;
2587  search->pack = NULL;
2588  memcpy(search->filename, fs_gamedir, len + 1);
2589  search->next = fs_searchpaths;
2590  fs_searchpaths = search;
2591 
2592 }

◆ read_pak_file()

static ssize_t read_pak_file ( file_t file,
void buf,
size_t  len 
)
static

Definition at line 1504 of file files.c.

1505 {
1506  size_t result;
1507 
1508  if (len > file->rest_out) {
1509  len = file->rest_out;
1510  }
1511  if (!len) {
1512  return 0;
1513  }
1514 
1515  result = fread(buf, 1, len, file->fp);
1516  if (result != len) {
1517  file->error = FS_ERR_READ(file->fp);
1518  if (!result) {
1519  return file->error;
1520  }
1521  }
1522 
1523  file->rest_out -= result;
1524  return result;
1525 }

Referenced by FS_Read().

◆ read_phys_file()

static ssize_t read_phys_file ( file_t file,
void buf,
size_t  len 
)
static

Definition at line 1527 of file files.c.

1528 {
1529  size_t result;
1530 
1531  result = fread(buf, 1, len, file->fp);
1532  if (result != len && ferror(file->fp)) {
1533  file->error = Q_Errno();
1534  if (!result) {
1535  return file->error;
1536  }
1537  }
1538 
1539  return result;
1540 }

Referenced by FS_Read().

◆ seek_pak_file()

static qerror_t seek_pak_file ( file_t file,
off_t  offset 
)
static

Definition at line 537 of file files.c.

538 {
539  packfile_t *entry = file->entry;
540  long filepos;
541 
542  if (offset > entry->filelen)
543  offset = entry->filelen;
544 
545  if (entry->filepos > LONG_MAX - offset)
546  return Q_ERR_INVAL;
547 
548  filepos = entry->filepos + offset;
549  if (fseek(file->fp, filepos, SEEK_SET) == -1)
550  return Q_Errno();
551 
552  file->rest_out = entry->filelen - offset;
553 
554  return Q_ERR_SUCCESS;
555 }

Referenced by FS_Seek().

◆ setup_base_paths()

static void setup_base_paths ( void  )
static

Definition at line 3499 of file files.c.

3500 {
3501  // base paths have both BASE and GAME bits set by default
3502  // the GAME bit will be removed once gamedir is set,
3503  // and will be put back once gamedir is reset to basegame
3504  add_game_dir(FS_PATH_BASE | FS_PATH_GAME, "%s/"BASEGAME, sys_basedir->string);
3506 }

Referenced by fs_game_changed(), and FS_Restart().

◆ setup_game_paths()

static void setup_game_paths ( void  )
static

Definition at line 3509 of file files.c.

3510 {
3511  searchpath_t *path;
3512 
3513  if (fs_game->string[0]) {
3514  // add system path first
3515  add_game_dir(FS_PATH_GAME, "%s/%s", sys_basedir->string, fs_game->string);
3516 
3517  // home paths override system paths
3518  if (sys_homedir->string[0]) {
3519  add_game_dir(FS_PATH_BASE, "%s/"BASEGAME, sys_homedir->string);
3520  add_game_dir(FS_PATH_GAME, "%s/%s", sys_homedir->string, fs_game->string);
3521  }
3522 
3523  // remove the game bit from base paths
3524  for (path = fs_base_searchpaths; path; path = path->next) {
3525  path->mode &= ~FS_PATH_GAME;
3526  }
3527 
3528  // this var is set for compatibility with server browsers, etc
3529  Cvar_FullSet("gamedir", fs_game->string, CVAR_ROM | CVAR_SERVERINFO, FROM_CODE);
3530 
3531  } else {
3532  if (sys_homedir->string[0]) {
3533  add_game_dir(FS_PATH_BASE | FS_PATH_GAME,
3534  "%s/"BASEGAME, sys_homedir->string);
3535  }
3536 
3537  // add the game bit to base paths
3538  for (path = fs_base_searchpaths; path; path = path->next) {
3539  path->mode |= FS_PATH_GAME;
3540  }
3541 
3542  Cvar_FullSet("gamedir", "", CVAR_ROM, FROM_CODE);
3543  }
3544 
3545  // this var is used by the game library to find it's home directory
3546  Cvar_FullSet("fs_gamedir", fs_gamedir, CVAR_ROM, FROM_CODE);
3547 }

Referenced by fs_game_changed(), and FS_Restart().

◆ validate_char()

static qboolean validate_char ( int  c)
inlinestatic

Definition at line 251 of file files.c.

252 {
253  if (!Q_isprint(c))
254  return qfalse;
255 
256 #ifdef _WIN32
257  if (strchr("<>:\"|?*", c))
258  return qfalse;
259 #endif
260 
261  return qtrue;
262 }

Referenced by cleanup_path(), and FS_ValidatePath().

Variable Documentation

◆ c_fs

const cmdreg_t c_fs[]
static
Initial value:
= {
{ "path", FS_Path_f },
{ "fdir", FS_FDir_f },
{ "dir", FS_Dir_f },
{ "whereis", FS_WhereIs_f },
{ "link", FS_Link_f, FS_Link_c },
{ "unlink", FS_UnLink_f, FS_Link_c },
{ "softlink", FS_Link_f, FS_Link_c },
{ "softunlink", FS_UnLink_f, FS_Link_c },
{ "fs_restart", FS_Restart_f },
{ NULL }
}

Definition at line 3592 of file files.c.

Referenced by FS_Init(), and FS_Shutdown().

◆ fs_base_searchpaths

searchpath_t* fs_base_searchpaths
static

Definition at line 175 of file files.c.

Referenced by free_game_paths(), fs_game_changed(), setup_base_paths(), and setup_game_paths().

◆ fs_files

file_t fs_files[MAX_FILE_HANDLES]
static

Definition at line 180 of file files.c.

Referenced by alloc_handle(), file_for_handle(), and FS_Shutdown().

◆ fs_game

◆ fs_gamedir

◆ fs_hard_links

list_t fs_hard_links
static

◆ fs_searchpaths

◆ fs_shareware

cvar_t* fs_shareware

Definition at line 204 of file files.c.

Referenced by CL_Connect_f(), FS_Init(), and Qcommon_Init().

◆ fs_soft_links

list_t fs_soft_links
static
read_phys_file
static ssize_t read_phys_file(file_t *file, void *buf, size_t len)
Definition: files.c:1527
Q_strlcat
size_t Q_strlcat(char *dst, const char *src, size_t size)
Definition: shared.c:735
handle
static void * handle
Definition: dynamic.c:52
FS_Link_g
static void FS_Link_g(genctx_t *ctx)
Definition: files.c:3315
FS_CopyInfo
file_info_t * FS_CopyInfo(const char *name, size_t size, time_t ctime, time_t mtime)
Definition: files.c:2599
Cvar_Set
cvar_t * Cvar_Set(const char *var_name, const char *value)
Definition: cvar.c:466
easy_open_read
static qhandle_t easy_open_read(char *buf, size_t size, unsigned mode, const char *dir, const char *name, const char *ext)
Definition: files.c:1730
FOR_EACH_SYMLINK
#define FOR_EACH_SYMLINK(link, list)
Definition: files.c:85
pack_t::files
packfile_t * files
Definition: files.c:133
fs_files
static file_t fs_files[MAX_FILE_HANDLES]
Definition: files.c:180
Sys_ListFiles_r
void Sys_ListFiles_r(const char *path, const char *filter, unsigned flags, size_t baselen, int *count_p, void **files, int depth)
Definition: system.c:868
file_t::rest_out
size_t rest_out
Definition: files.c:158
read_pak_file
static ssize_t read_pak_file(file_t *file, void *buf, size_t len)
Definition: files.c:1504
pack_put
static void pack_put(pack_t *pack)
Definition: files.c:2064
Com_AddConfigFile
void Com_AddConfigFile(const char *name, unsigned flags)
Definition: common.c:876
cmd_optarg
char * cmd_optarg
Definition: cmd.c:848
FS_COUNT_STRLWR
#define FS_COUNT_STRLWR
Definition: files.c:195
Q_snprintf
size_t Q_snprintf(char *dest, size_t size, const char *fmt,...)
Definition: shared.c:846
FS_Restart_f
static void FS_Restart_f(void)
Definition: files.c:3587
easy_open_write
static qhandle_t easy_open_write(char *buf, size_t size, unsigned mode, const char *dir, const char *name, const char *ext)
Definition: files.c:1781
FS_Read
ssize_t FS_Read(void *buf, size_t len, qhandle_t f)
Definition: files.c:1547
FS_ExtCmp
qboolean FS_ExtCmp(const char *ext, const char *name)
Definition: files.c:2649
sys_homedir
cvar_t * sys_homedir
Definition: system.c:52
COM_IsPath
qboolean COM_IsPath(const char *s)
Definition: shared.c:348
FS_ERR_WRITE
#define FS_ERR_WRITE(fp)
Definition: files.c:650
st
spawn_temp_t st
Definition: g_main.c:25
FS_FilterFile
qerror_t FS_FilterFile(qhandle_t f)
Definition: files.c:661
packfile_s::filelen
size_t filelen
Definition: files.c:118
Cvar_Get
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags)
Definition: cvar.c:257
Q_ErrorString
const char * Q_ErrorString(qerror_t error)
Definition: error.c:51
Z_LeakTest
void Z_LeakTest(memtag_t tag)
Definition: zone.c:120
FS_Path_f
static void FS_Path_f(void)
Definition: files.c:3223
open_file_write
static ssize_t open_file_write(file_t *file, const char *name)
Definition: files.c:887
pack_alloc
static pack_t * pack_alloc(FILE *fp, filetype_t type, const char *name, unsigned num_files, size_t names_len)
Definition: files.c:2080
file_t::pack
pack_t * pack
Definition: files.c:155
FS_COUNT_READ
#define FS_COUNT_READ
Definition: files.c:192
FS_FreeList
void FS_FreeList(void **list)
Definition: files.c:2939
FS_FDir_f
static void FS_FDir_f(void)
Definition: files.c:3004
FS_ReplaceSeparators
char * FS_ReplaceSeparators(char *s, int separator)
Definition: files.c:235
pack_get
static pack_t * pack_get(pack_t *pack)
Definition: files.c:2057
file_t::length
size_t length
Definition: files.c:159
PAK_EXT
#define PAK_EXT
validate_char
static qboolean validate_char(int c)
Definition: files.c:251
FS_FREE
@ FS_FREE
Definition: files.c:96
Cmd_PrintUsage
void Cmd_PrintUsage(const cmd_option_t *opt, const char *suffix)
Definition: cmd.c:1143
pack_t::type
filetype_t type
Definition: files.c:129
Q_vsnprintf
size_t Q_vsnprintf(char *dest, size_t size, const char *fmt, va_list argptr)
Definition: shared.c:791
ext
char ext[4]
Definition: images.c:657
MAX_FILE_HANDLES
#define MAX_FILE_HANDLES
Definition: files.c:59
pack_t
Definition: files.c:128
FS_REAL
@ FS_REAL
Definition: files.c:97
PATH_NOT_CHECKED
#define PATH_NOT_CHECKED
Definition: files.c:83
Cmd_Deregister
void Cmd_Deregister(const cmdreg_t *reg)
Definition: cmd.c:1580
FOR_EACH_SYMLINK_SAFE
#define FOR_EACH_SYMLINK_SAFE(link, next, list)
Definition: files.c:88
file_t::type
filetype_t type
Definition: files.c:148
FS_ERR_READ
#define FS_ERR_READ(fp)
Definition: files.c:648
Cmd_Argv
char * Cmd_Argv(int arg)
Definition: cmd.c:899
Cmd_Argc
int Cmd_Argc(void)
Definition: cmd.c:889
Prompt_AddMatch
qboolean Prompt_AddMatch(genctx_t *ctx, const char *s)
Definition: prompt.c:149
searchpath_s::next
struct searchpath_s * next
Definition: files.c:141
file_t::unique
qboolean unique
Definition: files.c:156
fopen_hack
static FILE * fopen_hack(const char *path, const char *mode)
Definition: files.c:844
packfile_s::filepos
size_t filepos
Definition: files.c:117
expand_open_file_read
static ssize_t expand_open_file_read(file_t *file, const char *name, qboolean unique)
Definition: files.c:1468
searchpath_s
Definition: files.c:140
FS_ValidatePath
int FS_ValidatePath(const char *s)
Definition: files.c:271
FS_FOpenFile
ssize_t FS_FOpenFile(const char *name, qhandle_t *f, unsigned mode)
Definition: files.c:1692
open_from_disk
static ssize_t open_from_disk(file_t *file, const char *fullpath)
Definition: files.c:1276
free_game_paths
static void free_game_paths(void)
Definition: files.c:3487
FS_COUNT_STRCMP
#define FS_COUNT_STRCMP
Definition: files.c:194
setup_base_paths
static void setup_base_paths(void)
Definition: files.c:3499
FS_COUNT_OPEN
#define FS_COUNT_OPEN
Definition: files.c:193
FS_NormalizePathBuffer
size_t FS_NormalizePathBuffer(char *out, const char *in, size_t size)
Definition: files.c:400
Z_TagMalloc
void * Z_TagMalloc(size_t size, memtag_t tag)
Definition: zone.c:275
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
FS_Link_c
static void FS_Link_c(genctx_t *ctx, int argnum)
Definition: files.c:3332
Cmd_ParseOptions
int Cmd_ParseOptions(const cmd_option_t *opt)
Definition: cmd.c:1057
FS_DPrintf
#define FS_DPrintf(...)
Definition: files.c:80
Z_Free
void Z_Free(void *ptr)
Definition: zone.c:147
Cmd_Register
void Cmd_Register(const cmdreg_t *reg)
Definition: cmd.c:1572
fs_shareware
cvar_t * fs_shareware
Definition: files.c:204
FS_ListFiles
void ** FS_ListFiles(const char *path, const char *filter, unsigned flags, int *count_p)
Definition: files.c:2716
pakcmp
static int pakcmp(const void *p1, const void *p2)
Definition: files.c:2487
free_all_links
static void free_all_links(list_t *list)
Definition: files.c:3339
packfile_s::namelen
size_t namelen
Definition: files.c:116
fs_game_changed
static void fs_game_changed(cvar_t *self)
Definition: files.c:3650
fs_base_searchpaths
static searchpath_t * fs_base_searchpaths
Definition: files.c:175
FS_WildCmp
qboolean FS_WildCmp(const char *filter, const char *string)
Definition: files.c:2636
fs_game
cvar_t * fs_game
Definition: files.c:202
pack_hash_file
static void pack_hash_file(pack_t *pack, packfile_t *file)
Definition: files.c:2110
pack_t::file_hash
packfile_t ** file_hash
Definition: files.c:134
Q_strlcpy
size_t Q_strlcpy(char *dst, const char *src, size_t size)
Definition: shared.c:715
free_search_path
static void free_search_path(searchpath_t *path)
Definition: files.c:3469
get_fp_info
static qerror_t get_fp_info(FILE *fp, file_info_t *info)
Definition: files.c:817
c_fs
static const cmdreg_t c_fs[]
Definition: files.c:3592
alloc_handle
static file_t * alloc_handle(qhandle_t *f)
Definition: files.c:415
print_file_list
static void print_file_list(const char *path, const char *ext, unsigned flags)
Definition: files.c:2977
file_for_handle
static file_t * file_for_handle(qhandle_t f)
Definition: files.c:430
Cvar_FullSet
cvar_t * Cvar_FullSet(const char *var_name, const char *value, int flags, from_t from)
Definition: cvar.c:437
file_t
Definition: files.c:147
seek_pak_file
static qerror_t seek_pak_file(file_t *file, off_t offset)
Definition: files.c:537
Com_WildCmpEx
qboolean Com_WildCmpEx(const char *filter, const char *string, int term, qboolean ignorecase)
Definition: utils.c:122
FS_WhereIs_f
static void FS_WhereIs_f(void)
Definition: files.c:3055
free_all_paths
static void free_all_paths(void)
Definition: files.c:3475
searchpath_s::mode
unsigned mode
Definition: files.c:142
FS_Write
ssize_t FS_Write(const void *buf, size_t len, qhandle_t f)
Definition: files.c:1643
pack_t::num_files
unsigned num_files
Definition: files.c:132
packfile_s::name
char * name
Definition: files.c:115
c
statCounters_t c
Definition: main.c:30
CL_RestartFilesystem
void CL_RestartFilesystem(qboolean total)
Definition: main.c:2418
pack_t::hash_size
unsigned hash_size
Definition: files.c:135
searchpath_s::pack
pack_t * pack
Definition: files.c:143
file_t::mode
unsigned mode
Definition: files.c:149
fs_searchpaths
static searchpath_t * fs_searchpaths
Definition: files.c:174
file_t::entry
packfile_t * entry
Definition: files.c:154
COM_SkipPath
char * COM_SkipPath(const char *pathname)
Definition: shared.c:152
Cmd_PrintHelp
void Cmd_PrintHelp(const cmd_option_t *opt)
Definition: cmd.c:1160
setup_game_paths
static void setup_game_paths(void)
Definition: files.c:3509
Cmd_PrintHint
void Cmd_PrintHint(void)
Definition: cmd.c:1178
err
int err
Definition: win.h:24
expand_links
static symlink_t * expand_links(list_t *list, char *buffer, size_t *len_p)
Definition: files.c:456
packfile_s
Definition: files.c:114
fs_soft_links
static list_t fs_soft_links
Definition: files.c:178
filetype_t
filetype_t
Definition: files.c:95
pack
static uint32_t pack(uint64_t n)
Definition: hq2x.c:99
FS_Dir_f
static void FS_Dir_f(void)
Definition: files.c:3029
sys_basedir
cvar_t * sys_basedir
Definition: system.c:50
FS_UnLink_f
static void FS_UnLink_f(void)
Definition: files.c:3351
FS_CreatePath
qerror_t FS_CreatePath(char *path)
Definition: files.c:605
FS_FCloseFile
void FS_FCloseFile(qhandle_t f)
Definition: files.c:759
Q_concat
size_t Q_concat(char *dest, size_t size,...)
Definition: shared.c:758
open_from_pak
static ssize_t open_from_pak(file_t *file, pack_t *pack, packfile_t *entry, qboolean unique)
Definition: files.c:1202
alphacmp
static int alphacmp(const void *p1, const void *p2)
Definition: files.c:2703
file_t::error
qerror_t error
Definition: files.c:157
cleanup_path
static void cleanup_path(char *s)
Definition: files.c:447
packfile_s::hash_next
struct packfile_s * hash_next
Definition: files.c:125
FS_PAK
@ FS_PAK
Definition: files.c:98
file_t::fp
FILE * fp
Definition: files.c:150
COM_FileExtension
char * COM_FileExtension(const char *in)
Definition: shared.c:199
open_file_read
static ssize_t open_file_read(file_t *file, const char *normalized, size_t namelen, qboolean unique)
Definition: files.c:1359
FS_Link_f
static void FS_Link_f(void)
Definition: files.c:3403
FS_BAD
@ FS_BAD
Definition: files.c:103
fs_gamedir
char fs_gamedir[MAX_OSPATH]
Definition: files.c:171
pack_t::filename
char * filename
Definition: files.c:137
infocmp
static int infocmp(const void *p1, const void *p2)
Definition: files.c:2695
load_pak_file
static pack_t * load_pak_file(const char *packfile)
Definition: files.c:2123
searchpath_s::filename
char filename[1]
Definition: files.c:144
FS_NormalizePath
size_t FS_NormalizePath(char *out, const char *in)
Definition: files.c:331
fs_hard_links
static list_t fs_hard_links
Definition: files.c:177
get_path_info
static qerror_t get_path_info(const char *path, file_info_t *info)
Definition: files.c:795