Simplify the logic - remove extraneous argument and calls to set_close_write_time().
[metze/samba/wip.git] / source3 / smbd / close.c
1 /*
2    Unix SMB/CIFS implementation.
3    file closing
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Jeremy Allison 1992-2007.
6    Copyright (C) Volker Lendecke 2005
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23
24 extern struct current_user current_user;
25
26 /****************************************************************************
27  Run a file if it is a magic script.
28 ****************************************************************************/
29
30 static NTSTATUS check_magic(struct files_struct *fsp)
31 {
32         int ret;
33         const char *magic_output = NULL;
34         SMB_STRUCT_STAT st;
35         int tmp_fd, outfd;
36         TALLOC_CTX *ctx = NULL;
37         const char *p;
38         struct connection_struct *conn = fsp->conn;
39         char *fname = NULL;
40         NTSTATUS status;
41
42         if (!*lp_magicscript(SNUM(conn))) {
43                 return NT_STATUS_OK;
44         }
45
46         DEBUG(5,("checking magic for %s\n", fsp_str_dbg(fsp)));
47
48         ctx = talloc_stackframe();
49
50         fname = fsp->fsp_name->base_name;
51
52         if (!(p = strrchr_m(fname,'/'))) {
53                 p = fname;
54         } else {
55                 p++;
56         }
57
58         if (!strequal(lp_magicscript(SNUM(conn)),p)) {
59                 status = NT_STATUS_OK;
60                 goto out;
61         }
62
63         if (*lp_magicoutput(SNUM(conn))) {
64                 magic_output = lp_magicoutput(SNUM(conn));
65         } else {
66                 magic_output = talloc_asprintf(ctx,
67                                 "%s.out",
68                                 fname);
69         }
70         if (!magic_output) {
71                 status = NT_STATUS_NO_MEMORY;
72                 goto out;
73         }
74
75         /* Ensure we don't depend on user's PATH. */
76         p = talloc_asprintf(ctx, "./%s", fname);
77         if (!p) {
78                 status = NT_STATUS_NO_MEMORY;
79                 goto out;
80         }
81
82         if (chmod(fname, 0755) == -1) {
83                 status = map_nt_error_from_unix(errno);
84                 goto out;
85         }
86         ret = smbrun(p,&tmp_fd);
87         DEBUG(3,("Invoking magic command %s gave %d\n",
88                 p,ret));
89
90         unlink(fname);
91         if (ret != 0 || tmp_fd == -1) {
92                 if (tmp_fd != -1) {
93                         close(tmp_fd);
94                 }
95                 status = NT_STATUS_UNSUCCESSFUL;
96                 goto out;
97         }
98         outfd = open(magic_output, O_CREAT|O_EXCL|O_RDWR, 0600);
99         if (outfd == -1) {
100                 int err = errno;
101                 close(tmp_fd);
102                 status = map_nt_error_from_unix(err);
103                 goto out;
104         }
105
106         if (sys_fstat(tmp_fd,&st) == -1) {
107                 int err = errno;
108                 close(tmp_fd);
109                 close(outfd);
110                 status = map_nt_error_from_unix(err);
111                 goto out;
112         }
113
114         if (transfer_file(tmp_fd,outfd,(SMB_OFF_T)st.st_ex_size) == (SMB_OFF_T)-1) {
115                 int err = errno;
116                 close(tmp_fd);
117                 close(outfd);
118                 status = map_nt_error_from_unix(err);
119                 goto out;
120         }
121         close(tmp_fd);
122         if (close(outfd) == -1) {
123                 status = map_nt_error_from_unix(errno);
124                 goto out;
125         }
126
127         status = NT_STATUS_OK;
128
129  out:
130         TALLOC_FREE(ctx);
131         return status;
132 }
133
134 /****************************************************************************
135   Common code to close a file or a directory.
136 ****************************************************************************/
137
138 static NTSTATUS close_filestruct(files_struct *fsp)
139 {
140         NTSTATUS status = NT_STATUS_OK;
141
142         if (fsp->fh->fd != -1) {
143                 if(flush_write_cache(fsp, CLOSE_FLUSH) == -1) {
144                         status = map_nt_error_from_unix(errno);
145                 }
146                 delete_write_cache(fsp);
147         }
148
149         return status;
150 }
151
152 /****************************************************************************
153  If any deferred opens are waiting on this close, notify them.
154 ****************************************************************************/
155
156 static void notify_deferred_opens(struct share_mode_lock *lck)
157 {
158         int i;
159
160         if (!should_notify_deferred_opens()) {
161                 return;
162         }
163  
164         for (i=0; i<lck->num_share_modes; i++) {
165                 struct share_mode_entry *e = &lck->share_modes[i];
166  
167                 if (!is_deferred_open_entry(e)) {
168                         continue;
169                 }
170  
171                 if (procid_is_me(&e->pid)) {
172                         /*
173                          * We need to notify ourself to retry the open.  Do
174                          * this by finding the queued SMB record, moving it to
175                          * the head of the queue and changing the wait time to
176                          * zero.
177                          */
178                         schedule_deferred_open_smb_message(e->op_mid);
179                 } else {
180                         char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
181
182                         share_mode_entry_to_message(msg, e);
183
184                         messaging_send_buf(smbd_messaging_context(),
185                                            e->pid, MSG_SMB_OPEN_RETRY,
186                                            (uint8 *)msg,
187                                            MSG_SMB_SHARE_MODE_ENTRY_SIZE);
188                 }
189         }
190 }
191
192 /****************************************************************************
193  Delete all streams
194 ****************************************************************************/
195
196 NTSTATUS delete_all_streams(connection_struct *conn, const char *fname)
197 {
198         struct stream_struct *stream_info;
199         int i;
200         unsigned int num_streams;
201         TALLOC_CTX *frame = talloc_stackframe();
202         NTSTATUS status;
203
204         status = SMB_VFS_STREAMINFO(conn, NULL, fname, talloc_tos(),
205                                     &num_streams, &stream_info);
206
207         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
208                 DEBUG(10, ("no streams around\n"));
209                 TALLOC_FREE(frame);
210                 return NT_STATUS_OK;
211         }
212
213         if (!NT_STATUS_IS_OK(status)) {
214                 DEBUG(10, ("SMB_VFS_STREAMINFO failed: %s\n",
215                            nt_errstr(status)));
216                 goto fail;
217         }
218
219         DEBUG(10, ("delete_all_streams found %d streams\n",
220                    num_streams));
221
222         if (num_streams == 0) {
223                 TALLOC_FREE(frame);
224                 return NT_STATUS_OK;
225         }
226
227         for (i=0; i<num_streams; i++) {
228                 int res;
229                 struct smb_filename *smb_fname_stream = NULL;
230
231                 if (strequal(stream_info[i].name, "::$DATA")) {
232                         continue;
233                 }
234
235                 status = create_synthetic_smb_fname(talloc_tos(), fname,
236                                                     stream_info[i].name, NULL,
237                                                     &smb_fname_stream);
238
239                 if (!NT_STATUS_IS_OK(status)) {
240                         DEBUG(0, ("talloc_aprintf failed\n"));
241                         goto fail;
242                 }
243
244                 res = SMB_VFS_UNLINK(conn, smb_fname_stream);
245
246                 if (res == -1) {
247                         status = map_nt_error_from_unix(errno);
248                         DEBUG(10, ("Could not delete stream %s: %s\n",
249                                    smb_fname_str_dbg(smb_fname_stream),
250                                    strerror(errno)));
251                         TALLOC_FREE(smb_fname_stream);
252                         break;
253                 }
254                 TALLOC_FREE(smb_fname_stream);
255         }
256
257  fail:
258         TALLOC_FREE(frame);
259         return status;
260 }
261
262 /****************************************************************************
263  Deal with removing a share mode on last close.
264 ****************************************************************************/
265
266 static NTSTATUS close_remove_share_mode(files_struct *fsp,
267                                         enum file_close_type close_type)
268 {
269         connection_struct *conn = fsp->conn;
270         bool delete_file = false;
271         bool changed_user = false;
272         struct share_mode_lock *lck = NULL;
273         NTSTATUS status = NT_STATUS_OK;
274         NTSTATUS tmp_status;
275         struct file_id id;
276
277         /*
278          * Lock the share entries, and determine if we should delete
279          * on close. If so delete whilst the lock is still in effect.
280          * This prevents race conditions with the file being created. JRA.
281          */
282
283         lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
284                                   NULL);
285
286         if (lck == NULL) {
287                 DEBUG(0, ("close_remove_share_mode: Could not get share mode "
288                           "lock for file %s\n", fsp_str_dbg(fsp)));
289                 status = NT_STATUS_INVALID_PARAMETER;
290                 goto done;
291         }
292
293         if (fsp->write_time_forced) {
294                 DEBUG(10,("close_remove_share_mode: write time forced "
295                         "for file %s\n",
296                         fsp_str_dbg(fsp)));
297                 set_close_write_time(fsp, lck->changed_write_time);
298         }
299
300         if (!del_share_mode(lck, fsp)) {
301                 DEBUG(0, ("close_remove_share_mode: Could not delete share "
302                           "entry for file %s\n",
303                           fsp_str_dbg(fsp)));
304         }
305
306         if (fsp->initial_delete_on_close && (lck->delete_token == NULL)) {
307                 bool became_user = False;
308
309                 /* Initial delete on close was set and no one else
310                  * wrote a real delete on close. */
311
312                 if (current_user.vuid != fsp->vuid) {
313                         become_user(conn, fsp->vuid);
314                         became_user = True;
315                 }
316                 set_delete_on_close_lck(lck, True, &current_user.ut);
317                 if (became_user) {
318                         unbecome_user();
319                 }
320         }
321
322         delete_file = lck->delete_on_close;
323
324         if (delete_file) {
325                 int i;
326                 /* See if others still have the file open. If this is the
327                  * case, then don't delete. If all opens are POSIX delete now. */
328                 for (i=0; i<lck->num_share_modes; i++) {
329                         struct share_mode_entry *e = &lck->share_modes[i];
330                         if (is_valid_share_mode_entry(e)) {
331                                 if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
332                                         continue;
333                                 }
334                                 delete_file = False;
335                                 break;
336                         }
337                 }
338         }
339
340         /* Notify any deferred opens waiting on this close. */
341         notify_deferred_opens(lck);
342         reply_to_oplock_break_requests(fsp);
343
344         /*
345          * NT can set delete_on_close of the last open
346          * reference to a file.
347          */
348
349         if (!(close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE)
350             || !delete_file
351             || (lck->delete_token == NULL)) {
352                 TALLOC_FREE(lck);
353                 return NT_STATUS_OK;
354         }
355
356         /*
357          * Ok, we have to delete the file
358          */
359
360         DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set "
361                  "- deleting file.\n", fsp_str_dbg(fsp)));
362
363         /*
364          * Don't try to update the write time when we delete the file
365          */
366         fsp->update_write_time_on_close = false;
367
368         if (!unix_token_equal(lck->delete_token, &current_user.ut)) {
369                 /* Become the user who requested the delete. */
370
371                 DEBUG(5,("close_remove_share_mode: file %s. "
372                         "Change user to uid %u\n",
373                         fsp_str_dbg(fsp),
374                         (unsigned int)lck->delete_token->uid));
375
376                 if (!push_sec_ctx()) {
377                         smb_panic("close_remove_share_mode: file %s. failed to push "
378                                   "sec_ctx.\n");
379                 }
380
381                 set_sec_ctx(lck->delete_token->uid,
382                             lck->delete_token->gid,
383                             lck->delete_token->ngroups,
384                             lck->delete_token->groups,
385                             NULL);
386
387                 changed_user = true;
388         }
389
390         /* We can only delete the file if the name we have is still valid and
391            hasn't been renamed. */
392
393         tmp_status = vfs_stat_fsp(fsp);
394         if (!NT_STATUS_IS_OK(tmp_status)) {
395                 DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
396                          "was set and stat failed with error %s\n",
397                          fsp_str_dbg(fsp), nt_errstr(tmp_status)));
398                 /*
399                  * Don't save the errno here, we ignore this error
400                  */
401                 goto done;
402         }
403
404         id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
405
406         if (!file_id_equal(&fsp->file_id, &id)) {
407                 DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
408                          "was set and dev and/or inode does not match\n",
409                          fsp_str_dbg(fsp)));
410                 DEBUG(5,("close_remove_share_mode: file %s. stored file_id %s, "
411                          "stat file_id %s\n",
412                          fsp_str_dbg(fsp),
413                          file_id_string_tos(&fsp->file_id),
414                          file_id_string_tos(&id)));
415                 /*
416                  * Don't save the errno here, we ignore this error
417                  */
418                 goto done;
419         }
420
421         if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
422             && !is_ntfs_stream_smb_fname(fsp->fsp_name)) {
423
424                 status = delete_all_streams(conn, fsp->fsp_name->base_name);
425
426                 if (!NT_STATUS_IS_OK(status)) {
427                         DEBUG(5, ("delete_all_streams failed: %s\n",
428                                   nt_errstr(status)));
429                         goto done;
430                 }
431         }
432
433
434         if (SMB_VFS_UNLINK(conn, fsp->fsp_name) != 0) {
435                 /*
436                  * This call can potentially fail as another smbd may
437                  * have had the file open with delete on close set and
438                  * deleted it when its last reference to this file
439                  * went away. Hence we log this but not at debug level
440                  * zero.
441                  */
442
443                 DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
444                          "was set and unlink failed with error %s\n",
445                          fsp_str_dbg(fsp), strerror(errno)));
446
447                 status = map_nt_error_from_unix(errno);
448         }
449
450         notify_fname(conn, NOTIFY_ACTION_REMOVED,
451                      FILE_NOTIFY_CHANGE_FILE_NAME,
452                      fsp->fsp_name->base_name);
453
454         /* As we now have POSIX opens which can unlink
455          * with other open files we may have taken
456          * this code path with more than one share mode
457          * entry - ensure we only delete once by resetting
458          * the delete on close flag. JRA.
459          */
460
461         set_delete_on_close_lck(lck, False, NULL);
462
463  done:
464
465         if (changed_user) {
466                 /* unbecome user. */
467                 pop_sec_ctx();
468         }
469
470         TALLOC_FREE(lck);
471         return status;
472 }
473
474 void set_close_write_time(struct files_struct *fsp, struct timespec ts)
475 {
476         DEBUG(6,("close_write_time: %s" , time_to_asc(convert_timespec_to_time_t(ts))));
477
478         if (null_timespec(ts)) {
479                 return;
480         }
481         fsp->update_write_time_on_close = true;
482         fsp->close_write_time = ts;
483 }
484
485 static NTSTATUS update_write_time_on_close(struct files_struct *fsp)
486 {
487         struct smb_file_time ft;
488         NTSTATUS status;
489
490         ZERO_STRUCT(ft);
491
492         if (!fsp->update_write_time_on_close) {
493                 return NT_STATUS_OK;
494         }
495
496         if (null_timespec(fsp->close_write_time)) {
497                 fsp->close_write_time = timespec_current();
498         }
499
500         /* Ensure we have a valid stat struct for the source. */
501         status = vfs_stat_fsp(fsp);
502         if (!NT_STATUS_IS_OK(status)) {
503                 return status;
504         }
505
506         if (!VALID_STAT(fsp->fsp_name->st)) {
507                 /* if it doesn't seem to be a real file */
508                 return NT_STATUS_OK;
509         }
510
511         /* On close if we're changing the real file time we
512          * must update it in the open file db too. */
513         (void)set_write_time(fsp->file_id, fsp->close_write_time);
514
515         ft.mtime = fsp->close_write_time;
516         status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, false);
517         if (!NT_STATUS_IS_OK(status)) {
518                 return status;
519         }
520
521         return status;
522 }
523
524 static NTSTATUS ntstatus_keeperror(NTSTATUS s1, NTSTATUS s2)
525 {
526         if (!NT_STATUS_IS_OK(s1)) {
527                 return s1;
528         }
529         return s2;
530 }
531
532 /****************************************************************************
533  Close a file.
534
535  close_type can be NORMAL_CLOSE=0,SHUTDOWN_CLOSE,ERROR_CLOSE.
536  printing and magic scripts are only run on normal close.
537  delete on close is done on normal and shutdown close.
538 ****************************************************************************/
539
540 static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
541                                   enum file_close_type close_type)
542 {
543         NTSTATUS status = NT_STATUS_OK;
544         NTSTATUS tmp;
545         connection_struct *conn = fsp->conn;
546
547         if (fsp->aio_write_behind) {
548                 /*
549                  * If we're finishing write behind on a close we can get a write
550                  * error here, we must remember this.
551                  */
552                 int ret = wait_for_aio_completion(fsp);
553                 if (ret) {
554                         status = ntstatus_keeperror(
555                                 status, map_nt_error_from_unix(ret));
556                 }
557         } else {
558                 cancel_aio_by_fsp(fsp);
559         }
560  
561         /*
562          * If we're flushing on a close we can get a write
563          * error here, we must remember this.
564          */
565
566         tmp = close_filestruct(fsp);
567         status = ntstatus_keeperror(status, tmp);
568
569         if (fsp->print_file) {
570                 print_fsp_end(fsp, close_type);
571                 file_free(req, fsp);
572                 return NT_STATUS_OK;
573         }
574
575         /* Remove the oplock before potentially deleting the file. */
576         if(fsp->oplock_type) {
577                 release_file_oplock(fsp);
578         }
579
580         /* If this is an old DOS or FCB open and we have multiple opens on
581            the same handle we only have one share mode. Ensure we only remove
582            the share mode on the last close. */
583
584         if (fsp->fh->ref_count == 1) {
585                 /* Should we return on error here... ? */
586                 tmp = close_remove_share_mode(fsp, close_type);
587                 status = ntstatus_keeperror(status, tmp);
588         }
589
590         locking_close_file(smbd_messaging_context(), fsp);
591
592         tmp = fd_close(fsp);
593         status = ntstatus_keeperror(status, tmp);
594
595         /* check for magic scripts */
596         if (close_type == NORMAL_CLOSE) {
597                 tmp = check_magic(fsp);
598                 status = ntstatus_keeperror(status, tmp);
599         }
600
601         /*
602          * Ensure pending modtime is set after close.
603          */
604
605         tmp = update_write_time_on_close(fsp);
606         if (NT_STATUS_EQUAL(tmp, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
607                 /* Someone renamed the file or a parent directory containing
608                  * this file. We can't do anything about this, we don't have
609                  * an "update timestamp by fd" call in POSIX. Eat the error. */
610
611                 tmp = NT_STATUS_OK;
612         }
613
614         status = ntstatus_keeperror(status, tmp);
615
616         DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
617                 conn->server_info->unix_name, fsp_str_dbg(fsp),
618                 conn->num_files_open - 1,
619                 nt_errstr(status) ));
620
621         file_free(req, fsp);
622         return status;
623 }
624
625 /****************************************************************************
626  Close a directory opened by an NT SMB call. 
627 ****************************************************************************/
628   
629 static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
630                                 enum file_close_type close_type)
631 {
632         struct share_mode_lock *lck = NULL;
633         bool delete_dir = False;
634         NTSTATUS status = NT_STATUS_OK;
635
636         /*
637          * NT can set delete_on_close of the last open
638          * reference to a directory also.
639          */
640
641         lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
642                                   NULL);
643
644         if (lck == NULL) {
645                 DEBUG(0, ("close_directory: Could not get share mode lock for "
646                           "%s\n", fsp_str_dbg(fsp)));
647                 status = NT_STATUS_INVALID_PARAMETER;
648                 goto out;
649         }
650
651         if (!del_share_mode(lck, fsp)) {
652                 DEBUG(0, ("close_directory: Could not delete share entry for "
653                           "%s\n", fsp_str_dbg(fsp)));
654         }
655
656         if (fsp->initial_delete_on_close) {
657                 bool became_user = False;
658
659                 /* Initial delete on close was set - for
660                  * directories we don't care if anyone else
661                  * wrote a real delete on close. */
662
663                 if (current_user.vuid != fsp->vuid) {
664                         become_user(fsp->conn, fsp->vuid);
665                         became_user = True;
666                 }
667                 send_stat_cache_delete_message(fsp->fsp_name->base_name);
668                 set_delete_on_close_lck(lck, True, &current_user.ut);
669                 if (became_user) {
670                         unbecome_user();
671                 }
672         }
673
674         delete_dir = lck->delete_on_close;
675
676         if (delete_dir) {
677                 int i;
678                 /* See if others still have the dir open. If this is the
679                  * case, then don't delete. If all opens are POSIX delete now. */
680                 for (i=0; i<lck->num_share_modes; i++) {
681                         struct share_mode_entry *e = &lck->share_modes[i];
682                         if (is_valid_share_mode_entry(e)) {
683                                 if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
684                                         continue;
685                                 }
686                                 delete_dir = False;
687                                 break;
688                         }
689                 }
690         }
691
692         if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
693                                 delete_dir &&
694                                 lck->delete_token) {
695         
696                 /* Become the user who requested the delete. */
697
698                 if (!push_sec_ctx()) {
699                         smb_panic("close_directory: failed to push sec_ctx.\n");
700                 }
701
702                 set_sec_ctx(lck->delete_token->uid,
703                                 lck->delete_token->gid,
704                                 lck->delete_token->ngroups,
705                                 lck->delete_token->groups,
706                                 NULL);
707
708                 TALLOC_FREE(lck);
709
710                 status = rmdir_internals(talloc_tos(), fsp->conn,
711                                          fsp->fsp_name);
712
713                 DEBUG(5,("close_directory: %s. Delete on close was set - "
714                          "deleting directory returned %s.\n",
715                          fsp_str_dbg(fsp), nt_errstr(status)));
716
717                 /* unbecome user. */
718                 pop_sec_ctx();
719
720                 /*
721                  * Ensure we remove any change notify requests that would
722                  * now fail as the directory has been deleted.
723                  */
724
725                 if(NT_STATUS_IS_OK(status)) {
726                         remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_DELETE_PENDING);
727                 }
728         } else {
729                 TALLOC_FREE(lck);
730                 remove_pending_change_notify_requests_by_fid(
731                         fsp, NT_STATUS_OK);
732         }
733
734         status = fd_close(fsp);
735
736         if (!NT_STATUS_IS_OK(status)) {
737                 DEBUG(0, ("Could not close dir! fname=%s, fd=%d, err=%d=%s\n",
738                           fsp_str_dbg(fsp), fsp->fh->fd, errno,
739                           strerror(errno)));
740         }
741
742         if (fsp->dptr) {
743                 dptr_CloseDir(fsp->dptr);
744         }
745
746         /*
747          * Do the code common to files and directories.
748          */
749         close_filestruct(fsp);
750         file_free(req, fsp);
751
752  out:
753         TALLOC_FREE(lck);
754         return status;
755 }
756
757 /****************************************************************************
758  Close a files_struct.
759 ****************************************************************************/
760   
761 NTSTATUS close_file(struct smb_request *req, files_struct *fsp,
762                     enum file_close_type close_type)
763 {
764         NTSTATUS status;
765         struct files_struct *base_fsp = fsp->base_fsp;
766
767         if(fsp->is_directory) {
768                 status = close_directory(req, fsp, close_type);
769         } else if (fsp->fake_file_handle != NULL) {
770                 status = close_fake_file(req, fsp);
771         } else {
772                 status = close_normal_file(req, fsp, close_type);
773         }
774
775         if ((base_fsp != NULL) && (close_type != SHUTDOWN_CLOSE)) {
776
777                 /*
778                  * fsp was a stream, the base fsp can't be a stream as well
779                  *
780                  * For SHUTDOWN_CLOSE this is not possible here, because
781                  * SHUTDOWN_CLOSE only happens from files.c which walks the
782                  * complete list of files. If we mess with more than one fsp
783                  * those loops will become confused.
784                  */
785
786                 SMB_ASSERT(base_fsp->base_fsp == NULL);
787                 close_file(req, base_fsp, close_type);
788         }
789
790         return status;
791 }
792
793 /****************************************************************************
794  Deal with an (authorized) message to close a file given the share mode
795  entry.
796 ****************************************************************************/
797
798 void msg_close_file(struct messaging_context *msg_ctx,
799                         void *private_data,
800                         uint32_t msg_type,
801                         struct server_id server_id,
802                         DATA_BLOB *data)
803 {
804         files_struct *fsp = NULL;
805         struct share_mode_entry e;
806
807         message_to_share_mode_entry(&e, (char *)data->data);
808
809         if(DEBUGLVL(10)) {
810                 char *sm_str = share_mode_str(NULL, 0, &e);
811                 if (!sm_str) {
812                         smb_panic("talloc failed");
813                 }
814                 DEBUG(10,("msg_close_file: got request to close share mode "
815                         "entry %s\n", sm_str));
816                 TALLOC_FREE(sm_str);
817         }
818
819         fsp = file_find_dif(e.id, e.share_file_id);
820         if (!fsp) {
821                 DEBUG(10,("msg_close_file: failed to find file.\n"));
822                 return;
823         }
824         close_file(NULL, fsp, NORMAL_CLOSE);
825 }