smbcomwrite.c 5.5 KB

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