Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-test
[ira/wip.git] / source4 / ntvfs / posix / pvfs_write.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    POSIX NTVFS backend - write
5
6    Copyright (C) Andrew Tridgell 2004
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 #include "vfs_posix.h"
24 #include "librpc/gen_ndr/security.h"
25 #include "lib/events/events.h"
26
27 static void pvfs_write_time_update_handler(struct event_context *ev,
28                                            struct timed_event *te,
29                                            struct timeval tv,
30                                            void *private_data)
31 {
32         struct pvfs_file_handle *h = talloc_get_type(private_data,
33                                      struct pvfs_file_handle);
34         struct odb_lock *lck;
35         NTSTATUS status;
36         NTTIME write_time;
37
38         lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
39         if (lck == NULL) {
40                 DEBUG(0,("Unable to lock opendb for write time update\n"));
41                 return;
42         }
43
44         write_time = timeval_to_nttime(&tv);
45
46         status = odb_set_write_time(lck, write_time, false);
47         if (!NT_STATUS_IS_OK(status)) {
48                 DEBUG(0,("Unable to update write time: %s\n",
49                         nt_errstr(status)));
50                 return;
51         }
52
53         talloc_free(lck);
54
55         h->write_time.update_event = NULL;
56 }
57
58 static void pvfs_trigger_write_time_update(struct pvfs_file_handle *h)
59 {
60         struct pvfs_state *pvfs = h->pvfs;
61         struct timeval tv;
62
63         if (h->write_time.update_triggered) {
64                 return;
65         }
66
67         tv = timeval_current_ofs(0, pvfs->writetime_delay);
68
69         h->write_time.update_triggered = true;
70         h->write_time.update_on_close = true;
71         h->write_time.update_event = event_add_timed(pvfs->ntvfs->ctx->event_ctx,
72                                                      h, tv,
73                                                      pvfs_write_time_update_handler,
74                                                      h);
75         if (!h->write_time.update_event) {
76                 DEBUG(0,("Failed event_add_timed\n"));
77         }
78 }
79
80 /*
81   write to a file
82 */
83 NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs,
84                     struct ntvfs_request *req, union smb_write *wr)
85 {
86         struct pvfs_state *pvfs = ntvfs->private_data;
87         ssize_t ret;
88         struct pvfs_file *f;
89         NTSTATUS status;
90
91         if (wr->generic.level != RAW_WRITE_WRITEX) {
92                 return ntvfs_map_write(ntvfs, req, wr);
93         }
94
95         f = pvfs_find_fd(pvfs, req, wr->writex.in.file.ntvfs);
96         if (!f) {
97                 return NT_STATUS_INVALID_HANDLE;
98         }
99
100         if (f->handle->fd == -1) {
101                 return NT_STATUS_INVALID_DEVICE_REQUEST;
102         }
103
104         if (!(f->access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA))) {
105                 return NT_STATUS_ACCESS_DENIED;
106         }
107
108         status = pvfs_check_lock(pvfs, f, req->smbpid, 
109                                  wr->writex.in.offset,
110                                  wr->writex.in.count,
111                                  WRITE_LOCK);
112         NT_STATUS_NOT_OK_RETURN(status);
113
114         status = pvfs_break_level2_oplocks(f);
115         NT_STATUS_NOT_OK_RETURN(status);
116
117         pvfs_trigger_write_time_update(f->handle);
118
119         if (f->handle->name->stream_name) {
120                 ret = pvfs_stream_write(pvfs,
121                                         f->handle,
122                                         wr->writex.in.data, 
123                                         wr->writex.in.count,
124                                         wr->writex.in.offset);
125         } else {
126 #if HAVE_LINUX_AIO
127                 /* possibly try an aio write */
128                 if ((req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC) &&
129                     (pvfs->flags & PVFS_FLAG_LINUX_AIO)) {
130                         status = pvfs_aio_pwrite(req, wr, f);
131                         if (NT_STATUS_IS_OK(status)) {
132                                 return NT_STATUS_OK;
133                         }
134                 }
135 #endif
136                 ret = pwrite(f->handle->fd, 
137                              wr->writex.in.data, 
138                              wr->writex.in.count,
139                              wr->writex.in.offset);
140         }
141         if (ret == -1) {
142                 if (errno == EFBIG) {
143                         return NT_STATUS_INVALID_PARAMETER;
144                 }
145                 return pvfs_map_errno(pvfs, errno);
146         }
147
148         f->handle->seek_offset = wr->writex.in.offset + ret;
149         
150         wr->writex.out.nwritten = ret;
151         wr->writex.out.remaining = 0; /* should fill this in? */
152
153         return NT_STATUS_OK;
154 }