1/* 2 Unix SMB/CIFS implementation. 3 client file read/write routines 4 Copyright (C) Andrew Tridgell 1994-1998 5 Copyright (C) James Myers 2003 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. 19*/ 20 21#include "includes.h" 22#include "libcli/raw/libcliraw.h" 23#include "libcli/raw/raw_proto.h" 24#include "libcli/libcli.h" 25 26/**************************************************************************** 27 Read size bytes at offset offset using SMBreadX. 28****************************************************************************/ 29ssize_t smbcli_read(struct smbcli_tree *tree, int fnum, void *_buf, off_t offset, 30 size_t size) 31{ 32 uint8_t *buf = (uint8_t *)_buf; 33 union smb_read parms; 34 int readsize; 35 ssize_t total = 0; 36 37 if (size == 0) { 38 return 0; 39 } 40 41 parms.readx.level = RAW_READ_READX; 42 parms.readx.in.file.fnum = fnum; 43 44 /* 45 * Set readsize to the maximum size we can handle in one readX, 46 * rounded down to a multiple of 1024. 47 */ 48 readsize = (tree->session->transport->negotiate.max_xmit - (MIN_SMB_SIZE+32)); 49 if (readsize > 0xFFFF) readsize = 0xFFFF; 50 51 while (total < size) { 52 NTSTATUS status; 53 54 readsize = MIN(readsize, size-total); 55 56 parms.readx.in.offset = offset; 57 parms.readx.in.mincnt = readsize; 58 parms.readx.in.maxcnt = readsize; 59 parms.readx.in.remaining = size - total; 60 parms.readx.in.read_for_execute = false; 61 parms.readx.out.data = buf + total; 62 63 status = smb_raw_read(tree, &parms); 64 65 if (!NT_STATUS_IS_OK(status)) { 66 return -1; 67 } 68 69 total += parms.readx.out.nread; 70 offset += parms.readx.out.nread; 71 72 /* If the server returned less than we asked for we're at EOF */ 73 if (parms.readx.out.nread < readsize) 74 break; 75 } 76 77 return total; 78} 79 80 81/**************************************************************************** 82 write to a file 83 write_mode: 0x0001 disallow write cacheing 84 0x0002 return bytes remaining 85 0x0004 use raw named pipe protocol 86 0x0008 start of message mode named pipe protocol 87****************************************************************************/ 88ssize_t smbcli_write(struct smbcli_tree *tree, 89 int fnum, uint16_t write_mode, 90 const void *_buf, off_t offset, size_t size) 91{ 92 const uint8_t *buf = (const uint8_t *)_buf; 93 union smb_write parms; 94 int block = (tree->session->transport->negotiate.max_xmit - (MIN_SMB_SIZE+32)); 95 ssize_t total = 0; 96 97 if (size == 0) { 98 return 0; 99 } 100 101 if (block > 0xFFFF) block = 0xFFFF; 102 103 104 parms.writex.level = RAW_WRITE_WRITEX; 105 parms.writex.in.file.fnum = fnum; 106 parms.writex.in.wmode = write_mode; 107 parms.writex.in.remaining = 0; 108 109 while (total < size) { 110 NTSTATUS status; 111 112 block = MIN(block, size - total); 113 114 parms.writex.in.offset = offset; 115 parms.writex.in.count = block; 116 parms.writex.in.data = buf; 117 118 status = smb_raw_write(tree, &parms); 119 120 if (!NT_STATUS_IS_OK(status)) { 121 return -1; 122 } 123 124 offset += parms.writex.out.nwritten; 125 total += parms.writex.out.nwritten; 126 buf += parms.writex.out.nwritten; 127 } 128 129 return total; 130} 131 132/**************************************************************************** 133 write to a file using a SMBwrite and not bypassing 0 byte writes 134****************************************************************************/ 135ssize_t smbcli_smbwrite(struct smbcli_tree *tree, 136 int fnum, const void *_buf, off_t offset, size_t size1) 137{ 138 const uint8_t *buf = (const uint8_t *)_buf; 139 union smb_write parms; 140 ssize_t total = 0; 141 142 parms.write.level = RAW_WRITE_WRITE; 143 parms.write.in.remaining = 0; 144 145 do { 146 size_t size = MIN(size1, tree->session->transport->negotiate.max_xmit - 48); 147 if (size > 0xFFFF) size = 0xFFFF; 148 149 parms.write.in.file.fnum = fnum; 150 parms.write.in.offset = offset; 151 parms.write.in.count = size; 152 parms.write.in.data = buf + total; 153 154 if (NT_STATUS_IS_ERR(smb_raw_write(tree, &parms))) 155 return -1; 156 157 size = parms.write.out.nwritten; 158 if (size == 0) 159 break; 160 161 size1 -= size; 162 total += size; 163 offset += size; 164 } while (size1); 165 166 return total; 167} 168