Changeset View
Changeset View
Standalone View
Standalone View
src/xattr_p.h
Show First 20 Lines • Show All 47 Lines • ▼ Show 20 Line(s) | |||||
48 | #include <sys/types.h> | 48 | #include <sys/types.h> | ||
49 | #include <sys/extattr.h> | 49 | #include <sys/extattr.h> | ||
50 | #include <errno.h> | 50 | #include <errno.h> | ||
51 | #elif defined(Q_OS_WIN) | 51 | #elif defined(Q_OS_WIN) | ||
52 | #include <windows.h> | 52 | #include <windows.h> | ||
53 | #define ssize_t SSIZE_T | 53 | #define ssize_t SSIZE_T | ||
54 | #endif | 54 | #endif | ||
55 | 55 | | |||
56 | #if defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) | ||||
56 | inline ssize_t k_getxattr(const QString& path, const QString& name, QString* value) | 57 | inline ssize_t k_getxattr(const QString& path, const QString& name, QString* value) | ||
57 | { | 58 | { | ||
58 | const QByteArray p = QFile::encodeName(path); | 59 | const QByteArray p = QFile::encodeName(path); | ||
59 | const char* encodedPath = p.constData(); | 60 | const char* encodedPath = p.constData(); | ||
60 | 61 | | |||
61 | const QByteArray n = name.toUtf8(); | 62 | const QByteArray n = name.toUtf8(); | ||
62 | const char* attributeName = n.constData(); | 63 | const char* attributeName = n.constData(); | ||
63 | 64 | | |||
64 | // First get the size of the data we are going to get to reserve the right amount of space. | 65 | // First get the size of the data we are going to get to reserve the right amount of space. | ||
65 | #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_getxattr)) | 66 | #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_getxattr)) | ||
66 | const ssize_t size = getxattr(encodedPath, attributeName, nullptr, 0); | 67 | const ssize_t size = getxattr(encodedPath, attributeName, nullptr, 0); | ||
67 | #elif defined(Q_OS_MAC) | 68 | #elif defined(Q_OS_MAC) | ||
68 | const ssize_t size = getxattr(encodedPath, attributeName, NULL, 0, 0, 0); | 69 | const ssize_t size = getxattr(encodedPath, attributeName, NULL, 0, 0, 0); | ||
69 | #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) | 70 | #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) | ||
70 | const ssize_t size = extattr_get_file(encodedPath, EXTATTR_NAMESPACE_USER, attributeName, NULL, 0); | 71 | const ssize_t size = extattr_get_file(encodedPath, EXTATTR_NAMESPACE_USER, attributeName, NULL, 0); | ||
71 | #elif defined(Q_OS_WIN) | | |||
72 | const QString fullADSName = path + QLatin1Char(':') + name; | | |||
73 | HANDLE hFile = ::CreateFileW(reinterpret_cast<const WCHAR*>(fullADSName.utf16()), GENERIC_READ, FILE_SHARE_READ, NULL, | | |||
74 | OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); | | |||
75 | | ||||
76 | if(!hFile) return 0; | | |||
77 | | ||||
78 | LARGE_INTEGER lsize; | | |||
79 | lsize.LowPart = GetFileSize(hFile, (DWORD*)&lsize.HighPart); | | |||
80 | ssize_t size = (qint64)lsize.QuadPart; | | |||
81 | #else | | |||
82 | const ssize_t size = 0; | | |||
83 | #endif | 72 | #endif | ||
84 | 73 | | |||
85 | if (!value) { | 74 | if (!value) { | ||
86 | return size; | 75 | return size; | ||
87 | } | 76 | } | ||
88 | 77 | | |||
89 | if (size <= 0) { | 78 | if (size <= 0) { | ||
90 | value->clear(); | 79 | value->clear(); | ||
91 | return size; | 80 | return size; | ||
92 | } | 81 | } | ||
93 | 82 | | |||
94 | QByteArray data(size, Qt::Uninitialized); | 83 | QByteArray data(size, Qt::Uninitialized); | ||
95 | 84 | | |||
96 | #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_getxattr)) | 85 | #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_getxattr)) | ||
97 | const ssize_t r = getxattr(encodedPath, attributeName, data.data(), size); | 86 | const ssize_t r = getxattr(encodedPath, attributeName, data.data(), size); | ||
98 | #elif defined(Q_OS_MAC) | 87 | #elif defined(Q_OS_MAC) | ||
99 | const ssize_t r = getxattr(encodedPath, attributeName, data.data(), size, 0, 0); | 88 | const ssize_t r = getxattr(encodedPath, attributeName, data.data(), size, 0, 0); | ||
100 | #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) | 89 | #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) | ||
101 | const ssize_t r = extattr_get_file(encodedPath, EXTATTR_NAMESPACE_USER, attributeName, data.data(), size); | 90 | const ssize_t r = extattr_get_file(encodedPath, EXTATTR_NAMESPACE_USER, attributeName, data.data(), size); | ||
102 | #elif defined(Q_OS_WIN) | | |||
103 | ssize_t r = 0; | | |||
104 | // should we care about attributes longer than 2GiB? - unix xattr are restricted to much lower values | | |||
105 | ::ReadFile(hFile, data.data(), size, (DWORD*)&r, NULL); | | |||
106 | CloseHandle(hFile); | | |||
107 | #else | | |||
108 | const ssize_t r = 0; | | |||
109 | #endif | 91 | #endif | ||
110 | 92 | | |||
111 | *value = QString::fromUtf8(data); | 93 | *value = QString::fromUtf8(data); | ||
112 | return r; | 94 | return r; | ||
113 | } | 95 | } | ||
114 | 96 | | |||
115 | inline int k_setxattr(const QString& path, const QString& name, const QString& value) | 97 | inline int k_setxattr(const QString& path, const QString& name, const QString& value) | ||
116 | { | 98 | { | ||
Show All 10 Lines | |||||
127 | 109 | | |||
128 | #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_setxattr)) | 110 | #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_setxattr)) | ||
129 | return setxattr(encodedPath, attributeName, attributeValue, valueSize, 0); | 111 | return setxattr(encodedPath, attributeName, attributeValue, valueSize, 0); | ||
130 | #elif defined(Q_OS_MAC) | 112 | #elif defined(Q_OS_MAC) | ||
131 | return setxattr(encodedPath, attributeName, attributeValue, valueSize, 0, 0); | 113 | return setxattr(encodedPath, attributeName, attributeValue, valueSize, 0, 0); | ||
132 | #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) | 114 | #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) | ||
133 | const ssize_t count = extattr_set_file(encodedPath, EXTATTR_NAMESPACE_USER, attributeName, attributeValue, valueSize); | 115 | const ssize_t count = extattr_set_file(encodedPath, EXTATTR_NAMESPACE_USER, attributeName, attributeValue, valueSize); | ||
134 | return count == -1 ? -1 : 0; | 116 | return count == -1 ? -1 : 0; | ||
117 | #endif | ||||
118 | } | ||||
119 | | ||||
120 | | ||||
121 | inline int k_removexattr(const QString& path, const QString& name) | ||||
122 | { | ||||
123 | const QByteArray p = QFile::encodeName(path); | ||||
124 | const char* encodedPath = p.constData(); | ||||
125 | | ||||
126 | const QByteArray n = name.toUtf8(); | ||||
127 | const char* attributeName = n.constData(); | ||||
128 | | ||||
129 | #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_removexattr)) | ||||
130 | return removexattr(encodedPath, attributeName); | ||||
131 | #elif defined(Q_OS_MAC) | ||||
132 | return removexattr(encodedPath, attributeName, XATTR_NOFOLLOW ); | ||||
133 | #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) | ||||
134 | return extattr_delete_file (encodedPath, EXTATTR_NAMESPACE_USER, attributeName); | ||||
135 | #endif | ||||
136 | } | ||||
137 | | ||||
138 | inline bool k_hasAttribute(const QString& path, const QString& name) | ||||
139 | { | ||||
140 | auto ret = k_getxattr(path, name, nullptr); | ||||
141 | return (ret >= 0); | ||||
142 | } | ||||
143 | | ||||
144 | inline bool k_isSupported(const QString& path) | ||||
145 | { | ||||
146 | auto ret = k_getxattr(path, QStringLiteral("user.test"), nullptr); | ||||
147 | return (ret >= 0) || (errno != ENOTSUP); | ||||
148 | } | ||||
149 | | ||||
135 | #elif defined(Q_OS_WIN) | 150 | #elif defined(Q_OS_WIN) | ||
151 | | ||||
152 | inline ssize_t k_getxattr(const QString& path, const QString& name, QString* value) | ||||
153 | { | ||||
154 | const QString fullADSName = path + QLatin1Char(':') + name; | ||||
155 | HANDLE hFile = ::CreateFileW(reinterpret_cast<const WCHAR*>(fullADSName.utf16()), GENERIC_READ, FILE_SHARE_READ, NULL, | ||||
156 | OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); | ||||
157 | | ||||
158 | if(!hFile) return 0; | ||||
159 | | ||||
160 | LARGE_INTEGER lsize; | ||||
161 | lsize.LowPart = GetFileSize(hFile, (DWORD*)&lsize.HighPart); | ||||
162 | | ||||
163 | if (size <= 0) { | ||||
164 | CloseHandle(hFile); | ||||
165 | value->clear(); | ||||
166 | return size; | ||||
167 | } | ||||
168 | | ||||
169 | ssize_t r = 0; | ||||
170 | // should we care about attributes longer than 2GiB? - unix xattr are restricted to much lower values | ||||
171 | ::ReadFile(hFile, data.data(), size, (DWORD*)&r, NULL); | ||||
172 | CloseHandle(hFile); | ||||
173 | | ||||
174 | *value = QString::fromUtf8(data); | ||||
175 | return r; | ||||
176 | } | ||||
177 | | ||||
178 | inline int k_setxattr(const QString& path, const QString& name, const QString& value) | ||||
179 | { | ||||
180 | const QByteArray v = value.toUtf8(); | ||||
181 | | ||||
136 | const QString fullADSName = path + QLatin1Char(':') + name; | 182 | const QString fullADSName = path + QLatin1Char(':') + name; | ||
137 | HANDLE hFile = ::CreateFileW(reinterpret_cast<const WCHAR*>(fullADSName.utf16()), GENERIC_WRITE, FILE_SHARE_READ, NULL, | 183 | HANDLE hFile = ::CreateFileW(reinterpret_cast<const WCHAR*>(fullADSName.utf16()), GENERIC_WRITE, FILE_SHARE_READ, NULL, | ||
138 | CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); | 184 | CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); | ||
139 | 185 | | |||
140 | if(!hFile) return -1; | 186 | if(!hFile) return -1; | ||
141 | 187 | | |||
142 | DWORD count = 0; | 188 | DWORD count = 0; | ||
143 | 189 | | |||
144 | if(!::WriteFile(hFile, attributeValue, valueSize, &count, NULL)) { | 190 | if(!::WriteFile(hFile, v.constData(), v.size(), &count, NULL)) { | ||
145 | DWORD dw = GetLastError(); | 191 | DWORD dw = GetLastError(); | ||
146 | TCHAR msg[1024]; | 192 | TCHAR msg[1024]; | ||
147 | FormatMessage( | 193 | FormatMessage( | ||
148 | FORMAT_MESSAGE_ALLOCATE_BUFFER | | 194 | FORMAT_MESSAGE_ALLOCATE_BUFFER | | ||
149 | FORMAT_MESSAGE_FROM_SYSTEM | | 195 | FORMAT_MESSAGE_FROM_SYSTEM | | ||
150 | FORMAT_MESSAGE_IGNORE_INSERTS, | 196 | FORMAT_MESSAGE_IGNORE_INSERTS, | ||
151 | NULL, | 197 | NULL, | ||
152 | dw, | 198 | dw, | ||
153 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | 199 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||
154 | (LPTSTR) &msg, | 200 | (LPTSTR) &msg, | ||
155 | 0, NULL ); | 201 | 0, NULL ); | ||
156 | qWarning() << "failed to write to ADS:" << msg; | 202 | qWarning() << "failed to write to ADS:" << msg; | ||
157 | } | | |||
158 | | ||||
159 | CloseHandle(hFile); | 203 | CloseHandle(hFile); | ||
160 | return count; | | |||
161 | #else | | |||
162 | return -1; | 204 | return -1; | ||
163 | #endif | | |||
164 | } | 205 | } | ||
165 | 206 | | |||
166 | 207 | CloseHandle(hFile); | |||
167 | inline int k_removexattr(const QString& path, const QString& name) | 208 | return count; | ||
168 | { | | |||
169 | const QByteArray p = QFile::encodeName(path); | | |||
170 | const char* encodedPath = p.constData(); | | |||
171 | | ||||
172 | const QByteArray n = name.toUtf8(); | | |||
173 | const char* attributeName = n.constData(); | | |||
174 | | ||||
175 | #if defined(Q_OS_LINUX) || (defined(__GLIBC__) && !defined(__stub_removexattr)) | | |||
176 | return removexattr(encodedPath, attributeName); | | |||
177 | #elif defined(Q_OS_MAC) | | |||
178 | return removexattr(encodedPath, attributeName, XATTR_NOFOLLOW ); | | |||
179 | #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) | | |||
180 | return extattr_delete_file (encodedPath, EXTATTR_NAMESPACE_USER, attributeName); | | |||
181 | #elif defined(Q_OS_WIN) | | |||
182 | const QString fullADSName = path + QLatin1Char(':') + name; | | |||
183 | int ret = (DeleteFileW(reinterpret_cast<const WCHAR*>(fullADSName.utf16()))) ? 0 : -1; | | |||
184 | return ret; | | |||
185 | #else | | |||
186 | return -1; | | |||
187 | #endif | | |||
188 | | ||||
189 | } | 209 | } | ||
190 | 210 | | |||
191 | inline bool k_hasAttribute(const QString& path, const QString& name) | 211 | inline bool k_hasAttribute(const QString& path, const QString& name) | ||
192 | { | 212 | { | ||
193 | #if defined(Q_OS_WIN) | | |||
194 | // enumerate all streams: | 213 | // enumerate all streams: | ||
195 | const QString streamName = QStringLiteral(":") + name + QStringLiteral(":$DATA"); | 214 | const QString streamName = QStringLiteral(":") + name + QStringLiteral(":$DATA"); | ||
196 | HANDLE hFile = ::CreateFileW(reinterpret_cast<const WCHAR*>(path.utf16()), GENERIC_READ, FILE_SHARE_READ, NULL, | 215 | HANDLE hFile = ::CreateFileW(reinterpret_cast<const WCHAR*>(path.utf16()), GENERIC_READ, FILE_SHARE_READ, NULL, | ||
197 | OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); | 216 | OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); | ||
198 | 217 | | |||
199 | if(!hFile) { | 218 | if(!hFile) { | ||
200 | return false; | 219 | return false; | ||
201 | } | 220 | } | ||
Show All 12 Lines | 231 | if(QString::fromUtf16((ushort*)p->StreamName, p->StreamNameLength / sizeof(ushort)) == streamName) { | |||
214 | CloseHandle(hFile); | 233 | CloseHandle(hFile); | ||
215 | return true; | 234 | return true; | ||
216 | } | 235 | } | ||
217 | } while(p->NextEntryOffset != NULL); | 236 | } while(p->NextEntryOffset != NULL); | ||
218 | } | 237 | } | ||
219 | delete[] fi; | 238 | delete[] fi; | ||
220 | CloseHandle(hFile); | 239 | CloseHandle(hFile); | ||
221 | return false; | 240 | return false; | ||
222 | #else | 241 | } | ||
223 | auto ret = k_getxattr(path, name, nullptr); | 242 | | ||
224 | return (ret >= 0); | 243 | inline int k_removexattr(const QString& path, const QString& name) | ||
225 | #endif | 244 | { | ||
245 | const QString fullADSName = path + QLatin1Char(':') + name; | ||||
246 | int ret = (DeleteFileW(reinterpret_cast<const WCHAR*>(fullADSName.utf16()))) ? 0 : -1; | ||||
247 | return ret; | ||||
226 | } | 248 | } | ||
227 | 249 | | |||
228 | inline bool k_isSupported(const QString& path) | 250 | inline bool k_isSupported(const QString& path) | ||
229 | { | 251 | { | ||
230 | #if defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) | | |||
231 | auto ret = k_getxattr(path, QStringLiteral("user.test"), nullptr); | | |||
232 | return (ret >= 0) || (errno != ENOTSUP); | | |||
233 | #elif defined(Q_OS_WIN) | | |||
234 | QFileInfo f(path); | 252 | QFileInfo f(path); | ||
235 | const QString drive = QString(f.absolutePath().left(2)) + QStringLiteral("\\"); | 253 | const QString drive = QString(f.absolutePath().left(2)) + QStringLiteral("\\"); | ||
236 | WCHAR szFSName[MAX_PATH]; | 254 | WCHAR szFSName[MAX_PATH]; | ||
237 | DWORD dwVolFlags; | 255 | DWORD dwVolFlags; | ||
238 | ::GetVolumeInformationW(reinterpret_cast<const WCHAR*>(drive.utf16()), NULL, 0, NULL, NULL, &dwVolFlags, szFSName, MAX_PATH); | 256 | ::GetVolumeInformationW(reinterpret_cast<const WCHAR*>(drive.utf16()), NULL, 0, NULL, NULL, &dwVolFlags, szFSName, MAX_PATH); | ||
239 | return ((dwVolFlags & FILE_NAMED_STREAMS) && _wcsicmp(szFSName, L"NTFS") == 0); | 257 | return ((dwVolFlags & FILE_NAMED_STREAMS) && _wcsicmp(szFSName, L"NTFS") == 0); | ||
258 | } | ||||
259 | | ||||
240 | #else | 260 | #else | ||
261 | inline ssize_t k_getxattr(const QString&, const QString&, QString*) | ||||
262 | { | ||||
263 | return 0; | ||||
264 | } | ||||
265 | | ||||
266 | inline int k_setxattr(const QString&, const QString&, const QString&) | ||||
267 | { | ||||
268 | return -1; | ||||
269 | } | ||||
270 | | ||||
271 | inline int k_removexattr(const QString&, const QString&) | ||||
272 | { | ||||
273 | return -1; | ||||
274 | } | ||||
275 | | ||||
276 | inline bool k_hasAttribute(const QString&, const QString&) | ||||
277 | { | ||||
278 | return false | ||||
279 | } | ||||
280 | | ||||
281 | inline bool k_isSupported(const QString&) | ||||
282 | { | ||||
241 | return false; | 283 | return false; | ||
242 | #endif | | |||
243 | } | 284 | } | ||
285 | #endif | ||||
286 | | ||||
244 | #endif // KFILEMETADATA_XATTR_P_H | 287 | #endif // KFILEMETADATA_XATTR_P_H |