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