29e57e5a0821255d43f12de3904113db08943527
[kai/samba-autobuild/.git] / source4 / ntvfs / posix / pvfs_open.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    POSIX NTVFS backend - open and close
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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "include/includes.h"
24 #include "vfs_posix.h"
25
26
27 /*
28   find open file handle given fnum
29 */
30 struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
31                                struct smbsrv_request *req, uint16_t fnum)
32 {
33         struct pvfs_file *f;
34         for (f=pvfs->open_files;f;f=f->next) {
35                 if (f->fnum == fnum) {
36                         if (req->session != f->session) {
37                                 DEBUG(2,("pvfs_find_fd: attempt to use wrong session for fnum %d\n", fnum));
38                                 return NULL;
39                         }
40                         return f;
41                 }
42         }
43         return NULL;
44 }
45
46 /*
47   by using a destructor we make sure that abnormal cleanup will not 
48   leak file descriptors (assuming at least the top level pointer is freed, which
49   will cascade down to here)
50 */
51 static int pvfs_fd_destructor(void *p)
52 {
53         struct pvfs_file *f = p;
54         if (f->fd != -1) {
55                 close(f->fd);
56                 f->fd = -1;
57         }
58         return 0;
59 }
60
61 /*
62   open a file
63   TODO: this is a temporary implementation derived from the simple backend
64   its purpose is to allow other tests to run 
65 */
66 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
67                    struct smbsrv_request *req, union smb_open *io)
68 {
69         struct pvfs_state *pvfs = ntvfs->private_data;
70         int fd, flags;
71         struct pvfs_filename *name;
72         struct pvfs_file *f;
73         NTSTATUS status;
74
75         if (io->generic.level != RAW_OPEN_GENERIC) {
76                 return ntvfs_map_open(req, io, ntvfs);
77         }
78
79         /* resolve the cifs name to a posix name */
80         status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
81                                    PVFS_RESOLVE_NO_WILDCARD, &name);
82         if (!NT_STATUS_IS_OK(status)) {
83                 return status;
84         }
85
86         switch (io->generic.in.open_disposition) {
87         case NTCREATEX_DISP_SUPERSEDE:
88         case NTCREATEX_DISP_OVERWRITE_IF:
89                 flags = O_CREAT | O_TRUNC;
90                 break;
91         case NTCREATEX_DISP_OPEN:
92         case NTCREATEX_DISP_OVERWRITE:
93                 flags = 0;
94                 break;
95         case NTCREATEX_DISP_CREATE:
96                 flags = O_CREAT | O_EXCL;
97                 break;
98         case NTCREATEX_DISP_OPEN_IF:
99                 flags = O_CREAT;
100                 break;
101         default:
102                 flags = 0;
103                 break;
104         }
105         
106         flags |= O_RDWR;
107
108 /* we need to do this differently to support systems without O_DIRECTORY */
109 #ifndef O_DIRECTORY
110 #define O_DIRECTORY 0
111 #endif
112
113         if (name->exists &&
114             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
115             !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
116                 return NT_STATUS_NOT_A_DIRECTORY;
117         }
118
119         if ((name->exists && name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ||
120             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
121                 flags = O_RDONLY | O_DIRECTORY;
122                 if (pvfs->flags & PVFS_FLAG_READONLY) {
123                         goto do_open;
124                 }
125                 switch (io->generic.in.open_disposition) {
126                 case NTCREATEX_DISP_CREATE:
127                         if (mkdir(name->full_name, 0755) == -1) {
128                                 return pvfs_map_errno(pvfs,errno);
129                         }
130                         break;
131                 case NTCREATEX_DISP_OPEN_IF:
132                         if (mkdir(name->full_name, 0755) == -1 && errno != EEXIST) {
133                                 return pvfs_map_errno(pvfs,errno);
134                         }
135                         break;
136                 }
137         }
138
139 do_open:
140         fd = open(name->full_name, flags, 0644);
141         if (fd == -1) {
142                 if (errno == 0)
143                         errno = ENOENT;
144                 return pvfs_map_errno(pvfs,errno);
145         }
146
147         f = talloc_p(pvfs, struct pvfs_file);
148         if (f == NULL) {
149                 close(fd);
150                 return NT_STATUS_NO_MEMORY;
151         }
152
153         /* re-resolve the open fd */
154         status = pvfs_resolve_name_fd(pvfs, fd, name);
155         if (!NT_STATUS_IS_OK(status)) {
156                 return status;
157         }
158
159         f->fnum = fd;
160         f->fd = fd;
161         f->name = talloc_steal(f, name);
162         f->session = req->session;
163         f->smbpid = req->smbpid;
164
165         /* setup a destructor to avoid file descriptor leaks on
166            abnormal termination */
167         talloc_set_destructor(f, pvfs_fd_destructor);
168
169         DLIST_ADD(pvfs->open_files, f);
170
171         ZERO_STRUCT(io->generic.out);
172         
173         io->generic.out.create_time = name->dos.create_time;
174         io->generic.out.access_time = name->dos.access_time;
175         io->generic.out.write_time = name->dos.write_time;
176         io->generic.out.change_time = name->dos.change_time;
177         io->generic.out.fnum = f->fnum;
178         io->generic.out.alloc_size = name->dos.alloc_size;
179         io->generic.out.size = name->st.st_size;
180         io->generic.out.attrib = name->dos.attrib;
181         io->generic.out.is_directory = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)?1:0;
182
183         return NT_STATUS_OK;
184 }
185
186
187 /*
188   close a file
189 */
190 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
191                     struct smbsrv_request *req, union smb_close *io)
192 {
193         struct pvfs_state *pvfs = ntvfs->private_data;
194         struct pvfs_file *f;
195         NTSTATUS status;
196
197         if (io->generic.level != RAW_CLOSE_CLOSE) {
198                 /* we need a mapping function */
199                 return NT_STATUS_INVALID_LEVEL;
200         }
201
202         f = pvfs_find_fd(pvfs, req, io->close.in.fnum);
203         if (!f) {
204                 return NT_STATUS_INVALID_HANDLE;
205         }
206
207         if (close(f->fd) != 0) {
208                 status = pvfs_map_errno(pvfs, errno);
209         } else {
210                 status = NT_STATUS_OK;
211         }
212
213         talloc_set_destructor(f, NULL);
214
215         DLIST_REMOVE(pvfs->open_files, f);
216         talloc_free(f);
217
218         return status;
219 }
220
221
222 /*
223   logoff - close all file descriptors open by a vuid
224 */
225 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
226                      struct smbsrv_request *req)
227 {
228         struct pvfs_state *pvfs = ntvfs->private_data;
229         struct pvfs_file *f, *next;
230
231         for (f=pvfs->open_files;f;f=next) {
232                 next = f->next;
233                 if (f->session == req->session) {
234                         talloc_set_destructor(f, NULL);
235                         DLIST_REMOVE(pvfs->open_files, f);
236                         talloc_free(f);
237                 }
238         }
239
240         return NT_STATUS_OK;
241 }
242
243
244 /*
245   exit - close files for the current pid
246 */
247 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
248                    struct smbsrv_request *req)
249 {
250         struct pvfs_state *pvfs = ntvfs->private_data;
251         struct pvfs_file *f, *next;
252
253         for (f=pvfs->open_files;f;f=next) {
254                 next = f->next;
255                 if (f->smbpid == req->smbpid) {
256                         talloc_set_destructor(f, NULL);
257                         DLIST_REMOVE(pvfs->open_files, f);
258                         talloc_free(f);
259                 }
260         }
261
262         return NT_STATUS_OK;
263 }