From 4a671e56e9e8448e8f11b1dd4654780cdad0ad4f Mon Sep 17 00:00:00 2001 From: franklahm Date: Thu, 10 Dec 2009 17:40:25 +0000 Subject: [PATCH] Add support for ea:ad volumes --- etc/cnid_dbd/cmd_dbd_scanvol.c | 213 +++++++++++++++++++++++++--- include/atalk/ea.h | 10 +- libatalk/vfs/ea.c | 250 ++++++++++++++++++--------------- 3 files changed, 337 insertions(+), 136 deletions(-) diff --git a/etc/cnid_dbd/cmd_dbd_scanvol.c b/etc/cnid_dbd/cmd_dbd_scanvol.c index 3addca9f..db3dfefc 100644 --- a/etc/cnid_dbd/cmd_dbd_scanvol.c +++ b/etc/cnid_dbd/cmd_dbd_scanvol.c @@ -1,5 +1,5 @@ /* - $Id: cmd_dbd_scanvol.c,v 1.13 2009-12-09 15:25:28 franklahm Exp $ + $Id: cmd_dbd_scanvol.c,v 1.14 2009-12-10 17:40:25 franklahm Exp $ Copyright (c) 2009 Frank Lahm @@ -27,10 +27,15 @@ #include #include #include + #include #include #include #include +#include +#include +#include + #include "cmd_dbd.h" #include "dbif.h" #include "db_param.h" @@ -57,6 +62,8 @@ static char *netatalk_dirs[] = { static struct cnid_dbd_rqst rqst; static struct cnid_dbd_rply rply; static jmp_buf jmp; +static struct vol volume; /* fake it for ea_open */ +static char pname[MAXPATHLEN] = "../"; /* Taken form afpd/desktop.c @@ -245,6 +252,104 @@ static int check_adfile(const char *fname, const struct stat *st) return 0; } +/* + Remove all files with file::EA* from adouble dir +*/ +static void remove_eafiles(const char *name, struct ea *ea) +{ + DIR *dp = NULL; + struct dirent *ep; + char eaname[MAXPATHLEN]; + + strlcpy(eaname, name, sizeof(eaname)); + if (strlcat(eaname, "::EA", sizeof(eaname)) >= sizeof(eaname)) { + dbd_log(LOGSTD, "name too long: '%s/%s/%s'", cwdbuf, ADv2_DIRNAME, name); + return; + } + + if ((chdir(ADv2_DIRNAME)) != 0) { + dbd_log(LOGSTD, "Couldn't chdir to '%s/%s': %s", + cwdbuf, ADv2_DIRNAME, strerror(errno)); + return; + } + + if ((dp = opendir(".")) == NULL) { + dbd_log(LOGSTD, "Couldn't open the directory '%s/%s': %s", + cwdbuf, ADv2_DIRNAME, strerror(errno)); + return; + } + + while ((ep = readdir(dp))) { + if (strstr(ep->d_name, eaname) != NULL) { + dbd_log(LOGSTD, "Removing EA file: '%s/%s/%s'", + cwdbuf, ADv2_DIRNAME, ep->d_name); + if ((unlink(ep->d_name)) != 0) { + dbd_log(LOGSTD, "Error unlinking EA file '%s/%s/%s': %s", + cwdbuf, ADv2_DIRNAME, ep->d_name, strerror(errno)); + } + } /* if */ + } /* while */ + + if (dp) + closedir(dp); + +} + +/* + Check Extended Attributes files +*/ +static int check_eafiles(const char *fname) +{ + unsigned int count = 0; + int ret = 0, remove; + struct ea ea; + struct stat st; + char *eaname; + + if ((ret = ea_open(&volume, fname, EA_RDWR, &ea)) != 0) { + if (errno == ENOENT) + return 0; + dbd_log(LOGSTD, "Error calling ea_open for file: %s/%s, removing EA files", + cwdbuf, fname); + if ( ! (dbd_flags & DBD_FLAGS_SCAN)) + remove_eafiles(fname, &ea); + return -1; + } + + /* Check all EAs */ + while (count < ea.ea_count) { + dbd_log(LOGDEBUG, "EA: %s", (*ea.ea_entries)[count].ea_name); + remove = 0; + + eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name, 0); + + if (stat(eaname, &st) != 0) { + if (errno == ENOENT) + dbd_log(LOGSTD, "Missing EA: %s/%s", cwdbuf, eaname); + else + dbd_log(LOGSTD, "Bogus EA: %s/%s", cwdbuf, eaname); + remove = 1; + } else if (st.st_size != (*ea.ea_entries)[count].ea_size) { + dbd_log(LOGSTD, "Bogus EA: %s/%s, removing it...", cwdbuf, eaname); + remove = 1; + if ((unlink(eaname)) != 0) + dbd_log(LOGSTD, "Error removing EA file '%s/%s': %s", + cwdbuf, eaname, strerror(errno)); + } + + if (remove) { + /* Be CAREFUL here! This should do what ea_delentry does. ea_close relies on it !*/ + free((*ea.ea_entries)[count].ea_name); + (*ea.ea_entries)[count].ea_name = NULL; + } + + count++; + } /* while */ + + ea_close(&ea); + return ret; +} + /* Check for .AppleDouble folder and .Parent, create if missing */ @@ -253,8 +358,8 @@ static int check_addir(int volroot) int addir_ok, adpar_ok; struct stat st; struct adouble ad; - char *mname; - + char *mname = NULL; + /* Check for ad-dir */ if ( (addir_ok = access(ADv2_DIRNAME, F_OK)) != 0) { if (errno != ENOENT) { @@ -295,7 +400,7 @@ static int check_addir(int volroot) } /* Get basename of cwd from cwdbuf */ - utompath(strrchr(cwdbuf, '/') + 1); + mname = utompath(strrchr(cwdbuf, '/') + 1); /* Update name in ad file */ ad_setname(&ad, mname); @@ -314,7 +419,67 @@ static int check_addir(int volroot) return 0; } -/* +/* + Check if file cotains "::EA" and if it does check if its correspondig data fork exists. + Returns: + 0 = name is not an EA file + 1 = name is an EA file and no problem was found + -1 = name is an EA file and data fork is gone + */ +static int check_eafile_in_adouble(const char *name) +{ + int ret = 0; + char *namep, *namedup = NULL; + + /* Check if this is an AFPVOL_EA_AD vol */ + if (volinfo->v_vfs_ea == AFPVOL_EA_AD) { + /* Does the filename contain "::EA" ? */ + namedup = strdup(name); + if ((namep = strstr(namedup, "::EA")) == NULL) { + ret = 0; + goto ea_check_done; + } else { + /* File contains "::EA" so it's an EA file. Check for data file */ + + /* Get string before "::EA" from EA filename */ + namep[0] = 0; + strlcpy(pname + 3, namedup, sizeof(pname)); /* Prepends "../" */ + + if ((access( pname, F_OK)) == 0) { + ret = 1; + goto ea_check_done; + } else { + ret = -1; + if (errno != ENOENT) { + dbd_log(LOGSTD, "Access error for file '%s/%s': %s", + cwdbuf, name, strerror(errno)); + goto ea_check_done; + } + + /* Orphaned EA file*/ + dbd_log(LOGSTD, "Orphaned Extended Attribute file '%s/%s/%s'", + cwdbuf, ADv2_DIRNAME, name); + + if (dbd_flags & DBD_FLAGS_SCAN) + /* Scan only requested, dont change anything */ + goto ea_check_done; + + if ((unlink(name)) != 0) { + dbd_log(LOGSTD, "Error unlinking orphaned Extended Attribute file '%s/%s/%s'", + cwdbuf, ADv2_DIRNAME, name); + } + } /* if (access) */ + } /* if strstr */ + } /* if AFPVOL_EA_AD */ + +ea_check_done: + if (namedup) + free(namedup); + + return ret; +} + +/* Check files and dirs inside .AppleDouble folder: - remove orphaned files - bail on dirs @@ -324,7 +489,6 @@ static int read_addir(void) DIR *dp; struct dirent *ep; struct stat st; - static char fname[MAXPATHLEN] = "../"; if ((chdir(ADv2_DIRNAME)) != 0) { dbd_log(LOGSTD, "Couldn't chdir to '%s/%s': %s", @@ -359,12 +523,16 @@ static int read_addir(void) continue; } + /* Check if for orphaned and corrupt Extended Attributes file */ + if (check_eafile_in_adouble(ep->d_name) != 0) + continue; + /* Check for data file */ - strcpy(fname+3, ep->d_name); - if ((access( fname, F_OK)) != 0) { + strcpy(pname + 3, ep->d_name); + if ((access( pname, F_OK)) != 0) { if (errno != ENOENT) { dbd_log(LOGSTD, "Access error for file '%s/%s': %s", - cwdbuf, ep->d_name, strerror(errno)); + cwdbuf, pname, strerror(errno)); continue; } /* Orphaned ad-file*/ @@ -395,9 +563,9 @@ static int read_addir(void) return 0; } -/* - Check CNID for a file/dir, both from db and from ad-file. - For detailed specs see intro. +/* + Check CNID for a file/dir, both from db and from ad-file. + For detailed specs see intro. */ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfile_ok, int adflags) { @@ -421,7 +589,7 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi ad_flush(&ad); } else - ad_cnid = ad_getid(&ad, st->st_dev, st->st_ino, did, stamp); + ad_cnid = ad_getid(&ad, st->st_dev, st->st_ino, did, stamp); if (ad_cnid == 0) dbd_log( LOGSTD, "Incorrect CNID data in .AppleDouble data for '%s/%s' (bad stamp?)", cwdbuf, name); @@ -499,7 +667,7 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi dbd_log( LOGSTD, "New CNID for '%s/%s': %u", cwdbuf, name, ntohl(db_cnid)); } } - + if ((ad_cnid == 0) && db_cnid) { /* in db but zeroID in ad-file, write it to ad-file if AFPVOL_CACHE */ if ((volinfo->v_flags & AFPVOL_CACHE) && ADFILE_OK) { @@ -615,6 +783,10 @@ static int dbd_readdir(int volroot, cnid_t did) } } + /* Check EA files */ + if (volinfo->v_vfs_ea == AFPVOL_EA_AD) + check_eafiles(ep->d_name); + /************************************************************************** Recursion **************************************************************************/ @@ -662,6 +834,11 @@ static int scanvol(struct volinfo *vi, dbd_flags_t flags) volinfo = vi; dbd_flags = flags; + /* Init a fake struct vol with just enough so we can call ea_open and friends */ + volume.v_adouble = AD_VERSION2; + volume.v_vfs_ea = volinfo->v_vfs_ea; + initvol_vfs(&volume); + /* Run with umask 0 */ umask(0); @@ -678,8 +855,8 @@ static int scanvol(struct volinfo *vi, dbd_flags_t flags) return 0; } -/* - Remove all CNIDs from dbd that are not in dbd_rebuild +/* + Remove all CNIDs from dbd that are not in dbd_rebuild */ static void delete_orphaned_cnids(DBD *dbd, DBD *dbd_rebuild, dbd_flags_t flags) { @@ -801,8 +978,8 @@ int cmd_dbd_scanvol(DBD *dbd_ref, struct volinfo *volinfo, dbd_flags_t flags) return -1; if (! nocniddb) { - /* We can only do this in exclusive mode, otherwise we might delete CNIDs added from - other clients in between our pass 1 and 2 */ + /* We can only do this in exclusive mode, otherwise we might delete CNIDs added from + other clients in between our pass 1 and 2 */ if (flags & DBD_FLAGS_EXCL) delete_orphaned_cnids(dbd, dbd_rebuild, flags); } diff --git a/include/atalk/ea.h b/include/atalk/ea.h index 4d47a0d3..48432ef6 100644 --- a/include/atalk/ea.h +++ b/include/atalk/ea.h @@ -1,5 +1,5 @@ /* - $Id: ea.h,v 1.9 2009-11-18 11:14:59 didg Exp $ + $Id: ea.h,v 1.10 2009-12-10 17:40:25 franklahm Exp $ Copyright (c) 2009 Frank Lahm This program is free software; you can redistribute it and/or modify @@ -149,4 +149,12 @@ extern int sys_remove_ea(VFS_FUNC_ARGS_EA_REMOVE); /* native EA VFSfile/dir cp/mv/rm */ extern int sys_ea_copyfile(VFS_FUNC_ARGS_COPYFILE); +/* dbd needs access to these */ +extern int ea_open(const struct vol * restrict vol, + const char * restrict uname, + eaflags_t eaflags, + struct ea * restrict ea); +extern int ea_close(struct ea * restrict ea); +extern char *ea_path(const struct ea * restrict ea, const char * restrict eaname, int macname); + #endif /* ATALK_EA_H */ diff --git a/libatalk/vfs/ea.c b/libatalk/vfs/ea.c index 89ffc90f..8d1a1f0d 100644 --- a/libatalk/vfs/ea.c +++ b/libatalk/vfs/ea.c @@ -1,5 +1,5 @@ /* - $Id: ea.c,v 1.17 2009-12-04 10:26:10 franklahm Exp $ + $Id: ea.c,v 1.18 2009-12-10 17:40:25 franklahm Exp $ Copyright (c) 2009 Frank Lahm This program is free software; you can redistribute it and/or modify @@ -275,48 +275,6 @@ static int pack_header(struct ea * restrict ea) return 0; } -/* - * Function: ea_path - * - * Purpose: return name of ea header filename - * - * Arguments: - * - * ea (r) ea handle - * eaname (r) name of EA or NULL - * - * Returns: pointer to name in static buffer, NULL on error - * - * Effects: - * - * Calls ad_open, copies buffer, appends "::EA" and if supplied append eanme - * Files: "file" -> "file/.AppleDouble/file::EA" - * Dirs: "dir" -> "dir/.AppleDouble/.Parent::EA" - * "file" with EA "myEA" -> "file/.AppleDouble/file::EA:myEA" - */ -static char * ea_path(const struct ea * restrict ea, - const char * restrict eaname) -{ - char *adname; - static char pathbuf[MAXPATHLEN + 1]; - - /* get name of a adouble file from uname */ - adname = ea->vol->ad_path(ea->filename, (ea->ea_flags & EA_DIR) ? ADFLAGS_DIR : 0); - /* copy it so we can work with it */ - strlcpy(pathbuf, adname, MAXPATHLEN + 1); - /* append "::EA" */ - strlcat(pathbuf, "::EA", MAXPATHLEN + 1); - - if (eaname) { - strlcat(pathbuf, "::", MAXPATHLEN + 1); - if ((eaname = mtoupath(ea->vol, eaname)) == NULL) - return NULL; - strlcat(pathbuf, eaname, MAXPATHLEN + 1); - } - - return pathbuf; -} - /* * Function: ea_addentry * @@ -398,52 +356,6 @@ error: return -1; } -/* - * Function: ea_delentry - * - * Purpose: delete one EA from ea->ea_entries[] - * - * Arguments: - * - * ea (rw) pointer to struct ea - * attruname (r) EA name - * - * Returns: new number of EA entries, -1 on error - * - * Effects: - * - * Remove entry from ea->ea_entries[]. Decrement ea->ea_count. - * Marks it as unused just by freeing name and setting it to NULL. - * ea_close and pack_buffer must honor this. - */ -static int ea_delentry(struct ea * restrict ea, - const char * restrict attruname) -{ - int ret = 0; - unsigned int count = 0; - - if (ea->ea_count == 0) { - LOG(log_error, logtype_afpd, "ea_delentry('%s'): illegal ea_count of 0 on deletion"); - return -1; - } - - while (count < ea->ea_count) { - /* search matching EA */ - if (strcmp(attruname, (*ea->ea_entries)[count].ea_name) == 0) { - free((*ea->ea_entries)[count].ea_name); - (*ea->ea_entries)[count].ea_name = NULL; - - LOG(log_debug, logtype_afpd, "ea_delentry('%s'): deleted no %u/%u", - attruname, count + 1, ea->ea_count); - - break; - } - count++; - } - - return ret; -} - /* * Function: create_ea_header * @@ -534,7 +446,7 @@ static int write_ea(const struct ea * restrict ea, struct stat st; char *eaname; - if ((eaname = ea_path(ea, attruname)) == NULL) { + if ((eaname = ea_path(ea, attruname, 1)) == NULL) { LOG(log_error, logtype_afpd, "write_ea('%s'): ea_path error", attruname); return AFPERR_MISC; } @@ -575,6 +487,51 @@ exit: return ret; } +/* + * Function: ea_delentry + * + * Purpose: delete one EA from ea->ea_entries[] + * + * Arguments: + * + * ea (rw) pointer to struct ea + * attruname (r) EA name + * + * Returns: new number of EA entries, -1 on error + * + * Effects: + * + * Remove entry from ea->ea_entries[]. Decrement ea->ea_count. + * Marks it as unused just by freeing name and setting it to NULL. + * ea_close and pack_buffer must honor this. + */ +static int ea_delentry(struct ea * restrict ea, const char * restrict attruname) +{ + int ret = 0; + unsigned int count = 0; + + if (ea->ea_count == 0) { + LOG(log_error, logtype_afpd, "ea_delentry('%s'): illegal ea_count of 0 on deletion"); + return -1; + } + + while (count < ea->ea_count) { + /* search matching EA */ + if (strcmp(attruname, (*ea->ea_entries)[count].ea_name) == 0) { + free((*ea->ea_entries)[count].ea_name); + (*ea->ea_entries)[count].ea_name = NULL; + + LOG(log_debug, logtype_afpd, "ea_delentry('%s'): deleted no %u/%u", + attruname, count + 1, ea->ea_count); + + break; + } + count++; + } + + return ret; +} + /* * Function: delete_ea_file * @@ -587,14 +544,13 @@ exit: * * Returns: 0 on success, -1 on error */ -static int delete_ea_file(const struct ea * restrict ea, - const char *eaname) +static int delete_ea_file(const struct ea * restrict ea, const char *eaname) { int ret = 0; char *eafile; struct stat st; - if ((eafile = ea_path(ea, eaname)) == NULL) { + if ((eafile = ea_path(ea, eaname, 1)) == NULL) { LOG(log_error, logtype_afpd, "delete_ea_file('%s'): ea_path error", eaname); return -1; } @@ -612,6 +568,53 @@ static int delete_ea_file(const struct ea * restrict ea, return ret; } +/************************************************************************************* + * ea_path, ea_open and ea_close are only global so that dbd can call them + *************************************************************************************/ + +/* + * Function: ea_path + * + * Purpose: return name of ea header filename + * + * Arguments: + * + * ea (r) ea handle + * eaname (r) name of EA or NULL + * macname (r) if != 0 call mtoupath on eaname + * + * Returns: pointer to name in static buffer, NULL on error + * + * Effects: + * + * Calls ad_open, copies buffer, appends "::EA" and if supplied append eanme + * Files: "file" -> "file/.AppleDouble/file::EA" + * Dirs: "dir" -> "dir/.AppleDouble/.Parent::EA" + * "file" with EA "myEA" -> "file/.AppleDouble/file::EA:myEA" + */ +char *ea_path(const struct ea * restrict ea, const char * restrict eaname, int macname) +{ + char *adname; + static char pathbuf[MAXPATHLEN + 1]; + + /* get name of a adouble file from uname */ + adname = ea->vol->ad_path(ea->filename, (ea->ea_flags & EA_DIR) ? ADFLAGS_DIR : 0); + /* copy it so we can work with it */ + strlcpy(pathbuf, adname, MAXPATHLEN + 1); + /* append "::EA" */ + strlcat(pathbuf, "::EA", MAXPATHLEN + 1); + + if (eaname) { + strlcat(pathbuf, "::", MAXPATHLEN + 1); + if (macname) + if ((eaname = mtoupath(ea->vol, eaname)) == NULL) + return NULL; + strlcat(pathbuf, eaname, MAXPATHLEN + 1); + } + + return pathbuf; +} + /* * Function: ea_open * @@ -627,7 +630,9 @@ static int delete_ea_file(const struct ea * restrict ea, * Eiterh EA_RDONLY or EA_RDWR MUST be requested * ea (w) pointer to a struct ea that we fill * - * Returns: 0 on success, -1 on error + * Returns: 0 on success + * -1 on misc error with errno = EFAULT + * -2 if no EA header exists with errno = ENOENT * * Effects: * @@ -636,10 +641,10 @@ static int delete_ea_file(const struct ea * restrict ea, * file is either read or write locked depending on the open flags. * When you're done with struct ea you must call ea_close on it. */ -static int ea_open(const struct vol * restrict vol, - const char * restrict uname, - eaflags_t eaflags, - struct ea * restrict ea) +int ea_open(const struct vol * restrict vol, + const char * restrict uname, + eaflags_t eaflags, + struct ea * restrict ea) { int ret = 0; char *eaname; @@ -665,7 +670,7 @@ static int ea_open(const struct vol * restrict vol, return -1; } - eaname = ea_path(ea, NULL); + eaname = ea_path(ea, NULL, 0); LOG(log_maxdebug, logtype_afpd, "ea_open: ea_path: %s", eaname); /* Check if it exists, if not create it if EA_CREATE is in eaflags */ @@ -676,7 +681,7 @@ static int ea_open(const struct vol * restrict vol, if ( ! (eaflags & EA_CREATE)) { /* creation was not requested, so return with error */ - ret = -1; + ret = -2; goto exit; } @@ -708,6 +713,11 @@ static int ea_open(const struct vol * restrict vol, /* header file exists, so read and parse it */ /* malloc buffer where we read disk file into */ + if (st.st_size < EA_HEADER_SIZE) { + LOG(log_error, logtype_afpd, "ea_open('%s'): bogus EA header file", eaname); + ret = -1; + goto exit; + } ea->ea_size = st.st_size; ea->ea_data = malloc(st.st_size); if (! ea->ea_data) { @@ -754,9 +764,14 @@ static int ea_open(const struct vol * restrict vol, } exit: - if (ret == 0) { + switch (ret) { + case 0: ea->ea_inited = EA_INITED; - } else { + break; + case -1: + errno = EFAULT; /* force some errno distinguishable from ENOENT */ + /* fall through */ + case -2: if (ea->ea_data) { free(ea->ea_data); ea->ea_data = NULL; @@ -765,6 +780,7 @@ exit: close(ea->ea_fd); ea->ea_fd = -1; } + break; } return ret; @@ -786,7 +802,7 @@ exit: * Flushes and then closes and frees all resouces held by ea handle. * Pack data in ea into ea_data, then write ea_data to disk */ -static int ea_close(struct ea * restrict ea) +int ea_close(struct ea * restrict ea) { int ret = 0; unsigned int count = 0; @@ -808,7 +824,7 @@ static int ea_close(struct ea * restrict ea) } else { if (ea->ea_count == 0) { /* Check if EA header exists and remove it */ - eaname = ea_path(ea, NULL); + eaname = ea_path(ea, NULL, 0); if ((stat(eaname, &st)) == 0) { if ((unlink(eaname)) != 0) { LOG(log_error, logtype_afpd, "ea_close('%s'): unlink: %s", @@ -987,7 +1003,7 @@ int get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT) while (count < ea.ea_count) { if (strcmp(attruname, (*ea.ea_entries)[count].ea_name) == 0) { - if ( (eafile = ea_path(&ea, attruname)) == NULL) { + if ( (eafile = ea_path(&ea, attruname, 1)) == NULL) { ret = AFPERR_MISC; break; } @@ -1312,12 +1328,12 @@ int ea_renamefile(VFS_FUNC_ARGS_RENAMEFILE) easize = (*srcea.ea_entries)[count].ea_size; /* Build src and dst paths for rename() */ - if ((eapath = ea_path(&srcea, eaname)) == NULL) { + if ((eapath = ea_path(&srcea, eaname, 1)) == NULL) { ret = AFPERR_MISC; goto exit; } strcpy(srceapath, eapath); - if ((eapath = ea_path(&dstea, eaname)) == NULL) { + if ((eapath = ea_path(&dstea, eaname, 1)) == NULL) { ret = AFPERR_MISC; goto exit; } @@ -1409,12 +1425,12 @@ int ea_copyfile(VFS_FUNC_ARGS_COPYFILE) easize = (*srcea.ea_entries)[count].ea_size; /* Build src and dst paths for copy_file() */ - if ((eapath = ea_path(&srcea, eaname)) == NULL) { + if ((eapath = ea_path(&srcea, eaname, 1)) == NULL) { ret = AFPERR_MISC; goto exit; } strcpy(srceapath, eapath); - if ((eapath = ea_path(&dstea, eaname)) == NULL) { + if ((eapath = ea_path(&dstea, eaname, 1)) == NULL) { ret = AFPERR_MISC; goto exit; } @@ -1467,7 +1483,7 @@ int ea_chown(VFS_FUNC_ARGS_CHOWN) } } - if ((chown(ea_path(&ea, NULL), uid, gid)) != 0) { + if ((chown(ea_path(&ea, NULL, 0), uid, gid)) != 0) { switch (errno) { case EPERM: case EACCES: @@ -1480,7 +1496,7 @@ int ea_chown(VFS_FUNC_ARGS_CHOWN) } while (count < ea.ea_count) { - if ((eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name)) == NULL) { + if ((eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name, 1)) == NULL) { ret = AFPERR_MISC; goto exit; } @@ -1528,8 +1544,8 @@ int ea_chmod_file(VFS_FUNC_ARGS_SETFILEMODE) } /* Set mode on EA header file */ - if ((setfilmode(ea_path(&ea, NULL), ea_header_mode(mode), NULL, vol->v_umask)) != 0) { - LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): %s", ea_path(&ea, NULL), strerror(errno)); + if ((setfilmode(ea_path(&ea, NULL, 0), ea_header_mode(mode), NULL, vol->v_umask)) != 0) { + LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): %s", ea_path(&ea, NULL, 0), strerror(errno)); switch (errno) { case EPERM: case EACCES: @@ -1543,7 +1559,7 @@ int ea_chmod_file(VFS_FUNC_ARGS_SETFILEMODE) /* Set mode on EA files */ while (count < ea.ea_count) { - if ((eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name)) == NULL) { + if ((eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name, 1)) == NULL) { ret = AFPERR_MISC; goto exit; } @@ -1604,8 +1620,8 @@ int ea_chmod_dir(VFS_FUNC_ARGS_SETDIRUNIXMODE) } /* Set mode on EA header */ - if ((setfilmode(ea_path(&ea, NULL), ea_header_mode(mode), NULL, vol->v_umask)) != 0) { - LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): %s", ea_path(&ea, NULL), strerror(errno)); + if ((setfilmode(ea_path(&ea, NULL, 0), ea_header_mode(mode), NULL, vol->v_umask)) != 0) { + LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): %s", ea_path(&ea, NULL, 0), strerror(errno)); switch (errno) { case EPERM: case EACCES: @@ -1630,7 +1646,7 @@ int ea_chmod_dir(VFS_FUNC_ARGS_SETDIRUNIXMODE) LOG(log_warning, logtype_afpd, "ea_chmod_dir('%s'): contains a slash", eaname); eaname = eaname_safe; } - if ((eaname = ea_path(&ea, eaname)) == NULL) { + if ((eaname = ea_path(&ea, eaname, 1)) == NULL) { ret = AFPERR_MISC; goto exit; } -- 2.39.2