Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / net / oncrpc / nfs.c
1 /*
2  * Copyright (C) 2013 Marin Hannache <ipxe@mareo.fr>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <assert.h>
25 #include <errno.h>
26 #include <libgen.h>
27 #include <byteswap.h>
28 #include <ipxe/time.h>
29 #include <ipxe/iobuf.h>
30 #include <ipxe/open.h>
31 #include <ipxe/features.h>
32 #include <ipxe/nfs.h>
33 #include <ipxe/oncrpc.h>
34 #include <ipxe/oncrpc_iob.h>
35 #include <ipxe/portmap.h>
36 #include <ipxe/mount.h>
37 #include <ipxe/settings.h>
38
39 /** @file
40  *
41  * Network File System protocol
42  *
43  */
44
45 /** NFS LOOKUP procedure */
46 #define NFS_LOOKUP      3
47 /** NFS READLINK procedure */
48 #define NFS_READLINK    5
49 /** NFS READ procedure */
50 #define NFS_READ        6
51
52 /**
53  * Extract a file handle from the beginning of an I/O buffer
54  *
55  * @v io_buf            I/O buffer
56  * @v fh                File handle
57  * @ret size            Size of the data read
58  */
59 size_t nfs_iob_get_fh ( struct io_buffer *io_buf, struct nfs_fh *fh ) {
60         fh->size = oncrpc_iob_get_int ( io_buf );
61
62         if ( fh->size > 64 )
63                 return sizeof ( uint32_t );
64
65         memcpy (fh->fh, io_buf->data, fh->size );
66         iob_pull ( io_buf, fh->size );
67
68         return fh->size + sizeof ( uint32_t );
69 }
70
71 /**
72  * Add a file handle to the end of an I/O buffer
73  *
74  * @v io_buf            I/O buffer
75  * @v fh                File handle
76  * @ret size            Size of the data written
77  */
78 size_t nfs_iob_add_fh ( struct io_buffer *io_buf, const struct nfs_fh *fh ) {
79         size_t s;
80
81         s = oncrpc_iob_add_int ( io_buf, fh->size );
82         memcpy ( iob_put ( io_buf, fh->size ), &fh->fh, fh->size );
83
84         return s + fh->size;
85 }
86
87 /**
88  * Send a LOOKUP request
89  *
90  * @v intf              Interface to send the request on
91  * @v session           ONC RPC session
92  * @v fh                The file handle of the the directory
93  * @v filename          The file name
94  * @ret rc              Return status code
95  */
96 int nfs_lookup ( struct interface *intf, struct oncrpc_session *session,
97                  const struct nfs_fh *fh, const char *filename ) {
98         struct oncrpc_field fields[] = {
99                 ONCRPC_SUBFIELD ( array, fh->size, &fh->fh ),
100                 ONCRPC_FIELD ( str, filename ),
101                 ONCRPC_FIELD_END,
102         };
103
104         return oncrpc_call ( intf, session, NFS_LOOKUP, fields );
105 }
106
107 /**
108  * Send a READLINK request
109  *
110  * @v intf              Interface to send the request on
111  * @v session           ONC RPC session
112  * @v fh                The symlink file handle
113  * @ret rc              Return status code
114  */
115 int nfs_readlink ( struct interface *intf, struct oncrpc_session *session,
116                    const struct nfs_fh *fh ) {
117         struct oncrpc_field fields[] = {
118                 ONCRPC_SUBFIELD ( array, fh->size, &fh->fh ),
119                 ONCRPC_FIELD_END,
120         };
121
122         return oncrpc_call ( intf, session, NFS_READLINK, fields );
123 }
124
125 /**
126  * Send a READ request
127  *
128  * @v intf              Interface to send the request on
129  * @v session           ONC RPC session
130  * @v fh                The file handle
131  * @v offset            Offset
132  * @v count             Byte count
133  * @ret rc              Return status code
134  */
135 int nfs_read ( struct interface *intf, struct oncrpc_session *session,
136                const struct nfs_fh *fh, uint64_t offset, uint32_t count ) {
137         struct oncrpc_field fields[] = {
138                 ONCRPC_SUBFIELD ( array, fh->size, &fh->fh ),
139                 ONCRPC_FIELD ( int64, offset ),
140                 ONCRPC_FIELD ( int32, count ),
141                 ONCRPC_FIELD_END,
142         };
143
144         return oncrpc_call ( intf, session, NFS_READ, fields );
145 }
146
147 /**
148  * Parse a LOOKUP reply
149  *
150  * @v lookup_reply      A structure where the data will be saved
151  * @v reply             The ONC RPC reply to get data from
152  * @ret rc              Return status code
153  */
154 int nfs_get_lookup_reply ( struct nfs_lookup_reply *lookup_reply,
155                            struct oncrpc_reply *reply ) {
156         if ( ! lookup_reply || ! reply )
157                 return -EINVAL;
158
159         lookup_reply->status = oncrpc_iob_get_int ( reply->data );
160         switch ( lookup_reply->status )
161         {
162         case NFS3_OK:
163                 break;
164         case NFS3ERR_PERM:
165                 return -EPERM;
166         case NFS3ERR_NOENT:
167                 return -ENOENT;
168         case NFS3ERR_IO:
169                 return -EIO;
170         case NFS3ERR_ACCES:
171                 return -EACCES;
172         case NFS3ERR_NOTDIR:
173                 return -ENOTDIR;
174         case NFS3ERR_NAMETOOLONG:
175                 return -ENAMETOOLONG;
176         case NFS3ERR_STALE:
177                 return -ESTALE;
178         case NFS3ERR_BADHANDLE:
179         case NFS3ERR_SERVERFAULT:
180         default:
181                 return -EPROTO;
182         }
183
184         nfs_iob_get_fh ( reply->data, &lookup_reply->fh );
185
186         if ( oncrpc_iob_get_int ( reply->data ) == 1 )
187                 lookup_reply->ent_type = oncrpc_iob_get_int ( reply->data );
188
189         return 0;
190 }
191 /**
192  * Parse a READLINK reply
193  *
194  * @v readlink_reply    A structure where the data will be saved
195  * @v reply             The ONC RPC reply to get data from
196  * @ret rc              Return status code
197  */
198 int nfs_get_readlink_reply ( struct nfs_readlink_reply *readlink_reply,
199                              struct oncrpc_reply *reply ) {
200         if ( ! readlink_reply || ! reply )
201                 return -EINVAL;
202
203         readlink_reply->status = oncrpc_iob_get_int ( reply->data );
204         switch ( readlink_reply->status )
205         {
206         case NFS3_OK:
207                  break;
208         case NFS3ERR_IO:
209                 return -EIO;
210         case NFS3ERR_ACCES:
211                 return -EACCES;
212         case NFS3ERR_INVAL:
213                 return -EINVAL;
214         case NFS3ERR_NOTSUPP:
215                 return -ENOTSUP;
216         case NFS3ERR_STALE:
217                 return -ESTALE;
218         case NFS3ERR_BADHANDLE:
219         case NFS3ERR_SERVERFAULT:
220         default:
221                 return -EPROTO;
222         }
223
224         if ( oncrpc_iob_get_int ( reply->data ) == 1 )
225                 iob_pull ( reply->data, 5 * sizeof ( uint32_t ) +
226                                         8 * sizeof ( uint64_t ) );
227
228         readlink_reply->path_len = oncrpc_iob_get_int ( reply->data );
229         readlink_reply->path     = reply->data->data;
230
231         return 0;
232 }
233
234 /**
235  * Parse a READ reply
236  *
237  * @v read_reply        A structure where the data will be saved
238  * @v reply             The ONC RPC reply to get data from
239  * @ret rc              Return status code
240  */
241 int nfs_get_read_reply ( struct nfs_read_reply *read_reply,
242                          struct oncrpc_reply *reply ) {
243         if ( ! read_reply || ! reply )
244                 return -EINVAL;
245
246         read_reply->status = oncrpc_iob_get_int ( reply->data );
247         switch ( read_reply->status )
248         {
249         case NFS3_OK:
250                  break;
251         case NFS3ERR_PERM:
252                 return -EPERM;
253         case NFS3ERR_NOENT:
254                 return -ENOENT;
255         case NFS3ERR_IO:
256                 return -EIO;
257         case NFS3ERR_NXIO:
258                 return -ENXIO;
259         case NFS3ERR_ACCES:
260                 return -EACCES;
261         case NFS3ERR_INVAL:
262                 return -EINVAL;
263         case NFS3ERR_STALE:
264                 return -ESTALE;
265         case NFS3ERR_BADHANDLE:
266         case NFS3ERR_SERVERFAULT:
267         default:
268                 return -EPROTO;
269         }
270
271         if ( oncrpc_iob_get_int ( reply->data ) == 1 )
272         {
273                 iob_pull ( reply->data, 5 * sizeof ( uint32_t ) );
274                 read_reply->filesize = oncrpc_iob_get_int64 ( reply->data );
275                 iob_pull ( reply->data, 7 * sizeof ( uint64_t ) );
276         }
277
278         read_reply->count    = oncrpc_iob_get_int ( reply->data );
279         read_reply->eof      = oncrpc_iob_get_int ( reply->data );
280         read_reply->data_len = oncrpc_iob_get_int ( reply->data );
281         read_reply->data     = reply->data->data;
282
283         if ( read_reply->count != read_reply->data_len )
284                 return -EPROTO;
285
286         return 0;
287 }
288