You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by "William A. Rowe, Jr." <wr...@rowe-clan.net> on 2001/01/19 19:22:12 UTC

apr_stat

Thanks, everyone, who's commented so far... here's the plan;

apr_status_t apr_stat(apr_finfo_t *finfo, const char *fname, 
                      apr_int32_t wantthis, apr_pool_t *p)

wantthis is the bit flag of attributes we are interested in.  
Some will always be returned, and the apr_stat function can
always return anything _they comes for free_.  

apr_stat will reply in a new member value, finfo_valid, to 
describe the results returned.  It will only fail for the 
current reasons.  If it can't get a particular result, it 
just goes on, and it's the caller's job to check finfo.valid.

#define APR_FINFO_LINK   0x00000001
#define APR_FINFO_MTIME  0x00000010
#define APR_FINFO_CTIME  0x00000020
#define APR_FINFO_ATIME  0x00000040
#define APR_FINFO_SIZE   0x00000100
#define APR_FINFO_ASIZE  0x00000200
#define APR_FINFO_CSIZE  0x00000400
#define APR_FINFO_DEV    0x00001000
#define APR_FINFO_INODE  0x00002000
#define APR_FINFO_TYPE   0x00008000
#define APR_FINFO_USER   0x00010000 
#define APR_FINFO_GROUP  0x00020000 
#define APR_FINFO_UPROT  0x00100000 
#define APR_FINFO_GPROT  0x00200000
#define APR_FINFO_WPROT  0x00400000
#define APR_FINFO_ICASE  0x01000000  /*  dev is case insensitive */
#define APR_FINFO_FCASE  0x02000000  /*  retrieve filename case */

#define APR_FINFO_MIN    0x00008170  /*  minimal: type, dates and size */
#define APR_FINFO_IDENT  0x00003000  /*  dev and inode */
#define APR_FINFO_OWNER  0x00030000  /*  user and group */
#define APR_FINFO_PROT   0x00700000  /*  all protections */

The first flag, APR_FINFO_LINK, superceeds the apr_lstat call.  If that
flag is set in finfo.valid, the call returned the stat of the link.

On systems that don't support them, dev should then be derived from 
a hash of the mount point and inode should be derived from a hash of
the full pathname.  If they come free, great.  Otherwise we may need
to parse, or cycle through the tree.  Don't ask unless you are willing 
to wait; canonical will walk the whole tree anyways and work these out
in a more optimal fashion.

Same goes for user/group/protections.  Some unices don't support
group concepts at all, and both prot and owner fields get very 
expensive on win32.  Again, if it doesn't matter, don't ask.

The rest should be blatently obvious, except the APR_FINFO_xCASE

The ICASE/FCASE flags should help somewhat to get the proper case
in an optimal fashion.  The fileinfo structure grows char *filespec,
which caches the name that was passed (for free).  If APR_FINFO_FCASE 
is specified, the char *filename member contains the file's name (no 
path).  If the case matched, this is optimized to be the offset into 
filespec.  Just what it does depends on the flags;

