jcifs.smb.SmbRandomAccessFile Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jcifs-ng Show documentation
Show all versions of jcifs-ng Show documentation
A pure-java CIFS/SMB client library
/* jcifs smb client library in Java
* Copyright (C) 2003 "Michael B. Allen"
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcifs.smb;
import java.io.IOException;
import java.net.MalformedURLException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jcifs.CIFSContext;
import jcifs.CIFSException;
import jcifs.SmbConstants;
import jcifs.SmbFileHandle;
import jcifs.SmbRandomAccess;
import jcifs.internal.fscc.FileEndOfFileInformation;
import jcifs.internal.smb1.com.SmbComReadAndX;
import jcifs.internal.smb1.com.SmbComReadAndXResponse;
import jcifs.internal.smb1.com.SmbComWrite;
import jcifs.internal.smb1.com.SmbComWriteAndX;
import jcifs.internal.smb1.com.SmbComWriteAndXResponse;
import jcifs.internal.smb1.com.SmbComWriteResponse;
import jcifs.internal.smb1.trans2.Trans2SetFileInformation;
import jcifs.internal.smb1.trans2.Trans2SetFileInformationResponse;
import jcifs.internal.smb2.info.Smb2SetInfoRequest;
import jcifs.internal.smb2.io.Smb2ReadRequest;
import jcifs.internal.smb2.io.Smb2ReadResponse;
import jcifs.internal.smb2.io.Smb2WriteRequest;
import jcifs.internal.smb2.io.Smb2WriteResponse;
import jcifs.util.Encdec;
/**
*
*
*
*/
public class SmbRandomAccessFile implements SmbRandomAccess {
private static final Logger log = LoggerFactory.getLogger(SmbRandomAccessFile.class);
private static final int WRITE_OPTIONS = 0x0842;
private SmbFile file;
private long fp;
private int openFlags, access = 0, readSize, writeSize, options = 0;
private byte[] tmp = new byte[8];
private SmbComWriteAndXResponse write_andx_resp = null;
private boolean largeReadX;
private final boolean unsharedFile;
private SmbFileHandleImpl handle;
private int sharing;
/**
* Instantiate a random access file from URL
*
* @param url
* @param mode
* @param sharing
* @param tc
* @throws SmbException
* @throws MalformedURLException
*/
@SuppressWarnings ( "resource" )
public SmbRandomAccessFile ( String url, String mode, int sharing, CIFSContext tc ) throws SmbException, MalformedURLException {
this(new SmbFile(url, tc), mode, sharing, true);
}
/**
* Instantiate a random access file from a {@link SmbFile}
*
* @param file
* @param mode
* @throws SmbException
*/
public SmbRandomAccessFile ( SmbFile file, String mode ) throws SmbException {
this(file, mode, SmbConstants.DEFAULT_SHARING, false);
}
/**
* Instantiate a random access file from a {@link SmbFile}
*
* @param file
* @param mode
* @throws SmbException
*/
SmbRandomAccessFile ( SmbFile file, String mode, int sharing, boolean unsharedFile ) throws SmbException {
this.file = file;
this.sharing = sharing;
this.unsharedFile = unsharedFile;
try ( SmbTreeHandleInternal th = this.file.ensureTreeConnected() ) {
if ( mode.equals("r") ) {
this.openFlags = SmbConstants.O_CREAT | SmbConstants.O_RDONLY;
this.access = SmbConstants.FILE_READ_DATA;
}
else if ( mode.equals("rw") ) {
this.openFlags = SmbConstants.O_CREAT | SmbConstants.O_RDWR | SmbConstants.O_APPEND;
this.write_andx_resp = new SmbComWriteAndXResponse(th.getConfig());
this.options = WRITE_OPTIONS;
this.access = SmbConstants.FILE_READ_DATA | SmbConstants.FILE_WRITE_DATA;
}
else {
throw new IllegalArgumentException("Invalid mode");
}
try ( SmbFileHandle h = ensureOpen() ) {}
this.readSize = th.getReceiveBufferSize() - 70;
this.writeSize = th.getSendBufferSize() - 70;
if ( th.hasCapability(SmbConstants.CAP_LARGE_READX) ) {
this.largeReadX = true;
this.readSize = Math.min(th.getConfig().getReceiveBufferSize() - 70, th.areSignaturesActive() ? 0xFFFF - 70 : 0xFFFFFF - 70);
}
// there seems to be a bug with some servers that causes corruption if using signatures + CAP_LARGE_WRITE
if ( th.hasCapability(SmbConstants.CAP_LARGE_WRITEX) && !th.areSignaturesActive() ) {
this.writeSize = Math.min(th.getConfig().getSendBufferSize() - 70, 0xFFFF - 70);
}
this.fp = 0L;
}
catch ( CIFSException e ) {
throw SmbException.wrap(e);
}
}
/**
* @return
* @throws SmbException
*/
synchronized SmbFileHandleImpl ensureOpen () throws CIFSException {
// ensure file is open
if ( this.handle == null || !this.handle.isValid() ) {
// one extra acquire to keep this open till the stream is released
this.handle = this.file.openUnshared(this.openFlags, this.access, this.sharing, SmbConstants.ATTR_NORMAL, this.options).acquire();
return this.handle;
}
return this.handle.acquire();
}
/**
* Ensures that the file descriptor is openend
*
* @throws CIFSException
*/
public void open () throws CIFSException {
try ( SmbFileHandleImpl fh = ensureOpen() ) {}
}
@Override
public synchronized void close () throws SmbException {
try {
if ( this.handle != null ) {
try {
this.handle.close();
}
catch ( CIFSException e ) {
throw SmbException.wrap(e);
}
this.handle = null;
}
}
finally {
this.file.clearAttributeCache();
if ( this.unsharedFile ) {
this.file.close();
}
}
}
@Override
public int read () throws SmbException {
if ( read(this.tmp, 0, 1) == -1 ) {
return -1;
}
return this.tmp[ 0 ] & 0xFF;
}
@Override
public int read ( byte b[] ) throws SmbException {
return read(b, 0, b.length);
}
@Override
public int read ( byte b[], int off, int len ) throws SmbException {
if ( len <= 0 ) {
return 0;
}
long start = this.fp;
try ( SmbFileHandleImpl fh = ensureOpen();
SmbTreeHandleImpl th = fh.getTree() ) {
int r, n;
SmbComReadAndXResponse response = new SmbComReadAndXResponse(th.getConfig(), b, off);
do {
r = len > this.readSize ? this.readSize : len;
if ( th.isSMB2() ) {
Smb2ReadRequest request = new Smb2ReadRequest(th.getConfig(), fh.getFileId(), b, off);
request.setOffset(this.fp);
request.setReadLength(r);
request.setRemainingBytes(len - off);
try {
Smb2ReadResponse resp = th.send(request, RequestParam.NO_RETRY);
n = resp.getDataLength();
}
catch ( SmbException e ) {
if ( e.getNtStatus() == 0xC0000011 ) {
log.debug("Reached end of file", e);
n = -1;
}
else {
throw e;
}
}
}
else {
SmbComReadAndX request = new SmbComReadAndX(th.getConfig(), fh.getFid(), this.fp, r, null);
if ( this.largeReadX ) {
request.setMaxCount(r & 0xFFFF);
request.setOpenTimeout( ( r >> 16 ) & 0xFFFF);
}
try {
th.send(request, response, RequestParam.NO_RETRY);
n = response.getDataLength();
}
catch ( CIFSException e ) {
throw SmbException.wrap(e);
}
}
if ( n <= 0 ) {
return (int) ( ( this.fp - start ) > 0L ? this.fp - start : -1 );
}
this.fp += n;
len -= n;
off += n;
response.adjustOffset(n);
}
while ( len > 0 && n == r );
return (int) ( this.fp - start );
}
catch ( CIFSException e ) {
throw SmbException.wrap(e);
}
}
@Override
public final void readFully ( byte b[] ) throws SmbException {
readFully(b, 0, b.length);
}
@Override
public final void readFully ( byte b[], int off, int len ) throws SmbException {
int n = 0, count;
do {
count = this.read(b, off + n, len - n);
if ( count < 0 )
throw new SmbEndOfFileException();
n += count;
}
while ( n < len );
}
@Override
public int skipBytes ( int n ) throws SmbException {
if ( n > 0 ) {
this.fp += n;
return n;
}
return 0;
}
@Override
public void write ( int b ) throws SmbException {
this.tmp[ 0 ] = (byte) b;
write(this.tmp, 0, 1);
}
@Override
public void write ( byte b[] ) throws SmbException {
write(b, 0, b.length);
}
@Override
public void write ( byte b[], int off, int len ) throws SmbException {
if ( len <= 0 ) {
return;
}
// ensure file is open
try ( SmbFileHandleImpl fh = ensureOpen();
SmbTreeHandleImpl th = fh.getTree() ) {
int w;
do {
w = len > this.writeSize ? this.writeSize : len;
long cnt;
if ( th.isSMB2() ) {
Smb2WriteRequest request = new Smb2WriteRequest(th.getConfig(), fh.getFileId());
request.setOffset(this.fp);
request.setRemainingBytes(len - w - off);
request.setData(b, off, w);
Smb2WriteResponse resp = th.send(request, RequestParam.NO_RETRY);
cnt = resp.getCount();
}
else {
SmbComWriteAndX request = new SmbComWriteAndX(th.getConfig(), fh.getFid(), this.fp, len - w - off, b, off, w, null);
th.send(request, this.write_andx_resp, RequestParam.NO_RETRY);
cnt = this.write_andx_resp.getCount();
}
this.fp += cnt;
len -= cnt;
off += cnt;
}
while ( len > 0 );
}
catch ( CIFSException e ) {
throw SmbException.wrap(e);
}
}
@Override
public long getFilePointer () {
return this.fp;
}
@Override
public void seek ( long pos ) {
this.fp = pos;
}
@Override
public long length () throws SmbException {
return this.file.length();
}
@Override
public void setLength ( long newLength ) throws SmbException {
try ( SmbFileHandleImpl fh = ensureOpen();
SmbTreeHandleImpl th = fh.getTree() ) {
if ( th.isSMB2() ) {
Smb2SetInfoRequest req = new Smb2SetInfoRequest(th.getConfig(), fh.getFileId());
req.setFileInformation(new FileEndOfFileInformation(newLength));
th.send(req, RequestParam.NO_RETRY);
}
else if ( th.hasCapability(SmbConstants.CAP_NT_SMBS) ) {
th.send(
new Trans2SetFileInformation(th.getConfig(), fh.getFid(), new FileEndOfFileInformation(newLength)),
new Trans2SetFileInformationResponse(th.getConfig()),
RequestParam.NO_RETRY);
}
else {
// this is the original, COM_WRITE allows truncation but no 64 bit offsets
SmbComWriteResponse rsp = new SmbComWriteResponse(th.getConfig());
th.send(
new SmbComWrite(th.getConfig(), fh.getFid(), (int) ( newLength & 0xFFFFFFFFL ), 0, this.tmp, 0, 0),
rsp,
RequestParam.NO_RETRY);
}
}
catch ( CIFSException e ) {
throw SmbException.wrap(e);
}
}
@Override
public final boolean readBoolean () throws SmbException {
if ( ( read(this.tmp, 0, 1) ) < 0 ) {
throw new SmbEndOfFileException();
}
return this.tmp[ 0 ] != (byte) 0x00;
}
@Override
public final byte readByte () throws SmbException {
if ( ( read(this.tmp, 0, 1) ) < 0 ) {
throw new SmbEndOfFileException();
}
return this.tmp[ 0 ];
}
@Override
public final int readUnsignedByte () throws SmbException {
if ( ( read(this.tmp, 0, 1) ) < 0 ) {
throw new SmbEndOfFileException();
}
return this.tmp[ 0 ] & 0xFF;
}
@Override
public final short readShort () throws SmbException {
if ( ( read(this.tmp, 0, 2) ) < 0 ) {
throw new SmbEndOfFileException();
}
return Encdec.dec_uint16be(this.tmp, 0);
}
@Override
public final int readUnsignedShort () throws SmbException {
if ( ( read(this.tmp, 0, 2) ) < 0 ) {
throw new SmbEndOfFileException();
}
return Encdec.dec_uint16be(this.tmp, 0) & 0xFFFF;
}
@Override
public final char readChar () throws SmbException {
if ( ( read(this.tmp, 0, 2) ) < 0 ) {
throw new SmbEndOfFileException();
}
return (char) Encdec.dec_uint16be(this.tmp, 0);
}
@Override
public final int readInt () throws SmbException {
if ( ( read(this.tmp, 0, 4) ) < 0 ) {
throw new SmbEndOfFileException();
}
return Encdec.dec_uint32be(this.tmp, 0);
}
@Override
public final long readLong () throws SmbException {
if ( ( read(this.tmp, 0, 8) ) < 0 ) {
throw new SmbEndOfFileException();
}
return Encdec.dec_uint64be(this.tmp, 0);
}
@Override
public final float readFloat () throws SmbException {
if ( ( read(this.tmp, 0, 4) ) < 0 ) {
throw new SmbEndOfFileException();
}
return Encdec.dec_floatbe(this.tmp, 0);
}
@Override
public final double readDouble () throws SmbException {
if ( ( read(this.tmp, 0, 8) ) < 0 ) {
throw new SmbEndOfFileException();
}
return Encdec.dec_doublebe(this.tmp, 0);
}
@Override
public final String readLine () throws SmbException {
StringBuffer input = new StringBuffer();
int c = -1;
boolean eol = false;
while ( !eol ) {
switch ( c = read() ) {
case -1:
case '\n':
eol = true;
break;
case '\r':
eol = true;
long cur = this.fp;
if ( read() != '\n' ) {
this.fp = cur;
}
break;
default:
input.append((char) c);
break;
}
}
if ( ( c == -1 ) && ( input.length() == 0 ) ) {
return null;
}
return input.toString();
}
@Override
public final String readUTF () throws SmbException {
int size = readUnsignedShort();
byte[] b = new byte[size];
read(b, 0, size);
try {
return Encdec.dec_utf8(b, 0, size);
}
catch ( IOException ioe ) {
throw new SmbException("", ioe);
}
}
@Override
public final void writeBoolean ( boolean v ) throws SmbException {
this.tmp[ 0 ] = (byte) ( v ? 1 : 0 );
write(this.tmp, 0, 1);
}
@Override
public final void writeByte ( int v ) throws SmbException {
this.tmp[ 0 ] = (byte) v;
write(this.tmp, 0, 1);
}
@Override
public final void writeShort ( int v ) throws SmbException {
Encdec.enc_uint16be((short) v, this.tmp, 0);
write(this.tmp, 0, 2);
}
@Override
public final void writeChar ( int v ) throws SmbException {
Encdec.enc_uint16be((short) v, this.tmp, 0);
write(this.tmp, 0, 2);
}
@Override
public final void writeInt ( int v ) throws SmbException {
Encdec.enc_uint32be(v, this.tmp, 0);
write(this.tmp, 0, 4);
}
@Override
public final void writeLong ( long v ) throws SmbException {
Encdec.enc_uint64be(v, this.tmp, 0);
write(this.tmp, 0, 8);
}
@Override
public final void writeFloat ( float v ) throws SmbException {
Encdec.enc_floatbe(v, this.tmp, 0);
write(this.tmp, 0, 4);
}
@Override
public final void writeDouble ( double v ) throws SmbException {
Encdec.enc_doublebe(v, this.tmp, 0);
write(this.tmp, 0, 8);
}
@Override
public final void writeBytes ( String s ) throws SmbException {
byte[] b = s.getBytes();
write(b, 0, b.length);
}
@Override
public final void writeChars ( String s ) throws SmbException {
int clen = s.length();
int blen = 2 * clen;
byte[] b = new byte[blen];
char[] c = new char[clen];
s.getChars(0, clen, c, 0);
for ( int i = 0, j = 0; i < clen; i++ ) {
b[ j++ ] = (byte) ( c[ i ] >>> 8 );
b[ j++ ] = (byte) ( c[ i ] >>> 0 );
}
write(b, 0, blen);
}
@Override
public final void writeUTF ( String str ) throws SmbException {
int len = str.length();
int ch, size = 0;
byte[] dst;
for ( int i = 0; i < len; i++ ) {
ch = str.charAt(i);
size += ch > 0x07F ? ( ch > 0x7FF ? 3 : 2 ) : 1;
}
dst = new byte[size];
writeShort(size);
Encdec.enc_utf8(str, dst, 0, size);
write(dst, 0, size);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy