def check_stage_dir_perms(prefix, path): """Check the stage directory perms to ensure match expectations.""" # Ensure the path's subdirectories -- to `$user` -- have their parent's # perms while those from `$user` on are owned and restricted to the # user. assert path.startswith(prefix) user = getpass.getuser() prefix_status = os.stat(prefix) uid = os.getuid() # Obtain lists of ancestor and descendant paths of the $user node, if any. # # Skip processing prefix ancestors since no guarantee they will be in the # required group (e.g. $TEMPDIR on HPC machines). skip = prefix if prefix.endswith(os.sep) else prefix + os.sep group_paths, user_node, user_paths = partition_path(path.replace(skip, ""), user) for p in group_paths: p_status = os.stat(os.path.join(prefix, p)) assert p_status.st_gid == prefix_status.st_gid assert p_status.st_mode == prefix_status.st_mode # Add the path ending with the $user node to the user paths to ensure paths # from $user (on down) meet the ownership and permission requirements. if user_node: user_paths.insert(0, user_node) for p in user_paths: p_status = os.stat(os.path.join(prefix, p)) assert uid == p_status.st_uid assert p_status.st_mode & stat.S_IRWXU == stat.S_IRWXU
def _create_stage_root(path): """Create the stage root directory and ensure appropriate access perms.""" assert path.startswith(os.path.sep) and len(path.strip()) > 1 err_msg = 'Cannot create stage root {0}: Access to {1} is denied' user_uid = os.getuid() # Obtain lists of ancestor and descendant paths of the $user node, if any. group_paths, user_node, user_paths = partition_path( path, getpass.getuser()) for p in group_paths: if not os.path.exists(p): # Ensure access controls of subdirs created above `$user` inherit # from the parent and share the group. par_stat = os.stat(os.path.dirname(p)) mkdirp(p, group=par_stat.st_gid, mode=par_stat.st_mode) p_stat = os.stat(p) if par_stat.st_gid != p_stat.st_gid: tty.warn( "Expected {0} to have group {1}, but it is {2}".format( p, par_stat.st_gid, p_stat.st_gid)) if par_stat.st_mode & p_stat.st_mode != par_stat.st_mode: tty.warn( "Expected {0} to support mode {1}, but it is {2}".format( p, par_stat.st_mode, p_stat.st_mode)) if not can_access(p): raise OSError(errno.EACCES, err_msg.format(path, p)) # Add the path ending with the $user node to the user paths to ensure paths # from $user (on down) meet the ownership and permission requirements. if user_node: user_paths.insert(0, user_node) for p in user_paths: # Ensure access controls of subdirs from `$user` on down are # restricted to the user. if not os.path.exists(p): mkdirp(p, mode=stat.S_IRWXU) p_stat = os.stat(p) if p_stat.st_mode & stat.S_IRWXU != stat.S_IRWXU: tty.error( "Expected {0} to support mode {1}, but it is {2}".format( p, stat.S_IRWXU, p_stat.st_mode)) raise OSError(errno.EACCES, err_msg.format(path, p)) else: p_stat = os.stat(p) if user_uid != p_stat.st_uid: tty.warn( "Expected user {0} to own {1}, but it is owned by {2}".format( user_uid, p, p_stat.st_uid))
def create_stage_root(path): # type: (str) -> None """Create the stage root directory and ensure appropriate access perms.""" assert os.path.isabs(path) and len(path.strip()) > 1 err_msg = 'Cannot create stage root {0}: Access to {1} is denied' user_uid = getuid() # Obtain lists of ancestor and descendant paths of the $user node, if any. group_paths, user_node, user_paths = partition_path( path, getpass.getuser()) for p in group_paths: if not os.path.exists(p): # Ensure access controls of subdirs created above `$user` inherit # from the parent and share the group. par_stat = os.stat(os.path.dirname(p)) mkdirp(p, group=par_stat.st_gid, mode=par_stat.st_mode) p_stat = os.stat(p) if par_stat.st_gid != p_stat.st_gid: tty.warn( "Expected {0} to have group {1}, but it is {2}".format( p, par_stat.st_gid, p_stat.st_gid)) if par_stat.st_mode & p_stat.st_mode != par_stat.st_mode: tty.warn( "Expected {0} to support mode {1}, but it is {2}".format( p, par_stat.st_mode, p_stat.st_mode)) if not can_access(p): raise OSError(errno.EACCES, err_msg.format(path, p)) # Add the path ending with the $user node to the user paths to ensure paths # from $user (on down) meet the ownership and permission requirements. if user_node: user_paths.insert(0, user_node) for p in user_paths: # Ensure access controls of subdirs from `$user` on down are # restricted to the user. owner_uid = get_owner_uid(p) if user_uid != owner_uid: tty.warn( "Expected user {0} to own {1}, but it is owned by {2}".format( user_uid, p, owner_uid)) spack_src_subdir = os.path.join(path, _source_path_subdir) # When staging into a user-specified directory with `spack stage -p <PATH>`, we need # to ensure the `spack-src` subdirectory exists, as we can't rely on it being # created automatically by spack. It's not clear why this is the case for `spack # stage -p`, but since `mkdirp()` is idempotent, this should not change the behavior # for any other code paths. if not os.path.isdir(spack_src_subdir): mkdirp(spack_src_subdir, mode=stat.S_IRWXU)
def test_partition_path(path, entry, expected): assert fs.partition_path(path, entry) == expected