user requests neither [they don't care]
  *filename is null

user requests APR_FINFO_ICASE [just asking about the device]
  test dev for case sensitivity, set .valid |= APR_FINFO_ICASE if so
  *filename is null

user requests APR_FINFO_FCASE [doesn't know the case]
  test dev for case sensitivity, set .valid |= APR_FINFO_ICASE if so
  *filename is set to its true case plus .valid |= APR_FINFO_FCASE

user requests APR_FINFO_FCASE && APR_FINFO_ICASE [user remembers the dev]
  if user sets finfo.dev [known to be case insensitive] and dev = finfo.dev 
    we _skip_ the dev case sensitivity test and set .valid |= APR_FINFO_ICASE
  *filename is set to its true case and .valid |= APR_FINFO_FCASE

So this will help optimize any application that has performance issues
and a strong requirement to know the true file name (such as... apache ;-?)

Combinations will impact performance.  Asking on win32 for dev/inode
and the fcase effectively requires two stats.  Ask for just what you
need.

I'm suggesting we add asize (allocated size, e.g. for filesystems
with preallocation) and csize (the actual size consumed on disk.)
Apache may have no application, but other applications may.  These
may not come for free on all platforms.  size itself is the number
of bytes you get when you read the file byte for byte from front
to the end.  asize is the maximum allocated extent.  And csize may
factor compressions, and offset by blocking.  Expensive calculations
if you have to chase down the dev, unknowable on some platforms.

So let's hear it... this should be committed today to get us out of the
mess we are in with Win32.  I'll offer the 'patch' on the first hurrah.

Re: apr_stat

Posted by Greg Stein <gs...@lyra.org>.
On Fri, Jan 19, 2001 at 12:22:12PM -0600, William A. Rowe, Jr. wrote:
> Thanks, everyone, who's commented so far... here's the plan;
> 
> apr_status_t apr_stat(apr_finfo_t *finfo, const char *fname, 
>                       apr_int32_t wantthis, apr_pool_t *p)
> 
> wantthis is the bit flag of attributes we are interested in.  
> Some will always be returned, and the apr_stat function can
> always return anything _they comes for free_.  

Sounds fine.

> apr_stat will reply in a new member value, finfo_valid, to 
> describe the results returned.  It will only fail for the 
> current reasons.  If it can't get a particular result, it 
> just goes on, and it's the caller's job to check finfo.valid.

If I ask for a value and it can't return it, then I should get an error.
I've explicitly said "give me this."

> #define APR_FINFO_LINK   0x00000001
> #define APR_FINFO_MTIME  0x00000010
> #define APR_FINFO_CTIME  0x00000020
> #define APR_FINFO_ATIME  0x00000040
> #define APR_FINFO_SIZE   0x00000100
> #define APR_FINFO_ASIZE  0x00000200
> #define APR_FINFO_CSIZE  0x00000400
> #define APR_FINFO_DEV    0x00001000
> #define APR_FINFO_INODE  0x00002000
> #define APR_FINFO_TYPE   0x00008000

probably 0x00004000 instead.

> #define APR_FINFO_USER   0x00010000 
> #define APR_FINFO_GROUP  0x00020000 
> #define APR_FINFO_UPROT  0x00100000 
> #define APR_FINFO_GPROT  0x00200000
> #define APR_FINFO_WPROT  0x00400000

I don't think we need to differentiate between user/group/world perms.
Return none or return them all.

>...
> I'm suggesting we add asize (allocated size, e.g. for filesystems
> with preallocation) and csize (the actual size consumed on disk.)

Let's leave these out until we have a real need and can properly support
them. This stuff is all so non-portable to begin with, let's not bite off
more than we truly need.

Cheers,
-g

-- 
Greg Stein, http://www.lyra.org/

Re: apr_stat

Posted by rb...@covalent.net.
On Fri, 19 Jan 2001, William A. Rowe, Jr. wrote:

> From: <rb...@covalent.net>
> Sent: Friday, January 19, 2001 12:46 PM
> 
> 
> > 
> > ++1.  If you get Windows working, I'll do Unix when you are done.
> 
> How about the other way around?
> 
> Here's the proof-of-concept on unix;  I don't promise it's complete,
> and don't promise it compiles, but it underscores the concept.

Looks good.  If you apply the Windows patch today sometime, I'll make sure
this applies, but from a quick inspection, I suspect this will be a simple
patch and build.  No work needed.  :-)

Ryan

_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
406 29th St.
San Francisco, CA 94131
-------------------------------------------------------------------------------


Re: apr_stat

Posted by "William A. Rowe, Jr." <wr...@rowe-clan.net>.
From: <rb...@covalent.net>
Sent: Friday, January 19, 2001 12:46 PM


> 
> ++1.  If you get Windows working, I'll do Unix when you are done.

How about the other way around?

Here's the proof-of-concept on unix;  I don't promise it's complete,
and don't promise it compiles, but it underscores the concept.

Windows is obviously much trickier... I'm working that up now, repleat
with the open a file from an apr_finfo_t (of course, we already get
stats from an open apr_file_t).  Since both apr_finfo_t and apr_file_t
will capture a filename, they are -interchangable-.

One thing I don't like, looking at this, is that we pass 'our own'
apr_finfo_t structure, which means it is just as likely to be passed
on the stack.  That's not healthy for later opening the file from the
apr_finfo_t, yet we have 'resolved' not to actually copy these filenames.
I imagine it really ought to be one or the other, we do or we don't
copy the name, therefore we musn't or must allocate an apr_finfo_t from
the pool.

Bill

