osi_Assert(filePos <= avc->m.Length);
#else
if (filePos > avc->m.Length) {
+#if AFS_DISCON_ENV
+ if (AFS_IS_DISCON_RW)
+ afs_PopulateDCache(avc, filePos, &treq);
+#endif
afs_Trace4(afs_iclSetp, CM_TRACE_SETLENGTH, ICL_TYPE_STRING,
__FILE__, ICL_TYPE_LONG, __LINE__, ICL_TYPE_OFFSET,
ICL_HANDLE_OFFSET(avc->m.Length), ICL_TYPE_OFFSET,
osi_Assert(filePos <= avc->m.Length);
#else
if (filePos > avc->m.Length) {
+# ifdef AFS_DISCON_ENV
+ if (AFS_IS_DISCON_RW)
+ afs_PopulateDCache(avc, filePos, &treq);
+# endif
afs_Trace4(afs_iclSetp, CM_TRACE_SETLENGTH, ICL_TYPE_STRING,
__FILE__, ICL_TYPE_LONG, __LINE__, ICL_TYPE_OFFSET,
ICL_HANDLE_OFFSET(avc->m.Length), ICL_TYPE_OFFSET,
QRemove(&avc->shadowq);
ReleaseWriteLock(&afs_disconDirtyLock);
}
+
+/*!
+ * Populate a dcache with empty chunks up to a given file size,
+ * used before extending a file in order to avoid 'holes' which
+ * we can't access in disconnected mode.
+ *
+ * \param avc The vcache which is being extended (locked)
+ * \param alen The new length of the file
+ *
+ */
+void afs_PopulateDCache(struct vcache *avc, afs_size_t apos, struct vrequest *areq) {
+ struct dcache *tdc;
+ afs_size_t len, offset;
+ afs_int32 start, end;
+
+ /* We're doing this to deal with the situation where we extend
+ * by writing after lseek()ing past the end of the file . If that
+ * extension skips chunks, then those chunks won't be created, and
+ * GetDCache will assume that they have to be fetched from the server.
+ * So, for each chunk between the current file position, and the new
+ * length we GetDCache for that chunk.
+ */
+
+ if (AFS_CHUNK(apos) == 0 || apos <= avc->m.Length)
+ return;
+
+ if (avc->m.Length == 0)
+ start = 0;
+ else
+ start = AFS_CHUNK(avc->m.Length)+1;
+
+ end = AFS_CHUNK(apos);
+
+ while (start<end) {
+ len = AFS_CHUNKTOSIZE(start);
+ tdc = afs_GetDCache(avc, AFS_CHUNKTOBASE(start), areq, &offset, &len, 4);
+ if (tdc)
+ afs_PutDCache(tdc);
+ start++;
+ }
+}
+
#endif