Fix the mess with ldb includes.
[Samba/ekacnet.git] / source4 / ntvfs / posix / pvfs_setfileinfo.c
blobd2604485d45104a1dc1886ba5944d7a7bb0df736
1 /*
2 Unix SMB/CIFS implementation.
4 POSIX NTVFS backend - setfileinfo
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 3 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, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "vfs_posix.h"
24 #include "system/time.h"
25 #include "librpc/gen_ndr/xattr.h"
29 determine what access bits are needed for a call
31 static uint32_t pvfs_setfileinfo_access(union smb_setfileinfo *info)
33 uint32_t needed;
35 switch (info->generic.level) {
36 case RAW_SFILEINFO_EA_SET:
37 needed = SEC_FILE_WRITE_EA;
38 break;
40 case RAW_SFILEINFO_DISPOSITION_INFO:
41 case RAW_SFILEINFO_DISPOSITION_INFORMATION:
42 needed = SEC_STD_DELETE;
43 break;
45 case RAW_SFILEINFO_END_OF_FILE_INFO:
46 needed = SEC_FILE_WRITE_DATA;
47 break;
49 case RAW_SFILEINFO_POSITION_INFORMATION:
50 needed = 0;
51 break;
53 case RAW_SFILEINFO_SEC_DESC:
54 needed = 0;
55 if (info->set_secdesc.in.secinfo_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
56 needed |= SEC_STD_WRITE_OWNER;
58 if (info->set_secdesc.in.secinfo_flags & SECINFO_DACL) {
59 needed |= SEC_STD_WRITE_DAC;
61 if (info->set_secdesc.in.secinfo_flags & SECINFO_SACL) {
62 needed |= SEC_FLAG_SYSTEM_SECURITY;
64 break;
66 case RAW_SFILEINFO_RENAME_INFORMATION:
67 case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
68 needed = SEC_STD_DELETE;
69 break;
71 default:
72 needed = SEC_FILE_WRITE_ATTRIBUTE;
73 break;
76 return needed;
80 rename_information level for streams
82 static NTSTATUS pvfs_setfileinfo_rename_stream(struct pvfs_state *pvfs,
83 struct ntvfs_request *req,
84 struct pvfs_filename *name,
85 int fd,
86 DATA_BLOB *odb_locking_key,
87 union smb_setfileinfo *info)
89 NTSTATUS status;
90 struct odb_lock *lck = NULL;
92 if (info->rename_information.in.new_name[0] != ':') {
93 return NT_STATUS_INVALID_PARAMETER;
96 status = pvfs_access_check_simple(pvfs, req, name, SEC_FILE_WRITE_ATTRIBUTE);
97 if (!NT_STATUS_IS_OK(status)) {
98 return status;
101 lck = odb_lock(req, pvfs->odb_context, odb_locking_key);
102 if (lck == NULL) {
103 DEBUG(0,("Unable to lock opendb for can_stat\n"));
104 return NT_STATUS_INTERNAL_DB_CORRUPTION;
108 status = pvfs_stream_rename(pvfs, name, fd,
109 info->rename_information.in.new_name+1);
110 return status;
114 rename_information level
116 static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs,
117 struct ntvfs_request *req,
118 struct pvfs_filename *name,
119 int fd,
120 DATA_BLOB *odb_locking_key,
121 union smb_setfileinfo *info)
123 NTSTATUS status;
124 struct pvfs_filename *name2;
125 char *new_name, *p;
126 struct odb_lock *lck = NULL;
128 /* renames are only allowed within a directory */
129 if (strchr_m(info->rename_information.in.new_name, '\\') &&
130 (req->ctx->protocol != PROTOCOL_SMB2)) {
131 return NT_STATUS_NOT_SUPPORTED;
134 /* handle stream renames specially */
135 if (name->stream_name) {
136 return pvfs_setfileinfo_rename_stream(pvfs, req, name, fd,
137 odb_locking_key, info);
140 /* w2k3 does not appear to allow relative rename. On SMB2, vista sends it sometimes,
141 but I suspect it is just uninitialised memory */
142 if (info->rename_information.in.root_fid != 0 &&
143 (req->ctx->protocol != PROTOCOL_SMB2)) {
144 return NT_STATUS_INVALID_PARAMETER;
147 /* construct the fully qualified windows name for the new file name */
148 if (req->ctx->protocol == PROTOCOL_SMB2) {
149 /* SMB2 sends the full path of the new name */
150 new_name = talloc_asprintf(req, "\\%s", info->rename_information.in.new_name);
151 } else {
152 new_name = talloc_strdup(req, name->original_name);
153 if (new_name == NULL) {
154 return NT_STATUS_NO_MEMORY;
156 p = strrchr_m(new_name, '\\');
157 if (p == NULL) {
158 return NT_STATUS_OBJECT_NAME_INVALID;
159 } else {
160 *p = 0;
163 new_name = talloc_asprintf(req, "%s\\%s", new_name,
164 info->rename_information.in.new_name);
166 if (new_name == NULL) {
167 return NT_STATUS_NO_MEMORY;
170 /* resolve the new name */
171 status = pvfs_resolve_name(pvfs, name, new_name, 0, &name2);
172 if (!NT_STATUS_IS_OK(status)) {
173 return status;
176 /* if the destination exists, then check the rename is allowed */
177 if (name2->exists) {
178 if (strcmp(name2->full_name, name->full_name) == 0) {
179 /* rename to same name is null-op */
180 return NT_STATUS_OK;
183 if (!info->rename_information.in.overwrite) {
184 return NT_STATUS_OBJECT_NAME_COLLISION;
187 status = pvfs_can_delete(pvfs, req, name2, NULL);
188 if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
189 return NT_STATUS_ACCESS_DENIED;
191 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
192 return NT_STATUS_ACCESS_DENIED;
194 if (!NT_STATUS_IS_OK(status)) {
195 return status;
199 status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE);
200 if (!NT_STATUS_IS_OK(status)) {
201 return status;
204 lck = odb_lock(req, pvfs->odb_context, odb_locking_key);
205 if (lck == NULL) {
206 DEBUG(0,("Unable to lock opendb for can_stat\n"));
207 return NT_STATUS_INTERNAL_DB_CORRUPTION;
210 status = pvfs_do_rename(pvfs, lck, name, name2->full_name);
211 talloc_free(lck);
212 NT_STATUS_NOT_OK_RETURN(status);
213 if (NT_STATUS_IS_OK(status)) {
214 name->full_name = talloc_steal(name, name2->full_name);
215 name->original_name = talloc_steal(name, name2->original_name);
218 return NT_STATUS_OK;
222 add a single DOS EA
224 NTSTATUS pvfs_setfileinfo_ea_set(struct pvfs_state *pvfs,
225 struct pvfs_filename *name,
226 int fd, uint16_t num_eas,
227 struct ea_struct *eas)
229 struct xattr_DosEAs *ealist;
230 int i, j;
231 NTSTATUS status;
233 if (num_eas == 0) {
234 return NT_STATUS_OK;
237 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
238 return NT_STATUS_NOT_SUPPORTED;
241 ealist = talloc(name, struct xattr_DosEAs);
243 /* load the current list */
244 status = pvfs_doseas_load(pvfs, name, fd, ealist);
245 if (!NT_STATUS_IS_OK(status)) {
246 return status;
249 for (j=0;j<num_eas;j++) {
250 struct ea_struct *ea = &eas[j];
251 /* see if its already there */
252 for (i=0;i<ealist->num_eas;i++) {
253 if (strcasecmp_m(ealist->eas[i].name, ea->name.s) == 0) {
254 ealist->eas[i].value = ea->value;
255 break;
259 if (i==ealist->num_eas) {
260 /* add it */
261 ealist->eas = talloc_realloc(ealist, ealist->eas,
262 struct xattr_EA,
263 ealist->num_eas+1);
264 if (ealist->eas == NULL) {
265 return NT_STATUS_NO_MEMORY;
267 ealist->eas[i].name = ea->name.s;
268 ealist->eas[i].value = ea->value;
269 ealist->num_eas++;
273 /* pull out any null EAs */
274 for (i=0;i<ealist->num_eas;i++) {
275 if (ealist->eas[i].value.length == 0) {
276 memmove(&ealist->eas[i],
277 &ealist->eas[i+1],
278 (ealist->num_eas-(i+1)) * sizeof(ealist->eas[i]));
279 ealist->num_eas--;
280 i--;
284 status = pvfs_doseas_save(pvfs, name, fd, ealist);
285 if (!NT_STATUS_IS_OK(status)) {
286 return status;
289 notify_trigger(pvfs->notify_context,
290 NOTIFY_ACTION_MODIFIED,
291 FILE_NOTIFY_CHANGE_EA,
292 name->full_name);
294 name->dos.ea_size = 4;
295 for (i=0;i<ealist->num_eas;i++) {
296 name->dos.ea_size += 4 + strlen(ealist->eas[i].name)+1 +
297 ealist->eas[i].value.length;
300 /* update the ea_size attrib */
301 return pvfs_dosattrib_save(pvfs, name, fd);
305 set info on a open file
307 NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
308 struct ntvfs_request *req,
309 union smb_setfileinfo *info)
311 struct pvfs_state *pvfs = ntvfs->private_data;
312 struct pvfs_file *f;
313 struct pvfs_file_handle *h;
314 struct pvfs_filename newstats;
315 NTSTATUS status;
316 uint32_t access_needed;
317 uint32_t change_mask = 0;
319 f = pvfs_find_fd(pvfs, req, info->generic.in.file.ntvfs);
320 if (!f) {
321 return NT_STATUS_INVALID_HANDLE;
324 h = f->handle;
326 access_needed = pvfs_setfileinfo_access(info);
327 if ((f->access_mask & access_needed) != access_needed) {
328 return NT_STATUS_ACCESS_DENIED;
331 /* update the file information */
332 status = pvfs_resolve_name_handle(pvfs, h);
333 if (!NT_STATUS_IS_OK(status)) {
334 return status;
337 /* we take a copy of the current file stats, then update
338 newstats in each of the elements below. At the end we
339 compare, and make any changes needed */
340 newstats = *h->name;
342 switch (info->generic.level) {
343 case RAW_SFILEINFO_SETATTR:
344 if (!null_time(info->setattr.in.write_time)) {
345 unix_to_nt_time(&newstats.dos.write_time, info->setattr.in.write_time);
347 if (info->setattr.in.attrib != FILE_ATTRIBUTE_NORMAL) {
348 newstats.dos.attrib = info->setattr.in.attrib;
350 break;
352 case RAW_SFILEINFO_SETATTRE:
353 case RAW_SFILEINFO_STANDARD:
354 if (!null_time(info->setattre.in.create_time)) {
355 unix_to_nt_time(&newstats.dos.create_time, info->setattre.in.create_time);
357 if (!null_time(info->setattre.in.access_time)) {
358 unix_to_nt_time(&newstats.dos.access_time, info->setattre.in.access_time);
360 if (!null_time(info->setattre.in.write_time)) {
361 unix_to_nt_time(&newstats.dos.write_time, info->setattre.in.write_time);
363 break;
365 case RAW_SFILEINFO_EA_SET:
366 return pvfs_setfileinfo_ea_set(pvfs, h->name, h->fd,
367 info->ea_set.in.num_eas,
368 info->ea_set.in.eas);
370 case RAW_SFILEINFO_BASIC_INFO:
371 case RAW_SFILEINFO_BASIC_INFORMATION:
372 if (!null_nttime(info->basic_info.in.create_time)) {
373 newstats.dos.create_time = info->basic_info.in.create_time;
375 if (!null_nttime(info->basic_info.in.access_time)) {
376 newstats.dos.access_time = info->basic_info.in.access_time;
378 if (!null_nttime(info->basic_info.in.write_time)) {
379 newstats.dos.write_time = info->basic_info.in.write_time;
381 if (!null_nttime(info->basic_info.in.change_time)) {
382 newstats.dos.change_time = info->basic_info.in.change_time;
384 if (info->basic_info.in.attrib != 0) {
385 newstats.dos.attrib = info->basic_info.in.attrib;
387 break;
389 case RAW_SFILEINFO_DISPOSITION_INFO:
390 case RAW_SFILEINFO_DISPOSITION_INFORMATION:
391 return pvfs_set_delete_on_close(pvfs, req, f,
392 info->disposition_info.in.delete_on_close);
394 case RAW_SFILEINFO_ALLOCATION_INFO:
395 case RAW_SFILEINFO_ALLOCATION_INFORMATION:
396 status = pvfs_break_level2_oplocks(f);
397 NT_STATUS_NOT_OK_RETURN(status);
399 newstats.dos.alloc_size = info->allocation_info.in.alloc_size;
400 if (newstats.dos.alloc_size < newstats.st.st_size) {
401 newstats.st.st_size = newstats.dos.alloc_size;
403 newstats.dos.alloc_size = pvfs_round_alloc_size(pvfs,
404 newstats.dos.alloc_size);
405 break;
407 case RAW_SFILEINFO_END_OF_FILE_INFO:
408 case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
409 status = pvfs_break_level2_oplocks(f);
410 NT_STATUS_NOT_OK_RETURN(status);
412 newstats.st.st_size = info->end_of_file_info.in.size;
413 break;
415 case RAW_SFILEINFO_POSITION_INFORMATION:
416 h->position = info->position_information.in.position;
417 break;
419 case RAW_SFILEINFO_MODE_INFORMATION:
420 /* this one is a puzzle */
421 if (info->mode_information.in.mode != 0 &&
422 info->mode_information.in.mode != 2 &&
423 info->mode_information.in.mode != 4 &&
424 info->mode_information.in.mode != 6) {
425 return NT_STATUS_INVALID_PARAMETER;
427 h->mode = info->mode_information.in.mode;
428 break;
430 case RAW_SFILEINFO_RENAME_INFORMATION:
431 case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
432 return pvfs_setfileinfo_rename(pvfs, req, h->name, f->handle->fd,
433 &h->odb_locking_key,
434 info);
436 case RAW_SFILEINFO_SEC_DESC:
437 notify_trigger(pvfs->notify_context,
438 NOTIFY_ACTION_MODIFIED,
439 FILE_NOTIFY_CHANGE_SECURITY,
440 h->name->full_name);
441 return pvfs_acl_set(pvfs, req, h->name, h->fd, f->access_mask, info);
443 default:
444 return NT_STATUS_INVALID_LEVEL;
447 /* possibly change the file size */
448 if (newstats.st.st_size != h->name->st.st_size) {
449 if (h->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
450 return NT_STATUS_FILE_IS_A_DIRECTORY;
452 if (h->name->stream_name) {
453 status = pvfs_stream_truncate(pvfs, h->name, h->fd, newstats.st.st_size);
454 if (!NT_STATUS_IS_OK(status)) {
455 return status;
458 change_mask |= FILE_NOTIFY_CHANGE_STREAM_SIZE;
459 } else {
460 int ret;
461 if (f->access_mask &
462 (SEC_FILE_WRITE_DATA|SEC_FILE_APPEND_DATA)) {
463 ret = ftruncate(h->fd, newstats.st.st_size);
464 } else {
465 ret = truncate(h->name->full_name, newstats.st.st_size);
467 if (ret == -1) {
468 return pvfs_map_errno(pvfs, errno);
470 change_mask |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
474 /* possibly change the file timestamps */
475 if (newstats.dos.create_time != h->name->dos.create_time) {
476 change_mask |= FILE_NOTIFY_CHANGE_CREATION;
478 if (newstats.dos.access_time != h->name->dos.access_time) {
479 change_mask |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
481 if (newstats.dos.write_time != h->name->dos.write_time) {
482 change_mask |= FILE_NOTIFY_CHANGE_LAST_WRITE;
484 if ((change_mask & FILE_NOTIFY_CHANGE_LAST_ACCESS) ||
485 (change_mask & FILE_NOTIFY_CHANGE_LAST_WRITE)) {
486 struct timeval tv[2];
488 nttime_to_timeval(&tv[0], newstats.dos.access_time);
489 nttime_to_timeval(&tv[1], newstats.dos.write_time);
491 if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
492 if (utimes(h->name->full_name, tv) == -1) {
493 DEBUG(0,("pvfs_setfileinfo: utimes() failed '%s' - %s\n",
494 h->name->full_name, strerror(errno)));
495 return pvfs_map_errno(pvfs, errno);
499 if (change_mask & FILE_NOTIFY_CHANGE_LAST_WRITE) {
500 struct odb_lock *lck;
502 lck = odb_lock(req, h->pvfs->odb_context, &h->odb_locking_key);
503 if (lck == NULL) {
504 DEBUG(0,("Unable to lock opendb for write time update\n"));
505 return NT_STATUS_INTERNAL_ERROR;
508 status = odb_set_write_time(lck, newstats.dos.write_time, true);
509 if (!NT_STATUS_IS_OK(status)) {
510 DEBUG(0,("Unable to update write time: %s\n",
511 nt_errstr(status)));
512 talloc_free(lck);
513 return status;
516 talloc_free(lck);
518 h->write_time.update_forced = true;
519 h->write_time.update_on_close = false;
520 talloc_free(h->write_time.update_event);
521 h->write_time.update_event = NULL;
524 /* possibly change the attribute */
525 if (newstats.dos.attrib != h->name->dos.attrib) {
526 mode_t mode;
527 if ((newstats.dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
528 !(h->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
529 return NT_STATUS_INVALID_PARAMETER;
531 mode = pvfs_fileperms(pvfs, newstats.dos.attrib);
532 if (!(h->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
533 if (fchmod(h->fd, mode) == -1) {
534 return pvfs_map_errno(pvfs, errno);
537 change_mask |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
540 *h->name = newstats;
542 notify_trigger(pvfs->notify_context,
543 NOTIFY_ACTION_MODIFIED,
544 change_mask,
545 h->name->full_name);
547 return pvfs_dosattrib_save(pvfs, h->name, h->fd);
551 retry an open after a sharing violation
553 static void pvfs_retry_setpathinfo(struct pvfs_odb_retry *r,
554 struct ntvfs_module_context *ntvfs,
555 struct ntvfs_request *req,
556 void *_info,
557 void *private_data,
558 enum pvfs_wait_notice reason)
560 union smb_setfileinfo *info = talloc_get_type(_info,
561 union smb_setfileinfo);
562 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
564 talloc_free(r);
566 switch (reason) {
567 case PVFS_WAIT_CANCEL:
568 /*TODO*/
569 status = NT_STATUS_CANCELLED;
570 break;
571 case PVFS_WAIT_TIMEOUT:
572 /* if it timed out, then give the failure
573 immediately */
574 /*TODO*/
575 status = NT_STATUS_SHARING_VIOLATION;
576 break;
577 case PVFS_WAIT_EVENT:
579 /* try the open again, which could trigger another retry setup
580 if it wants to, so we have to unmark the async flag so we
581 will know if it does a second async reply */
582 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
584 status = pvfs_setpathinfo(ntvfs, req, info);
585 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
586 /* the 2nd try also replied async, so we don't send
587 the reply yet */
588 return;
591 /* re-mark it async, just in case someone up the chain does
592 paranoid checking */
593 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
594 break;
597 /* send the reply up the chain */
598 req->async_states->status = status;
599 req->async_states->send_fn(req);
603 setup for a unlink retry after a sharing violation
604 or a non granted oplock
606 static NTSTATUS pvfs_setpathinfo_setup_retry(struct ntvfs_module_context *ntvfs,
607 struct ntvfs_request *req,
608 union smb_setfileinfo *info,
609 struct odb_lock *lck,
610 NTSTATUS status)
612 struct pvfs_state *pvfs = ntvfs->private_data;
613 struct timeval end_time;
615 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
616 end_time = timeval_add(&req->statistics.request_time,
617 0, pvfs->sharing_violation_delay);
618 } else if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
619 end_time = timeval_add(&req->statistics.request_time,
620 pvfs->oplock_break_timeout, 0);
621 } else {
622 return NT_STATUS_INTERNAL_ERROR;
625 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, info, NULL,
626 pvfs_retry_setpathinfo);
630 set info on a pathname
632 NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
633 struct ntvfs_request *req, union smb_setfileinfo *info)
635 struct pvfs_state *pvfs = ntvfs->private_data;
636 struct pvfs_filename *name;
637 struct pvfs_filename newstats;
638 NTSTATUS status;
639 uint32_t access_needed;
640 uint32_t change_mask = 0;
641 struct odb_lock *lck = NULL;
642 DATA_BLOB odb_locking_key;
644 /* resolve the cifs name to a posix name */
645 status = pvfs_resolve_name(pvfs, req, info->generic.in.file.path,
646 PVFS_RESOLVE_STREAMS, &name);
647 if (!NT_STATUS_IS_OK(status)) {
648 return status;
651 if (!name->exists) {
652 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
655 access_needed = pvfs_setfileinfo_access(info);
656 status = pvfs_access_check_simple(pvfs, req, name, access_needed);
657 if (!NT_STATUS_IS_OK(status)) {
658 return status;
661 /* we take a copy of the current file stats, then update
662 newstats in each of the elements below. At the end we
663 compare, and make any changes needed */
664 newstats = *name;
666 switch (info->generic.level) {
667 case RAW_SFILEINFO_SETATTR:
668 if (!null_time(info->setattr.in.write_time)) {
669 unix_to_nt_time(&newstats.dos.write_time, info->setattr.in.write_time);
671 if (info->setattr.in.attrib == 0) {
672 newstats.dos.attrib = FILE_ATTRIBUTE_NORMAL;
673 } else if (info->setattr.in.attrib != FILE_ATTRIBUTE_NORMAL) {
674 newstats.dos.attrib = info->setattr.in.attrib;
676 break;
678 case RAW_SFILEINFO_SETATTRE:
679 case RAW_SFILEINFO_STANDARD:
680 if (!null_time(info->setattre.in.create_time)) {
681 unix_to_nt_time(&newstats.dos.create_time, info->setattre.in.create_time);
683 if (!null_time(info->setattre.in.access_time)) {
684 unix_to_nt_time(&newstats.dos.access_time, info->setattre.in.access_time);
686 if (!null_time(info->setattre.in.write_time)) {
687 unix_to_nt_time(&newstats.dos.write_time, info->setattre.in.write_time);
689 break;
691 case RAW_SFILEINFO_EA_SET:
692 return pvfs_setfileinfo_ea_set(pvfs, name, -1,
693 info->ea_set.in.num_eas,
694 info->ea_set.in.eas);
696 case RAW_SFILEINFO_BASIC_INFO:
697 case RAW_SFILEINFO_BASIC_INFORMATION:
698 if (!null_nttime(info->basic_info.in.create_time)) {
699 newstats.dos.create_time = info->basic_info.in.create_time;
701 if (!null_nttime(info->basic_info.in.access_time)) {
702 newstats.dos.access_time = info->basic_info.in.access_time;
704 if (!null_nttime(info->basic_info.in.write_time)) {
705 newstats.dos.write_time = info->basic_info.in.write_time;
707 if (!null_nttime(info->basic_info.in.change_time)) {
708 newstats.dos.change_time = info->basic_info.in.change_time;
710 if (info->basic_info.in.attrib != 0) {
711 newstats.dos.attrib = info->basic_info.in.attrib;
713 break;
715 case RAW_SFILEINFO_ALLOCATION_INFO:
716 case RAW_SFILEINFO_ALLOCATION_INFORMATION:
717 status = pvfs_can_update_file_size(pvfs, req, name, &lck);
719 * on a sharing violation we need to retry when the file is closed by
720 * the other user, or after 1 second
721 * on a non granted oplock we need to retry when the file is closed by
722 * the other user, or after 30 seconds
724 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
725 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
726 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
727 return pvfs_setpathinfo_setup_retry(pvfs->ntvfs, req, info, lck, status);
729 NT_STATUS_NOT_OK_RETURN(status);
731 if (info->allocation_info.in.alloc_size > newstats.dos.alloc_size) {
732 /* strange. Increasing the allocation size via setpathinfo
733 should be silently ignored */
734 break;
736 newstats.dos.alloc_size = info->allocation_info.in.alloc_size;
737 if (newstats.dos.alloc_size < newstats.st.st_size) {
738 newstats.st.st_size = newstats.dos.alloc_size;
740 newstats.dos.alloc_size = pvfs_round_alloc_size(pvfs,
741 newstats.dos.alloc_size);
742 break;
744 case RAW_SFILEINFO_END_OF_FILE_INFO:
745 case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
746 status = pvfs_can_update_file_size(pvfs, req, name, &lck);
748 * on a sharing violation we need to retry when the file is closed by
749 * the other user, or after 1 second
750 * on a non granted oplock we need to retry when the file is closed by
751 * the other user, or after 30 seconds
753 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
754 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
755 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
756 return pvfs_setpathinfo_setup_retry(pvfs->ntvfs, req, info, lck, status);
758 NT_STATUS_NOT_OK_RETURN(status);
760 newstats.st.st_size = info->end_of_file_info.in.size;
761 break;
763 case RAW_SFILEINFO_MODE_INFORMATION:
764 if (info->mode_information.in.mode != 0 &&
765 info->mode_information.in.mode != 2 &&
766 info->mode_information.in.mode != 4 &&
767 info->mode_information.in.mode != 6) {
768 return NT_STATUS_INVALID_PARAMETER;
770 return NT_STATUS_OK;
772 case RAW_SFILEINFO_RENAME_INFORMATION:
773 case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
774 status = pvfs_locking_key(name, name, &odb_locking_key);
775 NT_STATUS_NOT_OK_RETURN(status);
776 status = pvfs_setfileinfo_rename(pvfs, req, name, -1,
777 &odb_locking_key, info);
778 NT_STATUS_NOT_OK_RETURN(status);
779 return NT_STATUS_OK;
781 case RAW_SFILEINFO_DISPOSITION_INFO:
782 case RAW_SFILEINFO_DISPOSITION_INFORMATION:
783 case RAW_SFILEINFO_POSITION_INFORMATION:
784 return NT_STATUS_OK;
786 default:
787 return NT_STATUS_INVALID_LEVEL;
790 /* possibly change the file size */
791 if (newstats.st.st_size != name->st.st_size) {
792 if (name->stream_name) {
793 status = pvfs_stream_truncate(pvfs, name, -1, newstats.st.st_size);
794 if (!NT_STATUS_IS_OK(status)) {
795 return status;
797 } else if (truncate(name->full_name, newstats.st.st_size) == -1) {
798 return pvfs_map_errno(pvfs, errno);
800 change_mask |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
803 /* possibly change the file timestamps */
804 if (newstats.dos.create_time != name->dos.create_time) {
805 change_mask |= FILE_NOTIFY_CHANGE_CREATION;
807 if (newstats.dos.access_time != name->dos.access_time) {
808 change_mask |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
810 if (newstats.dos.write_time != name->dos.write_time) {
811 change_mask |= FILE_NOTIFY_CHANGE_LAST_WRITE;
813 if ((change_mask & FILE_NOTIFY_CHANGE_LAST_ACCESS) ||
814 (change_mask & FILE_NOTIFY_CHANGE_LAST_WRITE)) {
815 struct timeval tv[2];
817 nttime_to_timeval(&tv[0], newstats.dos.access_time);
818 nttime_to_timeval(&tv[1], newstats.dos.write_time);
820 if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
821 if (utimes(name->full_name, tv) == -1) {
822 DEBUG(0,("pvfs_setpathinfo: utimes() failed '%s' - %s\n",
823 name->full_name, strerror(errno)));
824 return pvfs_map_errno(pvfs, errno);
828 if (change_mask & FILE_NOTIFY_CHANGE_LAST_WRITE) {
829 if (lck == NULL) {
830 DATA_BLOB lkey;
831 status = pvfs_locking_key(name, name, &lkey);
832 NT_STATUS_NOT_OK_RETURN(status);
834 lck = odb_lock(req, pvfs->odb_context, &lkey);
835 data_blob_free(&lkey);
836 if (lck == NULL) {
837 DEBUG(0,("Unable to lock opendb for write time update\n"));
838 return NT_STATUS_INTERNAL_ERROR;
842 status = odb_set_write_time(lck, newstats.dos.write_time, true);
843 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
844 /* it could be that nobody has opened the file */
845 } else if (!NT_STATUS_IS_OK(status)) {
846 DEBUG(0,("Unable to update write time: %s\n",
847 nt_errstr(status)));
848 return status;
852 /* possibly change the attribute */
853 newstats.dos.attrib |= (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY);
854 if (newstats.dos.attrib != name->dos.attrib) {
855 mode_t mode = pvfs_fileperms(pvfs, newstats.dos.attrib);
856 if (chmod(name->full_name, mode) == -1) {
857 return pvfs_map_errno(pvfs, errno);
859 change_mask |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
862 *name = newstats;
864 if (change_mask != 0) {
865 notify_trigger(pvfs->notify_context,
866 NOTIFY_ACTION_MODIFIED,
867 change_mask,
868 name->full_name);
871 return pvfs_dosattrib_save(pvfs, name, -1);