4 Установка атрибутов файлов
7 Copyright (c) 1996 Eugene Roshal
8 Copyright (c) 2000 Far Group
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions
14 1. Redistributions of source code must retain the above copyright
15 notice, this list of conditions and the following disclaimer.
16 2. Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in the
18 documentation and/or other materials provided with the distribution.
19 3. The name of the authors may not be used to endorse or promote products
20 derived from this software without specific prior written permission.
22 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "headers.hpp"
36 #include <set> // for std::set
37 #include <pwd.h> // for getpwent()
38 #include <grp.h> // for getgrent()
42 #include "chgprior.hpp"
43 #include "scantree.hpp"
44 #include "filepanels.hpp"
46 #include "ctrlobj.hpp"
47 #include "constitle.hpp"
48 #include "TPreRedrawFunc.hpp"
49 #include "keyboard.hpp"
50 #include "message.hpp"
52 #include "datetime.hpp"
53 #include "fileattr.hpp"
54 #include "setattr.hpp"
55 #include "pathmix.hpp"
57 #include "fileowner.hpp"
58 #include "wakeful.hpp"
59 #include "DlgGuid.hpp"
60 #include "execute.hpp"
61 #include "FSFileFlags.h"
63 #include "interf.hpp" // for BoxSymbols
65 struct FSFileFlagsSafe
: FSFileFlags
67 FSFileFlagsSafe(const FARString
&path
, DWORD attrs
)
68 : FSFileFlags((attrs
& FILE_ATTRIBUTE_DEVICE
) ? DEVNULL
: path
.GetMB())
80 SA_SEPARATOR_OWNERSHIP
,
90 SA_CHECKBOX_USER_READ
,
91 SA_CHECKBOX_USER_WRITE
,
92 SA_CHECKBOX_USER_EXECUTE
,
94 SA_CHECKBOX_GROUP_READ
,
95 SA_CHECKBOX_GROUP_WRITE
,
96 SA_CHECKBOX_GROUP_EXECUTE
,
98 SA_CHECKBOX_OTHER_READ
,
99 SA_CHECKBOX_OTHER_WRITE
,
100 SA_CHECKBOX_OTHER_EXECUTE
,
106 SA_FIXEDIT_MODE_OCTAL
,
107 SA_BUTTON_MODE_ORIGINAL
,
109 SA_SEPARATOR_ATTRIBUTES
,
110 SA_CHECKBOX_IMMUTABLE
,
112 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
119 SA_FIXEDIT_LAST_ACCESS_DATE
,
120 SA_FIXEDIT_LAST_ACCESS_TIME
,
121 SA_TEXT_LAST_MODIFICATION
,
122 SA_FIXEDIT_LAST_MODIFICATION_DATE
,
123 SA_FIXEDIT_LAST_MODIFICATION_TIME
,
125 SA_FIXEDIT_LAST_CHANGE_DATE
,
126 SA_FIXEDIT_LAST_CHANGE_TIME
,
131 SA_CHECKBOX_SUBFOLDERS
,
137 static const struct MODEPAIR
142 {SA_CHECKBOX_USER_READ
, S_IRUSR
},
143 {SA_CHECKBOX_USER_WRITE
, S_IWUSR
},
144 {SA_CHECKBOX_USER_EXECUTE
, S_IXUSR
},
145 {SA_CHECKBOX_GROUP_READ
, S_IRGRP
},
146 {SA_CHECKBOX_GROUP_WRITE
, S_IWGRP
},
147 {SA_CHECKBOX_GROUP_EXECUTE
, S_IXGRP
},
148 {SA_CHECKBOX_OTHER_READ
, S_IROTH
},
149 {SA_CHECKBOX_OTHER_WRITE
, S_IWOTH
},
150 {SA_CHECKBOX_OTHER_EXECUTE
, S_IXOTH
},
151 {SA_CHECKBOX_SUID
, S_ISUID
},
152 {SA_CHECKBOX_SGID
, S_ISGID
},
153 {SA_CHECKBOX_STICKY
, S_ISVTX
}
156 #define EDITABLE_MODES \
157 (S_IXOTH | S_IWOTH | S_IROTH | S_IXGRP | S_IWGRP | S_IRGRP | S_IXUSR | S_IWUSR | S_IRUSR | S_ISUID \
160 static const int PreserveOriginalIDs
[] = {
161 SA_CHECKBOX_USER_READ
, SA_CHECKBOX_USER_WRITE
, SA_CHECKBOX_USER_EXECUTE
,
162 SA_CHECKBOX_GROUP_READ
, SA_CHECKBOX_GROUP_WRITE
, SA_CHECKBOX_GROUP_EXECUTE
,
163 SA_CHECKBOX_OTHER_READ
, SA_CHECKBOX_OTHER_WRITE
, SA_CHECKBOX_OTHER_EXECUTE
,
164 SA_CHECKBOX_SUID
, SA_CHECKBOX_SGID
, SA_CHECKBOX_STICKY
,
165 SA_CHECKBOX_IMMUTABLE
, SA_CHECKBOX_APPEND
,
166 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
178 struct SetAttrDlgParam
181 DWORD FileSystemFlags
= 0;
182 DIALOGMODE DialogMode
;
183 FARString strSelName
;
186 bool OwnerChanged
= false, GroupChanged
= false;
187 // значения CheckBox`ов на момент старта диалога
188 int OriginalCBAttr
[ARRAYSIZE(PreserveOriginalIDs
)]; // values at dialog start and any user change for restore by subfolders checkbox
189 int OriginalCBAttr0
[ARRAYSIZE(PreserveOriginalIDs
)]; // values at dialog start
190 int OriginalCBAttr2
[ARRAYSIZE(PreserveOriginalIDs
)]; // -1 = original, other = was change
191 DWORD OriginalCBFlag
[ARRAYSIZE(PreserveOriginalIDs
)]; // checkbox flags at dialog start
192 bool _b_mode_check_or_edit_process
= false;
193 FARCHECKEDSTATE OSubfoldersState
;
194 bool OAccessTime
, OModifyTime
, OStatusChangeTime
;
195 unsigned char SymLinkInfoCycle
= 0;
197 FARString SymlinkButtonTitles
[3];
200 #define DM_SETATTR (DM_USER + 1)
202 static int DialogID2PreservedOriginalIndex(int id
)
204 for (size_t i
= 0; i
< ARRAYSIZE(PreserveOriginalIDs
); ++i
) {
205 if (PreserveOriginalIDs
[i
] == id
)
211 static void BlankEditIfChanged(HANDLE hDlg
, int EditControl
, FARString
&Remembered
, bool &Changed
)
213 LPCWSTR Actual
= reinterpret_cast<LPCWSTR
>(SendDlgMessage(hDlg
, DM_GETCONSTTEXTPTR
, EditControl
, 0));
215 Changed
= StrCmp(Actual
, Remembered
) != 0;
220 SendDlgMessage(hDlg
, DM_SETTEXTPTR
, EditControl
, reinterpret_cast<LONG_PTR
>(L
""));
223 static std::wstring
BriefInfo(const FARString
&strSelName
)
225 std::vector
<std::wstring
> lines
;
227 std::string cmd
= "file -- \"";
228 cmd
+= EscapeCmdStr(Wide2MB(strSelName
.CPtr()));
233 if (POpen(lines
, cmd
.c_str())) {
234 for (const auto &line
: lines
) {
236 size_t p
= out
.find(':');
237 if (p
!= std::string::npos
) {
241 if (p
!= std::string::npos
&& !out
.empty()) {
249 static char SetAttrGetBitCharFromModeCheckBoxes(HANDLE hDlg
, int _i1
, int _i2
, int _i3
)
253 i1
= (int)SendDlgMessage(hDlg
, DM_GETCHECK
, _i1
, 0);
254 i2
= (int)SendDlgMessage(hDlg
, DM_GETCHECK
, _i2
, 0);
255 i3
= (int)SendDlgMessage(hDlg
, DM_GETCHECK
, _i3
, 0);
256 if (i1
== BSTATE_3STATE
|| i2
== BSTATE_3STATE
|| i3
== BSTATE_3STATE
)
259 int i
= (i1
== BSTATE_CHECKED
? 1 : 0) + (i2
== BSTATE_CHECKED
? 2 : 0) + (i3
== BSTATE_CHECKED
? 4 : 0);
260 char buffer
[3] = {0};
261 snprintf(buffer
, 2, "%o", i
);
266 static void SetAttrCalcBitsCharFromModeCheckBoxes(HANDLE hDlg
)
268 wchar_t str_octal
[5] = {0};
269 str_octal
[0] = SetAttrGetBitCharFromModeCheckBoxes(hDlg
, SA_CHECKBOX_STICKY
, SA_CHECKBOX_SGID
, SA_CHECKBOX_SUID
);
270 str_octal
[1] = SetAttrGetBitCharFromModeCheckBoxes(hDlg
, SA_CHECKBOX_USER_EXECUTE
, SA_CHECKBOX_USER_WRITE
, SA_CHECKBOX_USER_READ
);
271 str_octal
[2] = SetAttrGetBitCharFromModeCheckBoxes(hDlg
, SA_CHECKBOX_GROUP_EXECUTE
, SA_CHECKBOX_GROUP_WRITE
, SA_CHECKBOX_GROUP_READ
);
272 str_octal
[3] = SetAttrGetBitCharFromModeCheckBoxes(hDlg
, SA_CHECKBOX_OTHER_EXECUTE
, SA_CHECKBOX_OTHER_WRITE
, SA_CHECKBOX_OTHER_READ
);
274 SendDlgMessage(hDlg
, DM_SETTEXTPTR
, SA_FIXEDIT_MODE_OCTAL
, (LONG_PTR
)str_octal
);
277 void SetAttrGetModeCheckBoxesFromChar(HANDLE hDlg
, wchar_t c
, int _i1
, int _i2
, int _i3
)
281 SendDlgMessage(hDlg
, DM_SETCHECK
, _i1
, BSTATE_UNCHECKED
);
282 SendDlgMessage(hDlg
, DM_SETCHECK
, _i2
, BSTATE_UNCHECKED
);
283 SendDlgMessage(hDlg
, DM_SETCHECK
, _i3
, BSTATE_UNCHECKED
);
286 SendDlgMessage(hDlg
, DM_SETCHECK
, _i1
, BSTATE_CHECKED
);
287 SendDlgMessage(hDlg
, DM_SETCHECK
, _i2
, BSTATE_UNCHECKED
);
288 SendDlgMessage(hDlg
, DM_SETCHECK
, _i3
, BSTATE_UNCHECKED
);
291 SendDlgMessage(hDlg
, DM_SETCHECK
, _i1
, BSTATE_UNCHECKED
);
292 SendDlgMessage(hDlg
, DM_SETCHECK
, _i2
, BSTATE_CHECKED
);
293 SendDlgMessage(hDlg
, DM_SETCHECK
, _i3
, BSTATE_UNCHECKED
);
296 SendDlgMessage(hDlg
, DM_SETCHECK
, _i1
, BSTATE_CHECKED
);
297 SendDlgMessage(hDlg
, DM_SETCHECK
, _i2
, BSTATE_CHECKED
);
298 SendDlgMessage(hDlg
, DM_SETCHECK
, _i3
, BSTATE_UNCHECKED
);
301 SendDlgMessage(hDlg
, DM_SETCHECK
, _i1
, BSTATE_UNCHECKED
);
302 SendDlgMessage(hDlg
, DM_SETCHECK
, _i2
, BSTATE_UNCHECKED
);
303 SendDlgMessage(hDlg
, DM_SETCHECK
, _i3
, BSTATE_CHECKED
);
306 SendDlgMessage(hDlg
, DM_SETCHECK
, _i1
, BSTATE_CHECKED
);
307 SendDlgMessage(hDlg
, DM_SETCHECK
, _i2
, BSTATE_UNCHECKED
);
308 SendDlgMessage(hDlg
, DM_SETCHECK
, _i3
, BSTATE_CHECKED
);
311 SendDlgMessage(hDlg
, DM_SETCHECK
, _i1
, BSTATE_UNCHECKED
);
312 SendDlgMessage(hDlg
, DM_SETCHECK
, _i2
, BSTATE_CHECKED
);
313 SendDlgMessage(hDlg
, DM_SETCHECK
, _i3
, BSTATE_CHECKED
);
316 SendDlgMessage(hDlg
, DM_SETCHECK
, _i1
, BSTATE_CHECKED
);
317 SendDlgMessage(hDlg
, DM_SETCHECK
, _i2
, BSTATE_CHECKED
);
318 SendDlgMessage(hDlg
, DM_SETCHECK
, _i3
, BSTATE_CHECKED
);
321 SendDlgMessage(hDlg
, DM_SETCHECK
, _i1
, BSTATE_3STATE
);
322 SendDlgMessage(hDlg
, DM_SETCHECK
, _i2
, BSTATE_3STATE
);
323 SendDlgMessage(hDlg
, DM_SETCHECK
, _i3
, BSTATE_3STATE
);
328 LONG_PTR WINAPI
SetAttrDlgProc(HANDLE hDlg
, int Msg
, int Param1
, LONG_PTR Param2
)
330 SetAttrDlgParam
*DlgParam
=
331 reinterpret_cast<SetAttrDlgParam
*>(SendDlgMessage(hDlg
, DM_GETDLGDATA
, 0, 0));
336 if (DlgParam
->SymLinkInfoCycle
== 0) {
337 DlgParam
->SymLink
= reinterpret_cast<LPCWSTR
>
338 (SendDlgMessage(hDlg
, DM_GETCONSTTEXTPTR
, SA_EDIT_INFO
, 0));
343 OrigIdx
= DialogID2PreservedOriginalIndex(Param1
);
344 if (OrigIdx
!= -1 || Param1
== SA_CHECKBOX_SUBFOLDERS
) {
346 DlgParam
->OriginalCBAttr
[OrigIdx
] = static_cast<int>(Param2
);
347 DlgParam
->OriginalCBAttr2
[OrigIdx
] = 0;
348 if( !DlgParam
->_b_mode_check_or_edit_process
) {
349 DlgParam
->_b_mode_check_or_edit_process
= true;
350 SetAttrCalcBitsCharFromModeCheckBoxes(hDlg
);
351 DlgParam
->_b_mode_check_or_edit_process
= false;
354 int FocusPos
= static_cast<int>(SendDlgMessage(hDlg
, DM_GETFOCUS
, 0, 0));
355 FARCHECKEDSTATE SubfoldersState
= static_cast<FARCHECKEDSTATE
>(
356 SendDlgMessage(hDlg
, DM_GETCHECK
, SA_CHECKBOX_SUBFOLDERS
, 0));
359 DlgParam
->_b_mode_check_or_edit_process
= true;
360 // если снимаем атрибуты для SubFolders
361 // этот кусок всегда работает если есть хотя бы одна папка
362 // иначе SA_CHECKBOX_SUBFOLDERS недоступен и всегда снят.
363 if (FocusPos
== SA_CHECKBOX_SUBFOLDERS
) {
364 if (DlgParam
->DialogMode
== MODE_FOLDER
) // каталог однозначно!
366 if (DlgParam
->OSubfoldersState
!= SubfoldersState
) // Состояние изменилось?
369 if (SubfoldersState
!= BSTATE_UNCHECKED
) {
370 for (size_t i
= 0; i
< ARRAYSIZE(PreserveOriginalIDs
); ++i
) {
371 SendDlgMessage(hDlg
, DM_SET3STATE
, PreserveOriginalIDs
[i
], TRUE
);
372 if (DlgParam
->OriginalCBAttr2
[i
] == -1) {
373 SendDlgMessage(hDlg
, DM_SETCHECK
, PreserveOriginalIDs
[i
],
378 BlankEditIfChanged(hDlg
, SA_COMBO_OWNER
, DlgParam
->strOwner
,
379 DlgParam
->OwnerChanged
);
380 BlankEditIfChanged(hDlg
, SA_COMBO_GROUP
, DlgParam
->strGroup
,
381 DlgParam
->GroupChanged
);
385 for (size_t i
= 0; i
< ARRAYSIZE(PreserveOriginalIDs
); ++i
) {
386 SendDlgMessage(hDlg
, DM_SET3STATE
, PreserveOriginalIDs
[i
], FALSE
);
387 SendDlgMessage(hDlg
, DM_SETCHECK
, PreserveOriginalIDs
[i
],
388 DlgParam
->OriginalCBAttr
[i
]);
390 SendDlgMessage(hDlg
, DM_SETTEXTPTR
, SA_COMBO_OWNER
,
391 reinterpret_cast<LONG_PTR
>(DlgParam
->strOwner
.CPtr()));
392 SendDlgMessage(hDlg
, DM_SETTEXTPTR
, SA_COMBO_GROUP
,
393 reinterpret_cast<LONG_PTR
>(DlgParam
->strGroup
.CPtr()));
396 if (Opt
.SetAttrFolderRules
) {
397 FAR_FIND_DATA_EX FindData
;
399 if (apiGetFindDataEx(DlgParam
->strSelName
, FindData
)) {
400 const SETATTRDLG Items
[] = {SA_TEXT_LAST_ACCESS
,
401 SA_TEXT_LAST_MODIFICATION
, SA_TEXT_LAST_CHANGE
};
402 bool *ParamTimes
[] = {&DlgParam
->OAccessTime
, &DlgParam
->OModifyTime
,
403 &DlgParam
->OStatusChangeTime
};
404 const PFILETIME FDTimes
[] = {&FindData
.ftUnixAccessTime
,
405 &FindData
.ftUnixModificationTime
,
406 &FindData
.ftUnixStatusChangeTime
};
408 for (size_t i
= 0; i
< ARRAYSIZE(Items
); i
++) {
409 if (!*ParamTimes
[i
]) {
410 SendDlgMessage(hDlg
, DM_SETATTR
, Items
[i
],
411 (SubfoldersState
!= BSTATE_UNCHECKED
)
413 : (LONG_PTR
)FDTimes
[i
]);
414 *ParamTimes
[i
] = false;
423 // Состояние изменилось?
424 if (DlgParam
->OSubfoldersState
!= SubfoldersState
) {
426 if (SubfoldersState
!= BSTATE_UNCHECKED
) {
427 for (size_t i
= 0; i
< ARRAYSIZE(PreserveOriginalIDs
); ++i
) {
428 if (DlgParam
->OriginalCBAttr2
[i
] == -1) {
429 SendDlgMessage(hDlg
, DM_SET3STATE
, PreserveOriginalIDs
[i
], TRUE
);
430 SendDlgMessage(hDlg
, DM_SETCHECK
, PreserveOriginalIDs
[i
],
434 SendDlgMessage(hDlg
, DM_SETTEXTPTR
, SA_COMBO_OWNER
,
435 reinterpret_cast<LONG_PTR
>(L
""));
436 SendDlgMessage(hDlg
, DM_SETTEXTPTR
, SA_COMBO_GROUP
,
437 reinterpret_cast<LONG_PTR
>(L
""));
441 for (size_t i
= 0; i
< ARRAYSIZE(PreserveOriginalIDs
); ++i
) {
442 SendDlgMessage(hDlg
, DM_SET3STATE
, PreserveOriginalIDs
[i
],
443 ((DlgParam
->OriginalCBFlag
[i
] & DIF_3STATE
) ? TRUE
: FALSE
));
444 SendDlgMessage(hDlg
, DM_SETCHECK
, PreserveOriginalIDs
[i
],
445 DlgParam
->OriginalCBAttr
[i
]);
447 SendDlgMessage(hDlg
, DM_SETTEXTPTR
, SA_COMBO_OWNER
,
448 reinterpret_cast<LONG_PTR
>(DlgParam
->strOwner
.CPtr()));
449 SendDlgMessage(hDlg
, DM_SETTEXTPTR
, SA_COMBO_GROUP
,
450 reinterpret_cast<LONG_PTR
>(DlgParam
->strGroup
.CPtr()));
455 DlgParam
->OSubfoldersState
= SubfoldersState
;
457 SetAttrCalcBitsCharFromModeCheckBoxes(hDlg
);
458 DlgParam
->_b_mode_check_or_edit_process
= false;
463 else if (Param1
== SA_TXTBTN_INFO
) {
465 SendDlgMessage(hDlg
, DM_SETTEXTPTR
, SA_TXTBTN_INFO
,
466 reinterpret_cast<LONG_PTR
>(DlgParam
->SymlinkButtonTitles
[DlgParam
->SymLinkInfoCycle
].CPtr()));
468 switch (DlgParam
->SymLinkInfoCycle
++) {
470 DlgParam
->SymLink
= reinterpret_cast<LPCWSTR
>
471 (SendDlgMessage(hDlg
, DM_GETCONSTTEXTPTR
, SA_EDIT_INFO
, 0));
472 ConvertNameToReal(DlgParam
->SymLink
, strText
);
473 SendDlgMessage(hDlg
, DM_SETREADONLY
, SA_EDIT_INFO
, 1);
477 ConvertNameToReal(DlgParam
->SymLink
, strText
);
478 strText
= BriefInfo(strText
);
479 SendDlgMessage(hDlg
, DM_SETREADONLY
, SA_EDIT_INFO
, 1);
483 strText
= DlgParam
->SymLink
;
484 SendDlgMessage(hDlg
, DM_SETREADONLY
, SA_EDIT_INFO
, 0);
485 DlgParam
->SymLinkInfoCycle
= 0;
487 SendDlgMessage(hDlg
, DM_SETTEXTPTR
, SA_EDIT_INFO
, reinterpret_cast<LONG_PTR
>(strText
.CPtr()));
490 // Set Original for Modes and Attributes
491 } else if (Param1
== SA_BUTTON_MODE_ORIGINAL
) {
492 DlgParam
->_b_mode_check_or_edit_process
= true;
493 for (size_t i
= 0; i
< ARRAYSIZE(PreserveOriginalIDs
); ++i
) {
494 DlgParam
->OriginalCBAttr2
[i
] = -1;
495 SendDlgMessage(hDlg
, DM_SET3STATE
, PreserveOriginalIDs
[i
],
496 ((DlgParam
->OriginalCBFlag
[i
] & DIF_3STATE
) ? TRUE
: FALSE
));
497 SendDlgMessage(hDlg
, DM_SETCHECK
, PreserveOriginalIDs
[i
],
498 DlgParam
->OriginalCBAttr0
[i
]);
500 SetAttrCalcBitsCharFromModeCheckBoxes(hDlg
);
501 DlgParam
->_b_mode_check_or_edit_process
= false;
502 SendDlgMessage(hDlg
, DM_SETFOCUS
, SA_FIXEDIT_MODE_OCTAL
, 0);
504 // Set Original? / Set All? / Clear All?
505 } else if (Param1
== SA_BUTTON_ORIGINAL
) {
506 FAR_FIND_DATA_EX FindData
;
508 if (apiGetFindDataEx(DlgParam
->strSelName
, FindData
)) {
509 SendDlgMessage(hDlg
, DM_SETATTR
, SA_TEXT_LAST_ACCESS
,
510 (LONG_PTR
)&FindData
.ftUnixAccessTime
);
511 SendDlgMessage(hDlg
, DM_SETATTR
, SA_TEXT_LAST_MODIFICATION
,
512 (LONG_PTR
)&FindData
.ftUnixModificationTime
);
513 SendDlgMessage(hDlg
, DM_SETATTR
, SA_TEXT_LAST_CHANGE
,
514 (LONG_PTR
)&FindData
.ftUnixStatusChangeTime
);
515 DlgParam
->OAccessTime
= DlgParam
->OModifyTime
= DlgParam
->OStatusChangeTime
= false;
518 SendDlgMessage(hDlg
, DM_SETFOCUS
, SA_FIXEDIT_LAST_ACCESS_DATE
, 0);
520 } else if (Param1
== SA_BUTTON_CURRENT
|| Param1
== SA_BUTTON_BLANK
) {
522 FILETIME CurrentTime
;
523 if (Param1
== SA_BUTTON_CURRENT
) {
524 WINPORT(GetSystemTimeAsFileTime
)(&CurrentTime
);
525 Value
= reinterpret_cast<LONG_PTR
>(&CurrentTime
);
527 SendDlgMessage(hDlg
, DM_SETATTR
, SA_TEXT_LAST_ACCESS
, Value
);
528 SendDlgMessage(hDlg
, DM_SETATTR
, SA_TEXT_LAST_MODIFICATION
, Value
);
529 // SendDlgMessage(hDlg, DM_SETATTR, SA_TEXT_LAST_CHANGE, Value);
530 DlgParam
->OAccessTime
= DlgParam
->OModifyTime
= DlgParam
->OStatusChangeTime
= true;
531 SendDlgMessage(hDlg
, DM_SETFOCUS
, SA_FIXEDIT_LAST_ACCESS_DATE
, 0);
536 case DN_MOUSECLICK
: {
537 //_SVS(SysLog(L"Msg=DN_MOUSECLICK Param1=%d Param2=%d",Param1,Param2));
538 if (Param1
>= SA_TEXT_LAST_ACCESS
&& Param1
<= SA_FIXEDIT_LAST_CHANGE_TIME
) {
539 if (reinterpret_cast<MOUSE_EVENT_RECORD
*>(Param2
)->dwEventFlags
== DOUBLE_CLICK
) {
540 // Дадим Менеджеру диалогов "попотеть"
541 DefDlgProc(hDlg
, Msg
, Param1
, Param2
);
542 SendDlgMessage(hDlg
, DM_SETATTR
, Param1
, -1);
545 if (Param1
== SA_TEXT_LAST_ACCESS
|| Param1
== SA_TEXT_LAST_MODIFICATION
546 || Param1
== SA_TEXT_LAST_CHANGE
) {
550 SendDlgMessage(hDlg
, DM_SETFOCUS
, Param1
, 0);
553 case DN_EDITCHANGE
: {
555 case SA_FIXEDIT_MODE_OCTAL
:
556 if (!DlgParam
->_b_mode_check_or_edit_process
) {
557 DlgParam
->_b_mode_check_or_edit_process
= true;
558 std::wstring str_octal
;
559 int length
= (int)SendDlgMessage(hDlg
, DM_GETTEXTLENGTH
, SA_FIXEDIT_MODE_OCTAL
, 0);
560 str_octal
.resize(length
+1);
561 LONG_PTR rv
= SendDlgMessage(hDlg
, DM_GETTEXTPTR
, SA_FIXEDIT_MODE_OCTAL
, (LONG_PTR
)&str_octal
[0]);
563 length
= str_octal
.length();
564 SetAttrGetModeCheckBoxesFromChar(hDlg
, length
<1 ? ' ' : str_octal
[0], SA_CHECKBOX_STICKY
, SA_CHECKBOX_SGID
, SA_CHECKBOX_SUID
);
565 SetAttrGetModeCheckBoxesFromChar(hDlg
, length
<2 ? ' ' : str_octal
[1], SA_CHECKBOX_USER_EXECUTE
, SA_CHECKBOX_USER_WRITE
, SA_CHECKBOX_USER_READ
);
566 SetAttrGetModeCheckBoxesFromChar(hDlg
, length
<3 ? ' ' : str_octal
[2], SA_CHECKBOX_GROUP_EXECUTE
, SA_CHECKBOX_GROUP_WRITE
, SA_CHECKBOX_GROUP_READ
);
567 SetAttrGetModeCheckBoxesFromChar(hDlg
, length
<4 ? ' ' : str_octal
[3], SA_CHECKBOX_OTHER_EXECUTE
, SA_CHECKBOX_OTHER_WRITE
, SA_CHECKBOX_OTHER_READ
);
569 DlgParam
->_b_mode_check_or_edit_process
= false;
572 case SA_FIXEDIT_LAST_ACCESS_DATE
:
573 case SA_FIXEDIT_LAST_ACCESS_TIME
:
574 DlgParam
->OAccessTime
= true;
576 case SA_FIXEDIT_LAST_MODIFICATION_DATE
:
577 case SA_FIXEDIT_LAST_MODIFICATION_TIME
:
578 DlgParam
->OModifyTime
= true;
580 case SA_FIXEDIT_LAST_CHANGE_DATE
:
581 case SA_FIXEDIT_LAST_CHANGE_TIME
:
582 DlgParam
->OStatusChangeTime
= true;
590 if (Param1
== SA_FIXEDIT_LAST_ACCESS_DATE
|| Param1
== SA_FIXEDIT_LAST_MODIFICATION_DATE
591 || Param1
== SA_FIXEDIT_LAST_CHANGE_DATE
) {
592 if (GetDateFormat() == 2) {
593 if (reinterpret_cast<LPCWSTR
>(SendDlgMessage(hDlg
, DM_GETCONSTTEXTPTR
, Param1
, 0))[0]
596 SendDlgMessage(hDlg
, DM_GETCURSORPOS
, Param1
, (LONG_PTR
)&Pos
);
599 SendDlgMessage(hDlg
, DM_SETCURSORPOS
, Param1
, (LONG_PTR
)&Pos
);
607 FARString strDate
, strTime
;
614 WINPORT(GetSystemTimeAsFileTime
)(&ft
);
616 ft
= *reinterpret_cast<PFILETIME
>(Param2
);
619 ConvertDate(ft
, strDate
, strTime
, 12, FALSE
, FALSE
, 2, TRUE
);
622 // Глянем на место, где был клик
627 case SA_TEXT_LAST_ACCESS
:
628 Set1
= SA_FIXEDIT_LAST_ACCESS_DATE
;
629 Set2
= SA_FIXEDIT_LAST_ACCESS_TIME
;
630 DlgParam
->OAccessTime
= true;
632 case SA_TEXT_LAST_MODIFICATION
:
633 Set1
= SA_FIXEDIT_LAST_MODIFICATION_DATE
;
634 Set2
= SA_FIXEDIT_LAST_MODIFICATION_TIME
;
635 DlgParam
->OModifyTime
= true;
637 case SA_TEXT_LAST_CHANGE
:
638 Set1
= SA_FIXEDIT_LAST_CHANGE_DATE
;
639 Set2
= SA_FIXEDIT_LAST_CHANGE_TIME
;
640 DlgParam
->OStatusChangeTime
= true;
643 case SA_FIXEDIT_LAST_ACCESS_DATE
:
644 case SA_FIXEDIT_LAST_MODIFICATION_DATE
:
645 case SA_FIXEDIT_LAST_CHANGE_DATE
:
652 SendDlgMessage(hDlg
, DM_SETTEXTPTR
, Set1
, (LONG_PTR
)strDate
.CPtr());
656 SendDlgMessage(hDlg
, DM_SETTEXTPTR
, Set2
, (LONG_PTR
)strTime
.CPtr());
663 return DefDlgProc(hDlg
, Msg
, Param1
, Param2
);
666 void ShellSetFileAttributesMsg(const wchar_t *Name
)
668 static int Width
= 54;
672 WidthTemp
= Max(StrLength(Name
), 54);
674 Width
= WidthTemp
= 54;
676 WidthTemp
= Min(WidthTemp
, WidthNameForMessage
);
677 Width
= Max(Width
, WidthTemp
);
678 FARString strOutFileName
= Name
;
679 TruncPathStr(strOutFileName
, Width
);
680 CenterStr(strOutFileName
, strOutFileName
, Width
+ 4);
681 Message(0, 0, Msg::SetAttrTitle
, Msg::SetAttrSetting
, strOutFileName
);
682 PreRedrawItem preRedrawItem
= PreRedraw
.Peek();
683 preRedrawItem
.Param
.Param1
= Name
;
684 PreRedraw
.SetParam(preRedrawItem
.Param
);
687 bool ReadFileTime(int Type
, const wchar_t *Name
, FILETIME
&FileTime
, const wchar_t *OSrcDate
,
688 const wchar_t *OSrcTime
)
691 FAR_FIND_DATA_EX ffd
= {};
693 if (apiGetFindDataEx(Name
, ffd
)) {
694 LPFILETIME Times
[] = {&ffd
.ftLastWriteTime
, &ffd
.ftCreationTime
, &ffd
.ftLastAccessTime
,
696 LPFILETIME OriginalFileTime
= Times
[Type
];
698 if (WINPORT(FileTimeToLocalFileTime
)(OriginalFileTime
, &oft
)) {
700 if (WINPORT(FileTimeToSystemTime
)(&oft
, &ost
)) {
702 GetFileDateAndTime(OSrcDate
, DateN
, ARRAYSIZE(DateN
), GetDateSeparator());
704 GetFileDateAndTime(OSrcTime
, TimeN
, ARRAYSIZE(TimeN
), GetTimeSeparator());
707 switch (GetDateFormat()) {
709 st
.wMonth
= DateN
[0] != (WORD
)-1 ? DateN
[0] : ost
.wMonth
;
710 st
.wDay
= DateN
[1] != (WORD
)-1 ? DateN
[1] : ost
.wDay
;
711 st
.wYear
= DateN
[2] != (WORD
)-1 ? DateN
[2] : ost
.wYear
;
714 st
.wDay
= DateN
[0] != (WORD
)-1 ? DateN
[0] : ost
.wDay
;
715 st
.wMonth
= DateN
[1] != (WORD
)-1 ? DateN
[1] : ost
.wMonth
;
716 st
.wYear
= DateN
[2] != (WORD
)-1 ? DateN
[2] : ost
.wYear
;
719 st
.wYear
= DateN
[0] != (WORD
)-1 ? DateN
[0] : ost
.wYear
;
720 st
.wMonth
= DateN
[1] != (WORD
)-1 ? DateN
[1] : ost
.wMonth
;
721 st
.wDay
= DateN
[2] != (WORD
)-1 ? DateN
[2] : ost
.wDay
;
725 st
.wHour
= TimeN
[0] != (WORD
)-1 ? (TimeN
[0]) : ost
.wHour
;
726 st
.wMinute
= TimeN
[1] != (WORD
)-1 ? (TimeN
[1]) : ost
.wMinute
;
727 st
.wSecond
= TimeN
[2] != (WORD
)-1 ? (TimeN
[2]) : ost
.wSecond
;
728 st
.wMilliseconds
= TimeN
[3] != (WORD
)-1 ? (TimeN
[3]) : ost
.wMilliseconds
;
730 if (st
.wYear
< 100) {
731 st
.wYear
= static_cast<WORD
>(ConvertYearToFull(st
.wYear
));
735 if (WINPORT(SystemTimeToFileTime
)(&st
, &lft
)) {
736 if (WINPORT(LocalFileTimeToFileTime
)(&lft
, &FileTime
)) {
737 Result
= WINPORT(CompareFileTime
)(&FileTime
, OriginalFileTime
) != 0;
746 void PR_ShellSetFileAttributesMsg()
748 PreRedrawItem preRedrawItem
= PreRedraw
.Peek();
749 ShellSetFileAttributesMsg(reinterpret_cast<const wchar_t *>(preRedrawItem
.Param
.Param1
));
752 static void CheckFileOwnerGroup(DialogItemEx
&ComboItem
,
753 bool(WINAPI
*GetFN
)(const wchar_t *, const wchar_t *, FARString
&),
754 FARString strComputerName
,
755 FARString strSelName
)
758 GetFN(strComputerName
, strSelName
, strCur
);
759 if (ComboItem
.strData
.IsEmpty()) {
760 ComboItem
.strData
= strCur
;
762 else if (ComboItem
.strData
!= strCur
) {
763 ComboItem
.strData
= Msg::SetAttrOwnerMultiple
;
767 static bool ApplyFileOwnerGroupIfChanged(DialogItemEx
&ComboItem
,
768 int (*ESetFN
)(LPCWSTR Name
, LPCWSTR Owner
, int SkipMode
),
769 int &SkipMode
, const FARString
&strSelName
, const FARString
&strInit
, bool force
= false)
771 if (!ComboItem
.strData
.IsEmpty() && (force
|| StrCmp(strInit
, ComboItem
.strData
))) {
772 int Result
= ESetFN(strSelName
, ComboItem
.strData
, SkipMode
);
773 if (Result
== SETATTR_RET_SKIPALL
) {
774 SkipMode
= SETATTR_RET_SKIP
;
776 else if (Result
== SETATTR_RET_ERROR
) {
783 static void ApplyFSFileFlags(DialogItemEx
*AttrDlg
, const FARString
&strSelName
, DWORD FileAttr
)
785 FSFileFlagsSafe
FFFlags(strSelName
.GetMB(), FileAttr
);
786 if (AttrDlg
[SA_CHECKBOX_IMMUTABLE
].Selected
== BSTATE_CHECKED
787 || AttrDlg
[SA_CHECKBOX_IMMUTABLE
].Selected
== BSTATE_UNCHECKED
) {
788 FFFlags
.SetImmutable(AttrDlg
[SA_CHECKBOX_IMMUTABLE
].Selected
!= BSTATE_UNCHECKED
);
790 if (AttrDlg
[SA_CHECKBOX_APPEND
].Selected
== BSTATE_CHECKED
791 || AttrDlg
[SA_CHECKBOX_APPEND
].Selected
== BSTATE_UNCHECKED
) {
792 FFFlags
.SetAppend(AttrDlg
[SA_CHECKBOX_APPEND
].Selected
!= BSTATE_UNCHECKED
);
794 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
795 if (AttrDlg
[SA_CHECKBOX_HIDDEN
].Selected
== BSTATE_CHECKED
796 || AttrDlg
[SA_CHECKBOX_HIDDEN
].Selected
== BSTATE_UNCHECKED
) {
797 FFFlags
.SetHidden(AttrDlg
[SA_CHECKBOX_HIDDEN
].Selected
!= BSTATE_UNCHECKED
);
800 FFFlags
.Apply(strSelName
.GetMB());
804 std::set
<FARString
> Set
; // sorts and prevents duplicates
805 std::vector
<FarListItem
> Items
;
807 void Append(const wchar_t *s
) { Set
.emplace(s
); }
808 void Append(const char *s
) { Set
.emplace(s
); }
810 ListPwGrEnt(bool bGroups
, int SelCount
);
811 FarList
*GetFarList() {
816 ListPwGrEnt::ListPwGrEnt(bool bGroups
, int SelCount
)
819 Append(Msg::SetAttrOwnerMultiple
);
821 if (!bGroups
) { // usernames
824 while ((pw
= getpwent()) != NULL
) {
832 while ((gr
= getgrent()) != NULL
) {
838 Items
.reserve(Set
.size());
839 for (const auto &Str
: Set
) {
840 Items
.emplace_back();
841 Items
.back().Flags
= 0;
842 Items
.back().Text
= Str
.CPtr();
845 List
.ItemsNumber
= Items
.size();
846 List
.Items
= Items
.data();
849 bool ShellSetFileAttributes(Panel
*SrcPanel
, LPCWSTR Object
)
851 std::vector
<FARString
> SelectedNames
;
853 SudoClientRegion scr
;
855 ChangePriority
ChPriority(ChangePriority::NORMAL
);
856 short DlgX
= 70, DlgY
= 25;
858 int SelCount
= SrcPanel
? SrcPanel
->GetSelCount() : 1;
864 const short ColX1Of3
= 5;
865 const short ColX2Of3
= ColX1Of3
+ (DlgX
- 3) / 3;
866 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
867 const short ColX3Of3
= ColX2Of3
+ (DlgX
- 3) / 3;
869 static const wchar_t VerticalLine
[] = {BoxSymbols
[BS_V1
], BoxSymbols
[BS_V1
], BoxSymbols
[BS_V1
], 0};
871 DialogDataEx AttrDlgData
[] = {
872 {DI_DOUBLEBOX
, 3, 1, short(DlgX
- 4), short(DlgY
- 2), {}, 0, Msg::SetAttrTitle
},
873 {DI_TEXT
, -1, 2, 0, 2, {}, 0, Msg::SetAttrFor
},
874 {DI_TEXT
, -1, 3, 0, 3, {}, DIF_SHOWAMPERSAND
, L
""},
875 {DI_TEXT
, 3, 4, 0, 4, {}, DIF_SEPARATOR
, L
""},
876 {DI_TEXT
, 5, 5, 17, 5, {}, DIF_FOCUS
, Msg::SetAttrBriefInfo
}, // if symlink in will Button & need first focus here
877 {DI_EDIT
, 18, 5, short(DlgX
- 6), 5, {}, DIF_SELECTONENTRY
| DIF_FOCUS
| DIF_READONLY
, L
""}, // not readonly only if symlink
878 {DI_TEXT
, 3, 6, 0, 6, {}, DIF_SEPARATOR
, Msg::SetAttrOwnerTitle
},
879 {DI_TEXT
, 5, 7, 17, 7, {}, 0, Msg::SetAttrOwner
},
880 //{DI_EDIT, 18, 6, short(DlgX - 6), 6, {}, 0, L""},
881 {DI_COMBOBOX
, 18, 7, short(DlgX
-6), 7, {}, DIF_DROPDOWNLIST
|DIF_LISTNOAMPERSAND
|DIF_LISTWRAPMODE
,L
""},
882 {DI_TEXT
, 5, 8, 17, 8, {}, 0, Msg::SetAttrGroup
},
883 //{DI_EDIT, 18, 7, short(DlgX - 6), 7, {}, 0, L""},
884 {DI_COMBOBOX
, 18, 8, short(DlgX
-6), 8, {}, DIF_DROPDOWNLIST
|DIF_LISTNOAMPERSAND
|DIF_LISTWRAPMODE
,L
""},
886 {DI_TEXT
, 3, 9, 0, 9, {}, DIF_SEPARATOR
, Msg::SetAttrModeTitle
},
887 {DI_VTEXT
, 39, 10, 39, 12, {}, DIF_BOXCOLOR
, VerticalLine
},
888 {DI_VTEXT
, 51, 10, 51, 12, {}, DIF_BOXCOLOR
, VerticalLine
},
890 {DI_TEXT
, 5, 10, 18, 10, {}, 0, Msg::SetAttrAccessUser
},
891 {DI_CHECKBOX
, 19, 10, 23, 10, {}, DIF_3STATE
, Msg::SetAttrAccessUserRead
},
892 {DI_CHECKBOX
, 26, 10, 30, 10, {}, DIF_3STATE
, Msg::SetAttrAccessUserWrite
},
893 {DI_CHECKBOX
, 33, 10, 37, 10, {}, DIF_3STATE
, Msg::SetAttrAccessUserExecute
},
894 {DI_TEXT
, 5, 11, 18, 11, {}, 0, Msg::SetAttrAccessGroup
},
895 {DI_CHECKBOX
, 19, 11, 23, 11, {}, DIF_3STATE
, Msg::SetAttrAccessGroupRead
},
896 {DI_CHECKBOX
, 26, 11, 30, 11, {}, DIF_3STATE
, Msg::SetAttrAccessGroupWrite
},
897 {DI_CHECKBOX
, 33, 11, 37, 11, {}, DIF_3STATE
, Msg::SetAttrAccessGroupExecute
},
898 {DI_TEXT
, 5, 12, 18, 12, {}, 0, Msg::SetAttrAccessOther
},
899 {DI_CHECKBOX
, 19, 12, 23, 12, {}, DIF_3STATE
, Msg::SetAttrAccessOtherRead
},
900 {DI_CHECKBOX
, 26, 12, 30, 12, {}, DIF_3STATE
, Msg::SetAttrAccessOtherWrite
},
901 {DI_CHECKBOX
, 33, 12, 37, 12, {}, DIF_3STATE
, Msg::SetAttrAccessOtherExecute
},
903 {DI_CHECKBOX
, 40, 10, 52, 10, {}, DIF_3STATE
, Msg::SetAttrSUID
},
904 {DI_CHECKBOX
, 40, 11, 52, 11, {}, DIF_3STATE
, Msg::SetAttrSGID
},
905 {DI_CHECKBOX
, 40, 12, 52, 12, {}, DIF_3STATE
, Msg::SetAttrSticky
},
907 {DI_TEXT
, 52, 10, 62, 10, {}, 0, L
"O&ctal: SUGO"},
908 {DI_FIXEDIT
, 59, 11, 62, 11, {(DWORD_PTR
)L
"####"}, DIF_MASKEDIT
, L
""},
909 {DI_BUTTON
, 52, 12, 62, 12, {}, DIF_BTNNOCLOSE
, Msg::SetAttrModeOriginal
},
911 {DI_TEXT
, 3, 13, 0, 13, {}, DIF_SEPARATOR
, Msg::SetAttrAttributesTitle
},
912 {DI_CHECKBOX
, ColX1Of3
, 14, 0, 14, {}, DIF_FOCUS
| DIF_3STATE
, Msg::SetAttrImmutable
},
913 {DI_CHECKBOX
, ColX2Of3
, 14, 0, 14, {}, DIF_3STATE
, Msg::SetAttrAppend
},
914 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
915 {DI_CHECKBOX
, ColX3Of3
, 14, 0, 14, {}, DIF_3STATE
, Msg::SetAttrHidden
},
918 {DI_TEXT
, 3, 15, 0, 15, {}, DIF_SEPARATOR
, L
""},
919 {DI_TEXT
, short(DlgX
- 29), 16, 0, 16, {}, 0, L
""},
920 {DI_TEXT
, 5, 17, 0, 17, {}, 0, Msg::SetAttrAccessTime
},
921 {DI_FIXEDIT
, short(DlgX
- 29), 17, short(DlgX
- 19), 17, {}, DIF_MASKEDIT
, L
""},
922 {DI_FIXEDIT
, short(DlgX
- 17), 17, short(DlgX
- 6), 17, {}, DIF_MASKEDIT
, L
""},
923 {DI_TEXT
, 5, 18, 0, 18, {}, 0, Msg::SetAttrModificationTime
},
924 {DI_FIXEDIT
, short(DlgX
- 29), 18, short(DlgX
- 19), 18, {}, DIF_MASKEDIT
, L
""},
925 {DI_FIXEDIT
, short(DlgX
- 17), 18, short(DlgX
- 6), 18, {}, DIF_MASKEDIT
, L
""},
926 {DI_TEXT
, 5, 19, 0, 19, {}, 0, Msg::SetAttrStatusChangeTime
},
927 {DI_FIXEDIT
, short(DlgX
- 29), 19, short(DlgX
- 19), 19, {}, DIF_MASKEDIT
| DIF_READONLY
, L
""},
928 {DI_FIXEDIT
, short(DlgX
- 17), 19, short(DlgX
- 6), 19, {}, DIF_MASKEDIT
| DIF_READONLY
, L
""},
929 {DI_BUTTON
, 0, 20, 0, 20, {}, DIF_CENTERGROUP
| DIF_BTNNOCLOSE
, Msg::SetAttrOriginal
},
930 {DI_BUTTON
, 0, 20, 0, 20, {}, DIF_CENTERGROUP
| DIF_BTNNOCLOSE
, Msg::SetAttrCurrent
},
931 {DI_BUTTON
, 0, 20, 0, 20, {}, DIF_CENTERGROUP
| DIF_BTNNOCLOSE
, Msg::SetAttrBlank
},
932 {DI_TEXT
, 3, 21, 0, 21, {}, DIF_SEPARATOR
| DIF_HIDDEN
, L
""},
933 {DI_CHECKBOX
, 5, 22, 0, 22, {}, DIF_DISABLE
| DIF_HIDDEN
, Msg::SetAttrSubfolders
},
934 {DI_TEXT
, 3, short(DlgY
- 4), 0, short(DlgY
- 4), {}, DIF_SEPARATOR
, L
""},
935 {DI_BUTTON
, 0, short(DlgY
- 3), 0, short(DlgY
- 3), {}, DIF_DEFAULT
| DIF_CENTERGROUP
, Msg::SetAttrSet
},
936 {DI_BUTTON
, 0, short(DlgY
- 3), 0, short(DlgY
- 3), {}, DIF_CENTERGROUP
, Msg::Cancel
}
938 MakeDialogItemsEx(AttrDlgData
, AttrDlg
);
939 SetAttrDlgParam DlgParam
{};
941 ListPwGrEnt
Owners(false, SelCount
);
942 ListPwGrEnt
Groups(true, SelCount
);
943 AttrDlg
[SA_COMBO_OWNER
].ListItems
= Owners
.GetFarList();
944 AttrDlg
[SA_COMBO_GROUP
].ListItems
= Groups
.GetFarList();
946 if (SrcPanel
&& SrcPanel
->GetMode() == PLUGIN_PANEL
) {
948 HANDLE hPlugin
= SrcPanel
->GetPluginHandle();
950 if (hPlugin
== INVALID_HANDLE_VALUE
) {
954 CtrlObject
->Plugins
.GetOpenPluginInfo(hPlugin
, &Info
);
956 if (!(Info
.Flags
& OPIF_REALNAMES
)) {
957 AttrDlg
[SA_BUTTON_SET
].Flags
|= DIF_DISABLE
;
958 //AttrDlg[SA_BUTTON_BRIEFINFO].Flags|= DIF_DISABLE;
959 DlgParam
.Plugin
= true;
964 DWORD FileAttr
= INVALID_FILE_ATTRIBUTES
, FileMode
= 0;
965 FARString strSelName
;
966 FAR_FIND_DATA_EX FindData
;
968 SrcPanel
->GetSelName(nullptr, FileAttr
, FileMode
);
969 SrcPanel
->GetSelName(&strSelName
, FileAttr
, FileMode
, &FindData
);
971 FAR_FIND_DATA_EX FindData2;
972 if (apiGetFindDataEx(strSelName, FindData2) && FindData2.dwUnixMode) {
973 FindData = FindData2;
974 FileAttr = FindData.dwFileAttributes;
975 FileMode = FindData.dwUnixMode;
980 apiGetFindDataEx(Object
, FindData
);
981 FileAttr
= FindData
.dwFileAttributes
;
982 FileMode
= FindData
.dwUnixMode
;
985 // fprintf(stderr, "FileMode=%u\n", FileMode);
987 if (SelCount
== 1 && TestParentFolderName(strSelName
))
990 wchar_t DateSeparator
= GetDateSeparator();
991 wchar_t TimeSeparator
= GetTimeSeparator();
992 wchar_t DecimalSeparator
= GetDecimalSeparator();
993 LPCWSTR FmtMask1
= L
"99%c99%c99%c99N", FmtMask2
= L
"99%c99%c9999N", FmtMask3
= L
"N9999%c99%c99";
994 FARString strDMask
, strTMask
;
995 strTMask
.Format(FmtMask1
, TimeSeparator
, TimeSeparator
, DecimalSeparator
);
997 switch (GetDateFormat()) {
999 AttrDlg
[SA_TEXT_TITLEDATE
].strData
.Format(Msg::SetAttrTimeTitle1
, DateSeparator
,
1000 DateSeparator
, TimeSeparator
, TimeSeparator
, DecimalSeparator
);
1001 strDMask
.Format(FmtMask2
, DateSeparator
, DateSeparator
);
1004 AttrDlg
[SA_TEXT_TITLEDATE
].strData
.Format(Msg::SetAttrTimeTitle2
, DateSeparator
,
1005 DateSeparator
, TimeSeparator
, TimeSeparator
, DecimalSeparator
);
1006 strDMask
.Format(FmtMask2
, DateSeparator
, DateSeparator
);
1009 AttrDlg
[SA_TEXT_TITLEDATE
].strData
.Format(Msg::SetAttrTimeTitle3
, DateSeparator
,
1010 DateSeparator
, TimeSeparator
, TimeSeparator
, DecimalSeparator
);
1011 strDMask
.Format(FmtMask3
, DateSeparator
, DateSeparator
);
1015 AttrDlg
[SA_FIXEDIT_LAST_ACCESS_DATE
].strMask
= AttrDlg
[SA_FIXEDIT_LAST_MODIFICATION_DATE
].strMask
=
1016 AttrDlg
[SA_FIXEDIT_LAST_CHANGE_DATE
].strMask
= strDMask
;
1018 AttrDlg
[SA_FIXEDIT_LAST_ACCESS_TIME
].strMask
= AttrDlg
[SA_FIXEDIT_LAST_MODIFICATION_TIME
].strMask
=
1019 AttrDlg
[SA_FIXEDIT_LAST_CHANGE_TIME
].strMask
= strTMask
;
1020 bool FolderPresent
= false;//, LinkPresent = false;
1021 int FolderCount
= 0, Link2FileCount
= 0, Link2DirCount
= 0;
1022 FARString strLinkName
;
1024 if (SelCount
== 1) {
1025 FSFileFlagsSafe
FFFlags(strSelName
.GetMB(), FileAttr
);
1026 if (FileAttr
& FILE_ATTRIBUTE_REPARSE_POINT
) {
1027 DlgParam
.SymlinkButtonTitles
[0] = Msg::SetAttrSymlinkObject
;
1028 DlgParam
.SymlinkButtonTitles
[1] = Msg::SetAttrSymlinkObjectInfo
;
1029 DlgParam
.SymlinkButtonTitles
[2] = Msg::SetAttrSymlinkContent
;
1031 AttrDlg
[SA_TXTBTN_INFO
].Type
= DI_BUTTON
;
1032 AttrDlg
[SA_TXTBTN_INFO
].strData
= DlgParam
.SymlinkButtonTitles
[2];
1033 ReadSymlink(strSelName
, DlgParam
.SymLink
);
1034 AttrDlg
[SA_EDIT_INFO
].strData
= DlgParam
.SymLink
;
1035 AttrDlg
[SA_EDIT_INFO
].Flags
&= ~DIF_READONLY
; // not readonly only if symlink
1038 else if (FileAttr
& FILE_ATTRIBUTE_DEVICE_CHAR
)
1039 AttrDlg
[SA_EDIT_INFO
].strData
= Msg::FileFilterAttrDevChar
;
1040 else if (FileAttr
& FILE_ATTRIBUTE_DEVICE_BLOCK
)
1041 AttrDlg
[SA_EDIT_INFO
].strData
= Msg::FileFilterAttrDevBlock
;
1042 else if (FileAttr
& FILE_ATTRIBUTE_DEVICE_FIFO
)
1043 AttrDlg
[SA_EDIT_INFO
].strData
= Msg::FileFilterAttrDevFIFO
;
1044 else if (FileAttr
& FILE_ATTRIBUTE_DEVICE_SOCK
)
1045 AttrDlg
[SA_EDIT_INFO
].strData
= Msg::FileFilterAttrDevSock
;
1047 AttrDlg
[SA_EDIT_INFO
].strData
= BriefInfo(strSelName
);
1051 if (FileAttr
& FILE_ATTRIBUTE_DIRECTORY
) {
1052 if (!DlgParam
.Plugin
) {
1053 FileAttr
= apiGetFileAttributes(strSelName
);
1056 //_SVS(SysLog(L"SelName=%ls FileAttr=0x%08X",SelName,FileAttr));
1057 AttrDlg
[SA_SEPARATOR4
].Flags
&= ~DIF_HIDDEN
;
1058 AttrDlg
[SA_CHECKBOX_SUBFOLDERS
].Flags
&= ~(DIF_DISABLE
| DIF_HIDDEN
);
1059 AttrDlg
[SA_CHECKBOX_SUBFOLDERS
].Selected
=
1060 Opt
.SetAttrFolderRules
? BSTATE_UNCHECKED
: BSTATE_CHECKED
;
1061 AttrDlg
[SA_DOUBLEBOX
].Y2
+= 2;
1062 for (int i
= SA_SEPARATOR5
; i
<= SA_BUTTON_CANCEL
; i
++) {
1068 if (Opt
.SetAttrFolderRules
) {
1069 if (DlgParam
.Plugin
|| apiGetFindDataEx(strSelName
, FindData
)) {
1070 ConvertDate(FindData
.ftUnixAccessTime
, AttrDlg
[SA_FIXEDIT_LAST_ACCESS_DATE
].strData
,
1071 AttrDlg
[SA_FIXEDIT_LAST_ACCESS_TIME
].strData
, 12, FALSE
, FALSE
, 2, TRUE
);
1072 ConvertDate(FindData
.ftUnixModificationTime
,
1073 AttrDlg
[SA_FIXEDIT_LAST_MODIFICATION_DATE
].strData
,
1074 AttrDlg
[SA_FIXEDIT_LAST_MODIFICATION_TIME
].strData
, 12, FALSE
, FALSE
, 2,
1076 ConvertDate(FindData
.ftUnixStatusChangeTime
,
1077 AttrDlg
[SA_FIXEDIT_LAST_CHANGE_DATE
].strData
,
1078 AttrDlg
[SA_FIXEDIT_LAST_CHANGE_TIME
].strData
, 12, FALSE
, FALSE
, 2, TRUE
);
1082 FolderPresent
= TRUE
;
1085 if ((FileAttr
!= INVALID_FILE_ATTRIBUTES
)
1086 && ((FileAttr
& FILE_ATTRIBUTE_DIRECTORY
) == 0 || Opt
.SetAttrFolderRules
)) {
1087 for (size_t i
= 0; i
< ARRAYSIZE(AP
); i
++) {
1088 AttrDlg
[AP
[i
].Item
].Selected
=
1089 (FileMode
& AP
[i
].Mode
) ? BSTATE_CHECKED
: BSTATE_UNCHECKED
;
1091 AttrDlg
[SA_CHECKBOX_IMMUTABLE
].Selected
= FFFlags
.Immutable() ? BSTATE_CHECKED
: BSTATE_UNCHECKED
;
1092 AttrDlg
[SA_CHECKBOX_APPEND
].Selected
= FFFlags
.Append() ? BSTATE_CHECKED
: BSTATE_UNCHECKED
;
1093 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
1094 AttrDlg
[SA_CHECKBOX_HIDDEN
].Selected
= FFFlags
.Hidden() ? BSTATE_CHECKED
: BSTATE_UNCHECKED
;
1098 for (auto i
: PreserveOriginalIDs
) {
1099 AttrDlg
[i
].Flags
&= ~DIF_3STATE
;
1102 AttrDlg
[SA_TEXT_NAME
].strData
= strSelName
;
1103 TruncStr(AttrDlg
[SA_TEXT_NAME
].strData
, DlgX
- 10);
1105 const SETATTRDLG Dates
[] = {SA_FIXEDIT_LAST_ACCESS_DATE
, SA_FIXEDIT_LAST_MODIFICATION_DATE
,
1106 SA_FIXEDIT_LAST_CHANGE_DATE
};
1107 const SETATTRDLG Times
[] = {SA_FIXEDIT_LAST_ACCESS_TIME
, SA_FIXEDIT_LAST_MODIFICATION_TIME
,
1108 SA_FIXEDIT_LAST_CHANGE_TIME
};
1109 const PFILETIME TimeValues
[] = {&FindData
.ftUnixAccessTime
, &FindData
.ftUnixModificationTime
,
1110 &FindData
.ftUnixStatusChangeTime
};
1112 if (DlgParam
.Plugin
|| (!DlgParam
.Plugin
&& apiGetFindDataEx(strSelName
, FindData
))) {
1113 for (size_t i
= 0; i
< ARRAYSIZE(Dates
); i
++) {
1114 ConvertDate(*TimeValues
[i
], AttrDlg
[Dates
[i
]].strData
, AttrDlg
[Times
[i
]].strData
, 12,
1115 FALSE
, FALSE
, 2, TRUE
);
1119 FARString strComputerName
;
1121 FARString strCurDir
;
1122 SrcPanel
->GetCurDir(strCurDir
);
1125 GetFileOwner(strComputerName
, strSelName
, AttrDlg
[SA_COMBO_OWNER
].strData
);
1126 GetFileGroup(strComputerName
, strSelName
, AttrDlg
[SA_COMBO_GROUP
].strData
);
1127 } // end of if (SelCount==1)
1129 for (size_t i
= 0; i
< ARRAYSIZE(AP
); i
++) {
1130 AttrDlg
[AP
[i
].Item
].Selected
= BSTATE_3STATE
;
1133 AttrDlg
[SA_FIXEDIT_LAST_ACCESS_DATE
].strData
.Clear();
1134 AttrDlg
[SA_FIXEDIT_LAST_ACCESS_TIME
].strData
.Clear();
1135 AttrDlg
[SA_FIXEDIT_LAST_MODIFICATION_DATE
].strData
.Clear();
1136 AttrDlg
[SA_FIXEDIT_LAST_MODIFICATION_TIME
].strData
.Clear();
1137 AttrDlg
[SA_FIXEDIT_LAST_CHANGE_DATE
].strData
.Clear();
1138 AttrDlg
[SA_FIXEDIT_LAST_CHANGE_TIME
].strData
.Clear();
1139 AttrDlg
[SA_BUTTON_ORIGINAL
].Flags
|= DIF_DISABLE
;
1140 AttrDlg
[SA_TEXT_NAME
].strData
= Msg::SetAttrSelectedObjects
;
1142 for (auto i
: PreserveOriginalIDs
) {
1143 AttrDlg
[i
].Selected
= BSTATE_UNCHECKED
;
1146 // проверка - есть ли среди выделенных - каталоги?
1147 // так же проверка на атрибуты
1148 // так же подсчет числа каталогов и symlinks
1150 SrcPanel
->GetSelName(nullptr, FileAttr
, FileMode
);
1152 FolderPresent
= false;
1153 FolderCount
= 0; Link2FileCount
= 0; Link2DirCount
= 0;
1156 FARString strComputerName
;
1157 FARString strCurDir
;
1158 SrcPanel
->GetCurDir(strCurDir
);
1160 while (SrcPanel
->GetSelName(&strSelName
, FileAttr
, FileMode
, &FindData
)) {
1161 if (FileAttr
& FILE_ATTRIBUTE_DIRECTORY
) {
1162 if (FileAttr
& FILE_ATTRIBUTE_REPARSE_POINT
)
1166 if (!FolderPresent
) {
1167 FolderPresent
= true;
1168 AttrDlg
[SA_SEPARATOR4
].Flags
&= ~DIF_HIDDEN
;
1169 AttrDlg
[SA_CHECKBOX_SUBFOLDERS
].Flags
&= ~(DIF_DISABLE
| DIF_HIDDEN
);
1170 AttrDlg
[SA_DOUBLEBOX
].Y2
+= 2;
1171 for (int i
= SA_SEPARATOR5
; i
<= SA_BUTTON_CANCEL
; i
++) {
1178 else if (FileAttr
& FILE_ATTRIBUTE_REPARSE_POINT
)
1181 for (size_t i
= 0; i
< ARRAYSIZE(AP
); i
++) {
1182 if (FileMode
& AP
[i
].Mode
) {
1183 AttrDlg
[AP
[i
].Item
].Selected
++;
1186 CheckFileOwnerGroup(AttrDlg
[SA_COMBO_OWNER
], GetFileOwner
, strComputerName
, strSelName
);
1187 CheckFileOwnerGroup(AttrDlg
[SA_COMBO_GROUP
], GetFileGroup
, strComputerName
, strSelName
);
1189 FSFileFlagsSafe
FFFlags(strSelName
.GetMB(), FileAttr
);
1190 if (FFFlags
.Immutable())
1191 AttrDlg
[SA_CHECKBOX_IMMUTABLE
].Selected
++;
1192 if (FFFlags
.Append())
1193 AttrDlg
[SA_CHECKBOX_APPEND
].Selected
++;
1194 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
1195 if (FFFlags
.Hidden())
1196 AttrDlg
[SA_CHECKBOX_HIDDEN
].Selected
++;
1200 // BUGBUG, copy-paste
1201 if (!FolderPresent
&& (FindData
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)) {
1202 FolderPresent
= true;
1203 AttrDlg
[SA_SEPARATOR4
].Flags
&= ~DIF_HIDDEN
;
1204 AttrDlg
[SA_CHECKBOX_SUBFOLDERS
].Flags
&= ~(DIF_DISABLE
| DIF_HIDDEN
);
1205 AttrDlg
[SA_DOUBLEBOX
].Y2
+= 2;
1206 for (int i
= SA_SEPARATOR5
; i
<= SA_BUTTON_CANCEL
; i
++) {
1212 for (size_t i
= 0; i
< ARRAYSIZE(AP
); i
++) {
1213 if (FindData
.dwUnixMode
& AP
[i
].Mode
) {
1214 AttrDlg
[AP
[i
].Item
].Selected
++;
1219 SrcPanel
->GetSelName(nullptr, FileAttr
, FileMode
);
1220 SrcPanel
->GetSelName(&strSelName
, FileAttr
, FileMode
, &FindData
);
1223 // выставим "неопределенку" или то, что нужно
1224 for (auto i
: PreserveOriginalIDs
) {
1225 // снимаем 3-state, если "есть все или нет ничего"
1226 // за исключением случая, если есть Фолдер среди объектов
1227 if ((!AttrDlg
[i
].Selected
|| AttrDlg
[i
].Selected
>= SelCount
) && !FolderPresent
) {
1228 AttrDlg
[i
].Flags
&= ~DIF_3STATE
;
1231 AttrDlg
[i
].Selected
= (AttrDlg
[i
].Selected
>= SelCount
)
1233 : (!AttrDlg
[i
].Selected
? BSTATE_UNCHECKED
: BSTATE_3STATE
);
1237 FARString strTmp
, strSep
=L
" (";
1238 int FilesCount
= SelCount
-FolderCount
-Link2FileCount
-Link2DirCount
;
1239 strTmp
.Format(Msg::SetAttrInfoSelAll
, SelCount
);
1241 { strTmp
.AppendFormat(Msg::SetAttrInfoSelDirs
, strSep
.CPtr(), FolderCount
); strSep
=L
", "; }
1243 { strTmp
.AppendFormat(Msg::SetAttrInfoSelFiles
, strSep
.CPtr(), FilesCount
); strSep
=L
", "; }
1244 if (Link2DirCount
>0)
1245 { strTmp
.AppendFormat(Msg::SetAttrInfoSelSymDirs
, strSep
.CPtr(), Link2DirCount
); strSep
=L
", "; }
1246 if (Link2FileCount
>0)
1247 strTmp
.AppendFormat(Msg::SetAttrInfoSelSymFiles
, strSep
.CPtr(), Link2FileCount
);
1248 strTmp
.Append(L
')');
1249 AttrDlg
[SA_EDIT_INFO
].strData
= strTmp
;
1254 // поведение для каталогов как у 1.65?
1255 if (FolderPresent
&& !Opt
.SetAttrFolderRules
) {
1256 AttrDlg
[SA_CHECKBOX_SUBFOLDERS
].Selected
= BSTATE_CHECKED
;
1257 AttrDlg
[SA_FIXEDIT_LAST_ACCESS_DATE
].strData
.Clear();
1258 AttrDlg
[SA_FIXEDIT_LAST_ACCESS_TIME
].strData
.Clear();
1259 AttrDlg
[SA_FIXEDIT_LAST_MODIFICATION_DATE
].strData
.Clear();
1260 AttrDlg
[SA_FIXEDIT_LAST_MODIFICATION_TIME
].strData
.Clear();
1261 AttrDlg
[SA_FIXEDIT_LAST_CHANGE_DATE
].strData
.Clear();
1262 AttrDlg
[SA_FIXEDIT_LAST_CHANGE_TIME
].strData
.Clear();
1264 for (auto i
: PreserveOriginalIDs
) {
1265 AttrDlg
[i
].Selected
= BSTATE_3STATE
;
1266 AttrDlg
[i
].Flags
|= DIF_3STATE
;
1270 // запомним состояние переключателей.
1271 for (size_t i
= 0; i
< ARRAYSIZE(PreserveOriginalIDs
); ++i
) {
1272 DlgParam
.OriginalCBAttr
[i
] = DlgParam
.OriginalCBAttr0
[i
] =AttrDlg
[PreserveOriginalIDs
[i
]].Selected
;
1273 DlgParam
.OriginalCBAttr2
[i
] = -1;
1274 DlgParam
.OriginalCBFlag
[i
] = AttrDlg
[PreserveOriginalIDs
[i
]].Flags
;
1277 DlgParam
.strOwner
= AttrDlg
[SA_COMBO_OWNER
].strData
;
1278 DlgParam
.strGroup
= AttrDlg
[SA_COMBO_GROUP
].strData
;
1279 FARString strInitOwner
= DlgParam
.strOwner
, strInitGroup
= DlgParam
.strGroup
;
1281 DlgParam
.DialogMode
= ((SelCount
== 1 && !(FileAttr
& FILE_ATTRIBUTE_DIRECTORY
))
1283 : (SelCount
== 1 ? MODE_FOLDER
: MODE_MULTIPLE
));
1284 DlgParam
.strSelName
= strSelName
;
1285 DlgParam
.OSubfoldersState
= static_cast<FARCHECKEDSTATE
>(AttrDlg
[SA_CHECKBOX_SUBFOLDERS
].Selected
);
1287 Dialog
Dlg(AttrDlg
, ARRAYSIZE(AttrDlgData
), SetAttrDlgProc
, (LONG_PTR
)&DlgParam
);
1288 Dlg
.SetHelp(L
"FileAttrDlg"); // ^ - это одиночный диалог!
1289 Dlg
.SetId(FileAttrDlgId
);
1291 /*if (LinkPresent) {
1295 Dlg
.SetPosition(-1, -1, DlgX
, DlgY
);
1296 SetAttrCalcBitsCharFromModeCheckBoxes(&Dlg
); // set octal
1299 switch (Dlg
.GetExitCode()) {
1300 case SA_BUTTON_SET
: {
1301 const size_t Times
[] = {SA_FIXEDIT_LAST_ACCESS_TIME
, SA_FIXEDIT_LAST_MODIFICATION_TIME
,
1302 SA_FIXEDIT_LAST_CHANGE_TIME
};
1304 for (size_t i
= 0; i
< ARRAYSIZE(Times
); i
++) {
1305 LPWSTR TimePtr
= AttrDlg
[Times
[i
]].strData
.GetBuffer();
1306 TimePtr
[8] = GetTimeSeparator();
1307 AttrDlg
[Times
[i
]].strData
.ReleaseBuffer(AttrDlg
[Times
[i
]].strData
.GetLength());
1310 TPreRedrawFuncGuard
preRedrawFuncGuard(PR_ShellSetFileAttributesMsg
);
1311 ShellSetFileAttributesMsg(SelCount
== 1 ? strSelName
.CPtr() : nullptr);
1312 int SkipMode
= SETATTR_RET_UNKNOWN
;
1314 if (SelCount
== 1 && (FileAttr
& FILE_ATTRIBUTE_REPARSE_POINT
) != 0) {
1315 FARString OldSymLink
;
1316 ReadSymlink(strSelName
, OldSymLink
);
1317 if (DlgParam
.SymLink
!= OldSymLink
) {
1319 if ( !apiPathExists(DlgParam
.SymLink
) ) {
1320 FARString strTmp1
, strTmp2
, strTmp3
;
1321 strTmp1
.Format(Msg::SetAttrSymlinkWarn1
, strSelName
.CPtr());
1322 strTmp2
.Format(Msg::SetAttrSymlinkWarn2
, DlgParam
.SymLink
.CPtr());
1323 strTmp3
.Format(Msg::SetAttrSymlinkWarn3
, OldSymLink
.CPtr());
1324 r
= Message(MSG_WARNING
, 2,
1325 Msg::Error
, strTmp1
, strTmp2
, strTmp3
, L
" ", Msg::SetAttrSymlinkWarn4
,
1326 Msg::HSkip
, Msg::HChange
);
1329 fprintf(stderr
, "Symlink change: '%ls' -> '%ls'\n",
1330 OldSymLink
.CPtr(), DlgParam
.SymLink
.CPtr());
1331 sdc_unlink(strSelName
.GetMB().c_str());
1332 r
= sdc_symlink(DlgParam
.SymLink
.GetMB().c_str(), strSelName
.GetMB().c_str());
1334 Message(MSG_WARNING
| MSG_ERRORTYPE
, 1,
1335 Msg::Error
, Msg::SetAttrSymlinkFailed
, strSelName
, Msg::Ok
);
1340 if (SelCount
== 1 && !(FileAttr
& FILE_ATTRIBUTE_DIRECTORY
)) {
1343 for (size_t i
= 0; i
< ARRAYSIZE(AP
); i
++) {
1344 if (AttrDlg
[AP
[i
].Item
].Selected
) {
1345 NewMode
|= AP
[i
].Mode
;
1349 if (!ApplyFileOwnerGroupIfChanged(AttrDlg
[SA_COMBO_OWNER
], ESetFileOwner
, SkipMode
,
1350 strSelName
, strInitOwner
))
1352 if (!ApplyFileOwnerGroupIfChanged(AttrDlg
[SA_COMBO_GROUP
], ESetFileGroup
, SkipMode
,
1353 strSelName
, strInitGroup
))
1356 FILETIME UnixAccessTime
= {}, UnixModificationTime
= {};
1357 int SetAccessTime
= DlgParam
.OAccessTime
1358 && ReadFileTime(0, strSelName
, UnixAccessTime
,
1359 AttrDlg
[SA_FIXEDIT_LAST_ACCESS_DATE
].strData
,
1360 AttrDlg
[SA_FIXEDIT_LAST_ACCESS_TIME
].strData
);
1361 int SetModifyTime
= DlgParam
.OModifyTime
1362 && ReadFileTime(1, strSelName
, UnixModificationTime
,
1363 AttrDlg
[SA_FIXEDIT_LAST_MODIFICATION_DATE
].strData
,
1364 AttrDlg
[SA_FIXEDIT_LAST_MODIFICATION_TIME
].strData
);
1366 //_SVS(SysLog(L"\n\tSetWriteTime=%d\n\tSetCreationTime=%d\n\tSetLastAccessTime=%d",SetWriteTime,SetCreationTime,SetLastAccessTime));
1368 if (SetAccessTime
|| SetModifyTime
) {
1369 if (ESetFileTime(strSelName
, SetAccessTime
? &UnixAccessTime
: nullptr,
1370 SetModifyTime
? &UnixModificationTime
: nullptr, FileAttr
, SkipMode
)
1371 == SETATTR_RET_SKIPALL
) {
1372 SkipMode
= SETATTR_RET_SKIP
;
1376 if ((FileMode
& EDITABLE_MODES
) != (NewMode
& EDITABLE_MODES
)) {
1377 if (ESetFileMode(strSelName
, NewMode
, SkipMode
) == SETATTR_RET_SKIPALL
) {
1378 SkipMode
= SETATTR_RET_SKIP
;
1382 ApplyFSFileFlags(AttrDlg
, strSelName
, FileAttr
);
1384 /* Multi *********************************************************** */
1387 ConsoleTitle
SetAttrTitle(Msg::SetAttrTitle
);
1389 CtrlObject
->Cp()->GetAnotherPanel(SrcPanel
)->CloseFile();
1391 DWORD SetMode
= 0, ClearMode
= 0;
1393 for (size_t i
= 0; i
< ARRAYSIZE(AP
); i
++) {
1394 switch (AttrDlg
[AP
[i
].Item
].Selected
) {
1395 case BSTATE_CHECKED
:
1396 SetMode
|= AP
[i
].Mode
;
1398 case BSTATE_UNCHECKED
:
1399 ClearMode
|= AP
[i
].Mode
;
1405 SrcPanel
->GetSelName(nullptr, FileAttr
, FileMode
);
1408 bool Cancel
= false;
1411 bool SingleFileDone
= false;
1412 while ((SrcPanel
? SrcPanel
->GetSelName(&strSelName
, FileAttr
, FileMode
, &FindData
)
1416 SingleFileDone
= true;
1418 //_SVS(SysLog(L"SelName='%ls'\n\tFileAttr =0x%08X\n\tSetAttr =0x%08X\n\tClearAttr=0x%08X\n\tResult =0x%08X",
1419 // SelName,FileAttr,SetAttr,ClearAttr,((FileAttr|SetAttr)&(~ClearAttr))));
1420 DWORD CurTime
= WINPORT(GetTickCount
)();
1422 if (CurTime
- LastTime
> RedrawTimeout
) {
1424 ShellSetFileAttributesMsg(strSelName
);
1430 if (!ApplyFileOwnerGroupIfChanged(AttrDlg
[SA_COMBO_OWNER
], ESetFileOwner
, SkipMode
,
1431 strSelName
, strInitOwner
))
1433 if (!ApplyFileOwnerGroupIfChanged(AttrDlg
[SA_COMBO_GROUP
], ESetFileGroup
, SkipMode
,
1434 strSelName
, strInitGroup
))
1437 FILETIME UnixAccessTime
= {}, UnixModificationTime
= {};
1438 int SetAccessTime
= DlgParam
.OAccessTime
1439 && ReadFileTime(0, strSelName
, UnixAccessTime
,
1440 AttrDlg
[SA_FIXEDIT_LAST_ACCESS_DATE
].strData
,
1441 AttrDlg
[SA_FIXEDIT_LAST_ACCESS_TIME
].strData
);
1442 int SetModifyTime
= DlgParam
.OModifyTime
1443 && ReadFileTime(1, strSelName
, UnixModificationTime
,
1444 AttrDlg
[SA_FIXEDIT_LAST_MODIFICATION_DATE
].strData
,
1445 AttrDlg
[SA_FIXEDIT_LAST_MODIFICATION_TIME
].strData
);
1447 RetCode
= ESetFileTime(strSelName
, SetAccessTime
? &UnixAccessTime
: nullptr,
1448 SetModifyTime
? &UnixModificationTime
: nullptr, FileAttr
, SkipMode
);
1450 if (RetCode
== SETATTR_RET_ERROR
)
1452 else if (RetCode
== SETATTR_RET_SKIP
)
1454 else if (RetCode
== SETATTR_RET_SKIPALL
) {
1455 SkipMode
= SETATTR_RET_SKIP
;
1459 if (FileAttr
!= INVALID_FILE_ATTRIBUTES
) {
1460 if (((FileMode
| SetMode
) & ~ClearMode
) != FileMode
) {
1462 RetCode
= ESetFileMode(strSelName
, ((FileMode
| SetMode
) & (~ClearMode
)),
1465 if (RetCode
== SETATTR_RET_ERROR
)
1467 else if (RetCode
== SETATTR_RET_SKIP
)
1469 else if (RetCode
== SETATTR_RET_SKIPALL
) {
1470 SkipMode
= SETATTR_RET_SKIP
;
1475 if ((FileAttr
& FILE_ATTRIBUTE_DIRECTORY
)
1476 && AttrDlg
[SA_CHECKBOX_SUBFOLDERS
].Selected
) {
1477 ScanTree
ScTree(FALSE
);
1478 ScTree
.SetFindPath(strSelName
, L
"*");
1479 DWORD LastTime
= WINPORT(GetTickCount
)();
1480 FARString strFullName
;
1482 while (ScTree
.GetNextName(&FindData
, strFullName
)) {
1483 DWORD CurTime
= WINPORT(GetTickCount
)();
1485 if (CurTime
- LastTime
> RedrawTimeout
) {
1487 ShellSetFileAttributesMsg(strFullName
);
1489 if (CheckForEsc()) {
1495 if (!ApplyFileOwnerGroupIfChanged(AttrDlg
[SA_COMBO_GROUP
], ESetFileOwner
,
1496 SkipMode
, strFullName
, strInitOwner
,
1497 DlgParam
.OSubfoldersState
))
1499 if (!ApplyFileOwnerGroupIfChanged(AttrDlg
[SA_COMBO_GROUP
], ESetFileGroup
,
1500 SkipMode
, strFullName
, strInitGroup
,
1501 DlgParam
.OSubfoldersState
))
1504 SetAccessTime
= DlgParam
.OAccessTime
1505 && ReadFileTime(0, strFullName
, UnixAccessTime
,
1506 AttrDlg
[SA_FIXEDIT_LAST_ACCESS_DATE
].strData
,
1507 AttrDlg
[SA_FIXEDIT_LAST_ACCESS_TIME
].strData
);
1508 SetModifyTime
= DlgParam
.OModifyTime
1509 && ReadFileTime(1, strFullName
, UnixModificationTime
,
1510 AttrDlg
[SA_FIXEDIT_LAST_MODIFICATION_DATE
].strData
,
1511 AttrDlg
[SA_FIXEDIT_LAST_MODIFICATION_TIME
].strData
);
1513 if (SetAccessTime
|| SetModifyTime
) {
1514 RetCode
= ESetFileTime(strFullName
,
1515 SetAccessTime
? &UnixAccessTime
: nullptr,
1516 SetModifyTime
? &UnixModificationTime
: nullptr,
1517 FindData
.dwFileAttributes
, SkipMode
);
1519 if (RetCode
== SETATTR_RET_ERROR
) {
1522 } else if (RetCode
== SETATTR_RET_SKIP
)
1524 else if (RetCode
== SETATTR_RET_SKIPALL
) {
1525 SkipMode
= SETATTR_RET_SKIP
;
1530 if (((FindData
.dwUnixMode
| SetMode
) & (~ClearMode
))
1531 != FindData
.dwUnixMode
) {
1532 RetCode
= ESetFileMode(strFullName
,
1533 (FindData
.dwUnixMode
| SetMode
) & (~ClearMode
), SkipMode
);
1535 if (RetCode
== SETATTR_RET_ERROR
) {
1538 } else if (RetCode
== SETATTR_RET_SKIP
)
1540 else if (RetCode
== SETATTR_RET_SKIPALL
) {
1541 SkipMode
= SETATTR_RET_SKIP
;
1544 ApplyFSFileFlags(AttrDlg
, strFullName
, FileAttr
);
1549 ApplyFSFileFlags(AttrDlg
, strSelName
, FileAttr
);
1551 } // END: while (SrcPanel->GetSelNameCompat(...))
1560 SrcPanel
->SaveSelection();
1561 SrcPanel
->Update(UPDATE_KEEP_SELECTION
);
1562 SrcPanel
->ClearSelection();
1563 CtrlObject
->Cp()->GetAnotherPanel(SrcPanel
)->Update(UPDATE_KEEP_SELECTION
| UPDATE_SECONDARY
);
1565 CtrlObject
->Cp()->Redraw();