/* based on generic filldir in fs/readir.c */ static int unionfs_filldir(void *dirent, const char *oname, int namelen, loff_t offset, u64 ino, unsigned int d_type) { struct unionfs_getdents_callback *buf = dirent; struct filldir_node *found = NULL; int err = 0; int is_whiteout; char *name = (char *) oname; buf->filldir_called++; is_whiteout = is_whiteout_name(&name, &namelen); found = find_filldir_node(buf->rdstate, name, namelen, is_whiteout); if (found) { /* * If we had non-whiteout entry in dir cache, then mark it * as a whiteout and but leave it in the dir cache. */ if (is_whiteout && !found->whiteout) found->whiteout = is_whiteout; goto out; } /* if 'name' isn't a whiteout, filldir it. */ if (!is_whiteout) { off_t pos = rdstate2offset(buf->rdstate); u64 unionfs_ino = ino; err = buf->filldir(buf->dirent, name, namelen, pos, unionfs_ino, d_type); buf->rdstate->offset++; verify_rdstate_offset(buf->rdstate); } /* * If we did fill it, stuff it in our hash, otherwise return an * error. */ if (err) { buf->filldir_error = err; goto out; } buf->entries_written++; err = add_filldir_node(buf->rdstate, name, namelen, buf->rdstate->bindex, is_whiteout); if (err) buf->filldir_error = err; out: return err; }
/* This filldir function makes sure only whiteouts exist within a directory. */ static int readdir_util_callback(void *dirent, const char *oname, int namelen, loff_t offset, u64 ino, unsigned int d_type) { int err = 0; struct unionfs_rdutil_callback *buf = dirent; int is_whiteout; struct filldir_node *found; char *name = (char *) oname; buf->filldir_called = 1; if (name[0] == '.' && (namelen == 1 || (name[1] == '.' && namelen == 2))) goto out; is_whiteout = is_whiteout_name(&name, &namelen); found = find_filldir_node(buf->rdstate, name, namelen, is_whiteout); /* If it was found in the table there was a previous whiteout. */ if (found) goto out; /* * if it wasn't found and isn't a whiteout, the directory isn't * empty. */ err = -ENOTEMPTY; if ((buf->mode == RD_CHECK_EMPTY) && !is_whiteout) goto out; err = add_filldir_node(buf->rdstate, name, namelen, buf->rdstate->bindex, is_whiteout); out: buf->err = err; return err; }