Greg Stein <[EMAIL PROTECTED]> writes: > (btw, for completeness, we'd also want ways to turn off readonly and to the > executable state)
Here's a patch that does that, and provides a way to query the attributes. It also makes the permission setting by apr_file_attrs_set respect the umask of the process. So when removing readonly, the world write flag, for example, only gets set if the umask allows. Index: file_io/unix/filestat.c =================================================================== RCS file: /home/cvspublic/apr/file_io/unix/filestat.c,v retrieving revision 1.49 diff -u -r1.49 filestat.c --- file_io/unix/filestat.c 1 Feb 2002 01:40:38 -0000 1.49 +++ file_io/unix/filestat.c 2 Feb 2002 20:32:36 -0000 @@ -109,6 +109,42 @@ */ } +/* This function is necessary because the APR mutex interface doesn't + * provide static mutex initialisation, i.e. there is nothing equivalent + * to PTHREAD_MUTEX_INITIALIZER. It's difficult to see how it could, given + * the need for a pool. + */ +static apr_thread_mutex_t *umask_mutex; +apr_status_t apr_unix_setup_umask(apr_pool_t *cont) +{ + return apr_thread_mutex_create(&umask_mutex, APR_THREAD_MUTEX_DEFAULT, cont); +} + +static apr_status_t get_umask(apr_fileperms_t *umask_perms, apr_pool_t *cont) +{ + apr_status_t status; + mode_t umask_raw; + +#ifdef APR_HAS_THREADS + status = apr_thread_mutex_lock(umask_mutex); + if (!APR_STATUS_IS_SUCCESS(status)) + return status; +#endif + + umask_raw = umask(0); + umask(umask_raw); + +#ifdef APR_HAS_THREADS + status = apr_thread_mutex_unlock(umask_mutex); + if (!APR_STATUS_IS_SUCCESS(status)) + return status; +#endif + + *umask_perms = apr_unix_mode2perms(umask_raw); + + return APR_SUCCESS; +} + APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, apr_int32_t wanted, apr_file_t *thefile) @@ -142,26 +178,84 @@ { apr_status_t status; apr_finfo_t finfo; + apr_fileperms_t mask; + apr_fileperms_t attr_perms; status = apr_stat(&finfo, fname, APR_FINFO_PROT, cont); if (!APR_STATUS_IS_SUCCESS(status)) return status; if (attributes & APR_FILE_ATTR_READONLY) { + /* Make readonly by removing all write bits */ finfo.protection &= ~APR_UWRITE; finfo.protection &= ~APR_GWRITE; finfo.protection &= ~APR_WWRITE; } + else { + /* Make non-readonly by setting all write bits permitted by umask */ + attr_perms = APR_UWRITE | APR_GWRITE | APR_WWRITE; + status = get_umask(&mask, cont); + if (!APR_STATUS_IS_SUCCESS(status)) + return status; + attr_perms &= ~mask; + finfo.protection |= attr_perms; + } + if (attributes & APR_FILE_ATTR_EXECUTABLE) { - /* ### TODO: should this be umask'd? */ - finfo.protection |= APR_UEXECUTE; - finfo.protection |= APR_GEXECUTE; - finfo.protection |= APR_WEXECUTE; + /* Make executable by setting all execute bits permitted by umask */ + attr_perms = APR_UEXECUTE | APR_GEXECUTE | APR_WEXECUTE; + status = get_umask(&mask, cont); + if (!APR_STATUS_IS_SUCCESS(status)) + return status; + attr_perms &= ~mask; + finfo.protection |= attr_perms; + } + else { + /* Make non-executable by removing all execute bits */ + finfo.protection &= ~APR_UEXECUTE; + finfo.protection &= ~APR_GEXECUTE; + finfo.protection &= ~APR_WEXECUTE; } return apr_file_perms_set(fname, finfo.protection); } +APR_DECLARE(apr_status_t) apr_file_attrs_get(const char *fname, + apr_fileattrs_t *attributes, + apr_pool_t *cont) +{ + apr_status_t status; + apr_finfo_t finfo; + apr_fileperms_t perm_mask; + mode_t mask; + + status = apr_stat(&finfo, fname, APR_FINFO_PROT, cont); + if (!APR_STATUS_IS_SUCCESS(status)) + return status; + + *attributes = 0; + + /* All the write bits */ + perm_mask = APR_UWRITE | APR_GWRITE | APR_WWRITE; + + /* Claim readonly only if no write bits are set */ + if (!(finfo.protection & perm_mask)) + *attributes |= APR_FILE_ATTR_READONLY; + + /* All the execute bits allowed by umask */ + perm_mask = APR_UEXECUTE | APR_GEXECUTE | APR_WEXECUTE; + status = get_umask(&mask, cont); + if (!APR_STATUS_IS_SUCCESS(status)) + return status; + perm_mask &= ~mask; + + /* Claim executable only if all execute bits are set */ + if ((finfo.protection & perm_mask) == perm_mask) + *attributes |= APR_FILE_ATTR_EXECUTABLE; + + return APR_SUCCESS; +} + APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname, apr_int32_t wanted, apr_pool_t *cont) Index: file_io/win32/filestat.c =================================================================== RCS file: /home/cvspublic/apr/file_io/win32/filestat.c,v retrieving revision 1.62 diff -u -r1.62 filestat.c --- file_io/win32/filestat.c 1 Feb 2002 01:40:38 -0000 1.62 +++ file_io/win32/filestat.c 2 Feb 2002 20:32:36 -0000 @@ -618,3 +618,10 @@ { return APR_ENOTIMPL; } + +APR_DECLARE(apr_status_t) apr_file_attrs_get(const char *fname, + apr_fileattrs_t *attributes, + apr_pool_t *cont) +{ + return APR_ENOTIMPL; +} Index: include/apr_file_io.h =================================================================== RCS file: /home/cvspublic/apr/include/apr_file_io.h,v retrieving revision 1.117 diff -u -r1.117 apr_file_io.h --- include/apr_file_io.h 1 Feb 2002 01:40:38 -0000 1.117 +++ include/apr_file_io.h 2 Feb 2002 20:32:37 -0000 @@ -578,7 +578,7 @@ /** * Set attributes of the specified file. * @param fname The full path to the file (using / on all systems) - * @param attributes Or'd combination of + * @param attributes Or'd combination of attribute flags * <PRE> * APR_FILE_ATTR_READONLY - make the file readonly * APR_FILE_ATTR_EXECUTABLE - make the file executable @@ -588,11 +588,29 @@ * of the file permissions, because the operations to provide these * attributes are platform specific and may involve more than simply * setting permission bits. + * @remark If any of the attribute flags are not set in the parameter passed + * to this function, then those attributes will be removed from the file. * @warning Platforms which do not implement this feature will return * APR_ENOTIMPL. */ APR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname, apr_fileattrs_t attributes, + apr_pool_t *cont); + +/** + * Get attributes of the specified file. + * @param fname The full path to the file (using / on all systems) + * @param attributes Pointer to variable in which to store the file's attributes + * @param cont the pool to use. + * @remark This function should be used in preference to explict examination + * of the file permissions, because the operations to provide these + * attributes are platform specific and may involve more than simply + * setting permission bits. + * @warning Platforms which do not implement this feature will return + * APR_ENOTIMPL. + */ +APR_DECLARE(apr_status_t) apr_file_attrs_get(const char *fname, + apr_fileattrs_t *attributes, apr_pool_t *cont); /** Index: include/arch/unix/fileio.h =================================================================== RCS file: /home/cvspublic/apr/include/arch/unix/fileio.h,v retrieving revision 1.37 diff -u -r1.37 fileio.h --- include/arch/unix/fileio.h 21 Nov 2001 04:21:04 -0000 1.37 +++ include/arch/unix/fileio.h 2 Feb 2002 20:32:37 -0000 @@ -154,5 +154,7 @@ mode_t apr_unix_perms2mode(apr_fileperms_t perms); apr_fileperms_t apr_unix_mode2perms(mode_t mode); +apr_status_t apr_unix_setup_umask(apr_pool_t *cont); + #endif /* ! FILE_IO_H */ Index: misc/unix/start.c =================================================================== RCS file: /home/cvspublic/apr/misc/unix/start.c,v retrieving revision 1.61 diff -u -r1.61 start.c --- misc/unix/start.c 1 Feb 2002 17:27:38 -0000 1.61 +++ misc/unix/start.c 2 Feb 2002 20:32:37 -0000 @@ -132,6 +132,11 @@ #endif apr_signal_init(pool); +#if !defined(BEOS) && !defined(OS2) && !defined(WIN32) + if ((status = apr_unix_setup_umask(pool)) != APR_SUCCESS) { + return status; + } +#endif return APR_SUCCESS; } -- Philip