/* * 9P network client for VirtIO 9P test cases (based on QTest) * * Copyright (c) 2014 SUSE LINUX Products GmbH * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ /* * Not so fast! You might want to read the 9p developer docs first: * https://wiki.qemu.org/Documentation/9p */ #ifndef TESTS_LIBQOS_VIRTIO_9P_CLIENT_H #define TESTS_LIBQOS_VIRTIO_9P_CLIENT_H #include "hw/9pfs/9p.h" #include "hw/9pfs/9p-synth.h" #include "virtio-9p.h" #include "qgraph.h" #include "tests/qtest/libqtest-single.h" #define P9_MAX_SIZE 4096 /* Max size of a T-message or R-message */ typedef struct { QTestState *qts; QVirtio9P *v9p; uint16_t tag; uint64_t t_msg; uint32_t t_size; uint64_t r_msg; /* No r_size, it is hardcoded to P9_MAX_SIZE */ size_t t_off; size_t r_off; uint32_t free_head; } P9Req; /* type[1] version[4] path[8] */ typedef char v9fs_qid[13]; typedef struct v9fs_attr { uint64_t valid; v9fs_qid qid; uint32_t mode; uint32_t uid; uint32_t gid; uint64_t nlink; uint64_t rdev; uint64_t size; uint64_t blksize; uint64_t blocks; uint64_t atime_sec; uint64_t atime_nsec; uint64_t mtime_sec; uint64_t mtime_nsec; uint64_t ctime_sec; uint64_t ctime_nsec; uint64_t btime_sec; uint64_t btime_nsec; uint64_t gen; uint64_t data_version; } v9fs_attr; #define P9_GETATTR_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */ #define P9_GETATTR_ALL 0x00003fffULL /* Mask for ALL fields */ struct V9fsDirent { v9fs_qid qid; uint64_t offset; uint8_t type; char *name; struct V9fsDirent *next; }; /* options for 'Twalk' 9p request */ typedef struct TWalkOpt { /* 9P client being used (mandatory) */ QVirtio9P *client; /* user supplied tag number being returned with response (optional) */ uint16_t tag; /* file ID of directory from where walk should start (optional) */ uint32_t fid; /* file ID for target directory being walked to (optional) */ uint32_t newfid; /* low level variant of path to walk to (optional) */ uint16_t nwname; char **wnames; /* high level variant of path to walk to (optional) */ const char *path; /* data being received from 9p server as 'Rwalk' response (optional) */ struct { uint16_t *nwqid; v9fs_qid **wqid; } rwalk; /* only send Twalk request but not wait for a reply? (optional) */ bool requestOnly; /* do we expect an Rlerror response, if yes which error code? (optional) */ uint32_t expectErr; } TWalkOpt; /* result of 'Twalk' 9p request */ typedef struct TWalkRes { /* file ID of target directory been walked to */ uint32_t newfid; /* if requestOnly was set: request object for further processing */ P9Req *req; } TWalkRes; /* options for 'Tversion' 9p request */ typedef struct TVersionOpt { /* 9P client being used (mandatory) */ QVirtio9P *client; /* user supplied tag number being returned with response (optional) */ uint16_t tag; /* maximum message size that can be handled by client (optional) */ uint32_t msize; /* protocol version (optional) */ const char *version; /* only send Tversion request but not wait for a reply? (optional) */ bool requestOnly; /* do we expect an Rlerror response, if yes which error code? (optional) */ uint32_t expectErr; } TVersionOpt; /* result of 'Tversion' 9p request */ typedef struct TVersionRes { /* if requestOnly was set: request object for further processing */ P9Req *req; } TVersionRes; /* options for 'Tattach' 9p request */ typedef struct TAttachOpt { /* 9P client being used (mandatory) */ QVirtio9P *client; /* user supplied tag number being returned with response (optional) */ uint16_t tag; /* file ID to be associated with root of file tree (optional) */ uint32_t fid; /* numerical uid of user being introduced to server (optional) */ uint32_t n_uname; /* data being received from 9p server as 'Rattach' response (optional) */ struct { /* server's idea of the root of the file tree */ v9fs_qid *qid; } rattach; /* only send Tattach request but not wait for a reply? (optional) */ bool requestOnly; /* do we expect an Rlerror response, if yes which error code? (optional) */ uint32_t expectErr; } TAttachOpt; /* result of 'Tattach' 9p request */ typedef struct TAttachRes { /* if requestOnly was set: request object for further processing */ P9Req *req; } TAttachRes; /* options for 'Tgetattr' 9p request */ typedef struct TGetAttrOpt { /* 9P client being used (mandatory) */ QVirtio9P *client; /* user supplied tag number being returned with response (optional) */ uint16_t tag; /* file ID of file/dir whose attributes shall be retrieved (required) */ uint32_t fid; /* bitmask indicating attribute fields to be retrieved (optional) */ uint64_t request_mask; /* data being received from 9p server as 'Rgetattr' response (optional) */ struct { v9fs_attr *attr; } rgetattr; /* only send Tgetattr request but not wait for a reply? (optional) */ bool requestOnly; /* do we expect an Rlerror response, if yes which error code? (optional) */ uint32_t expectErr; } TGetAttrOpt; /* result of 'Tgetattr' 9p request */ typedef struct TGetAttrRes { /* if requestOnly was set: request object for further processing */ P9Req *req; } TGetAttrRes; /* options for 'Treaddir' 9p request */ typedef struct TReadDirOpt { /* 9P client being used (mandatory) */ QVirtio9P *client; /* user supplied tag number being returned with response (optional) */ uint16_t tag; /* file ID of directory whose entries shall be retrieved (required) */ uint32_t fid; /* offset in entries stream, i.e. for multiple requests (optional) */ uint64_t offset; /* maximum bytes to be returned by server (required) */ uint32_t count; /* data being received from 9p server as 'Rreaddir' response (optional) */ struct { uint32_t *count; uint32_t *nentries; struct V9fsDirent **entries; } rreaddir; /* only send Treaddir request but not wait for a reply? (optional) */ bool requestOnly; /* do we expect an Rlerror response, if yes which error code? (optional) */ uint32_t expectErr; } TReadDirOpt; /* result of 'Treaddir' 9p request */ typedef struct TReadDirRes { /* if requestOnly was set: request object for further processing */ P9Req *req; } TReadDirRes; /* options for 'Tlopen' 9p request */ typedef struct TLOpenOpt { /* 9P client being used (mandatory) */ QVirtio9P *client; /* user supplied tag number being returned with response (optional) */ uint16_t tag; /* file ID of file / directory to be opened (required) */ uint32_t fid; /* Linux open(2) flags such as O_RDONLY, O_RDWR, O_WRONLY (optional) */ uint32_t flags; /* data being received from 9p server as 'Rlopen' response (optional) */ struct { v9fs_qid *qid; uint32_t *iounit; } rlopen; /* only send Tlopen request but not wait for a reply? (optional) */ bool requestOnly; /* do we expect an Rlerror response, if yes which error code? (optional) */ uint32_t expectErr; } TLOpenOpt; /* result of 'Tlopen' 9p request */ typedef struct TLOpenRes { /* if requestOnly was set: request object for further processing */ P9Req *req; } TLOpenRes; /* options for 'Twrite' 9p request */ typedef struct TWriteOpt { /* 9P client being used (mandatory) */ QVirtio9P *client; /* user supplied tag number being returned with response (optional) */ uint16_t tag; /* file ID of file to write to (required) */ uint32_t fid; /* start position of write from beginning of file (optional) */ uint64_t offset; /* how many bytes to write */ uint32_t count; /* data to be written */ const void *data; /* only send Twrite request but not wait for a reply? (optional) */ bool requestOnly; /* do we expect an Rlerror response, if yes which error code? (optional) */ uint32_t expectErr; } TWriteOpt; /* result of 'Twrite' 9p request */ typedef struct TWriteRes { /* if requestOnly was set: request object for further processing */ P9Req *req; /* amount of bytes written */ uint32_t count; } TWriteRes; /* options for 'Tflush' 9p request */ typedef struct TFlushOpt { /* 9P client being used (mandatory) */ QVirtio9P *client; /* user supplied tag number being returned with response (optional) */ uint16_t tag; /* message to flush (required) */ uint16_t oldtag; /* only send Tflush request but not wait for a reply? (optional) */ bool requestOnly; /* do we expect an Rlerror response, if yes which error code? (optional) */ uint32_t expectErr; } TFlushOpt; /* result of 'Tflush' 9p request */ typedef struct TFlushRes { /* if requestOnly was set: request object for further processing */ P9Req *req; } TFlushRes; /* options for 'Tmkdir' 9p request */ typedef struct TMkdirOpt { /* 9P client being used (mandatory) */ QVirtio9P *client; /* user supplied tag number being returned with response (optional) */ uint16_t tag; /* low level variant of directory where new one shall be created */ uint32_t dfid; /* high-level variant of directory where new one shall be created */ const char *atPath; /* New directory's name (required) */ const char *name; /* Linux mkdir(2) mode bits (optional) */ uint32_t mode; /* effective group ID of caller */ uint32_t gid; /* data being received from 9p server as 'Rmkdir' response (optional) */ struct { /* QID of newly created directory */ v9fs_qid *qid; } rmkdir; /* only send Tmkdir request but not wait for a reply? (optional) */ bool requestOnly; /* do we expect an Rlerror response, if yes which error code? (optional) */ uint32_t expectErr; } TMkdirOpt; /* result of 'TMkdir' 9p request */ typedef struct TMkdirRes { /* if requestOnly was set: request object for further processing */ P9Req *req; } TMkdirRes; /* options for 'Tlcreate' 9p request */ typedef struct TlcreateOpt { /* 9P client being used (mandatory) */ QVirtio9P *client; /* user supplied tag number being returned with response (optional) */ uint16_t tag; /* low-level variant of directory where new file shall be created */ uint32_t fid; /* high-level variant of directory where new file shall be created */ const char *atPath; /* name of new file (required) */ const char *name; /* Linux kernel intent bits */ uint32_t flags; /* Linux create(2) mode bits */ uint32_t mode; /* effective group ID of caller */ uint32_t gid; /* data being received from 9p server as 'Rlcreate' response (optional) */ struct { v9fs_qid *qid; uint32_t *iounit; } rlcreate; /* only send Tlcreate request but not wait for a reply? (optional) */ bool requestOnly; /* do we expect an Rlerror response, if yes which error code? (optional) */ uint32_t expectErr; } TlcreateOpt; /* result of 'Tlcreate' 9p request */ typedef struct TlcreateRes { /* if requestOnly was set: request object for further processing */ P9Req *req; } TlcreateRes; /* options for 'Tsymlink' 9p request */ typedef struct TsymlinkOpt { /* 9P client being used (mandatory) */ QVirtio9P *client; /* user supplied tag number being returned with response (optional) */ uint16_t tag; /* low-level variant of directory where symlink shall be created */ uint32_t fid; /* high-level variant of directory where symlink shall be created */ const char *atPath; /* name of symlink (required) */ const char *name; /* where symlink will point to (required) */ const char *symtgt; /* effective group ID of caller */ uint32_t gid; /* data being received from 9p server as 'Rsymlink' response (optional) */ struct { v9fs_qid *qid; } rsymlink; /* only send Tsymlink request but not wait for a reply? (optional) */ bool requestOnly; /* do we expect an Rlerror response, if yes which error code? (optional) */ uint32_t expectErr; } TsymlinkOpt; /* result of 'Tsymlink' 9p request */ typedef struct TsymlinkRes { /* if requestOnly was set: request object for further processing */ P9Req *req; } TsymlinkRes; /* options for 'Tlink' 9p request */ typedef struct TlinkOpt { /* 9P client being used (mandatory) */ QVirtio9P *client; /* user supplied tag number being returned with response (optional) */ uint16_t tag; /* low-level variant of directory where hard link shall be created */ uint32_t dfid; /* high-level variant of directory where hard link shall be created */ const char *atPath; /* low-level variant of target referenced by new hard link */ uint32_t fid; /* high-level variant of target referenced by new hard link */ const char *toPath; /* name of hard link (required) */ const char *name; /* only send Tlink request but not wait for a reply? (optional) */ bool requestOnly; /* do we expect an Rlerror response, if yes which error code? (optional) */ uint32_t expectErr; } TlinkOpt; /* result of 'Tlink' 9p request */ typedef struct TlinkRes { /* if requestOnly was set: request object for further processing */ P9Req *req; } TlinkRes; /* options for 'Tunlinkat' 9p request */ typedef struct TunlinkatOpt { /* 9P client being used (mandatory) */ QVirtio9P *client; /* user supplied tag number being returned with response (optional) */ uint16_t tag; /* low-level variant of directory where name shall be unlinked */ uint32_t dirfd; /* high-level variant of directory where name shall be unlinked */ const char *atPath; /* name of directory entry to be unlinked (required) */ const char *name; /* Linux unlinkat(2) flags */ uint32_t flags; /* only send Tunlinkat request but not wait for a reply? (optional) */ bool requestOnly; /* do we expect an Rlerror response, if yes which error code? (optional) */ uint32_t expectErr; } TunlinkatOpt; /* result of 'Tunlinkat' 9p request */ typedef struct TunlinkatRes { /* if requestOnly was set: request object for further processing */ P9Req *req; } TunlinkatRes; void v9fs_set_allocator(QGuestAllocator *t_alloc); void v9fs_memwrite(P9Req *req, const void *addr, size_t len); void v9fs_memskip(P9Req *req, size_t len); void v9fs_memread(P9Req *req, void *addr, size_t len); void v9fs_uint8_read(P9Req *req, uint8_t *val); void v9fs_uint16_write(P9Req *req, uint16_t val); void v9fs_uint16_read(P9Req *req, uint16_t *val); void v9fs_uint32_write(P9Req *req, uint32_t val); void v9fs_uint64_write(P9Req *req, uint64_t val); void v9fs_uint32_read(P9Req *req, uint32_t *val); void v9fs_uint64_read(P9Req *req, uint64_t *val); uint16_t v9fs_string_size(const char *string); void v9fs_string_write(P9Req *req, const char *string); void v9fs_string_read(P9Req *req, uint16_t *len, char **string); P9Req *v9fs_req_init(QVirtio9P *v9p, uint32_t size, uint8_t id, uint16_t tag); void v9fs_req_send(P9Req *req); void v9fs_req_wait_for_reply(P9Req *req, uint32_t *len); void v9fs_req_recv(P9Req *req, uint8_t id); void v9fs_req_free(P9Req *req); void v9fs_rlerror(P9Req *req, uint32_t *err); TVersionRes v9fs_tversion(TVersionOpt); void v9fs_rversion(P9Req *req, uint16_t *len, char **version); TAttachRes v9fs_tattach(TAttachOpt); void v9fs_rattach(P9Req *req, v9fs_qid *qid); TWalkRes v9fs_twalk(TWalkOpt opt); void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid); TGetAttrRes v9fs_tgetattr(TGetAttrOpt); void v9fs_rgetattr(P9Req *req, v9fs_attr *attr); TReadDirRes v9fs_treaddir(TReadDirOpt); void v9fs_rreaddir(P9Req *req, uint32_t *count, uint32_t *nentries, struct V9fsDirent **entries); void v9fs_free_dirents(struct V9fsDirent *e); TLOpenRes v9fs_tlopen(TLOpenOpt); void v9fs_rlopen(P9Req *req, v9fs_qid *qid, uint32_t *iounit); TWriteRes v9fs_twrite(TWriteOpt); void v9fs_rwrite(P9Req *req, uint32_t *count); TFlushRes v9fs_tflush(TFlushOpt); void v9fs_rflush(P9Req *req); TMkdirRes v9fs_tmkdir(TMkdirOpt); void v9fs_rmkdir(P9Req *req, v9fs_qid *qid); TlcreateRes v9fs_tlcreate(TlcreateOpt); void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, uint32_t *iounit); TsymlinkRes v9fs_tsymlink(TsymlinkOpt); void v9fs_rsymlink(P9Req *req, v9fs_qid *qid); TlinkRes v9fs_tlink(TlinkOpt); void v9fs_rlink(P9Req *req); TunlinkatRes v9fs_tunlinkat(TunlinkatOpt); void v9fs_runlinkat(P9Req *req); #endif