SYSCALL_DEFINE3(old_readdir, unsigned int, fd, struct old_linux_dirent __user *, dirent, unsigned int, count) { int error; struct file * file; struct readdir_callback buf; if (scribe_track_next_file_read()) { scribe_kill(current->scribe->ctx, -ENOMEM); return -ENOMEM; } error = -EBADF; file = fget(fd); if (!file) goto out; buf.result = 0; buf.dirent = dirent; error = vfs_readdir(file, fillonedir, &buf); if (buf.result) error = buf.result; fput(file); out: return error; }
static int scribe_getname(struct socket *sock, struct sockaddr *addr, int *sockaddr_len, int peer) { struct scribe_ps *scribe = current->scribe; int ret, err; if (!is_scribed(scribe)) return sock->real_ops->getname(sock, addr, sockaddr_len, peer); err = scribe_result( ret, sock->real_ops->getname(sock, addr, sockaddr_len, peer)); if (err) goto out; if (ret < 0) goto out; err = scribe_value(sockaddr_len); if (err) goto out; err = scribe_buffer(addr, *sockaddr_len); out: if (err) { scribe_kill(scribe->ctx, err); return err; } return ret; }
SYSCALL_DEFINE3(getdents64, unsigned int, fd, struct linux_dirent64 __user *, dirent, unsigned int, count) { struct file * file; struct linux_dirent64 __user * lastdirent; struct getdents_callback64 buf; int error; error = -EFAULT; if (!access_ok(VERIFY_WRITE, dirent, count)) goto out; if (scribe_track_next_file_read()) { scribe_kill(current->scribe->ctx, -ENOMEM); return -ENOMEM; } error = -EBADF; file = fget(fd); if (!file) goto out; buf.current_dir = dirent; buf.previous = NULL; buf.count = count; buf.error = 0; error = vfs_readdir(file, filldir64, &buf); if (error >= 0) error = buf.error; lastdirent = buf.previous; if (lastdirent) { typeof(lastdirent->d_off) d_off = file->f_pos; if (__put_user(d_off, &lastdirent->d_off)) error = -EFAULT; else error = count - buf.count; } fput(file); out: return error; }
static int get_data_event(struct scribe_ps *scribe, struct data_desc *desc) { union scribe_event_data_union event; if (is_recording(scribe)) { event = scribe->prepared_data_event; if (event.generic) { scribe->prepared_data_event.generic = NULL; if (desc->do_info) { /* we're good */ } else if (desc->do_extra) { BUG_ON(event.extra->h.size < desc->size); event.extra->h.size = desc->size; } else { BUG_ON(event.regular->h.size < desc->size); event.regular->h.size = desc->size; } goto out; } if (desc->do_info) event.info = scribe_alloc_event( SCRIBE_EVENT_DATA_INFO); else if (desc->do_extra) event.extra = scribe_alloc_event_sized( SCRIBE_EVENT_DATA_EXTRA, desc->size); else event.regular = scribe_alloc_event_sized( SCRIBE_EVENT_DATA, desc->size); if (!event.generic) { scribe_kill(scribe->ctx, -ENOMEM); return -ENOMEM; } goto out; } else /* replaying */ { event = scribe->prepared_data_event; if (event.generic) { scribe->prepared_data_event.generic = NULL; goto out; } /* * Not using scribe_dequeue_event_sized() because we don't * really know the size (maybe we are in * scribe_prepare_data_event() and @desc->size would only be the * maximum size). */ /* * XXX XXX We cannot dequeue in the middle of the stream * because our data event may act as a fence. * So we'll peek, which means that we'll have to dequeue it * eventually. */ if (desc->do_info) event.generic = scribe_find_event_specific( scribe, SCRIBE_EVENT_DATA_INFO); else if (desc->do_extra) event.generic = scribe_find_event_specific( scribe, SCRIBE_EVENT_DATA_EXTRA); else event.generic = scribe_find_event_specific( scribe, SCRIBE_EVENT_DATA); if (IS_ERR(event.generic)) return PTR_ERR(event.generic); } out: desc->event = event; return 0; }