wrowe 01/01/31 21:44:19
Modified: file_io/win32 dir.c filestat.c
Log:
- refactored out the common APR_FINFO_MIN setup into a single fillin
function for consistency [required a small, slightly ugly hack.]
- reverted the protection change from earlier today. Apache no longer
requests protections (unless they truly need it, say in mod_dav_fs),
and no longer assumes that the protection member reflects existance.
- Added the name member to apr_stat, such that if APR_FINFO_NAME is
requested from apr_stat/lstat, the name in true case is returned.
This patch prepares for canonical optmization of Apache. [The code
chooses to FindFirstFile instead of GetFileAttributesEx iff that
field is required.]
- Remaining needs; return name from apr_getfileinfo if it is reasonable,
return device/inode/nlink from stat/dir_read if reasonable.
Revision Changes Path
1.51 +3 -35 apr/file_io/win32/dir.c
Index: dir.c
===================================================================
RCS file: /home/cvs/apr/file_io/win32/dir.c,v
retrieving revision 1.50
retrieving revision 1.51
diff -u -r1.50 -r1.51
--- dir.c 2001/01/29 06:21:40 1.50
+++ dir.c 2001/02/01 05:44:17 1.51
@@ -213,43 +213,11 @@
fname = thedir->n.entry->cFileName;
}
- memset(finfo, '\0', sizeof(*finfo));
- finfo->name = fname;
- finfo->valid = APR_FINFO_WIN32_DIR;
+ fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) thedir->w.entry, 0);
finfo->cntxt = thedir->cntxt;
-
- /* Do the best job we can determining the file type.
- * Win32 only returns device names in a directory in response to a
specific
- * request (e.g. FindFirstFile("CON"), not to wildcards, so we will
ignore
- * the BLK, CHR, and other oddballs, since they should -not- occur in
this
- * context.
- */
- if (thedir->n.entry->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
- finfo->filetype = APR_LNK;
- finfo->valid |= APR_FINFO_TYPE;
- }
- else if (thedir->n.entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- finfo->filetype = APR_DIR;
- finfo->valid |= APR_FINFO_TYPE;
- }
- else {
- finfo->filetype = APR_REG;
- finfo->valid |= APR_FINFO_TYPE;
- }
- FileTimeToAprTime(&finfo->ctime, &thedir->n.entry->ftCreationTime);
- FileTimeToAprTime(&finfo->mtime, &thedir->n.entry->ftLastWriteTime);
- FileTimeToAprTime(&finfo->atime, &thedir->n.entry->ftLastAccessTime);
-#if APR_HAS_LARGE_FILES
- finfo->size = ((apr_off_t)thedir->n.entry->nFileSizeHigh << 32)
- | (apr_off_t)thedir->n.entry->nFileSizeLow;
-#else
- finfo->size = (apr_off_t)thedir->n.entry->nFileSizeLow;
- if (finfo->size < 0 || FileInformation.nFileSizeHigh)
- finfo->size = 0x7fffffff;
-#endif
- if (thedir->n.entry->dwFileAttributes & FILE_ATTRIBUTE_READONLY)
- finfo->protection = APR_FREADONLY;
+ finfo->valid |= APR_FINFO_NAME;
+ finfo->name = fname;
if (wanted &= ~finfo->valid) {
/* Go back and get more_info if we can't answer the whole inquiry
1.46 +134 -122 apr/file_io/win32/filestat.c
Index: filestat.c
===================================================================
RCS file: /home/cvs/apr/file_io/win32/filestat.c,v
retrieving revision 1.45
retrieving revision 1.46
diff -u -r1.45 -r1.46
--- filestat.c 2001/01/31 20:01:16 1.45
+++ filestat.c 2001/02/01 05:44:17 1.46
@@ -195,16 +195,27 @@
PACL dacl = NULL;
apr_status_t rv;
- if (whatfile == MORE_OF_WFSPEC)
- (apr_wchar_t*)ufile;
- else if (whatfile == MORE_OF_FSPEC)
- (char*)ufile;
- else if (whatfile == MORE_OF_HANDLE)
- (HANDLE)ufile;
+ if (os_level < APR_WIN_NT)
+ {
+ /* Read, write execute for owner. In the Win9x environment, any
+ * readable file is executable (well, not entirely 100% true, but
+ * still looking for some cheap logic that would help us here.)
+ */
+ if (finfo->protection & APR_FREADONLY) {
+ finfo->protection |= APR_WREAD | APR_WEXECUTE;
+ }
+ else {
+ finfo->protection |= APR_WREAD | APR_WEXECUTE | APR_WWRITE;
+ }
+ finfo->protection |= (finfo->protection << prot_scope_group)
+ | (finfo->protection << prot_scope_user);
- if ((wanted & (APR_FINFO_PROT | APR_FINFO_OWNER))
- && os_level >= APR_WIN_NT)
+ finfo->valid |= APR_FINFO_UPROT | APR_FINFO_GPROT | APR_FINFO_WPROT;
+ }
+ else if (wanted & (APR_FINFO_PROT | APR_FINFO_OWNER))
{
+ /* On NT this request is incredibly expensive, but accurate.
+ */
SECURITY_INFORMATION sinf = 0;
PSECURITY_DESCRIPTOR pdesc = NULL;
if (wanted & (APR_FINFO_USER | APR_FINFO_UPROT))
@@ -256,91 +267,109 @@
}
}
- if (!(finfo->valid & APR_FINFO_UPROT)) {
- /* Read, write execute for owner. In the Win32 environment,
- * anything readable is executable (well, not entirely 100% true,
- * but I'm looking for some obvious logic that would help us here.)
- */
- if (finfo->protection & APR_FREADONLY) {
- finfo->protection |= S_IREAD | S_IEXEC;
- }
- else {
- finfo->protection |= S_IREAD | S_IWRITE | S_IEXEC;
- }
- finfo->valid |= APR_FINFO_UPROT;
- }
-
return ((wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS);
}
-APR_DECLARE(apr_status_t) apr_getfileinfo(apr_finfo_t *finfo, apr_int32_t
wanted,
- apr_file_t *thefile)
+/* This generic fillin depends upon byhandle to be passed as 0 when
+ * a WIN32_FILE_ATTRIBUTE_DATA or either WIN32_FIND_DATA [A or W] is
+ * passed for wininfo. When the BY_HANDLE_FILE_INFORMATION structure
+ * is passed for wininfo, byhandle is passed as 1 to offset the one
+ * dword discrepancy in the High/Low size structure members.
+ */
+void fillin_fileinfo(apr_finfo_t *finfo, WIN32_FILE_ATTRIBUTE_DATA *wininfo,
+ int byhandle)
{
- BY_HANDLE_FILE_INFORMATION FileInformation;
- apr_oslevel_e os_level;
+ DWORD *sizes = &wininfo->nFileSizeHigh + byhandle;
- if (!GetFileInformationByHandle(thefile->filehand, &FileInformation)) {
- return apr_get_os_error();
- }
-
memset(finfo, '\0', sizeof(*finfo));
- finfo->cntxt = thefile->cntxt;
- FileTimeToAprTime(&finfo->atime, &FileInformation.ftLastAccessTime);
- FileTimeToAprTime(&finfo->ctime, &FileInformation.ftCreationTime);
- FileTimeToAprTime(&finfo->mtime, &FileInformation.ftLastWriteTime);
-
- finfo->inode = (apr_ino_t)FileInformation.nFileIndexLow
- | ((apr_ino_t)FileInformation.nFileIndexHigh << 32);
- finfo->device = FileInformation.dwVolumeSerialNumber;
- finfo->nlink = FileInformation.nNumberOfLinks;
+ FileTimeToAprTime(&finfo->atime, &wininfo->ftLastAccessTime);
+ FileTimeToAprTime(&finfo->ctime, &wininfo->ftCreationTime);
+ FileTimeToAprTime(&finfo->mtime, &wininfo->ftLastWriteTime);
#if APR_HAS_LARGE_FILES
- finfo->size = (apr_off_t)FileInformation.nFileSizeLow
- | ((apr_off_t)FileInformation.nFileSizeHigh << 32);
+ finfo->size = (apr_off_t)sizes[1]
+ | ((apr_off_t)sizes[0] << 32);
#else
- finfo->size = (apr_off_t)FileInformation.nFileSizeLow;
- if (finfo->size < 0 || FileInformation.nFileSizeHigh)
+ finfo->size = (apr_off_t)sizes[1];
+ if (finfo->size < 0 || sizes[0])
finfo->size = 0x7fffffff;
#endif
+
+ if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ finfo->filetype = APR_LNK;
+ }
+ else if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ finfo->filetype = APR_DIR;
+ }
+ else {
+ /* XXX: Solve this: Short of opening the handle to the file, the
+ * 'FileType' appears to be unknowable (in any trustworthy or
+ * consistent sense), that is, as far as PIPE, CHR, etc are
concerned.
+ */
+ finfo->filetype = APR_REG;
+ }
+
+ /* The following flags are [for this moment] private to Win32.
+ * That's the only excuse for not toggling valid bits to reflect them.
+ */
+ if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_READONLY)
+ finfo->protection = APR_FREADONLY;
finfo->valid = APR_FINFO_ATIME | APR_FINFO_CTIME | APR_FINFO_MTIME
- | APR_FINFO_IDENT | APR_FINFO_NLINK | APR_FINFO_SIZE;
+ | APR_FINFO_SIZE | APR_FINFO_TYPE; /* == APR_FINFO_MIN */
+}
+
+
+APR_DECLARE(apr_status_t) apr_getfileinfo(apr_finfo_t *finfo, apr_int32_t
wanted,
+ apr_file_t *thefile)
+{
+ BY_HANDLE_FILE_INFORMATION FileInfo;
+
+ if (!GetFileInformationByHandle(thefile->filehand, &FileInfo)) {
+ return apr_get_os_error();
+ }
+ fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) &FileInfo, 1);
+ finfo->cntxt = thefile->cntxt;
+
+ /* Extra goodies known only by GetFileInformationByHandle() */
+ finfo->inode = (apr_ino_t)FileInfo.nFileIndexLow
+ | ((apr_ino_t)FileInfo.nFileIndexHigh << 32);
+ finfo->device = FileInfo.dwVolumeSerialNumber;
+ finfo->nlink = FileInfo.nNumberOfLinks;
+
+ finfo->valid |= APR_FINFO_IDENT | APR_FINFO_NLINK;
- if (wanted & APR_FINFO_TYPE)
+ if ((wanted & APR_FINFO_TYPE) && (APR_FINFO_TYPE == APR_REG))
{
+ /* Go the extra mile to be -certain- that we have a real, regular
+ * file, since the attribute bits aren't a certain thing.
+ */
DWORD FileType;
- if (FileInformation.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
{
- finfo->filetype = APR_LNK;
- finfo->valid |= APR_FINFO_TYPE;
- }
- else if (FileInformation.dwFileAttributes &
FILE_ATTRIBUTE_DIRECTORY) {
- finfo->filetype = APR_DIR;
- finfo->valid |= APR_FINFO_TYPE;
- }
- else if (FileType = GetFileType(thefile->filehand)) {
+ if (FileType = GetFileType(thefile->filehand)) {
if (FileType == FILE_TYPE_DISK) {
finfo->filetype = APR_REG;
- finfo->valid |= APR_FINFO_TYPE;
}
else if (FileType == FILE_TYPE_CHAR) {
finfo->filetype = APR_CHR;
- finfo->valid |= APR_FINFO_TYPE;
}
else if (FileType == FILE_TYPE_PIPE) {
finfo->filetype = APR_PIPE;
- finfo->valid |= APR_FINFO_TYPE;
+ }
+ else {
+ finfo->filetype = APR_NOFILE;
}
}
}
-
- if (FileInformation.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
- finfo->protection = APR_FREADONLY;
- if (wanted &= ~finfo->valid)
+ if (wanted &= ~finfo->valid) {
+ apr_oslevel_e os_level;
+ if (apr_get_oslevel(thefile->cntxt, &os_level))
+ os_level = APR_WIN_95;
return more_finfo(finfo, thefile->filehand, wanted, MORE_OF_HANDLE,
os_level);
+ }
return APR_SUCCESS;
}
@@ -357,12 +386,15 @@
#ifdef APR_HAS_UNICODE_FS
apr_wchar_t wfname[APR_PATH_MAX];
#endif
- /*
- * The WIN32_FILE_ATTRIBUTE_DATA is a subset of this structure
- */
- WIN32_FIND_DATA FileInformation;
apr_oslevel_e os_level;
-
+ char *filename = NULL;
+ /* These all share a common subset of this structure */
+ union {
+ WIN32_FIND_DATAW w;
+ WIN32_FIND_DATAA n;
+ WIN32_FILE_ATTRIBUTE_DATA i;
+ } FileInfo;
+
if (apr_get_oslevel(cont, &os_level))
os_level = APR_WIN_95;
@@ -380,85 +412,65 @@
if (rv = utf8_to_unicode_path(wfname, sizeof(wfname)
/ sizeof(apr_wchar_t), fname))
return rv;
- if (!GetFileAttributesExW(wfname, GetFileExInfoStandard,
- &FileInformation)) {
- return apr_get_os_error();
+ if (!(wanted & APR_FINFO_NAME)) {
+ if (!GetFileAttributesExW(wfname, GetFileExInfoStandard,
+ &FileInfo.i))
+ return apr_get_os_error();
}
+ else {
+ /* Guard against bogus wildcards and retrieve by name
+ * since we want the true name, and set aside a long
+ * enough string to handle the longest file name.
+ */
+ char tmpname[APR_FILE_MAX * 3 + 1];
+ HANDLE hFind;
+ if (strchr(fname, '*') || strchr(fname, '?'))
+ return APR_ENOENT;
+ hFind = FindFirstFileW(wfname, &FileInfo.w);
+ if (hFind == INVALID_HANDLE_VALUE)
+ return apr_get_os_error();
+ FindClose(hFind);
+ if (unicode_to_utf8_path(tmpname, sizeof(tmpname),
+ FileInfo.w.cFileName)) {
+ return APR_ENAMETOOLONG;
+ }
+ filename = apr_pstrdup(cont, tmpname);
+ }
}
else
#endif
- if (os_level >= APR_WIN_98) {
+ if ((os_level >= APR_WIN_98) && !(wanted & APR_FINFO_NAME))
+ {
if (!GetFileAttributesExA(fname, GetFileExInfoStandard,
- &FileInformation)) {
+ &FileInfo.i)) {
return apr_get_os_error();
}
}
else {
- /* What a waste of cpu cycles... but we don't have a choice
- * Be sure we insulate ourselves against bogus wildcards
+ /* Guard against bogus wildcards and retrieve by name
+ * since we want the true name, or are stuck in Win95
*/
HANDLE hFind;
if (strchr(fname, '*') || strchr(fname, '?'))
return APR_ENOENT;
- hFind = FindFirstFile(fname, &FileInformation);
+ hFind = FindFirstFileA(fname, &FileInfo.n);
if (hFind == INVALID_HANDLE_VALUE) {
return apr_get_os_error();
}
- else {
- FindClose(hFind);
- }
+ FindClose(hFind);
+ filename = apr_pstrdup(cont, FileInfo.n.cFileName);
}
- memset(finfo, '\0', sizeof(*finfo));
+ fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) &FileInfo, 0);
finfo->cntxt = cont;
- finfo->valid = APR_FINFO_ATIME | APR_FINFO_CTIME | APR_FINFO_MTIME
- | APR_FINFO_SIZE | APR_FINFO_TYPE; /* I.e., APR_FINFO_MIN */
-
- /* File times */
- FileTimeToAprTime(&finfo->atime, &FileInformation.ftLastAccessTime);
- FileTimeToAprTime(&finfo->ctime, &FileInformation.ftCreationTime);
- FileTimeToAprTime(&finfo->mtime, &FileInformation.ftLastWriteTime);
-#if APR_HAS_LARGE_FILES
- finfo->size = (apr_off_t)FileInformation.nFileSizeLow
- | ((apr_off_t)FileInformation.nFileSizeHigh << 32);
-#else
- finfo->size = (apr_off_t)FileInformation.nFileSizeLow;
- if (finfo->size < 0 || FileInformation.nFileSizeHigh)
- finfo->size = 0x7fffffff;
-#endif
-
- /* Filetype - Directory or file?
- */
- if (FileInformation.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
- finfo->filetype = APR_LNK;
- }
- else if (FileInformation.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- finfo->filetype = APR_DIR;
- }
- else {
- /* XXX: Solve this
- * Short of opening the handle to the file, the 'FileType' appears
- * to be unknowable (in any trustworthy or consistent sense), that
- * is, as far as PIPE, CHR, etc.
- */
- finfo->filetype = APR_REG;
- }
-
- /*
- * Hummm, should we assume the file is always executable? Is there a way
- * to know other than guess based on the file extension or make an
- * expensive system call?
- */
- if (FileInformation.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
- finfo->protection |= S_IREAD | S_IEXEC;
- }
- else {
- finfo->protection |= S_IREAD | S_IWRITE | S_IEXEC;
+ if (filename) {
+ finfo->name = filename;
+ finfo->valid |= APR_FINFO_NAME;
}
if (wanted &= ~finfo->valid) {
- /* Caller wants more than APR_FINFO_MIN */
+ /* Caller wants more than APR_FINFO_MIN | APR_FINFO_NAME */
#ifdef APR_HAS_UNICODE_FS
if (os_level >= APR_WIN_NT)
return more_finfo(finfo, wfname, wanted, MORE_OF_WFSPEC,
os_level);