+
+ // Is it a PK3 symlink?
+ // TODO also handle directory symlinks by parsing the whole structure...
+ // but heck, file symlinks are good enough for now
+ if(search->pack->files[pack_ind].flags & PACKFILE_FLAG_SYMLINK)
+ {
+ if(symlinkLevels <= 0)
+ {
+ Con_Printf("symlink: %s: too many levels of symbolic links\n", filename);
+ return NULL;
+ }
+ else
+ {
+ char linkbuf[MAX_QPATH];
+ fs_offset_t count;
+ qfile_t *linkfile = FS_OpenPackedFile (search->pack, pack_ind);
+ const char *mergeslash;
+ char *mergestart;
+
+ if(!linkfile)
+ return NULL;
+ count = FS_Read(linkfile, linkbuf, sizeof(linkbuf) - 1);
+ FS_Close(linkfile);
+ if(count < 0)
+ return NULL;
+ linkbuf[count] = 0;
+
+ // Now combine the paths...
+ mergeslash = strrchr(filename, '/');
+ mergestart = linkbuf;
+ if(!mergeslash)
+ mergeslash = filename;
+ while(!strncmp(mergestart, "../", 3))
+ {
+ mergestart += 3;
+ while(mergeslash > filename)
+ {
+ --mergeslash;
+ if(*mergeslash == '/')
+ break;
+ }
+ }
+ // Now, mergestart will point to the path to be appended, and mergeslash points to where it should be appended
+ if(mergeslash == filename)
+ {
+ // Either mergeslash == filename, then we just replace the name (done below)
+ }
+ else
+ {
+ // Or, we append the name after mergeslash;
+ // or rather, we can also shift the linkbuf so we can put everything up to and including mergeslash first
+ int spaceNeeded = mergeslash - filename + 1;
+ int spaceRemoved = mergestart - linkbuf;
+ if(count - spaceRemoved + spaceNeeded >= MAX_QPATH)
+ {
+ Con_DPrintf("symlink: too long path rejected\n");
+ return NULL;
+ }
+ memmove(linkbuf + spaceNeeded, linkbuf + spaceRemoved, count - spaceRemoved);
+ memcpy(linkbuf, filename, spaceNeeded);
+ linkbuf[count - spaceRemoved + spaceNeeded] = 0;
+ mergestart = linkbuf;
+ }
+ if (!quiet && developer_loading.integer)
+ Con_DPrintf("symlink: %s -> %s\n", filename, mergestart);
+ if(FS_CheckNastyPath (mergestart, false))
+ {
+ Con_DPrintf("symlink: nasty path %s rejected\n", mergestart);
+ return NULL;
+ }
+ return FS_OpenReadFile(mergestart, quiet, nonblocking, symlinkLevels - 1);
+ }
+ }
+