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 *===========================================================================*/ 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 *===========================================================================*/ 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 *===========================================================================*/ 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