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/>.
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)
35 switch (info->generic.level) {
36 case RAW_SFILEINFO_EA_SET:
37 needed = SEC_FILE_WRITE_EA;
40 case RAW_SFILEINFO_DISPOSITION_INFO:
41 case RAW_SFILEINFO_DISPOSITION_INFORMATION:
42 needed = SEC_STD_DELETE;
45 case RAW_SFILEINFO_END_OF_FILE_INFO:
46 needed = SEC_FILE_WRITE_DATA;
49 case RAW_SFILEINFO_POSITION_INFORMATION:
53 case RAW_SFILEINFO_SEC_DESC:
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;
66 case RAW_SFILEINFO_RENAME_INFORMATION:
67 case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
68 needed = SEC_STD_DELETE;
72 needed = SEC_FILE_WRITE_ATTRIBUTE;
80 rename_information level
82 static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs,
83 struct ntvfs_request *req,
84 struct pvfs_filename *name,
85 union smb_setfileinfo *info)
88 struct pvfs_filename *name2;
91 /* renames are only allowed within a directory */
92 if (strchr_m(info->rename_information.in.new_name, '\\') &&
93 (req->ctx->protocol != PROTOCOL_SMB2)) {
94 return NT_STATUS_NOT_SUPPORTED;
97 if (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
98 /* don't allow this for now */
99 return NT_STATUS_FILE_IS_A_DIRECTORY;
102 /* don't allow stream renames for now */
103 if (name->stream_name) {
104 return NT_STATUS_INVALID_PARAMETER;
107 /* w2k3 does not appear to allow relative rename. On SMB2, vista sends it sometimes,
108 but I suspect it is just uninitialised memory */
109 if (info->rename_information.in.root_fid != 0 &&
110 (req->ctx->protocol != PROTOCOL_SMB2)) {
111 return NT_STATUS_INVALID_PARAMETER;
114 /* construct the fully qualified windows name for the new file name */
115 if (req->ctx->protocol == PROTOCOL_SMB2) {
116 /* SMB2 sends the full path of the new name */
117 new_name = talloc_asprintf(req, "\\%s", info->rename_information.in.new_name);
119 new_name = talloc_strdup(req, name->original_name);
120 if (new_name == NULL) {
121 return NT_STATUS_NO_MEMORY;
123 p = strrchr_m(new_name, '\\');
125 return NT_STATUS_OBJECT_NAME_INVALID;
130 new_name = talloc_asprintf(req, "%s\\%s", new_name,
131 info->rename_information.in.new_name);
133 if (new_name == NULL) {
134 return NT_STATUS_NO_MEMORY;
137 /* resolve the new name */
138 status = pvfs_resolve_name(pvfs, name, new_name, 0, &name2);
139 if (!NT_STATUS_IS_OK(status)) {
143 /* if the destination exists, then check the rename is allowed */
145 if (strcmp(name2->full_name, name->full_name) == 0) {
146 /* rename to same name is null-op */
150 if (!info->rename_information.in.overwrite) {
151 return NT_STATUS_OBJECT_NAME_COLLISION;
154 status = pvfs_can_delete(pvfs, req, name2, NULL);
155 if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
156 return NT_STATUS_ACCESS_DENIED;
158 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
159 return NT_STATUS_ACCESS_DENIED;
161 if (!NT_STATUS_IS_OK(status)) {
166 status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE);
167 if (!NT_STATUS_IS_OK(status)) {
171 status = pvfs_do_rename(pvfs, name, name2->full_name);
172 if (NT_STATUS_IS_OK(status)) {
173 name->full_name = talloc_steal(name, name2->full_name);
174 name->original_name = talloc_steal(name, name2->original_name);
183 NTSTATUS pvfs_setfileinfo_ea_set(struct pvfs_state *pvfs,
184 struct pvfs_filename *name,
185 int fd, uint16_t num_eas,
186 struct ea_struct *eas)
188 struct xattr_DosEAs *ealist;
196 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
197 return NT_STATUS_NOT_SUPPORTED;
200 ealist = talloc(name, struct xattr_DosEAs);
202 /* load the current list */
203 status = pvfs_doseas_load(pvfs, name, fd, ealist);
204 if (!NT_STATUS_IS_OK(status)) {
208 for (j=0;j<num_eas;j++) {
209 struct ea_struct *ea = &eas[j];
210 /* see if its already there */
211 for (i=0;i<ealist->num_eas;i++) {
212 if (strcasecmp_m(ealist->eas[i].name, ea->name.s) == 0) {
213 ealist->eas[i].value = ea->value;
218 if (i==ealist->num_eas) {
220 ealist->eas = talloc_realloc(ealist, ealist->eas,
223 if (ealist->eas == NULL) {
224 return NT_STATUS_NO_MEMORY;
226 ealist->eas[i].name = ea->name.s;
227 ealist->eas[i].value = ea->value;
232 /* pull out any null EAs */
233 for (i=0;i<ealist->num_eas;i++) {
234 if (ealist->eas[i].value.length == 0) {
235 memmove(&ealist->eas[i],
237 (ealist->num_eas-(i+1)) * sizeof(ealist->eas[i]));
243 status = pvfs_doseas_save(pvfs, name, fd, ealist);
244 if (!NT_STATUS_IS_OK(status)) {
248 notify_trigger(pvfs->notify_context,
249 NOTIFY_ACTION_MODIFIED,
250 FILE_NOTIFY_CHANGE_EA,
253 name->dos.ea_size = 4;
254 for (i=0;i<ealist->num_eas;i++) {
255 name->dos.ea_size += 4 + strlen(ealist->eas[i].name)+1 +
256 ealist->eas[i].value.length;
259 /* update the ea_size attrib */
260 return pvfs_dosattrib_save(pvfs, name, fd);
264 set info on a open file
266 NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
267 struct ntvfs_request *req,
268 union smb_setfileinfo *info)
270 struct pvfs_state *pvfs = ntvfs->private_data;
271 struct utimbuf unix_times;
273 struct pvfs_file_handle *h;
274 struct pvfs_filename newstats;
276 uint32_t access_needed;
277 uint32_t change_mask = 0;
279 f = pvfs_find_fd(pvfs, req, info->generic.in.file.ntvfs);
281 return NT_STATUS_INVALID_HANDLE;
286 access_needed = pvfs_setfileinfo_access(info);
287 if ((f->access_mask & access_needed) != access_needed) {
288 return NT_STATUS_ACCESS_DENIED;
291 /* update the file information */
292 status = pvfs_resolve_name_fd(pvfs, h->fd, h->name);
293 if (!NT_STATUS_IS_OK(status)) {
297 /* we take a copy of the current file stats, then update
298 newstats in each of the elements below. At the end we
299 compare, and make any changes needed */
302 switch (info->generic.level) {
303 case RAW_SFILEINFO_SETATTR:
304 if (!null_time(info->setattr.in.write_time)) {
305 unix_to_nt_time(&newstats.dos.write_time, info->setattr.in.write_time);
307 if (info->setattr.in.attrib != FILE_ATTRIBUTE_NORMAL) {
308 newstats.dos.attrib = info->setattr.in.attrib;
312 case RAW_SFILEINFO_SETATTRE:
313 case RAW_SFILEINFO_STANDARD:
314 if (!null_time(info->setattre.in.create_time)) {
315 unix_to_nt_time(&newstats.dos.create_time, info->setattre.in.create_time);
317 if (!null_time(info->setattre.in.access_time)) {
318 unix_to_nt_time(&newstats.dos.access_time, info->setattre.in.access_time);
320 if (!null_time(info->setattre.in.write_time)) {
321 unix_to_nt_time(&newstats.dos.write_time, info->setattre.in.write_time);
325 case RAW_SFILEINFO_EA_SET:
326 return pvfs_setfileinfo_ea_set(pvfs, h->name, h->fd,
327 info->ea_set.in.num_eas,
328 info->ea_set.in.eas);
330 case RAW_SFILEINFO_BASIC_INFO:
331 case RAW_SFILEINFO_BASIC_INFORMATION:
332 if (!null_nttime(info->basic_info.in.create_time)) {
333 newstats.dos.create_time = info->basic_info.in.create_time;
335 if (!null_nttime(info->basic_info.in.access_time)) {
336 newstats.dos.access_time = info->basic_info.in.access_time;
338 if (!null_nttime(info->basic_info.in.write_time)) {
339 newstats.dos.write_time = info->basic_info.in.write_time;
340 newstats.dos.flags |= XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME;
341 h->sticky_write_time = true;
343 if (!null_nttime(info->basic_info.in.change_time)) {
344 newstats.dos.change_time = info->basic_info.in.change_time;
346 if (info->basic_info.in.attrib != 0) {
347 newstats.dos.attrib = info->basic_info.in.attrib;
351 case RAW_SFILEINFO_DISPOSITION_INFO:
352 case RAW_SFILEINFO_DISPOSITION_INFORMATION:
353 return pvfs_set_delete_on_close(pvfs, req, f,
354 info->disposition_info.in.delete_on_close);
356 case RAW_SFILEINFO_ALLOCATION_INFO:
357 case RAW_SFILEINFO_ALLOCATION_INFORMATION:
358 status = pvfs_break_level2_oplocks(f);
359 NT_STATUS_NOT_OK_RETURN(status);
361 newstats.dos.alloc_size = info->allocation_info.in.alloc_size;
362 if (newstats.dos.alloc_size < newstats.st.st_size) {
363 newstats.st.st_size = newstats.dos.alloc_size;
365 newstats.dos.alloc_size = pvfs_round_alloc_size(pvfs,
366 newstats.dos.alloc_size);
369 case RAW_SFILEINFO_END_OF_FILE_INFO:
370 case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
371 status = pvfs_break_level2_oplocks(f);
372 NT_STATUS_NOT_OK_RETURN(status);
374 newstats.st.st_size = info->end_of_file_info.in.size;
377 case RAW_SFILEINFO_POSITION_INFORMATION:
378 h->position = info->position_information.in.position;
381 case RAW_SFILEINFO_MODE_INFORMATION:
382 /* this one is a puzzle */
383 if (info->mode_information.in.mode != 0 &&
384 info->mode_information.in.mode != 2 &&
385 info->mode_information.in.mode != 4 &&
386 info->mode_information.in.mode != 6) {
387 return NT_STATUS_INVALID_PARAMETER;
389 h->mode = info->mode_information.in.mode;
392 case RAW_SFILEINFO_RENAME_INFORMATION:
393 case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
394 return pvfs_setfileinfo_rename(pvfs, req, h->name,
397 case RAW_SFILEINFO_SEC_DESC:
398 notify_trigger(pvfs->notify_context,
399 NOTIFY_ACTION_MODIFIED,
400 FILE_NOTIFY_CHANGE_SECURITY,
402 return pvfs_acl_set(pvfs, req, h->name, h->fd, f->access_mask, info);
405 return NT_STATUS_INVALID_LEVEL;
408 /* possibly change the file size */
409 if (newstats.st.st_size != h->name->st.st_size) {
410 if (h->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
411 return NT_STATUS_FILE_IS_A_DIRECTORY;
413 if (h->name->stream_name) {
414 status = pvfs_stream_truncate(pvfs, h->name, h->fd, newstats.st.st_size);
415 if (!NT_STATUS_IS_OK(status)) {
419 change_mask |= FILE_NOTIFY_CHANGE_STREAM_SIZE;
423 (SEC_FILE_WRITE_DATA|SEC_FILE_APPEND_DATA)) {
424 ret = ftruncate(h->fd, newstats.st.st_size);
426 ret = truncate(h->name->full_name, newstats.st.st_size);
429 return pvfs_map_errno(pvfs, errno);
431 change_mask |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
435 /* possibly change the file timestamps */
436 ZERO_STRUCT(unix_times);
437 if (newstats.dos.create_time != h->name->dos.create_time) {
438 change_mask |= FILE_NOTIFY_CHANGE_CREATION;
440 if (newstats.dos.access_time != h->name->dos.access_time) {
441 unix_times.actime = nt_time_to_unix(newstats.dos.access_time);
442 change_mask |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
444 if (newstats.dos.write_time != h->name->dos.write_time) {
445 unix_times.modtime = nt_time_to_unix(newstats.dos.write_time);
446 change_mask |= FILE_NOTIFY_CHANGE_LAST_WRITE;
448 if (unix_times.actime != 0 || unix_times.modtime != 0) {
449 if (utime(h->name->full_name, &unix_times) == -1) {
450 return pvfs_map_errno(pvfs, errno);
454 /* possibly change the attribute */
455 if (newstats.dos.attrib != h->name->dos.attrib) {
456 mode_t mode = pvfs_fileperms(pvfs, newstats.dos.attrib);
457 if (!(h->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
458 if (fchmod(h->fd, mode) == -1) {
459 return pvfs_map_errno(pvfs, errno);
462 change_mask |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
467 notify_trigger(pvfs->notify_context,
468 NOTIFY_ACTION_MODIFIED,
472 return pvfs_dosattrib_save(pvfs, h->name, h->fd);
476 retry an open after a sharing violation
478 static void pvfs_retry_setpathinfo(struct pvfs_odb_retry *r,
479 struct ntvfs_module_context *ntvfs,
480 struct ntvfs_request *req,
483 enum pvfs_wait_notice reason)
485 union smb_setfileinfo *info = talloc_get_type(_info,
486 union smb_setfileinfo);
487 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
492 case PVFS_WAIT_CANCEL:
494 status = NT_STATUS_CANCELLED;
496 case PVFS_WAIT_TIMEOUT:
497 /* if it timed out, then give the failure
500 status = NT_STATUS_SHARING_VIOLATION;
502 case PVFS_WAIT_EVENT:
504 /* try the open again, which could trigger another retry setup
505 if it wants to, so we have to unmark the async flag so we
506 will know if it does a second async reply */
507 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
509 status = pvfs_setpathinfo(ntvfs, req, info);
510 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
511 /* the 2nd try also replied async, so we don't send
516 /* re-mark it async, just in case someone up the chain does
518 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
522 /* send the reply up the chain */
523 req->async_states->status = status;
524 req->async_states->send_fn(req);
528 setup for a unlink retry after a sharing violation
529 or a non granted oplock
531 static NTSTATUS pvfs_setpathinfo_setup_retry(struct ntvfs_module_context *ntvfs,
532 struct ntvfs_request *req,
533 union smb_setfileinfo *info,
534 struct odb_lock *lck,
537 struct pvfs_state *pvfs = ntvfs->private_data;
538 struct timeval end_time;
540 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
541 end_time = timeval_add(&req->statistics.request_time,
542 0, pvfs->sharing_violation_delay);
543 } else if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
544 end_time = timeval_add(&req->statistics.request_time,
545 pvfs->oplock_break_timeout, 0);
547 return NT_STATUS_INTERNAL_ERROR;
550 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, info, NULL,
551 pvfs_retry_setpathinfo);
555 set info on a pathname
557 NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
558 struct ntvfs_request *req, union smb_setfileinfo *info)
560 struct pvfs_state *pvfs = ntvfs->private_data;
561 struct pvfs_filename *name;
562 struct pvfs_filename newstats;
564 struct utimbuf unix_times;
565 uint32_t access_needed;
566 uint32_t change_mask = 0;
567 struct odb_lock *lck = NULL;
569 /* resolve the cifs name to a posix name */
570 status = pvfs_resolve_name(pvfs, req, info->generic.in.file.path,
571 PVFS_RESOLVE_STREAMS, &name);
572 if (!NT_STATUS_IS_OK(status)) {
577 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
580 access_needed = pvfs_setfileinfo_access(info);
581 status = pvfs_access_check_simple(pvfs, req, name, access_needed);
582 if (!NT_STATUS_IS_OK(status)) {
586 /* we take a copy of the current file stats, then update
587 newstats in each of the elements below. At the end we
588 compare, and make any changes needed */
591 switch (info->generic.level) {
592 case RAW_SFILEINFO_SETATTR:
593 if (!null_time(info->setattr.in.write_time)) {
594 unix_to_nt_time(&newstats.dos.write_time, info->setattr.in.write_time);
596 if (info->setattr.in.attrib == 0) {
597 newstats.dos.attrib = FILE_ATTRIBUTE_NORMAL;
598 } else if (info->setattr.in.attrib != FILE_ATTRIBUTE_NORMAL) {
599 newstats.dos.attrib = info->setattr.in.attrib;
603 case RAW_SFILEINFO_SETATTRE:
604 case RAW_SFILEINFO_STANDARD:
605 if (!null_time(info->setattre.in.create_time)) {
606 unix_to_nt_time(&newstats.dos.create_time, info->setattre.in.create_time);
608 if (!null_time(info->setattre.in.access_time)) {
609 unix_to_nt_time(&newstats.dos.access_time, info->setattre.in.access_time);
611 if (!null_time(info->setattre.in.write_time)) {
612 unix_to_nt_time(&newstats.dos.write_time, info->setattre.in.write_time);
616 case RAW_SFILEINFO_EA_SET:
617 return pvfs_setfileinfo_ea_set(pvfs, name, -1,
618 info->ea_set.in.num_eas,
619 info->ea_set.in.eas);
621 case RAW_SFILEINFO_BASIC_INFO:
622 case RAW_SFILEINFO_BASIC_INFORMATION:
623 if (!null_nttime(info->basic_info.in.create_time)) {
624 newstats.dos.create_time = info->basic_info.in.create_time;
626 if (!null_nttime(info->basic_info.in.access_time)) {
627 newstats.dos.access_time = info->basic_info.in.access_time;
629 if (!null_nttime(info->basic_info.in.write_time)) {
630 newstats.dos.write_time = info->basic_info.in.write_time;
632 if (!null_nttime(info->basic_info.in.change_time)) {
633 newstats.dos.change_time = info->basic_info.in.change_time;
635 if (info->basic_info.in.attrib != 0) {
636 newstats.dos.attrib = info->basic_info.in.attrib;
640 case RAW_SFILEINFO_ALLOCATION_INFO:
641 case RAW_SFILEINFO_ALLOCATION_INFORMATION:
642 status = pvfs_can_update_file_size(pvfs, req, name, &lck);
644 * on a sharing violation we need to retry when the file is closed by
645 * the other user, or after 1 second
646 * on a non granted oplock we need to retry when the file is closed by
647 * the other user, or after 30 seconds
649 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
650 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
651 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
652 return pvfs_setpathinfo_setup_retry(pvfs->ntvfs, req, info, lck, status);
654 NT_STATUS_NOT_OK_RETURN(status);
656 if (info->allocation_info.in.alloc_size > newstats.dos.alloc_size) {
657 /* strange. Increasing the allocation size via setpathinfo
658 should be silently ignored */
661 newstats.dos.alloc_size = info->allocation_info.in.alloc_size;
662 if (newstats.dos.alloc_size < newstats.st.st_size) {
663 newstats.st.st_size = newstats.dos.alloc_size;
665 newstats.dos.alloc_size = pvfs_round_alloc_size(pvfs,
666 newstats.dos.alloc_size);
669 case RAW_SFILEINFO_END_OF_FILE_INFO:
670 case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
671 status = pvfs_can_update_file_size(pvfs, req, name, &lck);
673 * on a sharing violation we need to retry when the file is closed by
674 * the other user, or after 1 second
675 * on a non granted oplock we need to retry when the file is closed by
676 * the other user, or after 30 seconds
678 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
679 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
680 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
681 return pvfs_setpathinfo_setup_retry(pvfs->ntvfs, req, info, lck, status);
683 NT_STATUS_NOT_OK_RETURN(status);
685 newstats.st.st_size = info->end_of_file_info.in.size;
688 case RAW_SFILEINFO_MODE_INFORMATION:
689 if (info->mode_information.in.mode != 0 &&
690 info->mode_information.in.mode != 2 &&
691 info->mode_information.in.mode != 4 &&
692 info->mode_information.in.mode != 6) {
693 return NT_STATUS_INVALID_PARAMETER;
697 case RAW_SFILEINFO_RENAME_INFORMATION:
698 case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
699 return pvfs_setfileinfo_rename(pvfs, req, name,
702 case RAW_SFILEINFO_DISPOSITION_INFO:
703 case RAW_SFILEINFO_DISPOSITION_INFORMATION:
704 case RAW_SFILEINFO_POSITION_INFORMATION:
708 return NT_STATUS_INVALID_LEVEL;
711 /* possibly change the file size */
712 if (newstats.st.st_size != name->st.st_size) {
713 if (name->stream_name) {
714 status = pvfs_stream_truncate(pvfs, name, -1, newstats.st.st_size);
715 if (!NT_STATUS_IS_OK(status)) {
718 } else if (truncate(name->full_name, newstats.st.st_size) == -1) {
719 return pvfs_map_errno(pvfs, errno);
721 change_mask |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
724 /* possibly change the file timestamps */
725 ZERO_STRUCT(unix_times);
726 if (newstats.dos.create_time != name->dos.create_time) {
727 change_mask |= FILE_NOTIFY_CHANGE_CREATION;
729 if (newstats.dos.access_time != name->dos.access_time) {
730 unix_times.actime = nt_time_to_unix(newstats.dos.access_time);
731 change_mask |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
733 if (newstats.dos.write_time != name->dos.write_time) {
734 unix_times.modtime = nt_time_to_unix(newstats.dos.write_time);
735 change_mask |= FILE_NOTIFY_CHANGE_LAST_WRITE;
737 if (unix_times.actime != 0 || unix_times.modtime != 0) {
738 if (utime(name->full_name, &unix_times) == -1) {
739 return pvfs_map_errno(pvfs, errno);
743 /* possibly change the attribute */
744 newstats.dos.attrib |= (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY);
745 if (newstats.dos.attrib != name->dos.attrib) {
746 mode_t mode = pvfs_fileperms(pvfs, newstats.dos.attrib);
747 if (chmod(name->full_name, mode) == -1) {
748 return pvfs_map_errno(pvfs, errno);
750 change_mask |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
755 if (change_mask != 0) {
756 notify_trigger(pvfs->notify_context,
757 NOTIFY_ACTION_MODIFIED,
762 return pvfs_dosattrib_save(pvfs, name, -1);