|
@@ -29,84 +29,179 @@
|
29
|
29
|
#include <gpxe/uaccess.h>
|
30
|
30
|
#include <gpxe/in.h>
|
31
|
31
|
#include <gpxe/tftp.h>
|
32
|
|
-#include <gpxe/posix_io.h>
|
|
32
|
+#include <gpxe/xfer.h>
|
|
33
|
+#include <gpxe/open.h>
|
|
34
|
+#include <gpxe/process.h>
|
33
|
35
|
#include <pxe.h>
|
34
|
36
|
|
35
|
|
-/** File descriptor for "single-file-only" PXE TFTP transfer */
|
36
|
|
-static int pxe_single_fd = -1;
|
|
37
|
+/** A PXE TFTP connection */
|
|
38
|
+struct pxe_tftp_connection {
|
|
39
|
+ /** Data transfer interface */
|
|
40
|
+ struct xfer_interface xfer;
|
|
41
|
+ /** Data buffer */
|
|
42
|
+ userptr_t buffer;
|
|
43
|
+ /** Size of data buffer */
|
|
44
|
+ size_t size;
|
|
45
|
+ /** Starting offset of data buffer */
|
|
46
|
+ size_t start;
|
|
47
|
+ /** File position */
|
|
48
|
+ size_t offset;
|
|
49
|
+ /** Maximum file position */
|
|
50
|
+ size_t max_offset;
|
|
51
|
+ /** Block size */
|
|
52
|
+ size_t blksize;
|
|
53
|
+ /** Block index */
|
|
54
|
+ unsigned int blkidx;
|
|
55
|
+ /** Overall return status code */
|
|
56
|
+ int rc;
|
|
57
|
+};
|
|
58
|
+
|
|
59
|
+/** The PXE TFTP connection */
|
|
60
|
+static struct pxe_tftp_connection pxe_tftp = {
|
|
61
|
+ .xfer = XFER_INIT ( &null_xfer_ops ),
|
|
62
|
+};
|
|
63
|
+
|
|
64
|
+/**
|
|
65
|
+ * Close PXE TFTP connection
|
|
66
|
+ *
|
|
67
|
+ * @v rc Final status code
|
|
68
|
+ */
|
|
69
|
+static void pxe_tftp_close ( int rc ) {
|
|
70
|
+ xfer_nullify ( &pxe_tftp.xfer );
|
|
71
|
+ xfer_close ( &pxe_tftp.xfer, rc );
|
|
72
|
+ pxe_tftp.rc = rc;
|
|
73
|
+}
|
|
74
|
+
|
|
75
|
+/**
|
|
76
|
+ * Receive new data
|
|
77
|
+ *
|
|
78
|
+ * @v xfer Data transfer interface
|
|
79
|
+ * @v iobuf I/O buffer
|
|
80
|
+ * @v meta Transfer metadata
|
|
81
|
+ * @ret rc Return status code
|
|
82
|
+ */
|
|
83
|
+static int pxe_tftp_xfer_deliver_iob ( struct xfer_interface *xfer __unused,
|
|
84
|
+ struct io_buffer *iobuf,
|
|
85
|
+ struct xfer_metadata *meta ) {
|
|
86
|
+ size_t len = iob_len ( iobuf );
|
|
87
|
+ int rc = 0;
|
|
88
|
+
|
|
89
|
+ /* Calculate new buffer position */
|
|
90
|
+ if ( meta->whence != SEEK_CUR )
|
|
91
|
+ pxe_tftp.offset = 0;
|
|
92
|
+ pxe_tftp.offset += meta->offset;
|
|
93
|
+
|
|
94
|
+ /* Copy data block to buffer */
|
|
95
|
+ if ( len == 0 ) {
|
|
96
|
+ /* No data (pure seek); treat as success */
|
|
97
|
+ } else if ( pxe_tftp.offset < pxe_tftp.start ) {
|
|
98
|
+ DBG ( " buffer underrun at %zx (min %zx)",
|
|
99
|
+ pxe_tftp.offset, pxe_tftp.start );
|
|
100
|
+ rc = -ENOBUFS;
|
|
101
|
+ } else if ( ( pxe_tftp.offset + len ) >
|
|
102
|
+ ( pxe_tftp.start + pxe_tftp.size ) ) {
|
|
103
|
+ DBG ( " buffer overrun at %zx (max %zx)",
|
|
104
|
+ ( pxe_tftp.offset + len ),
|
|
105
|
+ ( pxe_tftp.start + pxe_tftp.size ) );
|
|
106
|
+ rc = -ENOBUFS;
|
|
107
|
+ } else {
|
|
108
|
+ copy_to_user ( pxe_tftp.buffer,
|
|
109
|
+ ( pxe_tftp.offset - pxe_tftp.start ),
|
|
110
|
+ iobuf->data, len );
|
|
111
|
+ }
|
|
112
|
+
|
|
113
|
+ /* Calculate new buffer position */
|
|
114
|
+ pxe_tftp.offset += len;
|
|
115
|
+
|
|
116
|
+ /* Mildly ugly hack; assume that the first non-zero seek
|
|
117
|
+ * indicates the block size.
|
|
118
|
+ */
|
|
119
|
+ if ( pxe_tftp.blksize == 0 )
|
|
120
|
+ pxe_tftp.blksize = pxe_tftp.offset;
|
37
|
121
|
|
38
|
|
-/** Block size for "single-file-only" PXE TFTP transfer */
|
39
|
|
-static size_t pxe_single_blksize;
|
|
122
|
+ /* Record maximum offset as the file size */
|
|
123
|
+ if ( pxe_tftp.max_offset < pxe_tftp.offset )
|
|
124
|
+ pxe_tftp.max_offset = pxe_tftp.offset;
|
40
|
125
|
|
41
|
|
-/** Current block index for "single-file-only" PXE TFTP transfer */
|
42
|
|
-static unsigned int pxe_single_blkidx;
|
|
126
|
+ /* Terminate transfer on error */
|
|
127
|
+ if ( rc != 0 )
|
|
128
|
+ pxe_tftp_close ( rc );
|
43
|
129
|
|
44
|
|
-/** Length of a PXE-derived URI
|
|
130
|
+ free_iob ( iobuf );
|
|
131
|
+ return rc;
|
|
132
|
+}
|
|
133
|
+
|
|
134
|
+/**
|
|
135
|
+ * Handle close() event
|
45
|
136
|
*
|
46
|
|
- * The "single-file-only" API calls use a filename field of 128 bytes.
|
47
|
|
- * 256 bytes provides plenty of space for constructing the (temporary)
|
48
|
|
- * full URI.
|
|
137
|
+ * @v xfer Data transfer interface
|
|
138
|
+ * @v rc Reason for close
|
49
|
139
|
*/
|
50
|
|
-#define PXE_URI_LEN 256
|
|
140
|
+static void pxe_tftp_xfer_close ( struct xfer_interface *xfer __unused,
|
|
141
|
+ int rc ) {
|
|
142
|
+ pxe_tftp_close ( rc );
|
|
143
|
+}
|
|
144
|
+
|
|
145
|
+static struct xfer_interface_operations pxe_tftp_xfer_ops = {
|
|
146
|
+ .close = pxe_tftp_xfer_close,
|
|
147
|
+ .vredirect = xfer_vopen,
|
|
148
|
+ .window = unlimited_xfer_window,
|
|
149
|
+ .alloc_iob = default_xfer_alloc_iob,
|
|
150
|
+ .deliver_iob = pxe_tftp_xfer_deliver_iob,
|
|
151
|
+ .deliver_raw = xfer_deliver_as_iob,
|
|
152
|
+};
|
51
|
153
|
|
52
|
154
|
/**
|
53
|
|
- * Build PXE URI string
|
|
155
|
+ * Maximum length of a PXE TFTP URI
|
54
|
156
|
*
|
55
|
|
- * @v uri_string URI string to fill in
|
56
|
|
- * @v ipaddress Server IP address (in network byte order)
|
57
|
|
- * @v port Server port (in network byte order)
|
58
|
|
- * @v filename File name
|
59
|
|
- * @v blksize Requested block size, or 0
|
|
157
|
+ * The PXE TFTP API provides 128 characters for the filename; the
|
|
158
|
+ * extra 128 bytes allow for the remainder of the URI.
|
|
159
|
+ */
|
|
160
|
+#define PXE_TFTP_URI_LEN 256
|
|
161
|
+
|
|
162
|
+/**
|
|
163
|
+ * Open PXE TFTP connection
|
60
|
164
|
*
|
61
|
|
- * The URI string buffer must be at least @c PXE_URI_LEN bytes long.
|
|
165
|
+ * @v ipaddress IP address
|
|
166
|
+ * @v port TFTP server port
|
|
167
|
+ * @v filename File name
|
|
168
|
+ * @v blksize Requested block size
|
|
169
|
+ * @ret rc Return status code
|
62
|
170
|
*/
|
63
|
|
-static void pxe_tftp_build_uri ( char *uri_string,
|
64
|
|
- uint32_t ipaddress, unsigned int port,
|
65
|
|
- const unsigned char *filename,
|
66
|
|
- int blksize ) {
|
|
171
|
+static int pxe_tftp_open ( uint32_t ipaddress, unsigned int port,
|
|
172
|
+ const unsigned char *filename, size_t blksize ) {
|
|
173
|
+ char uri_string[PXE_TFTP_URI_LEN];
|
67
|
174
|
struct in_addr address;
|
|
175
|
+ int rc;
|
|
176
|
+
|
|
177
|
+ /* Intel bug-for-bug hack */
|
|
178
|
+ pxe_set_cached_filename ( filename );
|
|
179
|
+
|
|
180
|
+ /* Reset PXE TFTP connection structure */
|
|
181
|
+ memset ( &pxe_tftp, 0, sizeof ( pxe_tftp ) );
|
|
182
|
+ xfer_init ( &pxe_tftp.xfer, &pxe_tftp_xfer_ops, NULL );
|
|
183
|
+ pxe_tftp.rc = -EINPROGRESS;
|
68
|
184
|
|
|
185
|
+ /* Construct URI string */
|
69
|
186
|
address.s_addr = ipaddress;
|
70
|
187
|
if ( ! port )
|
71
|
188
|
port = htons ( TFTP_PORT );
|
72
|
|
- if ( ! blksize )
|
73
|
|
- blksize = TFTP_MAX_BLKSIZE;
|
74
|
|
- tftp_set_request_blksize ( blksize );
|
75
|
|
-
|
76
|
|
- snprintf ( uri_string, PXE_URI_LEN, "tftp://%s:%d%s%s",
|
|
189
|
+ if ( blksize < TFTP_DEFAULT_BLKSIZE )
|
|
190
|
+ blksize = TFTP_DEFAULT_BLKSIZE;
|
|
191
|
+ snprintf ( uri_string, sizeof ( uri_string ),
|
|
192
|
+ "tftp://%s:%d%s%s?blksize=%d",
|
77
|
193
|
inet_ntoa ( address ), ntohs ( port ),
|
78
|
|
- ( ( filename[0] == '/' ) ? "" : "/" ), filename );
|
79
|
|
-}
|
|
194
|
+ ( ( filename[0] == '/' ) ? "" : "/" ), filename, blksize );
|
|
195
|
+ DBG ( " %s", uri_string );
|
80
|
196
|
|
81
|
|
-/**
|
82
|
|
- * Read as much as possible from file
|
83
|
|
- *
|
84
|
|
- * @v fd File descriptor
|
85
|
|
- * @v buffer Data buffer
|
86
|
|
- * @v max_len Maximum length to read
|
87
|
|
- * @ret len Actual length read, or negative error
|
88
|
|
- */
|
89
|
|
-static ssize_t pxe_tftp_read_all ( int fd, userptr_t buffer,
|
90
|
|
- size_t max_len ) {
|
91
|
|
- fd_set fdset;
|
92
|
|
- off_t offset = 0;
|
93
|
|
- int ready;
|
94
|
|
- ssize_t len;
|
95
|
|
-
|
96
|
|
- do {
|
97
|
|
- FD_ZERO ( &fdset );
|
98
|
|
- FD_SET ( fd, &fdset );
|
99
|
|
- ready = select ( &fdset, 1 );
|
100
|
|
- if ( ready < 0 )
|
101
|
|
- return ready;
|
102
|
|
- len = read_user ( fd, buffer, offset, max_len );
|
103
|
|
- if ( len < 0 )
|
104
|
|
- return len;
|
105
|
|
- offset += len;
|
106
|
|
- max_len -= len;
|
107
|
|
- } while ( max_len && len );
|
108
|
|
-
|
109
|
|
- return offset;
|
|
197
|
+ /* Open PXE TFTP connection */
|
|
198
|
+ if ( ( rc = xfer_open_uri_string ( &pxe_tftp.xfer,
|
|
199
|
+ uri_string ) ) != 0 ) {
|
|
200
|
+ DBG ( " could not open (%s)\n", strerror ( rc ) );
|
|
201
|
+ return rc;
|
|
202
|
+ }
|
|
203
|
+
|
|
204
|
+ return 0;
|
110
|
205
|
}
|
111
|
206
|
|
112
|
207
|
/**
|
|
@@ -131,11 +226,6 @@ static ssize_t pxe_tftp_read_all ( int fd, userptr_t buffer,
|
131
|
226
|
* routing will take place. See the relevant
|
132
|
227
|
* @ref pxe_routing "implementation note" for more details.
|
133
|
228
|
*
|
134
|
|
- * Because we support arbitrary protocols, most of which have no
|
135
|
|
- * notion of "block size" and will return data in arbitrary-sized
|
136
|
|
- * chunks, we cheat and pretend to the caller that the blocksize is
|
137
|
|
- * always accepted as-is.
|
138
|
|
- *
|
139
|
229
|
* On x86, you must set the s_PXE::StatusCallout field to a nonzero
|
140
|
230
|
* value before calling this function in protected mode. You cannot
|
141
|
231
|
* call this function with a 32-bit stack segment. (See the relevant
|
|
@@ -157,33 +247,35 @@ static ssize_t pxe_tftp_read_all ( int fd, userptr_t buffer,
|
157
|
247
|
* other PXE API call "if an MTFTP connection is active".
|
158
|
248
|
*/
|
159
|
249
|
PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) {
|
160
|
|
- char uri_string[PXE_URI_LEN];
|
|
250
|
+ int rc;
|
161
|
251
|
|
162
|
252
|
DBG ( "PXENV_TFTP_OPEN" );
|
163
|
253
|
|
164
|
254
|
/* Guard against callers that fail to close before re-opening */
|
165
|
|
- close ( pxe_single_fd );
|
166
|
|
- pxe_single_fd = -1;
|
167
|
|
-
|
168
|
|
- /* Construct URI */
|
169
|
|
- pxe_tftp_build_uri ( uri_string, tftp_open->ServerIPAddress,
|
170
|
|
- tftp_open->TFTPPort, tftp_open->FileName,
|
171
|
|
- tftp_open->PacketSize );
|
172
|
|
- DBG ( " %s", uri_string );
|
173
|
|
-
|
174
|
|
- /* Open URI */
|
175
|
|
- pxe_single_fd = open ( uri_string );
|
176
|
|
- if ( pxe_single_fd < 0 ) {
|
177
|
|
- tftp_open->Status = PXENV_STATUS ( pxe_single_fd );
|
|
255
|
+ pxe_tftp_close ( 0 );
|
|
256
|
+
|
|
257
|
+ /* Open connection */
|
|
258
|
+ if ( ( rc = pxe_tftp_open ( tftp_open->ServerIPAddress,
|
|
259
|
+ tftp_open->TFTPPort,
|
|
260
|
+ tftp_open->FileName,
|
|
261
|
+ tftp_open->PacketSize ) ) != 0 ) {
|
|
262
|
+ tftp_open->Status = PXENV_STATUS ( rc );
|
178
|
263
|
return PXENV_EXIT_FAILURE;
|
179
|
264
|
}
|
180
|
265
|
|
181
|
|
- /* Record parameters for later use */
|
182
|
|
- pxe_single_blksize = tftp_open->PacketSize;
|
183
|
|
- pxe_single_blkidx = 0;
|
|
266
|
+ /* Wait for OACK to arrive so that we have the block size */
|
|
267
|
+ while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
|
|
268
|
+ ( pxe_tftp.blksize == 0 ) ) {
|
|
269
|
+ step();
|
|
270
|
+ }
|
|
271
|
+ tftp_open->PacketSize = pxe_tftp.blksize;
|
|
272
|
+
|
|
273
|
+ /* EINPROGRESS is normal; we don't wait for the whole transfer */
|
|
274
|
+ if ( rc == -EINPROGRESS )
|
|
275
|
+ rc = 0;
|
184
|
276
|
|
185
|
|
- tftp_open->Status = PXENV_STATUS_SUCCESS;
|
186
|
|
- return PXENV_EXIT_SUCCESS;
|
|
277
|
+ tftp_open->Status = PXENV_STATUS ( rc );
|
|
278
|
+ return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
|
187
|
279
|
}
|
188
|
280
|
|
189
|
281
|
/**
|
|
@@ -206,8 +298,7 @@ PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) {
|
206
|
298
|
PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close ) {
|
207
|
299
|
DBG ( "PXENV_TFTP_CLOSE" );
|
208
|
300
|
|
209
|
|
- close ( pxe_single_fd );
|
210
|
|
- pxe_single_fd = -1;
|
|
301
|
+ pxe_tftp_close ( 0 );
|
211
|
302
|
tftp_close->Status = PXENV_STATUS_SUCCESS;
|
212
|
303
|
return PXENV_EXIT_SUCCESS;
|
213
|
304
|
}
|
|
@@ -274,25 +365,29 @@ PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close ) {
|
274
|
365
|
* @ref pxe_x86_pmode16 "implementation note" for more details.)
|
275
|
366
|
*/
|
276
|
367
|
PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) {
|
277
|
|
- userptr_t buffer;
|
278
|
|
- ssize_t len;
|
|
368
|
+ int rc;
|
279
|
369
|
|
280
|
370
|
DBG ( "PXENV_TFTP_READ to %04x:%04x",
|
281
|
371
|
tftp_read->Buffer.segment, tftp_read->Buffer.offset );
|
282
|
372
|
|
283
|
|
- buffer = real_to_user ( tftp_read->Buffer.segment,
|
284
|
|
- tftp_read->Buffer.offset );
|
285
|
|
- len = pxe_tftp_read_all ( pxe_single_fd, buffer, pxe_single_blksize );
|
286
|
|
- if ( len < 0 ) {
|
287
|
|
- tftp_read->Status = PXENV_STATUS ( len );
|
288
|
|
- return PXENV_EXIT_FAILURE;
|
289
|
|
- }
|
290
|
|
-
|
291
|
|
- tftp_read->BufferSize = len;
|
292
|
|
- tftp_read->PacketNumber = ++pxe_single_blkidx;
|
293
|
|
-
|
294
|
|
- tftp_read->Status = PXENV_STATUS_SUCCESS;
|
295
|
|
- return PXENV_EXIT_SUCCESS;
|
|
373
|
+ /* Read single block into buffer */
|
|
374
|
+ pxe_tftp.buffer = real_to_user ( tftp_read->Buffer.segment,
|
|
375
|
+ tftp_read->Buffer.offset );
|
|
376
|
+ pxe_tftp.size = pxe_tftp.blksize;
|
|
377
|
+ pxe_tftp.start = pxe_tftp.offset;
|
|
378
|
+ while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
|
|
379
|
+ ( pxe_tftp.offset == pxe_tftp.start ) )
|
|
380
|
+ step();
|
|
381
|
+ pxe_tftp.buffer = UNULL;
|
|
382
|
+ tftp_read->BufferSize = ( pxe_tftp.offset - pxe_tftp.start );
|
|
383
|
+ tftp_read->PacketNumber = ++pxe_tftp.blkidx;
|
|
384
|
+
|
|
385
|
+ /* EINPROGRESS is normal if we haven't reached EOF yet */
|
|
386
|
+ if ( rc == -EINPROGRESS )
|
|
387
|
+ rc = 0;
|
|
388
|
+
|
|
389
|
+ tftp_read->Status = PXENV_STATUS ( rc );
|
|
390
|
+ return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
|
296
|
391
|
}
|
297
|
392
|
|
298
|
393
|
/**
|
|
@@ -388,40 +483,31 @@ PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) {
|
388
|
483
|
*/
|
389
|
484
|
PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
|
390
|
485
|
*tftp_read_file ) {
|
391
|
|
- char uri_string[PXE_URI_LEN];
|
392
|
|
- int fd;
|
393
|
|
- userptr_t buffer;
|
394
|
|
- ssize_t len;
|
395
|
|
- int rc = 0;
|
396
|
|
-
|
397
|
|
- DBG ( "PXENV_TFTP_READ_FILE" );
|
398
|
|
-
|
399
|
|
- /* Construct URI */
|
400
|
|
- pxe_tftp_build_uri ( uri_string, tftp_read_file->ServerIPAddress,
|
401
|
|
- tftp_read_file->TFTPSrvPort,
|
402
|
|
- tftp_read_file->FileName, 0 );
|
403
|
|
- DBG ( " %s", uri_string );
|
|
486
|
+ int rc;
|
404
|
487
|
|
405
|
|
- DBG ( " to %08lx+%lx", tftp_read_file->Buffer,
|
|
488
|
+ DBG ( "PXENV_TFTP_READ_FILE to %08lx+%lx", tftp_read_file->Buffer,
|
406
|
489
|
tftp_read_file->BufferSize );
|
407
|
490
|
|
408
|
|
- /* Open URI */
|
409
|
|
- fd = open ( uri_string );
|
410
|
|
- if ( fd < 0 ) {
|
411
|
|
- tftp_read_file->Status = PXENV_STATUS ( fd );
|
|
491
|
+ /* Open TFTP file */
|
|
492
|
+ if ( ( rc = pxe_tftp_open ( tftp_read_file->ServerIPAddress, 0,
|
|
493
|
+ tftp_read_file->FileName, 0 ) ) != 0 ) {
|
|
494
|
+ tftp_read_file->Status = PXENV_STATUS ( rc );
|
412
|
495
|
return PXENV_EXIT_FAILURE;
|
413
|
496
|
}
|
414
|
497
|
|
415
|
|
- /* Read file */
|
416
|
|
- buffer = phys_to_user ( tftp_read_file->Buffer );
|
417
|
|
- len = pxe_tftp_read_all ( fd, buffer, tftp_read_file->BufferSize );
|
418
|
|
- if ( len < 0 )
|
419
|
|
- rc = len;
|
|
498
|
+ /* Read entire file */
|
|
499
|
+ pxe_tftp.buffer = phys_to_user ( tftp_read_file->Buffer );
|
|
500
|
+ pxe_tftp.size = tftp_read_file->BufferSize;
|
|
501
|
+ while ( ( rc = pxe_tftp.rc ) == -EINPROGRESS )
|
|
502
|
+ step();
|
|
503
|
+ pxe_tftp.buffer = UNULL;
|
|
504
|
+ tftp_read_file->BufferSize = pxe_tftp.max_offset;
|
|
505
|
+
|
|
506
|
+ /* Close TFTP file */
|
|
507
|
+ pxe_tftp_close ( rc );
|
420
|
508
|
|
421
|
|
- close ( fd );
|
422
|
|
- tftp_read_file->BufferSize = len;
|
423
|
509
|
tftp_read_file->Status = PXENV_STATUS ( rc );
|
424
|
|
- return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
|
|
510
|
+ return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
|
425
|
511
|
}
|
426
|
512
|
|
427
|
513
|
/**
|
|
@@ -468,33 +554,31 @@ PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
|
468
|
554
|
*/
|
469
|
555
|
PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE
|
470
|
556
|
*tftp_get_fsize ) {
|
471
|
|
- char uri_string[PXE_URI_LEN];
|
472
|
|
- int fd;
|
473
|
|
- ssize_t size;
|
|
557
|
+ int rc;
|
474
|
558
|
|
475
|
559
|
DBG ( "PXENV_TFTP_GET_FSIZE" );
|
476
|
560
|
|
477
|
|
- /* Construct URI */
|
478
|
|
- pxe_tftp_build_uri ( uri_string, tftp_get_fsize->ServerIPAddress,
|
479
|
|
- 0, tftp_get_fsize->FileName, 0 );
|
480
|
|
- DBG ( " %s", uri_string );
|
481
|
|
-
|
482
|
|
- /* Open URI */
|
483
|
|
- fd = open ( uri_string );
|
484
|
|
- if ( fd < 0 ) {
|
485
|
|
- tftp_get_fsize->Status = PXENV_STATUS ( fd );
|
|
561
|
+ /* Open TFTP file */
|
|
562
|
+ if ( ( rc = pxe_tftp_open ( tftp_get_fsize->ServerIPAddress, 0,
|
|
563
|
+ tftp_get_fsize->FileName, 0 ) ) != 0 ) {
|
|
564
|
+ tftp_get_fsize->Status = PXENV_STATUS ( rc );
|
486
|
565
|
return PXENV_EXIT_FAILURE;
|
487
|
566
|
}
|
488
|
567
|
|
489
|
|
- /* Determine size */
|
490
|
|
- size = fsize ( fd );
|
491
|
|
- close ( fd );
|
492
|
|
- if ( size < 0 ) {
|
493
|
|
- tftp_get_fsize->Status = PXENV_STATUS ( size );
|
494
|
|
- return PXENV_EXIT_FAILURE;
|
|
568
|
+ /* Wait for initial seek to arrive, and record size */
|
|
569
|
+ while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
|
|
570
|
+ ( pxe_tftp.max_offset == 0 ) ) {
|
|
571
|
+ step();
|
495
|
572
|
}
|
|
573
|
+ tftp_get_fsize->FileSize = pxe_tftp.max_offset;
|
496
|
574
|
|
497
|
|
- tftp_get_fsize->FileSize = size;
|
498
|
|
- tftp_get_fsize->Status = PXENV_STATUS_SUCCESS;
|
499
|
|
- return PXENV_EXIT_SUCCESS;
|
|
575
|
+ /* EINPROGRESS is normal; we don't wait for the whole transfer */
|
|
576
|
+ if ( rc == -EINPROGRESS )
|
|
577
|
+ rc = 0;
|
|
578
|
+
|
|
579
|
+ /* Close TFTP file */
|
|
580
|
+ pxe_tftp_close ( rc );
|
|
581
|
+
|
|
582
|
+ tftp_get_fsize->Status = PXENV_STATUS ( rc );
|
|
583
|
+ return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
|
500
|
584
|
}
|