void cfs_walk_dir_generic(struct ceph_mount_info* _fs, const char* _entry_point, cfs_dentry_handler_t _handler, cfs_dentry_comparator_t _comparator, void* _data, unsigned int _level) { int ceph_opendir_res = -1; int ceph_readdirplus_r_res = 0; int sb_mask = 0; char path[PATH_MAX]; struct ceph_dir_result* cfs_dir = NULL; struct dirent entry; struct stat sb; pfcq_zero(&entry, sizeof(struct dirent)); pfcq_zero(&sb, sizeof(struct stat)); pfcq_zero(path, PATH_MAX); debug("Walking into %s entry...\n", _entry_point); ceph_opendir_res = ceph_opendir(_fs, _entry_point, &cfs_dir); if (unlikely(ceph_opendir_res != 0)) { warning("ceph_opendir"); goto out; } while (likely((ceph_readdirplus_r_res = ceph_readdirplus_r(_fs, cfs_dir, &entry, &sb, &sb_mask)) == 1)) { if (unlikely(strcmp(entry.d_name, ".") == 0 || strcmp(entry.d_name, "..") == 0)) continue; if (likely(_comparator)) if (unlikely(!_comparator(_entry_point, &entry, &sb, _level))) continue; if (likely(strcmp(_entry_point, "/") == 0)) { if (unlikely(snprintf(path, PATH_MAX, "/%s", entry.d_name) < 0)) continue; } else { if (unlikely(snprintf(path, PATH_MAX, "%s/%s", _entry_point, entry.d_name) < 0)) continue; } if (likely(_handler)) _handler(_fs, path, &entry, &sb, _data, _level); } if (unlikely(ceph_closedir(_fs, cfs_dir) != 0)) warning("ceph_closedir"); out: debug("Walking out of %s entry...\n", _entry_point); return; }
/** * FSAL_readdir : * Read the entries of an opened directory. * * \param 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 dirents (output) * Adress of the buffer where the direntries are to be stored. * \param end_position (output) * Cookie that indicates the current position in the directory. * \param count (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 CEPHFSAL_readdir(fsal_dir_t *extdescriptor, fsal_op_context_t * p_context, /* IN */ fsal_cookie_t extstart, fsal_attrib_mask_t attrmask, fsal_mdsize_t buffersize, fsal_dirent_t *dirents, fsal_cookie_t *extend, fsal_count_t *count, fsal_boolean_t *end_of_dir) { int rc = 0; fsal_status_t status; struct dirent de; cephfsal_dir_t* descriptor = (cephfsal_dir_t*) extdescriptor; struct ceph_mount_info *cmount = descriptor->ctx.export_context->cmount; loff_t start = ((cephfsal_cookie_t*) extstart.data)->cookie; loff_t* end = &((cephfsal_cookie_t*) extend->data)->cookie; unsigned int max_entries = buffersize / sizeof(fsal_dirent_t); /* sanity checks */ if(!descriptor || !dirents || !end || !count || !end_of_dir) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir); *end_of_dir = FALSE; *count = 0; TakeTokenFSCall(); (void) ceph_seekdir(cmount, DH(descriptor), start); while ((*count <= max_entries) && !(*end_of_dir)) { struct stat st; memset(&dirents[*count], sizeof(fsal_dirent_t), 0); memset(&de, sizeof(struct dirent), 0); memset(&st, sizeof(struct stat), 0); int stmask = 0; TakeTokenFSCall(); rc = ceph_readdirplus_r(cmount, DH(descriptor), &de, &st, &stmask); if (rc < 0) /* Error */ Return(posix2fsal_error(rc), 0, INDEX_FSAL_readdir); else if (rc == 1) { /* Got a dirent */ cephfsal_handle_t* entryhandle = (cephfsal_handle_t*) &(dirents[*count].handle.data); cephfsal_cookie_t* entrycookie = (cephfsal_cookie_t*) &(dirents[*count].cookie); /* skip . and .. */ if(!strcmp(de.d_name, ".") || !strcmp(de.d_name, "..")) continue; entryhandle->data.vi.ino.val = st.st_ino; entryhandle->data.vi.snapid.val = st.st_dev; status = FSAL_str2name(de.d_name, FSAL_MAX_NAME_LEN, &(dirents[*count].name)); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_readdir); entrycookie->data.cookie = ceph_telldir(cmount, DH(descriptor)); dirents[*count].attributes.asked_attributes = attrmask; status = posix2fsal_attributes(&st, &(dirents[*count].attributes)); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(dirents[*count].attributes .asked_attributes); FSAL_SET_MASK(dirents[*count].attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); } if (*count != 0) { dirents[(*count)-1].nextentry = &(dirents[*count]); } (*count)++; } else if (rc == 0) /* EOF */ *end_of_dir = TRUE; else{ /* Can't happen */ abort(); } } /* while */ (*end) = ceph_telldir(cmount, DH(descriptor)); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir); }
/* * Get the next file to backup. */ static bRC get_next_file_to_backup(bpContext *ctx) { int status; struct save_pkt sp; struct dirent *entry; plugin_ctx *p_ctx = (plugin_ctx *)ctx->pContext; /* * See if we just saved the directory then we are done processing this directory. */ switch (p_ctx->type) { case FT_DIREND: /* * See if there is anything on the dir stack to pop off and continue reading that directory. */ if (!p_ctx->dir_stack->empty()) { const char *cwd; struct dir_stack_entry *new_entry; /* * Change the GLFS cwd back one dir. */ status = ceph_chdir(p_ctx->cmount, ".."); if (status < 0) { berrno be; Jmsg(ctx, M_ERROR, "ceph_chdir(%s) failed: %s\n", "..", be.bstrerror(-status)); return bRC_Error; } /* * Save where we are in the tree. */ cwd = ceph_getcwd(p_ctx->cmount); pm_strcpy(p_ctx->cwd, cwd); /* * Pop the previous directory handle and continue processing that. */ new_entry = (struct dir_stack_entry *)p_ctx->dir_stack->pop(); memcpy(&p_ctx->statp, &new_entry->statp, sizeof(p_ctx->statp)); p_ctx->cdir = new_entry->cdir; free(new_entry); } else { return bRC_OK; } break; default: break; } if (!p_ctx->cdir) { return bRC_Error; } /* * Loop until we know what file is next or when we are done. */ while (1) { int stmask = 0; memset(&p_ctx->statp, 0, sizeof(p_ctx->statp)); memset(&p_ctx->de, 0, sizeof(p_ctx->de)); status = ceph_readdirplus_r(p_ctx->cmount, p_ctx->cdir, &p_ctx->de, &p_ctx->statp, &stmask); /* * No more entries in this directory ? */ if (status == 0) { status = ceph_stat(p_ctx->cmount, p_ctx->cwd, &p_ctx->statp); if (status < 0) { berrno be; Jmsg(ctx, M_ERROR, "ceph_stat(%s) failed: %s\n", p_ctx->cwd, be.bstrerror(-status)); return bRC_Error; } status = ceph_closedir(p_ctx->cmount, p_ctx->cdir); if (status < 0) { berrno be; Jmsg(ctx, M_ERROR, "ceph_closedir(%s) failed: %s\n", p_ctx->cwd, be.bstrerror(-status)); return bRC_Error; } p_ctx->cdir = NULL; p_ctx->type = FT_DIREND; pm_strcpy(p_ctx->next_filename, p_ctx->cwd); Dmsg(ctx, dbglvl, "cephfs-fd: next file to backup %s\n", p_ctx->next_filename); return bRC_More; } entry = &p_ctx->de; /* * Skip `.', `..', and excluded file names. */ if (entry->d_name[0] == '\0' || (entry->d_name[0] == '.' && (entry->d_name[1] == '\0' || (entry->d_name[1] == '.' && entry->d_name[2] == '\0')))) { continue; } Mmsg(p_ctx->next_filename, "%s/%s", p_ctx->cwd, entry->d_name); /* * Determine the FileType. */ switch (p_ctx->statp.st_mode & S_IFMT) { case S_IFREG: p_ctx->type = FT_REG; break; case S_IFLNK: p_ctx->type = FT_LNK; status = ceph_readlink(p_ctx->cmount, p_ctx->next_filename, p_ctx->link_target, sizeof_pool_memory(p_ctx->link_target)); if (status < 0) { berrno be; Jmsg(ctx, M_ERROR, "ceph_readlink(%s) failed: %s\n", p_ctx->next_filename, be.bstrerror(-status)); p_ctx->type = FT_NOFOLLOW; } p_ctx->link_target[status] = '\0'; break; case S_IFDIR: p_ctx->type = FT_DIRBEGIN; break; case S_IFCHR: case S_IFBLK: case S_IFIFO: #ifdef S_IFSOCK case S_IFSOCK: #endif p_ctx->type = FT_SPEC; break; default: Jmsg(ctx, M_FATAL, "Unknown filetype encountered %ld for %s\n", p_ctx->statp.st_mode & S_IFMT, p_ctx->next_filename); return bRC_Error; } /* * See if we accept this file under the currently loaded fileset. */ memset(&sp, 0, sizeof(sp)); sp.pkt_size = sizeof(sp); sp.pkt_end = sizeof(sp); sp.fname = p_ctx->next_filename; sp.type = p_ctx->type; memcpy(&sp.statp, &p_ctx->statp, sizeof(sp.statp)); if (bfuncs->AcceptFile(ctx, &sp) == bRC_Skip) { Dmsg(ctx, dbglvl, "cephfs-fd: file %s skipped due to current fileset settings\n", p_ctx->next_filename); continue; } /* * If we made it here we have the next file to backup. */ break; } Dmsg(ctx, dbglvl, "cephfs-fd: next file to backup %s\n", p_ctx->next_filename); return bRC_More; }