xref: /haiku/src/add-ons/kernel/file_systems/ntfs/libntfs/ea.c (revision 268f99dd7dc4bd7474a8bd2742d3f1ec1de6752a)
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