10490778eSAugustin Cavalier /**
20490778eSAugustin Cavalier * ea.c - Processing of EA's
30490778eSAugustin Cavalier *
40490778eSAugustin Cavalier * This module is part of ntfs-3g library
50490778eSAugustin Cavalier *
6*9102cad6SAugustin Cavalier * Copyright (c) 2014-2021 Jean-Pierre Andre
70490778eSAugustin Cavalier *
80490778eSAugustin Cavalier * This program/include file is free software; you can redistribute it and/or
90490778eSAugustin Cavalier * modify it under the terms of the GNU General Public License as published
100490778eSAugustin Cavalier * by the Free Software Foundation; either version 2 of the License, or
110490778eSAugustin Cavalier * (at your option) any later version.
120490778eSAugustin Cavalier *
130490778eSAugustin Cavalier * This program/include file is distributed in the hope that it will be
140490778eSAugustin Cavalier * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
150490778eSAugustin Cavalier * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
160490778eSAugustin Cavalier * GNU General Public License for more details.
170490778eSAugustin Cavalier *
180490778eSAugustin Cavalier * You should have received a copy of the GNU General Public License
190490778eSAugustin Cavalier * along with this program (in the main directory of the NTFS-3G
200490778eSAugustin Cavalier * distribution in the file COPYING); if not, write to the Free Software
210490778eSAugustin Cavalier * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
220490778eSAugustin Cavalier */
230490778eSAugustin Cavalier
240490778eSAugustin Cavalier #ifdef HAVE_CONFIG_H
250490778eSAugustin Cavalier #include "config.h"
260490778eSAugustin Cavalier #endif
270490778eSAugustin Cavalier
280490778eSAugustin Cavalier #ifdef HAVE_STDIO_H
290490778eSAugustin Cavalier #include <stdio.h>
300490778eSAugustin Cavalier #endif
310490778eSAugustin Cavalier #ifdef HAVE_STDLIB_H
320490778eSAugustin Cavalier #include <stdlib.h>
330490778eSAugustin Cavalier #endif
340490778eSAugustin Cavalier #ifdef HAVE_STRING_H
350490778eSAugustin Cavalier #include <string.h>
360490778eSAugustin Cavalier #endif
370490778eSAugustin Cavalier #ifdef HAVE_FCNTL_H
380490778eSAugustin Cavalier #include <fcntl.h>
390490778eSAugustin Cavalier #endif
400490778eSAugustin Cavalier #ifdef HAVE_UNISTD_H
410490778eSAugustin Cavalier #include <unistd.h>
420490778eSAugustin Cavalier #endif
430490778eSAugustin Cavalier #ifdef HAVE_ERRNO_H
440490778eSAugustin Cavalier #include <errno.h>
450490778eSAugustin Cavalier #endif
46*9102cad6SAugustin Cavalier #ifdef MAJOR_IN_MKDEV
47*9102cad6SAugustin Cavalier #include <sys/mkdev.h>
48*9102cad6SAugustin Cavalier #endif
49*9102cad6SAugustin Cavalier #ifdef MAJOR_IN_SYSMACROS
50*9102cad6SAugustin Cavalier #include <sys/sysmacros.h>
51*9102cad6SAugustin Cavalier #endif
520490778eSAugustin Cavalier
530490778eSAugustin Cavalier #include "types.h"
540490778eSAugustin Cavalier #include "param.h"
550490778eSAugustin Cavalier #include "layout.h"
560490778eSAugustin Cavalier #include "attrib.h"
570490778eSAugustin Cavalier #include "index.h"
580490778eSAugustin Cavalier #include "dir.h"
590490778eSAugustin Cavalier #include "ea.h"
600490778eSAugustin Cavalier #include "misc.h"
610490778eSAugustin Cavalier #include "logging.h"
620490778eSAugustin Cavalier #include "xattrs.h"
630490778eSAugustin Cavalier
64*9102cad6SAugustin Cavalier static const char lxdev[] = "$LXDEV";
65*9102cad6SAugustin Cavalier static const char lxmod[] = "$LXMOD";
66*9102cad6SAugustin Cavalier
67*9102cad6SAugustin Cavalier
680490778eSAugustin Cavalier /*
690490778eSAugustin Cavalier * Create a needed attribute (EA or EA_INFORMATION)
700490778eSAugustin Cavalier *
710490778eSAugustin Cavalier * Returns 0 if successful,
720490778eSAugustin Cavalier * -1 otherwise, with errno indicating why it failed.
730490778eSAugustin Cavalier */
740490778eSAugustin Cavalier
ntfs_need_ea(ntfs_inode * ni,ATTR_TYPES type,int size,int flags)750490778eSAugustin Cavalier static int ntfs_need_ea(ntfs_inode *ni, ATTR_TYPES type, int size, int flags)
760490778eSAugustin Cavalier {
770490778eSAugustin Cavalier u8 dummy;
780490778eSAugustin Cavalier int res;
790490778eSAugustin Cavalier
800490778eSAugustin Cavalier res = 0;
810490778eSAugustin Cavalier if (!ntfs_attr_exist(ni,type, AT_UNNAMED,0)) {
820490778eSAugustin Cavalier if (!(flags & XATTR_REPLACE)) {
830490778eSAugustin Cavalier /*
840490778eSAugustin Cavalier * no needed attribute : add one,
850490778eSAugustin Cavalier * apparently, this does not feed the new value in
860490778eSAugustin Cavalier * Note : NTFS version must be >= 3
870490778eSAugustin Cavalier */
880490778eSAugustin Cavalier if (ni->vol->major_ver >= 3) {
890490778eSAugustin Cavalier res = ntfs_attr_add(ni, type,
900490778eSAugustin Cavalier AT_UNNAMED,0,&dummy,(s64)size);
910490778eSAugustin Cavalier if (!res) {
920490778eSAugustin Cavalier NInoFileNameSetDirty(ni);
930490778eSAugustin Cavalier }
940490778eSAugustin Cavalier NInoSetDirty(ni);
950490778eSAugustin Cavalier } else {
960490778eSAugustin Cavalier errno = EOPNOTSUPP;
970490778eSAugustin Cavalier res = -1;
980490778eSAugustin Cavalier }
990490778eSAugustin Cavalier } else {
1000490778eSAugustin Cavalier errno = ENODATA;
1010490778eSAugustin Cavalier res = -1;
1020490778eSAugustin Cavalier }
1030490778eSAugustin Cavalier }
1040490778eSAugustin Cavalier return (res);
1050490778eSAugustin Cavalier }
1060490778eSAugustin Cavalier
1070490778eSAugustin Cavalier /*
1080490778eSAugustin Cavalier * Restore the old EA_INFORMATION or delete the current one,
1090490778eSAugustin Cavalier * when EA cannot be updated.
1100490778eSAugustin Cavalier *
1110490778eSAugustin Cavalier * As this is used in the context of some other error, the caller
1120490778eSAugustin Cavalier * is responsible for returning the proper error, and errno is
1130490778eSAugustin Cavalier * left unchanged.
1140490778eSAugustin Cavalier * Only double errors are logged here.
1150490778eSAugustin Cavalier */
1160490778eSAugustin Cavalier
restore_ea_info(ntfs_attr * nai,const EA_INFORMATION * old_ea_info)1170490778eSAugustin Cavalier static void restore_ea_info(ntfs_attr *nai, const EA_INFORMATION *old_ea_info)
1180490778eSAugustin Cavalier {
1190490778eSAugustin Cavalier s64 written;
1200490778eSAugustin Cavalier int olderrno;
1210490778eSAugustin Cavalier
1220490778eSAugustin Cavalier olderrno = errno;
1230490778eSAugustin Cavalier if (old_ea_info) {
1240490778eSAugustin Cavalier written = ntfs_attr_pwrite(nai, 0, sizeof(EA_INFORMATION),
1250490778eSAugustin Cavalier old_ea_info);
1260490778eSAugustin Cavalier if ((size_t)written != sizeof(EA_INFORMATION)) {
1270490778eSAugustin Cavalier ntfs_log_error("Could not restore the EA_INFORMATION,"
1280490778eSAugustin Cavalier " possible inconsistency in inode %lld\n",
1290490778eSAugustin Cavalier (long long)nai->ni->mft_no);
1300490778eSAugustin Cavalier }
1310490778eSAugustin Cavalier } else {
1320490778eSAugustin Cavalier if (ntfs_attr_rm(nai)) {
1330490778eSAugustin Cavalier ntfs_log_error("Could not delete the EA_INFORMATION,"
1340490778eSAugustin Cavalier " possible inconsistency in inode %lld\n",
1350490778eSAugustin Cavalier (long long)nai->ni->mft_no);
1360490778eSAugustin Cavalier }
1370490778eSAugustin Cavalier }
1380490778eSAugustin Cavalier errno = olderrno;
1390490778eSAugustin Cavalier }
1400490778eSAugustin Cavalier
1410490778eSAugustin Cavalier /*
1420490778eSAugustin Cavalier * Update both EA and EA_INFORMATION
1430490778eSAugustin Cavalier */
1440490778eSAugustin Cavalier
ntfs_update_ea(ntfs_inode * ni,const char * value,size_t size,const EA_INFORMATION * ea_info,const EA_INFORMATION * old_ea_info)1450490778eSAugustin Cavalier static int ntfs_update_ea(ntfs_inode *ni, const char *value, size_t size,
1460490778eSAugustin Cavalier const EA_INFORMATION *ea_info,
1470490778eSAugustin Cavalier const EA_INFORMATION *old_ea_info)
1480490778eSAugustin Cavalier {
1490490778eSAugustin Cavalier ntfs_attr *na;
1500490778eSAugustin Cavalier ntfs_attr *nai;
1510490778eSAugustin Cavalier int res;
1520490778eSAugustin Cavalier
1530490778eSAugustin Cavalier res = 0;
1540490778eSAugustin Cavalier nai = ntfs_attr_open(ni, AT_EA_INFORMATION, AT_UNNAMED, 0);
1550490778eSAugustin Cavalier if (nai) {
1560490778eSAugustin Cavalier na = ntfs_attr_open(ni, AT_EA, AT_UNNAMED, 0);
1570490778eSAugustin Cavalier if (na) {
1580490778eSAugustin Cavalier /*
1590490778eSAugustin Cavalier * Set EA_INFORMATION first, it is easier to
1600490778eSAugustin Cavalier * restore the old value, if setting EA fails.
1610490778eSAugustin Cavalier */
1620490778eSAugustin Cavalier if (ntfs_attr_pwrite(nai, 0, sizeof(EA_INFORMATION),
1630490778eSAugustin Cavalier ea_info)
1640490778eSAugustin Cavalier != (s64)sizeof(EA_INFORMATION)) {
1650490778eSAugustin Cavalier res = -errno;
1660490778eSAugustin Cavalier } else {
1670490778eSAugustin Cavalier if (((na->data_size > (s64)size)
1680490778eSAugustin Cavalier && ntfs_attr_truncate(na, size))
1690490778eSAugustin Cavalier || (ntfs_attr_pwrite(na, 0, size, value)
1700490778eSAugustin Cavalier != (s64)size)) {
1710490778eSAugustin Cavalier res = -errno;
1720490778eSAugustin Cavalier if (old_ea_info)
1730490778eSAugustin Cavalier restore_ea_info(nai,
1740490778eSAugustin Cavalier old_ea_info);
1750490778eSAugustin Cavalier }
1760490778eSAugustin Cavalier }
1770490778eSAugustin Cavalier ntfs_attr_close(na);
1780490778eSAugustin Cavalier }
1790490778eSAugustin Cavalier ntfs_attr_close(nai);
1800490778eSAugustin Cavalier } else {
1810490778eSAugustin Cavalier res = -errno;
1820490778eSAugustin Cavalier }
1830490778eSAugustin Cavalier return (res);
1840490778eSAugustin Cavalier }
1850490778eSAugustin Cavalier
1860490778eSAugustin Cavalier /*
1870490778eSAugustin Cavalier * Return the existing EA
1880490778eSAugustin Cavalier *
1890490778eSAugustin Cavalier * The EA_INFORMATION is not examined and the consistency of the
1900490778eSAugustin Cavalier * existing EA is not checked.
1910490778eSAugustin Cavalier *
1920490778eSAugustin Cavalier * If successful, the full attribute is returned unchanged
1930490778eSAugustin Cavalier * and its size is returned.
1940490778eSAugustin Cavalier * If the designated buffer is too small, the needed size is
1950490778eSAugustin Cavalier * returned, and the buffer is left unchanged.
1960490778eSAugustin Cavalier * If there is an error, a negative value is returned and errno
1970490778eSAugustin Cavalier * is set according to the error.
1980490778eSAugustin Cavalier */
1990490778eSAugustin Cavalier
ntfs_get_ntfs_ea(ntfs_inode * ni,char * value,size_t size)2000490778eSAugustin Cavalier int ntfs_get_ntfs_ea(ntfs_inode *ni, char *value, size_t size)
2010490778eSAugustin Cavalier {
2020490778eSAugustin Cavalier s64 ea_size;
2030490778eSAugustin Cavalier void *ea_buf;
2040490778eSAugustin Cavalier int res = 0;
2050490778eSAugustin Cavalier
2060490778eSAugustin Cavalier if (ntfs_attr_exist(ni, AT_EA, AT_UNNAMED, 0)) {
2070490778eSAugustin Cavalier ea_buf = ntfs_attr_readall(ni, AT_EA, (ntfschar*)NULL, 0,
2080490778eSAugustin Cavalier &ea_size);
2090490778eSAugustin Cavalier if (ea_buf) {
2100490778eSAugustin Cavalier if (value && (ea_size <= (s64)size))
2110490778eSAugustin Cavalier memcpy(value, ea_buf, ea_size);
2120490778eSAugustin Cavalier free(ea_buf);
2130490778eSAugustin Cavalier res = ea_size;
2140490778eSAugustin Cavalier } else {
2150490778eSAugustin Cavalier ntfs_log_error("Failed to read EA from inode %lld\n",
2160490778eSAugustin Cavalier (long long)ni->mft_no);
2170490778eSAugustin Cavalier errno = ENODATA;
2180490778eSAugustin Cavalier res = -errno;
2190490778eSAugustin Cavalier }
2200490778eSAugustin Cavalier } else {
2210490778eSAugustin Cavalier errno = ENODATA;
2220490778eSAugustin Cavalier res = -errno;
2230490778eSAugustin Cavalier }
2240490778eSAugustin Cavalier return (res);
2250490778eSAugustin Cavalier }
2260490778eSAugustin Cavalier
2270490778eSAugustin Cavalier /*
2280490778eSAugustin Cavalier * Set a new EA, and set EA_INFORMATION accordingly
2290490778eSAugustin Cavalier *
2300490778eSAugustin Cavalier * This is roughly the same as ZwSetEaFile() on Windows, however
2310490778eSAugustin Cavalier * the "offset to next" of the last EA should not be cleared.
2320490778eSAugustin Cavalier *
2330490778eSAugustin Cavalier * Consistency of the new EA is first checked.
2340490778eSAugustin Cavalier *
2350490778eSAugustin Cavalier * EA_INFORMATION is set first, and it is restored to its former
2360490778eSAugustin Cavalier * state if setting EA fails.
2370490778eSAugustin Cavalier *
2380490778eSAugustin Cavalier * Returns 0 if successful
2390490778eSAugustin Cavalier * a negative value if an error occurred.
2400490778eSAugustin Cavalier */
2410490778eSAugustin Cavalier
ntfs_set_ntfs_ea(ntfs_inode * ni,const char * value,size_t size,int flags)2420490778eSAugustin Cavalier int ntfs_set_ntfs_ea(ntfs_inode *ni, const char *value, size_t size, int flags)
2430490778eSAugustin Cavalier {
2440490778eSAugustin Cavalier EA_INFORMATION ea_info;
2450490778eSAugustin Cavalier EA_INFORMATION *old_ea_info;
2460490778eSAugustin Cavalier s64 old_ea_size;
2470490778eSAugustin Cavalier int res;
2480490778eSAugustin Cavalier size_t offs;
2490490778eSAugustin Cavalier size_t nextoffs;
2500490778eSAugustin Cavalier BOOL ok;
2510490778eSAugustin Cavalier int ea_count;
2520490778eSAugustin Cavalier int ea_packed;
2530490778eSAugustin Cavalier const EA_ATTR *p_ea;
2540490778eSAugustin Cavalier
2550490778eSAugustin Cavalier res = -1;
2560490778eSAugustin Cavalier if (value && (size > 0)) {
2570490778eSAugustin Cavalier /* do consistency checks */
2580490778eSAugustin Cavalier offs = 0;
2590490778eSAugustin Cavalier ok = TRUE;
2600490778eSAugustin Cavalier ea_count = 0;
2610490778eSAugustin Cavalier ea_packed = 0;
2620490778eSAugustin Cavalier nextoffs = 0;
2630490778eSAugustin Cavalier while (ok && (offs < size)) {
2640490778eSAugustin Cavalier p_ea = (const EA_ATTR*)&value[offs];
2650490778eSAugustin Cavalier nextoffs = offs + le32_to_cpu(p_ea->next_entry_offset);
2660490778eSAugustin Cavalier /* null offset to next not allowed */
2670490778eSAugustin Cavalier ok = (nextoffs > offs)
2680490778eSAugustin Cavalier && (nextoffs <= size)
2690490778eSAugustin Cavalier && !(nextoffs & 3)
2700490778eSAugustin Cavalier && p_ea->name_length
2710490778eSAugustin Cavalier /* zero sized value are allowed */
2720490778eSAugustin Cavalier && ((offs + offsetof(EA_ATTR,name)
2730490778eSAugustin Cavalier + p_ea->name_length + 1
2740490778eSAugustin Cavalier + le16_to_cpu(p_ea->value_length))
2750490778eSAugustin Cavalier <= nextoffs)
2760490778eSAugustin Cavalier && ((offs + offsetof(EA_ATTR,name)
2770490778eSAugustin Cavalier + p_ea->name_length + 1
2780490778eSAugustin Cavalier + le16_to_cpu(p_ea->value_length))
2790490778eSAugustin Cavalier >= (nextoffs - 3))
2800490778eSAugustin Cavalier && !p_ea->name[p_ea->name_length];
2810490778eSAugustin Cavalier /* name not checked, as chkdsk accepts any chars */
2820490778eSAugustin Cavalier if (ok) {
2830490778eSAugustin Cavalier if (p_ea->flags & NEED_EA)
2840490778eSAugustin Cavalier ea_count++;
2850490778eSAugustin Cavalier /*
2860490778eSAugustin Cavalier * Assume ea_packed includes :
2870490778eSAugustin Cavalier * 4 bytes for header (flags and lengths)
2880490778eSAugustin Cavalier * + name length + 1
2890490778eSAugustin Cavalier * + value length
2900490778eSAugustin Cavalier */
2910490778eSAugustin Cavalier ea_packed += 5 + p_ea->name_length
2920490778eSAugustin Cavalier + le16_to_cpu(p_ea->value_length);
2930490778eSAugustin Cavalier offs = nextoffs;
2940490778eSAugustin Cavalier }
2950490778eSAugustin Cavalier }
2960490778eSAugustin Cavalier /*
297*9102cad6SAugustin Cavalier * EA and REPARSE_POINT compatibility not checked any more,
298*9102cad6SAugustin Cavalier * required by Windows 10, but having both may lead to
299*9102cad6SAugustin Cavalier * problems with earlier versions.
3000490778eSAugustin Cavalier */
301*9102cad6SAugustin Cavalier if (ok) {
3020490778eSAugustin Cavalier ea_info.ea_length = cpu_to_le16(ea_packed);
3030490778eSAugustin Cavalier ea_info.need_ea_count = cpu_to_le16(ea_count);
3040490778eSAugustin Cavalier ea_info.ea_query_length = cpu_to_le32(nextoffs);
3050490778eSAugustin Cavalier
3060490778eSAugustin Cavalier old_ea_size = 0;
3070490778eSAugustin Cavalier old_ea_info = NULL;
3080490778eSAugustin Cavalier /* Try to save the old EA_INFORMATION */
3090490778eSAugustin Cavalier if (ntfs_attr_exist(ni, AT_EA_INFORMATION,
3100490778eSAugustin Cavalier AT_UNNAMED, 0)) {
3110490778eSAugustin Cavalier old_ea_info = ntfs_attr_readall(ni,
3120490778eSAugustin Cavalier AT_EA_INFORMATION,
3130490778eSAugustin Cavalier (ntfschar*)NULL, 0, &old_ea_size);
3140490778eSAugustin Cavalier }
3150490778eSAugustin Cavalier /*
3160490778eSAugustin Cavalier * no EA or EA_INFORMATION : add them
3170490778eSAugustin Cavalier */
3180490778eSAugustin Cavalier if (!ntfs_need_ea(ni, AT_EA_INFORMATION,
3190490778eSAugustin Cavalier sizeof(EA_INFORMATION), flags)
3200490778eSAugustin Cavalier && !ntfs_need_ea(ni, AT_EA, 0, flags)) {
3210490778eSAugustin Cavalier res = ntfs_update_ea(ni, value, size,
3220490778eSAugustin Cavalier &ea_info, old_ea_info);
3230490778eSAugustin Cavalier } else {
3240490778eSAugustin Cavalier res = -errno;
3250490778eSAugustin Cavalier }
3260490778eSAugustin Cavalier if (old_ea_info)
3270490778eSAugustin Cavalier free(old_ea_info);
3280490778eSAugustin Cavalier } else {
3290490778eSAugustin Cavalier errno = EINVAL;
3300490778eSAugustin Cavalier res = -errno;
3310490778eSAugustin Cavalier }
3320490778eSAugustin Cavalier } else {
3330490778eSAugustin Cavalier errno = EINVAL;
3340490778eSAugustin Cavalier res = -errno;
3350490778eSAugustin Cavalier }
3360490778eSAugustin Cavalier return (res);
3370490778eSAugustin Cavalier }
3380490778eSAugustin Cavalier
3390490778eSAugustin Cavalier /*
3400490778eSAugustin Cavalier * Remove the EA (including EA_INFORMATION)
3410490778eSAugustin Cavalier *
3420490778eSAugustin Cavalier * EA_INFORMATION is removed first, and it is restored to its former
3430490778eSAugustin Cavalier * state if removing EA fails.
3440490778eSAugustin Cavalier *
3450490778eSAugustin Cavalier * Returns 0, or -1 if there is a problem
3460490778eSAugustin Cavalier */
3470490778eSAugustin Cavalier
ntfs_remove_ntfs_ea(ntfs_inode * ni)3480490778eSAugustin Cavalier int ntfs_remove_ntfs_ea(ntfs_inode *ni)
3490490778eSAugustin Cavalier {
3500490778eSAugustin Cavalier EA_INFORMATION *old_ea_info;
3510490778eSAugustin Cavalier s64 old_ea_size;
3520490778eSAugustin Cavalier int res;
3530490778eSAugustin Cavalier ntfs_attr *na;
3540490778eSAugustin Cavalier ntfs_attr *nai;
3550490778eSAugustin Cavalier
3560490778eSAugustin Cavalier res = 0;
3570490778eSAugustin Cavalier if (ni) {
3580490778eSAugustin Cavalier /*
3590490778eSAugustin Cavalier * open and delete the EA_INFORMATION and the EA
3600490778eSAugustin Cavalier */
3610490778eSAugustin Cavalier nai = ntfs_attr_open(ni, AT_EA_INFORMATION, AT_UNNAMED, 0);
3620490778eSAugustin Cavalier if (nai) {
3630490778eSAugustin Cavalier na = ntfs_attr_open(ni, AT_EA, AT_UNNAMED, 0);
3640490778eSAugustin Cavalier if (na) {
3650490778eSAugustin Cavalier /* Try to save the old EA_INFORMATION */
3660490778eSAugustin Cavalier old_ea_info = ntfs_attr_readall(ni,
3670490778eSAugustin Cavalier AT_EA_INFORMATION,
3680490778eSAugustin Cavalier (ntfschar*)NULL, 0, &old_ea_size);
3690490778eSAugustin Cavalier res = ntfs_attr_rm(na);
3700490778eSAugustin Cavalier NInoFileNameSetDirty(ni);
3710490778eSAugustin Cavalier if (!res) {
3720490778eSAugustin Cavalier res = ntfs_attr_rm(nai);
3730490778eSAugustin Cavalier if (res && old_ea_info) {
3740490778eSAugustin Cavalier /*
3750490778eSAugustin Cavalier * Failed to remove the EA, try to
3760490778eSAugustin Cavalier * restore the EA_INFORMATION
3770490778eSAugustin Cavalier */
3780490778eSAugustin Cavalier restore_ea_info(nai,
3790490778eSAugustin Cavalier old_ea_info);
3800490778eSAugustin Cavalier }
3810490778eSAugustin Cavalier } else {
3820490778eSAugustin Cavalier ntfs_log_error("Failed to remove the"
3830490778eSAugustin Cavalier " EA_INFORMATION from inode %lld\n",
3840490778eSAugustin Cavalier (long long)ni->mft_no);
3850490778eSAugustin Cavalier }
3860490778eSAugustin Cavalier free(old_ea_info);
3870490778eSAugustin Cavalier ntfs_attr_close(na);
3880490778eSAugustin Cavalier } else {
3890490778eSAugustin Cavalier /* EA_INFORMATION present, but no EA */
3900490778eSAugustin Cavalier res = ntfs_attr_rm(nai);
3910490778eSAugustin Cavalier NInoFileNameSetDirty(ni);
3920490778eSAugustin Cavalier }
3930490778eSAugustin Cavalier ntfs_attr_close(nai);
3940490778eSAugustin Cavalier } else {
3950490778eSAugustin Cavalier errno = ENODATA;
3960490778eSAugustin Cavalier res = -1;
3970490778eSAugustin Cavalier }
3980490778eSAugustin Cavalier NInoSetDirty(ni);
3990490778eSAugustin Cavalier } else {
4000490778eSAugustin Cavalier errno = EINVAL;
4010490778eSAugustin Cavalier res = -1;
4020490778eSAugustin Cavalier }
4030490778eSAugustin Cavalier return (res ? -1 : 0);
4040490778eSAugustin Cavalier }
405*9102cad6SAugustin Cavalier
406*9102cad6SAugustin Cavalier /*
407*9102cad6SAugustin Cavalier * Check for the presence of an EA "$LXDEV" (used by WSL)
408*9102cad6SAugustin Cavalier * and return its value as a device address
409*9102cad6SAugustin Cavalier *
410*9102cad6SAugustin Cavalier * Returns zero if successful
411*9102cad6SAugustin Cavalier * -1 if failed, with errno set
412*9102cad6SAugustin Cavalier */
413*9102cad6SAugustin Cavalier
ntfs_ea_check_wsldev(ntfs_inode * ni,dev_t * rdevp)414*9102cad6SAugustin Cavalier int ntfs_ea_check_wsldev(ntfs_inode *ni, dev_t *rdevp)
415*9102cad6SAugustin Cavalier {
416*9102cad6SAugustin Cavalier const EA_ATTR *p_ea;
417*9102cad6SAugustin Cavalier int bufsize;
418*9102cad6SAugustin Cavalier char *buf;
419*9102cad6SAugustin Cavalier int lth;
420*9102cad6SAugustin Cavalier int res;
421*9102cad6SAugustin Cavalier int offset;
422*9102cad6SAugustin Cavalier int next;
423*9102cad6SAugustin Cavalier BOOL found;
424*9102cad6SAugustin Cavalier struct {
425*9102cad6SAugustin Cavalier le32 major;
426*9102cad6SAugustin Cavalier le32 minor;
427*9102cad6SAugustin Cavalier } device;
428*9102cad6SAugustin Cavalier
429*9102cad6SAugustin Cavalier res = -EOPNOTSUPP;
430*9102cad6SAugustin Cavalier bufsize = 256; /* expected to be enough */
431*9102cad6SAugustin Cavalier buf = (char*)malloc(bufsize);
432*9102cad6SAugustin Cavalier if (buf) {
433*9102cad6SAugustin Cavalier lth = ntfs_get_ntfs_ea(ni, buf, bufsize);
434*9102cad6SAugustin Cavalier /* retry if short buf */
435*9102cad6SAugustin Cavalier if (lth > bufsize) {
436*9102cad6SAugustin Cavalier free(buf);
437*9102cad6SAugustin Cavalier bufsize = lth;
438*9102cad6SAugustin Cavalier buf = (char*)malloc(bufsize);
439*9102cad6SAugustin Cavalier if (buf)
440*9102cad6SAugustin Cavalier lth = ntfs_get_ntfs_ea(ni, buf, bufsize);
441*9102cad6SAugustin Cavalier }
442*9102cad6SAugustin Cavalier }
443*9102cad6SAugustin Cavalier if (buf && (lth > 0) && (lth <= bufsize)) {
444*9102cad6SAugustin Cavalier offset = 0;
445*9102cad6SAugustin Cavalier found = FALSE;
446*9102cad6SAugustin Cavalier do {
447*9102cad6SAugustin Cavalier p_ea = (const EA_ATTR*)&buf[offset];
448*9102cad6SAugustin Cavalier next = le32_to_cpu(p_ea->next_entry_offset);
449*9102cad6SAugustin Cavalier found = ((next > (int)(sizeof(lxdev) + sizeof(device)))
450*9102cad6SAugustin Cavalier && (p_ea->name_length == (sizeof(lxdev) - 1))
451*9102cad6SAugustin Cavalier && (p_ea->value_length
452*9102cad6SAugustin Cavalier == const_cpu_to_le16(sizeof(device)))
453*9102cad6SAugustin Cavalier && !memcmp(p_ea->name, lxdev, sizeof(lxdev)));
454*9102cad6SAugustin Cavalier if (!found)
455*9102cad6SAugustin Cavalier offset += next;
456*9102cad6SAugustin Cavalier } while (!found && (next > 0) && (offset < lth));
457*9102cad6SAugustin Cavalier if (found) {
458*9102cad6SAugustin Cavalier /* beware of alignment */
459*9102cad6SAugustin Cavalier memcpy(&device, &p_ea->name[p_ea->name_length + 1],
460*9102cad6SAugustin Cavalier sizeof(device));
461*9102cad6SAugustin Cavalier *rdevp = makedev(le32_to_cpu(device.major),
462*9102cad6SAugustin Cavalier le32_to_cpu(device.minor));
463*9102cad6SAugustin Cavalier res = 0;
464*9102cad6SAugustin Cavalier }
465*9102cad6SAugustin Cavalier }
466*9102cad6SAugustin Cavalier free(buf);
467*9102cad6SAugustin Cavalier return (res);
468*9102cad6SAugustin Cavalier }
469*9102cad6SAugustin Cavalier
ntfs_ea_set_wsl_not_symlink(ntfs_inode * ni,mode_t type,dev_t dev)470*9102cad6SAugustin Cavalier int ntfs_ea_set_wsl_not_symlink(ntfs_inode *ni, mode_t type, dev_t dev)
471*9102cad6SAugustin Cavalier {
472*9102cad6SAugustin Cavalier le32 mode;
473*9102cad6SAugustin Cavalier struct {
474*9102cad6SAugustin Cavalier le32 major;
475*9102cad6SAugustin Cavalier le32 minor;
476*9102cad6SAugustin Cavalier } device;
477*9102cad6SAugustin Cavalier struct EA_WSL {
478*9102cad6SAugustin Cavalier struct EA_LXMOD { /* always inserted */
479*9102cad6SAugustin Cavalier EA_ATTR base;
480*9102cad6SAugustin Cavalier char name[sizeof(lxmod)];
481*9102cad6SAugustin Cavalier char value[sizeof(mode)];
482*9102cad6SAugustin Cavalier char stuff[3 & -(sizeof(lxmod) + sizeof(mode))];
483*9102cad6SAugustin Cavalier } mod;
484*9102cad6SAugustin Cavalier struct EA_LXDEV { /* char or block devices only */
485*9102cad6SAugustin Cavalier EA_ATTR base;
486*9102cad6SAugustin Cavalier char name[sizeof(lxdev)];
487*9102cad6SAugustin Cavalier char value[sizeof(device)];
488*9102cad6SAugustin Cavalier char stuff[3 & -(sizeof(lxdev) + sizeof(device))];
489*9102cad6SAugustin Cavalier } dev;
490*9102cad6SAugustin Cavalier } attr;
491*9102cad6SAugustin Cavalier int len;
492*9102cad6SAugustin Cavalier int res;
493*9102cad6SAugustin Cavalier
494*9102cad6SAugustin Cavalier memset(&attr, 0, sizeof(attr));
495*9102cad6SAugustin Cavalier mode = cpu_to_le32((u32)(type | 0644));
496*9102cad6SAugustin Cavalier attr.mod.base.next_entry_offset
497*9102cad6SAugustin Cavalier = const_cpu_to_le32(sizeof(attr.mod));
498*9102cad6SAugustin Cavalier attr.mod.base.flags = 0;
499*9102cad6SAugustin Cavalier attr.mod.base.name_length = sizeof(lxmod) - 1;
500*9102cad6SAugustin Cavalier attr.mod.base.value_length = const_cpu_to_le16(sizeof(mode));
501*9102cad6SAugustin Cavalier memcpy(attr.mod.name, lxmod, sizeof(lxmod));
502*9102cad6SAugustin Cavalier memcpy(attr.mod.value, &mode, sizeof(mode));
503*9102cad6SAugustin Cavalier len = sizeof(attr.mod);
504*9102cad6SAugustin Cavalier
505*9102cad6SAugustin Cavalier if (S_ISCHR(type) || S_ISBLK(type)) {
506*9102cad6SAugustin Cavalier device.major = cpu_to_le32(major(dev));
507*9102cad6SAugustin Cavalier device.minor = cpu_to_le32(minor(dev));
508*9102cad6SAugustin Cavalier attr.dev.base.next_entry_offset
509*9102cad6SAugustin Cavalier = const_cpu_to_le32(sizeof(attr.dev));
510*9102cad6SAugustin Cavalier attr.dev.base.flags = 0;
511*9102cad6SAugustin Cavalier attr.dev.base.name_length = sizeof(lxdev) - 1;
512*9102cad6SAugustin Cavalier attr.dev.base.value_length = const_cpu_to_le16(sizeof(device));
513*9102cad6SAugustin Cavalier memcpy(attr.dev.name, lxdev, sizeof(lxdev));
514*9102cad6SAugustin Cavalier memcpy(attr.dev.value, &device, sizeof(device));
515*9102cad6SAugustin Cavalier len += sizeof(attr.dev);
516*9102cad6SAugustin Cavalier }
517*9102cad6SAugustin Cavalier res = ntfs_set_ntfs_ea(ni, (char*)&attr, len, 0);
518*9102cad6SAugustin Cavalier return (res);
519*9102cad6SAugustin Cavalier }
520