files.c

Go to the documentation of this file.
00001 
00011 /*
00012 Copyright (C) 1997-2001 Id Software, Inc.
00013 
00014 This program is free software; you can redistribute it and/or
00015 modify it under the terms of the GNU General Public License
00016 as published by the Free Software Foundation; either version 2
00017 of the License, or (at your option) any later version.
00018 
00019 This program is distributed in the hope that it will be useful,
00020 but WITHOUT ANY WARRANTY; without even the implied warranty of
00021 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 
00023 See the GNU General Public License for more details.
00024 
00025 You should have received a copy of the GNU General Public License
00026 along with this program; if not, write to the Free Software
00027 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00028 
00029 */
00030 
00031 #include "common.h"
00032 #include "../ports/system.h"
00033 #include "../shared/defines.h"
00034 #include "../shared/typedefs.h"
00035 #include "../shared/parse.h"
00036 #include <unistd.h>
00037 
00039 static int fs_openedFiles;
00040 
00041 static filelink_t *fs_links;
00042 
00043 static searchpath_t *fs_searchpaths;
00044 
00049 const char *FS_Gamedir (void)
00050 {
00051     searchpath_t *search;
00052 
00053     for (search = fs_searchpaths; search; search = search->next) {
00054         if (search->pack == NULL)
00055             return search->filename;
00056     }
00057 
00058     return NULL;
00059 }
00060 
00066 void FS_NormPath (char *path)
00067 {
00068     Sys_NormPath(path);
00069 }
00070 
00075 int FS_FileLength (qFILE * f)
00076 {
00077     int pos;
00078     int end;
00079 
00080     if (!f->f)
00081         return 0;
00082 
00083     pos = ftell(f->f);
00084     fseek(f->f, 0, SEEK_END);
00085     end = ftell(f->f);
00086     fseek(f->f, pos, SEEK_SET);
00087 
00088     return end;
00089 }
00090 
00097 void FS_CreatePath (const char *path)
00098 {
00099     char pathCopy[MAX_OSPATH];
00100     char *ofs;
00101 
00102     Q_strncpyz(pathCopy, path, sizeof(pathCopy));
00103 
00104     for (ofs = pathCopy + 1; *ofs; ofs++) {
00105         /* create the directory */
00106         if (*ofs == '/') {
00107             *ofs = 0;
00108             Sys_Mkdir(pathCopy);
00109             *ofs = '/';
00110         }
00111     }
00112 }
00113 
00118 void FS_CloseFile (qFILE * f)
00119 {
00120     if (f->f) {
00121         fclose(f->f);
00122         fs_openedFiles--;
00123     } else if (f->z) {
00124         unzCloseCurrentFile(f->z);
00125         fs_openedFiles--;
00126     }
00127     assert(fs_openedFiles >= 0);
00128 
00129     f->f = f->z = NULL;
00130 }
00131 
00141 static int FS_OpenFileSingle (const char *filename, qFILE * file, filemode_t mode)
00142 {
00143     searchpath_t *search;
00144     char netpath[MAX_OSPATH];
00145     int i;
00146     filelink_t *link;
00147 
00148     file->z = file->f = NULL;
00149 
00150     /* open for write or append in gamedir and return */
00151     if (mode == FILE_WRITE || mode == FILE_APPEND) {
00152         Com_sprintf(netpath, sizeof(netpath), "%s/%s", FS_Gamedir(), filename);
00153         FS_CreatePath(netpath);
00154 
00155         file->f = fopen(netpath, (mode == FILE_WRITE ? "wb" : "ab"));
00156         if (file->f) {
00157             fs_openedFiles++;
00158             return 0;
00159         }
00160 
00161         return -1;
00162     }
00163 
00164     Q_strncpyz(file->name, filename, sizeof(file->name));
00165 
00166     /* check for links first */
00167     for (link = fs_links; link; link = link->next)
00168         if (!strncmp(filename, link->from, link->fromlength)) {
00169             Com_sprintf(netpath, sizeof(netpath), "%s%s", link->to, filename + link->fromlength);
00170             file->f = fopen(netpath, "rb");
00171             if (file->f) {
00172                 fs_openedFiles++;
00173                 return FS_FileLength(file);
00174             }
00175             Com_Printf("linked file could not be opened: %s\n", netpath);
00176             return -1;
00177         }
00178 
00179     /* search through the path, one element at a time */
00180     for (search = fs_searchpaths; search; search = search->next) {
00181         /* is the element a pak file? */
00182         if (search->pack) {
00183             /* look through all the pak file elements */
00184             pack_t *pak = search->pack;
00185             for (i = 0; i < pak->numfiles; i++)
00186                 /* found it! */
00187                 if (!Q_strcasecmp(pak->files[i].name, filename)) {
00188                     /* open a new file on the pakfile */
00189                     if (unzLocateFile(pak->handle.z, filename, 2) == UNZ_OK) {  /* found it! */
00190                         if (unzOpenCurrentFile(pak->handle.z) == UNZ_OK) {
00191                             unz_file_info info;
00192                             if (unzGetCurrentFileInfo(pak->handle.z, &info, NULL, 0, NULL, 0, NULL, 0) != UNZ_OK)
00193                                 Sys_Error("Couldn't get size of %s in %s", filename, pak->filename);
00194                             unzGetCurrentFileInfoPosition(pak->handle.z, &file->filepos);
00195                             file->z = pak->handle.z;
00196                             fs_openedFiles++;
00197                             return info.uncompressed_size;
00198                         }
00199                     }
00200                     return pak->files[i].filelen;
00201                 }
00202         } else {
00203             /* check a file in the directory tree */
00204             Com_sprintf(netpath, sizeof(netpath), "%s/%s", search->filename, filename);
00205 
00206             file->f = fopen(netpath, "rb");
00207             if (!file->f)
00208                 continue;
00209 
00210             fs_openedFiles++;
00211             return FS_FileLength(file);
00212         }
00213     }
00214 
00215     file->f = NULL;
00216     file->z = NULL;
00217     return -1;
00218 }
00219 
00220 #define PK3_SEEK_BUFFER_SIZE 65536
00221 
00228 int FS_Seek (qFILE * f, long offset, int origin)
00229 {
00230     if (f->z) {
00231         byte buffer[PK3_SEEK_BUFFER_SIZE];
00232         int remainder = offset;
00233 
00234         if (offset < 0 || origin == FS_SEEK_END) {
00235             Sys_Error("Negative offsets and FS_SEEK_END not implemented "
00236                     "for FS_Seek on pk3 file contents\n");
00237         }
00238 
00239         switch (origin) {
00240         case FS_SEEK_SET:
00241             unzSetCurrentFileInfoPosition(f->z, (unsigned long)f->filepos);
00242             unzOpenCurrentFile(f->z);
00243             /* fallthrough */
00244         case FS_SEEK_CUR:
00245             while (remainder > PK3_SEEK_BUFFER_SIZE) {
00246                 FS_Read(buffer, PK3_SEEK_BUFFER_SIZE, f);
00247                 remainder -= PK3_SEEK_BUFFER_SIZE;
00248             }
00249             FS_Read(buffer, remainder, f);
00250             return offset;
00251 
00252         default:
00253             Sys_Error("Bad origin in FS_Seek");
00254         }
00255     } else if (f->f) {
00256         int _origin;
00257         switch (origin) {
00258         case FS_SEEK_CUR:
00259             _origin = SEEK_CUR;
00260             break;
00261         case FS_SEEK_END:
00262             _origin = SEEK_END;
00263             break;
00264         case FS_SEEK_SET:
00265             _origin = SEEK_SET;
00266             break;
00267         default:
00268             Sys_Error("Bad origin in FS_Seek\n");
00269         }
00270         return fseek(f->f, offset, _origin);
00271     } else
00272         Sys_Error("FS_Seek: no file opened\n");
00273 }
00274 
00280 int FS_OpenFile (const char *filename, qFILE * file, filemode_t mode)
00281 {
00282     /* open file */
00283     return FS_OpenFileSingle(filename, file, mode);
00284 }
00285 
00291 int FS_CheckFile (const char *fmt, ...)
00292 {
00293     int result;
00294     qFILE file;
00295     va_list ap;
00296     char filename[MAX_QPATH];
00297 
00298     va_start(ap, fmt);
00299     Q_vsnprintf(filename, sizeof(filename), fmt, ap);
00300     va_end(ap);
00301 
00302     result = FS_OpenFileSingle(filename, &file, FILE_READ);
00303     if (result != -1)
00304         FS_CloseFile(&file);
00305 
00306     return result;
00307 }
00308 
00309 #define MAX_READ    0x10000     /* read in blocks of 64k */
00310 
00324 int FS_Read (void *buffer, int len, qFILE * f)
00325 {
00326     int block, remaining;
00327     int read;
00328     byte *buf;
00329     int tries;
00330 
00331     buf = (byte *) buffer;
00332 
00333     if (f->z) {
00334         read = unzReadCurrentFile(f->z, buf, len);
00335         if (read == -1)
00336             Sys_Error("FS_Read (zipfile): -1 bytes read");
00337 
00338         return read;
00339     }
00340 
00341     remaining = len;
00342     tries = 0;
00343     while (remaining) {
00344         block = remaining;
00345         if (block > MAX_READ)
00346             block = MAX_READ;
00347         read = fread(buf, 1, block, f->f);
00348 
00349         /* end of file reached */
00350         if (read != block && feof(f->f))
00351             return (len - remaining + read);
00352 
00353         if (read == 0) {
00354             /* we might have been trying to read from a CD */
00355             if (!tries)
00356                 tries = 1;
00357             else
00358                 Sys_Error("FS_Read: 0 bytes read");
00359         }
00360 
00361         if (read == -1)
00362             Sys_Error("FS_Read: -1 bytes read");
00363 
00364         /* do some progress bar thing here... */
00365         remaining -= read;
00366         buf += read;
00367     }
00368     return len;
00369 }
00370 
00379 int FS_LoadFile (const char *path, byte **buffer)
00380 {
00381     qFILE h;
00382     byte *buf;
00383     int len;
00384 
00385     /* look for it in the filesystem or pack files */
00386     len = FS_OpenFile(path, &h, FILE_READ);
00387     if (!h.f && !h.z) {
00388         if (buffer)
00389             *buffer = NULL;
00390         return -1;
00391     }
00392 
00393     if (!buffer) {
00394         FS_CloseFile(&h);
00395         return len;
00396     }
00397 
00398     assert(com_fileSysPool);
00399     buf = (byte*)_Mem_Alloc(len + 1, qtrue, com_fileSysPool, 0, path, 0);
00400     if (!buf)
00401         return -1;
00402     *buffer = buf;
00403 
00404     FS_Read(buf, len, &h);
00405     buf[len] = 0;
00406 
00407     FS_CloseFile(&h);
00408 
00409     return len;
00410 }
00411 
00412 void FS_FreeFile (void *buffer)
00413 {
00414     _Mem_Free(buffer, "FS_FreeFile", 0);
00415 }
00416 
00423 static pack_t *FS_LoadPackFile (const char *packfile)
00424 {
00425     const char *extension = Com_GetExtension(packfile);
00426 
00427     if (!strcmp(extension, "pk3") || !strcmp(extension, "zip")) {
00428         int i;
00429         pack_t *pack;
00430         packfile_t *newfiles;
00431         unz_file_info file_info;
00432         unz_global_info gi;
00433         unzFile uf = unzOpen(packfile);
00434         unsigned int err = unzGetGlobalInfo(uf, &gi);
00435         char filenameInZip[MAX_QPATH];
00436 
00437         if (err != UNZ_OK) {
00438             Com_Printf("Could not load '%s'\n", packfile);
00439             return NULL;
00440         }
00441 
00442         unzGoToFirstFile(uf);
00443         for (i = 0; i < gi.number_entry; i++) {
00444             err = unzGetCurrentFileInfo(uf, &file_info, filenameInZip, sizeof(filenameInZip), NULL, 0, NULL, 0);
00445             if (err != UNZ_OK) {
00446                 break;
00447             }
00448             unzGoToNextFile(uf);
00449         }
00450 
00451         pack = (pack_t *)Mem_PoolAlloc(sizeof(*pack), com_fileSysPool, 0);
00452         Q_strncpyz(pack->filename, packfile, sizeof(pack->filename));
00453         pack->handle.z = uf;
00454         pack->handle.f = NULL;
00455         pack->numfiles = gi.number_entry;
00456         unzGoToFirstFile(uf);
00457 
00458         /* Allocate space for array of packfile structures (filename, offset, length) */
00459         newfiles = (packfile_t *)Mem_PoolAlloc(i * sizeof(*newfiles), com_fileSysPool, 0);
00460 
00461         for (i = 0; i < gi.number_entry; i++) {
00462             err = unzGetCurrentFileInfo(uf, &file_info, filenameInZip, sizeof(filenameInZip), NULL, 0, NULL, 0);
00463             if (err != UNZ_OK)
00464                 break;
00465             Q_strlwr(filenameInZip);
00466 
00467             unzGetCurrentFileInfoPosition(uf, &newfiles[i].filepos);
00468             Q_strncpyz(newfiles[i].name, filenameInZip, sizeof(newfiles[i].name));
00469             newfiles[i].filelen = file_info.compressed_size;
00470             unzGoToNextFile(uf);
00471         }
00472         pack->files = newfiles;
00473 
00474         /* Sort our list alphabetically - also rearrange the unsigned long values */
00475         qsort((void *)pack->files, i, sizeof(*newfiles), Q_StringSort);
00476 
00477         Com_Printf("Added packfile %s (%li files)\n", packfile, gi.number_entry);
00478         return pack;
00479     } else {
00480         /* Unrecognized file type! */
00481         Com_Printf("Pack file type %s unrecognized\n", extension);
00482         return NULL;
00483     }
00484 }
00485 
00486 #define MAX_PACKFILES 1024
00487 
00488 static const char *pakFileExt[] = {
00489     "pk3", "zip", NULL
00490 };
00491 
00496 static void FS_AddGameDirectory (const char *dir)
00497 {
00498     searchpath_t *search;
00499     char **dirnames = NULL;
00500     int ndirs = 0, i;
00501     char pakfile_list[MAX_PACKFILES][MAX_OSPATH];
00502     int pakfile_count = 0;
00503     char pattern[MAX_OSPATH];
00504     const char **extList;
00505 
00506     search = fs_searchpaths;
00507     while (search) {
00508         if (!strcmp(search->filename, dir))
00509             return;
00510         search = search->next;
00511     }
00512 
00513     Com_Printf("Adding game dir: %s\n", dir);
00514 
00515     extList = pakFileExt;
00516     while (*extList) {
00517         Com_sprintf(pattern, sizeof(pattern), "%s/*.%s", dir, *extList);
00518         dirnames = FS_ListFiles(pattern, &ndirs, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM);
00519         if (dirnames != NULL) {
00520             for (i = 0; i < ndirs - 1; i++) {
00521                 if (strrchr(dirnames[i], '/')) {
00522                     Q_strncpyz(pakfile_list[pakfile_count], dirnames[i], sizeof(pakfile_list[pakfile_count]));
00523                     pakfile_count++;
00524                     if (pakfile_count >= MAX_PACKFILES) {
00525                         Com_Printf("Warning: Max allowed pakfiles reached (%i) - skipping the rest\n", MAX_PACKFILES);
00526                         break;
00527                     }
00528                 }
00529                 Mem_Free(dirnames[i]);
00530             }
00531             Mem_Free(dirnames);
00532         }
00533         extList++;
00534     }
00535 
00536     /* Sort our list alphabetically */
00537     qsort((void *)pakfile_list, pakfile_count, MAX_OSPATH, Q_StringSort);
00538 
00539     for (i = 0; i < pakfile_count; i++) {
00540         pack_t *pak = FS_LoadPackFile(pakfile_list[i]);
00541         if (!pak)
00542             continue;
00543 
00544         search = (searchpath_t *)Mem_PoolAlloc(sizeof(*search), com_fileSysPool, 0);
00545         search->pack = pak;
00546         search->next = fs_searchpaths;
00547         fs_searchpaths = search;
00548     }
00549 
00550     /* add the directory to the search path */
00551     search = (searchpath_t *)Mem_PoolAlloc(sizeof(*search), com_fileSysPool, 0);
00552     Q_strncpyz(search->filename, dir, sizeof(search->filename));
00553     search->next = fs_searchpaths;
00554     fs_searchpaths = search;
00555 }
00556 
00564 char **FS_ListFiles (const char *findname, int *numfiles, unsigned musthave, unsigned canthave)
00565 {
00566     char *s;
00567     int nfiles = 0, i;
00568     char **list = NULL;
00569     char tempList[MAX_FILES][MAX_OSPATH];
00570 
00571     *numfiles = 0;
00572 
00573     s = Sys_FindFirst(findname, musthave, canthave);
00574     while (s) {
00575         if (s[strlen(s) - 1] != '.')
00576             nfiles++;
00577         s = Sys_FindNext(musthave, canthave);
00578     }
00579     Sys_FindClose();
00580 
00581     if (!nfiles)
00582         return NULL;
00583 
00584     nfiles++; /* add space for a guard */
00585     *numfiles = nfiles;
00586 
00587     list = (char **)Mem_PoolAlloc(sizeof(char*) * nfiles, com_fileSysPool, 0);
00588     memset(tempList, 0, sizeof(tempList));
00589 
00590     s = Sys_FindFirst(findname, musthave, canthave);
00591     nfiles = 0;
00592     while (s) {
00593         if (s[strlen(s) - 1] != '.') {
00594             Q_strncpyz(tempList[nfiles], s, sizeof(tempList[nfiles]));
00595 #ifdef _WIN32
00596             Q_strlwr(tempList[nfiles]);
00597 #endif
00598             nfiles++;
00599             if (nfiles >= MAX_FILES)
00600                 break;
00601         }
00602         s = Sys_FindNext(musthave, canthave);
00603     }
00604     Sys_FindClose();
00605 
00606     qsort(tempList, nfiles, MAX_OSPATH, Q_StringSort);
00607     for (i = 0; i < nfiles; i++) {
00608         list[i] = Mem_PoolStrDup(tempList[i], com_fileSysPool, 0);
00609     }
00610 
00611     return list;
00612 }
00613 
00618 const char *FS_NextPath (const char *prevpath)
00619 {
00620     searchpath_t *s;
00621     char *prev;
00622 
00623     if (!prevpath)
00624         return FS_Gamedir();
00625 
00626     prev = NULL;
00627     for (s = fs_searchpaths; s; s = s->next) {
00628         if (s->pack)
00629             continue;
00630         if (prev && !strcmp(prevpath, prev))
00631             return s->filename;
00632         prev = s->filename;
00633     }
00634 
00635     return NULL;
00636 }
00637 
00642 static void FS_AddHomeAsGameDirectory (const char *dir)
00643 {
00644     char gdir[MAX_OSPATH];
00645     char *homedir = Sys_GetHomeDirectory();
00646 
00647     if (homedir) {
00648 #ifdef _WIN32
00649         Com_sprintf(gdir, sizeof(gdir), "%s/"UFO_VERSION"/%s", homedir, dir);
00650 #elif defined (__APPLE__) || defined (MACOSX)
00651         Com_sprintf(gdir, sizeof(gdir), "%s/Documents/UFOAI-"UFO_VERSION"/%s", homedir, dir);
00652 #else
00653         Com_sprintf(gdir, sizeof(gdir), "%s/.ufoai/"UFO_VERSION"/%s", homedir, dir);
00654 #endif
00655         FS_CreatePath(va("%s/", gdir));
00656 
00657         FS_AddGameDirectory(gdir);
00658     } else {
00659         Com_Printf("could not find the home directory\n");
00660     }
00661 }
00662 
00663 #ifdef COMPILE_UFO
00664 
00667 void FS_ExecAutoexec (void)
00668 {
00669     char name[MAX_QPATH];
00670     searchpath_t *s;
00671 
00672     /* search through all the paths for an autoexec.cfg file */
00673     for (s = fs_searchpaths; s != NULL; s = s->next) {
00674         snprintf(name, sizeof(name), "%s/autoexec.cfg", s->filename);
00675 
00676         if (Sys_FindFirst(name, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM)) {
00677             Cbuf_AddText("exec autoexec.cfg\n");
00678             Sys_FindClose();
00679             break;
00680         }
00681 
00682         Sys_FindClose();
00683     }
00684 
00685     Cbuf_Execute();  /* execute it */
00686 }
00687 
00691 static void FS_Link_f (void)
00692 {
00693     filelink_t *l, **prev;
00694 
00695     if (Cmd_Argc() != 3) {
00696         Com_Printf("Usage: %s <from> <to>\n", Cmd_Argv(0));
00697         return;
00698     }
00699 
00700     /* see if the link already exists */
00701     prev = &fs_links;
00702     for (l = fs_links; l; l = l->next) {
00703         if (!strcmp(l->from, Cmd_Argv(1))) {
00704             Mem_Free(l->to);
00705             if (!strlen(Cmd_Argv(2))) { /* delete it */
00706                 *prev = l->next;
00707                 Mem_Free(l->from);
00708                 Mem_Free(l);
00709                 return;
00710             }
00711             l->to = Mem_PoolStrDup(Cmd_Argv(2), com_fileSysPool, 0);
00712             return;
00713         }
00714         prev = &l->next;
00715     }
00716 
00717     /* create a new link */
00718     l = (filelink_t *)Mem_PoolAlloc(sizeof(*l), com_fileSysPool, 0);
00719     l->next = fs_links;
00720     fs_links = l;
00721     l->from = Mem_PoolStrDup(Cmd_Argv(1), com_fileSysPool, 0);
00722     l->fromlength = strlen(l->from);
00723     l->to = Mem_PoolStrDup(Cmd_Argv(2), com_fileSysPool, 0);
00724 }
00725 
00731 static void FS_Dir_f (void)
00732 {
00733     const char *path = NULL;
00734     char findname[1024];
00735     char wildcard[1024] = "*.*";
00736     char **dirnames;
00737     int ndirs;
00738 
00739     if (Cmd_Argc() != 1)
00740         Q_strncpyz(wildcard, Cmd_Argv(1), sizeof(wildcard));
00741 
00742     while ((path = FS_NextPath(path)) != NULL) {
00743         Com_sprintf(findname, sizeof(findname), "%s/%s", path, wildcard);
00744         FS_NormPath(findname);
00745 
00746         Com_Printf("Directory of %s\n", findname);
00747         Com_Printf("----\n");
00748 
00749         dirnames = FS_ListFiles(findname, &ndirs, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM);
00750         if (dirnames != NULL) {
00751             int i;
00752 
00753             for (i = 0; i < ndirs - 1; i++) {
00754                 if (strrchr(dirnames[i], '/'))
00755                     Com_Printf("%s\n", strrchr(dirnames[i], '/') + 1);
00756                 else
00757                     Com_Printf("%s\n", dirnames[i]);
00758 
00759                 Mem_Free(dirnames[i]);
00760             }
00761             Mem_Free(dirnames);
00762         }
00763         Com_Printf("\n");
00764     }
00765 }
00766 
00770 static void FS_Info_f (void)
00771 {
00772     searchpath_t *search;
00773     filelink_t *l;
00774 
00775     Com_Printf("Filesystem information\n");
00776     Com_Printf("...write dir: '%s'\n", FS_Gamedir());
00777 
00778     for (search = fs_searchpaths; search; search = search->next) {
00779         if (search->pack == NULL)
00780             Com_Printf("...path: '%s'\n", search->filename);
00781         else
00782             Com_Printf("...pakfile: '%s' (%i files)\n", search->pack->filename, search->pack->numfiles);
00783     }
00784 
00785     for (l = fs_links; l; l = l->next)
00786         Com_Printf("...link: %s : %s\n", l->from, l->to);
00787 }
00788 
00794 static const cmdList_t fs_commands[] = {
00795     {"fs_restart", FS_RestartFilesystem, "Reloads the file subsystem"},
00796     {"link", FS_Link_f, "Create file links"},
00797     {"dir", FS_Dir_f, "Show the filesystem contents - also supports wildcarding"},
00798     {"fs_info", FS_Info_f, "Show information about the virtual filesystem"},
00799 
00800     {NULL, NULL, NULL}
00801 };
00802 
00803 static void FS_RemoveCommands (void)
00804 {
00805     const cmdList_t *commands;
00806 
00807     for (commands = fs_commands; commands->name; commands++)
00808         Cmd_RemoveCommand(commands->name);
00809 }
00810 
00811 static void FS_InitCommandsAndCvars (void)
00812 {
00813     const cmdList_t *commands;
00814 
00815     for (commands = fs_commands; commands->name; commands++)
00816         Cmd_AddCommand(commands->name, commands->function, commands->description);
00817 }
00818 #endif
00819 
00824 void FS_InitFilesystem (qboolean writeToHomeDir)
00825 {
00826     Com_Printf("\n---- filesystem initialization -----\n");
00827 
00828 #ifdef PKGDATADIR
00829     /* add the system search path */
00830     FS_AddGameDirectory(PKGDATADIR"/"BASEDIRNAME);
00831 #endif
00832 
00833     if (writeToHomeDir) {
00834         FS_AddGameDirectory("./" BASEDIRNAME);
00835         FS_AddHomeAsGameDirectory(BASEDIRNAME);
00836     } else {
00837         FS_AddHomeAsGameDirectory(BASEDIRNAME);
00838         FS_AddGameDirectory("./" BASEDIRNAME);
00839     }
00840 
00841 #ifdef COMPILE_UFO
00842     FS_InitCommandsAndCvars();
00843 #endif
00844 
00845     Com_Printf("using %s for writing\n", FS_Gamedir());
00846 }
00847 
00854 typedef struct listBlock_s {
00855     char path[MAX_QPATH];
00856     linkedList_t *files;
00857     struct listBlock_s *next;
00858 } listBlock_t;
00859 
00860 static listBlock_t *fs_blocklist = NULL;
00861 
00867 static void _AddToListBlock (linkedList_t** fl, const char* name, qboolean stripPath)
00868 {
00869     const char *f;
00870     const linkedList_t *entry;
00871 
00872     /* strip path */
00873     if (stripPath)
00874         f = Com_SkipPath(name);
00875     else
00876         f = name;
00877 
00878     if (*fl == NULL)
00879         entry = NULL;
00880     else
00881         entry = LIST_ContainsString(*fl, f);
00882 
00883     /* add the new file */
00884     if (entry == NULL)
00885         LIST_AddString(fl, f);
00886 }
00887 
00892 int FS_BuildFileList (const char *fileList)
00893 {
00894     listBlock_t *block, *tblock;
00895     searchpath_t *search;
00896     char files[MAX_QPATH];
00897     char findname[1024];
00898     int i;
00899 
00900     /* bring it into normal form */
00901     Q_strncpyz(files, fileList, sizeof(files));
00902     FS_NormPath(files);
00903 
00904     /* check the blocklist for older searches
00905      * and do a new one after deleting them */
00906     for (block = fs_blocklist, tblock = NULL; block;) {
00907         if (!strcmp(block->path, files)) {
00908             /* delete old one */
00909             if (tblock)
00910                 tblock->next = block->next;
00911             else
00912                 fs_blocklist = block->next;
00913 
00914             LIST_Delete(&block->files);
00915             Mem_Free(block);
00916 
00917             if (tblock)
00918                 block = tblock->next;
00919             else
00920                 block = fs_blocklist;
00921             continue;
00922         }
00923 
00924         tblock = block;
00925         block = block->next;
00926     }
00927 
00928     /* allocate a new block and link it into the list */
00929     block = (listBlock_t *)Mem_PoolAlloc(sizeof(*block), com_fileSysPool, 0);
00930     block->next = fs_blocklist;
00931     fs_blocklist = block;
00932 
00933     /* store the search string */
00934     Q_strncpyz(block->path, files, sizeof(block->path));
00935 
00936     /* search for the files */
00937     LIST_Delete(&block->files);
00938 
00939     /* search through the path, one element at a time */
00940     for (search = fs_searchpaths; search; search = search->next) {
00941         /* is the element a pak file? */
00942         if (search->pack) {
00943             const char *ext = strrchr(files, '.');
00944             const pack_t *pak = search->pack;
00945             size_t l = strlen(files);
00946             if (!ext)
00947                 break;
00948             Q_strncpyz(findname, files, sizeof(findname));
00949             FS_NormPath(findname);
00950             l -= (strlen(ext) + 1);
00951             findname[l] = '\0';
00952 
00953             /* look through all the pak file elements */
00954             for (i = 0; i < pak->numfiles; i++) {
00955                 /* found it! */
00956                 const char *fileNameEntry = pak->files[i].name;
00957                 qboolean matchAlsoInSubDirs = (findname[0] == '*' || !strncmp(fileNameEntry, findname, l))
00958                          && (ext[0] == '*' || strstr(fileNameEntry, ext));
00959                 if (matchAlsoInSubDirs) {
00960                     qboolean add = qfalse;
00961                     if (strstr(findname, "**"))
00962                         add = qtrue;
00963                     else {
00964                         char pathName[MAX_QPATH];
00965                         char pathNameEntry[MAX_QPATH];
00966                         Com_FilePath(findname, pathName);
00967                         Com_FilePath(fileNameEntry, pathNameEntry);
00968                         if (!strcmp(pathNameEntry, pathName))
00969                             add = qtrue;
00970                     }
00971 
00972                     if (add)
00973                         _AddToListBlock(&block->files, pak->files[i].name, qtrue);
00974                 }
00975             }
00976         } else if (strstr(files, "**")) {
00977             linkedList_t *list = NULL, *loopList;
00978             const char *wildcard = strstr(files, "**");
00979             const size_t l = strlen(files) - strlen(wildcard);
00980             const char *name = &findname[l + 1];
00981 
00982             Q_strncpyz(findname, files, sizeof(findname));
00983             FS_NormPath(findname);
00984             findname[l] = '\0';
00985             if (l > 0 && findname[l - 1] == '/')
00986                 findname[l - 1] = '\0';
00987 
00988             Sys_ListFilteredFiles(search->filename, findname, name, &list);
00989 
00990             loopList = list;
00991             while (loopList) {
00992                 _AddToListBlock(&block->files, (const char *)loopList->data, qfalse);
00993                 loopList = loopList->next;
00994             }
00995 
00996             LIST_Delete(&list);
00997         } else {
00998             int nfiles = 0;
00999             char **filenames;
01000 
01001             Com_sprintf(findname, sizeof(findname), "%s/%s", search->filename, files);
01002             FS_NormPath(findname);
01003 
01004             filenames = FS_ListFiles(findname, &nfiles, 0, SFF_HIDDEN | SFF_SYSTEM);
01005             if (filenames != NULL) {
01006                 for (i = 0; i < nfiles - 1; i++) {
01007                     _AddToListBlock(&block->files, filenames[i], qtrue);
01008                     Mem_Free(filenames[i]);
01009                 }
01010                 Mem_Free(filenames);
01011             }
01012         }
01013     }
01014 
01015     return LIST_Count(block->files);
01016 }
01017 
01018 const char* FS_NextFileFromFileList (const char *files)
01019 {
01020     static linkedList_t *listEntry = NULL;
01021     static listBlock_t *_block = NULL;
01022     listBlock_t *block;
01023     const char *file = NULL;
01024 
01025     /* restart the list? */
01026     if (files == NULL) {
01027         _block = NULL;
01028         return NULL;
01029     }
01030 
01031     for (block = fs_blocklist; block; block = block->next)
01032         if (!strncmp(files, block->path, MAX_QPATH))
01033             break;
01034 
01035     if (!block) {
01036         FS_BuildFileList(files);
01037         for (block = fs_blocklist; block; block = block->next)
01038             if (!strncmp(files, block->path, MAX_QPATH))
01039                 break;
01040         if (!block) {
01041             /* still no filelist */
01042             Com_Printf("FS_NextFileFromFileList: Could not create filelist for %s\n", files);
01043             return NULL;
01044         }
01045     }
01046 
01047     /* everytime we switch between different blocks we get the
01048      * first file again when we switch back */
01049     if (_block != block) {
01050         _block = block;
01051         listEntry = block->files;
01052     }
01053 
01054     if (listEntry) {
01055         file = (const char *)listEntry->data;
01056         listEntry = listEntry->next;
01057     }
01058 
01059     /* finished */
01060     return file;
01061 }
01062 
01072 const char *FS_GetFileData (const char *files)
01073 {
01074     listBlock_t *block;
01075     static linkedList_t *fileList = NULL;
01076     static byte *buffer = NULL;
01077 
01078     /* free the old file */
01079     if (buffer) {
01080         FS_FreeFile(buffer);
01081         buffer = NULL;
01082     }
01083 
01084     if (!files) {
01085         fileList = NULL;
01086         return NULL;
01087     }
01088 
01089     for (block = fs_blocklist; block; block = block->next)
01090         if (!strcmp(files, block->path))
01091             break;
01092 
01093     if (!block) {
01094         /* didn't find any valid file list */
01095         fileList = NULL;
01096         FS_BuildFileList(files);
01097         for (block = fs_blocklist; block; block = block->next)
01098             if (!strcmp(files, block->path))
01099                 break;
01100         if (!block) {
01101             /* still no filelist */
01102             Com_Printf("FS_GetFileData: Could not create filelist for %s\n", files);
01103             return NULL;
01104         }
01105     }
01106 
01107     if (!fileList)
01108         /* start the list */
01109         fileList = block->files;
01110     else
01111         /* search a new file */
01112         fileList = fileList->next;
01113 
01114     if (fileList) {
01115         char filename[MAX_QPATH];
01116 
01117         /* load a new file */
01118         Q_strncpyz(filename, block->path, sizeof(filename));
01119         strcpy(strrchr(filename, '/') + 1, (const char *)fileList->data);
01120 
01121         FS_LoadFile(filename, &buffer);
01122         return (const char*)buffer;
01123     }
01124 
01125     /* finished */
01126     return NULL;
01127 }
01128 
01129 void FS_SkipBlock (const char **text)
01130 {
01131     const char *token;
01132     int depth;
01133 
01134     depth = 1;
01135 
01136     do {
01137         token = Com_Parse(text);
01138         if (*token == '{')
01139             depth++;
01140         else if (*token == '}')
01141             depth--;
01142     } while (depth && *text);
01143 }
01144 
01145 char *FS_NextScriptHeader (const char *files, const char **name, const char **text)
01146 {
01147     static char lastList[MAX_QPATH] = "";
01148     static listBlock_t *lBlock;
01149     static linkedList_t *lFile = NULL;
01150     static byte *lBuffer = NULL;
01151 
01152     static char headerType[MAX_VAR];
01153     static char headerName[MAX_VAR];
01154     listBlock_t *block;
01155     const char *token;
01156 
01157     if (!text) {
01158         *lastList = 0;
01159         return NULL;
01160     }
01161 
01162     if (strcmp(files, lastList)) {
01163         /* search for file lists */
01164         Q_strncpyz(lastList, files, sizeof(lastList));
01165 
01166         for (block = fs_blocklist; block; block = block->next)
01167             if (!strcmp(files, block->path))
01168                 break;
01169 
01170         if (!block)
01171             /* didn't find any valid file list */
01172             return NULL;
01173 
01174         lBlock = block;
01175         lFile = block->files;
01176     }
01177 
01178     while (lBlock) {
01179         if (lBuffer) {
01180             /* continue reading the current file */
01181             if (*text) {
01182                 token = Com_Parse(text);
01183                 if (*token == '{') {
01184                     FS_SkipBlock(text);
01185                     continue;
01186                 }
01187 
01188                 Q_strncpyz(headerType, token, sizeof(headerType));
01189                 if (*text) {
01190                     token = Com_Parse(text);
01191                     Q_strncpyz(headerName, token, sizeof(headerName));
01192                     *name = headerName;
01193                     return headerType;
01194                 }
01195             }
01196 
01197             /* search a new file */
01198             lFile = lFile->next;
01199 
01200             while (!lFile && lBlock)
01201                 /* it was the last file in the block, continue to next block */
01202                 for (lBlock = lBlock->next; lBlock; lBlock = lBlock->next)
01203                     if (!strcmp(files, lBlock->path)) {
01204                         lFile = lBlock->files;
01205                         break;
01206                     }
01207         }
01208 
01209         if (lFile) {
01210             char filename[MAX_QPATH];
01211 
01212             /* free the old file */
01213             if (lBuffer) {
01214                 FS_FreeFile(lBuffer);
01215                 lBuffer = NULL;
01216             }
01217 
01218             /* load a new file */
01219             Q_strncpyz(filename, lBlock->path, sizeof(filename));
01220             strcpy(strrchr(filename, '/') + 1, (const char *)lFile->data);
01221 
01222             FS_LoadFile(filename, &lBuffer);
01223             /* skip a file that couldn't get loaded */
01224             if (!lBuffer) {
01225                 lFile = lFile->next;
01226                 continue;
01227             }
01228             *text = (char*)lBuffer;
01229         } else if (!lBuffer)
01230             break;
01231     }
01232 
01233     /* free the old file */
01234     if (lBuffer) {
01235         FS_FreeFile(lBuffer);
01236         lBuffer = NULL;
01237     }
01238 
01239     /* finished */
01240     return NULL;
01241 }
01242 
01243 /* global vars for maplisting */
01244 char *fs_maps[MAX_MAPS];
01245 int fs_numInstalledMaps = -1;
01246 static qboolean fs_mapsInstalledInit = qfalse;
01247 
01251 static int FS_MapDefSort (const void *map1, const void *map2)
01252 {
01253     const char *mapStr1 = *(const char * const *)map1;
01254     const char *mapStr2 = *(const char * const *)map2;
01255 
01256     /* skip special map chars for rma and base attack */
01257     if (mapStr1[0] == '+')
01258         mapStr1++;
01259     if (mapStr2[0] == '+')
01260         mapStr2++;
01261 
01262     return Q_StringSort(mapStr1, mapStr2);
01263 }
01264 
01275 static int CheckBSPFile (const char *filename)
01276 {
01277     int i;
01278     int header[2];
01279     qFILE file;
01280     char name[MAX_QPATH];
01281 
01282     /* load the file */
01283     Com_sprintf(name, sizeof(name), "maps/%s.bsp", filename);
01284 
01285     FS_OpenFile(name, &file, FILE_READ);
01286     if (!file.f && !file.z)
01287         return 1;
01288 
01289     FS_Read(header, sizeof(header), &file);
01290 
01291     FS_CloseFile(&file);
01292 
01293     for (i = 0; i < 2; i++)
01294         header[i] = LittleLong(header[i]);
01295 
01296     if (header[0] != IDBSPHEADER)
01297         return 2;
01298     if (header[1] != BSPVERSION)
01299         return 3;
01300 
01301     /* valid BSP-File */
01302     return 0;
01303 }
01304 
01310 void FS_GetMaps (qboolean reset)
01311 {
01312     char findname[MAX_OSPATH];
01313     char filename[MAX_QPATH];
01314     int status, i;
01315     const char *baseMapName = NULL;
01316     char **dirnames;
01317     int ndirs;
01318     searchpath_t *search;
01319     pack_t *pak;
01320 
01321     /* force a reread */
01322     if (!reset && fs_mapsInstalledInit)
01323         return;
01324     else if (fs_mapsInstalledInit) {
01325         for (i = 0; i <= fs_numInstalledMaps; i++)
01326             Mem_Free(fs_maps[i]);
01327     }
01328 
01329     fs_numInstalledMaps = -1;
01330 
01331     /* search through the path, one element at a time */
01332     for (search = fs_searchpaths; search; search = search->next) {
01333         /* is the element a pak file? */
01334         if (search->pack) {
01335             /* look through all the pak file elements */
01336             pak = search->pack;
01337             for (i = 0; i < pak->numfiles; i++) {
01338                 /* found it! */
01339                 baseMapName = strchr(pak->files[i].name, '/');
01340                 if (baseMapName) {
01342                     baseMapName = strchr(baseMapName + 1, '/');
01343                     /* ugly hack - only show the maps in base/maps - not in base/maps/b and so on */
01344                     if (baseMapName)
01345                         continue;
01346                 } else
01347                     continue;
01348 
01349                 if (strstr(pak->files[i].name, ".bsp") || strstr(pak->files[i].name, ".ump") ) {
01350                     if (fs_numInstalledMaps + 1 >= MAX_MAPS) {
01351                         Com_Printf("FS_GetMaps: Max maps limit hit\n");
01352                         break;
01353                     }
01354                     fs_maps[fs_numInstalledMaps + 1] = (char *)Mem_PoolAlloc(MAX_QPATH * sizeof(char), com_fileSysPool, 0);
01355                     if (fs_maps[fs_numInstalledMaps + 1] == NULL) {
01356                         Com_Printf("Could not allocate memory in FS_GetMaps\n");
01357                         continue;
01358                     }
01359                     Q_strncpyz(findname, pak->files[i].name, sizeof(findname));
01360                     FS_NormPath(findname);
01361                     baseMapName = Com_SkipPath(findname);
01362                     Com_StripExtension(baseMapName, filename, sizeof(filename));
01363                     fs_numInstalledMaps++;
01364                     if (strstr(findname, ".ump"))
01365                         Com_sprintf(fs_maps[fs_numInstalledMaps], MAX_QPATH, "+%s", filename);
01366                     else
01367                         Q_strncpyz(fs_maps[fs_numInstalledMaps], filename, MAX_QPATH);
01368                 }
01369             }
01370         } else {
01371             Com_sprintf(findname, sizeof(findname), "%s/maps/*.bsp", search->filename);
01372             FS_NormPath(findname);
01373 
01374             dirnames = FS_ListFiles(findname, &ndirs, 0, SFF_HIDDEN | SFF_SYSTEM);
01375             if (dirnames != NULL) {
01376                 for (i = 0; i < ndirs - 1; i++) {
01377                     baseMapName = Com_SkipPath(dirnames[i]);
01378                     Com_StripExtension(baseMapName, filename, sizeof(filename));
01379                     status = CheckBSPFile(filename);
01380                     if (!status) {
01381                         if (fs_numInstalledMaps + 1 >= MAX_MAPS) {
01382                             Com_Printf("FS_GetMaps: Max maps limit hit\n");
01383                             break;
01384                         }
01385                         fs_maps[fs_numInstalledMaps + 1] = (char *) Mem_PoolAlloc(MAX_QPATH * sizeof(char), com_fileSysPool, 0);
01386                         if (fs_maps[fs_numInstalledMaps + 1] == NULL) {
01387                             Com_Printf("Could not allocate memory in FS_GetMaps\n");
01388                             Mem_Free(dirnames[i]);
01389                             continue;
01390                         }
01391                         fs_numInstalledMaps++;
01392                         Q_strncpyz(fs_maps[fs_numInstalledMaps], filename, MAX_QPATH);
01393                     } else
01394                         Com_Printf("invalid mapstatus: %i (%s)\n", status, dirnames[i]);
01395                     Mem_Free(dirnames[i]);
01396                 }
01397                 Mem_Free(dirnames);
01398             }
01399             /* +RMA to maplisting */
01400             Com_sprintf(findname, sizeof(findname), "%s/maps/*.ump", search->filename);
01401             FS_NormPath(findname);
01402 
01403             dirnames = FS_ListFiles(findname, &ndirs, 0, SFF_HIDDEN | SFF_SYSTEM);
01404             if (dirnames != NULL) {
01405                 for (i = 0; i < ndirs - 1; i++) {
01406                     baseMapName = Com_SkipPath(dirnames[i]);
01407                     Com_StripExtension(baseMapName, filename, sizeof(filename));
01408                     if (fs_numInstalledMaps + 1 >= MAX_MAPS) {
01409                         Com_Printf("FS_GetMaps: Max maps limit hit\n");
01410                         break;
01411                     }
01412                     fs_maps[fs_numInstalledMaps + 1] = (char *) Mem_PoolAlloc(MAX_QPATH * sizeof(char), com_fileSysPool, 0);
01413                     if (fs_maps[fs_numInstalledMaps + 1] == NULL) {
01414                         Com_Printf("Could not allocate memory in FS_GetMaps\n");
01415                         Mem_Free(dirnames[i]);
01416                         continue;
01417                     }
01418                     fs_numInstalledMaps++;
01419                     Com_sprintf(fs_maps[fs_numInstalledMaps], MAX_QPATH, "+%s", filename);
01420                     Mem_Free(dirnames[i]);
01421                 }
01422                 Mem_Free(dirnames);
01423             }
01424         }
01425     }
01426 
01427     fs_mapsInstalledInit = qtrue;
01428 
01429     qsort(fs_maps, fs_numInstalledMaps + 1, sizeof(char *), FS_MapDefSort);
01430 }
01431 
01436 int FS_Printf (qFILE *f, const char *msg, ...)
01437 {
01438     va_list ap;
01439     int len;
01440     char buf[1024];
01441 
01442     va_start(ap, msg);
01443     Q_vsnprintf(buf, sizeof(buf), msg, ap);
01444     len = fprintf(f->f, "%s", buf);
01445     va_end(ap);
01446 
01447     return len;
01448 }
01449 
01453 int FS_Write (const void *buffer, int len, qFILE * f)
01454 {
01455     int block, remaining;
01456     int written;
01457     const byte *buf;
01458     int tries;
01459 
01460     if (!f->f)
01461         return 0;
01462 
01463     buf = (const byte *) buffer;
01464 
01465     remaining = len;
01466     tries = 0;
01467     while (remaining) {
01468         block = remaining;
01469         written = fwrite(buf, 1, block, f->f);
01470         if (written == 0) {
01471             if (!tries) {
01472                 tries = 1;
01473             } else {
01474                 Com_Printf("FS_Write: 0 bytes written\n");
01475                 return 0;
01476             }
01477         }
01478 
01479         if (written == -1) {
01480             Com_Printf("FS_Write: -1 bytes written\n");
01481             return 0;
01482         }
01483 
01484         remaining -= written;
01485         buf += written;
01486     }
01487     return len;
01488 }
01489 
01490 
01491 int FS_WriteFile (const void *buffer, size_t len, const char *filename)
01492 {
01493     qFILE f;
01494     int c, lencheck;
01495 
01496     FS_OpenFile(filename, &f, FILE_WRITE);
01497     if (f.f)
01498         c = FS_Write(buffer, len, &f);
01499     else
01500         return 0;
01501 
01502     lencheck = FS_FileLength(&f);
01503     FS_CloseFile(&f);
01504 
01505     /* if file write failed (file is incomplete) then delete it */
01506     if (c != len || lencheck != len) {
01507         Com_Printf("FS_WriteFile: failed to finish writing '%s'\n", filename);
01508         if (remove(va("%s/%s", FS_Gamedir(), filename)))
01509             Com_Printf("FS_WriteFile: could not remove file: %s\n", filename);
01510         return 0;
01511     }
01512 
01513     return c;
01514 }
01515 
01519 const char *FS_GetCwd (void)
01520 {
01521     static char buf[MAX_OSPATH];
01522     Q_strncpyz(buf, Sys_Cwd(), sizeof(buf));
01523     FS_NormPath(buf);
01524     return buf;
01525 }
01526 
01532 qboolean FS_FileExists (const char *filename)
01533 {
01534 #ifdef _WIN32
01535     return (_access(filename, 00) == 0);
01536 #else
01537     return (access(filename, R_OK) == 0);
01538 #endif
01539 }
01540 
01546 void FS_Shutdown (void)
01547 {
01548     searchpath_t *p, *next;
01549 
01550     if (fs_openedFiles != 0) {
01551         Com_Printf("There are still %i opened files\n", fs_openedFiles);
01552     }
01553 
01554     /* free everything */
01555     for (p = fs_searchpaths; p; p = next) {
01556         next = p->next;
01557 
01558         if (p->pack) {
01559             unzClose(p->pack->handle.z);
01560             Mem_Free(p->pack->files);
01561             Mem_Free(p->pack);
01562         }
01563         Mem_Free(p);
01564     }
01565 
01566     /* any FS_ calls will now be an error until reinitialized */
01567     fs_searchpaths = NULL;
01568     fs_links = NULL;
01569     fs_mapsInstalledInit = qfalse;
01570     fs_numInstalledMaps = -1;
01571 
01572 #ifdef COMPILE_UFO
01573     FS_RemoveCommands();
01574 #endif
01575 
01576     Mem_FreePool(com_fileSysPool);
01577 }
01578 
01585 void FS_RestartFilesystem (void)
01586 {
01587     /* free anything we currently have loaded */
01588     FS_Shutdown();
01589 
01590     /* try to start up normally */
01591     FS_InitFilesystem(qtrue);
01592 
01598     if (FS_CheckFile("default.cfg") < 0) {
01599         Sys_Error("Couldn't load default.cfg");
01600     }
01601 }
01602 
01607 void FS_CopyFile (const char *fromOSPath, const char *toOSPath)
01608 {
01609     FILE *f;
01610     int len;
01611     byte *buf;
01612 
01613     if (!fs_searchpaths)
01614         Sys_Error("Filesystem call made without initialization");
01615 
01616     Com_Printf("FS_CopyFile: copy %s to %s\n", fromOSPath, toOSPath);
01617 
01618     f = fopen(fromOSPath, "rb");
01619     if (!f)
01620         return;
01621 
01622     fseek(f, 0, SEEK_END);
01623     len = ftell(f);
01624     fseek(f, 0, SEEK_SET);
01625 
01626     buf = (byte *)Mem_PoolAlloc(len, com_fileSysPool, 0);
01627     if (fread(buf, 1, len, f) != len)
01628         Sys_Error("Short read in FS_CopyFile");
01629     fclose(f);
01630 
01631     FS_CreatePath(toOSPath);
01632 
01633     f = fopen(toOSPath, "wb");
01634     if (!f) {
01635         Mem_Free(buf);
01636         return;
01637     }
01638 
01639     if (fwrite(buf, 1, len, f) != len)
01640         Sys_Error("Short write in FS_CopyFile()");
01641 
01642     fclose(f);
01643     Mem_Free(buf);
01644 }
01645 
01649 void FS_RemoveFile (const char *osPath)
01650 {
01651     if (!fs_searchpaths)
01652         Sys_Error("Filesystem call made without initialization");
01653 
01654     Com_Printf("FS_RemoveFile: remove %s\n", osPath);
01655     remove(osPath);
01656 }
01657 
01666 qboolean FS_RenameFile (const char *from, const char *to, qboolean relative)
01667 {
01668     char from_buf[MAX_OSPATH];
01669     char to_buf[MAX_OSPATH];
01670 
01671     if (!fs_searchpaths)
01672         Sys_Error("Filesystem call made without initialization");
01673 
01674     if (relative) {
01675         Com_sprintf(from_buf, sizeof(from_buf), "%s/%s", FS_Gamedir(), from);
01676         Com_sprintf(to_buf, sizeof(to_buf), "%s/%s", FS_Gamedir(), to);
01677         from = from_buf;
01678         to = to_buf;
01679     }
01680 
01681     if (rename(from, to))
01682         return qfalse;
01683     return qtrue;
01684 }

Generated by  doxygen 1.6.2