001: /* jcifs smb client library in Java
002: * Copyright (C) 2000 "Michael B. Allen" <jcifs at samba dot org>
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018:
019: package jcifs.smb;
020:
021: import java.net.URL;
022: import java.net.UnknownHostException;
023: import java.net.MalformedURLException;
024: import java.io.InputStream;
025: import java.io.IOException;
026:
027: /**
028: * This InputStream can read bytes from a file on an SMB file server. Offsets are 64 bits.
029: */
030:
031: public class SmbFileInputStream extends InputStream {
032:
033: private long fp;
034: private int readSize, openFlags;
035: private byte[] tmp = new byte[1];
036:
037: SmbFile file;
038:
039: /**
040: * Creates an {@link java.io.InputStream} for reading bytes from a file on
041: * an SMB server addressed by the <code>url</code> parameter. See {@link
042: * jcifs.smb.SmbFile} for a detailed description and examples of the smb
043: * URL syntax.
044: *
045: * @param url An smb URL string representing the file to read from
046: */
047:
048: public SmbFileInputStream(String url) throws SmbException,
049: MalformedURLException, UnknownHostException {
050: this (new SmbFile(url));
051: }
052:
053: /**
054: * Creates an {@link java.io.InputStream} for reading bytes from a file on
055: * an SMB server represented by the {@link jcifs.smb.SmbFile} parameter. See
056: * {@link jcifs.smb.SmbFile} for a detailed description and examples of
057: * the smb URL syntax.
058: *
059: * @param file An <code>SmbFile</code> specifying the file to read from
060: */
061:
062: public SmbFileInputStream(SmbFile file) throws SmbException,
063: MalformedURLException, UnknownHostException {
064: this (file, SmbFile.O_RDONLY);
065: }
066:
067: SmbFileInputStream(SmbFile file, int openFlags)
068: throws SmbException, MalformedURLException,
069: UnknownHostException {
070: this .file = file;
071: this .openFlags = openFlags;
072: file.open(openFlags, SmbFile.ATTR_NORMAL, 0);
073: readSize = Math.min(
074: file.tree.session.transport.rcv_buf_size - 70,
075: file.tree.session.transport.server.maxBufferSize - 70);
076: }
077:
078: /**
079: * Closes this input stream and releases any system resources associated with the stream.
080: *
081: * @throws IOException if a network error occurs
082: */
083:
084: public void close() throws IOException {
085: file.close();
086: tmp = null;
087: }
088:
089: /**
090: * Reads a byte of data from this input stream.
091: *
092: * @throws IOException if a network error occurs
093: */
094:
095: public int read() throws IOException {
096: // need oplocks to cache otherwise use BufferedInputStream
097: if (read(tmp, 0, 1) == -1) {
098: return -1;
099: }
100: return tmp[0] & 0xFF;
101: }
102:
103: /**
104: * Reads up to b.length bytes of data from this input stream into an array of bytes.
105: *
106: * @throws IOException if a network error occurs
107: */
108:
109: public int read(byte[] b) throws IOException {
110: return read(b, 0, b.length);
111: }
112:
113: /**
114: * Reads up to len bytes of data from this input stream into an array of bytes.
115: *
116: * @throws IOException if a network error occurs
117: */
118:
119: public int read(byte[] b, int off, int len) throws IOException {
120: if (len <= 0) {
121: return 0;
122: }
123: long start = fp;
124:
125: if (tmp == null) {
126: throw new IOException("Bad file descriptor");
127: }
128: // ensure file is open
129: file.open(openFlags, SmbFile.ATTR_NORMAL, 0);
130:
131: /*
132: * Read AndX Request / Response
133: */
134:
135: if (file.log.level > 2)
136: file.log.println("read: fid=" + file.fid + ",off=" + off
137: + ",len=" + len);
138:
139: SmbComReadAndXResponse response = new SmbComReadAndXResponse(b,
140: off);
141:
142: if (file.type == SmbFile.TYPE_NAMED_PIPE) {
143: response.responseTimeout = 0;
144: }
145:
146: int r, n;
147: do {
148: r = len > readSize ? readSize : len;
149:
150: if (file.log.level > 2)
151: file.log.println("read: len=" + len + ",r=" + r
152: + ",fp=" + fp);
153:
154: try {
155: file.send(new SmbComReadAndX(file.fid, fp, r, null),
156: response);
157: } catch (SmbException se) {
158: if (file.type == SmbFile.TYPE_NAMED_PIPE
159: && se.getNtStatus() == NtStatus.NT_STATUS_PIPE_BROKEN) {
160: return -1;
161: }
162: throw se;
163: }
164: if ((n = response.dataLength) <= 0) {
165: return (int) ((fp - start) > 0L ? fp - start : -1);
166: }
167: fp += n;
168: len -= n;
169: response.off += n;
170: } while (len > 0 && n == r);
171:
172: return (int) (fp - start);
173: }
174:
175: /**
176: * This stream class is unbuffered. Therefore this method will always
177: * return 0 for streams connected to regular files. However, a
178: * stream created from a Named Pipe this method will query the server using a
179: * "peek named pipe" operation and return the number of available bytes
180: * on the server.
181: */
182: public int available() throws IOException {
183: SmbNamedPipe pipe;
184: TransPeekNamedPipe req;
185: TransPeekNamedPipeResponse resp;
186:
187: if (file.type != SmbFile.TYPE_NAMED_PIPE) {
188: return 0;
189: }
190:
191: pipe = (SmbNamedPipe) file;
192: file.open((pipe.pipeType & 0xFF0000) | SmbFile.O_EXCL,
193: SmbFile.ATTR_NORMAL, 0);
194:
195: req = new TransPeekNamedPipe(file.unc, file.fid);
196: resp = new TransPeekNamedPipeResponse(pipe);
197:
198: pipe.sendTransaction(req, resp);
199: if (resp.status == TransPeekNamedPipeResponse.STATUS_DISCONNECTED
200: || resp.status == TransPeekNamedPipeResponse.STATUS_SERVER_END_CLOSED) {
201: file.opened = false;
202: return 0;
203: }
204: return resp.available;
205: }
206:
207: /**
208: * Skip n bytes of data on this stream. This operation will not result
209: * in any IO with the server. Unlink <tt>InputStream</tt> value less than
210: * the one provided will not be returned if it exceeds the end of the file
211: * (if this is a problem let us know).
212: */
213: public long skip(long n) throws IOException {
214: if (n > 0) {
215: fp += n;
216: return n;
217: }
218: return 0;
219: }
220: }
|