wrowe 01/05/15 20:46:32
Modified: file_io/win32 filestat.c
Log:
Partially solve the char/device issue, with a couple of observations
I made testing some canonicalization. Not perfect, and needs a bit
of fleshing out, but the traveled codepath does work.
Revision Changes Path
1.51 +94 -28 apr/file_io/win32/filestat.c
Index: filestat.c
===================================================================
RCS file: /home/cvs/apr/file_io/win32/filestat.c,v
retrieving revision 1.50
retrieving revision 1.51
diff -u -r1.50 -r1.51
--- filestat.c 2001/04/13 15:31:31 1.50
+++ filestat.c 2001/05/16 03:46:32 1.51
@@ -278,12 +278,18 @@
* 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.
+ * dword discrepancy in offset of the High/Low size structure members.
+ *
+ * The generic fillin returns 1 if the caller should further inquire
+ * if this is a CHR filetype. If it's resonably certain it can't be,
+ * then the function returns 0.
*/
-void fillin_fileinfo(apr_finfo_t *finfo, WIN32_FILE_ATTRIBUTE_DATA *wininfo,
- int byhandle)
+int fillin_fileinfo(apr_finfo_t *finfo,
+ WIN32_FILE_ATTRIBUTE_DATA *wininfo,
+ int byhandle)
{
DWORD *sizes = &wininfo->nFileSizeHigh + byhandle;
+ int warn = 0;
memset(finfo, '\0', sizeof(*finfo));
@@ -306,11 +312,21 @@
else if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
finfo->filetype = APR_DIR;
}
+ else if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_DEVICE) {
+ /* Warning: This test only succeeds on Win9x, on NT these files
+ * (con, aux, nul, lpt#, com# etc) escape early detection!
+ */
+ finfo->filetype = APR_CHR;
+ }
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.
+ /* Warning: Short of opening the handle to the file, the 'FileType'
+ * appears to be unknowable (in any trustworthy or consistent sense)
+ * on WinNT/2K as far as PIPE, CHR, etc are concerned.
*/
+ if (!wininfo->ftLastWriteTime.dwLowDateTime
+ && !wininfo->ftLastWriteTime.dwHighDateTime
+ && !finfo->size)
+ warn = 1;
finfo->filetype = APR_REG;
}
@@ -322,6 +338,7 @@
finfo->valid = APR_FINFO_ATIME | APR_FINFO_CTIME | APR_FINFO_MTIME
| APR_FINFO_SIZE | APR_FINFO_TYPE; /* == APR_FINFO_MIN */
+ return warn;
}
@@ -335,38 +352,37 @@
}
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) && (APR_FINFO_TYPE == APR_REG))
+ if (finfo->filetype == 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.
+ * file, since the attribute bits aren't a certain thing. Even
+ * though fillin should have hinted if we *must* do this, we
+ * don't need to take chances while the handle is already open.
*/
DWORD FileType;
if (FileType = GetFileType(thefile->filehand)) {
- if (FileType == FILE_TYPE_DISK) {
- finfo->filetype = APR_REG;
- }
- else if (FileType == FILE_TYPE_CHAR) {
+ if (FileType == FILE_TYPE_CHAR) {
finfo->filetype = APR_CHR;
}
else if (FileType == FILE_TYPE_PIPE) {
finfo->filetype = APR_PIPE;
- }
- else {
- finfo->filetype = APR_NOFILE;
}
+ /* Otherwise leave the original conclusion alone
+ */
}
}
+ 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 &= ~finfo->valid) {
apr_oslevel_e os_level;
if (apr_get_oslevel(thefile->cntxt, &os_level))
@@ -386,6 +402,8 @@
APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname,
apr_int32_t wanted, apr_pool_t *cont)
{
+ /* XXX: is constant - needs testing - which needs a lighter-weight root
test fn */
+ int isroot = 0;
#ifdef APR_HAS_UNICODE_FS
apr_wchar_t wfname[APR_PATH_MAX];
#endif
@@ -442,16 +460,36 @@
}
else
#endif
- if ((os_level >= APR_WIN_98) && !(wanted & APR_FINFO_NAME))
+ if ((os_level >= APR_WIN_98) && (!(wanted & APR_FINFO_NAME) || isroot))
{
+ /* cannot use FindFile on a Win98 root, it returns \*
+ */
if (!GetFileAttributesExA(fname, GetFileExInfoStandard,
&FileInfo.i)) {
return apr_get_os_error();
}
}
+ else if (isroot) {
+ /* This is Win95 and we are trying to stat a root. Lie.
+ */
+ if (GetDriveType(fname) != DRIVE_UNKNOWN)
+ {
+ finfo->cntxt = cont;
+ finfo->filetype = 0;
+ finfo->mtime = apr_time_now();
+ finfo->protection |= APR_WREAD | APR_WEXECUTE | APR_WWRITE;
+ finfo->protection |= (finfo->protection << prot_scope_group)
+ | (finfo->protection << prot_scope_user);
+ finfo->valid |= APR_FINFO_TYPE | APR_FINFO_PROT |
APR_FINFO_MTIME;
+ return (wanted &= ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
+ }
+ else
+ return APR_FROM_OS_ERROR(ERROR_PATH_NOT_FOUND);
+ }
else {
/* Guard against bogus wildcards and retrieve by name
- * since we want the true name, or are stuck in Win95
+ * since we want the true name, or are stuck in Win95,
+ * or are looking for the root of a Win98 drive.
*/
HANDLE hFind;
if (strchr(fname, '*') || strchr(fname, '?'))
@@ -464,10 +502,38 @@
filename = apr_pstrdup(cont, FileInfo.n.cFileName);
}
- fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) &FileInfo, 0);
+ if (fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) &FileInfo, 0))
+ {
+ /* Go the extra mile to assure we have a file. WinNT/2000 seems
+ * to reliably translate char devices to the path '\\.\device'
+ * so go ask for the full path.
+ */
+ if (os_level >= APR_WIN_NT) {
+#ifdef APR_HAS_UNICODE_FS
+ apr_wchar_t tmpname[APR_FILE_MAX];
+ apr_wchar_t *tmpoff;
+ if (GetFullPathNameW(wfname, sizeof(tmpname) /
sizeof(apr_wchar_t),
+ tmpname, &tmpoff))
+ {
+ if ((tmpoff == tmpname + 4)
+ && !wcsncmp(tmpname, L"\\\\.\\", 4))
+ finfo->filetype = APR_CHR;
+ }
+#else
+ char tmpname[APR_FILE_MAX];
+ char *tmpoff;
+ if (GetFullPathName(fname, sizeof(tmpname), tmpname, &tmpoff))
+ {
+ if ((tmpoff == tmpname + 4)
+ && !strncmp(tmpname, "\\\\.\\", 4))
+ finfo->filetype = APR_CHR;
+ }
+#endif
+ }
+ }
finfo->cntxt = cont;
- if (filename) {
+ if (filename && !isroot) {
finfo->name = filename;
finfo->valid |= APR_FINFO_NAME;
}