1 #include "chmod_data.h"
2 
3 #include <libfilezilla/string.hpp>
4 
5 #include <cstring>
6 
ConvertPermissions(std::wstring const & rwx,char * permissions)7 bool ChmodData::ConvertPermissions(std::wstring const& rwx, char* permissions)
8 {
9 	if (!permissions) {
10 		return false;
11 	}
12 
13 	size_t pos = rwx.find('(');
14 	if (pos != std::wstring::npos && rwx.back() == ')') {
15 		// MLSD permissions:
16 		//   foo (0644)
17 		return DoConvertPermissions(rwx.substr(pos + 1, rwx.size() - pos - 2), permissions);
18 	}
19 
20 	return DoConvertPermissions(rwx, permissions);
21 }
22 
DoConvertPermissions(std::wstring const & rwx,char * permissions)23 bool ChmodData::DoConvertPermissions(std::wstring const& rwx, char* permissions)
24 {
25 	if (rwx.size() < 3) {
26 		return false;
27 	}
28 	size_t i;
29 	for (i = 0; i < rwx.size(); ++i) {
30 		if (rwx[i] < '0' || rwx[i] > '9') {
31 			break;
32 		}
33 	}
34 	if (i == rwx.size()) {
35 		// Mode, e.g. 0723
36 		for (i = 0; i < 3; ++i) {
37 			int m = rwx[rwx.size() - 3 + i] - '0';
38 
39 			for (int j = 0; j < 3; ++j) {
40 				if (m & (4 >> j)) {
41 					permissions[i * 3 + j] = 2;
42 				}
43 				else {
44 					permissions[i * 3 + j] = 1;
45 				}
46 			}
47 		}
48 
49 		return true;
50 	}
51 
52 	unsigned char const permchars[3] = { 'r', 'w', 'x' };
53 
54 	if (rwx.size() != 10) {
55 		return false;
56 	}
57 
58 	for (int j = 0; j < 9; ++j) {
59 		bool set = rwx[j + 1] == permchars[j % 3];
60 		permissions[j] = set ? 2 : 1;
61 	}
62 	if (rwx[3] == 's') {
63 		permissions[2] = 2;
64 	}
65 	if (rwx[6] == 's') {
66 		permissions[5] = 2;
67 	}
68 	if (rwx[9] == 't') {
69 		permissions[8] = 2;
70 	}
71 
72 	return true;
73 }
74 
75 
GetPermissions(const char * previousPermissions,bool dir)76 std::wstring ChmodData::GetPermissions(const char* previousPermissions, bool dir)
77 {
78 	// Construct a new permission string
79 
80 	if (numeric_.size() < 3) {
81 		return numeric_;
82 	}
83 
84 	for (size_t i = numeric_.size() - 3; i < numeric_.size(); ++i) {
85 		if ((numeric_[i] < '0' || numeric_[i] > '9') && numeric_[i] != 'x') {
86 			return numeric_;
87 		}
88 	}
89 
90 	if (!previousPermissions) {
91 		std::wstring ret = numeric_;
92 		size_t const size = ret.size();
93 		if (numeric_[size - 1] == 'x') {
94 			ret[size - 1] = dir ? '5' : '4';
95 		}
96 		if (numeric_[size - 2] == 'x') {
97 			ret[size - 2] = dir ? '5' : '4';
98 		}
99 		if (numeric_[size - 3] == 'x') {
100 			ret[size - 3] = dir ? '7' : '6';
101 		}
102 		// Use default of  (0...0)755 for dirs and
103 		// 644 for files
104 		for (size_t i = 0; i < size - 3; ++i) {
105 			if (numeric_[i] == 'x') {
106 				ret[i] = '0';
107 			}
108 		}
109 		return ret;
110 	}
111 
112 	// 2 set, 1 unset, 0 keep
113 
114 	const char defaultPerms[9] = { 2, 2, 2, 2, 1, 2, 2, 1, 2 };
115 	char perms[9];
116 	memcpy(perms, permissions_, 9);
117 
118 	std::wstring permission = numeric_.substr(0, numeric_.size() - 3);
119 	size_t k = 0;
120 	for (size_t i = numeric_.size() - 3; i < numeric_.size(); ++i, ++k) {
121 		for (size_t j = k * 3; j < k * 3 + 3; ++j) {
122 			if (!perms[j]) {
123 				if (previousPermissions[j]) {
124 					perms[j] = previousPermissions[j];
125 				}
126 				else {
127 					perms[j] = defaultPerms[j];
128 				}
129 			}
130 		}
131 		permission += fz::to_wstring((perms[k * 3] - 1) * 4 + (perms[k * 3 + 1] - 1) * 2 + (perms[k * 3 + 2] - 1) * 1);
132 	}
133 
134 	return permission;
135 }
136