 43e0d9fb35
			
		
	
	
		43e0d9fb35
		
	
	
	
	
		
			
			As with previous patches, unify those 2 functions into a single function v9fs_tunlinkat() by using a declarative function arguments approach. Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com> Message-Id: <1dea593edd464908d92501933c068388c01f1744.1664917004.git.qemu_oss@crudebyte.com>
		
			
				
	
	
		
			495 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			495 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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
 |