9p-iov-marshal.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /*
  2. * 9p backend
  3. *
  4. * Copyright IBM, Corp. 2010
  5. *
  6. * Authors:
  7. * Anthony Liguori <aliguori@us.ibm.com>
  8. *
  9. * This work is licensed under the terms of the GNU GPL, version 2. See
  10. * the COPYING file in the top-level directory.
  11. *
  12. */
  13. #include "qemu/osdep.h"
  14. #include <glib/gprintf.h>
  15. #include <utime.h>
  16. #include "9p-iov-marshal.h"
  17. #include "qemu/bswap.h"
  18. static ssize_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count,
  19. size_t offset, size_t size, int pack)
  20. {
  21. int i = 0;
  22. size_t copied = 0;
  23. size_t req_size = size;
  24. for (i = 0; size && i < sg_count; i++) {
  25. size_t len;
  26. if (offset >= sg[i].iov_len) {
  27. /* skip this sg */
  28. offset -= sg[i].iov_len;
  29. continue;
  30. } else {
  31. len = MIN(sg[i].iov_len - offset, size);
  32. if (pack) {
  33. memcpy(sg[i].iov_base + offset, addr, len);
  34. } else {
  35. memcpy(addr, sg[i].iov_base + offset, len);
  36. }
  37. size -= len;
  38. copied += len;
  39. addr += len;
  40. if (size) {
  41. offset = 0;
  42. continue;
  43. }
  44. }
  45. }
  46. if (copied < req_size) {
  47. /*
  48. * We copied less that requested size. error out
  49. */
  50. return -ENOBUFS;
  51. }
  52. return copied;
  53. }
  54. static ssize_t v9fs_unpack(void *dst, struct iovec *out_sg, int out_num,
  55. size_t offset, size_t size)
  56. {
  57. return v9fs_packunpack(dst, out_sg, out_num, offset, size, 0);
  58. }
  59. ssize_t v9fs_pack(struct iovec *in_sg, int in_num, size_t offset,
  60. const void *src, size_t size)
  61. {
  62. return v9fs_packunpack((void *)src, in_sg, in_num, offset, size, 1);
  63. }
  64. ssize_t v9fs_iov_vunmarshal(struct iovec *out_sg, int out_num, size_t offset,
  65. int bswap, const char *fmt, va_list ap)
  66. {
  67. int i;
  68. ssize_t copied = 0;
  69. size_t old_offset = offset;
  70. for (i = 0; fmt[i]; i++) {
  71. switch (fmt[i]) {
  72. case 'b': {
  73. uint8_t *valp = va_arg(ap, uint8_t *);
  74. copied = v9fs_unpack(valp, out_sg, out_num, offset, sizeof(*valp));
  75. break;
  76. }
  77. case 'w': {
  78. uint16_t val = 0, *valp;
  79. valp = va_arg(ap, uint16_t *);
  80. copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
  81. if (copied <= 0) {
  82. break;
  83. }
  84. if (bswap) {
  85. *valp = le16_to_cpu(val);
  86. } else {
  87. *valp = val;
  88. }
  89. break;
  90. }
  91. case 'd': {
  92. uint32_t val = 0, *valp;
  93. valp = va_arg(ap, uint32_t *);
  94. copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
  95. if (copied <= 0) {
  96. break;
  97. }
  98. if (bswap) {
  99. *valp = le32_to_cpu(val);
  100. } else {
  101. *valp = val;
  102. }
  103. break;
  104. }
  105. case 'q': {
  106. uint64_t val = 0, *valp;
  107. valp = va_arg(ap, uint64_t *);
  108. copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
  109. if (copied <= 0) {
  110. break;
  111. }
  112. if (bswap) {
  113. *valp = le64_to_cpu(val);
  114. } else {
  115. *valp = val;
  116. }
  117. break;
  118. }
  119. case 's': {
  120. V9fsString *str = va_arg(ap, V9fsString *);
  121. copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
  122. "w", &str->size);
  123. if (copied > 0) {
  124. offset += copied;
  125. str->data = g_malloc(str->size + 1);
  126. copied = v9fs_unpack(str->data, out_sg, out_num, offset,
  127. str->size);
  128. if (copied >= 0) {
  129. str->data[str->size] = 0;
  130. } else {
  131. v9fs_string_free(str);
  132. }
  133. }
  134. break;
  135. }
  136. case 'Q': {
  137. V9fsQID *qidp = va_arg(ap, V9fsQID *);
  138. copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
  139. "bdq", &qidp->type, &qidp->version,
  140. &qidp->path);
  141. break;
  142. }
  143. case 'S': {
  144. V9fsStat *statp = va_arg(ap, V9fsStat *);
  145. copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
  146. "wwdQdddqsssssddd",
  147. &statp->size, &statp->type,
  148. &statp->dev, &statp->qid,
  149. &statp->mode, &statp->atime,
  150. &statp->mtime, &statp->length,
  151. &statp->name, &statp->uid,
  152. &statp->gid, &statp->muid,
  153. &statp->extension,
  154. &statp->n_uid, &statp->n_gid,
  155. &statp->n_muid);
  156. break;
  157. }
  158. case 'I': {
  159. V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
  160. copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
  161. "ddddqqqqq",
  162. &iattr->valid, &iattr->mode,
  163. &iattr->uid, &iattr->gid,
  164. &iattr->size, &iattr->atime_sec,
  165. &iattr->atime_nsec,
  166. &iattr->mtime_sec,
  167. &iattr->mtime_nsec);
  168. break;
  169. }
  170. default:
  171. g_assert_not_reached();
  172. }
  173. if (copied < 0) {
  174. return copied;
  175. }
  176. offset += copied;
  177. }
  178. return offset - old_offset;
  179. }
  180. ssize_t v9fs_iov_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
  181. int bswap, const char *fmt, ...)
  182. {
  183. ssize_t ret;
  184. va_list ap;
  185. va_start(ap, fmt);
  186. ret = v9fs_iov_vunmarshal(out_sg, out_num, offset, bswap, fmt, ap);
  187. va_end(ap);
  188. return ret;
  189. }
  190. ssize_t v9fs_iov_vmarshal(struct iovec *in_sg, int in_num, size_t offset,
  191. int bswap, const char *fmt, va_list ap)
  192. {
  193. int i;
  194. ssize_t copied = 0;
  195. size_t old_offset = offset;
  196. for (i = 0; fmt[i]; i++) {
  197. switch (fmt[i]) {
  198. case 'b': {
  199. uint8_t val = va_arg(ap, int);
  200. copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
  201. break;
  202. }
  203. case 'w': {
  204. uint16_t val = va_arg(ap, int);
  205. if (bswap) {
  206. val = cpu_to_le16(val);
  207. }
  208. copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
  209. break;
  210. }
  211. case 'd': {
  212. uint32_t val = va_arg(ap, uint32_t);
  213. if (bswap) {
  214. val = cpu_to_le32(val);
  215. }
  216. copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
  217. break;
  218. }
  219. case 'q': {
  220. uint64_t val = va_arg(ap, uint64_t);
  221. if (bswap) {
  222. val = cpu_to_le64(val);
  223. }
  224. copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
  225. break;
  226. }
  227. case 's': {
  228. V9fsString *str = va_arg(ap, V9fsString *);
  229. copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
  230. "w", str->size);
  231. if (copied > 0) {
  232. offset += copied;
  233. copied = v9fs_pack(in_sg, in_num, offset, str->data, str->size);
  234. }
  235. break;
  236. }
  237. case 'Q': {
  238. V9fsQID *qidp = va_arg(ap, V9fsQID *);
  239. copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap, "bdq",
  240. qidp->type, qidp->version,
  241. qidp->path);
  242. break;
  243. }
  244. case 'S': {
  245. V9fsStat *statp = va_arg(ap, V9fsStat *);
  246. copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
  247. "wwdQdddqsssssddd",
  248. statp->size, statp->type, statp->dev,
  249. &statp->qid, statp->mode, statp->atime,
  250. statp->mtime, statp->length,
  251. &statp->name,
  252. &statp->uid, &statp->gid, &statp->muid,
  253. &statp->extension, statp->n_uid,
  254. statp->n_gid, statp->n_muid);
  255. break;
  256. }
  257. case 'A': {
  258. V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
  259. copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
  260. "qQdddqqqqqqqqqqqqqqq",
  261. statp->st_result_mask,
  262. &statp->qid, statp->st_mode,
  263. statp->st_uid, statp->st_gid,
  264. statp->st_nlink, statp->st_rdev,
  265. statp->st_size, statp->st_blksize,
  266. statp->st_blocks, statp->st_atime_sec,
  267. statp->st_atime_nsec,
  268. statp->st_mtime_sec,
  269. statp->st_mtime_nsec,
  270. statp->st_ctime_sec,
  271. statp->st_ctime_nsec,
  272. statp->st_btime_sec,
  273. statp->st_btime_nsec, statp->st_gen,
  274. statp->st_data_version);
  275. break;
  276. }
  277. default:
  278. g_assert_not_reached();
  279. }
  280. if (copied < 0) {
  281. return copied;
  282. }
  283. offset += copied;
  284. }
  285. return offset - old_offset;
  286. }
  287. ssize_t v9fs_iov_marshal(struct iovec *in_sg, int in_num, size_t offset,
  288. int bswap, const char *fmt, ...)
  289. {
  290. ssize_t ret;
  291. va_list ap;
  292. va_start(ap, fmt);
  293. ret = v9fs_iov_vmarshal(in_sg, in_num, offset, bswap, fmt, ap);
  294. va_end(ap);
  295. return ret;
  296. }