static int filldir(char *buf, int buflen, const char *name, int namelen, loff_t offset, ino_t ino, unsigned int d_type, int *filled) { struct dirent64 *dirent = (struct dirent64 *)(buf + *filled); struct dirent64 holder; int reclen = ROUND_UP64(NAME_OFFSET(dirent) + namelen + 1); /* * @buf is not guaranteed to be properly aligned. To work around, * first fill stack-allocated @holder, then copy @holder into @buf by * memmove(). */ /* check overflow */ if ((*filled + reclen) > buflen) return 1; holder.d_ino = ino; #ifdef _DIRENT_HAVE_D_OFF holder.d_off = offset; #endif holder.d_reclen = reclen; #ifdef _DIRENT_HAVE_D_TYPE holder.d_type = (unsigned short) d_type; #endif /* gcc unrolls memcpy() of structs into field-wise assignments, * assuming proper alignment. Humor it. */ (*memmover)(dirent, &holder, NAME_OFFSET(dirent)); memcpy(dirent->d_name, name, namelen); dirent->d_name[namelen] = 0; *filled += reclen; return 0; }
static int filldir64(void * __buf, const char * name, int namlen, loff_t offset, ino_t ino, unsigned int d_type) { struct linux_dirent64 * dirent, d; struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf; int reclen = ROUND_UP64(NAME_OFFSET(dirent) + namlen + 1); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; dirent = buf->previous; if (dirent) { d.d_off = offset; copy_to_user(&dirent->d_off, &d.d_off, sizeof(d.d_off)); } dirent = buf->current_dir; buf->previous = dirent; memset(&d, 0, NAME_OFFSET(&d)); d.d_ino = ino; d.d_reclen = reclen; d.d_type = d_type; copy_to_user(dirent, &d, NAME_OFFSET(&d)); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); ((char *) dirent) += reclen; buf->current_dir = dirent; buf->count -= reclen; return 0; }
static int filldir64(void * __buf, const char * name, int namlen, loff_t offset, ino_t ino, unsigned int d_type) { struct linux_dirent64 __user *dirent; struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf; int reclen = ROUND_UP64(NAME_OFFSET(dirent) + namlen + 1); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; dirent = buf->previous; if (dirent) { if (__put_user(offset, &dirent->d_off)) goto efault; } dirent = buf->current_dir; if (__put_user(ino, &dirent->d_ino)) goto efault; if (__put_user(0, &dirent->d_off)) goto efault; if (__put_user(reclen, &dirent->d_reclen)) goto efault; if (__put_user(d_type, &dirent->d_type)) goto efault; if (copy_to_user(dirent->d_name, name, namlen)) goto efault; if (__put_user(0, dirent->d_name + namlen)) goto efault; buf->previous = dirent; ((char *) dirent) += reclen; buf->current_dir = dirent; buf->count -= reclen; return 0; efault: buf->error = -EFAULT; return -EFAULT; }