/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- set_sparse_flag
- set_link_read_only_flag
- unix_mode
- dos_mode_from_sbuf
- get_ea_dos_attribute
- set_ea_dos_attribute
- dos_mode_msdfs
- dos_attributes_to_stat_dos_flags
- get_stat_dos_flags
- set_stat_dos_flags
- dos_mode
- file_set_dosmode
- file_ntimes
- set_sticky_write_time_path
- set_sticky_write_time_fsp
- update_write_time
1 /*
2 Unix SMB/CIFS implementation.
3 dos mode handling functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) James Peach 2006
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22
23 static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
/* [<][>][^][v][top][bottom][index][help] */
24 {
25 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
26 if (sbuf->st_size > sbuf->st_blocks * (SMB_OFF_T)STAT_ST_BLOCKSIZE) {
27 return FILE_ATTRIBUTE_SPARSE;
28 }
29 #endif
30 return 0;
31 }
32
33 static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
/* [<][>][^][v][top][bottom][index][help] */
34 {
35 #ifdef S_ISLNK
36 #if LINKS_READ_ONLY
37 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
38 return aRONLY;
39 #endif
40 #endif
41 return 0;
42 }
43
44 /****************************************************************************
45 Change a dos mode to a unix mode.
46 Base permission for files:
47 if creating file and inheriting (i.e. parent_dir != NULL)
48 apply read/write bits from parent directory.
49 else
50 everybody gets read bit set
51 dos readonly is represented in unix by removing everyone's write bit
52 dos archive is represented in unix by the user's execute bit
53 dos system is represented in unix by the group's execute bit
54 dos hidden is represented in unix by the other's execute bit
55 if !inheriting {
56 Then apply create mask,
57 then add force bits.
58 }
59 Base permission for directories:
60 dos directory is represented in unix by unix's dir bit and the exec bit
61 if !inheriting {
62 Then apply create mask,
63 then add force bits.
64 }
65 ****************************************************************************/
66
67 mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname,
/* [<][>][^][v][top][bottom][index][help] */
68 const char *inherit_from_dir)
69 {
70 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
71 mode_t dir_mode = 0; /* Mode of the inherit_from directory if
72 * inheriting. */
73
74 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
75 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
76 }
77
78 if (fname && (inherit_from_dir != NULL)
79 && lp_inherit_perms(SNUM(conn))) {
80 SMB_STRUCT_STAT sbuf;
81
82 DEBUG(2, ("unix_mode(%s) inheriting from %s\n", fname,
83 inherit_from_dir));
84 if (SMB_VFS_STAT(conn, inherit_from_dir, &sbuf) != 0) {
85 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n", fname,
86 inherit_from_dir, strerror(errno)));
87 return(0); /* *** shouldn't happen! *** */
88 }
89
90 /* Save for later - but explicitly remove setuid bit for safety. */
91 dir_mode = sbuf.st_mode & ~S_ISUID;
92 DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode));
93 /* Clear "result" */
94 result = 0;
95 }
96
97 if (IS_DOS_DIR(dosmode)) {
98 /* We never make directories read only for the owner as under DOS a user
99 can always create a file in a read-only directory. */
100 result |= (S_IFDIR | S_IWUSR);
101
102 if (dir_mode) {
103 /* Inherit mode of parent directory. */
104 result |= dir_mode;
105 } else {
106 /* Provisionally add all 'x' bits */
107 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
108
109 /* Apply directory mask */
110 result &= lp_dir_mask(SNUM(conn));
111 /* Add in force bits */
112 result |= lp_force_dir_mode(SNUM(conn));
113 }
114 } else {
115 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
116 result |= S_IXUSR;
117
118 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
119 result |= S_IXGRP;
120
121 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
122 result |= S_IXOTH;
123
124 if (dir_mode) {
125 /* Inherit 666 component of parent directory mode */
126 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
127 } else {
128 /* Apply mode mask */
129 result &= lp_create_mask(SNUM(conn));
130 /* Add in force bits */
131 result |= lp_force_create_mode(SNUM(conn));
132 }
133 }
134
135 DEBUG(3,("unix_mode(%s) returning 0%o\n",fname,(int)result ));
136 return(result);
137 }
138
139 /****************************************************************************
140 Change a unix mode to a dos mode.
141 ****************************************************************************/
142
143 static uint32 dos_mode_from_sbuf(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
/* [<][>][^][v][top][bottom][index][help] */
144 {
145 int result = 0;
146 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
147
148 if (ro_opts == MAP_READONLY_YES) {
149 /* Original Samba method - map inverse of user "w" bit. */
150 if ((sbuf->st_mode & S_IWUSR) == 0) {
151 result |= aRONLY;
152 }
153 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
154 /* Check actual permissions for read-only. */
155 if (!can_write_to_file(conn, path, sbuf)) {
156 result |= aRONLY;
157 }
158 } /* Else never set the readonly bit. */
159
160 if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0))
161 result |= aARCH;
162
163 if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0))
164 result |= aSYSTEM;
165
166 if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0))
167 result |= aHIDDEN;
168
169 if (S_ISDIR(sbuf->st_mode))
170 result = aDIR | (result & aRONLY);
171
172 result |= set_sparse_flag(sbuf);
173 result |= set_link_read_only_flag(sbuf);
174
175 DEBUG(8,("dos_mode_from_sbuf returning "));
176
177 if (result & aHIDDEN) DEBUG(8, ("h"));
178 if (result & aRONLY ) DEBUG(8, ("r"));
179 if (result & aSYSTEM) DEBUG(8, ("s"));
180 if (result & aDIR ) DEBUG(8, ("d"));
181 if (result & aARCH ) DEBUG(8, ("a"));
182
183 DEBUG(8,("\n"));
184 return result;
185 }
186
187 /****************************************************************************
188 Get DOS attributes from an EA.
189 ****************************************************************************/
190
191 static bool get_ea_dos_attribute(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf, uint32 *pattr)
/* [<][>][^][v][top][bottom][index][help] */
192 {
193 ssize_t sizeret;
194 fstring attrstr;
195 unsigned int dosattr;
196
197 if (!lp_store_dos_attributes(SNUM(conn))) {
198 return False;
199 }
200
201 /* Don't reset pattr to zero as we may already have filename-based attributes we
202 need to preserve. */
203
204 sizeret = SMB_VFS_GETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, sizeof(attrstr));
205 if (sizeret == -1) {
206 if (errno == ENOSYS
207 #if defined(ENOTSUP)
208 || errno == ENOTSUP) {
209 #else
210 ) {
211 #endif
212 DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n",
213 path, strerror(errno) ));
214 set_store_dos_attributes(SNUM(conn), False);
215 }
216 return False;
217 }
218 /* Null terminate string. */
219 attrstr[sizeret] = 0;
220 DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path, attrstr));
221
222 if (sizeret < 2 || attrstr[0] != '0' || attrstr[1] != 'x' ||
223 sscanf(attrstr, "%x", &dosattr) != 1) {
224 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path, attrstr));
225 return False;
226 }
227
228 if (S_ISDIR(sbuf->st_mode)) {
229 dosattr |= aDIR;
230 }
231 *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK);
232
233 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
234
235 if (dosattr & aHIDDEN) DEBUG(8, ("h"));
236 if (dosattr & aRONLY ) DEBUG(8, ("r"));
237 if (dosattr & aSYSTEM) DEBUG(8, ("s"));
238 if (dosattr & aDIR ) DEBUG(8, ("d"));
239 if (dosattr & aARCH ) DEBUG(8, ("a"));
240
241 DEBUG(8,("\n"));
242
243 return True;
244 }
245
246 /****************************************************************************
247 Set DOS attributes in an EA.
248 ****************************************************************************/
249
250 static bool set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, uint32 dosmode)
/* [<][>][^][v][top][bottom][index][help] */
251 {
252 fstring attrstr;
253 files_struct *fsp = NULL;
254 bool ret = False;
255
256 if (!lp_store_dos_attributes(SNUM(conn))) {
257 return False;
258 }
259
260 snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK);
261 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) {
262 if((errno != EPERM) && (errno != EACCES)) {
263 if (errno == ENOSYS
264 #if defined(ENOTSUP)
265 || errno == ENOTSUP) {
266 #else
267 ) {
268 #endif
269 DEBUG(1,("set_ea_dos_attributes: Cannot set attribute EA on file %s: Error = %s\n",
270 path, strerror(errno) ));
271 set_store_dos_attributes(SNUM(conn), False);
272 }
273 return False;
274 }
275
276 /* We want DOS semantics, ie allow non owner with write permission to change the
277 bits on a file. Just like file_ntimes below.
278 */
279
280 /* Check if we have write access. */
281 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
282 return False;
283
284 /*
285 * We need to open the file with write access whilst
286 * still in our current user context. This ensures we
287 * are not violating security in doing the setxattr.
288 */
289
290 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, path, sbuf,
291 &fsp)))
292 return ret;
293 become_root();
294 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == 0) {
295 ret = True;
296 }
297 unbecome_root();
298 close_file_fchmod(NULL, fsp);
299 return ret;
300 }
301 DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, path));
302 return True;
303 }
304
305 /****************************************************************************
306 Change a unix mode to a dos mode for an ms dfs link.
307 ****************************************************************************/
308
309 uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
/* [<][>][^][v][top][bottom][index][help] */
310 {
311 uint32 result = 0;
312
313 DEBUG(8,("dos_mode_msdfs: %s\n", path));
314
315 if (!VALID_STAT(*sbuf)) {
316 return 0;
317 }
318
319 /* First do any modifications that depend on the path name. */
320 /* hide files with a name starting with a . */
321 if (lp_hide_dot_files(SNUM(conn))) {
322 const char *p = strrchr_m(path,'/');
323 if (p) {
324 p++;
325 } else {
326 p = path;
327 }
328
329 /* Only . and .. are not hidden. */
330 if (p[0] == '.' && !((p[1] == '\0') ||
331 (p[1] == '.' && p[2] == '\0'))) {
332 result |= aHIDDEN;
333 }
334 }
335
336 result |= dos_mode_from_sbuf(conn, path, sbuf);
337
338 /* Optimization : Only call is_hidden_path if it's not already
339 hidden. */
340 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
341 result |= aHIDDEN;
342 }
343
344 DEBUG(8,("dos_mode_msdfs returning "));
345
346 if (result & aHIDDEN) DEBUG(8, ("h"));
347 if (result & aRONLY ) DEBUG(8, ("r"));
348 if (result & aSYSTEM) DEBUG(8, ("s"));
349 if (result & aDIR ) DEBUG(8, ("d"));
350 if (result & aARCH ) DEBUG(8, ("a"));
351 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
352
353 DEBUG(8,("\n"));
354
355 return(result);
356 }
357
358 #ifdef HAVE_STAT_DOS_FLAGS
359 /****************************************************************************
360 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
361 ****************************************************************************/
362
363 int dos_attributes_to_stat_dos_flags(uint32_t dosmode)
/* [<][>][^][v][top][bottom][index][help] */
364 {
365 uint32_t dos_stat_flags = 0;
366
367 if (dosmode & aARCH)
368 dos_stat_flags |= UF_DOS_ARCHIVE;
369 if (dosmode & aHIDDEN)
370 dos_stat_flags |= UF_DOS_HIDDEN;
371 if (dosmode & aRONLY)
372 dos_stat_flags |= UF_DOS_RO;
373 if (dosmode & aSYSTEM)
374 dos_stat_flags |= UF_DOS_SYSTEM;
375 if (dosmode & FILE_ATTRIBUTE_NONINDEXED)
376 dos_stat_flags |= UF_DOS_NOINDEX;
377
378 return dos_stat_flags;
379 }
380
381 /****************************************************************************
382 Gets DOS attributes, accessed via st_flags in the stat struct.
383 ****************************************************************************/
384
385 static bool get_stat_dos_flags(connection_struct *conn,
/* [<][>][^][v][top][bottom][index][help] */
386 const char *fname,
387 const SMB_STRUCT_STAT *sbuf,
388 uint32_t *dosmode)
389 {
390 SMB_ASSERT(sbuf && VALID_STAT(*sbuf));
391 SMB_ASSERT(dosmode);
392
393 if (!lp_store_dos_attributes(SNUM(conn))) {
394 return false;
395 }
396
397 DEBUG(5, ("Getting stat dos attributes for %s.\n", fname));
398
399 if (sbuf->st_flags & UF_DOS_ARCHIVE)
400 *dosmode |= aARCH;
401 if (sbuf->st_flags & UF_DOS_HIDDEN)
402 *dosmode |= aHIDDEN;
403 if (sbuf->st_flags & UF_DOS_RO)
404 *dosmode |= aRONLY;
405 if (sbuf->st_flags & UF_DOS_SYSTEM)
406 *dosmode |= aSYSTEM;
407 if (sbuf->st_flags & UF_DOS_NOINDEX)
408 *dosmode |= FILE_ATTRIBUTE_NONINDEXED;
409 if (S_ISDIR(sbuf->st_mode))
410 *dosmode |= aDIR;
411
412 *dosmode |= set_sparse_flag(sbuf);
413 *dosmode |= set_link_read_only_flag(sbuf);
414
415 return true;
416 }
417
418 /****************************************************************************
419 Sets DOS attributes, stored in st_flags of the inode.
420 ****************************************************************************/
421
422 static bool set_stat_dos_flags(connection_struct *conn,
/* [<][>][^][v][top][bottom][index][help] */
423 const char *fname,
424 SMB_STRUCT_STAT *sbuf,
425 uint32_t dosmode,
426 bool *attributes_changed)
427 {
428 uint32_t new_flags = 0;
429 int error = 0;
430
431 SMB_ASSERT(sbuf && VALID_STAT(*sbuf));
432 SMB_ASSERT(attributes_changed);
433
434 *attributes_changed = false;
435
436 if (!lp_store_dos_attributes(SNUM(conn))) {
437 return false;
438 }
439
440 DEBUG(5, ("Setting stat dos attributes for %s.\n", fname));
441
442 new_flags = (sbuf->st_flags & ~UF_DOS_FLAGS) |
443 dos_attributes_to_stat_dos_flags(dosmode);
444
445 /* Return early if no flags changed. */
446 if (new_flags == sbuf->st_flags)
447 return true;
448
449 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags,
450 sbuf->st_flags));
451
452 /* Set new flags with chflags. */
453 error = SMB_VFS_CHFLAGS(conn, fname, new_flags);
454 if (error) {
455 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
456 "file %s! errno=%d\n", new_flags, fname, errno));
457 return false;
458 }
459
460 *attributes_changed = true;
461 return true;
462 }
463 #endif /* HAVE_STAT_DOS_FLAGS */
464
465 /****************************************************************************
466 Change a unix mode to a dos mode.
467 ****************************************************************************/
468
469 uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
/* [<][>][^][v][top][bottom][index][help] */
470 {
471 uint32 result = 0;
472 bool offline, used_stat_dos_flags = false;
473
474 DEBUG(8,("dos_mode: %s\n", path));
475
476 if (!VALID_STAT(*sbuf)) {
477 return 0;
478 }
479
480 /* First do any modifications that depend on the path name. */
481 /* hide files with a name starting with a . */
482 if (lp_hide_dot_files(SNUM(conn))) {
483 const char *p = strrchr_m(path,'/');
484 if (p) {
485 p++;
486 } else {
487 p = path;
488 }
489
490 /* Only . and .. are not hidden. */
491 if (p[0] == '.' && !((p[1] == '\0') ||
492 (p[1] == '.' && p[2] == '\0'))) {
493 result |= aHIDDEN;
494 }
495 }
496
497 #ifdef HAVE_STAT_DOS_FLAGS
498 used_stat_dos_flags = get_stat_dos_flags(conn, path, sbuf, &result);
499 #endif
500 if (!used_stat_dos_flags) {
501 /* Get the DOS attributes from an EA by preference. */
502 if (get_ea_dos_attribute(conn, path, sbuf, &result)) {
503 result |= set_sparse_flag(sbuf);
504 } else {
505 result |= dos_mode_from_sbuf(conn, path, sbuf);
506 }
507 }
508
509
510 offline = SMB_VFS_IS_OFFLINE(conn, path, sbuf);
511 if (S_ISREG(sbuf->st_mode) && offline) {
512 result |= FILE_ATTRIBUTE_OFFLINE;
513 }
514
515 /* Optimization : Only call is_hidden_path if it's not already
516 hidden. */
517 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
518 result |= aHIDDEN;
519 }
520
521 DEBUG(8,("dos_mode returning "));
522
523 if (result & aHIDDEN) DEBUG(8, ("h"));
524 if (result & aRONLY ) DEBUG(8, ("r"));
525 if (result & aSYSTEM) DEBUG(8, ("s"));
526 if (result & aDIR ) DEBUG(8, ("d"));
527 if (result & aARCH ) DEBUG(8, ("a"));
528 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
529
530 DEBUG(8,("\n"));
531
532 return(result);
533 }
534
535 /*******************************************************************
536 chmod a file - but preserve some bits.
537 ********************************************************************/
538
539 int file_set_dosmode(connection_struct *conn, const char *fname,
/* [<][>][^][v][top][bottom][index][help] */
540 uint32 dosmode, SMB_STRUCT_STAT *st,
541 const char *parent_dir,
542 bool newfile)
543 {
544 SMB_STRUCT_STAT st1;
545 int mask=0;
546 mode_t tmp;
547 mode_t unixmode;
548 int ret = -1, lret = -1;
549 uint32_t old_mode;
550
551 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
552 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
553
554 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname));
555
556 if (st == NULL) {
557 SET_STAT_INVALID(st1);
558 st = &st1;
559 }
560
561 if (!VALID_STAT(*st)) {
562 if (SMB_VFS_STAT(conn,fname,st))
563 return(-1);
564 }
565
566 unixmode = st->st_mode;
567
568 get_acl_group_bits(conn, fname, &st->st_mode);
569
570 if (S_ISDIR(st->st_mode))
571 dosmode |= aDIR;
572 else
573 dosmode &= ~aDIR;
574
575 old_mode = dos_mode(conn,fname,st);
576
577 if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
578 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
579 lret = SMB_VFS_SET_OFFLINE(conn, fname);
580 if (lret == -1) {
581 DEBUG(0, ("set_dos_mode: client has asked to set "
582 "FILE_ATTRIBUTE_OFFLINE to %s/%s but there was "
583 "an error while setting it or it is not supported.\n",
584 parent_dir, fname));
585 }
586 }
587 }
588
589 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
590 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
591
592 if (old_mode == dosmode) {
593 st->st_mode = unixmode;
594 return(0);
595 }
596
597 #ifdef HAVE_STAT_DOS_FLAGS
598 {
599 bool attributes_changed;
600
601 if (set_stat_dos_flags(conn, fname, st, dosmode,
602 &attributes_changed))
603 {
604 if (!newfile && attributes_changed) {
605 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
606 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
607 }
608 st->st_mode = unixmode;
609 return 0;
610 }
611 }
612 #endif
613
614 /* Store the DOS attributes in an EA by preference. */
615 if (set_ea_dos_attribute(conn, fname, st, dosmode)) {
616 if (!newfile) {
617 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
618 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
619 }
620 st->st_mode = unixmode;
621 return 0;
622 }
623
624 unixmode = unix_mode(conn,dosmode,fname, parent_dir);
625
626 /* preserve the s bits */
627 mask |= (S_ISUID | S_ISGID);
628
629 /* preserve the t bit */
630 #ifdef S_ISVTX
631 mask |= S_ISVTX;
632 #endif
633
634 /* possibly preserve the x bits */
635 if (!MAP_ARCHIVE(conn))
636 mask |= S_IXUSR;
637 if (!MAP_SYSTEM(conn))
638 mask |= S_IXGRP;
639 if (!MAP_HIDDEN(conn))
640 mask |= S_IXOTH;
641
642 unixmode |= (st->st_mode & mask);
643
644 /* if we previously had any r bits set then leave them alone */
645 if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
646 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
647 unixmode |= tmp;
648 }
649
650 /* if we previously had any w bits set then leave them alone
651 whilst adding in the new w bits, if the new mode is not rdonly */
652 if (!IS_DOS_READONLY(dosmode)) {
653 unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
654 }
655
656 ret = SMB_VFS_CHMOD(conn, fname, unixmode);
657 if (ret == 0) {
658 if(!newfile || (lret != -1)) {
659 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
660 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
661 }
662 st->st_mode = unixmode;
663 return 0;
664 }
665
666 if((errno != EPERM) && (errno != EACCES))
667 return -1;
668
669 if(!lp_dos_filemode(SNUM(conn)))
670 return -1;
671
672 /* We want DOS semantics, ie allow non owner with write permission to change the
673 bits on a file. Just like file_ntimes below.
674 */
675
676 /* Check if we have write access. */
677 if (CAN_WRITE(conn)) {
678 /*
679 * We need to open the file with write access whilst
680 * still in our current user context. This ensures we
681 * are not violating security in doing the fchmod.
682 * This file open does *not* break any oplocks we are
683 * holding. We need to review this.... may need to
684 * break batch oplocks open by others. JRA.
685 */
686 files_struct *fsp;
687 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, fname, st,
688 &fsp)))
689 return -1;
690 become_root();
691 ret = SMB_VFS_FCHMOD(fsp, unixmode);
692 unbecome_root();
693 close_file_fchmod(NULL, fsp);
694 if (!newfile) {
695 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
696 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
697 }
698 if (ret == 0) {
699 st->st_mode = unixmode;
700 }
701 }
702
703 return( ret );
704 }
705
706 /*******************************************************************
707 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
708 than POSIX.
709 *******************************************************************/
710
711 int file_ntimes(connection_struct *conn, const char *fname,
/* [<][>][^][v][top][bottom][index][help] */
712 struct smb_file_time *ft)
713 {
714 SMB_STRUCT_STAT sbuf;
715 int ret = -1;
716
717 errno = 0;
718 ZERO_STRUCT(sbuf);
719
720 DEBUG(6, ("file_ntime: actime: %s",
721 time_to_asc(convert_timespec_to_time_t(ft->atime))));
722 DEBUG(6, ("file_ntime: modtime: %s",
723 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
724 DEBUG(6, ("file_ntime: createtime: %s",
725 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
726
727 /* Don't update the time on read-only shares */
728 /* We need this as set_filetime (which can be called on
729 close and other paths) can end up calling this function
730 without the NEED_WRITE protection. Found by :
731 Leo Weppelman <leo@wau.mis.ah.nl>
732 */
733
734 if (!CAN_WRITE(conn)) {
735 return 0;
736 }
737
738 if(SMB_VFS_NTIMES(conn, fname, ft) == 0) {
739 return 0;
740 }
741
742 if((errno != EPERM) && (errno != EACCES)) {
743 return -1;
744 }
745
746 if(!lp_dos_filetimes(SNUM(conn))) {
747 return -1;
748 }
749
750 /* We have permission (given by the Samba admin) to
751 break POSIX semantics and allow a user to change
752 the time on a file they don't own but can write to
753 (as DOS does).
754 */
755
756 /* Check if we have write access. */
757 if (can_write_to_file(conn, fname, &sbuf)) {
758 /* We are allowed to become root and change the filetime. */
759 become_root();
760 ret = SMB_VFS_NTIMES(conn, fname, ft);
761 unbecome_root();
762 }
763
764 return ret;
765 }
766
767 /******************************************************************
768 Force a "sticky" write time on a pathname. This will always be
769 returned on all future write time queries and set on close.
770 ******************************************************************/
771
772 bool set_sticky_write_time_path(connection_struct *conn, const char *fname,
/* [<][>][^][v][top][bottom][index][help] */
773 struct file_id fileid, const struct timespec mtime)
774 {
775 if (null_timespec(mtime)) {
776 return true;
777 }
778
779 if (!set_sticky_write_time(fileid, mtime)) {
780 return false;
781 }
782
783 return true;
784 }
785
786 /******************************************************************
787 Force a "sticky" write time on an fsp. This will always be
788 returned on all future write time queries and set on close.
789 ******************************************************************/
790
791 bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime)
/* [<][>][^][v][top][bottom][index][help] */
792 {
793 fsp->write_time_forced = true;
794 TALLOC_FREE(fsp->update_write_time_event);
795
796 return set_sticky_write_time_path(fsp->conn, fsp->fsp_name,
797 fsp->file_id, mtime);
798 }
799
800 /******************************************************************
801 Update a write time immediately, without the 2 second delay.
802 ******************************************************************/
803
804 bool update_write_time(struct files_struct *fsp)
/* [<][>][^][v][top][bottom][index][help] */
805 {
806 if (!set_write_time(fsp->file_id, timespec_current())) {
807 return false;
808 }
809
810 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
811 FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name);
812
813 return true;
814 }