2
* ea.c - Processing of EA's
4
* This module is part of ntfs-3g library
6
* Copyright (c) 2014 Jean-Pierre Andre
8
* This program/include file is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU General Public License as published
10
* by the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
13
* This program/include file is distributed in the hope that it will be
14
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program (in the main directory of the NTFS-3G
20
* distribution in the file COPYING); if not, write to the Free Software
21
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
#ifdef HAVE_SETXATTR /* extended attributes support required */
50
#include <sys/xattr.h>
64
* Create a needed attribute (EA or EA_INFORMATION)
66
* Returns 0 if successful,
67
* -1 otherwise, with errno indicating why it failed.
70
static int ntfs_need_ea(ntfs_inode *ni, ATTR_TYPES type, int size, int flags)
76
if (!ntfs_attr_exist(ni,type, AT_UNNAMED,0)) {
77
if (!(flags & XATTR_REPLACE)) {
79
* no needed attribute : add one,
80
* apparently, this does not feed the new value in
81
* Note : NTFS version must be >= 3
83
if (ni->vol->major_ver >= 3) {
84
res = ntfs_attr_add(ni, type,
85
AT_UNNAMED,0,&dummy,(s64)size);
87
NInoFileNameSetDirty(ni);
103
* Restore the old EA_INFORMATION or delete the current one,
104
* when EA cannot be updated.
106
* As this is used in the context of some other error, the caller
107
* is responsible for returning the proper error, and errno is
109
* Only double errors are logged here.
112
static void restore_ea_info(ntfs_attr *nai, const EA_INFORMATION *old_ea_info)
119
written = ntfs_attr_pwrite(nai, 0, sizeof(EA_INFORMATION),
121
if ((size_t)written != sizeof(EA_INFORMATION)) {
122
ntfs_log_error("Could not restore the EA_INFORMATION,"
123
" possible inconsistency in inode %lld\n",
124
(long long)nai->ni->mft_no);
127
if (ntfs_attr_rm(nai)) {
128
ntfs_log_error("Could not delete the EA_INFORMATION,"
129
" possible inconsistency in inode %lld\n",
130
(long long)nai->ni->mft_no);
137
* Update both EA and EA_INFORMATION
140
static int ntfs_update_ea(ntfs_inode *ni, const char *value, size_t size,
141
const EA_INFORMATION *ea_info,
142
const EA_INFORMATION *old_ea_info)
149
nai = ntfs_attr_open(ni, AT_EA_INFORMATION, AT_UNNAMED, 0);
151
na = ntfs_attr_open(ni, AT_EA, AT_UNNAMED, 0);
154
* Set EA_INFORMATION first, it is easier to
155
* restore the old value, if setting EA fails.
157
if (ntfs_attr_pwrite(nai, 0, sizeof(EA_INFORMATION),
159
!= (s64)sizeof(EA_INFORMATION)) {
162
if (((na->data_size > (s64)size)
163
&& ntfs_attr_truncate(na, size))
164
|| (ntfs_attr_pwrite(na, 0, size, value)
174
ntfs_attr_close(nai);
182
* Return the existing EA
184
* The EA_INFORMATION is not examined and the consistency of the
185
* existing EA is not checked.
187
* If successful, the full attribute is returned unchanged
188
* and its size is returned.
189
* If the designated buffer is too small, the needed size is
190
* returned, and the buffer is left unchanged.
191
* If there is an error, a negative value is returned and errno
192
* is set according to the error.
195
int ntfs_get_ntfs_ea(ntfs_inode *ni, char *value, size_t size)
201
if (ntfs_attr_exist(ni, AT_EA, AT_UNNAMED, 0)) {
202
ea_buf = ntfs_attr_readall(ni, AT_EA, (ntfschar*)NULL, 0,
205
if (value && (ea_size <= (s64)size))
206
memcpy(value, ea_buf, ea_size);
210
ntfs_log_error("Failed to read EA from inode %lld\n",
211
(long long)ni->mft_no);
223
* Set a new EA, and set EA_INFORMATION accordingly
225
* This is roughly the same as ZwSetEaFile() on Windows, however
226
* the "offset to next" of the last EA should not be cleared.
228
* Consistency of the new EA is first checked.
230
* EA_INFORMATION is set first, and it is restored to its former
231
* state if setting EA fails.
233
* Returns 0 if successful
234
* a negative value if an error occurred.
237
int ntfs_set_ntfs_ea(ntfs_inode *ni, const char *value, size_t size, int flags)
239
EA_INFORMATION ea_info;
240
EA_INFORMATION *old_ea_info;
251
if (value && (size > 0)) {
252
/* do consistency checks */
258
while (ok && (offs < size)) {
259
p_ea = (const EA_ATTR*)&value[offs];
260
nextoffs = offs + le32_to_cpu(p_ea->next_entry_offset);
261
/* null offset to next not allowed */
262
ok = (nextoffs > offs)
263
&& (nextoffs <= size)
266
/* zero sized value are allowed */
267
&& ((offs + offsetof(EA_ATTR,name)
268
+ p_ea->name_length + 1
269
+ le16_to_cpu(p_ea->value_length))
271
&& ((offs + offsetof(EA_ATTR,name)
272
+ p_ea->name_length + 1
273
+ le16_to_cpu(p_ea->value_length))
275
&& !p_ea->name[p_ea->name_length];
276
/* name not checked, as chkdsk accepts any chars */
278
if (p_ea->flags & NEED_EA)
281
* Assume ea_packed includes :
282
* 4 bytes for header (flags and lengths)
286
ea_packed += 5 + p_ea->name_length
287
+ le16_to_cpu(p_ea->value_length);
292
* EA and REPARSE_POINT exclude each other
293
* see http://msdn.microsoft.com/en-us/library/windows/desktop/aa364404(v=vs.85).aspx
294
* Also return EINVAL if REPARSE_POINT is present.
297
&& !ntfs_attr_exist(ni, AT_REPARSE_POINT, AT_UNNAMED,0)) {
298
ea_info.ea_length = cpu_to_le16(ea_packed);
299
ea_info.need_ea_count = cpu_to_le16(ea_count);
300
ea_info.ea_query_length = cpu_to_le32(nextoffs);
304
/* Try to save the old EA_INFORMATION */
305
if (ntfs_attr_exist(ni, AT_EA_INFORMATION,
307
old_ea_info = ntfs_attr_readall(ni,
309
(ntfschar*)NULL, 0, &old_ea_size);
312
* no EA or EA_INFORMATION : add them
314
if (!ntfs_need_ea(ni, AT_EA_INFORMATION,
315
sizeof(EA_INFORMATION), flags)
316
&& !ntfs_need_ea(ni, AT_EA, 0, flags)) {
317
res = ntfs_update_ea(ni, value, size,
318
&ea_info, old_ea_info);
336
* Remove the EA (including EA_INFORMATION)
338
* EA_INFORMATION is removed first, and it is restored to its former
339
* state if removing EA fails.
341
* Returns 0, or -1 if there is a problem
344
int ntfs_remove_ntfs_ea(ntfs_inode *ni)
346
EA_INFORMATION *old_ea_info;
355
* open and delete the EA_INFORMATION and the EA
357
nai = ntfs_attr_open(ni, AT_EA_INFORMATION, AT_UNNAMED, 0);
359
na = ntfs_attr_open(ni, AT_EA, AT_UNNAMED, 0);
361
/* Try to save the old EA_INFORMATION */
362
old_ea_info = ntfs_attr_readall(ni,
364
(ntfschar*)NULL, 0, &old_ea_size);
365
res = ntfs_attr_rm(na);
366
NInoFileNameSetDirty(ni);
368
res = ntfs_attr_rm(nai);
369
if (res && old_ea_info) {
371
* Failed to remove the EA, try to
372
* restore the EA_INFORMATION
378
ntfs_log_error("Failed to remove the"
379
" EA_INFORMATION from inode %lld\n",
380
(long long)ni->mft_no);
385
/* EA_INFORMATION present, but no EA */
386
res = ntfs_attr_rm(nai);
387
NInoFileNameSetDirty(ni);
389
ntfs_attr_close(nai);
399
return (res ? -1 : 0);
402
#endif /* HAVE_SETXATTR */