📄 util_win32.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#ifdef WIN32#include <sys/stat.h>#include <stdarg.h>#include <time.h>#include <stdlib.h>#include "httpd.h"#include "http_log.h"/* Returns TRUE if the input string is a string * of one or more '.' characters. */static BOOL OnlyDots(char *pString){ char *c; if (*pString == '\0') return FALSE; for (c = pString;*c;c++) if (*c != '.') return FALSE; return TRUE;}/* Accepts as input a pathname, and tries to match it to an * existing path and return the pathname in the case that * is present on the existing path. This routine also * converts alias names to long names. * * WARNING: Folding to systemcase fails when /path/to/foo/../bar * is given and foo does not exist, is not a directory. */API_EXPORT(char *) ap_os_systemcase_filename(pool *pPool, const char *szFile){ char *buf, *t, *r; const char *q, *p; BOOL bDone = FALSE; BOOL bFileExists = TRUE; HANDLE hFind; WIN32_FIND_DATA wfd; size_t buflen; int slack = 0; if (!szFile || strlen(szFile) == 0) return ap_pstrdup(pPool, ""); buflen = strlen(szFile); t = buf = ap_palloc(pPool, buflen + 1); q = szFile; /* If there is drive information, copy it over. */ if (szFile[1] == ':') { /* Lowercase, so that when systemcase is used for * comparison, d: designations will match */ *(t++) = tolower(*(q++)); *(t++) = *(q++); } else if ((*q == '/') || (*q == '\\')) { /* Get past the root path (/ or //foo/bar/) so we can go * on to normalize individual path elements. */ *(t++) = '\\', ++q; if ((*q == '/') || (*q == '\\')) /* UNC name */ { /* Lower-case the machine name, so compares match. * FindFirstFile won't parse \\machine alone */ *(t++) = '\\', ++q; for (p = q; *p && (*p != '/') && (*p != '\\'); ++p) /* continue */ ; if (*p || p > q) { /* Lower-case the machine name, so compares match. * FindFirstFile won't parse \\machine\share alone */ memcpy(t, q, p - q); t[p - q] = '\0'; strlwr(t); t += p - q; q = p; if (*p) { *(t++) = '\\', ++q; for (p = q; *p && (*p != '/') && (*p != '\\'); ++p) /* continue */ ; if (*p || p > q) { /* Copy the lower-cased share name. FindFirstFile * cannot not find a \\machine\share name only */ memcpy(t, q, p - q); t[p - q] = '\0'; strlwr(t); t += p - q; q = p; if (*p) *(t++) = '\\', ++q; else bFileExists = FALSE; } else bFileExists = FALSE; } else bFileExists = FALSE; } else bFileExists = FALSE; } } while (bFileExists) { /* parse past any leading slashes */ for (; (*q == '/') || (*q == '\\'); ++q) *(t++) = '\\'; /* break on end of string */ if (!*q) break; /* get to the end of this path segment */ for (p = q; *p && (*p != '/') && (*p != '\\'); ++p) /* continue */ ; /* copy the segment */ memcpy(t, q, p - q); t[p - q] = '\0'; /* Test for nasties that can exhibit undesired effects */ if (strpbrk(t, "?\"<>*|:")) { t += p - q; q = p; break; } /* If the path exists so far, call FindFirstFile * again. However, if this portion of the path contains * only '.' charaters, skip the call to FindFirstFile * since it will convert '.' and '..' to actual names. * On win32, '...' is an alias for '..', so we gain * a bit of slack. */ if (*t == '.' && OnlyDots(t)) { if (p - q == 3) { t += 2; q = p; ++slack; } else { t += p - q; q = p; } /* Paths of 4 dots or more are invalid */ if (p - q > 3) break; } else { if ((hFind = FindFirstFile(buf, &wfd)) == INVALID_HANDLE_VALUE) { t += p - q; q = p; break; } else { size_t fnlen = strlen(wfd.cFileName); FindClose(hFind); /* the string length just changed, could have shrunk * (trailing spaces or dots) or could have grown * (longer filename aliases). Realloc as necessary */ slack -= fnlen - (p - q); if (slack < 0) { char *n; slack += buflen + fnlen - (p - q); buflen += buflen + fnlen - (p - q); n = ap_palloc(pPool, buflen + 1); memcpy (n, buf, t - buf); t = n + (t - buf); buf = n; } memcpy(t, wfd.cFileName, fnlen); t += fnlen; q = p; if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) break; } } } /* Convert all parsed '\'s to '/' for canonical form (doesn't touch * the non-existant portion of the path whatsoever.) */ for (r = buf; r < t; ++r) { if (*r == '\\') *r = '/'; } /* Copy the non-existant portion (minimally nul-terminates the string) */ strcpy(t, q); return buf;}/* Perform canonicalization with the exception that the * input case is preserved. */API_EXPORT(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); /* Change all '\' characters to '/' characters. * While doing this, remove any trailing '.'. * Also, blow away any directories with 3 or * more '.' */ 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -