Note that there are some explanatory texts on larger screens.

plurals
  1. POWhat could cause FileStream to read 0 bytes from an apparently locked file?
    primarykey
    data
    text
    <p>I have a 'pack files' method, written in J# that takes a bunch of files and writes them all into a stream, along with some enough metadata that they can be reconstructed as individual files by a related 'unpack' method. I've provided a rough version at the end of this question that gives a good indication of what the underlying J# does. I obtained this by running .NET reflector over the J# code to generate the equivalent J# libraries.</p> <p>Now the code below works perfectly in developement, but intermittently experiences errors in production. The exceptions labelled in the comments below as 'Error 1' and 'Error 2' have both been seen in the wild. In the case where 'ERROR 2' occurs, there are always 0 bytes written. There is no apparent pattern to when these errors occur. The file sizes involved are typically under 100kb.</p> <p>The files that get passed into the 'pack' method have very recently been created, as in milliseconds ago, wall-clock time. The output stream points at a file which has newly been created with no sharing. </p> <p>So to summarize, sometimes I get a file length of '0' returned for a file that I know exists... because I just created it. Due to the involvement of J# I cannot obtain the actual exception. (Of course if I was debugging I could break on the first chance exception, but as mentioned this never happens in the development environment). Other times I am unable to read any bytes out of the file, even though it has been successfully opened. There is exception during the copy process, I can only assume that 'Read' returned -1. </p> <p>What could be going on here? Any ideas? My suspicion is that there is a virus checked running in Prod, but not dev, and that maybe it's involved somehow. But what could a virus checker do when I have a file open and locked (as in the WriteToStream method) that would cause it to stop reading without an error? I have written up a little test app that can lock arbitrary files... but locking the file from another process doesn't seem to stop FileInfo.Length from working, and once the file stream opens, my test app can no longer lock the file, as you would expect.</p> <p>I'm stumped, I am. </p> <p>EDIT:</p> <p>Okay - here is the J# code instead. Have re-tagged the question.</p> <p>EDIT 2:</p> <p>I should also mention that the check for 0 length was added later for trouble-shooting purposes. Prior to that, it was always just failing after comparing 'length' to 'written'. So whenever 'length' does not equal 'written', sometimes 'length' is 0 and sometimes 'written' is 0. I am confident the problem is NOT a bug in my code, but is caused by something external. The purpose of this question is to find out what another process (e.g. a virus checker) could do to those files to cause my code to fail in the way I describe.</p> <pre><code>public static void packContentsToStream(Serializable serializable, Stream stream) { try { OutputStream output = new StreamWrapperOutputStream(stream); FileRecordPair[] recordPairs = SerializationUtil.getRecords(serializable); FileRecord[] records = new FileRecord[recordPairs.length]; File[] files = new Files[recordPairs.length]; for (int i = 0; i &lt; recordPairs.length; i++) { FileRecordPair pair = recordPairs[i]; records[i] = pair.getRecord(); files[i] = pair.getFile(); } SerializationUtil.writeToStream(serializable, output, false); // False keeps stream open SerializationUtil.writeToStream(records, output, false); for (int i = 0; i &lt; files.length; i++) { File file = files[i]; long written = writeToStream(file, output); if (written != records[i].getFileLength()) { throw new SystemException("Invalid record. The number of bytes written [" + written + "] did not match the recorded file length [" + records[i].getFileLength() + "]."); // ERROR 2 } } } catch (Exception e) { throw new SystemException("Could not write FileRecords", e); } } public static long writeToStream(HapiFile file, OutputStream stream) { long written = 0; if (file.exists()) { FileInputStream fis = null; try { fis = new FileInputStream(file); written = copy(fis, stream); } catch (Exception e) { throw new SystemException("Could not write file to stream", e); } finally { if (fis != null) { try { fis.close(); } catch (IOException ioe) { // For now - throw an exception to see if this might be causing the packing error throw new SystemException("Error closing file", ioe); } } } } return written; } public static int copy(InputStream is, OutputStream stream) throws IOException { int total = 0; int read = 0; byte[] buffer = new byte[BUFFER_SIZE]; while (read &gt; -1) { read = is.read(buffer); if (read &gt; 0) { stream.write(buffer, 0, read); total += read; } } return total; } // Relevant part of 'SerializationUtil.getRecords' private static FileRecord GetFor(File file, String recordName, int index, String pathToInstance) { String fileName = file.getName(); int length = (int) file.length(); // Safe as long as file is under 2GB if (length == 0) { throw new SystemException("Could not obtain file length for '" + file.getPath() + "'"); // ERROR 1 } if (index &gt; -1 &amp;&amp; recordName != null &amp;&amp; recordName.length() &gt; 0) { recordName = recordName + "." + index; } return new FileRecord(fileName, length, recordName, pathToInstance); } // File.length() implementation - obtained using .NET Reflector public virtual long length() { long length = 0L; if (this.__fileInfo != null) { SecurityManager manager = System.getSecurityManager(); if (manager != null) { manager.checkRead(this.__mCanonicalPath); } try { this.__fileInfo.Refresh(); if (!this.exists() || !(this.__fileInfo is FileInfo)) { return 0L; } length = ((FileInfo) this.__fileInfo).Length; } catch (FileNotFoundException) { } catch (IOException) { } } return length; } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload