fsal_status_t LUSTREFSAL_unlink(fsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_object_name, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_parent_directory_attributes /* [IN/OUT ] */ ) { fsal_status_t status; int rc, errsv; struct stat buffstat, buffstat_parent; fsal_path_t fsalpath; /* sanity checks. */ if(!p_parent_directory_handle || !p_context || !p_object_name) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_unlink); /* build the FID path */ status = fsal_internal_Handle2FidPath(p_context, p_parent_directory_handle, &fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_unlink); /* get directory metadata */ TakeTokenFSCall(); rc = lstat(fsalpath.path, &buffstat_parent); errsv = errno; ReleaseTokenFSCall(); if(rc) { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_unlink); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_unlink); } /* build the child path */ status = fsal_internal_appendNameToPath(&fsalpath, p_object_name); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_unlink); /* get file metadata */ TakeTokenFSCall(); rc = lstat(fsalpath.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_unlink); /* check access rights */ /* Sticky bit on the directory => the user who wants to delete the file must own it or its parent dir */ if((buffstat_parent.st_mode & S_ISVTX) && buffstat_parent.st_uid != p_context->credential.user && buffstat.st_uid != p_context->credential.user && p_context->credential.user != 0) { Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_unlink); } /* client must be able to lookup the parent directory and modify it */ status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat_parent, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_unlink); /****************************** * DELETE FROM THE FILESYSTEM * ******************************/ TakeTokenFSCall(); /* If the object to delete is a directory, use 'rmdir' to delete the object, else use 'unlink' */ rc = (S_ISDIR(buffstat.st_mode)) ? rmdir(fsalpath.path) : unlink(fsalpath.path); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_unlink); /*********************** * FILL THE ATTRIBUTES * ***********************/ if(p_parent_directory_attributes) { status = LUSTREFSAL_getattrs(p_parent_directory_handle, p_context, p_parent_directory_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_parent_directory_attributes->asked_attributes); FSAL_SET_MASK(p_parent_directory_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_unlink); }
/** * FSAL_readdir : * Read the entries of an opened directory. * * \param dir_descriptor (input): * Pointer to the directory descriptor filled by FSAL_opendir. * \param start_position (input): * Cookie that indicates the first object to be read during * this readdir operation. * This should be : * - FSAL_READDIR_FROM_BEGINNING for reading the content * of the directory from the beginning. * - The end_position parameter returned by the previous * call to FSAL_readdir. * \param get_attr_mask (input) * Specify the set of attributes to be retrieved for directory entries. * \param buffersize (input) * The size (in bytes) of the buffer where * the direntries are to be stored. * \param pdirent (output) * Adresse of the buffer where the direntries are to be stored. * \param end_position (output) * Cookie that indicates the current position in the directory. * \param nb_entries (output) * Pointer to the number of entries read during the call. * \param end_of_dir (output) * Pointer to a boolean that indicates if the end of dir * has been reached during the call. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t LUSTREFSAL_readdir(fsal_dir_t *dir_desc, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_cookie_t start_pos, /* IN */ fsal_attrib_mask_t get_attr_mask, /* IN */ fsal_mdsize_t buffersize, /* IN */ fsal_dirent_t * p_pdirent, /* OUT */ fsal_cookie_t * p_end_position, /* OUT */ fsal_count_t * p_nb_entries, /* OUT */ fsal_boolean_t * p_end_of_dir /* OUT */ ) { fsal_status_t st; fsal_count_t max_dir_entries; struct dirent *dp; struct dirent dpe; fsal_path_t fsalpath; int rc; lustrefsal_dir_t * p_dir_descriptor = (lustrefsal_dir_t *)dir_desc; lustrefsal_cookie_t start_position; /*****************/ /* sanity checks */ /*****************/ if(!p_dir_descriptor || !p_pdirent || !p_end_position || !p_nb_entries || !p_end_of_dir) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir); max_dir_entries = (buffersize / sizeof(fsal_dirent_t)); memcpy( (char *)& start_position.data.cookie, (char *)&start_pos.data, sizeof( off_t ) ) ; /***************************/ /* seek into the directory */ /***************************/ errno = 0; if(start_position.data.cookie == 0) { rewinddir(p_dir_descriptor->p_dir); rc = errno; } else { seekdir(p_dir_descriptor->p_dir, start_position.data.cookie); rc = errno; } if(rc) Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir); /************************/ /* browse the directory */ /************************/ *p_nb_entries = 0; while(*p_nb_entries < max_dir_entries) { /***********************/ /* read the next entry */ /***********************/ TakeTokenFSCall(); rc = readdir_r(p_dir_descriptor->p_dir, &dpe, &dp); ReleaseTokenFSCall(); if(rc) { rc = errno; Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir); } /* End of directory */ if(!dp) { *p_end_of_dir = 1; break; } /***********************************/ /* Get information about the entry */ /***********************************/ /* skip . and .. */ if(!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; /* build the full path of the file into "fsalpath */ if(FSAL_IS_ERROR (st = FSAL_str2name(dp->d_name, FSAL_MAX_NAME_LEN, &(p_pdirent[*p_nb_entries].name)))) ReturnStatus(st, INDEX_FSAL_readdir); memcpy(&fsalpath, &(p_dir_descriptor->path), sizeof(fsal_path_t)); st = fsal_internal_appendNameToPath(&fsalpath, &(p_pdirent[*p_nb_entries].name)); if(FSAL_IS_ERROR(st)) ReturnStatus(st, INDEX_FSAL_readdir); /* get object handle */ TakeTokenFSCall(); st = fsal_internal_Path2Handle((fsal_op_context_t *) &p_dir_descriptor->context, &fsalpath, &(p_pdirent[*p_nb_entries].handle)); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(st)) ReturnStatus(st, INDEX_FSAL_readdir); /************************ * Fills the attributes * ************************/ p_pdirent[*p_nb_entries].attributes.asked_attributes = get_attr_mask; st = LUSTREFSAL_getattrs(&(p_pdirent[*p_nb_entries].handle), (fsal_op_context_t *) &p_dir_descriptor->context, &p_pdirent[*p_nb_entries].attributes); if(FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes); FSAL_SET_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); } ((lustrefsal_cookie_t *) (&p_pdirent[*p_nb_entries].cookie))->data.cookie = telldir(p_dir_descriptor->p_dir); p_pdirent[*p_nb_entries].nextentry = NULL; if(*p_nb_entries) p_pdirent[*p_nb_entries - 1].nextentry = &(p_pdirent[*p_nb_entries]); memcpy((char *)p_end_position, (char *)&p_pdirent[*p_nb_entries].cookie, sizeof(lustrefsal_cookie_t)); (*p_nb_entries)++; } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir); }
fsal_status_t LUSTREFSAL_rename(lustrefsal_handle_t * p_old_parentdir_handle, /* IN */ fsal_name_t * p_old_name, /* IN */ lustrefsal_handle_t * p_new_parentdir_handle, /* IN */ fsal_name_t * p_new_name, /* IN */ lustrefsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_src_dir_attributes, /* [ IN/OUT ] */ fsal_attrib_list_t * p_tgt_dir_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; struct stat old_parent_buffstat, new_parent_buffstat, buffstat; fsal_path_t old_fsalpath, new_fsalpath; int src_equal_tgt = FALSE; /* sanity checks. * note : src/tgt_dir_attributes are optional. */ if(!p_old_parentdir_handle || !p_new_parentdir_handle || !p_old_name || !p_new_name || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); /* Get directory access path by fid */ status = fsal_internal_Handle2FidPath(p_context, p_old_parentdir_handle, &old_fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); /* retrieve directory metadata for checking access rights */ TakeTokenFSCall(); rc = lstat(old_fsalpath.path, &old_parent_buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_rename); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); } /* optimisation : don't do the job twice if source dir = dest dir */ if(!LUSTREFSAL_handlecmp(p_old_parentdir_handle, p_new_parentdir_handle, &status)) { FSAL_pathcpy(&new_fsalpath, &old_fsalpath); src_equal_tgt = TRUE; new_parent_buffstat = old_parent_buffstat; } else { status = fsal_internal_Handle2FidPath(p_context, p_new_parentdir_handle, &new_fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); /* retrieve destination attrs */ TakeTokenFSCall(); rc = lstat(new_fsalpath.path, &new_parent_buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_rename); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); } } /* check access rights */ status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &old_parent_buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); if(!src_equal_tgt) { status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &new_parent_buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); } /* build file paths */ status = fsal_internal_appendNameToPath(&old_fsalpath, p_old_name); if(FSAL_IS_ERROR(status)) Return(status.major, status.minor, INDEX_FSAL_rename); status = fsal_internal_appendNameToPath(&new_fsalpath, p_new_name); if(FSAL_IS_ERROR(status)) Return(status.major, status.minor, INDEX_FSAL_rename); TakeTokenFSCall(); rc = lstat(old_fsalpath.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); /* Check sticky bits */ /* Sticky bit on the source directory => the user who wants to delete the file must own it or its parent dir */ if((old_parent_buffstat.st_mode & S_ISVTX) && old_parent_buffstat.st_uid != p_context->credential.user && buffstat.st_uid != p_context->credential.user && p_context->credential.user != 0) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename); /* Sticky bit on the target directory => the user who wants to create the file must own it or its parent dir */ if(new_parent_buffstat.st_mode & S_ISVTX) { TakeTokenFSCall(); rc = lstat(new_fsalpath.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { if(errsv != ENOENT) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); } else if(new_parent_buffstat.st_uid != p_context->credential.user && buffstat.st_uid != p_context->credential.user && p_context->credential.user != 0) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename); } /************************************* * Rename the file on the filesystem * *************************************/ TakeTokenFSCall(); rc = rename(old_fsalpath.path, new_fsalpath.path); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); /*********************** * Fill the attributes * ***********************/ if(p_src_dir_attributes) { status = LUSTREFSAL_getattrs(p_old_parentdir_handle, p_context, p_src_dir_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_src_dir_attributes->asked_attributes); FSAL_SET_MASK(p_src_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } if(p_tgt_dir_attributes) { status = LUSTREFSAL_getattrs(p_new_parentdir_handle, p_context, p_tgt_dir_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_tgt_dir_attributes->asked_attributes); FSAL_SET_MASK(p_tgt_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename); }
/* * Read the entries of an opened directory. * * \param dir_descriptor (input): * Pointer to the directory descriptor filled by FSAL_opendir. * \param start_position (input): * Cookie that indicates the first object to be read during * this readdir operation. * This should be : * - FSAL_READDIR_FROM_BEGINNING for reading the content * of the directory from the beginning. * - The end_position parameter returned by the previous * call to FSAL_readdir. * \param get_attr_mask (input) * Specify the set of attributes to be retrieved for directory entries. * \param buffersize (input) * The size (in bytes) of the buffer where * the direntries are to be stored. * \param pdirent (output) * Adresse of the buffer where the direntries are to be stored. * \param end_position (output) * Cookie that indicates the current position in the directory. * \param nb_entries (output) * Pointer to the number of entries read during the call. * \param end_of_dir (output) * Pointer to a boolean that indicates if the end of dir * has been reached during the call. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - ERR_FSAL_FAULT (a NULL pointer was passed as mandatory argument) * - Other error codes can be returned : * ERR_FSAL_IO, ... */ fsal_status_t dpmfsal_readdir(dpmfsal_dir_t * dir_descriptor, // IN dpmfsal_cookie_t start_position, // IN fsal_attrib_mask_t get_attr_mask, // IN fsal_mdsize_t buffersize, // IN fsal_dirent_t * pdirent, // OUT dpmfsal_cookie_t * end_position, // OUT fsal_count_t * nb_entries, // OUT fsal_boolean_t * end_of_dir // OUT ) { int rc; struct dpns_direnstat * denstat; fsal_status_t st; unsigned long max_entries; // Sanity checks if (!dir_descriptor || !pdirent || !end_position || !nb_entries || !end_of_dir) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir); // How many entries should we read? max_entries = (buffersize / sizeof(fsal_dirent_t)); LogInfo(COMPONENT_FSAL, "dpmfsal_readdir: start :: %s :: up to %d entries", dir_descriptor->path.path, start_position, max_entries); // We might want to rewind serrno = 0; if (start_position.data.cookie == 0) { LogDebug(COMPONENT_FSAL, "dpmfsal_readdir: cookie == 0 :: rewind"); dpns_rewinddir(dir_descriptor->p_dir); } else { // Or simply move forward in the directory LogDebug(COMPONENT_FSAL, "dpmfsal_opendir: cookie == %d :: seek"); // dpns_seekdir(dir_descriptor->p_dir, start_position.cookie); (does not exist) } if (serrno) Return(dpns2fsal_error(serrno), serrno, INDEX_FSAL_readdir); // Read the directory entries TakeTokenFSCall(); *nb_entries = 0; while (*nb_entries < max_entries) { fsal_handle_t entry_handle; fsal_path_t entry_path; // Fetch the entry denstat = dpns_readdirx(dir_descriptor->p_dir); // Are we done? if (denstat == NULL) { LogDebug(COMPONENT_FSAL, "dpmfsal_readdir: (end of dir) after %d entries", *nb_entries); *end_of_dir = 1; break; } // Get the fsal_path_t struct corresponding to the entry name st = FSAL_str2name(denstat->d_name, FSAL_MAX_NAME_LEN, &(pdirent[*nb_entries].name)); if (FSAL_IS_ERROR(st)) ReturnStatus(st, INDEX_FSAL_readdir); strcpy(entry_path.path, dir_descriptor->path.path); fsal_internal_appendNameToPath(&entry_path, &(pdirent[*nb_entries].name)); // Set the direntry object handle dpnsDirEntry2fsal_handle(denstat, &entry_path, dir_descriptor, &(pdirent[*nb_entries].handle)); // Fill in the entry attributes pdirent[*nb_entries].attributes.asked_attributes = get_attr_mask; st = dpns2fsal_attributes(denstat, &pdirent[*nb_entries].attributes); if (FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(pdirent[*nb_entries].attributes.asked_attributes); FSAL_SET_MASK(pdirent[*nb_entries].attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); } pdirent[*nb_entries].cookie.data.cookie = start_position.data.cookie + *nb_entries; pdirent[*nb_entries].nextentry = NULL; if (*nb_entries) pdirent[*nb_entries - 1].nextentry = &(pdirent[*nb_entries]); (*end_position) = pdirent[*nb_entries].cookie; LogDebug(COMPONENT_FSAL, "dpmfsal_readdir: entry %d :: %d", *nb_entries, pdirent[*nb_entries].handle.data.id); (*nb_entries)++; } ReleaseTokenFSCall(); LogDebug(COMPONENT_FSAL, "dpmfsal_readdir: read %d entries :: end position is %d", *nb_entries, end_position->data.cookie); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir); }
/** * FSAL_symlink: * Create a symbolic link. * * \param parent_directory_handle (input): * Handle of the parent directory where the link is to be created. * \param p_linkname (input): * Name of the link to be created. * \param p_linkcontent (input): * Content of the link to be created. * \param cred (input): * Authentication context for the operation (user,...). * \param accessmode (ignored input): * Mode of the link to be created. * It has no sense in HPSS nor UNIX filesystems. * \param link_handle (output): * Pointer to the handle of the created symlink. * \param link_attributes (optionnal input/output): * Attributes of the newly created symlink. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t LUSTREFSAL_symlink(fsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_linkname, /* IN */ fsal_path_t * p_linkcontent, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN (ignored) */ fsal_handle_t * p_link_handle, /* OUT */ fsal_attrib_list_t * p_link_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; fsal_path_t fsalpath; struct stat buffstat; int setgid_bit = FALSE; /* sanity checks. * note : link_attributes is optional. */ if(!p_parent_directory_handle || !p_context || !p_link_handle || !p_linkname || !p_linkcontent) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_symlink); /* Tests if symlinking is allowed by configuration. */ if(!global_fs_info.symlink_support) Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_symlink); /* build the new path and check the permissions on the parent directory */ status = fsal_internal_Handle2FidPath(p_context, p_parent_directory_handle, &fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_symlink); /* retrieve directory metadata, for checking access */ TakeTokenFSCall(); rc = lstat(fsalpath.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_symlink); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink); } if(buffstat.st_mode & S_ISGID) setgid_bit = TRUE; status = fsal_internal_testAccess(p_context, FSAL_W_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_symlink); /* build symlink path */ status = fsal_internal_appendNameToPath(&fsalpath, p_linkname); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_symlink); /* create the symlink on the filesystem. */ TakeTokenFSCall(); rc = symlink(p_linkcontent->path, fsalpath.path); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink); /* Get symlink handle */ TakeTokenFSCall(); status = fsal_internal_Path2Handle(p_context, &fsalpath, p_link_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* chown the symlink to the current user/group */ TakeTokenFSCall(); rc = lchown(fsalpath.path, p_context->credential.user, setgid_bit ? -1 : p_context->credential.group); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink); /* get attributes if asked */ if(p_link_attributes) { status = LUSTREFSAL_getattrs(p_link_handle, p_context, p_link_attributes); /* On error, we set a flag in the returned attributes */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_link_attributes->asked_attributes); FSAL_SET_MASK(p_link_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_symlink); }
/** * FSAL_lookup : * Looks up for an object into a directory. * * Note : if parent handle and filename are NULL, * this retrieves root's handle. * * \param parent_directory_handle (input) * Handle of the parent directory to search the object in. * \param filename (input) * The name of the object to find. * \param p_context (input) * Authentication context for the operation (user,...). * \param object_handle (output) * The handle of the object corresponding to filename. * \param object_attributes (optional input/output) * Pointer to the attributes of the object we found. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * It can be NULL (increases performances). * * \return - ERR_FSAL_NO_ERROR, if no error. * - Another error code else. * */ fsal_status_t LUSTREFSAL_lookup(fsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_filename, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_handle_t * p_object_handle, /* OUT */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; struct stat buffstat; fsal_path_t pathfsal; /* sanity checks * note : object_attributes is optionnal * parent_directory_handle may be null for getting FS root. */ if(!p_object_handle || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); /* filename AND parent handle are NULL => lookup "/" */ if((p_parent_directory_handle && !p_filename) || (!p_parent_directory_handle && p_filename)) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); /* get information about root */ if(!p_parent_directory_handle) { /* get handle for the mount point */ FSAL_str2path(((lustrefsal_op_context_t *)p_context)->export_context->mount_point, ((lustrefsal_op_context_t *)p_context)->export_context->mnt_len, &pathfsal); TakeTokenFSCall(); status = fsal_internal_Path2Handle(p_context, &pathfsal, p_object_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* get attributes, if asked */ if(p_object_attributes) { status = LUSTREFSAL_getattrs(p_object_handle, p_context, p_object_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* Done */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookup); } /* retrieve directory attributes */ status = fsal_internal_Handle2FidPath(p_context, p_parent_directory_handle, &pathfsal); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* get directory metadata */ TakeTokenFSCall(); rc = lstat(pathfsal.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_lookup); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_lookup); } /* Be careful about junction crossing, symlinks, hardlinks,... */ switch (posix2fsal_type(buffstat.st_mode)) { case FSAL_TYPE_DIR: // OK break; case FSAL_TYPE_JUNCTION: // This is a junction Return(ERR_FSAL_XDEV, 0, INDEX_FSAL_lookup); case FSAL_TYPE_FILE: case FSAL_TYPE_LNK: case FSAL_TYPE_XATTR: // not a directory Return(ERR_FSAL_NOTDIR, 0, INDEX_FSAL_lookup); default: Return(ERR_FSAL_SERVERFAULT, 0, INDEX_FSAL_lookup); } LogFullDebug(COMPONENT_FSAL, "lookup of %s/%s\n", pathfsal.path, p_filename->name); /* check rights to enter into the directory */ status = fsal_internal_testAccess(p_context, FSAL_X_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); status = fsal_internal_appendNameToPath(&pathfsal, p_filename); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* get file handle, it it exists */ TakeTokenFSCall(); status = fsal_internal_Path2Handle(p_context, &pathfsal, p_object_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* get object attributes */ if(p_object_attributes) { status = LUSTREFSAL_getattrs(p_object_handle, p_context, p_object_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* lookup complete ! */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookup); }