wrowe 01/01/27 14:25:11
Modified: file_io/win32 dir.c filestat.c open.c
include apr.h.in apr.hw
include/arch/win32 fileio.h
Log:
This patch sets the server running once again, except in cases where
it still expects APR_SUCCESS responses to an APR_FINFO_NORM apr_stat.
Most of those are gone, those that remain are hiding in the modules.
Radically refactored apr_stat/lstat/getfileinfo/dir_read for Win32
to assure we are retrieving what we expect to retrieve, and reporting
the correct result (APR_SUCCESS or APR_INCOMPLETE). The potential
for a bit more optimization still remains.
While we have the future opportunity to cache the apr_stat'ed file
handle for a very fast open (dup handle) on Win32, patched to close
that file after a stat always. Needs a new semantic before we leave
handles dangling when the user intends to rm.
Correct Win32 apr_stat/lstat/getfileinfo/dir_read to all zero out
the finfo buffer on success (or incomplete success).
Fix Win32/Unix apr_lstat to throw the .valid bit APR_FINFO_LINK to
indicate we attempted to open the link. Only the .filetype APR_LNK
reflects if the file found was, in fact, a link.
Revision Changes Path
1.48 +15 -15 apr/file_io/win32/dir.c
Index: dir.c
===================================================================
RCS file: /home/cvs/apr/file_io/win32/dir.c,v
retrieving revision 1.47
retrieving revision 1.48
diff -u -r1.47 -r1.48
--- dir.c 2001/01/24 21:13:13 1.47
+++ dir.c 2001/01/27 22:25:10 1.48
@@ -146,6 +146,7 @@
apr_dir_t *thedir)
{
apr_status_t rv;
+ char *fname;
/* The while loops below allow us to skip all invalid file names, so that
* we aren't reporting any files where their absolute paths are too long.
*/
@@ -183,7 +184,7 @@
if (rv = unicode_to_utf8_path(thedir->name, APR_FILE_MAX * 3 + 1,
thedir->w.entry->cFileName))
return rv;
- finfo->name = thedir->name;
+ fname = thedir->name;
}
else
#endif
@@ -208,28 +209,28 @@
return apr_get_os_error();
}
}
- finfo->name = thedir->n.entry->cFileName;
+ fname = thedir->n.entry->cFileName;
}
- finfo->valid = APR_FINFO_NAME | APR_FINFO_TYPE | APR_FINFO_CTIME
- | APR_FINFO_ATIME | APR_FINFO_MTIME | APR_FINFO_SIZE;
- wanted |= ~finfo->valid;
- if (wanted) {
- /* Win32 apr_stat() is about to open a handle to this file.
- * we must create a full path that doesn't evaporate.
- */
- const char *fname = finfo->name;
- char *fspec = apr_pstrcat(thedir->cntxt, thedir->dirname,
- finfo->name, NULL);
- finfo->valid = 0;
+ if (wanted & ~APR_FINFO_WIN32_DIR) {
+ char fspec[APR_PATH_MAX];
+ int dirlen = strlen(thedir->dirname);
+ if (dirlen >= sizeof(fspec))
+ dirlen = sizeof(fspec) - 1;
+ apr_cpystrn(fspec, sizeof(fspec), thedir->dirname);
+ apr_cpystrn(fspec + dirlen, sizeof(fspec) - dirlen, fname);
rv = apr_stat(finfo, fspec, wanted, thedir->cntxt);
if (rv == APR_SUCCESS || rv == APR_INCOMPLETE) {
finfo->valid |= APR_FINFO_NAME;
finfo->name = fname;
finfo->fname = fspec;
+ rv = (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
}
return rv;
}
+ memset(finfo, '\0', sizeof(*finfo));
+ finfo->name = fname;
+ finfo->valid = APR_FINFO_WIN32_DIR;
finfo->cntxt = thedir->cntxt;
/* Do the best job we can determining the file type.
@@ -255,8 +256,7 @@
FileTimeToAprTime(&finfo->atime, &thedir->n.entry->ftLastAccessTime);
finfo->size = (thedir->n.entry->nFileSizeHigh * MAXDWORD)
+ thedir->n.entry->nFileSizeLow;
- finfo->fname = NULL;
- return APR_SUCCESS;
+ return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_dir_rewind(apr_dir_t *dir)
1.40 +91 -101 apr/file_io/win32/filestat.c
Index: filestat.c
===================================================================
RCS file: /home/cvs/apr/file_io/win32/filestat.c,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -r1.39 -r1.40
--- filestat.c 2001/01/23 04:10:46 1.39
+++ filestat.c 2001/01/27 22:25:10 1.40
@@ -68,75 +68,33 @@
apr_file_t *thefile)
{
BY_HANDLE_FILE_INFORMATION FileInformation;
- DWORD FileType;
- apr_oslevel_e os_level;
if (!GetFileInformationByHandle(thefile->filehand, &FileInformation)) {
return apr_get_os_error();
}
- FileType = GetFileType(thefile->filehand);
- if (!FileType) {
- return apr_get_os_error();
- }
+ memset(finfo, '\0', sizeof(*finfo));
- /* If my rudimentary knowledge of posix serves... inode is the absolute
- * id of the file (uniquifier) that is returned by NT (not 9x) as
follows:
- */
- if (apr_get_oslevel(thefile->cntxt, &os_level) || os_level >=
APR_WIN_NT)
- {
- finfo->inode = (apr_ino_t) FileInformation.nFileIndexHigh << 16
- | FileInformation.nFileIndexLow;
- finfo->device = FileInformation.dwVolumeSerialNumber;
- }
- else
- {
- /* Since the apr_stat is not implemented with CreateFile(),
- * (directories can't be opened with CreateFile() at all)
- * the apr_stat always returns 0 - so must apr_getfileinfo().
- */
- finfo->inode = 0;
- finfo->device = 0;
- }
- /* user and group could be returned as SID's, although this creates
- * it's own unique set of issues. All three fields are significantly
- * longer than the posix compatible kernals would ever require.
- * TODO: Someday solve this, and fix the executable flag below the
- * right way with a security permission test (as well as r/w flags.)
- */
- finfo->user = 0;
- finfo->group = 0;
-
- /* Filetype - Directory or file: this case _will_ never happen */
- if (FileInformation.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
- finfo->protection = S_IFLNK;
- finfo->filetype = APR_LNK;
- }
- else if (FileInformation.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- finfo->protection = S_IFDIR;
- finfo->filetype = APR_DIR;
- }
- else if (FileType == FILE_TYPE_DISK) {
- finfo->protection = S_IFREG;
- finfo->filetype = APR_REG;
- }
- else if (FileType == FILE_TYPE_CHAR) {
- finfo->protection = S_IFCHR;
- finfo->filetype = APR_CHR;
- }
- else if (FileType == FILE_TYPE_PIPE) {
- finfo->protection = S_IFIFO;
- finfo->filetype = APR_PIPE;
- }
- else {
- finfo->protection = 0;
- finfo->filetype = APR_NOFILE;
- }
+ FileTimeToAprTime(&finfo->atime, &FileInformation.ftLastAccessTime);
+ FileTimeToAprTime(&finfo->ctime, &FileInformation.ftCreationTime);
+ FileTimeToAprTime(&finfo->mtime, &FileInformation.ftLastWriteTime);
- /* Read, write execute for owner
- * In the Win32 environment, anything readable is executable
- * (well, not entirely 100% true, but I'm looking for a way
- * to get at the acl permissions in simplified fashion.)
+ finfo->inode = (apr_ino_t)FileInformation.nFileIndexLow
+ | ((apr_ino_t)FileInformation.nFileIndexHigh << 32);
+ finfo->device = FileInformation.dwVolumeSerialNumber;
+ finfo->nlink = FileInformation.nNumberOfLinks;
+
+#if APR_HAS_LARGE_FILES
+ finfo->size = (apr_off_t)FileInformation.nFileSizeLow
+ | ((apr_off_t)FileInformation.nFileSizeHigh << 32);
+#else
+ finfo->size = FileInformation.nFileSizeLow;
+#endif
+
+ /* 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.)
+ * TODO: The real permissions come from the DACL
*/
if (FileInformation.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
finfo->protection |= S_IREAD | S_IEXEC;
@@ -145,15 +103,46 @@
finfo->protection |= S_IREAD | S_IWRITE | S_IEXEC;
}
- /* File times */
- FileTimeToAprTime(&finfo->atime, &FileInformation.ftLastAccessTime);
- FileTimeToAprTime(&finfo->ctime, &FileInformation.ftCreationTime);
- FileTimeToAprTime(&finfo->mtime, &FileInformation.ftLastWriteTime);
+ /* TODO: return user and group could as * SID's, allocated in the pool.
+ * [These are variable length objects that will require a 'comparitor'
+ * and a 'get readable string of' functions.]
+ */
+
+ finfo->valid = APR_FINFO_ATIME | APR_FINFO_CTIME | APR_FINFO_MTIME
+ | APR_FINFO_IDENT | APR_FINFO_NLINK | APR_FINFO_SIZE
+ | APR_FINFO_UPROT;
- /* File size
- * Note: This cannot handle files greater than can be held by an int */
- finfo->size = FileInformation.nFileSizeLow;
+ if (wanted & APR_FINFO_TYPE)
+ {
+ 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 == 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;
+ }
+ }
+ }
+
+ if (wanted & ~finfo->valid)
+ return APR_INCOMPLETE;
+
return APR_SUCCESS;
}
@@ -174,7 +163,7 @@
* since in many cases the apr user is testing for 'not found'
* and this is not such a case.
*/
- if (!apr_get_oslevel(cont, &os_level) && os_level >= APR_WIN_NT)
+ if (!apr_get_oslevel(cont, &os_level) && os_level >= APR_WIN_NT)
{
apr_file_t *thefile = NULL;
apr_status_t rv;
@@ -187,37 +176,36 @@
* user, group or permissions.
*/
- if (rv = apr_open(&thefile, fname,
- ((wanted & APR_FINFO_LINK) ? APR_OPENLINK : 0)
- | ((wanted & (APR_FINFO_PROT | APR_FINFO_OWNER))
- ? APR_READCONTROL : 0), APR_OS_DEFAULT, cont))
- {
+ if ((rv = apr_open(&thefile, fname,
+ ((wanted & APR_FINFO_LINK) ? APR_OPENLINK : 0)
+ | ((wanted & (APR_FINFO_PROT | APR_FINFO_OWNER))
+ ? APR_READCONTROL : 0),
+ APR_OS_DEFAULT, cont)) == APR_SUCCESS) {
+ rv = apr_getfileinfo(finfo, wanted, thefile);
+ finfo->filehand = NULL;
+ apr_close(thefile);
+ }
+ else if (APR_STATUS_IS_EACCES(rv) && (wanted & (APR_FINFO_PROT
+ | APR_FINFO_OWNER))) {
/* We have a backup plan. Perhaps we couldn't grab READ_CONTROL?
- * proceed with the alternate...
+ * proceed without asking for that permission...
*/
- if (wanted & (APR_FINFO_PROT | APR_FINFO_OWNER)) {
- rv = apr_open(&thefile, fname,
- ((wanted & APR_FINFO_LINK) ? APR_OPENLINK : 0),
- APR_OS_DEFAULT, cont);
- wanted &= ~(APR_FINFO_PROT | APR_FINFO_OWNER);
+ if ((rv = apr_open(&thefile, fname,
+ ((wanted & APR_FINFO_LINK) ? APR_OPENLINK :
0),
+ APR_OS_DEFAULT, cont)) == APR_SUCCESS) {
+ rv = apr_getfileinfo(finfo, wanted & ~(APR_FINFO_PROT
+ | APR_FINFO_OWNER),
+ thefile);
+ finfo->filehand = NULL;
+ apr_close(thefile);
}
- if (rv)
- return rv;
}
-
- /*
- * NT5 (W2K) only supports symlinks in the same manner as mount
points.
- * This code should eventually take that into account, for now treat
- * every reparse point as a symlink...
- *
- * We must open the file with READ_CONTROL if we plan to retrieve the
- * user, group or permissions.
- */
- rv = apr_getfileinfo(finfo, wanted, thefile);
- finfo->cntxt = thefile->cntxt;
+ if (rv != APR_SUCCESS && rv != APR_INCOMPLETE)
+ return (rv);
+ /* We picked up this case above and had opened the link's properties
*/
+ if (wanted & APR_FINFO_LINK)
+ finfo->valid |= APR_FINFO_LINK;
finfo->fname = thefile->fname;
- finfo->filehand = thefile;
- return (rv);
}
else
{
@@ -230,15 +218,13 @@
if (strlen(fname) >= MAX_PATH) {
return APR_ENAMETOOLONG;
}
- else if (os_level >= APR_WIN_98)
- {
+ else if (os_level >= APR_WIN_98) {
if (!GetFileAttributesEx(fname, GetFileExInfoStandard,
&FileInformation)) {
return apr_get_os_error();
}
}
- else
- {
+ else {
/* What a waste of cpu cycles... but we don't have a choice
*/
HANDLE hFind;
@@ -247,7 +233,8 @@
hFind = FindFirstFile(fname, &FileInformation);
if (hFind == INVALID_HANDLE_VALUE) {
return apr_get_os_error();
- } else {
+ }
+ else {
FindClose(hFind);
}
}
@@ -301,6 +288,9 @@
if (finfo->size < 0 || FileInformation.nFileSizeHigh)
finfo->size = 0x7fffffff;
}
+ if (wanted & ~finfo->valid)
+ return APR_INCOMPLETE;
+
return APR_SUCCESS;
}
1.69 +5 -8 apr/file_io/win32/open.c
Index: open.c
===================================================================
RCS file: /home/cvs/apr/file_io/win32/open.c,v
retrieving revision 1.68
retrieving revision 1.69
diff -u -r1.68 -r1.69
--- open.c 2001/01/27 17:57:02 1.68
+++ open.c 2001/01/27 22:25:10 1.69
@@ -175,7 +175,7 @@
HANDLE handle = INVALID_HANDLE_VALUE;
DWORD oflags = 0;
DWORD createflags = 0;
- DWORD attributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN;
+ DWORD attributes = 0 /* FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_SEQUENTIAL_SCAN*/;
DWORD sharemode = FILE_SHARE_READ | FILE_SHARE_WRITE;
apr_oslevel_e os_level;
apr_status_t rv;
@@ -189,8 +189,6 @@
if (!apr_get_oslevel(cont, &os_level) && os_level >= APR_WIN_NT)
sharemode |= FILE_SHARE_DELETE;
- else
- os_level = 0;
if (flag & APR_CREATE) {
if (flag & APR_EXCL) {
@@ -218,15 +216,14 @@
if (flag & APR_DELONCLOSE) {
attributes |= FILE_FLAG_DELETE_ON_CLOSE;
}
- if (flag & APR_OPENLINK) {
- attributes |= FILE_FLAG_OPEN_REPARSE_POINT;
+ if (flag & APR_OPENLINK) {
+ attributes |= FILE_FLAG_OPEN_REPARSE_POINT;
}
if (!(flag & (APR_READ | APR_WRITE)) && (os_level >= APR_WIN_NT)) {
/* We once failed here, but this is how one opens
- * a directory as a file under winnt. Accelerate
- * further by not hitting storage, we don't need to.
+ * a directory as a file under winnt
*/
- attributes |= FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_NO_RECALL;
+ attributes |= FILE_FLAG_BACKUP_SEMANTICS;
}
if (flag & APR_XTHREAD) {
/* This win32 specific feature is required
1.63 +1 -0 apr/include/apr.h.in
Index: apr.h.in
===================================================================
RCS file: /home/cvs/apr/include/apr.h.in,v
retrieving revision 1.62
retrieving revision 1.63
diff -u -r1.62 -r1.63
--- apr.h.in 2001/01/19 07:04:35 1.62
+++ apr.h.in 2001/01/27 22:25:10 1.63
@@ -108,6 +108,7 @@
#define APR_HAS_DSO @aprdso@
#define APR_HAS_UNICODE_FS 0
#define APR_HAS_USER 1
+#define APR_HAS_LARGE_FILES 0
/* This macro tells APR that it is safe to make a file masquerade as a
* socket. This is necessary, because some platforms support poll'ing
1.48 +1 -0 apr/include/apr.hw
Index: apr.hw
===================================================================
RCS file: /home/cvs/apr/include/apr.hw,v
retrieving revision 1.47
retrieving revision 1.48
diff -u -r1.47 -r1.48
--- apr.hw 2001/01/19 07:04:35 1.47
+++ apr.hw 2001/01/27 22:25:10 1.48
@@ -187,6 +187,7 @@
#define APR_HAS_DSO 1
#define APR_HAS_UNICODE_FS 1
#define APR_HAS_USER 0
+#define APR_HAS_LARGE_FILES 1
/* Not all platforms have a real INADDR_NONE. This macro replaces
INADDR_NONE
* on all platforms.
1.43 +5 -0 apr/include/arch/win32/fileio.h
Index: fileio.h
===================================================================
RCS file: /home/cvs/apr/include/arch/win32/fileio.h,v
retrieving revision 1.42
retrieving revision 1.43
diff -u -r1.42 -r1.43
--- fileio.h 2001/01/23 19:54:42 1.42
+++ fileio.h 2001/01/27 22:25:11 1.43
@@ -135,6 +135,11 @@
#define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000
#endif
+/* Information bits available from the WIN32 FindFirstFile function */
+#define APR_FINFO_WIN32_DIR (APR_FINFO_NAME | APR_FINFO_TYPE \
+ | APR_FINFO_CTIME | APR_FINFO_ATIME \
+ | APR_FINFO_MTIME | APR_FINFO_SIZE)
+
/* quick run-down of fields in windows' apr_file_t structure that may have
* obvious uses.