apr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From wr...@apache.org
Subject cvs commit: apr/file_io/win32 filestat.c
Date Sun, 28 Jan 2001 05:14:19 GMT
wrowe       01/01/27 21:14:18

  Modified:    file_io/win32 filestat.c
  Log:
    Return to a GetFileAttributesEx() call for WinNT stat() calls.
    Next patch will reintroduce the stat()-by-open() - but only after
    we optimize it to do so when -required- (for inode, dev, or nlink).
    But not tonight.
  
    Adds User and Group results as PSID data.  This is only meaningful
    through the apr/user package, which right now only returns names.
    apr/user still needs (minimally) a compare function.
  
  Revision  Changes    Path
  1.41      +219 -120  apr/file_io/win32/filestat.c
  
  Index: filestat.c
  ===================================================================
  RCS file: /home/cvs/apr/file_io/win32/filestat.c,v
  retrieving revision 1.40
  retrieving revision 1.41
  diff -u -r1.40 -r1.41
  --- filestat.c	2001/01/27 22:25:10	1.40
  +++ filestat.c	2001/01/28 05:14:17	1.41
  @@ -62,12 +62,20 @@
   #include <sys/stat.h>
   #include "atime.h"
   #include "misc.h"
  +#include <aclapi.h>
   
  +static apr_status_t free_localheap(void *heap) {
  +    LocalFree(heap);
  +    return APR_SUCCESS;
  +}
   
   APR_DECLARE(apr_status_t) apr_getfileinfo(apr_finfo_t *finfo, apr_int32_t wanted,
                                             apr_file_t *thefile)
   {
       BY_HANDLE_FILE_INFORMATION FileInformation;
  +    apr_oslevel_e os_level;
  +    PSID user = NULL, grp = NULL;
  +    PACL dacl = NULL;
   
       if (!GetFileInformationByHandle(thefile->filehand, &FileInformation)) {
           return apr_get_os_error();
  @@ -88,20 +96,11 @@
       finfo->size =  (apr_off_t)FileInformation.nFileSizeLow
                   | ((apr_off_t)FileInformation.nFileSizeHigh << 32);
   #else
  -    finfo->size = FileInformation.nFileSizeLow;
  +    finfo->size = (apr_off_t)FileInformation.nFileSizeLow;
  +    if (finfo->size < 0 || FileInformation.nFileSizeHigh)
  +        finfo->size = 0x7fffffff;
   #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;
  -    }
  -    else {
  -        finfo->protection |= S_IREAD | S_IWRITE | S_IEXEC;
  -    }
       
       /* TODO: return user and group could as * SID's, allocated in the pool.
        * [These are variable length objects that will require a 'comparitor'
  @@ -140,6 +139,55 @@
           }
       }
   
  +    if ((wanted & (APR_FINFO_PROT | APR_FINFO_OWNER))
  +            && apr_get_oslevel(thefile->cntxt, &os_level)
  +            && os_level >= APR_WIN_NT) {
  +        SECURITY_INFORMATION sinf = 0;
  +        PSECURITY_DESCRIPTOR pdesc = NULL;
  +        if (wanted & APR_FINFO_USER)
  +            sinf != OWNER_SECURITY_INFORMATION;
  +        if (wanted & APR_FINFO_GROUP)
  +            sinf != GROUP_SECURITY_INFORMATION;
  +        if (wanted & APR_FINFO_PROT)
  +            sinf != SACL_SECURITY_INFORMATION;
  +        if (!GetSecurityInfo(thefile->filehand, SE_FILE_OBJECT, sinf,
  +                             (wanted & APR_FINFO_USER) ? &user : NULL,
  +                             (wanted & APR_FINFO_GROUP) ? &grp : NULL,
  +                             (wanted & APR_FINFO_PROT) ? &dacl : NULL,
  +                             NULL, &pdesc)) {
  +            apr_register_cleanup(thefile->cntxt, pdesc, free_localheap, 
  +                                 apr_null_cleanup);
  +        }
  +    }
  +
  +    if (user) {
  +        finfo->user = user;
  +        finfo->valid |= APR_FINFO_USER;
  +    }
  +
  +    if (grp) {
  +        finfo->group = grp;
  +        finfo->valid |= APR_FINFO_GROUP;
  +    }
  +
  +    if (dacl) {
  +        /* Retrieved the discresionary access list */
  +        
  +    }
  +    else {
  +        /* 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;
  +        }
  +        else {
  +            finfo->protection |= S_IREAD | S_IWRITE | S_IEXEC;
  +        }
  +    }    
  +    
       if (wanted & ~finfo->valid)
           return APR_INCOMPLETE;
   
  @@ -152,112 +200,181 @@
       return APR_ENOTIMPL;
   }
   
  -APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname,
  -                                   apr_int32_t wanted, apr_pool_t *cont)
  +static int stat_with_handle(apr_finfo_t *finfo, const char *fname,
  +                            apr_int32_t wanted, apr_pool_t *cont)
   {
  -    apr_oslevel_e os_level;
  -    /*
  -     * We need to catch the case where fname length == MAX_PATH since for
  -     * some strange reason GetFileAttributesEx fails with PATH_NOT_FOUND.
  -     * We would rather indicate length error than 'not found'
  -     * 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) 
  -    {
  -        apr_file_t *thefile = NULL;
  -        apr_status_t 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.
  +    apr_file_t *thefile = NULL;
  +    apr_status_t 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.
  +     */
  +    
  +    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 without asking for that permission...
            */
  -        
           if ((rv = apr_open(&thefile, fname, 
  -                           ((wanted & APR_FINFO_LINK) ? APR_OPENLINK : 0)
  -                         | ((wanted & (APR_FINFO_PROT | APR_FINFO_OWNER))
  -                               ? APR_READCONTROL : 0),
  +                           ((wanted & APR_FINFO_LINK) ? APR_OPENLINK : 0),
                              APR_OS_DEFAULT, cont)) == APR_SUCCESS) {
  -            rv = apr_getfileinfo(finfo, wanted, thefile);
  +            rv = apr_getfileinfo(finfo, wanted & ~(APR_FINFO_PROT 
  +                                                 | APR_FINFO_OWNER),
  +                                 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 without asking for that permission...
  -             */
  -            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 != 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;
  +
  +    return rv;
  +}
  +
  +APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname,
  +                                   apr_int32_t wanted, apr_pool_t *cont)
  +{
  +    /* The WIN32_FILE_ATTRIBUTE_DATA is a subset of this structure
  +     */
  +    WIN32_FIND_DATA FileInformation;
  +    apr_oslevel_e os_level;
  +    PSID user = NULL, grp = NULL;
  +    PACL dacl = NULL;
  +
  +    if (apr_get_oslevel(cont, &os_level))
  +        os_level = APR_WIN_95;
  +    
  +    /* Catch fname length == MAX_PATH since GetFileAttributesEx fails 
  +     * with PATH_NOT_FOUND.  We would rather indicate length error than 
  +     * 'not found'
  +     */        
  +    if (strlen(fname) >= APR_PATH_MAX) {
  +        return APR_ENAMETOOLONG;
  +    }
  +#ifdef APR_HAS_UNICODE_FS
  +    else if (os_level >= APR_WIN_NT) {
  +        apr_wchar_t wfname[APR_PATH_MAX];
  +        apr_status_t rv;
  +        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_PROT | APR_FINFO_OWNER)) {
  +            SECURITY_INFORMATION sinf = 0;
  +            PSECURITY_DESCRIPTOR pdesc = NULL;
  +            if (wanted & APR_FINFO_USER)
  +                sinf != OWNER_SECURITY_INFORMATION;
  +            if (wanted & APR_FINFO_GROUP)
  +                sinf != GROUP_SECURITY_INFORMATION;
  +            if (wanted & APR_FINFO_PROT)
  +                sinf != SACL_SECURITY_INFORMATION;
  +            if (!GetNamedSecurityInfoW(wfname, SE_FILE_OBJECT, sinf,
  +                                     (wanted & APR_FINFO_USER) ? &user : NULL,
  +                                     (wanted & APR_FINFO_GROUP) ? &grp : NULL,
  +                                     (wanted & APR_FINFO_PROT) ? &dacl : NULL,
  +                                     NULL, &pdesc)) {
  +                apr_register_cleanup(cont, pdesc, free_localheap, 
  +                                     apr_null_cleanup);
               }
           }
  -        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;
       }
  -    else
  -    {
  -        WIN32_FIND_DATA FileInformation;
  -        /*
  -         * Big enough for the Win95 FindFile, but actually the same
  -         * initial fields as the GetFileAttributesEx return structure
  -         * used for Win98
  -         */
  -        if (strlen(fname) >= MAX_PATH) {
  -            return APR_ENAMETOOLONG;
  -        }
  -        else if (os_level >= APR_WIN_98) {
  -            if (!GetFileAttributesEx(fname, GetFileExInfoStandard, 
  -                                     &FileInformation)) {
  -                return apr_get_os_error();
  -            }
  +#endif
  +    else if (os_level >= APR_WIN_98) {
  +        if (!GetFileAttributesExA(fname, GetFileExInfoStandard, 
  +                                 &FileInformation)) {
  +            return apr_get_os_error();
           }
  -        else  {
  -            /* What a waste of cpu cycles... but we don't have a choice
  -             */
  -            HANDLE hFind;
  -            if (strchr(fname, '*') || strchr(fname, '?'))
  -                return APR_ENOENT;
  -            hFind = FindFirstFile(fname, &FileInformation);
  -            if (hFind == INVALID_HANDLE_VALUE) {
  -                return apr_get_os_error();
  -    	    } 
  -            else {
  -                FindClose(hFind);
  -            }
  +    }
  +    else  {
  +        /* What a waste of cpu cycles... but we don't have a choice
  +         * Be sure we insulate ourselves against bogus wildcards
  +         */
  +        HANDLE hFind;
  +        if (strchr(fname, '*') || strchr(fname, '?'))
  +            return APR_ENOENT;
  +        hFind = FindFirstFile(fname, &FileInformation);
  +        if (hFind == INVALID_HANDLE_VALUE) {
  +            return apr_get_os_error();
  +    	} 
  +        else {
  +            FindClose(hFind);
           }
  +    }
  +
  +    memset(finfo, '\0', sizeof(*finfo));
  +    finfo->cntxt = cont;
  +    finfo->valid = APR_FINFO_ATIME | APR_FINFO_CTIME | APR_FINFO_MTIME
  +                 | APR_FINFO_SIZE  | APR_FINFO_TYPE;
  +
  +    /* 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
   
  -        memset(finfo, '\0', sizeof(*finfo));
  -        /* Filetype - Directory or file?
  +    /* 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.
            */
  -        if (FileInformation.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  -            finfo->protection = S_IFDIR;
  -            finfo->filetype = APR_DIR;
  -        }
  -        else {
  -            finfo->protection = S_IFREG;
  -            finfo->filetype = APR_REG;
  -        }
  -    
  +        finfo->filetype = APR_REG;
  +    }
  +
  +    if (user) {
  +        finfo->user = user;
  +        finfo->valid |= APR_FINFO_USER;
  +    }
  +
  +    if (grp) {
  +        finfo->group = grp;
  +        finfo->valid |= APR_FINFO_GROUP;
  +    }
  +
  +    if (dacl) {
  +        /* Retrieved the discresionary access list */
  +        
  +    }
  +    else {
           /* 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.)
  +         * (not entirely 100% true, but the dacl is -expensive-!)
            */
           if (FileInformation.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
               finfo->protection |= S_IREAD | S_IEXEC;
  @@ -265,29 +382,11 @@
           else {
               finfo->protection |= S_IREAD | S_IWRITE | S_IEXEC;
           }
  +        /* Lying through our teeth */
  +        finfo->valid |= APR_FINFO_UPROT;
   
  -        /* Is this an executable? Guess based on the file extension?
  -         * This is a rather silly test, IMHO... we are looking to test
  -         * if the user 'may' execute a file (permissions), 
  -         * not if the filetype is executable.
  -         * XXX: We need to find a solution, for real.  Or provide some
  -         * new mechanism for control.  Note that the PATHEXT env var,
  -         * in the format .ext[;.ext]... actually lists the 'executable'
  -         * types (invoking without an extension.)  Perhaps a registry
  -         * key test is even appropriate here.
  -         */
  -    
  -        /* File times */
  -        FileTimeToAprTime(&finfo->atime, &FileInformation.ftLastAccessTime);
  -        FileTimeToAprTime(&finfo->ctime, &FileInformation.ftCreationTime);
  -        FileTimeToAprTime(&finfo->mtime, &FileInformation.ftLastWriteTime);
  -
  -        /* Note: This cannot handle files greater than can be held by an int 
  -         */
  -        finfo->size = FileInformation.nFileSizeLow;
  -        if (finfo->size < 0 || FileInformation.nFileSizeHigh)
  -            finfo->size = 0x7fffffff;
       }
  +
       if (wanted & ~finfo->valid)
           return APR_INCOMPLETE;
   
  
  
  

Mime
View raw message