📄 open.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. */#include "apr_private.h"#include "apr_arch_file_io.h"#include "apr_file_io.h"#include "apr_general.h"#include "apr_strings.h"#include "apr_portable.h"#include "apr_thread_mutex.h"#if APR_HAVE_ERRNO_H#include <errno.h>#endif#include <winbase.h>#include <string.h>#if APR_HAVE_SYS_STAT_H#include <sys/stat.h>#endif#include "apr_arch_misc.h"#include "apr_arch_inherit.h"#if APR_HAS_UNICODE_FSapr_status_t utf8_to_unicode_path(apr_wchar_t* retstr, apr_size_t retlen, const char* srcstr){ /* TODO: The computations could preconvert the string to determine * the true size of the retstr, but that's a memory over speed * tradeoff that isn't appropriate this early in development. * * Allocate the maximum string length based on leading 4 * characters of \\?\ (allowing nearly unlimited path lengths) * plus the trailing null, then transform /'s into \\'s since * the \\?\ form doesn't allow '/' path seperators. * * Note that the \\?\ form only works for local drive paths, and * \\?\UNC\ is needed UNC paths. */ apr_size_t srcremains = strlen(srcstr) + 1; apr_wchar_t *t = retstr; apr_status_t rv; /* This is correct, we don't twist the filename if it is will * definately be shorter than MAX_PATH. It merits some * performance testing to see if this has any effect, but there * seem to be applications that get confused by the resulting * Unicode \\?\ style file names, especially if they use argv[0] * or call the Win32 API functions such as GetModuleName, etc. * Not every application is prepared to handle such names. * * Note that a utf-8 name can never result in more wide chars * than the original number of utf-8 narrow chars. */ if (srcremains > MAX_PATH) { if (srcstr[1] == ':' && (srcstr[2] == '/' || srcstr[2] == '\\')) { wcscpy (retstr, L"\\\\?\\"); retlen -= 4; t += 4; } else if ((srcstr[0] == '/' || srcstr[0] == '\\') && (srcstr[1] == '/' || srcstr[1] == '\\') && (srcstr[2] != '?')) { /* Skip the slashes */ srcstr += 2; srcremains -= 2; wcscpy (retstr, L"\\\\?\\UNC\\"); retlen -= 8; t += 8; } } if (rv = apr_conv_utf8_to_ucs2(srcstr, &srcremains, t, &retlen)) { return (rv == APR_INCOMPLETE) ? APR_EINVAL : rv; } if (srcremains) { return APR_ENAMETOOLONG; } for (; *t; ++t) if (*t == L'/') *t = L'\\'; return APR_SUCCESS;}apr_status_t unicode_to_utf8_path(char* retstr, apr_size_t retlen, const apr_wchar_t* srcstr){ /* Skip the leading 4 characters if the path begins \\?\, or substitute * // for the \\?\UNC\ path prefix, allocating the maximum string * length based on the remaining string, plus the trailing null. * then transform \\'s back into /'s since the \\?\ form never * allows '/' path seperators, and APR always uses '/'s. */ apr_size_t srcremains = wcslen(srcstr) + 1; apr_status_t rv; char *t = retstr; if (srcstr[0] == L'\\' && srcstr[1] == L'\\' && srcstr[2] == L'?' && srcstr[3] == L'\\') { if (srcstr[4] == L'U' && srcstr[5] == L'N' && srcstr[6] == L'C' && srcstr[7] == L'\\') { srcremains -= 8; srcstr += 8; retstr[0] = '\\'; retstr[1] = '\\'; retlen -= 2; t += 2; } else { srcremains -= 4; srcstr += 4; } } if (rv = apr_conv_ucs2_to_utf8(srcstr, &srcremains, t, &retlen)) { return rv; } if (srcremains) { return APR_ENAMETOOLONG; } return APR_SUCCESS;}#endifvoid *res_name_from_filename(const char *file, int global, apr_pool_t *pool){#if APR_HAS_UNICODE_FS IF_WIN_OS_IS_UNICODE { apr_wchar_t *wpre, *wfile, *ch; apr_size_t n = strlen(file) + 1; apr_size_t r, d; apr_status_t rv; if (apr_os_level >= APR_WIN_2000) { if (global) wpre = L"Global\\"; else wpre = L"Local\\"; } else wpre = L""; r = wcslen(wpre); if (n > 256 - r) { file += n - 256 - r; n = 256; /* skip utf8 continuation bytes */ while ((*file & 0xC0) == 0x80) { ++file; --n; } } wfile = apr_palloc(pool, (r + n) * sizeof(apr_wchar_t)); wcscpy(wfile, wpre); d = n; if (rv = apr_conv_utf8_to_ucs2(file, &n, wfile + r, &d)) { return NULL; } for (ch = wfile + r; *ch; ++ch) { if (*ch == ':' || *ch == '/' || *ch == '\\') *ch = '_'; } return wfile; }#endif#if APR_HAS_ANSI_FS ELSE_WIN_OS_IS_ANSI { char *nfile, *ch; apr_size_t n = strlen(file) + 1;#if !APR_HAS_UNICODE_FS apr_status_t rv; apr_size_t r, d; char *pre; if (apr_os_level >= APR_WIN_2000) { if (global) pre = "Global\\"; else pre = "Local\\"; } else pre = ""; r = strlen(pre); if (n > 256 - r) { file += n - 256 - r; n = 256; } nfile = apr_palloc(pool, (r + n) * sizeof(apr_wchar_t)); memcpy(nfile, pre, r); memcpy(nfile + r, file, n);#else const apr_size_t r = 0; if (n > 256) { file += n - 256; n = 256; } nfile = apr_pmemdup(pool, file, n);#endif for (ch = nfile + r; *ch; ++ch) { if (*ch == ':' || *ch == '/' || *ch == '\\') *ch = '_'; } return nfile; }#endif}apr_status_t file_cleanup(void *thefile){ apr_file_t *file = thefile; apr_status_t flush_rv = APR_SUCCESS; if (file->filehand != INVALID_HANDLE_VALUE) { /* In order to avoid later segfaults with handle 'reuse', * we must protect against the case that a dup2'ed handle * is being closed, and invalidate the corresponding StdHandle */ if (file->filehand == GetStdHandle(STD_ERROR_HANDLE)) { SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE); } if (file->filehand == GetStdHandle(STD_OUTPUT_HANDLE)) { SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE); } if (file->filehand == GetStdHandle(STD_INPUT_HANDLE)) { SetStdHandle(STD_INPUT_HANDLE, INVALID_HANDLE_VALUE); } if (file->buffered) { /* XXX: flush here is not mutex protected */ flush_rv = apr_file_flush((apr_file_t *)thefile); } CloseHandle(file->filehand); file->filehand = INVALID_HANDLE_VALUE; } if (file->pOverlapped && file->pOverlapped->hEvent) { CloseHandle(file->pOverlapped->hEvent); file->pOverlapped = NULL; } return flush_rv;}APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new, const char *fname, apr_int32_t flag, apr_fileperms_t perm, apr_pool_t *pool){ HANDLE handle = INVALID_HANDLE_VALUE; DWORD oflags = 0; DWORD createflags = 0; DWORD attributes = 0; DWORD sharemode = FILE_SHARE_READ | FILE_SHARE_WRITE; apr_status_t rv; if (flag & APR_READ) { oflags |= GENERIC_READ; } if (flag & APR_WRITE) { oflags |= GENERIC_WRITE; } if (flag & APR_WRITEATTRS) { oflags |= FILE_WRITE_ATTRIBUTES; } if (apr_os_level >= APR_WIN_NT) sharemode |= FILE_SHARE_DELETE; if (flag & APR_CREATE) { if (flag & APR_EXCL) { /* only create new if file does not already exist */ createflags = CREATE_NEW; } else if (flag & APR_TRUNCATE) { /* truncate existing file or create new */ createflags = CREATE_ALWAYS; } else { /* open existing but create if necessary */ createflags = OPEN_ALWAYS; } } else if (flag & APR_TRUNCATE) { /* only truncate if file already exists */ createflags = TRUNCATE_EXISTING; } else { /* only open if file already exists */ createflags = OPEN_EXISTING; } if ((flag & APR_EXCL) && !(flag & APR_CREATE)) { return APR_EACCES; } if (flag & APR_DELONCLOSE) { attributes |= FILE_FLAG_DELETE_ON_CLOSE; } if (flag & APR_OPENLINK) { attributes |= FILE_FLAG_OPEN_REPARSE_POINT; } /* Without READ or WRITE, we fail unless apr called apr_file_open * internally with the private APR_OPENINFO flag. * * With the APR_OPENINFO flag on NT, use the option flag * FILE_FLAG_BACKUP_SEMANTICS to allow us to open directories. * See the static resolve_ident() fn in file_io/win32/filestat.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -