1 /*
2  * Part of WCM Commander
3  * https://github.com/corporateshark/WCMCommander
4  * wcm@linderdaum.com
5  */
6 
7 #include "fileattributes.h"
8 
9 #include "ncdialogs.h"
10 #include "dialog_enums.h"
11 #include "dialog_helpers.h"
12 #include "ltext.h"
13 #include "panel.h"
14 #include "vfs.h"
15 
16 /*
17 Windows:
18 	Read only
19 	Archive
20 	Hidden
21 	System
22 	Compressed
23 	Encrypted
24 
25 	Not Indexed
26 	Sparse
27 	Temporary
28 	Offline
29 	Reparse point
30 	Virtual
31 
32 *NIX:
33 	Read by owner
34 	Write by owner
35 	Execute by owner
36 	Read by group
37 	Write by group
38 	Execute by group
39 	Read by others
40 	Write by others
41 	Execute by others
42 	Owner name
43 	Group Name
44 
45 Common:
46 	Last write time
47 	Creation time
48 	Last access time
49 	Change time (unsupported yet)
50 */
51 
52 class clFileAttributesWin: public NCVertDialog
53 {
54 public:
clFileAttributesWin(NCDialogParent * parent,PanelWin * Panel)55 	clFileAttributesWin( NCDialogParent* parent, PanelWin* Panel )
56 	 : NCVertDialog( ::createDialogAsChild, 0, parent, utf8_to_unicode(_LT("Attributes")).data(), bListOkCancel )
57 	 , m_Panel( Panel )
58 	 , m_Node( Panel ? Panel->GetCurrent() : nullptr )
59 	 , m_URI( Panel ? Panel->UriOfCurrent() : FSString() )
60 	 , m_Layout( 17, 3 )
61 	 , m_CaptionText( 0, this, utf8_to_unicode( _LT( "" ) ).data(), nullptr, StaticLine::CENTER )
62 	 , m_FileNameText( uiValue, this, utf8_to_unicode( _LT( "" ) ).data(), nullptr, StaticLine::CENTER )
63 #if defined(_WIN32)
64 	 , m_ReadOnly( uiVariable, this, utf8_to_unicode( _LT( "Read only" ) ).data(), 0, false )
65 	 , m_Archive( uiVariable, this, utf8_to_unicode( _LT( "Archive" ) ).data(), 0, false )
66 	 , m_Hidden( uiVariable, this, utf8_to_unicode( _LT( "Hidden" ) ).data(), 0, false )
67 	 , m_System( uiVariable, this, utf8_to_unicode( _LT( "System" ) ).data(), 0, false )
68 	 , m_Compressed( 0, this, utf8_to_unicode( _LT( "Compressed" ) ).data(), 0, false )
69 	 , m_Encrypted( 0, this, utf8_to_unicode( _LT( "Encrypted" ) ).data(), 0, false )
70 	 , m_NotIndexed( 0, this, utf8_to_unicode( _LT( "NotIndexed" ) ).data(), 0, false )
71 	 , m_Sparse( 0, this, utf8_to_unicode( _LT( "Sparse" ) ).data(), 0, false )
72 	 , m_Temporary( 0, this, utf8_to_unicode( _LT( "Temporary" ) ).data(), 0, false )
73 	 , m_Offline( 0, this, utf8_to_unicode( _LT( "Offline" ) ).data(), 0, false )
74 	 , m_ReparsePoint( 0, this, utf8_to_unicode( _LT( "ReparsePoint" ) ).data(), 0, false )
75 	 , m_Virtual( 0, this, utf8_to_unicode( _LT( "Virtual" ) ).data(), 0, false )
76 #else
77 	 , m_UserRead( uiVariable, this, utf8_to_unicode( _LT( "User &read" ) ).data(), 0, false )
78 	 , m_UserWrite( uiVariable, this, utf8_to_unicode( _LT( "User &write" ) ).data(), 0, false )
79     , m_UserExecute( uiVariable, this, utf8_to_unicode( _LT( "User e&xecute" ) ).data(), 0, false )
80 	 , m_GroupRead( uiVariable, this, utf8_to_unicode( _LT( "&Group read" ) ).data(), 0, false )
81 	 , m_GroupWrite( uiVariable, this, utf8_to_unicode( _LT( "Group write" ) ).data(), 0, false )
82 	 , m_GroupExecute( uiVariable, this, utf8_to_unicode( _LT( "Group execute" ) ).data(), 0, false )
83 	 , m_OthersRead( uiVariable, this, utf8_to_unicode( _LT( "&Others read" ) ).data(), 0, false )
84 	 , m_OthersWrite( uiVariable, this, utf8_to_unicode( _LT( "Others write" ) ).data(), 0, false )
85 	 , m_OthersExecute( uiVariable, this, utf8_to_unicode( _LT( "Others execute" ) ).data(), 0, false )
86 #endif
87 	// time
88 	 , m_LastWriteTimeLabel( 0, this, utf8_to_unicode( _LT( "Last write time" ) ).data(), nullptr, StaticLine::LEFT )
89 	 , m_CreationTimeLabel( 0, this, utf8_to_unicode( _LT( "Creation time" ) ).data(), nullptr, StaticLine::LEFT )
90 	 , m_LastAccessTimeLabel( 0, this, utf8_to_unicode( _LT( "Last access time" ) ).data(), nullptr, StaticLine::LEFT )
91 	 , m_ChangeTimeLabel( 0, this, utf8_to_unicode( _LT( "Change time" ) ).data(), nullptr, StaticLine::LEFT )
92 	 //
93 	 , m_LastWriteDate( 0, this, nullptr, utf8_to_unicode( _LT( "DD.MM.YYYY" ) ).data(), 9 )
94 	 , m_CreationDate( 0, this, nullptr, utf8_to_unicode( _LT( "DD.MM.YYYY" ) ).data(), 9 )
95 	 , m_LastAccessDate( 0, this, nullptr, utf8_to_unicode( _LT( "DD.MM.YYYY" ) ).data(), 9 )
96 	 , m_ChangeDate( 0, this, nullptr, utf8_to_unicode( _LT( "DD.MM.YYYY" ) ).data(), 9 )
97 	 //
98 	 , m_LastWriteTime( 0, this, nullptr, utf8_to_unicode( _LT( "HH:MM:SS" ) ).data(), 13 )
99 	 , m_CreationTime( 0, this, nullptr, utf8_to_unicode( _LT( "HH:MM:SS" ) ).data(), 13 )
100 	 , m_LastAccessTime( 0, this, nullptr, utf8_to_unicode( _LT( "HH:MM:SS" ) ).data(), 13 )
101 	 , m_ChangeTime( 0, this, nullptr, utf8_to_unicode( _LT( "HH:MM:SS" ) ).data(), 13 )
102 	{
103 		if ( m_Panel )
104 		{
105 			const unicode_t* FileName = m_Panel->GetCurrentFileName();
106 
107 			m_FileNameText.SetText( FileName );
108 		}
109 
110 		if ( m_Node && m_Node->IsDir() )
111 		{
112 			m_CaptionText.SetText( utf8_to_unicode( _LT("Change attributes for folder:") ).data() );
113 		}
114 		else
115 		{
116 			m_CaptionText.SetText( utf8_to_unicode( _LT("Change file attributes for:") ).data() );
117 		}
118 
119 		int Row = 0;
120 
121 		m_Layout.AddWinAndEnable( &m_CaptionText, Row, 0, Row, 2 ); Row++;
122 		m_Layout.AddWinAndEnable( &m_FileNameText, Row, 0, Row, 2 ); Row++;
123 
124 		int TRow = Row;
125 
126 #if defined(_WIN32)
127 		m_Layout.AddWinAndEnable( &m_ReadOnly, Row++, 0 );
128 		m_Layout.AddWinAndEnable( &m_Archive, Row++, 0 );
129 		m_Layout.AddWinAndEnable( &m_Hidden, Row++, 0 );
130 		m_Layout.AddWinAndEnable( &m_System, Row++, 0 );
131 		m_Layout.AddWinAndEnable( &m_Compressed, Row++, 0 );
132 		m_Layout.AddWinAndEnable( &m_Encrypted, Row++, 0 );
133 		Row = TRow;
134 		m_Layout.AddWinAndEnable( &m_NotIndexed, Row++, 1 );
135 		m_Layout.AddWinAndEnable( &m_Sparse, Row++, 1 );
136 		m_Layout.AddWinAndEnable( &m_Temporary, Row++, 1 );
137 		m_Layout.AddWinAndEnable( &m_Offline, Row++, 1 );
138 		m_Layout.AddWinAndEnable( &m_ReparsePoint, Row++, 1 );
139 		m_Layout.AddWinAndEnable( &m_Virtual, Row++, 1 );
140 
141 		// disable editing of these properties
142 		m_Compressed.Enable( false );
143 		m_Encrypted.Enable( false );
144 		m_NotIndexed.Enable( false );
145 		m_Sparse.Enable( false );
146 		m_Temporary.Enable( false );
147 		m_Offline.Enable( false );
148 		m_ReparsePoint.Enable( false );
149 		m_Virtual.Enable( false );
150 #else
151 		m_Layout.AddWinAndEnable( &m_UserRead, Row, 0 );
152 		m_Layout.AddWinAndEnable( &m_UserWrite, Row, 1 );
153 		m_Layout.AddWinAndEnable( &m_UserExecute, Row, 2 );
154 		Row++;
155 		m_Layout.AddWinAndEnable( &m_GroupRead, Row, 0 );
156 		m_Layout.AddWinAndEnable( &m_GroupWrite, Row, 1 );
157 		m_Layout.AddWinAndEnable( &m_GroupExecute, Row, 2 );
158 		Row++;
159 		m_Layout.AddWinAndEnable( &m_OthersRead, Row, 0 );
160 		m_Layout.AddWinAndEnable( &m_OthersWrite, Row, 1 );
161 		m_Layout.AddWinAndEnable( &m_OthersExecute, Row, 2 );
162 #endif
163 
164 		m_Layout.LineSet( Row++, 5 );
165 
166 		TRow = Row;
167 		m_Layout.AddWinAndEnable( &m_LastWriteTimeLabel, Row++, 0 );
168 		m_Layout.AddWinAndEnable( &m_CreationTimeLabel, Row++, 0 );
169 		m_Layout.AddWinAndEnable( &m_LastAccessTimeLabel, Row++, 0 );
170 #if defined(HAS_CHANGETIME)
171 		m_Layout.AddWinAndEnable( &m_ChangeTimeLabel, Row++, 0 );
172 #endif
173 		Row = TRow;
174 		m_Layout.AddWinAndEnable( &m_LastWriteDate, Row++, 1 );
175 		m_Layout.AddWinAndEnable( &m_CreationDate, Row++, 1 );
176 		m_Layout.AddWinAndEnable( &m_LastAccessDate, Row++, 1 );
177 #if defined(HAS_CHANGETIME)
178 		m_Layout.AddWinAndEnable( &m_ChangeDate, Row++, 1 );
179 #endif
180 		Row = TRow;
181 		m_Layout.AddWinAndEnable( &m_LastWriteTime, Row++, 2 );
182 		m_Layout.AddWinAndEnable( &m_CreationTime, Row++, 2 );
183 		m_Layout.AddWinAndEnable( &m_LastAccessTime, Row++, 2 );
184 #if defined(HAS_CHANGETIME)
185 		m_Layout.AddWinAndEnable( &m_ChangeTime, Row++, 2 );
186 #endif
187 
188 		m_LastWriteDate.SetValidator( new clDateValidator() );
189 		m_LastWriteDate.SetReplaceMode( true );
190 		m_CreationDate.SetValidator( new clDateValidator() );
191 		m_CreationDate.SetReplaceMode( true );
192 		m_LastAccessDate.SetValidator( new clDateValidator() );
193 		m_LastAccessDate.SetReplaceMode( true );
194 #if defined(HAS_CHANGETIME)
195 		m_ChangeDate.SetValidator( new clDateValidator() );
196 		m_ChangeDate.SetReplaceMode( true );
197 #endif
198 		m_LastWriteTime.SetValidator( new clTimeValidator() );
199 		m_LastWriteTime.SetReplaceMode( true );
200 		m_CreationTime.SetValidator( new clTimeValidator() );
201 		m_CreationTime.SetReplaceMode( true );
202 		m_LastAccessTime.SetValidator( new clTimeValidator() );
203 		m_LastAccessTime.SetReplaceMode( true );
204 #if defined(HAS_CHANGETIME)
205 		m_ChangeTime.SetValidator( new clTimeValidator() );
206 		m_ChangeTime.SetReplaceMode( true );
207 #endif
208 
209 		UpdateAttributes( m_Node );
210 
211 		AddLayout( &m_Layout );
212 
213 		order.clear();
214 #if defined(_WIN32)
215 		order.append(&m_ReadOnly);
216 		order.append(&m_Archive);
217 		order.append(&m_Hidden);
218 		order.append(&m_System);
219 #else
220 		order.append(&m_UserRead);
221 		order.append(&m_UserWrite);
222 		order.append(&m_UserExecute);
223 		order.append(&m_GroupRead);
224 		order.append(&m_GroupWrite);
225 		order.append(&m_GroupExecute);
226 		order.append(&m_OthersRead);
227 		order.append(&m_OthersWrite);
228 		order.append(&m_OthersExecute);
229 #endif // _WIN32
230 		order.append(&m_LastWriteDate);
231 		order.append(&m_LastWriteTime);
232 		order.append(&m_CreationDate);
233 		order.append(&m_CreationTime);
234 		order.append(&m_LastAccessDate);
235 		order.append(&m_LastAccessTime);
236 #if defined(HAS_CHANGETIME)
237 		order.append(&m_ChangeDate);
238 		order.append(&m_ChangeTime);
239 #endif // HAS_CHANGETIME
240 
241 		SetEnterCmd( CMD_OK );
242 		SetPosition();
243 	}
244 
GetURI() const245 	FSString GetURI() const { return m_URI; }
246 
GetNode() const247 	FSNode* GetNode() const
248 	{
249 		if ( !m_Node ) return nullptr;
250 
251 #if defined(_WIN32)
252 		m_Node->SetAttrReadOnly( m_ReadOnly.IsSet() );
253 		m_Node->SetAttrArchive( m_Archive.IsSet() );
254 		m_Node->SetAttrHidden( m_Hidden.IsSet() );
255 		m_Node->SetAttrSystem( m_System.IsSet() );
256 //		m_Node->SetAttrNotIndexed( m_NotIndexed.IsSet() );
257 //		m_Node->SetAttrTemporary( m_Temporary.IsSet() );
258 #else
259 		m_Node->SetAttrUserRead( m_UserRead.IsSet() );
260 		m_Node->SetAttrUserWrite( m_UserWrite.IsSet() );
261 		m_Node->SetAttrUserExecute( m_UserExecute.IsSet() );
262 		m_Node->SetAttrGroupRead( m_GroupRead.IsSet() );
263 		m_Node->SetAttrGroupWrite( m_GroupWrite.IsSet() );
264 		m_Node->SetAttrGroupExecute( m_GroupExecute.IsSet() );
265 		m_Node->SetAttrOthersRead( m_OthersRead.IsSet() );
266 		m_Node->SetAttrOthersWrite( m_OthersWrite.IsSet() );
267 		m_Node->SetAttrOthersExecute( m_OthersExecute.IsSet() );
268 #endif
269 		std::string LastWriteDate = m_LastWriteDate.GetTextStr();
270 		std::string LastWriteTime = m_LastWriteTime.GetTextStr();
271 		std::string CreationDate = m_CreationDate.GetTextStr();
272 		std::string CreationTime = m_CreationTime.GetTextStr();
273 		std::string LastAccessDate = m_LastAccessDate.GetTextStr();
274 		std::string LastAccessTime = m_LastAccessTime.GetTextStr();
275 		std::string ChangeDate = m_ChangeDate.GetTextStr();
276 		std::string ChangeTime = m_ChangeTime.GetTextStr();
277 
278 		m_Node->SetLastWriteTime( GetFSTimeFromStr( LastWriteDate, LastWriteTime ) );
279 		m_Node->SetCreationTime( GetFSTimeFromStr( CreationDate, CreationTime ) );
280 		m_Node->SetLastAccessTime( GetFSTimeFromStr( LastAccessDate, LastAccessTime ) );
281 		m_Node->SetChangeTime( GetFSTimeFromStr( ChangeDate, ChangeTime ) );
282 
283 		return m_Node;
284 	}
285 
286 private:
UpdateAttributes(FSNode * Node)287 	void UpdateAttributes( FSNode* Node )
288 	{
289 		if ( !Node ) return;
290 #if defined(_WIN32)
291 		m_ReadOnly.Change( Node->IsAttrReadOnly() );
292 		m_Archive.Change( Node->IsAttrArchive() );
293 		m_Hidden.Change( Node->IsAttrHidden() );
294 		m_System.Change( Node->IsAttrSystem() );
295 		m_Compressed.Change( Node->IsAttrCompressed() );
296 		m_Encrypted.Change( Node->IsAttrEncrypted() );
297 		m_NotIndexed.Change( Node->IsAttrNotIndexed() );
298 		m_Sparse.Change( Node->IsAttrSparse() );
299 		m_Temporary.Change( Node->IsAttrTemporary() );
300 		m_Offline.Change( Node->IsAttrOffline() );
301 		m_ReparsePoint.Change( Node->IsAttrReparsePoint() );
302 		m_Virtual.Change( Node->IsAttrVirtual() );
303 #else
304 		m_UserRead.Change( Node->IsAttrUserRead() );
305 		m_UserWrite.Change( Node->IsAttrUserWrite() );
306 		m_UserExecute.Change( Node->IsAttrUserExecute() );
307 		m_GroupRead.Change( Node->IsAttrGroupRead() );
308 		m_GroupWrite.Change( Node->IsAttrGroupWrite() );
309 		m_GroupExecute.Change( Node->IsAttrGroupExecute() );
310 		m_OthersRead.Change( Node->IsAttrOthersRead() );
311 		m_OthersWrite.Change( Node->IsAttrOthersWrite() );
312 		m_OthersExecute.Change( Node->IsAttrOthersExecute() );
313 #endif
314 		FSTime LastWriteTime = Node->GetLastWriteTime();
315 		FSTime CreationTime = Node->GetCreationTime();
316 		FSTime LastAccessTime = Node->GetLastAccessTime();
317 		FSTime ChangeTime = Node->GetChangeTime();
318 
319 		m_LastWriteDate.SetText( GetFSTimeStrDate( LastWriteTime ) );
320 		m_CreationDate.SetText( GetFSTimeStrDate( CreationTime ) );
321 		m_LastAccessDate.SetText( GetFSTimeStrDate( LastAccessTime ) );
322 		m_ChangeDate.SetText( GetFSTimeStrDate( ChangeTime ) );
323 
324 		m_LastWriteTime.SetText( GetFSTimeStrTime( LastWriteTime ) );
325 		m_CreationTime.SetText( GetFSTimeStrTime( CreationTime ) );
326 		m_LastAccessTime.SetText( GetFSTimeStrTime( LastAccessTime ) );
327 		m_ChangeTime.SetText( GetFSTimeStrTime( ChangeTime ) );
328 	}
329 
330 private:
331 	PanelWin* m_Panel;
332 	FSNode* m_Node;
333 	FSString m_URI;
334 
335 	Layout m_Layout;
336 
337 	StaticLine m_CaptionText;
338 	StaticLine m_FileNameText;
339 #if defined(_WIN32)
340 	SButton m_ReadOnly;
341 	SButton m_Archive;
342 	SButton m_Hidden;
343 	SButton m_System;
344 	SButton m_Compressed;
345 	SButton m_Encrypted;
346 	SButton m_NotIndexed;
347 	SButton m_Sparse;
348 	SButton m_Temporary;
349 	SButton m_Offline;
350 	SButton m_ReparsePoint;
351 	SButton m_Virtual;
352 #else
353 	SButton m_UserRead;
354 	SButton m_UserWrite;
355 	SButton m_UserExecute;
356 	SButton m_GroupRead;
357 	SButton m_GroupWrite;
358 	SButton m_GroupExecute;
359 	SButton m_OthersRead;
360 	SButton m_OthersWrite;
361 	SButton m_OthersExecute;
362 #endif
363 	// time
364 	StaticLine m_LastWriteTimeLabel;
365 	StaticLine m_CreationTimeLabel;
366 	StaticLine m_LastAccessTimeLabel;
367 	StaticLine m_ChangeTimeLabel;
368 
369 	EditLine m_LastWriteDate;
370 	EditLine m_CreationDate;
371 	EditLine m_LastAccessDate;
372 	EditLine m_ChangeDate;
373 
374 	EditLine m_LastWriteTime;
375 	EditLine m_CreationTime;
376 	EditLine m_LastAccessTime;
377 	EditLine m_ChangeTime;
378 };
379 
FileAttributesDlg(NCDialogParent * Parent,PanelWin * Panel)380 bool FileAttributesDlg( NCDialogParent* Parent, PanelWin* Panel )
381 {
382 	clFileAttributesWin Dialog( Parent, Panel );
383 
384 	if ( Dialog.DoModal( ) == CMD_OK )
385 	{
386 		FSNode* Node = Dialog.GetNode();
387 
388 		// apply changes
389 		if ( Node )
390 		{
391 			FSPath fspath;
392 			FSString URI = Dialog.GetURI();
393 			clPtr<FS> fs = ParzeURI( URI.GetUnicode(), fspath, {} );
394 			if ( fs )
395 			{
396 				int Err = 0;
397 				FSCInfo Info;
398 				fs->StatSetAttr( fspath, &Node->st, &Err, &Info );
399 				if ( Err != 0 )
400 				{
401 					throw_msg( "Error setting file attributes: %s", fs->StrError( Err ).GetUtf8() );
402 				}
403 				fs->SetFileTime( fspath, Node->GetCreationTime(), Node->GetLastAccessTime(), Node->GetLastWriteTime(), &Err, &Info );
404 				if ( Err != 0 )
405 				{
406 					throw_msg("Error setting file date & time: %s", fs->StrError(Err).GetUtf8());
407 				}
408 			}
409 		}
410 
411 		return true;
412 	}
413 
414 	return false;
415 }
416 
417