/** * Case insensitive sorting for directory entry names, so * that directory entries are listed first. */ static int filesort(const struct dirent **d1, const struct dirent **d2) { const char *name1 = (*d1)->d_name; const char *name2 = (*d2)->d_name; #ifndef HAVE_DIRENT_D_TYPE int type1 = DT_UNKNOWN; int type2 = DT_UNKNOWN; #else int type1 = (*d1)->d_type; int type2 = (*d2)->d_type; #endif /* OS / file system that doesn't support d_type field, or symlink */ if (type1 == DT_UNKNOWN || type1 == DT_LNK) type1 = get_dtype(name1); if (type2 == DT_UNKNOWN || type2 == DT_LNK) type2 = get_dtype(name2); if (type1 == DT_DIR) { if (type2 != DT_DIR) return -1; } else if (type2 == DT_DIR) { if (type1 != DT_DIR) return 1; } return strcasecmp(name1, name2); }
/* Scan the list and let the last match determine the fate. * Return 1 for exclude, 0 for include and -1 for undecided. */ int excluded_from_list(const char *pathname, int pathlen, const char *basename, int *dtype, struct exclude_list *el) { int i; if (el->nr) { for (i = el->nr - 1; 0 <= i; i--) { struct exclude *x = el->excludes[i]; const char *exclude = x->pattern; int to_exclude = x->to_exclude; if (x->flags & EXC_FLAG_MUSTBEDIR) { if (*dtype == DT_UNKNOWN) *dtype = get_dtype(NULL, pathname, pathlen); if (*dtype != DT_DIR) continue; } if (x->flags & EXC_FLAG_NODIR) { /* match basename */ if (x->flags & EXC_FLAG_NOWILDCARD) { if (!strcmp_icase(exclude, basename)) return to_exclude; } else if (x->flags & EXC_FLAG_ENDSWITH) { if (x->patternlen - 1 <= pathlen && !strcmp_icase(exclude + 1, pathname + pathlen - x->patternlen + 1)) return to_exclude; } else { if (fnmatch_icase(exclude, basename, 0) == 0) return to_exclude; } } else { /* match with FNM_PATHNAME: * exclude has base (baselen long) implicitly * in front of it. */ int baselen = x->baselen; if (*exclude == '/') exclude++; if (pathlen < baselen || (baselen && pathname[baselen-1] != '/') || strncmp_icase(pathname, x->base, baselen)) continue; if (x->flags & EXC_FLAG_NOWILDCARD) { if (!strcmp_icase(exclude, pathname + baselen)) return to_exclude; } else { if (fnmatch_icase(exclude, pathname+baselen, FNM_PATHNAME) == 0) return to_exclude; } } } } return -1; /* undecided */ }
static enum path_treatment treat_one_path(struct dir_struct *dir, struct strbuf *path, const struct path_simplify *simplify, int dtype, struct dirent *de) { int exclude; int has_path_in_index = !!cache_file_exists(path->buf, path->len, ignore_case); if (dtype == DT_UNKNOWN) dtype = get_dtype(de, path->buf, path->len); /* Always exclude indexed files */ if (dtype != DT_DIR && has_path_in_index) return path_none; /* * When we are looking at a directory P in the working tree, * there are three cases: * * (1) P exists in the index. Everything inside the directory P in * the working tree needs to go when P is checked out from the * index. * * (2) P does not exist in the index, but there is P/Q in the index. * We know P will stay a directory when we check out the contents * of the index, but we do not know yet if there is a directory * P/Q in the working tree to be killed, so we need to recurse. * * (3) P does not exist in the index, and there is no P/Q in the index * to require P to be a directory, either. Only in this case, we * know that everything inside P will not be killed without * recursing. */ if ((dir->flags & DIR_COLLECT_KILLED_ONLY) && (dtype == DT_DIR) && !has_path_in_index && (directory_exists_in_index(path->buf, path->len) == index_nonexistent)) return path_none; exclude = is_excluded(dir, path->buf, &dtype); /* * Excluded? If we don't explicitly want to show * ignored files, ignore it */ if (exclude && !(dir->flags & (DIR_SHOW_IGNORED|DIR_SHOW_IGNORED_TOO))) return path_excluded; switch (dtype) { default: return path_none; case DT_DIR: strbuf_addch(path, '/'); return treat_directory(dir, path->buf, path->len, exclude, simplify); case DT_REG: case DT_LNK: return exclude ? path_excluded : path_untracked; } }
static enum path_treatment treat_one_path(struct dir_struct *dir, struct strbuf *path, const struct path_simplify *simplify, int dtype, struct dirent *de) { int exclude; if (dtype == DT_UNKNOWN) dtype = get_dtype(de, path->buf, path->len); /* Always exclude indexed files */ if (dtype != DT_DIR && cache_name_exists(path->buf, path->len, ignore_case)) return path_none; exclude = is_excluded(dir, path->buf, &dtype); /* * Excluded? If we don't explicitly want to show * ignored files, ignore it */ if (exclude && !(dir->flags & (DIR_SHOW_IGNORED|DIR_SHOW_IGNORED_TOO))) return path_excluded; switch (dtype) { default: return path_none; case DT_DIR: strbuf_addch(path, '/'); return treat_directory(dir, path->buf, path->len, exclude, simplify); case DT_REG: case DT_LNK: return exclude ? path_excluded : path_untracked; } }
static enum path_treatment treat_one_path(struct dir_struct *dir, char *path, int *len, const struct path_simplify *simplify, int dtype, struct dirent *de) { int exclude = excluded(dir, path, &dtype); if (exclude && (dir->flags & DIR_COLLECT_IGNORED) && exclude_matches_pathspec(path, *len, simplify)) dir_add_ignored(dir, path, *len); /* * Excluded? If we don't explicitly want to show * ignored files, ignore it */ if (exclude && !(dir->flags & DIR_SHOW_IGNORED)) return path_ignored; if (dtype == DT_UNKNOWN) dtype = get_dtype(de, path, *len); /* * Do we want to see just the ignored files? * We still need to recurse into directories, * even if we don't ignore them, since the * directory may contain files that we do.. */ if (!exclude && (dir->flags & DIR_SHOW_IGNORED)) { if (dtype != DT_DIR) return path_ignored; } switch (dtype) { default: return path_ignored; case DT_DIR: memcpy(path + *len, "/", 2); (*len)++; switch (treat_directory(dir, path, *len, simplify)) { case show_directory: if (exclude != !!(dir->flags & DIR_SHOW_IGNORED)) return path_ignored; break; case recurse_into_directory: return path_recurse; case ignore_directory: return path_ignored; } break; case DT_REG: case DT_LNK: break; } return path_handled; }
/* * Scan the given exclude list in reverse to see whether pathname * should be ignored. The first match (i.e. the last on the list), if * any, determines the fate. Returns the exclude_list element which * matched, or NULL for undecided. */ static struct exclude *last_exclude_matching_from_list(const char *pathname, int pathlen, const char *basename, int *dtype, struct exclude_list *el) { int i; if (!el->nr) return NULL; /* undefined */ for (i = el->nr - 1; 0 <= i; i--) { struct exclude *x = el->excludes[i]; const char *exclude = x->pattern; int prefix = x->nowildcardlen; if (x->flags & EXC_FLAG_MUSTBEDIR) { if (*dtype == DT_UNKNOWN) *dtype = get_dtype(NULL, pathname, pathlen); if (*dtype != DT_DIR) continue; } if (x->flags & EXC_FLAG_NODIR) { if (match_basename(basename, pathlen - (basename - pathname), exclude, prefix, x->patternlen, x->flags)) return x; continue; } assert(x->baselen == 0 || x->base[x->baselen - 1] == '/'); if (match_pathname(pathname, pathlen, x->base, x->baselen ? x->baselen - 1 : 0, exclude, prefix, x->patternlen, x->flags)) return x; } return NULL; /* undecided */ }
/* * So this function is called when the volume is mkfsed with * dir_index disabled. In order to keep f_pos persistent * after we convert from an inlined dir to a blocked based, * we just pretend that we are a normal dir and return the * offset as if '.' and '..' really take place. * */ int ext4_read_inline_dir(struct file *file, struct dir_context *ctx, int *has_inline_data) { unsigned int offset, parent_ino; int i; struct ext4_dir_entry_2 *de; struct super_block *sb; struct inode *inode = file_inode(file); int ret, inline_size = 0; struct ext4_iloc iloc; void *dir_buf = NULL; int dotdot_offset, dotdot_size, extra_offset, extra_size; ret = ext4_get_inode_loc(inode, &iloc); if (ret) return ret; down_read(&EXT4_I(inode)->xattr_sem); if (!ext4_has_inline_data(inode)) { up_read(&EXT4_I(inode)->xattr_sem); *has_inline_data = 0; goto out; } inline_size = ext4_get_inline_size(inode); dir_buf = kmalloc(inline_size, GFP_NOFS); if (!dir_buf) { ret = -ENOMEM; up_read(&EXT4_I(inode)->xattr_sem); goto out; } ret = ext4_read_inline_data(inode, dir_buf, inline_size, &iloc); up_read(&EXT4_I(inode)->xattr_sem); if (ret < 0) goto out; ret = 0; sb = inode->i_sb; parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode); offset = ctx->pos; /* * dotdot_offset and dotdot_size is the real offset and * size for ".." and "." if the dir is block based while * the real size for them are only EXT4_INLINE_DOTDOT_SIZE. * So we will use extra_offset and extra_size to indicate them * during the inline dir iteration. */ dotdot_offset = EXT4_DIR_REC_LEN(1); dotdot_size = dotdot_offset + EXT4_DIR_REC_LEN(2); extra_offset = dotdot_size - EXT4_INLINE_DOTDOT_SIZE; extra_size = extra_offset + inline_size; /* * If the version has changed since the last call to * readdir(2), then we might be pointing to an invalid * dirent right now. Scan from the start of the inline * dir to make sure. */ if (file->f_version != inode->i_version) { for (i = 0; i < extra_size && i < offset;) { /* * "." is with offset 0 and * ".." is dotdot_offset. */ if (!i) { i = dotdot_offset; continue; } else if (i == dotdot_offset) { i = dotdot_size; continue; } /* for other entry, the real offset in * the buf has to be tuned accordingly. */ de = (struct ext4_dir_entry_2 *) (dir_buf + i - extra_offset); /* It's too expensive to do a full * dirent test each time round this * loop, but we do have to test at * least that it is non-zero. A * failure will be detected in the * dirent test below. */ if (ext4_rec_len_from_disk(de->rec_len, extra_size) < EXT4_DIR_REC_LEN(1)) break; i += ext4_rec_len_from_disk(de->rec_len, extra_size); } offset = i; ctx->pos = offset; file->f_version = inode->i_version; } while (ctx->pos < extra_size) { if (ctx->pos == 0) { if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR)) goto out; ctx->pos = dotdot_offset; continue; } if (ctx->pos == dotdot_offset) { if (!dir_emit(ctx, "..", 2, parent_ino, DT_DIR)) goto out; ctx->pos = dotdot_size; continue; } de = (struct ext4_dir_entry_2 *) (dir_buf + ctx->pos - extra_offset); if (ext4_check_dir_entry(inode, file, de, iloc.bh, dir_buf, extra_size, ctx->pos)) goto out; if (le32_to_cpu(de->inode)) { if (!dir_emit(ctx, de->name, de->name_len, le32_to_cpu(de->inode), get_dtype(sb, de->file_type))) goto out; } ctx->pos += ext4_rec_len_from_disk(de->rec_len, extra_size); } out: kfree(dir_buf); brelse(iloc.bh); return ret; }
static int read_directory_recursive(struct dir_struct *dir, const char *base, int baselen, int check_only, struct index_state *index, const char *worktree, IgnoreFunc ignore_func, void *data) { char *realpath = g_build_path (PATH_SEPERATOR, worktree, base, NULL); GDir *fdir = g_dir_open (realpath, 0, NULL); const char *dname; char *nfc_dname; int contents = 0; int dtype; if (fdir) { char path[SEAF_PATH_MAX + 1]; memcpy(path, base, baselen); while ((dname = g_dir_read_name(fdir)) != NULL) { int len = 0; #ifdef __APPLE__ nfc_dname = g_utf8_normalize (dname, -1, G_NORMALIZE_NFC); #else nfc_dname = g_strdup(dname); #endif if (is_dot_or_dotdot(nfc_dname)) { g_free (nfc_dname); continue; } if (ignore_func (realpath, nfc_dname, data)) { g_free (nfc_dname); continue; } dtype = get_dtype(nfc_dname, realpath); switch (dtype) { case DT_REG: len = strlen(nfc_dname); memcpy(path + baselen, nfc_dname, len + 1); len = strlen(path); break; case DT_DIR: len = strlen(nfc_dname); memcpy(path + baselen, nfc_dname, len + 1); memcpy(path + baselen + len, "/", 2); len = strlen(path); read_directory_recursive(dir, path, len, 0, index, worktree, ignore_func, data); g_free (nfc_dname); continue; default: /* DT_UNKNOWN */ len = 0; break; } if(len > 0) dir_add_name(dir, path, len, index); g_free (nfc_dname); } g_dir_close(fdir); } g_free(realpath); return contents; }
/* * Read a directory tree. We currently ignore anything but * directories, regular files and symlinks. That's because git * doesn't handle them at all yet. Maybe that will change some * day. * * Also, we ignore the name ".git" (even if it is not a directory). * That likely will not change. */ static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only, const struct path_simplify *simplify) { DIR *fdir = opendir(path); int contents = 0; if (fdir) { struct dirent *de; char fullname[PATH_MAX + 1]; memcpy(fullname, base, baselen); while ((de = readdir(fdir)) != NULL) { int len, dtype; int exclude; if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git")) continue; len = strlen(de->d_name); /* Ignore overly long pathnames! */ if (len + baselen + 8 > sizeof(fullname)) continue; memcpy(fullname + baselen, de->d_name, len+1); if (simplify_away(fullname, baselen + len, simplify)) continue; dtype = DTYPE(de); exclude = excluded(dir, fullname, &dtype); if (exclude && (dir->flags & DIR_COLLECT_IGNORED) && in_pathspec(fullname, baselen + len, simplify)) dir_add_ignored(dir, fullname, baselen + len); /* * Excluded? If we don't explicitly want to show * ignored files, ignore it */ if (exclude && !(dir->flags & DIR_SHOW_IGNORED)) continue; if (dtype == DT_UNKNOWN) dtype = get_dtype(de, fullname); /* * Do we want to see just the ignored files? * We still need to recurse into directories, * even if we don't ignore them, since the * directory may contain files that we do.. */ if (!exclude && (dir->flags & DIR_SHOW_IGNORED)) { if (dtype != DT_DIR) continue; } switch (dtype) { default: continue; case DT_DIR: memcpy(fullname + baselen + len, "/", 2); len++; switch (treat_directory(dir, fullname, baselen + len, simplify)) { case show_directory: if (exclude != !!(dir->flags & DIR_SHOW_IGNORED)) continue; break; case recurse_into_directory: contents += read_directory_recursive(dir, fullname, fullname, baselen + len, 0, simplify); continue; case ignore_directory: continue; } break; case DT_REG: case DT_LNK: break; } contents++; if (check_only) goto exit_early; else dir_add_name(dir, fullname, baselen + len); } exit_early: closedir(fdir); } return contents; }
int ext4_read_inline_dir(struct file *filp, void *dirent, filldir_t filldir, int *has_inline_data) { int error = 0; unsigned int offset, parent_ino; int i, stored; struct ext4_dir_entry_2 *de; struct super_block *sb; struct inode *inode = filp->f_path.dentry->d_inode; int ret, inline_size = 0; struct ext4_iloc iloc; void *dir_buf = NULL; ret = ext4_get_inode_loc(inode, &iloc); if (ret) return ret; down_read(&EXT4_I(inode)->xattr_sem); if (!ext4_has_inline_data(inode)) { up_read(&EXT4_I(inode)->xattr_sem); *has_inline_data = 0; goto out; } inline_size = ext4_get_inline_size(inode); dir_buf = kmalloc(inline_size, GFP_NOFS); if (!dir_buf) { ret = -ENOMEM; up_read(&EXT4_I(inode)->xattr_sem); goto out; } ret = ext4_read_inline_data(inode, dir_buf, inline_size, &iloc); up_read(&EXT4_I(inode)->xattr_sem); if (ret < 0) goto out; sb = inode->i_sb; stored = 0; parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode); while (!error && !stored && filp->f_pos < inode->i_size) { revalidate: /* * If the version has changed since the last call to * readdir(2), then we might be pointing to an invalid * dirent right now. Scan from the start of the inline * dir to make sure. */ if (filp->f_version != inode->i_version) { for (i = 0; i < inode->i_size && i < offset;) { if (!i) { /* skip "." and ".." if needed. */ i += EXT4_INLINE_DOTDOT_SIZE; continue; } de = (struct ext4_dir_entry_2 *) (dir_buf + i); /* It's too expensive to do a full * dirent test each time round this * loop, but we do have to test at * least that it is non-zero. A * failure will be detected in the * dirent test below. */ if (ext4_rec_len_from_disk(de->rec_len, inline_size) < EXT4_DIR_REC_LEN(1)) break; i += ext4_rec_len_from_disk(de->rec_len, inline_size); } offset = i; filp->f_pos = offset; filp->f_version = inode->i_version; } while (!error && filp->f_pos < inode->i_size) { if (filp->f_pos == 0) { error = filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR); if (error) break; stored++; error = filldir(dirent, "..", 2, 0, parent_ino, DT_DIR); if (error) break; stored++; filp->f_pos = offset = EXT4_INLINE_DOTDOT_SIZE; continue; } de = (struct ext4_dir_entry_2 *)(dir_buf + offset); if (ext4_check_dir_entry(inode, filp, de, iloc.bh, dir_buf, inline_size, offset)) { ret = stored; goto out; } offset += ext4_rec_len_from_disk(de->rec_len, inline_size); if (le32_to_cpu(de->inode)) { /* We might block in the next section * if the data destination is * currently swapped out. So, use a * version stamp to detect whether or * not the directory has been modified * during the copy operation. */ u64 version = filp->f_version; error = filldir(dirent, de->name, de->name_len, filp->f_pos, le32_to_cpu(de->inode), get_dtype(sb, de->file_type)); if (error) break; if (version != filp->f_version) goto revalidate; stored++; } filp->f_pos += ext4_rec_len_from_disk(de->rec_len, inline_size); } offset = 0; } out: kfree(dir_buf); brelse(iloc.bh); return ret; }
// Check that set offset works im2.set_offset(2.3); CHECK(im2.get_offset() == 2.3); // Check that scaling is correct CHECK(im.get_scaling() == 1.0); CHECK(im2.get_scaling() == 1.0); // Check that set scaling works im2.set_scaling(1.1); CHECK(im2.get_scaling() == 1.1); // CHECK that image dtype is correct CHECK(im.get_dtype() == mapnik::image_dtype_gray16); CHECK(im2.get_dtype() == mapnik::image_dtype_gray16); using pixel_type = mapnik::image_view_gray16::pixel_type; pixel_type expected_val; // Check that all data in the view is correct // IM expected_val = 0; pixel_type const* data_im = im.data(); CHECK(*data_im == expected_val); unsigned char const* data_b = im.bytes(); CHECK(*data_b == 0); for (std::size_t y = 0; y < im.height(); ++y) { std::size_t width = im.width(); pixel_type const* data_1 = im.get_row(y); pixel_type const* data_2 = im.get_row(y, 1);
int ext4_read_inline_dir(struct file *filp, void *dirent, filldir_t filldir) { int error = 0; unsigned int offset; int i, stored; void *inline_pos; struct ext4_dir_entry_2 *de; struct super_block *sb; struct inode *inode = filp->f_path.dentry->d_inode; int ret, inline_size = 0; struct ext4_iloc iloc; ret = ext4_get_inode_loc(inode, &iloc); if (ret) return ret; down_read(&EXT4_I(inode)->xattr_sem); if (!ext4_has_inline_data(inode)) goto out; sb = inode->i_sb; stored = 0; offset = filp->f_pos & (sb->s_blocksize - 1); while (!error && !stored && filp->f_pos < inode->i_size) { revalidate: /* If the version has changed since the last call to * readdir(2), then we might be pointing to an invalid * dirent right now. Scan from the start of the block * to make sure. */ if (filp->f_version != inode->i_version) { for (i = 0; i < inode->i_size && i < offset; ) { de = ext4_get_inline_entry(inode, &iloc, i, NULL, &inline_size); /* It's too expensive to do a full * dirent test each time round this * loop, but we do have to test at * least that it is non-zero. A * failure will be detected in the * dirent test below. */ if (ext4_rec_len_from_disk(de->rec_len, inline_size) < EXT4_DIR_REC_LEN(1)) break; i += ext4_rec_len_from_disk(de->rec_len, inline_size); } offset = i; filp->f_pos = offset; filp->f_version = inode->i_version; } while (!error && filp->f_pos < inode->i_size) { de = ext4_get_inline_entry(inode, &iloc, offset, &inline_pos, &inline_size); if (ext4_check_dir_entry(__func__, inode, de, iloc.bh, inline_pos, inline_size, offset)) { ret = stored; goto out; } offset += ext4_rec_len_from_disk(de->rec_len, inline_size); if (le32_to_cpu(de->inode)) { /* We might block in the next section * if the data destination is * currently swapped out. So, use a * version stamp to detect whether or * not the directory has been modified * during the copy operation. */ u64 version = filp->f_version; error = filldir(dirent, de->name, de->name_len, filp->f_pos, le32_to_cpu(de->inode), get_dtype(sb, de->file_type)); if (error) break; if (version != filp->f_version) goto revalidate; stored++; } filp->f_pos += ext4_rec_len_from_disk(de->rec_len, inline_size); } offset = 0; } out: up_read(&EXT4_I(inode)->xattr_sem); brelse(iloc.bh); return ret; }