r3240: - update the rules for what error codes should be given on the
[jelmer/samba4-debian.git] / source / ntvfs / posix / pvfs_setfileinfo.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    POSIX NTVFS backend - setfileinfo
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   set info on a open file
28 */
29 NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
30                           struct smbsrv_request *req, 
31                           union smb_setfileinfo *info)
32 {
33         struct pvfs_state *pvfs = ntvfs->private_data;
34         struct utimbuf unix_times;
35         struct pvfs_file *f;
36         uint32_t create_options;
37         struct pvfs_filename newstats;
38         NTSTATUS status;
39
40         f = pvfs_find_fd(pvfs, req, info->generic.file.fnum);
41         if (!f) {
42                 return NT_STATUS_INVALID_HANDLE;
43         }
44
45         /* update the file information */
46         status = pvfs_resolve_name_fd(pvfs, f->fd, f->name);
47         if (!NT_STATUS_IS_OK(status)) {
48                 return status;
49         }
50
51         /* we take a copy of the current file stats, then update
52            newstats in each of the elements below. At the end we
53            compare, and make any changes needed */
54         newstats = *f->name;
55
56         switch (info->generic.level) {
57         case RAW_SFILEINFO_SETATTR:
58                 if (!null_time(info->setattr.in.write_time)) {
59                         unix_to_nt_time(&newstats.dos.write_time, info->setattr.in.write_time);
60                 }
61                 if (info->setattr.in.attrib != FILE_ATTRIBUTE_NORMAL) {
62                         newstats.dos.attrib = info->setattr.in.attrib;
63                 }
64                 break;
65
66         case RAW_SFILEINFO_SETATTRE:
67         case RAW_SFILEINFO_STANDARD:
68                 if (!null_time(info->setattre.in.create_time)) {
69                         unix_to_nt_time(&newstats.dos.create_time, info->setattre.in.create_time);
70                 }
71                 if (!null_time(info->setattre.in.access_time)) {
72                         unix_to_nt_time(&newstats.dos.access_time, info->setattre.in.access_time);
73                 }
74                 if (!null_time(info->setattre.in.write_time)) {
75                         unix_to_nt_time(&newstats.dos.write_time, info->setattre.in.write_time);
76                 }
77                 break;
78
79         case RAW_SFILEINFO_BASIC_INFO:
80         case RAW_SFILEINFO_BASIC_INFORMATION:
81                 if (info->basic_info.in.create_time) {
82                         newstats.dos.create_time = info->basic_info.in.create_time;
83                 }
84                 if (info->basic_info.in.access_time) {
85                         newstats.dos.access_time = info->basic_info.in.access_time;
86                 }
87                 if (info->basic_info.in.write_time) {
88                         newstats.dos.write_time = info->basic_info.in.write_time;
89                 }
90                 if (info->basic_info.in.change_time) {
91                         newstats.dos.change_time = info->basic_info.in.change_time;
92                 }
93                 if (info->basic_info.in.attrib != FILE_ATTRIBUTE_NORMAL) {
94                         newstats.dos.attrib = info->basic_info.in.attrib;
95                 }
96                 break;
97
98         case RAW_SFILEINFO_DISPOSITION_INFO:
99         case RAW_SFILEINFO_DISPOSITION_INFORMATION:
100                 if (!(f->access_mask & STD_RIGHT_DELETE_ACCESS)) {
101                         return NT_STATUS_ACCESS_DENIED;
102                 }
103                 create_options = f->create_options;
104                 if (info->disposition_info.in.delete_on_close) {
105                         create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
106                 } else {
107                         create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
108                 }
109                 return pvfs_change_create_options(pvfs, req, f, create_options);
110
111         case RAW_SFILEINFO_ALLOCATION_INFO:
112         case RAW_SFILEINFO_ALLOCATION_INFORMATION:
113                 newstats.dos.alloc_size = info->allocation_info.in.alloc_size;
114                 break;
115
116         case RAW_SFILEINFO_END_OF_FILE_INFO:
117         case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
118                 newstats.st.st_size = info->end_of_file_info.in.size;
119                 break;
120
121         case RAW_SFILEINFO_POSITION_INFORMATION:
122                 f->position = info->position_information.in.position;
123                 break;
124
125         default:
126                 return NT_STATUS_INVALID_LEVEL;
127         }
128
129         /* possibly change the file size */
130         if (newstats.st.st_size != f->name->st.st_size) {
131                 if (ftruncate(f->fd, newstats.st.st_size) == -1) {
132                         return pvfs_map_errno(pvfs, errno);
133                 }
134         }
135
136         /* possibly change the file timestamps */
137         ZERO_STRUCT(unix_times);
138         if (newstats.dos.access_time != f->name->dos.access_time) {
139                 unix_times.actime = nt_time_to_unix(newstats.dos.access_time);
140         }
141         if (newstats.dos.write_time != f->name->dos.write_time) {
142                 unix_times.modtime = nt_time_to_unix(newstats.dos.write_time);
143         }
144         if (unix_times.actime != 0 || unix_times.modtime != 0) {
145                 if (utime(f->name->full_name, &unix_times) == -1) {
146                         return pvfs_map_errno(pvfs, errno);
147                 }
148         }
149
150         /* possibly change the attribute */
151         if (newstats.dos.attrib != f->name->dos.attrib) {
152                 mode_t mode = pvfs_fileperms(pvfs, newstats.dos.attrib);
153                 if (fchmod(f->fd, mode) == -1) {
154                         return pvfs_map_errno(pvfs, errno);
155                 }
156         }
157
158
159         return NT_STATUS_OK;
160 }
161
162
163 /*
164   set info on a pathname
165 */
166 NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
167                           struct smbsrv_request *req, union smb_setfileinfo *info)
168 {
169         struct pvfs_state *pvfs = ntvfs->private_data;
170         struct pvfs_filename *name;
171         struct pvfs_filename newstats;
172         NTSTATUS status;
173         struct utimbuf unix_times;
174
175         /* resolve the cifs name to a posix name */
176         status = pvfs_resolve_name(pvfs, req, info->generic.file.fname, 
177                                    PVFS_RESOLVE_NO_WILDCARD, &name);
178         if (!NT_STATUS_IS_OK(status)) {
179                 return status;
180         }
181
182         if (!name->exists) {
183                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
184         }
185
186
187         /* we take a copy of the current file stats, then update
188            newstats in each of the elements below. At the end we
189            compare, and make any changes needed */
190         newstats = *name;
191
192         switch (info->generic.level) {
193         case RAW_SFILEINFO_SETATTR:
194                 if (!null_time(info->setattr.in.write_time)) {
195                         unix_to_nt_time(&newstats.dos.write_time, info->setattr.in.write_time);
196                 }
197                 if (info->setattr.in.attrib != FILE_ATTRIBUTE_NORMAL) {
198                         newstats.dos.attrib = info->setattr.in.attrib;
199                 }
200                 break;
201
202         case RAW_SFILEINFO_SETATTRE:
203         case RAW_SFILEINFO_STANDARD:
204                 if (!null_time(info->setattre.in.create_time)) {
205                         unix_to_nt_time(&newstats.dos.create_time, info->setattre.in.create_time);
206                 }
207                 if (!null_time(info->setattre.in.access_time)) {
208                         unix_to_nt_time(&newstats.dos.access_time, info->setattre.in.access_time);
209                 }
210                 if (!null_time(info->setattre.in.write_time)) {
211                         unix_to_nt_time(&newstats.dos.write_time, info->setattre.in.write_time);
212                 }
213                 break;
214
215         case RAW_SFILEINFO_BASIC_INFO:
216         case RAW_SFILEINFO_BASIC_INFORMATION:
217                 if (info->basic_info.in.create_time) {
218                         newstats.dos.create_time = info->basic_info.in.create_time;
219                 }
220                 if (info->basic_info.in.access_time) {
221                         newstats.dos.access_time = info->basic_info.in.access_time;
222                 }
223                 if (info->basic_info.in.write_time) {
224                         newstats.dos.write_time = info->basic_info.in.write_time;
225                 }
226                 if (info->basic_info.in.change_time) {
227                         newstats.dos.change_time = info->basic_info.in.change_time;
228                 }
229                 if (info->basic_info.in.attrib != FILE_ATTRIBUTE_NORMAL) {
230                         newstats.dos.attrib = info->basic_info.in.attrib;
231                 }
232                 break;
233
234         case RAW_SFILEINFO_ALLOCATION_INFO:
235         case RAW_SFILEINFO_ALLOCATION_INFORMATION:
236                 newstats.dos.alloc_size = info->allocation_info.in.alloc_size;
237                 break;
238
239         case RAW_SFILEINFO_END_OF_FILE_INFO:
240         case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
241                 newstats.st.st_size = info->end_of_file_info.in.size;
242                 break;
243
244         case RAW_SFILEINFO_DISPOSITION_INFO:
245         case RAW_SFILEINFO_DISPOSITION_INFORMATION:
246         case RAW_SFILEINFO_POSITION_INFORMATION:
247                 return NT_STATUS_OK;
248
249         default:
250                 return NT_STATUS_INVALID_LEVEL;
251         }
252
253         /* possibly change the file size */
254         if (newstats.st.st_size != name->st.st_size) {
255                 if (truncate(name->full_name, newstats.st.st_size) == -1) {
256                         return pvfs_map_errno(pvfs, errno);
257                 }
258         }
259
260         /* possibly change the file timestamps */
261         ZERO_STRUCT(unix_times);
262         if (newstats.dos.access_time != name->dos.access_time) {
263                 unix_times.actime = nt_time_to_unix(newstats.dos.access_time);
264         }
265         if (newstats.dos.write_time != name->dos.write_time) {
266                 unix_times.modtime = nt_time_to_unix(newstats.dos.write_time);
267         }
268         if (unix_times.actime != 0 || unix_times.modtime != 0) {
269                 if (utime(name->full_name, &unix_times) == -1) {
270                         return pvfs_map_errno(pvfs, errno);
271                 }
272         }
273
274         /* possibly change the attribute */
275         if (newstats.dos.attrib != name->dos.attrib) {
276                 mode_t mode = pvfs_fileperms(pvfs, newstats.dos.attrib);
277                 if (chmod(name->full_name, mode) == -1) {
278                         return pvfs_map_errno(pvfs, errno);
279                 }
280         }
281
282         return NT_STATUS_OK;
283 }
284