1 /* Created (MFS based):
2 * February 2010 (Evgeniy Ivanov)
3 */
4
5 #include "fs.h"
6 #include <stddef.h>
7 #include <dirent.h>
8 #include <sys/param.h>
9
10
11 #define GETDENTS_BUFSIZ 4096
12 static char getdents_buf[GETDENTS_BUFSIZ];
13
14 #define RW_BUFSIZ (128 * 1024)
15 static char rw_buf[RW_BUFSIZ];
16
17
18 /*===========================================================================*
19 * fs_read *
20 *===========================================================================*/
fs_read(ino_t ino_nr,struct fsdriver_data * data,size_t bytes,off_t pos,int call)21 ssize_t fs_read(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
22 off_t pos, int call)
23 {
24 int r;
25 size_t bytes_left, bytes_done;
26 struct puffs_node *pn;
27 PUFFS_MAKECRED(pcr, &global_kcred);
28
29 if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL) {
30 lpuffs_debug("walk failed...\n");
31 return(EINVAL);
32 }
33
34 if (bytes > sizeof(rw_buf))
35 bytes = sizeof(rw_buf);
36 bytes_left = bytes;
37
38 if (global_pu->pu_ops.puffs_node_read == NULL)
39 return(EINVAL);
40
41 r = global_pu->pu_ops.puffs_node_read(global_pu, pn, (uint8_t *)rw_buf,
42 pos, &bytes_left, pcr, 0);
43 if (r) {
44 lpuffs_debug("puffs_node_read failed\n");
45 return(EINVAL);
46 }
47
48 bytes_done = bytes - bytes_left;
49
50 if (bytes_done > 0) {
51 if ((r = fsdriver_copyout(data, 0, rw_buf, bytes_done)) != OK)
52 return r;
53 update_timens(pn, ATIME, NULL);
54 }
55
56 return (ssize_t)bytes_done;
57 }
58
59
60 /*===========================================================================*
61 * fs_write *
62 *===========================================================================*/
fs_write(ino_t ino_nr,struct fsdriver_data * data,size_t bytes,off_t pos,int call)63 ssize_t fs_write(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
64 off_t pos, int call)
65 {
66 int r;
67 size_t bytes_left;
68 struct puffs_node *pn;
69 struct vattr va;
70 struct timespec cur_time;
71 PUFFS_MAKECRED(pcr, &global_kcred);
72
73 if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL) {
74 lpuffs_debug("walk failed...\n");
75 return(EINVAL);
76 }
77
78 if (bytes > sizeof(rw_buf))
79 bytes = sizeof(rw_buf);
80 bytes_left = bytes;
81
82 /* At first try to change vattr */
83 if (global_pu->pu_ops.puffs_node_setattr == NULL)
84 return(EINVAL);
85
86 (void)clock_time(&cur_time);
87
88 puffs_vattr_null(&va);
89 if ((u_quad_t)(pos + bytes_left) > pn->pn_va.va_size)
90 va.va_size = bytes_left + pos;
91 va.va_ctime = va.va_mtime = cur_time;
92 va.va_atime = pn->pn_va.va_atime;
93
94 r = global_pu->pu_ops.puffs_node_setattr(global_pu, pn, &va, pcr);
95 if (r) return(EINVAL);
96
97 if ((r = fsdriver_copyin(data, 0, rw_buf, bytes)) != OK)
98 return r;
99
100 if (global_pu->pu_ops.puffs_node_write == NULL)
101 return(EINVAL);
102
103 r = global_pu->pu_ops.puffs_node_write(global_pu, pn, (uint8_t *)rw_buf,
104 pos, &bytes_left, pcr, 0);
105 if (r != OK) return(EINVAL);
106
107 return (ssize_t)(bytes - bytes_left);
108 }
109
110
111 /*===========================================================================*
112 * fs_getdents *
113 *===========================================================================*/
fs_getdents(ino_t ino_nr,struct fsdriver_data * data,size_t bytes,off_t * pos)114 ssize_t fs_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
115 off_t *pos)
116 {
117 int r;
118 register struct puffs_node *pn;
119 size_t buf_left, written;
120 struct dirent *dent;
121 int eofflag = 0;
122 PUFFS_MAKECRED(pcr, &global_kcred);
123
124 if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL) {
125 lpuffs_debug("walk failed...\n");
126 return(EINVAL);
127 }
128
129 if (bytes > sizeof(getdents_buf))
130 bytes = sizeof(getdents_buf);
131 memset(getdents_buf, 0, sizeof(getdents_buf)); /* Avoid leaking any data */
132
133 buf_left = bytes;
134
135 dent = (struct dirent*) getdents_buf;
136
137 r = global_pu->pu_ops.puffs_node_readdir(global_pu, pn, dent, pos,
138 &buf_left, pcr, &eofflag, 0, 0);
139 if (r) {
140 lpuffs_debug("puffs_node_readdir returned error\n");
141 return(EINVAL);
142 }
143
144 assert(buf_left <= bytes);
145 written = bytes - buf_left;
146
147 if (written == 0 && !eofflag) {
148 lpuffs_debug("The user's buffer is too small\n");
149 return(EINVAL);
150 }
151
152 if (written) {
153 if ((r = fsdriver_copyout(data, 0, getdents_buf, written)) != OK)
154 return r;
155 }
156
157 update_timens(pn, ATIME, NULL);
158
159 /* The puffs readdir call has already updated the position. */
160 return written;
161 }
162