#include <windows.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <time.h>
#include <stdlib.h>
#include "httpd.h"
#include "http_log.h"
static BOOL OnlyDots(char *pString)
{
char *c;
if (*pString == '\0')
return FALSE;
for (c = pString;*c;c++)
if (*c != '.')
return FALSE;
return TRUE;
}
char * ap_os_systemcase_filename(pool *pPool,
const char *szFile)
{
char buf[HUGE_STRING_LEN];
char *pInputName;
char *p, *q, *t;
BOOL bDone = FALSE;
BOOL bFileExists = TRUE;
HANDLE hFind;
WIN32_FIND_DATA wfd;
if (!szFile || strlen(szFile) == 0 || strlen(szFile) >= sizeof(buf))
return ap_pstrdup(pPool, "");
t = buf;
pInputName = ap_pstrdup(pPool, szFile);
for (p = pInputName; *p; p++) {
if (*p == '/')
*p = '\\';
}
q = p = pInputName;
if (pInputName[1] == ':') {
*(t++) = tolower(*p++);
*(t++) = *p++;
q = p;
if (!*p)
bDone = TRUE;
}
if (*p == '\\') {
++p;
if (*p == '\\')
{
*(t++) = '\\';
++q;
p = strchr(p + 1, '\\');
if (p)
{
p++;
p = strchr(p, '\\');
if (p) {
strncpy(t,q,p-q);
strlwr(t);
t += p - q;
q = p;
p++;
}
}
if (!p) {
bFileExists = FALSE;
p = q;
}
}
}
p = strchr(p, '\\');
while (!bDone) {
if (p)
*p = '\0';
if (strchr(q, '*') || strchr(q, '?'))
bFileExists = FALSE;
if (bFileExists && !OnlyDots((*q == '.' ? q : q+1))) {
hFind = FindFirstFile(pInputName, &wfd);
if (hFind == INVALID_HANDLE_VALUE) {
bFileExists = FALSE;
}
else {
FindClose(hFind);
if (*q == '\\')
*(t++) = '\\';
t = strchr(strcpy(t, wfd.cFileName), '\0');
}
}
if (!bFileExists || OnlyDots((*q == '.' ? q : q+1))) {
strcpy(t, q);
t = strchr(t, '\0');
}
if (p) {
q = p;
*p++ = '\\';
p = strchr(p, '\\');
}
else {
bDone = TRUE;
}
}
*t = '\0';
for (p = buf; *p; p++) {
if (*p == '\\')
*p = '/';
}
return ap_pstrdup(pPool, buf);
}
char * ap_os_case_canonical_filename(pool *pPool,
const char *szFile)
{
char *pNewStr;
char *s;
char *p;
char *q;
if (szFile == NULL || strlen(szFile) == 0)
return ap_pstrdup(pPool, "");
pNewStr = ap_pstrdup(pPool, szFile);
for (p = pNewStr,s = pNewStr; *s; s++,p++) {
if (*s == '\\' || *s == '/') {
q = p;
while (p > pNewStr && *(p-1) == '.')
p--;
if (p == pNewStr && q-p <= 2 && *p == '.')
p = q;
else if (p > pNewStr && p < q && *(p-1) == '/') {
if (q-p > 2)
p--;
else
p = q;
}
*p = '/';
}
else {
*p = *s;
}
}
*p = '\0';
q = p;
while (p > pNewStr && (*(p-1) == '.' || *(p-1) == ' '))
p--;
if ((p > pNewStr) ||
(p == pNewStr && q-p > 2))
*p = '\0';
#ifdef WIN32_SHORT_FILENAME_INSECURE_BEHAVIOR
p = strchr(pNewStr, '~');
if (p != NULL)
#endif
{
char *pConvertedName, *pQstr, *pPstr;
char buf[HUGE_STRING_LEN];
pConvertedName = ap_os_systemcase_filename(pPool, pNewStr);
if (stricmp(pNewStr, pConvertedName)) {
buf[0] = '\0';
q = pQstr = pConvertedName;
p = pPstr = pNewStr;
do {
q = strchr(q,'/');
p = strchr(p,'/');
if (p != NULL) {
*q = '\0';
*p = '\0';
}
if (stricmp(pQstr, pPstr))
strcat(buf, pQstr);
else
strcat(buf, pPstr);
if (p != NULL) {
pQstr = q;
pPstr = p;
*q++ = '/';
*p++ = '/';
}
} while (p != NULL);
pNewStr = ap_pstrdup(pPool, buf);
}
}
return pNewStr;
}
char * ap_os_canonical_filename(pool *pPool, const char *szFile)
{
char *pNewName;
pNewName = ap_os_case_canonical_filename(pPool, szFile);
strlwr(pNewName);
return pNewName;
}
#undef stat
int os_stat(const char *szPath, struct stat *pStat)
{
int n;
int len = strlen(szPath);
if ((len == 0) || (len >= MAX_PATH)) {
return -1;
}
if (szPath[0] == '/' && szPath[1] == '/') {
char buf[_MAX_PATH];
char *s;
int nSlashes = 0;
strcpy(buf, szPath);
for (s = buf; *s; ++s) {
if (*s == '/') {
*s = '\\';
++nSlashes;
}
}
if (nSlashes == 3) {
if (++len >= MAX_PATH) {
return -1;
}
*s++ = '\\';
}
*s = '\0';
return stat(buf, pStat);
}
n = strlen(szPath);
if ((szPath[n - 1] == '\\' || szPath[n - 1] == '/') &&
!(n == 3 && szPath[1] == ':')) {
char buf[_MAX_PATH];
ap_assert(n < _MAX_PATH);
strcpy(buf, szPath);
buf[n - 1] = '\0';
return stat(buf, pStat);
}
return stat(szPath, pStat);
}
#undef _spawnv
int os_spawnv(int mode, const char *cmdname,
const char *const *argv)
{
int n;
char **aszArgs;
const char *szArg;
char *szCmd;
char *s;
szCmd = _alloca(strlen(cmdname)+1);
strcpy(szCmd, cmdname);
for (s = szCmd; *s; ++s) {
if (*s == '/') {
*s = '\\';
}
}
for (n = 0; argv[n]; ++n)
;
aszArgs = _alloca((n + 1) * sizeof(const char *));
for (n = 0; szArg = argv[n]; ++n) {
if (strchr(szArg, ' ')) {
int l = strlen(szArg);
aszArgs[n] = _alloca(l + 2 + 1);
aszArgs[n][0] = '"';
strcpy(&aszArgs[n][1], szArg);
aszArgs[n][l + 1] = '"';
aszArgs[n][l + 2] = '\0';
}
else {
aszArgs[n] = (char *)szArg;
}
}
aszArgs[n] = NULL;
return _spawnv(mode, szCmd, aszArgs);
}
#undef _spawnve
int os_spawnve(int mode, const char *cmdname,
const char *const *argv, const char *const *envp)
{
int n;
char **aszArgs;
const char *szArg;
char *szCmd;
char *s;
szCmd = _alloca(strlen(cmdname)+1);
strcpy(szCmd, cmdname);
for (s = szCmd; *s; ++s) {
if (*s == '/') {
*s = '\\';
}
}
for (n = 0; argv[n]; ++n)
;
aszArgs = _alloca((n + 1)*sizeof(const char *));
for (n = 0; szArg = argv[n]; ++n){
if (strchr(szArg, ' ')) {
int l = strlen(szArg);
aszArgs[n] = _alloca(l + 2 + 1);
aszArgs[n][0] = '"';
strcpy(&aszArgs[n][1], szArg);
aszArgs[n][l + 1] = '"';
aszArgs[n][l + 2] = '\0';
}
else {
aszArgs[n] = (char *)szArg;
}
}
aszArgs[n] = NULL;
return _spawnve(mode, szCmd, aszArgs, envp);
}
int os_spawnle(int mode, const char *cmdname, ...)
{
int n;
va_list vlist;
char **aszArgs;
const char *szArg;
const char *const *aszEnv;
char *szCmd;
char *s;
szCmd = _alloca(strlen(cmdname)+1);
strcpy(szCmd, cmdname);
for (s = szCmd; *s; ++s) {
if (*s == '/') {
*s = '\\';
}
}
va_start(vlist, cmdname);
for (n = 0; va_arg(vlist, const char *); ++n)
;
va_end(vlist);
aszArgs = _alloca((n + 1) * sizeof(const char *));
va_start(vlist, cmdname);
for (n = 0; szArg = va_arg(vlist, const char *); ++n) {
if (strchr(szArg, ' ')) {
int l = strlen(szArg);
aszArgs[n] = _alloca(l + 2 + 1);
aszArgs[n][0] = '"';
strcpy(&aszArgs[n][1], szArg);
aszArgs[n][l + 1] = '"';
aszArgs[n][l + 2] = '\0';
}
else {
aszArgs[n] = (char *)szArg;
}
}
aszArgs[n] = NULL;
aszEnv = va_arg(vlist, const char *const *);
va_end(vlist);
return _spawnve(mode, szCmd, aszArgs, aszEnv);
}
#undef strftime
int os_strftime(char *s, size_t max, const char *format,
const struct tm *tm) {
char *new_format = (char *) _alloca(max + 11);
size_t i, j, format_length = strlen(format);
int return_value;
int length_written;
for (i = 0, j = 0; (i < format_length && j < max);) {
if (format[i] != '%') {
new_format[j++] = format[i++];
continue;
}
switch (format[i+1]) {
case 'D':
memcpy(new_format + j, "%m/%d/%y", 8);
i += 2;
j += 8;
break;
case 'r':
memcpy(new_format + j, "%I:%M:%S %p", 11);
i += 2;
j += 11;
break;
case 'T':
memcpy(new_format + j, "%H:%M:%S", 8);
i += 2;
j += 8;
break;
case 'e':
length_written = ap_snprintf(new_format + j, max - j, "%2d",
tm->tm_mday);
j = (length_written == -1) ? max : (j + length_written);
i += 2;
break;
default:
new_format[j++] = format[i++];
new_format[j++] = format[i++];
}
}
if (j >= max) {
*s = '\0';
return_value = 0;
} else {
new_format[j] = '\0';
return_value = strftime(s, max, new_format, tm);
}
return return_value;
}
int ap_os_is_filename_valid(const char *file)
{
const char *segstart;
unsigned int seglength;
const char *pos;
static const char * const invalid_characters = "?\"<>*|:";
static const char * const invalid_filenames[] = {
"CON", "AUX", "COM1", "COM2", "COM3",
"COM4", "LPT1", "LPT2", "LPT3", "PRN", "NUL", NULL
};
if (strlen(file) >= MAX_PATH) {
return 0;
}
pos = file;
if (pos[0] && pos[1] == ':') {
pos += 2;
}
else {
if ((pos[0] == '\\' || pos[0] == '/') &&
(pos[1] == '\\' || pos[1] == '/')) {
pos += 2;
while (*pos && *pos != '/' && *pos != '\\')
pos++;
if (!*pos) {
return 0;
}
pos++;
while (*pos && *pos != '/' && *pos != '\\')
pos++;
if (!*pos) {
return 0;
}
}
}
while (*pos) {
unsigned int idx;
unsigned int baselength;
while (*pos == '/' || *pos == '\\') {
pos++;
}
if (*pos == '\0') {
break;
}
segstart = pos;
while (*pos && *pos != '/' && *pos != '\\') {
pos++;
}
seglength = pos - segstart;
for (idx = 0; idx < seglength; idx++) {
if ((segstart[idx] > 0 && segstart[idx] < 32) ||
strchr(invalid_characters, segstart[idx])) {
return 0;
}
}
if (segstart[seglength-1] == '.') {
return 0;
}
for (baselength = 0; baselength < seglength; baselength++) {
if (segstart[baselength] == '.') {
break;
}
}
if (baselength == 3 || baselength == 4) {
for (idx = 0; invalid_filenames[idx]; idx++) {
if (strlen(invalid_filenames[idx]) == baselength &&
!strnicmp(invalid_filenames[idx], segstart, baselength)) {
return 0;
}
}
}
}
return 1;
}
ap_os_dso_handle_t ap_os_dso_load(const char *module_name)
{
UINT em;
ap_os_dso_handle_t dsoh;
char path[MAX_PATH], *p;
ap_cpystrn(path, module_name, MAX_PATH);
p = path;
while (p = strchr(p, '/'))
*p = '\\';
em = SetErrorMode(SEM_FAILCRITICALERRORS);
dsoh = LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (!dsoh) {
dsoh = LoadLibraryEx(path, NULL, 0);
}
SetErrorMode(em);
return dsoh;
}
const char * ap_os_dso_error(void)
{
int len, nErrorCode;
static char errstr[120];
nErrorCode = GetLastError();
len = ap_snprintf(errstr, sizeof(errstr), "(%d) ", nErrorCode);
len += FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
nErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) errstr + len,
sizeof(errstr) - len,
NULL
);
if (len > 1 && errstr[len-2] == '\r' && errstr[len-1] == '\n') {
if (len > 2 && errstr[len-3] == '.')
len--;
errstr[len-2] = ':';
errstr[len-1] = ' ';
}
return errstr;
}