1987da915Sopenharmony_ci/** 2987da915Sopenharmony_ci * ea.c - Processing of EA's 3987da915Sopenharmony_ci * 4987da915Sopenharmony_ci * This module is part of ntfs-3g library 5987da915Sopenharmony_ci * 6987da915Sopenharmony_ci * Copyright (c) 2014-2021 Jean-Pierre Andre 7987da915Sopenharmony_ci * 8987da915Sopenharmony_ci * This program/include file is free software; you can redistribute it and/or 9987da915Sopenharmony_ci * modify it under the terms of the GNU General Public License as published 10987da915Sopenharmony_ci * by the Free Software Foundation; either version 2 of the License, or 11987da915Sopenharmony_ci * (at your option) any later version. 12987da915Sopenharmony_ci * 13987da915Sopenharmony_ci * This program/include file is distributed in the hope that it will be 14987da915Sopenharmony_ci * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 15987da915Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16987da915Sopenharmony_ci * GNU General Public License for more details. 17987da915Sopenharmony_ci * 18987da915Sopenharmony_ci * You should have received a copy of the GNU General Public License 19987da915Sopenharmony_ci * along with this program (in the main directory of the NTFS-3G 20987da915Sopenharmony_ci * distribution in the file COPYING); if not, write to the Free Software 21987da915Sopenharmony_ci * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22987da915Sopenharmony_ci */ 23987da915Sopenharmony_ci 24987da915Sopenharmony_ci#ifdef HAVE_CONFIG_H 25987da915Sopenharmony_ci#include "config.h" 26987da915Sopenharmony_ci#endif 27987da915Sopenharmony_ci 28987da915Sopenharmony_ci#ifdef HAVE_STDIO_H 29987da915Sopenharmony_ci#include <stdio.h> 30987da915Sopenharmony_ci#endif 31987da915Sopenharmony_ci#ifdef HAVE_STDLIB_H 32987da915Sopenharmony_ci#include <stdlib.h> 33987da915Sopenharmony_ci#endif 34987da915Sopenharmony_ci#ifdef HAVE_STRING_H 35987da915Sopenharmony_ci#include <string.h> 36987da915Sopenharmony_ci#endif 37987da915Sopenharmony_ci#ifdef HAVE_FCNTL_H 38987da915Sopenharmony_ci#include <fcntl.h> 39987da915Sopenharmony_ci#endif 40987da915Sopenharmony_ci#ifdef HAVE_UNISTD_H 41987da915Sopenharmony_ci#include <unistd.h> 42987da915Sopenharmony_ci#endif 43987da915Sopenharmony_ci#ifdef HAVE_ERRNO_H 44987da915Sopenharmony_ci#include <errno.h> 45987da915Sopenharmony_ci#endif 46987da915Sopenharmony_ci#ifdef MAJOR_IN_MKDEV 47987da915Sopenharmony_ci#include <sys/mkdev.h> 48987da915Sopenharmony_ci#endif 49987da915Sopenharmony_ci#ifdef MAJOR_IN_SYSMACROS 50987da915Sopenharmony_ci#include <sys/sysmacros.h> 51987da915Sopenharmony_ci#endif 52987da915Sopenharmony_ci 53987da915Sopenharmony_ci#include "types.h" 54987da915Sopenharmony_ci#include "param.h" 55987da915Sopenharmony_ci#include "layout.h" 56987da915Sopenharmony_ci#include "attrib.h" 57987da915Sopenharmony_ci#include "index.h" 58987da915Sopenharmony_ci#include "dir.h" 59987da915Sopenharmony_ci#include "ea.h" 60987da915Sopenharmony_ci#include "misc.h" 61987da915Sopenharmony_ci#include "logging.h" 62987da915Sopenharmony_ci#include "xattrs.h" 63987da915Sopenharmony_ci 64987da915Sopenharmony_cistatic const char lxdev[] = "$LXDEV"; 65987da915Sopenharmony_cistatic const char lxmod[] = "$LXMOD"; 66987da915Sopenharmony_ci 67987da915Sopenharmony_ci 68987da915Sopenharmony_ci/* 69987da915Sopenharmony_ci * Create a needed attribute (EA or EA_INFORMATION) 70987da915Sopenharmony_ci * 71987da915Sopenharmony_ci * Returns 0 if successful, 72987da915Sopenharmony_ci * -1 otherwise, with errno indicating why it failed. 73987da915Sopenharmony_ci */ 74987da915Sopenharmony_ci 75987da915Sopenharmony_cistatic int ntfs_need_ea(ntfs_inode *ni, ATTR_TYPES type, int size, int flags) 76987da915Sopenharmony_ci{ 77987da915Sopenharmony_ci u8 dummy; 78987da915Sopenharmony_ci int res; 79987da915Sopenharmony_ci 80987da915Sopenharmony_ci res = 0; 81987da915Sopenharmony_ci if (!ntfs_attr_exist(ni,type, AT_UNNAMED,0)) { 82987da915Sopenharmony_ci if (!(flags & XATTR_REPLACE)) { 83987da915Sopenharmony_ci /* 84987da915Sopenharmony_ci * no needed attribute : add one, 85987da915Sopenharmony_ci * apparently, this does not feed the new value in 86987da915Sopenharmony_ci * Note : NTFS version must be >= 3 87987da915Sopenharmony_ci */ 88987da915Sopenharmony_ci if (ni->vol->major_ver >= 3) { 89987da915Sopenharmony_ci res = ntfs_attr_add(ni, type, 90987da915Sopenharmony_ci AT_UNNAMED,0,&dummy,(s64)size); 91987da915Sopenharmony_ci if (!res) { 92987da915Sopenharmony_ci NInoFileNameSetDirty(ni); 93987da915Sopenharmony_ci } 94987da915Sopenharmony_ci NInoSetDirty(ni); 95987da915Sopenharmony_ci } else { 96987da915Sopenharmony_ci errno = EOPNOTSUPP; 97987da915Sopenharmony_ci res = -1; 98987da915Sopenharmony_ci } 99987da915Sopenharmony_ci } else { 100987da915Sopenharmony_ci errno = ENODATA; 101987da915Sopenharmony_ci res = -1; 102987da915Sopenharmony_ci } 103987da915Sopenharmony_ci } 104987da915Sopenharmony_ci return (res); 105987da915Sopenharmony_ci} 106987da915Sopenharmony_ci 107987da915Sopenharmony_ci/* 108987da915Sopenharmony_ci * Restore the old EA_INFORMATION or delete the current one, 109987da915Sopenharmony_ci * when EA cannot be updated. 110987da915Sopenharmony_ci * 111987da915Sopenharmony_ci * As this is used in the context of some other error, the caller 112987da915Sopenharmony_ci * is responsible for returning the proper error, and errno is 113987da915Sopenharmony_ci * left unchanged. 114987da915Sopenharmony_ci * Only double errors are logged here. 115987da915Sopenharmony_ci */ 116987da915Sopenharmony_ci 117987da915Sopenharmony_cistatic void restore_ea_info(ntfs_attr *nai, const EA_INFORMATION *old_ea_info) 118987da915Sopenharmony_ci{ 119987da915Sopenharmony_ci s64 written; 120987da915Sopenharmony_ci int olderrno; 121987da915Sopenharmony_ci 122987da915Sopenharmony_ci olderrno = errno; 123987da915Sopenharmony_ci if (old_ea_info) { 124987da915Sopenharmony_ci written = ntfs_attr_pwrite(nai, 0, sizeof(EA_INFORMATION), 125987da915Sopenharmony_ci old_ea_info); 126987da915Sopenharmony_ci if ((size_t)written != sizeof(EA_INFORMATION)) { 127987da915Sopenharmony_ci ntfs_log_error("Could not restore the EA_INFORMATION," 128987da915Sopenharmony_ci " possible inconsistency in inode %lld\n", 129987da915Sopenharmony_ci (long long)nai->ni->mft_no); 130987da915Sopenharmony_ci } 131987da915Sopenharmony_ci } else { 132987da915Sopenharmony_ci if (ntfs_attr_rm(nai)) { 133987da915Sopenharmony_ci ntfs_log_error("Could not delete the EA_INFORMATION," 134987da915Sopenharmony_ci " possible inconsistency in inode %lld\n", 135987da915Sopenharmony_ci (long long)nai->ni->mft_no); 136987da915Sopenharmony_ci } 137987da915Sopenharmony_ci } 138987da915Sopenharmony_ci errno = olderrno; 139987da915Sopenharmony_ci} 140987da915Sopenharmony_ci 141987da915Sopenharmony_ci/* 142987da915Sopenharmony_ci * Update both EA and EA_INFORMATION 143987da915Sopenharmony_ci */ 144987da915Sopenharmony_ci 145987da915Sopenharmony_cistatic int ntfs_update_ea(ntfs_inode *ni, const char *value, size_t size, 146987da915Sopenharmony_ci const EA_INFORMATION *ea_info, 147987da915Sopenharmony_ci const EA_INFORMATION *old_ea_info) 148987da915Sopenharmony_ci{ 149987da915Sopenharmony_ci ntfs_attr *na; 150987da915Sopenharmony_ci ntfs_attr *nai; 151987da915Sopenharmony_ci int res; 152987da915Sopenharmony_ci 153987da915Sopenharmony_ci res = 0; 154987da915Sopenharmony_ci nai = ntfs_attr_open(ni, AT_EA_INFORMATION, AT_UNNAMED, 0); 155987da915Sopenharmony_ci if (nai) { 156987da915Sopenharmony_ci na = ntfs_attr_open(ni, AT_EA, AT_UNNAMED, 0); 157987da915Sopenharmony_ci if (na) { 158987da915Sopenharmony_ci /* 159987da915Sopenharmony_ci * Set EA_INFORMATION first, it is easier to 160987da915Sopenharmony_ci * restore the old value, if setting EA fails. 161987da915Sopenharmony_ci */ 162987da915Sopenharmony_ci if (ntfs_attr_pwrite(nai, 0, sizeof(EA_INFORMATION), 163987da915Sopenharmony_ci ea_info) 164987da915Sopenharmony_ci != (s64)sizeof(EA_INFORMATION)) { 165987da915Sopenharmony_ci res = -errno; 166987da915Sopenharmony_ci } else { 167987da915Sopenharmony_ci if (((na->data_size > (s64)size) 168987da915Sopenharmony_ci && ntfs_attr_truncate(na, size)) 169987da915Sopenharmony_ci || (ntfs_attr_pwrite(na, 0, size, value) 170987da915Sopenharmony_ci != (s64)size)) { 171987da915Sopenharmony_ci res = -errno; 172987da915Sopenharmony_ci if (old_ea_info) 173987da915Sopenharmony_ci restore_ea_info(nai, 174987da915Sopenharmony_ci old_ea_info); 175987da915Sopenharmony_ci } 176987da915Sopenharmony_ci } 177987da915Sopenharmony_ci ntfs_attr_close(na); 178987da915Sopenharmony_ci } 179987da915Sopenharmony_ci ntfs_attr_close(nai); 180987da915Sopenharmony_ci } else { 181987da915Sopenharmony_ci res = -errno; 182987da915Sopenharmony_ci } 183987da915Sopenharmony_ci return (res); 184987da915Sopenharmony_ci} 185987da915Sopenharmony_ci 186987da915Sopenharmony_ci/* 187987da915Sopenharmony_ci * Return the existing EA 188987da915Sopenharmony_ci * 189987da915Sopenharmony_ci * The EA_INFORMATION is not examined and the consistency of the 190987da915Sopenharmony_ci * existing EA is not checked. 191987da915Sopenharmony_ci * 192987da915Sopenharmony_ci * If successful, the full attribute is returned unchanged 193987da915Sopenharmony_ci * and its size is returned. 194987da915Sopenharmony_ci * If the designated buffer is too small, the needed size is 195987da915Sopenharmony_ci * returned, and the buffer is left unchanged. 196987da915Sopenharmony_ci * If there is an error, a negative value is returned and errno 197987da915Sopenharmony_ci * is set according to the error. 198987da915Sopenharmony_ci */ 199987da915Sopenharmony_ci 200987da915Sopenharmony_ciint ntfs_get_ntfs_ea(ntfs_inode *ni, char *value, size_t size) 201987da915Sopenharmony_ci{ 202987da915Sopenharmony_ci s64 ea_size; 203987da915Sopenharmony_ci void *ea_buf; 204987da915Sopenharmony_ci int res = 0; 205987da915Sopenharmony_ci 206987da915Sopenharmony_ci if (ntfs_attr_exist(ni, AT_EA, AT_UNNAMED, 0)) { 207987da915Sopenharmony_ci ea_buf = ntfs_attr_readall(ni, AT_EA, (ntfschar*)NULL, 0, 208987da915Sopenharmony_ci &ea_size); 209987da915Sopenharmony_ci if (ea_buf) { 210987da915Sopenharmony_ci if (value && (ea_size <= (s64)size)) 211987da915Sopenharmony_ci memcpy(value, ea_buf, ea_size); 212987da915Sopenharmony_ci free(ea_buf); 213987da915Sopenharmony_ci res = ea_size; 214987da915Sopenharmony_ci } else { 215987da915Sopenharmony_ci ntfs_log_error("Failed to read EA from inode %lld\n", 216987da915Sopenharmony_ci (long long)ni->mft_no); 217987da915Sopenharmony_ci errno = ENODATA; 218987da915Sopenharmony_ci res = -errno; 219987da915Sopenharmony_ci } 220987da915Sopenharmony_ci } else { 221987da915Sopenharmony_ci errno = ENODATA; 222987da915Sopenharmony_ci res = -errno; 223987da915Sopenharmony_ci } 224987da915Sopenharmony_ci return (res); 225987da915Sopenharmony_ci} 226987da915Sopenharmony_ci 227987da915Sopenharmony_ci/* 228987da915Sopenharmony_ci * Set a new EA, and set EA_INFORMATION accordingly 229987da915Sopenharmony_ci * 230987da915Sopenharmony_ci * This is roughly the same as ZwSetEaFile() on Windows, however 231987da915Sopenharmony_ci * the "offset to next" of the last EA should not be cleared. 232987da915Sopenharmony_ci * 233987da915Sopenharmony_ci * Consistency of the new EA is first checked. 234987da915Sopenharmony_ci * 235987da915Sopenharmony_ci * EA_INFORMATION is set first, and it is restored to its former 236987da915Sopenharmony_ci * state if setting EA fails. 237987da915Sopenharmony_ci * 238987da915Sopenharmony_ci * Returns 0 if successful 239987da915Sopenharmony_ci * a negative value if an error occurred. 240987da915Sopenharmony_ci */ 241987da915Sopenharmony_ci 242987da915Sopenharmony_ciint ntfs_set_ntfs_ea(ntfs_inode *ni, const char *value, size_t size, int flags) 243987da915Sopenharmony_ci{ 244987da915Sopenharmony_ci EA_INFORMATION ea_info; 245987da915Sopenharmony_ci EA_INFORMATION *old_ea_info; 246987da915Sopenharmony_ci s64 old_ea_size; 247987da915Sopenharmony_ci int res; 248987da915Sopenharmony_ci size_t offs; 249987da915Sopenharmony_ci size_t nextoffs; 250987da915Sopenharmony_ci BOOL ok; 251987da915Sopenharmony_ci int ea_count; 252987da915Sopenharmony_ci int ea_packed; 253987da915Sopenharmony_ci const EA_ATTR *p_ea; 254987da915Sopenharmony_ci 255987da915Sopenharmony_ci res = -1; 256987da915Sopenharmony_ci if (value && (size > 0)) { 257987da915Sopenharmony_ci /* do consistency checks */ 258987da915Sopenharmony_ci offs = 0; 259987da915Sopenharmony_ci ok = TRUE; 260987da915Sopenharmony_ci ea_count = 0; 261987da915Sopenharmony_ci ea_packed = 0; 262987da915Sopenharmony_ci nextoffs = 0; 263987da915Sopenharmony_ci while (ok && (offs < size)) { 264987da915Sopenharmony_ci p_ea = (const EA_ATTR*)&value[offs]; 265987da915Sopenharmony_ci nextoffs = offs + le32_to_cpu(p_ea->next_entry_offset); 266987da915Sopenharmony_ci /* null offset to next not allowed */ 267987da915Sopenharmony_ci ok = (nextoffs > offs) 268987da915Sopenharmony_ci && (nextoffs <= size) 269987da915Sopenharmony_ci && !(nextoffs & 3) 270987da915Sopenharmony_ci && p_ea->name_length 271987da915Sopenharmony_ci /* zero sized value are allowed */ 272987da915Sopenharmony_ci && ((offs + offsetof(EA_ATTR,name) 273987da915Sopenharmony_ci + p_ea->name_length + 1 274987da915Sopenharmony_ci + le16_to_cpu(p_ea->value_length)) 275987da915Sopenharmony_ci <= nextoffs) 276987da915Sopenharmony_ci && ((offs + offsetof(EA_ATTR,name) 277987da915Sopenharmony_ci + p_ea->name_length + 1 278987da915Sopenharmony_ci + le16_to_cpu(p_ea->value_length)) 279987da915Sopenharmony_ci >= (nextoffs - 3)) 280987da915Sopenharmony_ci && !p_ea->name[p_ea->name_length]; 281987da915Sopenharmony_ci /* name not checked, as chkdsk accepts any chars */ 282987da915Sopenharmony_ci if (ok) { 283987da915Sopenharmony_ci if (p_ea->flags & NEED_EA) 284987da915Sopenharmony_ci ea_count++; 285987da915Sopenharmony_ci /* 286987da915Sopenharmony_ci * Assume ea_packed includes : 287987da915Sopenharmony_ci * 4 bytes for header (flags and lengths) 288987da915Sopenharmony_ci * + name length + 1 289987da915Sopenharmony_ci * + value length 290987da915Sopenharmony_ci */ 291987da915Sopenharmony_ci ea_packed += 5 + p_ea->name_length 292987da915Sopenharmony_ci + le16_to_cpu(p_ea->value_length); 293987da915Sopenharmony_ci offs = nextoffs; 294987da915Sopenharmony_ci } 295987da915Sopenharmony_ci } 296987da915Sopenharmony_ci /* 297987da915Sopenharmony_ci * EA and REPARSE_POINT compatibility not checked any more, 298987da915Sopenharmony_ci * required by Windows 10, but having both may lead to 299987da915Sopenharmony_ci * problems with earlier versions. 300987da915Sopenharmony_ci */ 301987da915Sopenharmony_ci if (ok) { 302987da915Sopenharmony_ci ea_info.ea_length = cpu_to_le16(ea_packed); 303987da915Sopenharmony_ci ea_info.need_ea_count = cpu_to_le16(ea_count); 304987da915Sopenharmony_ci ea_info.ea_query_length = cpu_to_le32(nextoffs); 305987da915Sopenharmony_ci 306987da915Sopenharmony_ci old_ea_size = 0; 307987da915Sopenharmony_ci old_ea_info = NULL; 308987da915Sopenharmony_ci /* Try to save the old EA_INFORMATION */ 309987da915Sopenharmony_ci if (ntfs_attr_exist(ni, AT_EA_INFORMATION, 310987da915Sopenharmony_ci AT_UNNAMED, 0)) { 311987da915Sopenharmony_ci old_ea_info = ntfs_attr_readall(ni, 312987da915Sopenharmony_ci AT_EA_INFORMATION, 313987da915Sopenharmony_ci (ntfschar*)NULL, 0, &old_ea_size); 314987da915Sopenharmony_ci } 315987da915Sopenharmony_ci /* 316987da915Sopenharmony_ci * no EA or EA_INFORMATION : add them 317987da915Sopenharmony_ci */ 318987da915Sopenharmony_ci if (!ntfs_need_ea(ni, AT_EA_INFORMATION, 319987da915Sopenharmony_ci sizeof(EA_INFORMATION), flags) 320987da915Sopenharmony_ci && !ntfs_need_ea(ni, AT_EA, 0, flags)) { 321987da915Sopenharmony_ci res = ntfs_update_ea(ni, value, size, 322987da915Sopenharmony_ci &ea_info, old_ea_info); 323987da915Sopenharmony_ci } else { 324987da915Sopenharmony_ci res = -errno; 325987da915Sopenharmony_ci } 326987da915Sopenharmony_ci if (old_ea_info) 327987da915Sopenharmony_ci free(old_ea_info); 328987da915Sopenharmony_ci } else { 329987da915Sopenharmony_ci errno = EINVAL; 330987da915Sopenharmony_ci res = -errno; 331987da915Sopenharmony_ci } 332987da915Sopenharmony_ci } else { 333987da915Sopenharmony_ci errno = EINVAL; 334987da915Sopenharmony_ci res = -errno; 335987da915Sopenharmony_ci } 336987da915Sopenharmony_ci return (res); 337987da915Sopenharmony_ci} 338987da915Sopenharmony_ci 339987da915Sopenharmony_ci/* 340987da915Sopenharmony_ci * Remove the EA (including EA_INFORMATION) 341987da915Sopenharmony_ci * 342987da915Sopenharmony_ci * EA_INFORMATION is removed first, and it is restored to its former 343987da915Sopenharmony_ci * state if removing EA fails. 344987da915Sopenharmony_ci * 345987da915Sopenharmony_ci * Returns 0, or -1 if there is a problem 346987da915Sopenharmony_ci */ 347987da915Sopenharmony_ci 348987da915Sopenharmony_ciint ntfs_remove_ntfs_ea(ntfs_inode *ni) 349987da915Sopenharmony_ci{ 350987da915Sopenharmony_ci EA_INFORMATION *old_ea_info; 351987da915Sopenharmony_ci s64 old_ea_size; 352987da915Sopenharmony_ci int res; 353987da915Sopenharmony_ci ntfs_attr *na; 354987da915Sopenharmony_ci ntfs_attr *nai; 355987da915Sopenharmony_ci 356987da915Sopenharmony_ci res = 0; 357987da915Sopenharmony_ci if (ni) { 358987da915Sopenharmony_ci /* 359987da915Sopenharmony_ci * open and delete the EA_INFORMATION and the EA 360987da915Sopenharmony_ci */ 361987da915Sopenharmony_ci nai = ntfs_attr_open(ni, AT_EA_INFORMATION, AT_UNNAMED, 0); 362987da915Sopenharmony_ci if (nai) { 363987da915Sopenharmony_ci na = ntfs_attr_open(ni, AT_EA, AT_UNNAMED, 0); 364987da915Sopenharmony_ci if (na) { 365987da915Sopenharmony_ci /* Try to save the old EA_INFORMATION */ 366987da915Sopenharmony_ci old_ea_info = ntfs_attr_readall(ni, 367987da915Sopenharmony_ci AT_EA_INFORMATION, 368987da915Sopenharmony_ci (ntfschar*)NULL, 0, &old_ea_size); 369987da915Sopenharmony_ci res = ntfs_attr_rm(na); 370987da915Sopenharmony_ci NInoFileNameSetDirty(ni); 371987da915Sopenharmony_ci if (!res) { 372987da915Sopenharmony_ci res = ntfs_attr_rm(nai); 373987da915Sopenharmony_ci if (res && old_ea_info) { 374987da915Sopenharmony_ci /* 375987da915Sopenharmony_ci * Failed to remove the EA, try to 376987da915Sopenharmony_ci * restore the EA_INFORMATION 377987da915Sopenharmony_ci */ 378987da915Sopenharmony_ci restore_ea_info(nai, 379987da915Sopenharmony_ci old_ea_info); 380987da915Sopenharmony_ci } 381987da915Sopenharmony_ci } else { 382987da915Sopenharmony_ci ntfs_log_error("Failed to remove the" 383987da915Sopenharmony_ci " EA_INFORMATION from inode %lld\n", 384987da915Sopenharmony_ci (long long)ni->mft_no); 385987da915Sopenharmony_ci } 386987da915Sopenharmony_ci free(old_ea_info); 387987da915Sopenharmony_ci ntfs_attr_close(na); 388987da915Sopenharmony_ci } else { 389987da915Sopenharmony_ci /* EA_INFORMATION present, but no EA */ 390987da915Sopenharmony_ci res = ntfs_attr_rm(nai); 391987da915Sopenharmony_ci NInoFileNameSetDirty(ni); 392987da915Sopenharmony_ci } 393987da915Sopenharmony_ci ntfs_attr_close(nai); 394987da915Sopenharmony_ci } else { 395987da915Sopenharmony_ci errno = ENODATA; 396987da915Sopenharmony_ci res = -1; 397987da915Sopenharmony_ci } 398987da915Sopenharmony_ci NInoSetDirty(ni); 399987da915Sopenharmony_ci } else { 400987da915Sopenharmony_ci errno = EINVAL; 401987da915Sopenharmony_ci res = -1; 402987da915Sopenharmony_ci } 403987da915Sopenharmony_ci return (res ? -1 : 0); 404987da915Sopenharmony_ci} 405987da915Sopenharmony_ci 406987da915Sopenharmony_ci/* 407987da915Sopenharmony_ci * Check for the presence of an EA "$LXDEV" (used by WSL) 408987da915Sopenharmony_ci * and return its value as a device address 409987da915Sopenharmony_ci * 410987da915Sopenharmony_ci * Returns zero if successful 411987da915Sopenharmony_ci * -1 if failed, with errno set 412987da915Sopenharmony_ci */ 413987da915Sopenharmony_ci 414987da915Sopenharmony_ciint ntfs_ea_check_wsldev(ntfs_inode *ni, dev_t *rdevp) 415987da915Sopenharmony_ci{ 416987da915Sopenharmony_ci const EA_ATTR *p_ea; 417987da915Sopenharmony_ci int bufsize; 418987da915Sopenharmony_ci char *buf; 419987da915Sopenharmony_ci int lth; 420987da915Sopenharmony_ci int res; 421987da915Sopenharmony_ci int offset; 422987da915Sopenharmony_ci int next; 423987da915Sopenharmony_ci BOOL found; 424987da915Sopenharmony_ci struct { 425987da915Sopenharmony_ci le32 major; 426987da915Sopenharmony_ci le32 minor; 427987da915Sopenharmony_ci } device; 428987da915Sopenharmony_ci 429987da915Sopenharmony_ci res = -EOPNOTSUPP; 430987da915Sopenharmony_ci bufsize = 256; /* expected to be enough */ 431987da915Sopenharmony_ci buf = (char*)malloc(bufsize); 432987da915Sopenharmony_ci if (buf) { 433987da915Sopenharmony_ci lth = ntfs_get_ntfs_ea(ni, buf, bufsize); 434987da915Sopenharmony_ci /* retry if short buf */ 435987da915Sopenharmony_ci if (lth > bufsize) { 436987da915Sopenharmony_ci free(buf); 437987da915Sopenharmony_ci bufsize = lth; 438987da915Sopenharmony_ci buf = (char*)malloc(bufsize); 439987da915Sopenharmony_ci if (buf) 440987da915Sopenharmony_ci lth = ntfs_get_ntfs_ea(ni, buf, bufsize); 441987da915Sopenharmony_ci } 442987da915Sopenharmony_ci } 443987da915Sopenharmony_ci if (buf && (lth > 0) && (lth <= bufsize)) { 444987da915Sopenharmony_ci offset = 0; 445987da915Sopenharmony_ci found = FALSE; 446987da915Sopenharmony_ci do { 447987da915Sopenharmony_ci p_ea = (const EA_ATTR*)&buf[offset]; 448987da915Sopenharmony_ci next = le32_to_cpu(p_ea->next_entry_offset); 449987da915Sopenharmony_ci found = ((next > (int)(sizeof(lxdev) + sizeof(device))) 450987da915Sopenharmony_ci && (p_ea->name_length == (sizeof(lxdev) - 1)) 451987da915Sopenharmony_ci && (p_ea->value_length 452987da915Sopenharmony_ci == const_cpu_to_le16(sizeof(device))) 453987da915Sopenharmony_ci && !memcmp(p_ea->name, lxdev, sizeof(lxdev))); 454987da915Sopenharmony_ci if (!found) 455987da915Sopenharmony_ci offset += next; 456987da915Sopenharmony_ci } while (!found && (next > 0) && (offset < lth)); 457987da915Sopenharmony_ci if (found) { 458987da915Sopenharmony_ci /* beware of alignment */ 459987da915Sopenharmony_ci memcpy(&device, &p_ea->name[p_ea->name_length + 1], 460987da915Sopenharmony_ci sizeof(device)); 461987da915Sopenharmony_ci *rdevp = makedev(le32_to_cpu(device.major), 462987da915Sopenharmony_ci le32_to_cpu(device.minor)); 463987da915Sopenharmony_ci res = 0; 464987da915Sopenharmony_ci } 465987da915Sopenharmony_ci } 466987da915Sopenharmony_ci free(buf); 467987da915Sopenharmony_ci return (res); 468987da915Sopenharmony_ci} 469987da915Sopenharmony_ci 470987da915Sopenharmony_ciint ntfs_ea_set_wsl_not_symlink(ntfs_inode *ni, mode_t type, dev_t dev) 471987da915Sopenharmony_ci{ 472987da915Sopenharmony_ci le32 mode; 473987da915Sopenharmony_ci struct { 474987da915Sopenharmony_ci le32 major; 475987da915Sopenharmony_ci le32 minor; 476987da915Sopenharmony_ci } device; 477987da915Sopenharmony_ci struct EA_WSL { 478987da915Sopenharmony_ci struct EA_LXMOD { /* always inserted */ 479987da915Sopenharmony_ci EA_ATTR base; 480987da915Sopenharmony_ci char name[sizeof(lxmod)]; 481987da915Sopenharmony_ci char value[sizeof(mode)]; 482987da915Sopenharmony_ci char stuff[3 & -(sizeof(lxmod) + sizeof(mode))]; 483987da915Sopenharmony_ci } mod; 484987da915Sopenharmony_ci struct EA_LXDEV { /* char or block devices only */ 485987da915Sopenharmony_ci EA_ATTR base; 486987da915Sopenharmony_ci char name[sizeof(lxdev)]; 487987da915Sopenharmony_ci char value[sizeof(device)]; 488987da915Sopenharmony_ci char stuff[3 & -(sizeof(lxdev) + sizeof(device))]; 489987da915Sopenharmony_ci } dev; 490987da915Sopenharmony_ci } attr; 491987da915Sopenharmony_ci int len; 492987da915Sopenharmony_ci int res; 493987da915Sopenharmony_ci 494987da915Sopenharmony_ci memset(&attr, 0, sizeof(attr)); 495987da915Sopenharmony_ci mode = cpu_to_le32((u32)(type | 0644)); 496987da915Sopenharmony_ci attr.mod.base.next_entry_offset 497987da915Sopenharmony_ci = const_cpu_to_le32(sizeof(attr.mod)); 498987da915Sopenharmony_ci attr.mod.base.flags = 0; 499987da915Sopenharmony_ci attr.mod.base.name_length = sizeof(lxmod) - 1; 500987da915Sopenharmony_ci attr.mod.base.value_length = const_cpu_to_le16(sizeof(mode)); 501987da915Sopenharmony_ci memcpy(attr.mod.name, lxmod, sizeof(lxmod)); 502987da915Sopenharmony_ci memcpy(attr.mod.value, &mode, sizeof(mode)); 503987da915Sopenharmony_ci len = sizeof(attr.mod); 504987da915Sopenharmony_ci 505987da915Sopenharmony_ci if (S_ISCHR(type) || S_ISBLK(type)) { 506987da915Sopenharmony_ci device.major = cpu_to_le32(major(dev)); 507987da915Sopenharmony_ci device.minor = cpu_to_le32(minor(dev)); 508987da915Sopenharmony_ci attr.dev.base.next_entry_offset 509987da915Sopenharmony_ci = const_cpu_to_le32(sizeof(attr.dev)); 510987da915Sopenharmony_ci attr.dev.base.flags = 0; 511987da915Sopenharmony_ci attr.dev.base.name_length = sizeof(lxdev) - 1; 512987da915Sopenharmony_ci attr.dev.base.value_length = const_cpu_to_le16(sizeof(device)); 513987da915Sopenharmony_ci memcpy(attr.dev.name, lxdev, sizeof(lxdev)); 514987da915Sopenharmony_ci memcpy(attr.dev.value, &device, sizeof(device)); 515987da915Sopenharmony_ci len += sizeof(attr.dev); 516987da915Sopenharmony_ci } 517987da915Sopenharmony_ci res = ntfs_set_ntfs_ea(ni, (char*)&attr, len, 0); 518987da915Sopenharmony_ci return (res); 519987da915Sopenharmony_ci} 520