Revision c494dd6f
b/hw/file-op-9p.h | ||
---|---|---|
29 | 29 |
{ |
30 | 30 |
int (*lstat)(FsContext *, const char *, struct stat *); |
31 | 31 |
ssize_t (*readlink)(FsContext *, const char *, char *, size_t); |
32 |
int (*chmod)(FsContext *, const char *, mode_t); |
|
33 |
int (*mknod)(FsContext *, const char *, mode_t, dev_t); |
|
34 |
int (*mksock)(FsContext *, const char *); |
|
35 |
int (*symlink)(FsContext *, const char *, const char *); |
|
36 |
int (*link)(FsContext *, const char *, const char *); |
|
32 | 37 |
int (*setuid)(FsContext *, uid_t); |
33 | 38 |
int (*close)(FsContext *, int); |
34 | 39 |
int (*closedir)(FsContext *, DIR *); |
35 | 40 |
DIR *(*opendir)(FsContext *, const char *); |
36 | 41 |
int (*open)(FsContext *, const char *, int); |
42 |
int (*open2)(FsContext *, const char *, int, mode_t); |
|
37 | 43 |
void (*rewinddir)(FsContext *, DIR *); |
38 | 44 |
off_t (*telldir)(FsContext *, DIR *); |
39 | 45 |
struct dirent *(*readdir)(FsContext *, DIR *); |
... | ... | |
41 | 47 |
ssize_t (*readv)(FsContext *, int, const struct iovec *, int); |
42 | 48 |
ssize_t (*writev)(FsContext *, int, const struct iovec *, int); |
43 | 49 |
off_t (*lseek)(FsContext *, int, off_t, int); |
50 |
int (*mkdir)(FsContext *, const char *, mode_t); |
|
51 |
int (*fstat)(FsContext *, int, struct stat *); |
|
44 | 52 |
void *opaque; |
45 | 53 |
} FileOperations; |
46 | 54 |
#endif |
b/hw/virtio-9p-local.c | ||
---|---|---|
12 | 12 |
*/ |
13 | 13 |
#include "virtio.h" |
14 | 14 |
#include "virtio-9p.h" |
15 |
#include <arpa/inet.h> |
|
15 | 16 |
#include <pwd.h> |
16 | 17 |
#include <grp.h> |
18 |
#include <sys/socket.h> |
|
19 |
#include <sys/un.h> |
|
17 | 20 |
|
18 | 21 |
static const char *rpath(FsContext *ctx, const char *path) |
19 | 22 |
{ |
... | ... | |
133 | 136 |
return writev(fd, iov, iovcnt); |
134 | 137 |
} |
135 | 138 |
|
139 |
static int local_chmod(FsContext *ctx, const char *path, mode_t mode) |
|
140 |
{ |
|
141 |
return chmod(rpath(ctx, path), mode); |
|
142 |
} |
|
143 |
|
|
144 |
static int local_mknod(FsContext *ctx, const char *path, mode_t mode, dev_t dev) |
|
145 |
{ |
|
146 |
return mknod(rpath(ctx, path), mode, dev); |
|
147 |
} |
|
148 |
|
|
149 |
static int local_mksock(FsContext *ctx2, const char *path) |
|
150 |
{ |
|
151 |
struct sockaddr_un addr; |
|
152 |
int s; |
|
153 |
|
|
154 |
addr.sun_family = AF_UNIX; |
|
155 |
snprintf(addr.sun_path, 108, "%s", rpath(ctx2, path)); |
|
156 |
|
|
157 |
s = socket(PF_UNIX, SOCK_STREAM, 0); |
|
158 |
if (s == -1) { |
|
159 |
return -1; |
|
160 |
} |
|
161 |
|
|
162 |
if (bind(s, (struct sockaddr *)&addr, sizeof(addr))) { |
|
163 |
close(s); |
|
164 |
return -1; |
|
165 |
} |
|
166 |
|
|
167 |
close(s); |
|
168 |
return 0; |
|
169 |
} |
|
170 |
|
|
171 |
static int local_mkdir(FsContext *ctx, const char *path, mode_t mode) |
|
172 |
{ |
|
173 |
return mkdir(rpath(ctx, path), mode); |
|
174 |
} |
|
175 |
|
|
176 |
static int local_fstat(FsContext *ctx, int fd, struct stat *stbuf) |
|
177 |
{ |
|
178 |
return fstat(fd, stbuf); |
|
179 |
} |
|
180 |
|
|
181 |
static int local_open2(FsContext *ctx, const char *path, int flags, mode_t mode) |
|
182 |
{ |
|
183 |
return open(rpath(ctx, path), flags, mode); |
|
184 |
} |
|
185 |
|
|
186 |
static int local_symlink(FsContext *ctx, const char *oldpath, |
|
187 |
const char *newpath) |
|
188 |
{ |
|
189 |
return symlink(oldpath, rpath(ctx, newpath)); |
|
190 |
} |
|
191 |
|
|
192 |
static int local_link(FsContext *ctx, const char *oldpath, const char *newpath) |
|
193 |
{ |
|
194 |
char *tmp = qemu_strdup(rpath(ctx, oldpath)); |
|
195 |
int err, serrno = 0; |
|
196 |
|
|
197 |
if (tmp == NULL) { |
|
198 |
return -ENOMEM; |
|
199 |
} |
|
200 |
|
|
201 |
err = link(tmp, rpath(ctx, newpath)); |
|
202 |
if (err == -1) { |
|
203 |
serrno = errno; |
|
204 |
} |
|
205 |
|
|
206 |
qemu_free(tmp); |
|
207 |
|
|
208 |
if (err == -1) { |
|
209 |
errno = serrno; |
|
210 |
} |
|
211 |
|
|
212 |
return err; |
|
213 |
} |
|
214 |
|
|
136 | 215 |
FileOperations local_ops = { |
137 | 216 |
.lstat = local_lstat, |
138 | 217 |
.setuid = local_setuid, |
... | ... | |
148 | 227 |
.readv = local_readv, |
149 | 228 |
.lseek = local_lseek, |
150 | 229 |
.writev = local_writev, |
230 |
.chmod = local_chmod, |
|
231 |
.mknod = local_mknod, |
|
232 |
.mksock = local_mksock, |
|
233 |
.mkdir = local_mkdir, |
|
234 |
.fstat = local_fstat, |
|
235 |
.open2 = local_open2, |
|
236 |
.symlink = local_symlink, |
|
237 |
.link = local_link, |
|
151 | 238 |
}; |
b/hw/virtio-9p.c | ||
---|---|---|
103 | 103 |
return s->ops->writev(&s->ctx, fd, iov, iovcnt); |
104 | 104 |
} |
105 | 105 |
|
106 |
static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode) |
|
107 |
{ |
|
108 |
return s->ops->chmod(&s->ctx, path->data, mode); |
|
109 |
} |
|
110 |
|
|
111 |
static int v9fs_do_mknod(V9fsState *s, V9fsString *path, mode_t mode, dev_t dev) |
|
112 |
{ |
|
113 |
return s->ops->mknod(&s->ctx, path->data, mode, dev); |
|
114 |
} |
|
115 |
|
|
116 |
static int v9fs_do_mksock(V9fsState *s, V9fsString *path) |
|
117 |
{ |
|
118 |
return s->ops->mksock(&s->ctx, path->data); |
|
119 |
} |
|
120 |
|
|
121 |
static int v9fs_do_mkdir(V9fsState *s, V9fsString *path, mode_t mode) |
|
122 |
{ |
|
123 |
return s->ops->mkdir(&s->ctx, path->data, mode); |
|
124 |
} |
|
125 |
|
|
126 |
static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf) |
|
127 |
{ |
|
128 |
return s->ops->fstat(&s->ctx, fd, stbuf); |
|
129 |
} |
|
130 |
|
|
131 |
static int v9fs_do_open2(V9fsState *s, V9fsString *path, int flags, mode_t mode) |
|
132 |
{ |
|
133 |
return s->ops->open2(&s->ctx, path->data, flags, mode); |
|
134 |
} |
|
135 |
|
|
136 |
static int v9fs_do_symlink(V9fsState *s, V9fsString *oldpath, |
|
137 |
V9fsString *newpath) |
|
138 |
{ |
|
139 |
return s->ops->symlink(&s->ctx, oldpath->data, newpath->data); |
|
140 |
} |
|
141 |
|
|
142 |
static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath) |
|
143 |
{ |
|
144 |
return s->ops->link(&s->ctx, oldpath->data, newpath->data); |
|
145 |
} |
|
146 |
|
|
106 | 147 |
static void v9fs_string_init(V9fsString *str) |
107 | 148 |
{ |
108 | 149 |
str->data = NULL; |
... | ... | |
1649 | 1690 |
qemu_free(vs); |
1650 | 1691 |
} |
1651 | 1692 |
|
1693 |
typedef struct V9fsCreateState { |
|
1694 |
V9fsPDU *pdu; |
|
1695 |
size_t offset; |
|
1696 |
V9fsFidState *fidp; |
|
1697 |
V9fsQID qid; |
|
1698 |
int32_t perm; |
|
1699 |
int8_t mode; |
|
1700 |
struct stat stbuf; |
|
1701 |
V9fsString name; |
|
1702 |
V9fsString extension; |
|
1703 |
V9fsString fullname; |
|
1704 |
} V9fsCreateState; |
|
1705 |
|
|
1706 |
static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err) |
|
1707 |
{ |
|
1708 |
if (err == 0) { |
|
1709 |
v9fs_string_copy(&vs->fidp->path, &vs->fullname); |
|
1710 |
stat_to_qid(&vs->stbuf, &vs->qid); |
|
1711 |
|
|
1712 |
vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0); |
|
1713 |
|
|
1714 |
err = vs->offset; |
|
1715 |
} |
|
1716 |
|
|
1717 |
complete_pdu(s, vs->pdu, err); |
|
1718 |
v9fs_string_free(&vs->name); |
|
1719 |
v9fs_string_free(&vs->extension); |
|
1720 |
v9fs_string_free(&vs->fullname); |
|
1721 |
qemu_free(vs); |
|
1722 |
} |
|
1723 |
|
|
1724 |
static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err) |
|
1725 |
{ |
|
1726 |
if (err) { |
|
1727 |
err = -errno; |
|
1728 |
} |
|
1729 |
v9fs_post_create(s, vs, err); |
|
1730 |
} |
|
1731 |
|
|
1732 |
static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs, |
|
1733 |
int err) |
|
1734 |
{ |
|
1735 |
if (!vs->fidp->dir) { |
|
1736 |
err = -errno; |
|
1737 |
} |
|
1738 |
v9fs_post_create(s, vs, err); |
|
1739 |
} |
|
1740 |
|
|
1741 |
static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs, |
|
1742 |
int err) |
|
1743 |
{ |
|
1744 |
if (err) { |
|
1745 |
err = -errno; |
|
1746 |
goto out; |
|
1747 |
} |
|
1748 |
|
|
1749 |
vs->fidp->dir = v9fs_do_opendir(s, &vs->fullname); |
|
1750 |
v9fs_create_post_opendir(s, vs, err); |
|
1751 |
return; |
|
1752 |
|
|
1753 |
out: |
|
1754 |
v9fs_post_create(s, vs, err); |
|
1755 |
} |
|
1756 |
|
|
1757 |
static void v9fs_create_post_mkdir(V9fsState *s, V9fsCreateState *vs, int err) |
|
1758 |
{ |
|
1759 |
if (err) { |
|
1760 |
err = -errno; |
|
1761 |
goto out; |
|
1762 |
} |
|
1763 |
|
|
1764 |
err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf); |
|
1765 |
v9fs_create_post_dir_lstat(s, vs, err); |
|
1766 |
return; |
|
1767 |
|
|
1768 |
out: |
|
1769 |
v9fs_post_create(s, vs, err); |
|
1770 |
} |
|
1771 |
|
|
1772 |
static void v9fs_create_post_mksock(V9fsState *s, V9fsCreateState *vs, |
|
1773 |
int err) |
|
1774 |
{ |
|
1775 |
if (err) { |
|
1776 |
err = -errno; |
|
1777 |
goto out; |
|
1778 |
} |
|
1779 |
|
|
1780 |
err = v9fs_do_chmod(s, &vs->fullname, vs->perm & 0777); |
|
1781 |
v9fs_create_post_perms(s, vs, err); |
|
1782 |
return; |
|
1783 |
|
|
1784 |
out: |
|
1785 |
v9fs_post_create(s, vs, err); |
|
1786 |
} |
|
1787 |
|
|
1788 |
static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err) |
|
1789 |
{ |
|
1790 |
if (err) { |
|
1791 |
vs->fidp->fd = -1; |
|
1792 |
err = -errno; |
|
1793 |
} |
|
1794 |
|
|
1795 |
v9fs_post_create(s, vs, err); |
|
1796 |
return; |
|
1797 |
} |
|
1798 |
|
|
1799 |
static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err) |
|
1800 |
{ |
|
1801 |
if (vs->fidp->fd == -1) { |
|
1802 |
err = -errno; |
|
1803 |
goto out; |
|
1804 |
} |
|
1805 |
|
|
1806 |
err = v9fs_do_fstat(s, vs->fidp->fd, &vs->stbuf); |
|
1807 |
v9fs_create_post_fstat(s, vs, err); |
|
1808 |
|
|
1809 |
return; |
|
1810 |
|
|
1811 |
out: |
|
1812 |
v9fs_post_create(s, vs, err); |
|
1813 |
|
|
1814 |
} |
|
1815 |
|
|
1816 |
static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err) |
|
1817 |
{ |
|
1818 |
|
|
1819 |
if (err == 0 || errno != ENOENT) { |
|
1820 |
err = -errno; |
|
1821 |
goto out; |
|
1822 |
} |
|
1823 |
|
|
1824 |
if (vs->perm & P9_STAT_MODE_DIR) { |
|
1825 |
err = v9fs_do_mkdir(s, &vs->fullname, vs->perm & 0777); |
|
1826 |
v9fs_create_post_mkdir(s, vs, err); |
|
1827 |
} else if (vs->perm & P9_STAT_MODE_SYMLINK) { |
|
1828 |
err = v9fs_do_symlink(s, &vs->extension, &vs->fullname); |
|
1829 |
v9fs_create_post_perms(s, vs, err); |
|
1830 |
} else if (vs->perm & P9_STAT_MODE_LINK) { |
|
1831 |
int32_t nfid = atoi(vs->extension.data); |
|
1832 |
V9fsFidState *nfidp = lookup_fid(s, nfid); |
|
1833 |
if (nfidp == NULL) { |
|
1834 |
err = -errno; |
|
1835 |
v9fs_post_create(s, vs, err); |
|
1836 |
} |
|
1837 |
err = v9fs_do_link(s, &nfidp->path, &vs->fullname); |
|
1838 |
v9fs_create_post_perms(s, vs, err); |
|
1839 |
} else if (vs->perm & P9_STAT_MODE_DEVICE) { |
|
1840 |
char ctype; |
|
1841 |
uint32_t major, minor; |
|
1842 |
mode_t nmode = 0; |
|
1843 |
|
|
1844 |
if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major, |
|
1845 |
&minor) != 3) { |
|
1846 |
err = -errno; |
|
1847 |
v9fs_post_create(s, vs, err); |
|
1848 |
} |
|
1849 |
|
|
1850 |
switch (ctype) { |
|
1851 |
case 'c': |
|
1852 |
nmode = S_IFCHR; |
|
1853 |
break; |
|
1854 |
case 'b': |
|
1855 |
nmode = S_IFBLK; |
|
1856 |
break; |
|
1857 |
default: |
|
1858 |
err = -EIO; |
|
1859 |
v9fs_post_create(s, vs, err); |
|
1860 |
} |
|
1861 |
|
|
1862 |
nmode |= vs->perm & 0777; |
|
1863 |
err = v9fs_do_mknod(s, &vs->fullname, nmode, makedev(major, minor)); |
|
1864 |
v9fs_create_post_perms(s, vs, err); |
|
1865 |
} else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) { |
|
1866 |
err = v9fs_do_mknod(s, &vs->fullname, S_IFIFO | (vs->mode & 0777), 0); |
|
1867 |
v9fs_post_create(s, vs, err); |
|
1868 |
} else if (vs->perm & P9_STAT_MODE_SOCKET) { |
|
1869 |
err = v9fs_do_mksock(s, &vs->fullname); |
|
1870 |
v9fs_create_post_mksock(s, vs, err); |
|
1871 |
} else { |
|
1872 |
vs->fidp->fd = v9fs_do_open2(s, &vs->fullname, |
|
1873 |
omode_to_uflags(vs->mode) | O_CREAT, |
|
1874 |
vs->perm & 0777); |
|
1875 |
v9fs_create_post_open2(s, vs, err); |
|
1876 |
} |
|
1877 |
|
|
1878 |
return; |
|
1879 |
|
|
1880 |
out: |
|
1881 |
v9fs_post_create(s, vs, err); |
|
1882 |
} |
|
1883 |
|
|
1652 | 1884 |
static void v9fs_create(V9fsState *s, V9fsPDU *pdu) |
1653 | 1885 |
{ |
1654 |
if (debug_9p_pdu) { |
|
1655 |
pprint_pdu(pdu); |
|
1886 |
int32_t fid; |
|
1887 |
V9fsCreateState *vs; |
|
1888 |
int err = 0; |
|
1889 |
|
|
1890 |
vs = qemu_malloc(sizeof(*vs)); |
|
1891 |
vs->pdu = pdu; |
|
1892 |
vs->offset = 7; |
|
1893 |
|
|
1894 |
v9fs_string_init(&vs->fullname); |
|
1895 |
|
|
1896 |
pdu_unmarshal(vs->pdu, vs->offset, "dsdbs", &fid, &vs->name, |
|
1897 |
&vs->perm, &vs->mode, &vs->extension); |
|
1898 |
|
|
1899 |
vs->fidp = lookup_fid(s, fid); |
|
1900 |
if (vs->fidp == NULL) { |
|
1901 |
err = -EINVAL; |
|
1902 |
goto out; |
|
1656 | 1903 |
} |
1904 |
|
|
1905 |
v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data, |
|
1906 |
vs->name.data); |
|
1907 |
|
|
1908 |
err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf); |
|
1909 |
v9fs_create_post_lstat(s, vs, err); |
|
1910 |
return; |
|
1911 |
|
|
1912 |
out: |
|
1913 |
complete_pdu(s, vs->pdu, err); |
|
1914 |
v9fs_string_free(&vs->name); |
|
1915 |
v9fs_string_free(&vs->extension); |
|
1916 |
qemu_free(vs); |
|
1657 | 1917 |
} |
1658 | 1918 |
|
1659 | 1919 |
static void v9fs_flush(V9fsState *s, V9fsPDU *pdu) |
Also available in: Unified diff