/* Read the contents of the symbolic link FILE_NAME relative to FD into no more than LEN bytes of BUF. The contents are not null-terminated. Returns the number of characters read, or -1 for errors. */ ssize_t readlinkat (int fd, const char *file_name, char *buf, size_t len) { error_t err; file_t file; struct stat64 st; file = __file_name_lookup_at (fd, 0, file_name, O_READ | O_NOLINK, 0); if (file == MACH_PORT_NULL) return -1; err = __io_stat (file, &st); if (! err) if (S_ISLNK (st.st_mode)) { char *rbuf = buf; err = __io_read (file, &rbuf, &len, 0, len); if (!err && rbuf != buf) { memcpy (buf, rbuf, len); __vm_deallocate (__mach_task_self (), (vm_address_t)rbuf, len); } } else err = EINVAL; __mach_port_deallocate (__mach_task_self (), file); return err ? __hurd_fail (err) : len; }
/* Get information about the file descriptor FD in BUF. */ int __fxstat64 (int vers, int fd, struct stat64 *buf) { error_t err; if (vers != _STAT_VER) return __hurd_fail (EINVAL); if (err = HURD_DPORT_USE (fd, __io_stat (port, buf))) return __hurd_dfail (fd, err); return 0; }
error_t _hurd_xattr_get (io_t port, const char *name, void *value, size_t *size) { if (strncmp (name, "gnu.", 4)) return EOPNOTSUPP; name += 4; if (!strcmp (name, "author")) { struct stat64 st; error_t err = __io_stat (port, &st); if (err) return err; if (st.st_author == st.st_uid) *size = 0; else if (value) { if (*size < sizeof st.st_author) return ERANGE; memcpy (value, &st.st_author, sizeof st.st_author); } *size = sizeof st.st_author; return 0; } if (!strcmp (name, "translator")) { char *buf = value; size_t bufsz = value ? *size : 0; error_t err = __file_get_translator (port, &buf, &bufsz); if (err) return err; if (value != NULL && *size < bufsz) { if (buf != value) munmap (buf, bufsz); return -ERANGE; } if (buf != value && bufsz > 0) { if (value != NULL) memcpy (value, buf, bufsz); munmap (buf, bufsz); } *size = bufsz; return 0; } return EOPNOTSUPP; }
/* Get information about the file descriptor FD in BUF. */ int __lxstat64 (int vers, const char *file, struct stat64 *buf) { error_t err; file_t port; if (vers != _STAT_VER) return __hurd_fail (EINVAL); port = __file_name_lookup (file, O_NOLINK, 0); if (port == MACH_PORT_NULL) return -1; err = __io_stat (port, buf); __mach_port_deallocate (__mach_task_self (), port); if (err) return __hurd_fail (err); return 0; }
/* Get information about the file descriptor FD in BUF. */ int __fxstatat64 (int vers, int fd, const char *filename, struct stat64 *buf, int flag) { error_t err; io_t port; if (vers != _STAT_VER) return __hurd_fail (EINVAL); port = __file_name_lookup_at (fd, flag, filename, 0, 0); if (port == MACH_PORT_NULL) return -1; err = __io_stat (port, buf); __mach_port_deallocate (__mach_task_self (), port); return __hurd_fail (err); }
error_t _hurd_xattr_set (io_t port, const char *name, const void *value, size_t size, int flags) { if (strncmp (name, "gnu.", 4)) return EOPNOTSUPP; name += 4; if (!strcmp (name, "author")) switch (size) { default: return EINVAL; case 0: /* "Clear" author by setting to st_uid. */ { struct stat64 st; error_t err = __io_stat (port, &st); if (err) return err; if (st.st_author == st.st_uid) { /* Nothing to do. */ if (flags & XATTR_REPLACE) return ENODATA; return 0; } if (flags & XATTR_CREATE) return EEXIST; return __file_chauthor (port, st.st_uid); } case sizeof (uid_t): /* Set the author. */ { uid_t id; memcpy (&id, value, sizeof id); if (flags & (XATTR_CREATE|XATTR_REPLACE)) { struct stat64 st; error_t err = __io_stat (port, &st); if (err) return err; if (st.st_author == st.st_uid) { if (flags & XATTR_REPLACE) return ENODATA; } else if (flags & XATTR_CREATE) return EEXIST; if (st.st_author == id) /* Nothing to do. */ return 0; } return __file_chauthor (port, id); } } if (!strcmp (name, "translator")) { if (flags & XATTR_REPLACE) { /* Must make sure it's already there. */ char *buf = NULL; size_t bufsz = 0; error_t err = __file_get_translator (port, &buf, &bufsz); if (err) return err; if (bufsz > 0) { munmap (buf, bufsz); return ENODATA; } } return __file_set_translator (port, FS_TRANS_SET | ((flags & XATTR_CREATE) ? FS_TRANS_EXCL : 0), 0, 0, value, size, MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND); } return EOPNOTSUPP; }
} error_t _hurd_xattr_list (io_t port, void *buffer, size_t *size) { size_t total = 0; char *bufp = buffer; inline void add (const char *name, size_t len) { total += len; if (bufp != NULL && total <= *size) bufp = __mempcpy (bufp, name, len); } #define add(s) add (s, sizeof s) struct stat64 st; error_t err = __io_stat (port, &st); if (err) return err; if (st.st_author != st.st_uid) add ("gnu.author"); if (st.st_mode & S_IPTRANS) add ("gnu.translator"); if (buffer != NULL && total > *size) return ERANGE; *size = total; return 0; }