Index: include/apr_file_info.h
===================================================================
RCS file: /home/cvs/apr/include/apr_file_info.h,v
retrieving revision 1.1
diff -u -r1.1 apr_file_info.h
--- include/apr_file_info.h 2001/01/19 17:29:44 1.1
+++ include/apr_file_info.h 2001/01/20 01:02:55
@@ -136,14 +136,40 @@
 
 typedef struct apr_finfo_t        apr_finfo_t;
 
+#define APR_FINFO_LINK   0x00000001
+#define APR_FINFO_MTIME  0x00000010
+#define APR_FINFO_CTIME  0x00000020
+#define APR_FINFO_ATIME  0x00000040
+#define APR_FINFO_SIZE   0x00000100
+#define APR_FINFO_ASIZE  0x00000200
+#define APR_FINFO_CSIZE  0x00000400
+#define APR_FINFO_DEV    0x00001000
+#define APR_FINFO_INODE  0x00002000
+#define APR_FINFO_TYPE   0x00008000
+#define APR_FINFO_USER   0x00010000 
+#define APR_FINFO_GROUP  0x00020000 
+#define APR_FINFO_UPROT  0x00100000 
+#define APR_FINFO_GPROT  0x00200000
+#define APR_FINFO_WPROT  0x00400000
+#define APR_FINFO_ICASE  0x01000000  /*  if dev is case insensitive */
+#define APR_FINFO_FCASE  0x02000000  /*  filename in proper case */
+
+#define APR_FINFO_MIN    0x00008170  /*  minimal: type, dates and size */
+#define APR_FINFO_IDENT  0x00003000  /*  dev and inode */
+#define APR_FINFO_OWNER  0x00030000  /*  user and group */
+#define APR_FINFO_PROT   0x00700000  /*  all protections */
+
 /**
  * The file information structure.  This is analogous to the POSIX
  * stat structure.
  */
 struct apr_finfo_t {
-    /** The access permissions of the file.  Currently this mimics Unix
-     *  access rights.
-     */
+    /** Allocates memory and closes lingering handles in the specified pool */
+    apr_pool_t *cntxt;
+    /** The bitmask describing valid fields of this apr_finfo_t structure 
+     *  including all available 'wanted' fields and potentially more */
+    apr_int32_t valid;
+    /** The access permissions of the file.  Mimics Unix access rights. */
     apr_fileperms_t protection;
     /** The type of file.  One of APR_NOFILE, APR_REG, APR_DIR, APR_CHR, 
      *  APR_BLK, APR_PIPE, APR_LNK, APR_SOCK 
@@ -153,18 +179,28 @@
     apr_uid_t user;
     /** The group id that owns the file */
     apr_gid_t group;
-    /** The inode of the file.  (Not portable?) */
+    /** The inode of the file. */
     apr_ino_t inode;
-    /** The id of the device the file is on.  (Not portable?) */
+    /** The id of the device the file is on. */
     apr_dev_t device;
     /** The size of the file */
     apr_off_t size;
+    /** The space allocated for the file */
+    apr_off_t csize;
+    /** The storage size consumed by the file */
+    apr_off_t csize;
     /** The time the file was last accessed */
     apr_time_t atime;
     /** The time the file was last modified */
     apr_time_t mtime;
     /** The time the file was last changed */
     apr_time_t ctime;
+    /** The full pathname of the file */
+    char *filespec;
+    /** The file's name alone, in filesystem case */
+    char *filename;
+    /** The file's handle, if accessed (can be submitted to apr_duphandle) */
+    apr_file_t *filehand;
 };
 
 /**
@@ -173,11 +209,12 @@
  * @param finfo Where to store the information about the file, which is
  * never touched if the call fails.
  * @param fname The name of the file to stat.
+ * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values 
  * @param cont the pool to use to allocate the new file. 
- * @deffunc apr_status_t apr_stat(apr_finfo_t *finfo, const char *fname, apr_pool_t *cont)
+ * @deffunc apr_status_t apr_stat(apr_finfo_t *finfo, const char *fname, apr_int32_t wanted, apr_pool_t *cont)
  */ 
 APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname,
