1 #include "headers.h" 2 3 #define INMEMORYTRUNCTHRESH (256 * 1024) 4 5 static int 6 dirfwstatlength(int fd, vlong offset) 7 { 8 Dir d; 9 memset(&d, 0xff, sizeof(d)); 10 d.name = d.uid = d.gid = d.muid = nil; 11 d.length = offset; 12 return dirfwstat(fd, &d); 13 } 14 15 SmbProcessResult 16 smbtruncatefile(SmbSession *s, SmbFile *f, vlong offset) 17 { 18 Dir *d; 19 ulong o; 20 uchar *db = nil; 21 vlong length; 22 int rv; 23 SmbProcessResult pr; 24 25 d = dirfstat(f->fd); 26 assert(d); 27 length = d->length; 28 free(d); 29 30 if (length == offset) 31 return SmbProcessResultReply; 32 33 rv = dirfwstatlength(f->fd, offset); 34 if (rv == 0) { 35 pr = SmbProcessResultReply; 36 goto done; 37 } 38 //smblogprint(-1, "dirfwstatlength failed: %r\n"); 39 if (length > offset) { 40 int nfd; 41 char *fullpath; 42 if (offset > INMEMORYTRUNCTHRESH) { 43 smblogprint(-1, "smbcomwrite: truncation beyond %lud not supported\n", offset); 44 pr = SmbProcessResultUnimp; 45 goto done; 46 } 47 db = smbemalloc(offset); 48 if (pread(f->fd, db, offset, 0) != offset) { 49 pr = SmbProcessResultMisc; 50 goto done; 51 } 52 fullpath = nil; 53 smbstringprint(&fullpath, "%s%s", f->t->serv->path, f->name); 54 nfd = open(fullpath, f->p9mode | OTRUNC); 55 free(fullpath); 56 if (nfd < 0) { 57 smbseterror(s, ERRDOS, ERRnoaccess); 58 pr = SmbProcessResultError; 59 goto done; 60 } 61 close(nfd); 62 if (pwrite(f->fd, db, offset, 0) != offset) { 63 pr = SmbProcessResultMisc; 64 goto done; 65 } 66 pr = SmbProcessResultReply; 67 } 68 else { 69 db = smbemalloc(16384); 70 memset(db, 0, 16384); 71 o = length; 72 while (o < offset) { 73 long tt = 16384; 74 if (tt > offset - o) 75 tt = offset - o; 76 if (pwrite(f->fd, db, tt, o) != tt) { 77 smbseterror(s, ERRDOS, ERRnoaccess); 78 pr = SmbProcessResultError; 79 goto done; 80 } 81 o += tt; 82 } 83 pr = SmbProcessResultReply; 84 } 85 done: 86 free(db); 87 return pr; 88 } 89 90 SmbProcessResult 91 smbcomwrite(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b) 92 { 93 SmbTree *t; 94 SmbFile *f; 95 ushort fid; 96 ushort count; 97 ulong offset; 98 long nb; 99 ushort yacount; 100 uchar fmt; 101 102 if (h->wordcount != 5) 103 return SmbProcessResultFormat; 104 105 fid = smbnhgets(pdata); pdata += 2; 106 count = smbnhgets(pdata); pdata += 2; 107 offset = smbnhgetl(pdata); 108 109 smblogprint(SMB_COM_WRITE, "smbcomwrite: fid 0x%.4ux count 0x%.4ux offset 0x%.8lux\n", 110 fid, count, offset); 111 112 if (!smbbuffergetb(b, &fmt) 113 || fmt != 1 114 || !smbbuffergets(b, &yacount) 115 || yacount != count 116 || smbbufferreadspace(b) < count) 117 return SmbProcessResultFormat; 118 119 t = smbidmapfind(s->tidmap, h->tid); 120 if (t == nil) { 121 smbseterror(s, ERRSRV, ERRinvtid); 122 return SmbProcessResultError; 123 } 124 f = smbidmapfind(s->fidmap, fid); 125 if (f == nil) { 126 smbseterror(s, ERRDOS, ERRbadfid); 127 return SmbProcessResultError; 128 } 129 130 if (!f->ioallowed) { 131 smbseterror(s, ERRDOS, ERRbadaccess); 132 return SmbProcessResultError; 133 } 134 135 if (count == 0) { 136 SmbProcessResult pr = smbtruncatefile(s, f, offset); 137 if (pr != SmbProcessResultReply) 138 return pr; 139 nb = 0; 140 } 141 else { 142 seek(f->fd, offset, 0); 143 nb = write(f->fd, smbbufferreadpointer(b), count); 144 if (nb < 0) { 145 smbseterror(s, ERRDOS, ERRnoaccess); 146 return SmbProcessResultError; 147 } 148 } 149 h->wordcount = 1; 150 if (!smbbufferputheader(s->response, h, &s->peerinfo) 151 || !smbbufferputs(s->response, nb) 152 || !smbbufferputs(s->response, 0)) 153 return SmbProcessResultMisc; 154 return SmbProcessResultReply; 155 } 156