/* * Function: sys_ea_copyfile * * Purpose: copy EAs * * Arguments: * * vol (r) current volume * sdf (r) source file descriptor * src (r) source path * dst (r) destination path * * Return AFP code AFP_OK on success or appropriate AFP error code * * Effects: * * Copies EAs from source file to dest file. */ int sys_ea_copyfile(VFS_FUNC_ARGS_COPYFILE) { int ret = 0; int cwd = -1; ssize_t size; char *names = NULL, *end_names, *name, *value = NULL; unsigned int setxattr_ENOTSUP = 0; if (sfd != -1) { if ((cwd = open(".", O_RDONLY)) == -1) { LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant open cwd: %s", strerror(errno)); ret = -1; goto getout; } } if (sfd != -1) { if (fchdir(sfd) == -1) { LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant chdir to sfd: %s", strerror(errno)); ret = -1; goto getout; } } size = sys_listxattr(src, NULL, 0); if (size < 0) { if (errno != ENOSYS && errno != ENOTSUP) { ret = -1; } goto getout; } names = malloc(size+1); if (names == NULL) { ret = -1; goto getout; } size = sys_listxattr(src, names, size); if (size < 0) { ret = -1; goto getout; } else { names[size] = '\0'; end_names = names + size; } if (sfd != -1) { if (fchdir(cwd) == -1) { LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant chdir to cwd: %s", strerror(errno)); ret = -1; goto getout; } } for (name = names; name != end_names; name = strchr(name, '\0') + 1) { void *old_value; /* check if this attribute shall be preserved */ if (!*name) continue; if (STRCMP(name, ==, AD_EA_META)) continue; if (sfd != -1) { if (fchdir(sfd) == -1) { LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant chdir to sfd: %s", strerror(errno)); ret = -1; goto getout; } } size = sys_getxattr (src, name, NULL, 0); if (size < 0) { ret = -1; continue; } value = realloc(old_value = value, size); if (size != 0 && value == NULL) { free(old_value); ret = -1; } size = sys_getxattr(src, name, value, size); if (size < 0) { ret = -1; continue; } if (sfd != -1) { if (fchdir(cwd) == -1) { LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant chdir to cwd: %s", strerror(errno)); ret = -1; goto getout; } } if (sys_setxattr(dst, name, value, size, 0) != 0) { if (errno == ENOTSUP) setxattr_ENOTSUP++; else { if (errno == ENOSYS) { ret = -1; /* no hope of getting any further */ break; } else { ret = -1; } } } } if (setxattr_ENOTSUP) { errno = ENOTSUP; ret = -1; } getout: if (cwd != -1) close(cwd); free(value); free(names); if (ret == -1) { switch(errno) { case ENOENT: /* no attribute */ break; case EACCES: LOG(log_debug, logtype_afpd, "sys_ea_copyfile(%s, %s): error: %s", src, dst, strerror(errno)); return AFPERR_ACCESS; default: LOG(log_error, logtype_afpd, "sys_ea_copyfile(%s, %s): error: %s", src, dst, strerror(errno)); return AFPERR_MISC; } } return AFP_OK; }
/* * Function: sys_list_eas * * Purpose: copy names of native EAs into attrnamebuf * * Arguments: * * vol (r) current volume * attrnamebuf (w) store names a consecutive C strings here * buflen (rw) length of names in attrnamebuf * uname (r) filename * oflag (r) link and create flag * * Returns: AFP code: AFP_OK on success or appropiate AFP error code * * Effects: * * Copies names of all EAs of uname as consecutive C strings into rbuf. * Increments *rbuflen accordingly. * We hide the adouble:ea extended attributes here, but we currently * allow reading, writing and deleteting them. */ int sys_list_eas(VFS_FUNC_ARGS_EA_LIST) { ssize_t attrbuflen = *buflen; int ret, len, nlen; char *buf; char *ptr; struct adouble ad, *adp; buf = malloc(ATTRNAMEBUFSIZ); if (!buf) return AFPERR_MISC; /* PBaranski fix */ if ( fd != -1) { LOG(log_debug, logtype_afpd, "sys_list_eas(%s): file is already opened", uname); ret = sys_flistxattr(fd, uname, buf, ATTRNAMEBUFSIZ); } else { if ((oflag & O_NOFOLLOW)) { ret = sys_llistxattr(uname, buf, ATTRNAMEBUFSIZ); } else { ret = sys_listxattr(uname, buf, ATTRNAMEBUFSIZ); } } /* PBaranski fix */ if (ret == -1) switch(errno) { case OPEN_NOFOLLOW_ERRNO: /* its a symlink and client requested O_NOFOLLOW, we pretend 0 EAs */ LOG(log_debug, logtype_afpd, "sys_list_extattr(%s): symlink with kXAttrNoFollow", uname); ret = AFP_OK; goto exit; default: LOG(log_debug, logtype_afpd, "sys_list_extattr(%s): error opening atttribute dir: %s", uname, strerror(errno)); ret = AFPERR_MISC; goto exit; } ptr = buf; while (ret > 0) { len = strlen(ptr); if (NOT_NETATALK_EA(ptr)) { /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */ if ( 0 >= ( nlen = convert_string(vol->v_volcharset, CH_UTF8_MAC, ptr, len, attrnamebuf + attrbuflen, 256)) ) { ret = AFPERR_MISC; goto exit; } LOG(log_debug7, logtype_afpd, "sys_list_extattr(%s): attribute: %s", uname, ptr); attrbuflen += nlen + 1; if (attrbuflen > (ATTRNAMEBUFSIZ - 256)) { /* Next EA name could overflow, so bail out with error. FIXME: evantually malloc/memcpy/realloc whatever. Is it worth it ? */ LOG(log_warning, logtype_afpd, "sys_list_extattr(%s): running out of buffer for EA names", uname); ret = AFPERR_MISC; goto exit; } } ret -= len + 1; ptr += len + 1; } ret = AFP_OK; exit: free(buf); *buflen = attrbuflen; return ret; }
static ssize_t vfswrap_listxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size) { return sys_listxattr(path, list, size); }
ssize_t vfswrap_listxattr(struct vfs_handle_struct *handle, struct connection_struct *conn,const char *path, char *list, size_t size) { return sys_listxattr(path, list, size); }
/* * Function: sys_list_eas * * Purpose: copy names of native EAs into attrnamebuf * * Arguments: * * vol (r) current volume * attrnamebuf (w) store names a consecutive C strings here * buflen (rw) length of names in attrnamebuf * uname (r) filename * oflag (r) link and create flag * * Returns: AFP code: AFP_OK on success or appropiate AFP error code * * Effects: * * Copies names of all EAs of uname as consecutive C strings into rbuf. * Increments *rbuflen accordingly. */ int sys_list_eas(VFS_FUNC_ARGS_EA_LIST) { ssize_t attrbuflen = *buflen; int ret, len, nlen; char *buf; char *ptr; buf = malloc(ATTRNAMEBUFSIZ); if (!buf) return AFPERR_MISC; if ((oflag & O_NOFOLLOW)) { ret = sys_llistxattr(uname, buf, ATTRNAMEBUFSIZ); } else { ret = sys_listxattr(uname, buf, ATTRNAMEBUFSIZ); } if (ret == -1) switch(errno) { case OPEN_NOFOLLOW_ERRNO: /* its a symlink and client requested O_NOFOLLOW */ ret = AFPERR_BADTYPE; goto exit; #ifdef HAVE_ATTROPEN /* Solaris */ case ENOATTR: ret = AFP_OK; goto exit; #endif default: LOG(log_error, logtype_afpd, "sys_list_extattr(%s): error opening atttribute dir: %s", uname, strerror(errno)); ret= AFPERR_MISC; goto exit; } ptr = buf; while (ret > 0) { len = strlen(ptr); /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */ if ( 0 >= ( nlen = convert_string(vol->v_volcharset, CH_UTF8_MAC, ptr, len, attrnamebuf + attrbuflen, 256)) ) { ret = AFPERR_MISC; goto exit; } LOG(log_debug7, logtype_afpd, "sys_list_extattr(%s): attribute: %s", uname, ptr); attrbuflen += nlen + 1; if (attrbuflen > (ATTRNAMEBUFSIZ - 256)) { /* Next EA name could overflow, so bail out with error. FIXME: evantually malloc/memcpy/realloc whatever. Is it worth it ? */ LOG(log_warning, logtype_afpd, "sys_list_extattr(%s): running out of buffer for EA names", uname); ret = AFPERR_MISC; goto exit; } ret -= len +1; ptr += len +1; } ret = AFP_OK; exit: free(buf); *buflen = attrbuflen; return ret; }