-                                   apr_pool_t *cont);
+                                   apr_int32_t wanted, apr_pool_t *cont);
 
 /**
  * get the specified file's stats.  The file is specified by filename, 
@@ -186,11 +223,14 @@
  * @param finfo Where to store the information about the file, which is
  * never touched if the call fails.
  * @param fname The name of the file to stat.
+ * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values 
  * @param cont the pool to use to allocate the new file. 
- * @deffunc apr_status_t apr_lstat(apr_finfo_t *finfo, const char *fname, apr_pool_t *cont)
+ * @deffunc apr_status_t apr_lstat(apr_finfo_t *finfo, const char *fname, apr_int32_t wanted, apr_pool_t *cont)
+ * @tip This function is depreciated, it's equivilant to calling apr_stat with 
+ * the wanted flag value APR_FINFO_LINK
  */ 
 APR_DECLARE(apr_status_t) apr_lstat(apr_finfo_t *finfo, const char *fname,
-                                    apr_pool_t *cont);
+                                    apr_int32_t wanted, apr_pool_t *cont);
 
 /**
  * Open the specified directory.
Index: include/apr_file_io.h
===================================================================
RCS file: /home/cvs/apr/include/apr_file_io.h,v
retrieving revision 1.87
diff -u -r1.87 apr_file_io.h
--- include/apr_file_io.h 2001/01/19 17:29:44 1.87
+++ include/apr_file_io.h 2001/01/20 01:02:55
@@ -521,10 +521,12 @@
 /**
  * get the specified file's stats.
  * @param finfo Where to store the information about the file.
+ * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values 
  * @param thefile The file to get information about.
- * @deffunc apr_status_t apr_getfileinfo(apr_finfo_t *finfo, apr_file_t *thefile)
+ * @deffunc apr_status_t apr_getfileinfo(apr_finfo_t *finfo, apr_int32_t wanted, apr_file_t *thefile)
  */ 
-APR_DECLARE(apr_status_t) apr_getfileinfo(apr_finfo_t *finfo,
+APR_DECLARE(apr_status_t) apr_getfileinfo(apr_finfo_t *finfo, 
+                                          apr_int32_t wanted,
                                           apr_file_t *thefile);
 
 #ifdef __cplusplus
Index: file_io/unix/filestat.c
===================================================================
RCS file: /home/cvs/apr/file_io/unix/filestat.c,v
retrieving revision 1.33
diff -u -r1.33 filestat.c
--- file_io/unix/filestat.c 2000/11/14 06:40:03 1.33
+++ file_io/unix/filestat.c 2001/01/20 01:02:55
@@ -55,6 +55,7 @@
 #include "fileio.h"
 #include "apr_file_io.h"
 #include "apr_general.h"
+#include "apr_strings.h"
 #include "apr_errno.h"
 
 static apr_filetype_e filetype_from_mode(int mode)
@@ -80,11 +81,14 @@
     return type;
 }
 
-apr_status_t apr_getfileinfo(apr_finfo_t *finfo, apr_file_t *thefile)
+apr_status_t apr_getfileinfo(apr_finfo_t *finfo, apr_int32_t wanted,
+                             apr_file_t *thefile)
 {
     struct stat info;
 
     if (fstat(thefile->filedes, &info) == 0) {
+        finfo->cntxt = thefile->cntxt;
+        finfo->valid = APR_FINFO_MIN| APR_FINFO_IDENT | APR_FINFO_OWNER | APR_FINFO_PROT;
         finfo->protection = apr_unix_mode2perms(info.st_mode);
         finfo->filetype = filetype_from_mode(info.st_mode);
         finfo->user = info.st_uid;
@@ -92,9 +96,18 @@
         finfo->size = info.st_size;
         finfo->inode = info.st_ino;
         finfo->device = info.st_dev;
+        finfo->nlinks = info.st_nlink;
         apr_ansi_time_to_apr_time(&finfo->atime, info.st_atime);
         apr_ansi_time_to_apr_time(&finfo->mtime, info.st_mtime);
         apr_ansi_time_to_apr_time(&finfo->ctime, info.st_ctime);
+        finfo->filepath = thefile->fname;
+        if (wanted & APR_FINFO_CSIZE) {
+            finfo->csize = info.st_blocks * 512;
+            finfo->valid |= APR_FINFO_CSIZE;
+        }
+        if (finfo->filetype = APR_LNK)
+            finfo->valid |= APR_FINFO_LINK
+        }
         return APR_SUCCESS;
     }
     else {
@@ -111,11 +124,20 @@
     return APR_SUCCESS;
 }
 
