788b0a7ceca6f3f12fe7dd7f4816199314f798f8
[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         int ret;
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                 set_close_write_time(fsp, lck->changed_write_time);
295         }
296
297         if (!del_share_mode(lck, fsp)) {
298                 DEBUG(0, ("close_remove_share_mode: Could not delete share "
299                           "entry for file %s\n",
300                           fsp_str_dbg(fsp)));
301         }
302
303         if (fsp->initial_delete_on_close && (lck->delete_token == NULL)) {
304                 bool became_user = False;
305
306                 /* Initial delete on close was set and no one else
307                  * wrote a real delete on close. */
308
309                 if (current_user.vuid != fsp->vuid) {
310                         become_user(conn, fsp->vuid);
311                         became_user = True;
312                 }
313                 set_delete_on_close_lck(lck, True, &current_user.ut);
314                 if (became_user) {
315                         unbecome_user();
316                 }
317         }
318
319         delete_file = lck->delete_on_close;
320
321         if (delete_file) {
322                 int i;
323                 /* See if others still have the file open. If this is the
324                  * case, then don't delete. If all opens are POSIX delete now. */
325                 for (i=0; i<lck->num_share_modes; i++) {
326                         struct share_mode_entry *e = &lck->share_modes[i];
327                         if (is_valid_share_mode_entry(e)) {
328                                 if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
329                                         continue;
330                                 }
331                                 delete_file = False;
332                                 break;
333                         }
334                 }
335         }
336
337         /* Notify any deferred opens waiting on this close. */
338         notify_deferred_opens(lck);
339         reply_to_oplock_break_requests(fsp);
340
341         /*
342          * NT can set delete_on_close of the last open
343          * reference to a file.
344          */
345
346         if (!(close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE)
347             || !delete_file
348             || (lck->delete_token == NULL)) {
349                 TALLOC_FREE(lck);
350                 return NT_STATUS_OK;
351         }
352
353         /*
354          * Ok, we have to delete the file
355          */
356
357         DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set "
358                  "- deleting file.\n", fsp_str_dbg(fsp)));
359
360         /*
361          * Don't try to update the write time when we delete the file
362          */
363         fsp->update_write_time_on_close = false;
364
365         if (!unix_token_equal(lck->delete_token, &current_user.ut)) {
366                 /* Become the user who requested the delete. */
367
368                 DEBUG(5,("close_remove_share_mode: file %s. "
369                         "Change user to uid %u\n",
370                         fsp_str_dbg(fsp),
371                         (unsigned int)lck->delete_token->uid));
372
373                 if (!push_sec_ctx()) {
374                         smb_panic("close_remove_share_mode: file %s. failed to push "
375                                   "sec_ctx.\n");
376                 }
377
378                 set_sec_ctx(lck->delete_token->uid,
379                             lck->delete_token->gid,
380                             lck->delete_token->ngroups,
381                             lck->delete_token->groups,
382                             NULL);
383
384                 changed_user = true;
385         }
386
387         /* We can only delete the file if the name we have is still valid and
388            hasn't been renamed. */
389
390         if (fsp->posix_open) {
391                 ret = SMB_VFS_LSTAT(conn, fsp->fsp_name);
392         } else {
393                 ret = SMB_VFS_STAT(conn, fsp->fsp_name);
394         }
395
396         if (ret != 0) {
397                 DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
398                          "was set and stat failed with error %s\n",
399                          fsp_str_dbg(fsp), strerror(errno)));
400                 /*
401                  * Don't save the errno here, we ignore this error
402                  */
403                 goto done;
404         }
405
406         id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
407
408         if (!file_id_equal(&fsp->file_id, &id)) {
409                 DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
410                          "was set and dev and/or inode does not match\n",
411                          fsp_str_dbg(fsp)));
412                 DEBUG(5,("close_remove_share_mode: file %s. stored file_id %s, "
413                          "stat file_id %s\n",
414                          fsp_str_dbg(fsp),
415                          file_id_string_tos(&fsp->file_id),
416                          file_id_string_tos(&id)));
417                 /*
418                  * Don't save the errno here, we ignore this error
419                  */
420                 goto done;
421         }
422
423         if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
424             && !is_ntfs_stream_smb_fname(fsp->fsp_name)) {
425
426                 status = delete_all_streams(conn, fsp->fsp_name->base_name);
427
428                 if (!NT_STATUS_IS_OK(status)) {
429                         DEBUG(5, ("delete_all_streams failed: %s\n",
430                                   nt_errstr(status)));
431                         goto done;
432                 }
433         }
434
435
436         if (SMB_VFS_UNLINK(conn, fsp->fsp_name) != 0) {
437                 /*
438                  * This call can potentially fail as another smbd may
439                  * have had the file open with delete on close set and
440                  * deleted it when its last reference to this file
441                  * went away. Hence we log this but not at debug level
442                  * zero.
443                  */
444
445                 DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
446                          "was set and unlink failed with error %s\n",
447                          fsp_str_dbg(fsp), strerror(errno)));
448
449                 status = map_nt_error_from_unix(errno);
450         }
451
452         notify_fname(conn, NOTIFY_ACTION_REMOVED,
453                      FILE_NOTIFY_CHANGE_FILE_NAME,
454                      fsp->fsp_name->base_name);
455
456         /* As we now have POSIX opens which can unlink
457          * with other open files we may have taken
458          * this code path with more than one share mode
459          * entry - ensure we only delete once by resetting
460          * the delete on close flag. JRA.
461          */
462
463         set_delete_on_close_lck(lck, False, NULL);
464
465  done:
466
467         if (changed_user) {
468                 /* unbecome user. */
469                 pop_sec_ctx();
470         }
471
472         TALLOC_FREE(lck);
473         return status;
474 }
475
476 void set_close_write_time(struct files_struct *fsp, struct timespec ts)
477 {
478         DEBUG(6,("close_write_time: %s" , time_to_asc(convert_timespec_to_time_t(ts))));
479
480         if (null_timespec(ts)) {
481                 return;
482         }
483         /*
484          * if the write time on close is explict set, then don't
485          * need to fix it up to the value in the locking db
486          */
487         fsp->write_time_forced = false;
488
489         fsp->update_write_time_on_close = true;
490         fsp->close_write_time = ts;
491 }
492
493 static NTSTATUS update_write_time_on_close(struct files_struct *fsp)
494 {
495         struct smb_file_time ft;
496         NTSTATUS status;
497         int ret = -1;
498
499         ZERO_STRUCT(ft);
500
501         if (!fsp->update_write_time_on_close) {
502                 return NT_STATUS_OK;
503         }
504
505         if (null_timespec(fsp->close_write_time)) {
506                 fsp->close_write_time = timespec_current();
507         }
508
509         /* Ensure we have a valid stat struct for the source. */
510         if (fsp->fh->fd != -1) {
511                 ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
512         } else {
513                 if (fsp->posix_open) {
514                         ret = SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name);
515                 } else {
516                         ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name);
517                 }
518         }
519
520         if (ret == -1) {
521                 return map_nt_error_from_unix(errno);
522         }
523
524         if (!VALID_STAT(fsp->fsp_name->st)) {
525                 /* if it doesn't seem to be a real file */
526                 return NT_STATUS_OK;
527         }
528
529         ft.mtime = fsp->close_write_time;
530         status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, true);
531         if (!NT_STATUS_IS_OK(status)) {
532                 return status;
533         }
534
535         return status;
536 }
537
538 static NTSTATUS ntstatus_keeperror(NTSTATUS s1, NTSTATUS s2)
539 {
540         if (!NT_STATUS_IS_OK(s1)) {
541                 return s1;
542         }
543         return s2;
544 }
545
546 /****************************************************************************
547  Close a file.
548
549  close_type can be NORMAL_CLOSE=0,SHUTDOWN_CLOSE,ERROR_CLOSE.
550  printing and magic scripts are only run on normal close.
551  delete on close is done on normal and shutdown close.
552 ****************************************************************************/
553
554 static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
555                                   enum file_close_type close_type)
556 {
557         NTSTATUS status = NT_STATUS_OK;
558         NTSTATUS tmp;
559         connection_struct *conn = fsp->conn;
560
561         if (fsp->aio_write_behind) {
562                 /*
563                  * If we're finishing write behind on a close we can get a write
564                  * error here, we must remember this.
565                  */
566                 int ret = wait_for_aio_completion(fsp);
567                 if (ret) {
568                         status = ntstatus_keeperror(
569                                 status, map_nt_error_from_unix(ret));
570                 }
571         } else {
572                 cancel_aio_by_fsp(fsp);
573         }
574  
575         /*
576          * If we're flushing on a close we can get a write
577          * error here, we must remember this.
578          */
579
580         tmp = close_filestruct(fsp);
581         status = ntstatus_keeperror(status, tmp);
582
583         if (fsp->print_file) {
584                 print_fsp_end(fsp, close_type);
585                 file_free(req, fsp);
586                 return NT_STATUS_OK;
587         }
588
589         /* Remove the oplock before potentially deleting the file. */
590         if(fsp->oplock_type) {
591                 release_file_oplock(fsp);
592         }
593
594         /* If this is an old DOS or FCB open and we have multiple opens on
595            the same handle we only have one share mode. Ensure we only remove
596            the share mode on the last close. */
597
598         if (fsp->fh->ref_count == 1) {
599                 /* Should we return on error here... ? */
600                 tmp = close_remove_share_mode(fsp, close_type);
601                 status = ntstatus_keeperror(status, tmp);
602         }
603
604         locking_close_file(smbd_messaging_context(), fsp);
605
606         tmp = fd_close(fsp);
607         status = ntstatus_keeperror(status, tmp);
608
609         /* check for magic scripts */
610         if (close_type == NORMAL_CLOSE) {
611                 tmp = check_magic(fsp);
612                 status = ntstatus_keeperror(status, tmp);
613         }
614
615         /*
616          * Ensure pending modtime is set after close.
617          */
618
619         tmp = update_write_time_on_close(fsp);
620         if (NT_STATUS_EQUAL(tmp, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
621                 /* Someone renamed the file or a parent directory containing
622                  * this file. We can't do anything about this, we don't have
623                  * an "update timestamp by fd" call in POSIX. Eat the error. */
624
625                 tmp = NT_STATUS_OK;
626         }
627
628         status = ntstatus_keeperror(status, tmp);
629
630         DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
631                 conn->server_info->unix_name, fsp_str_dbg(fsp),
632                 conn->num_files_open - 1,
633                 nt_errstr(status) ));
634
635         file_free(req, fsp);
636         return status;
637 }
638
639 /****************************************************************************
640  Close a directory opened by an NT SMB call. 
641 ****************************************************************************/
642   
643 static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
644                                 enum file_close_type close_type)
645 {
646         struct share_mode_lock *lck = NULL;
647         bool delete_dir = False;
648         NTSTATUS status = NT_STATUS_OK;
649
650         /*
651          * NT can set delete_on_close of the last open
652          * reference to a directory also.
653          */
654
655         lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
656                                   NULL);
657
658         if (lck == NULL) {
659                 DEBUG(0, ("close_directory: Could not get share mode lock for "
660                           "%s\n", fsp_str_dbg(fsp)));
661                 status = NT_STATUS_INVALID_PARAMETER;
662                 goto out;
663         }
664
665         if (!del_share_mode(lck, fsp)) {
666                 DEBUG(0, ("close_directory: Could not delete share entry for "
667                           "%s\n", fsp_str_dbg(fsp)));
668         }
669
670         if (fsp->initial_delete_on_close) {
671                 bool became_user = False;
672
673                 /* Initial delete on close was set - for
674                  * directories we don't care if anyone else
675                  * wrote a real delete on close. */
676
677                 if (current_user.vuid != fsp->vuid) {
678                         become_user(fsp->conn, fsp->vuid);
679                         became_user = True;
680                 }
681                 send_stat_cache_delete_message(fsp->fsp_name->base_name);
682                 set_delete_on_close_lck(lck, True, &current_user.ut);
683                 if (became_user) {
684                         unbecome_user();
685                 }
686         }
687
688         delete_dir = lck->delete_on_close;
689
690         if (delete_dir) {
691                 int i;
692                 /* See if others still have the dir open. If this is the
693                  * case, then don't delete. If all opens are POSIX delete now. */
694                 for (i=0; i<lck->num_share_modes; i++) {
695                         struct share_mode_entry *e = &lck->share_modes[i];
696                         if (is_valid_share_mode_entry(e)) {
697                                 if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
698                                         continue;
699                                 }
700                                 delete_dir = False;
701                                 break;
702                         }
703                 }
704         }
705
706         if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
707                                 delete_dir &&
708                                 lck->delete_token) {
709         
710                 /* Become the user who requested the delete. */
711
712                 if (!push_sec_ctx()) {
713                         smb_panic("close_directory: failed to push sec_ctx.\n");
714                 }
715
716                 set_sec_ctx(lck->delete_token->uid,
717                                 lck->delete_token->gid,
718                                 lck->delete_token->ngroups,
719                                 lck->delete_token->groups,
720                                 NULL);
721
722                 TALLOC_FREE(lck);
723
724                 status = rmdir_internals(talloc_tos(), fsp->conn,
725                                          fsp->fsp_name);
726
727                 DEBUG(5,("close_directory: %s. Delete on close was set - "
728                          "deleting directory returned %s.\n",
729                          fsp_str_dbg(fsp), nt_errstr(status)));
730
731                 /* unbecome user. */
732                 pop_sec_ctx();
733
734                 /*
735                  * Ensure we remove any change notify requests that would
736                  * now fail as the directory has been deleted.
737                  */
738
739                 if(NT_STATUS_IS_OK(status)) {
740                         remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_DELETE_PENDING);
741                 }
742         } else {
743                 TALLOC_FREE(lck);
744                 remove_pending_change_notify_requests_by_fid(
745                         fsp, NT_STATUS_OK);
746         }
747
748         status = fd_close(fsp);
749
750         if (!NT_STATUS_IS_OK(status)) {
751                 DEBUG(0, ("Could not close dir! fname=%s, fd=%d, err=%d=%s\n",
752                           fsp_str_dbg(fsp), fsp->fh->fd, errno,
753                           strerror(errno)));
754         }
755
756         /*
757          * Do the code common to files and directories.
758          */
759         close_filestruct(fsp);
760         file_free(req, fsp);
761
762  out:
763         TALLOC_FREE(lck);
764         return status;
765 }
766
767 /****************************************************************************
768  Close a files_struct.
769 ****************************************************************************/
770   
771 NTSTATUS close_file(struct smb_request *req, files_struct *fsp,
772                     enum file_close_type close_type)
773 {
774         NTSTATUS status;
775         struct files_struct *base_fsp = fsp->base_fsp;
776
777         if(fsp->is_directory) {
778                 status = close_directory(req, fsp, close_type);
779         } else if (fsp->fake_file_handle != NULL) {
780                 status = close_fake_file(req, fsp);
781         } else {
782                 status = close_normal_file(req, fsp, close_type);
783         }
784
785         if ((base_fsp != NULL) && (close_type != SHUTDOWN_CLOSE)) {
786
787                 /*
788                  * fsp was a stream, the base fsp can't be a stream as well
789                  *
790                  * For SHUTDOWN_CLOSE this is not possible here, because
791                  * SHUTDOWN_CLOSE only happens from files.c which walks the
792                  * complete list of files. If we mess with more than one fsp
793                  * those loops will become confused.
794                  */
795
796                 SMB_ASSERT(base_fsp->base_fsp == NULL);
797                 close_file(req, base_fsp, close_type);
798         }
799
800         return status;
801 }
802
803 /****************************************************************************
804  Deal with an (authorized) message to close a file given the share mode
805  entry.
806 ****************************************************************************/
807
808 void msg_close_file(struct messaging_context *msg_ctx,
809                         void *private_data,
810                         uint32_t msg_type,
811                         struct server_id server_id,
812                         DATA_BLOB *data)
813 {
814         files_struct *fsp = NULL;
815         struct share_mode_entry e;
816
817         message_to_share_mode_entry(&e, (char *)data->data);
818
819         if(DEBUGLVL(10)) {
820                 char *sm_str = share_mode_str(NULL, 0, &e);
821                 if (!sm_str) {
822                         smb_panic("talloc failed");
823                 }
824                 DEBUG(10,("msg_close_file: got request to close share mode "
825                         "entry %s\n", sm_str));
826                 TALLOC_FREE(sm_str);
827         }
828
829         fsp = file_find_dif(e.id, e.share_file_id);
830         if (!fsp) {
831                 DEBUG(10,("msg_close_file: failed to find file.\n"));
832                 return;
833         }
834         close_file(NULL, fsp, NORMAL_CLOSE);
835 }