{
NTSTATUS status;
struct files_struct *base_fsp = fsp->base_fsp;
+ bool close_base_fsp = false;
/*
* This fsp can never be an internal dirfsp. They must
*/
SMB_ASSERT(!fsp->fsp_flags.is_dirfsp);
+ if (fsp->stream_fsp != NULL) {
+ /*
+ * fsp is the base for a stream.
+ *
+ * We're called with SHUTDOWN_CLOSE from files.c which walks the
+ * complete list of files.
+ *
+ * We need to wait until the stream is closed.
+ */
+ SMB_ASSERT(close_type == SHUTDOWN_CLOSE);
+ return NT_STATUS_OK;
+ }
+
+ if (base_fsp != NULL) {
+ /*
+ * We need to remove the link in order to
+ * recurse for the base fsp below.
+ */
+ SMB_ASSERT(base_fsp->base_fsp == NULL);
+ SMB_ASSERT(base_fsp->stream_fsp == fsp);
+ base_fsp->stream_fsp = NULL;
+
+ if (close_type == SHUTDOWN_CLOSE) {
+ /*
+ * We're called with SHUTDOWN_CLOSE from files.c
+ * which walks the complete list of files.
+ *
+ * We may need to defer the SHUTDOWN_CLOSE
+ * if it's the next in the linked list.
+ *
+ * So we only close if the base is *not* the
+ * next in the list.
+ */
+ close_base_fsp = (fsp->next != base_fsp);
+ } else {
+ close_base_fsp = true;
+ }
+ }
+
if (fsp->fsp_flags.is_directory) {
status = close_directory(req, fsp, close_type);
} else if (fsp->fake_file_handle != NULL) {
status = close_normal_file(req, fsp, close_type);
}
- if ((base_fsp != NULL) && (close_type != SHUTDOWN_CLOSE)) {
+ if (close_base_fsp) {
/*
* fsp was a stream, the base fsp can't be a stream as well
*
- * For SHUTDOWN_CLOSE this is not possible here, because
+ * For SHUTDOWN_CLOSE this is not possible here
+ * (if the base_fsp was the next in the linked list), because
* SHUTDOWN_CLOSE only happens from files.c which walks the
* complete list of files. If we mess with more than one fsp
* those loops will become confused.
*/
- SMB_ASSERT(base_fsp->base_fsp == NULL);
close_file(req, base_fsp, close_type);
}
void fsp_set_base_fsp(struct files_struct *fsp, struct files_struct *base_fsp)
{
+ SMB_ASSERT(fsp->stream_fsp == NULL);
if (base_fsp != NULL) {
SMB_ASSERT(base_fsp->base_fsp == NULL);
+ SMB_ASSERT(base_fsp->stream_fsp == NULL);
+ }
+
+ if (fsp->base_fsp != NULL) {
+ SMB_ASSERT(fsp->base_fsp->stream_fsp == fsp);
+ fsp->base_fsp->stream_fsp = NULL;
}
fsp->base_fsp = base_fsp;
+ if (fsp->base_fsp != NULL) {
+ fsp->base_fsp->stream_fsp = fsp;
+ }
}