-apr_status_t apr_stat(apr_finfo_t *finfo, const char *fname, apr_pool_t *cont)
+apr_status_t apr_stat(apr_finfo_t *finfo, const char *fname,
+                      apr_int32_t wanted, apr_pool_t *cont)
 {
     struct stat info;
+    int srv;
 
-    if (stat(fname, &info) == 0) {
+    if (wanted & APR_FINFO_LINK)
+        srv = lstat(fname, &info);
+    else
+        srv = stat(fname,info);
+
+    if (srv == 0) {
+        finfo->cntxt = cont;
+        finfo->valid = APR_FINFO_MIN| APR_FINFO_IDENT | APR_FINFO_OWNER | APR_FINFO_PROT;
         finfo->protection = apr_unix_mode2perms(info.st_mode);
         finfo->filetype = filetype_from_mode(info.st_mode);
         finfo->user = info.st_uid;
@@ -123,9 +145,18 @@
         finfo->size = info.st_size;
         finfo->inode = info.st_ino;
         finfo->device = info.st_dev;
+        finfo->nlinks = info.st_nlink;
         apr_ansi_time_to_apr_time(&finfo->atime, info.st_atime);
         apr_ansi_time_to_apr_time(&finfo->mtime, info.st_mtime);
         apr_ansi_time_to_apr_time(&finfo->ctime, info.st_ctime);
+        finfo->filepath = fname;
+        if (wanted & APR_FINFO_CSIZE) {
+            finfo->csize = info.st_blocks * 512;
+            finfo->valid |= APR_FINFO_CSIZE;
+        }
+        if (finfo->filetype = APR_LNK)
+            finfo->valid |= APR_FINFO_LINK
+        }
         return APR_SUCCESS;
     }
     else {
@@ -163,24 +194,12 @@
     }
 }
 
-apr_status_t apr_lstat(apr_finfo_t *finfo, const char *fname, apr_pool_t *cont)
+/* Perhaps this becomes nothing but a macro?
+ */
+apr_status_t apr_lstat(apr_finfo_t *finfo, const char *fname,
+                      apr_int32_t wanted, apr_pool_t *cont)
 {
-    struct stat info;
+    return apr_stat(finfo, fname, wanted | APR_FINFO_LINK, cont);
+}
 
-    if (lstat(fname, &info) == 0) {
-        finfo->protection = apr_unix_mode2perms(info.st_mode);
-        finfo->filetype = filetype_from_mode(info.st_mode);
-        finfo->user = info.st_uid;
-        finfo->group = info.st_gid;
-        finfo->size = info.st_size;
-        finfo->inode = info.st_ino;
-        finfo->device = info.st_dev;
-        apr_ansi_time_to_apr_time(&finfo->atime, info.st_atime);
-        apr_ansi_time_to_apr_time(&finfo->mtime, info.st_mtime);
-        apr_ansi_time_to_apr_time(&finfo->ctime, info.st_ctime);
-        return APR_SUCCESS;
-    }
-    else {
-        return errno;
-    }
 }



Re: apr_stat

Posted by rb...@covalent.net.
BTW, could you commit your e-mail message to CVS in the docs
directory.  This is relatively complex, and we will most likely want a
detailed description at some point.

Ryan

On Fri, 19 Jan 2001 rbb@covalent.net wrote:

> 
> ++1.  If you get Windows working, I'll do Unix when you are done.
> 
> > Thanks, everyone, who's commented so far... here's the plan;
> > 
> > apr_status_t apr_stat(apr_finfo_t *finfo, const char *fname, 
> >                       apr_int32_t wantthis, apr_pool_t *p)
> 
> Ryan
> 
> _______________________________________________________________________________
> Ryan Bloom                        	rbb@apache.org
> 406 29th St.
> San Francisco, CA 94131
> -------------------------------------------------------------------------------
> 
> 


_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
406 29th St.
San Francisco, CA 94131
-------------------------------------------------------------------------------


Re: apr_stat

Posted by rb...@covalent.net.
++1.  If you get Windows working, I'll do Unix when you are done.

> Thanks, everyone, who's commented so far... here's the plan;
> 
> apr_status_t apr_stat(apr_finfo_t *finfo, const char *fname, 
>                       apr_int32_t wantthis, apr_pool_t *p)

Ryan

_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
406 29th St.
San Francisco, CA 94131
-------------------------------------------------------------------------------