1 #include "output/file.h"
5 #include <sys/sendfile.h>
7 #include <unistd.h> /* write */
8 #include <stdlib.h> /* malloc, free */
9 #include <string.h> /* memcpy */
11 static size_t file_get_size(output_item
*this);
12 static int file_send(output_item
*this, int fd
, int fdtype
);
13 static size_t file_remaining(output_item
*this);
14 static void file_release(output_item
*this);
16 static size_t file_get_size(output_item
*this) {
17 return ((file_output_item
*)this)->size
;
20 static int file_send(output_item
*this, int fd
, int fdtype
) {
21 file_output_item
*mthis
= (file_output_item
*)this;
22 /* Zero remaining.. this shouldn't occur in workflow */
23 size_t to_send
= file_remaining(this);
24 if(to_send
== 0) return 0;
25 /* Expand FDT_SOCKET to use flags (ex: for MSG_MORE) in certain situations (new output_type?) */
27 case FDT_SOCKET
: /* might be able to use sendfile here */
28 if(!mthis
->no_sendfile
) {
29 ssize_t sent
= sendfile(fd
, mthis
->fd
, &mthis
->index
, to_send
);
32 if(!(errno
== EINVAL
|| errno
== ENOSYS
))
34 mthis
->no_sendfile
= 1;
38 /* TODO: Need to figure out how to read from buffer async and pipe that to out */
40 ssize_t dataRead
= read(mthis
->fd
, buffer
, sizeof(buffer
));
41 mthis
->index
+= dataRead
;
44 /* NOTE: Due to nature of data input... output will necessarily block
45 * or go into loop until a non-block op works */
46 ssize_t written
= write(fd
, buffer
+ index
, dataRead
);
51 /* Bailed/closed, oh no! */
52 if(errno
!= EAGAIN
|| written
== 0)
59 /* XXX: Raise error */
64 static size_t file_remaining(output_item
*this) {
65 file_output_item
*mthis
= (file_output_item
*)this;
66 return mthis
->size
- mthis
->index
;
69 static void file_release(output_item
*this) {
70 file_output_item
*mthis
= (file_output_item
*)this;
76 static output_item_ops file_output_item_ops
= {
77 .get_size
= file_get_size
,
79 .remaining
= file_remaining
,
80 .release
= file_release
83 /* If an error occurs, fd doesn't changes ownership */
84 output_item
*new_file_output_item(int fd
) {
85 file_output_item
*mitem
;
87 if(0 != fstat(fd
, &buf
))
89 /* FD Must point to a real file */
90 if(!S_ISREG(buf
.st_mode
))
92 mitem
= calloc(1, sizeof(file_output_item
));
93 if(!mitem
) return NULL
;
94 mitem
->item
.ops
= &file_output_item_ops
;
96 mitem
->size
= buf
.st_size
;
98 return (output_item
*)mitem
;