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;
63 TODO: this is a temporary implementation derived from the simple backend
64 its purpose is to allow other tests to run
66 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
67 struct smbsrv_request *req, union smb_open *io)
69 struct pvfs_state *pvfs = ntvfs->private_data;
71 struct pvfs_filename *name;
75 if (io->generic.level != RAW_OPEN_GENERIC) {
76 return ntvfs_map_open(req, io, ntvfs);
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)) {
86 switch (io->generic.in.open_disposition) {
87 case NTCREATEX_DISP_SUPERSEDE:
88 case NTCREATEX_DISP_OVERWRITE_IF:
89 flags = O_CREAT | O_TRUNC;
91 case NTCREATEX_DISP_OPEN:
92 case NTCREATEX_DISP_OVERWRITE:
95 case NTCREATEX_DISP_CREATE:
96 flags = O_CREAT | O_EXCL;
98 case NTCREATEX_DISP_OPEN_IF:
108 /* we need to do this differently to support systems without O_DIRECTORY */
110 #define O_DIRECTORY 0
114 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
115 !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
116 return NT_STATUS_NOT_A_DIRECTORY;
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) {
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);
131 case NTCREATEX_DISP_OPEN_IF:
132 if (mkdir(name->full_name, 0755) == -1 && errno != EEXIST) {
133 return pvfs_map_errno(pvfs,errno);
140 fd = open(name->full_name, flags, 0644);
144 return pvfs_map_errno(pvfs,errno);
147 f = talloc_p(pvfs, struct pvfs_file);
150 return NT_STATUS_NO_MEMORY;
153 /* re-resolve the open fd */
154 status = pvfs_resolve_name_fd(pvfs, fd, name);
155 if (!NT_STATUS_IS_OK(status)) {
161 f->name = talloc_steal(f, name);
162 f->session = req->session;
163 f->smbpid = req->smbpid;
165 /* setup a destructor to avoid file descriptor leaks on
166 abnormal termination */
167 talloc_set_destructor(f, pvfs_fd_destructor);
169 DLIST_ADD(pvfs->open_files, f);
171 ZERO_STRUCT(io->generic.out);
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;
190 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
191 struct smbsrv_request *req, union smb_close *io)
193 struct pvfs_state *pvfs = ntvfs->private_data;
197 if (io->generic.level != RAW_CLOSE_CLOSE) {
198 /* we need a mapping function */
199 return NT_STATUS_INVALID_LEVEL;
202 f = pvfs_find_fd(pvfs, req, io->close.in.fnum);
204 return NT_STATUS_INVALID_HANDLE;
207 if (close(f->fd) != 0) {
208 status = pvfs_map_errno(pvfs, errno);
210 status = NT_STATUS_OK;
213 talloc_set_destructor(f, NULL);
215 DLIST_REMOVE(pvfs->open_files, f);
223 logoff - close all file descriptors open by a vuid
225 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
226 struct smbsrv_request *req)
228 struct pvfs_state *pvfs = ntvfs->private_data;
229 struct pvfs_file *f, *next;
231 for (f=pvfs->open_files;f;f=next) {
233 if (f->session == req->session) {
234 talloc_set_destructor(f, NULL);
235 DLIST_REMOVE(pvfs->open_files, f);
245 exit - close files for the current pid
247 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
248 struct smbsrv_request *req)
250 struct pvfs_state *pvfs = ntvfs->private_data;
251 struct pvfs_file *f, *next;
253 for (f=pvfs->open_files;f;f=next) {
255 if (f->smbpid == req->smbpid) {
256 talloc_set_destructor(f, NULL);
257 DLIST_REMOVE(pvfs->open_files, f);