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)
35 f = idr_find(pvfs->idtree_fnum, fnum);
40 if (req->session != f->session) {
41 DEBUG(2,("pvfs_find_fd: attempt to use wrong session for fnum %d\n",
50 by using a destructor we make sure that abnormal cleanup will not
51 leak file descriptors (assuming at least the top level pointer is freed, which
52 will cascade down to here)
54 static int pvfs_fd_destructor(void *p)
56 struct pvfs_file *f = p;
58 pvfs_lock_close(f->pvfs, f);
65 idr_remove(f->pvfs->idtree_fnum, f->fnum);
72 TODO: this is a temporary implementation derived from the simple backend
73 its purpose is to allow other tests to run
75 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
76 struct smbsrv_request *req, union smb_open *io)
78 struct pvfs_state *pvfs = ntvfs->private_data;
80 struct pvfs_filename *name;
89 if (io->generic.level != RAW_OPEN_GENERIC) {
90 return ntvfs_map_open(req, io, ntvfs);
93 /* resolve the cifs name to a posix name */
94 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
95 PVFS_RESOLVE_NO_WILDCARD, &name);
96 if (!NT_STATUS_IS_OK(status)) {
100 switch (io->generic.in.open_disposition) {
101 case NTCREATEX_DISP_SUPERSEDE:
102 case NTCREATEX_DISP_OVERWRITE_IF:
103 flags = O_CREAT | O_TRUNC;
105 case NTCREATEX_DISP_OPEN:
108 case NTCREATEX_DISP_OVERWRITE:
111 case NTCREATEX_DISP_CREATE:
112 flags = O_CREAT | O_EXCL;
114 case NTCREATEX_DISP_OPEN_IF:
124 /* we need to do this differently to support systems without O_DIRECTORY */
126 #define O_DIRECTORY 0
130 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
131 !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
132 return NT_STATUS_NOT_A_DIRECTORY;
135 if ((name->exists && name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ||
136 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
137 flags = O_RDONLY | O_DIRECTORY;
138 if (pvfs->flags & PVFS_FLAG_READONLY) {
141 switch (io->generic.in.open_disposition) {
142 case NTCREATEX_DISP_CREATE:
143 if (mkdir(name->full_name, 0755) == -1) {
144 return pvfs_map_errno(pvfs,errno);
147 case NTCREATEX_DISP_OPEN_IF:
148 if (mkdir(name->full_name, 0755) == -1 && errno != EEXIST) {
149 return pvfs_map_errno(pvfs,errno);
155 f = talloc_p(pvfs, struct pvfs_file);
157 return NT_STATUS_NO_MEMORY;
160 fnum = idr_get_new(pvfs->idtree_fnum, f, UINT16_MAX);
163 return NT_STATUS_TOO_MANY_OPENED_FILES;
167 fd = open(name->full_name, flags, 0644);
171 return pvfs_map_errno(pvfs,errno);
174 /* re-resolve the open fd */
175 status = pvfs_resolve_name_fd(pvfs, fd, name);
176 if (!NT_STATUS_IS_OK(status)) {
182 f->name = talloc_steal(f, name);
183 f->session = req->session;
184 f->smbpid = req->smbpid;
186 f->pending_list = NULL;
189 /* we must zero here to take account of padding */
190 ZERO_STRUCT(lock_context);
191 lock_context.device = name->st.st_dev;
192 lock_context.inode = name->st.st_ino;
193 f->locking_key = data_blob_talloc(f, &lock_context, sizeof(lock_context));
195 /* setup a destructor to avoid file descriptor leaks on
196 abnormal termination */
197 talloc_set_destructor(f, pvfs_fd_destructor);
199 DLIST_ADD(pvfs->open_files, f);
201 ZERO_STRUCT(io->generic.out);
203 io->generic.out.create_time = name->dos.create_time;
204 io->generic.out.access_time = name->dos.access_time;
205 io->generic.out.write_time = name->dos.write_time;
206 io->generic.out.change_time = name->dos.change_time;
207 io->generic.out.fnum = f->fnum;
208 io->generic.out.alloc_size = name->dos.alloc_size;
209 io->generic.out.size = name->st.st_size;
210 io->generic.out.attrib = name->dos.attrib;
211 io->generic.out.is_directory = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)?1:0;
220 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
221 struct smbsrv_request *req, union smb_close *io)
223 struct pvfs_state *pvfs = ntvfs->private_data;
227 if (io->generic.level != RAW_CLOSE_CLOSE) {
228 /* we need a mapping function */
229 return NT_STATUS_INVALID_LEVEL;
232 f = pvfs_find_fd(pvfs, req, io->close.in.fnum);
234 return NT_STATUS_INVALID_HANDLE;
237 if (close(f->fd) != 0) {
238 status = pvfs_map_errno(pvfs, errno);
240 status = NT_STATUS_OK;
244 DLIST_REMOVE(pvfs->open_files, f);
246 /* the destructor takes care of the rest */
254 logoff - close all file descriptors open by a vuid
256 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
257 struct smbsrv_request *req)
259 struct pvfs_state *pvfs = ntvfs->private_data;
260 struct pvfs_file *f, *next;
262 for (f=pvfs->open_files;f;f=next) {
264 if (f->session == req->session) {
265 DLIST_REMOVE(pvfs->open_files, f);
275 exit - close files for the current pid
277 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
278 struct smbsrv_request *req)
280 struct pvfs_state *pvfs = ntvfs->private_data;
281 struct pvfs_file *f, *next;
283 for (f=pvfs->open_files;f;f=next) {
285 if (f->smbpid == req->smbpid) {
286 DLIST_REMOVE(pvfs->open_files, f);