Skip to content

Commit 83fd2a1

Browse files
committed
Fix #329: Don't create empty RAF files on reading
When trying to read from a non-existing file, the FileHandle created a RandomAccessFile, which resulted in an empty file appearing on disk.
1 parent b5ad01a commit 83fd2a1

File tree

1 file changed

+75
-41
lines changed

1 file changed

+75
-41
lines changed

src/main/java/org/scijava/io/handle/FileHandle.java

Lines changed: 75 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public class FileHandle extends AbstractDataHandle<FileLocation> {
6262

6363
/** Gets the random access file object backing this FileHandle. */
6464
public RandomAccessFile getRandomAccessFile() throws IOException {
65-
return raf();
65+
return writer();
6666
}
6767

6868
public String getMode() {
@@ -101,199 +101,199 @@ public Date lastModified() {
101101

102102
@Override
103103
public long offset() throws IOException {
104-
return raf().getFilePointer();
104+
return exists() ? writer().getFilePointer() : 0;
105105
}
106106

107107
@Override
108108
public long length() throws IOException {
109-
return exists() ? raf().length() : -1;
109+
return exists() ? reader().length() : -1;
110110
}
111111

112112
@Override
113113
public void setLength(final long length) throws IOException {
114-
raf().setLength(length);
114+
writer().setLength(length);
115115
}
116116

117117
@Override
118118
public int read() throws IOException {
119-
return raf().read();
119+
return reader().read();
120120
}
121121

122122
@Override
123123
public int read(final byte[] b) throws IOException {
124-
return raf().read(b);
124+
return reader().read(b);
125125
}
126126

127127
@Override
128128
public int read(final byte[] b, final int off, final int len)
129129
throws IOException
130130
{
131-
return raf().read(b, off, len);
131+
return reader().read(b, off, len);
132132
}
133133

134134
@Override
135135
public void seek(final long pos) throws IOException {
136-
raf().seek(pos);
136+
reader().seek(pos);
137137
}
138138

139139
// -- DataInput methods --
140140

141141
@Override
142142
public boolean readBoolean() throws IOException {
143-
return raf().readBoolean();
143+
return reader().readBoolean();
144144
}
145145

146146
@Override
147147
public byte readByte() throws IOException {
148-
return raf().readByte();
148+
return reader().readByte();
149149
}
150150

151151
@Override
152152
public char readChar() throws IOException {
153-
return raf().readChar();
153+
return reader().readChar();
154154
}
155155

156156
@Override
157157
public double readDouble() throws IOException {
158-
return raf().readDouble();
158+
return reader().readDouble();
159159
}
160160

161161
@Override
162162
public float readFloat() throws IOException {
163-
return raf().readFloat();
163+
return reader().readFloat();
164164
}
165165

166166
@Override
167167
public void readFully(final byte[] b) throws IOException {
168-
raf().readFully(b);
168+
reader().readFully(b);
169169
}
170170

171171
@Override
172172
public void readFully(final byte[] b, final int off, final int len)
173173
throws IOException
174174
{
175-
raf().readFully(b, off, len);
175+
reader().readFully(b, off, len);
176176
}
177177

178178
@Override
179179
public int readInt() throws IOException {
180-
return raf().readInt();
180+
return reader().readInt();
181181
}
182182

183183
@Override
184184
public String readLine() throws IOException {
185-
return raf().readLine();
185+
return reader().readLine();
186186
}
187187

188188
@Override
189189
public long readLong() throws IOException {
190-
return raf().readLong();
190+
return reader().readLong();
191191
}
192192

193193
@Override
194194
public short readShort() throws IOException {
195-
return raf().readShort();
195+
return reader().readShort();
196196
}
197197

198198
@Override
199199
public int readUnsignedByte() throws IOException {
200-
return raf().readUnsignedByte();
200+
return reader().readUnsignedByte();
201201
}
202202

203203
@Override
204204
public int readUnsignedShort() throws IOException {
205-
return raf().readUnsignedShort();
205+
return reader().readUnsignedShort();
206206
}
207207

208208
@Override
209209
public String readUTF() throws IOException {
210-
return raf().readUTF();
210+
return reader().readUTF();
211211
}
212212

213213
@Override
214214
public int skipBytes(final int n) throws IOException {
215-
return raf().skipBytes(n);
215+
return reader().skipBytes(n);
216216
}
217217

218218
// -- DataOutput methods --
219219

220220
@Override
221221
public void write(final byte[] b) throws IOException {
222-
raf().write(b);
222+
writer().write(b);
223223
}
224224

225225
@Override
226226
public void write(final byte[] b, final int off, final int len)
227227
throws IOException
228228
{
229-
raf().write(b, off, len);
229+
writer().write(b, off, len);
230230
}
231231

232232
@Override
233233
public void write(final int b) throws IOException {
234-
raf().write(b);
234+
writer().write(b);
235235
}
236236

237237
@Override
238238
public void writeBoolean(final boolean v) throws IOException {
239-
raf().writeBoolean(v);
239+
writer().writeBoolean(v);
240240
}
241241

242242
@Override
243243
public void writeByte(final int v) throws IOException {
244-
raf().writeByte(v);
244+
writer().writeByte(v);
245245
}
246246

247247
@Override
248248
public void writeBytes(final String s) throws IOException {
249-
raf().writeBytes(s);
249+
writer().writeBytes(s);
250250
}
251251

252252
@Override
253253
public void writeChar(final int v) throws IOException {
254-
raf().writeChar(v);
254+
writer().writeChar(v);
255255
}
256256

257257
@Override
258258
public void writeChars(final String s) throws IOException {
259-
raf().writeChars(s);
259+
writer().writeChars(s);
260260
}
261261

262262
@Override
263263
public void writeDouble(final double v) throws IOException {
264-
raf().writeDouble(v);
264+
writer().writeDouble(v);
265265
}
266266

267267
@Override
268268
public void writeFloat(final float v) throws IOException {
269-
raf().writeFloat(v);
269+
writer().writeFloat(v);
270270
}
271271

272272
@Override
273273
public void writeInt(final int v) throws IOException {
274-
raf().writeInt(v);
274+
writer().writeInt(v);
275275
}
276276

277277
@Override
278278
public void writeLong(final long v) throws IOException {
279-
raf().writeLong(v);
279+
writer().writeLong(v);
280280
}
281281

282282
@Override
283283
public void writeShort(final int v) throws IOException {
284-
raf().writeShort(v);
284+
writer().writeShort(v);
285285
}
286286

287287
@Override
288288
public void writeUTF(final String str) throws IOException {
289-
raf().writeUTF(str);
289+
writer().writeUTF(str);
290290
}
291291

292292
// -- Closeable methods --
293293

294294
@Override
295295
public synchronized void close() throws IOException {
296-
if (raf != null) raf().close();
296+
if (raf != null) raf.close();
297297
closed = true;
298298
}
299299

@@ -306,12 +306,46 @@ public Class<FileLocation> getType() {
306306

307307
// -- Helper methods --
308308

309-
private RandomAccessFile raf() throws IOException {
310-
if (raf == null) initRAF();
309+
/**
310+
* Access method for the internal {@link RandomAccessFile}, that succeeds
311+
* independently of the underlying file existing on disk. This allows us to
312+
* create a new file for writing.
313+
*
314+
* @return the internal {@link RandomAccessFile} or creates if if needed.
315+
* @throws IOException if the {@link RandomAccessFile} could not be created.
316+
*/
317+
private RandomAccessFile writer() throws IOException {
318+
if (raf == null) initRAF(true);
311319
return raf;
312320
}
313321

314-
private synchronized void initRAF() throws IOException {
322+
/**
323+
* Access method for the internal {@link RandomAccessFile}, that only succeeds
324+
* if the underlying file exists on disk. This prevents accidental creation of
325+
* an empty RAF file when calling read operations on a non-existent file.
326+
*
327+
* @return the internal {@link RandomAccessFile} or creates if if needed.
328+
* @throws IOException if the {@link RandomAccessFile} could not be created,
329+
* or the backing file does not exists.
330+
*/
331+
private RandomAccessFile reader() throws IOException {
332+
if (raf == null) initRAF(false);
333+
return raf;
334+
}
335+
336+
/**
337+
* Initializes the {@link RandomAccessFile},
338+
*
339+
* @param create whether to create the {@link RandomAccessFile} if the
340+
* underlying file does not exist yet.
341+
* @throws IOException if the {@link RandomAccessFile} could not be created,
342+
* or the backing file does not exists and the {@code create}
343+
* parameter was set to {@code true}.
344+
*/
345+
private synchronized void initRAF(final boolean create) throws IOException {
346+
if (!create && !exists()) {
347+
throw new IOException("Trying to read from non-existent file!");
348+
}
315349
if (closed) throw new IOException("Handle already closed");
316350
if (raf != null) return;
317351
raf = new RandomAccessFile(get().getFile(), getMode());

0 commit comments

Comments
 (0)