/* * Function: sys_get_easize * * Purpose: get size of a native EA * * Arguments: * * vol (r) current volume * rbuf (w) DSI reply buffer * rbuflen (rw) current length of data in reply buffer * uname (r) filename * oflag (r) link and create flag * attruname (r) name of attribute * * Returns: AFP code: AFP_OK on success or appropiate AFP error code * * Effects: * * Copies EA size into rbuf in network order. Increments *rbuflen +4. */ int sys_get_easize(VFS_FUNC_ARGS_EA_GETSIZE) { ssize_t ret; uint32_t attrsize; LOG(log_debug7, logtype_afpd, "sys_getextattr_size(%s): attribute: \"%s\"", uname, attruname); if ((oflag & O_NOFOLLOW) ) { ret = sys_lgetxattr(uname, attruname, rbuf +4, 0); } else { ret = sys_getxattr(uname, attruname, rbuf +4, 0); } if (ret == -1) { memset(rbuf, 0, 4); *rbuflen += 4; switch(errno) { case OPEN_NOFOLLOW_ERRNO: /* its a symlink and client requested O_NOFOLLOW */ LOG(log_debug, logtype_afpd, "sys_getextattr_size(%s): symlink with kXAttrNoFollow", uname); return AFPERR_MISC; case ENOATTR: case ENOENT: return AFPERR_MISC; default: LOG(log_debug, logtype_afpd, "sys_getextattr_size: error: %s", strerror(errno)); return AFPERR_MISC; } } if (ret > MAX_EA_SIZE) ret = MAX_EA_SIZE; /* Start building reply packet */ LOG(log_debug7, logtype_afpd, "sys_getextattr_size(%s): attribute: \"%s\", size: %u", uname, attruname, ret); /* length of attribute data */ attrsize = htonl((uint32_t)ret); memcpy(rbuf, &attrsize, 4); *rbuflen += 4; ret = AFP_OK; return ret; }
/* * Function: sys_get_eacontent * * Purpose: copy native EA into rbuf * * Arguments: * * vol (r) current volume * rbuf (w) DSI reply buffer * rbuflen (rw) current length of data in reply buffer * uname (r) filename * oflag (r) link and create flag * attruname (r) name of attribute * maxreply (r) maximum EA size as of current specs/real-life * * Returns: AFP code: AFP_OK on success or appropiate AFP error code * * Effects: * * Copies EA into rbuf. Increments *rbuflen accordingly. */ int sys_get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT) { ssize_t ret; uint32_t attrsize; /* Start building reply packet */ maxreply -= MAX_REPLY_EXTRA_BYTES; if (maxreply > MAX_EA_SIZE) maxreply = MAX_EA_SIZE; LOG(log_debug7, logtype_afpd, "sys_getextattr_content(%s): attribute: \"%s\", size: %u", uname, attruname, maxreply); if ((oflag & O_NOFOLLOW) ) { ret = sys_lgetxattr(uname, attruname, rbuf +4, maxreply); } else { ret = sys_getxattr(uname, attruname, rbuf +4, maxreply); } if (ret == -1) { memset(rbuf, 0, 4); *rbuflen += 4; switch(errno) { case OPEN_NOFOLLOW_ERRNO: /* its a symlink and client requested O_NOFOLLOW */ LOG(log_debug, logtype_afpd, "sys_getextattr_content(%s): symlink with kXAttrNoFollow", uname); return AFPERR_MISC; case ENOATTR: return AFPERR_MISC; default: LOG(log_debug, logtype_afpd, "sys_getextattr_content(%s): error: %s", attruname, strerror(errno)); return AFPERR_MISC; } } /* remember where we must store length of attribute data in rbuf */ *rbuflen += 4 +ret; attrsize = htonl((uint32_t)ret); memcpy(rbuf, &attrsize, 4); return AFP_OK; }
/* * Function: sys_get_easize * * Purpose: get size of a native EA * * Arguments: * * vol (r) current volume * rbuf (w) DSI reply buffer * rbuflen (rw) current length of data in reply buffer * uname (r) filename * oflag (r) link and create flag * attruname (r) name of attribute * * Returns: AFP code: AFP_OK on success or appropiate AFP error code * * Effects: * * Copies EA size into rbuf in network order. Increments *rbuflen +4. */ int sys_get_easize(VFS_FUNC_ARGS_EA_GETSIZE) { ssize_t ret; uint32_t attrsize; LOG(log_debug7, logtype_afpd, "sys_getextattr_size(%s): attribute: \"%s\"", uname, attruname); /* PBaranski fix */ if (fd != -1) { LOG(log_debug, logtype_afpd, "sys_get_easize(%s): file is already opened", uname); ret = sys_fgetxattr(fd, attruname, rbuf +4, 0); } else { if ((oflag & O_NOFOLLOW) ) { ret = sys_lgetxattr(uname, attruname, rbuf +4, 0); } else { ret = sys_getxattr(uname, attruname, rbuf +4, 0); } } /* PBaranski fix */ if (ret == -1) { memset(rbuf, 0, 4); *rbuflen += 4; switch(errno) { case OPEN_NOFOLLOW_ERRNO: /* its a symlink and client requested O_NOFOLLOW */ LOG(log_debug, logtype_afpd, "sys_getextattr_size(%s): symlink with kXAttrNoFollow", uname); return AFPERR_MISC; case ENOATTR: case ENOENT: if (vol->v_obj->afp_version >= 34) return AFPERR_NOITEM; return AFPERR_MISC; default: LOG(log_debug, logtype_afpd, "sys_getextattr_size: error: %s", strerror(errno)); return AFPERR_MISC; } } if (ret > MAX_EA_SIZE) ret = MAX_EA_SIZE; if (vol->v_flags & AFPVOL_EA_SAMBA) { /* What can we do about xattrs that are 1 byte large? */ if (ret < 2) { memset(rbuf, 0, 4); *rbuflen += 4; if (vol->v_obj->afp_version >= 34) { return AFPERR_NOITEM; } return AFPERR_MISC; } ret--; } /* Start building reply packet */ LOG(log_debug7, logtype_afpd, "sys_getextattr_size(%s): attribute: \"%s\", size: %u", uname, attruname, ret); /* length of attribute data */ attrsize = htonl((uint32_t)ret); memcpy(rbuf, &attrsize, 4); *rbuflen += 4; ret = AFP_OK; return ret; }
/* * 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_get_eacontent * * Purpose: copy native EA into rbuf * * Arguments: * * vol (r) current volume * rbuf (w) DSI reply buffer * rbuflen (rw) current length of data in reply buffer * uname (r) filename * oflag (r) link and create flag * attruname (r) name of attribute * maxreply (r) maximum EA size as of current specs/real-life * fd (r) file descriptor * Returns: AFP code: AFP_OK on success or appropiate AFP error code * * Effects: * * Copies EA into rbuf. Increments *rbuflen accordingly. */ int sys_get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT) { ssize_t ret; uint32_t attrsize; /* Start building reply packet */ maxreply -= MAX_REPLY_EXTRA_BYTES; if (maxreply > MAX_EA_SIZE) maxreply = MAX_EA_SIZE; LOG(log_debug7, logtype_afpd, "sys_getextattr_content(%s): attribute: \"%s\", size: %u", uname, attruname, maxreply); if (vol->v_flags & AFPVOL_EA_SAMBA) { maxreply++; } /* PBaranski fix */ if (fd != -1) { LOG(log_debug, logtype_afpd, "sys_get_eacontent(%s): file is already opened", uname); ret = sys_fgetxattr(fd, attruname, rbuf +4, maxreply); } else { if ((oflag & O_NOFOLLOW) ) { ret = sys_lgetxattr(uname, attruname, rbuf +4, maxreply); } else { ret = sys_getxattr(uname, attruname, rbuf +4, maxreply); } } /* PBaranski fix */ if (ret == -1) { memset(rbuf, 0, 4); *rbuflen += 4; switch(errno) { case OPEN_NOFOLLOW_ERRNO: /* its a symlink and client requested O_NOFOLLOW */ LOG(log_debug, logtype_afpd, "sys_getextattr_content(%s): symlink with kXAttrNoFollow", uname); return AFPERR_MISC; case ENOATTR: if (vol->v_obj->afp_version >= 34) return AFPERR_NOITEM; return AFPERR_MISC; default: LOG(log_debug, logtype_afpd, "sys_getextattr_content(%s): error: %s", attruname, strerror(errno)); return AFPERR_MISC; } } if (vol->v_flags & AFPVOL_EA_SAMBA) { /* What can we do about xattrs that are 1 byte large? */ if (ret < 2) { memset(rbuf, 0, 4); *rbuflen += 4; if (vol->v_obj->afp_version >= 34) { return AFPERR_NOITEM; } return AFPERR_MISC; } ret--; } /* remember where we must store length of attribute data in rbuf */ *rbuflen += 4 +ret; attrsize = htonl((uint32_t)ret); memcpy(rbuf, &attrsize, 4); return AFP_OK; }
ssize_t vfswrap_getxattr(struct vfs_handle_struct *handle,struct connection_struct *conn,const char *path, const char *name, void *value, size_t size) { return sys_getxattr(path, name, value, size); }