xref: /minix3/minix/lib/libpuffs/read.c (revision ba736c796854b82e29da17267614db0a449419db)
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