|  | /* | 
|  | * 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 |