2 Unix SMB/CIFS implementation.
4 POSIX NTVFS backend - open and close
6 Copyright (C) Andrew Tridgell 2004
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.
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.
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.
23 #include "include/includes.h"
24 #include "vfs_posix.h"
28 find open file handle given fnum
30 struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
31 struct smbsrv_request *req, uint16_t fnum)
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));
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)
51 static int pvfs_fd_destructor(void *p)
53 struct pvfs_file *f = p;
55 brl_close(f->pvfs->brl_context, &f->locking_key, f->fnum);
66 TODO: this is a temporary implementation derived from the simple backend
67 its purpose is to allow other tests to run
69 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
70 struct smbsrv_request *req, union smb_open *io)
72 struct pvfs_state *pvfs = ntvfs->private_data;
74 struct pvfs_filename *name;
82 if (io->generic.level != RAW_OPEN_GENERIC) {
83 return ntvfs_map_open(req, io, ntvfs);
86 /* resolve the cifs name to a posix name */
87 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
88 PVFS_RESOLVE_NO_WILDCARD, &name);
89 if (!NT_STATUS_IS_OK(status)) {
93 switch (io->generic.in.open_disposition) {
94 case NTCREATEX_DISP_SUPERSEDE:
95 case NTCREATEX_DISP_OVERWRITE_IF:
96 flags = O_CREAT | O_TRUNC;
98 case NTCREATEX_DISP_OPEN:
99 case NTCREATEX_DISP_OVERWRITE:
102 case NTCREATEX_DISP_CREATE:
103 flags = O_CREAT | O_EXCL;
105 case NTCREATEX_DISP_OPEN_IF:
115 /* we need to do this differently to support systems without O_DIRECTORY */
117 #define O_DIRECTORY 0
121 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
122 !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
123 return NT_STATUS_NOT_A_DIRECTORY;
126 if ((name->exists && name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ||
127 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
128 flags = O_RDONLY | O_DIRECTORY;
129 if (pvfs->flags & PVFS_FLAG_READONLY) {
132 switch (io->generic.in.open_disposition) {
133 case NTCREATEX_DISP_CREATE:
134 if (mkdir(name->full_name, 0755) == -1) {
135 return pvfs_map_errno(pvfs,errno);
138 case NTCREATEX_DISP_OPEN_IF:
139 if (mkdir(name->full_name, 0755) == -1 && errno != EEXIST) {
140 return pvfs_map_errno(pvfs,errno);
147 fd = open(name->full_name, flags, 0644);
151 return pvfs_map_errno(pvfs,errno);
154 f = talloc_p(pvfs, struct pvfs_file);
157 return NT_STATUS_NO_MEMORY;
160 /* re-resolve the open fd */
161 status = pvfs_resolve_name_fd(pvfs, fd, name);
162 if (!NT_STATUS_IS_OK(status)) {
168 f->name = talloc_steal(f, name);
169 f->session = req->session;
170 f->smbpid = req->smbpid;
173 /* we must zero here to take account of padding */
174 ZERO_STRUCT(lock_context);
175 lock_context.device = name->st.st_dev;
176 lock_context.inode = name->st.st_ino;
177 f->locking_key = data_blob_talloc(f, &lock_context, sizeof(lock_context));
179 /* setup a destructor to avoid file descriptor leaks on
180 abnormal termination */
181 talloc_set_destructor(f, pvfs_fd_destructor);
183 DLIST_ADD(pvfs->open_files, f);
185 ZERO_STRUCT(io->generic.out);
187 io->generic.out.create_time = name->dos.create_time;
188 io->generic.out.access_time = name->dos.access_time;
189 io->generic.out.write_time = name->dos.write_time;
190 io->generic.out.change_time = name->dos.change_time;
191 io->generic.out.fnum = f->fnum;
192 io->generic.out.alloc_size = name->dos.alloc_size;
193 io->generic.out.size = name->st.st_size;
194 io->generic.out.attrib = name->dos.attrib;
195 io->generic.out.is_directory = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)?1:0;
204 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
205 struct smbsrv_request *req, union smb_close *io)
207 struct pvfs_state *pvfs = ntvfs->private_data;
211 if (io->generic.level != RAW_CLOSE_CLOSE) {
212 /* we need a mapping function */
213 return NT_STATUS_INVALID_LEVEL;
216 f = pvfs_find_fd(pvfs, req, io->close.in.fnum);
218 return NT_STATUS_INVALID_HANDLE;
221 status = brl_close(pvfs->brl_context, &f->locking_key, f->fnum);
222 if (!NT_STATUS_IS_OK(status)) {
226 if (close(f->fd) != 0) {
227 status = pvfs_map_errno(pvfs, errno);
229 status = NT_STATUS_OK;
232 talloc_set_destructor(f, NULL);
234 DLIST_REMOVE(pvfs->open_files, f);
242 logoff - close all file descriptors open by a vuid
244 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
245 struct smbsrv_request *req)
247 struct pvfs_state *pvfs = ntvfs->private_data;
248 struct pvfs_file *f, *next;
250 for (f=pvfs->open_files;f;f=next) {
252 if (f->session == req->session) {
253 talloc_set_destructor(f, NULL);
254 DLIST_REMOVE(pvfs->open_files, f);
264 exit - close files for the current pid
266 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
267 struct smbsrv_request *req)
269 struct pvfs_state *pvfs = ntvfs->private_data;
270 struct pvfs_file *f, *next;
272 for (f=pvfs->open_files;f;f=next) {
274 if (f->smbpid == req->smbpid) {
275 talloc_set_destructor(f, NULL);
276 DLIST_REMOVE(pvfs->open_files, f);