smbcomwrite.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "headers.h"
  10. #define INMEMORYTRUNCTHRESH (256 * 1024)
  11. static int
  12. dirfwstatlength(int fd, int64_t offset)
  13. {
  14. Dir d;
  15. memset(&d, 0xff, sizeof(d));
  16. d.name = d.uid = d.gid = d.muid = nil;
  17. d.length = offset;
  18. return dirfwstat(fd, &d);
  19. }
  20. SmbProcessResult
  21. smbtruncatefile(SmbSession *s, SmbFile *f, int64_t offset)
  22. {
  23. Dir *d;
  24. uint32_t o;
  25. uint8_t *db = nil;
  26. int64_t length;
  27. int rv;
  28. SmbProcessResult pr;
  29. d = dirfstat(f->fd);
  30. assert(d);
  31. length = d->length;
  32. free(d);
  33. if (length == offset)
  34. return SmbProcessResultReply;
  35. rv = dirfwstatlength(f->fd, offset);
  36. if (rv == 0) {
  37. pr = SmbProcessResultReply;
  38. goto done;
  39. }
  40. //smblogprint(-1, "dirfwstatlength failed: %r\n");
  41. if (length > offset) {
  42. int nfd;
  43. char *fullpath;
  44. if (offset > INMEMORYTRUNCTHRESH) {
  45. smblogprint(-1, "smbcomwrite: truncation beyond %lu not supported\n", offset);
  46. pr = SmbProcessResultUnimp;
  47. goto done;
  48. }
  49. db = smbemalloc(offset);
  50. if (pread(f->fd, db, offset, 0) != offset) {
  51. pr = SmbProcessResultMisc;
  52. goto done;
  53. }
  54. fullpath = nil;
  55. smbstringprint(&fullpath, "%s%s", f->t->serv->path, f->name);
  56. nfd = open(fullpath, f->p9mode | OTRUNC);
  57. free(fullpath);
  58. if (nfd < 0) {
  59. smbseterror(s, ERRDOS, ERRnoaccess);
  60. pr = SmbProcessResultError;
  61. goto done;
  62. }
  63. close(nfd);
  64. if (pwrite(f->fd, db, offset, 0) != offset) {
  65. pr = SmbProcessResultMisc;
  66. goto done;
  67. }
  68. pr = SmbProcessResultReply;
  69. }
  70. else {
  71. db = smbemalloc(16384);
  72. memset(db, 0, 16384);
  73. o = length;
  74. while (o < offset) {
  75. int32_t tt = 16384;
  76. if (tt > offset - o)
  77. tt = offset - o;
  78. if (pwrite(f->fd, db, tt, o) != tt) {
  79. smbseterror(s, ERRDOS, ERRnoaccess);
  80. pr = SmbProcessResultError;
  81. goto done;
  82. }
  83. o += tt;
  84. }
  85. pr = SmbProcessResultReply;
  86. }
  87. done:
  88. free(db);
  89. return pr;
  90. }
  91. SmbProcessResult
  92. smbcomwrite(SmbSession *s, SmbHeader *h, uint8_t *pdata, SmbBuffer *b)
  93. {
  94. SmbTree *t;
  95. SmbFile *f;
  96. uint16_t fid;
  97. uint16_t count;
  98. uint32_t offset;
  99. int32_t nb;
  100. uint16_t yacount;
  101. uint8_t fmt;
  102. if (h->wordcount != 5)
  103. return SmbProcessResultFormat;
  104. fid = smbnhgets(pdata); pdata += 2;
  105. count = smbnhgets(pdata); pdata += 2;
  106. offset = smbnhgetl(pdata);
  107. smblogprint(SMB_COM_WRITE, "smbcomwrite: fid 0x%.4x count 0x%.4x offset 0x%.8lux\n",
  108. fid, count, offset);
  109. if (!smbbuffergetb(b, &fmt)
  110. || fmt != 1
  111. || !smbbuffergets(b, &yacount)
  112. || yacount != count
  113. || smbbufferreadspace(b) < count)
  114. return SmbProcessResultFormat;
  115. t = smbidmapfind(s->tidmap, h->tid);
  116. if (t == nil) {
  117. smbseterror(s, ERRSRV, ERRinvtid);
  118. return SmbProcessResultError;
  119. }
  120. f = smbidmapfind(s->fidmap, fid);
  121. if (f == nil) {
  122. smbseterror(s, ERRDOS, ERRbadfid);
  123. return SmbProcessResultError;
  124. }
  125. if (!f->ioallowed) {
  126. smbseterror(s, ERRDOS, ERRbadaccess);
  127. return SmbProcessResultError;
  128. }
  129. if (count == 0) {
  130. SmbProcessResult pr = smbtruncatefile(s, f, offset);
  131. if (pr != SmbProcessResultReply)
  132. return pr;
  133. nb = 0;
  134. }
  135. else {
  136. seek(f->fd, offset, 0);
  137. nb = write(f->fd, smbbufferreadpointer(b), count);
  138. if (nb < 0) {
  139. smbseterror(s, ERRDOS, ERRnoaccess);
  140. return SmbProcessResultError;
  141. }
  142. }
  143. h->wordcount = 1;
  144. if (!smbbufferputheader(s->response, h, &s->peerinfo)
  145. || !smbbufferputs(s->response, nb)
  146. || !smbbufferputs(s->response, 0))
  147. return SmbProcessResultMisc;
  148. return SmbProcessResultReply;
  149. }
  150. SmbProcessResult
  151. smbcomwriteandx(SmbSession *s, SmbHeader *h, uint8_t *pdata, SmbBuffer *b)
  152. {
  153. uint8_t andxcommand;
  154. uint16_t andxoffset;
  155. uint32_t andxoffsetfixup;
  156. SmbTree *t;
  157. SmbFile *f;
  158. uint16_t dataoff, fid, count;
  159. int64_t offset;
  160. int32_t nb;
  161. if (h->wordcount != 12 && h->wordcount != 14)
  162. return SmbProcessResultFormat;
  163. andxcommand = *pdata++; // andx command
  164. pdata++; // reserved
  165. andxoffset = smbnhgets(pdata); pdata += 2; // andx offset
  166. fid = smbnhgets(pdata); pdata += 2; // fid
  167. offset = smbnhgetl(pdata); pdata += 4; // offset in file
  168. pdata += 4; // timeout
  169. pdata += 2; // write mode
  170. pdata += 2; // (Remaining) bytes waiting to be written
  171. pdata += 2; // Reserved
  172. count = smbnhgets(pdata); pdata += 2; // LSBs of length
  173. dataoff = smbnhgets(pdata); pdata += 2; // offset to data in packet
  174. if (dataoff + count > smbbufferwriteoffset(b))
  175. return SmbProcessResultFormat;
  176. if(h->wordcount == 14)
  177. offset |= (int64_t)smbnhgetl(pdata)<<32;
  178. smblogprint(SMB_COM_WRITE_ANDX, "smbcomwriteandx: fid 0x%.4x count 0x%.4x offset 0x%.llux\n",
  179. fid, count, offset);
  180. t = smbidmapfind(s->tidmap, h->tid);
  181. if (t == nil) {
  182. smbseterror(s, ERRSRV, ERRinvtid);
  183. return SmbProcessResultError;
  184. }
  185. f = smbidmapfind(s->fidmap, fid);
  186. if (f == nil) {
  187. smbseterror(s, ERRDOS, ERRbadfid);
  188. return SmbProcessResultError;
  189. }
  190. if (!f->ioallowed) {
  191. smbseterror(s, ERRDOS, ERRbadaccess);
  192. return SmbProcessResultError;
  193. }
  194. seek(f->fd, offset, 0);
  195. nb = write(f->fd, smbbufferpointer(b, dataoff), count);
  196. if (nb < 0) {
  197. smbseterror(s, ERRDOS, ERRnoaccess);
  198. return SmbProcessResultError;
  199. }
  200. h->wordcount = 6;
  201. if (!smbbufferputandxheader(s->response, h, &s->peerinfo, andxcommand, &andxoffsetfixup))
  202. return SmbProcessResultMisc;
  203. if (!smbbufferputs(s->response, nb) // Count
  204. || !smbbufferputs(s->response, 0) // Available
  205. || !smbbufferputl(s->response, 0) // Reserved
  206. || !smbbufferputs(s->response, 0)) // byte count in reply
  207. return SmbProcessResultMisc;
  208. if (andxcommand != SMB_COM_NO_ANDX_COMMAND)
  209. return smbchaincommand(s, h, andxoffsetfixup, andxcommand, andxoffset, b);
  210. return SmbProcessResultReply;
  211. }