handlers.c revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
1/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
6#include "handlers.h"
7
8#include <assert.h>
9#include <errno.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14#include <sys/types.h>
15#include <sys/stat.h>
16
17#include "nacl_io_demo.h"
18
19#define MAX_OPEN_FILES 10
20
21#if defined(WIN32)
22#define stat _stat
23#endif
24
25/**
26 * A mapping from int -> FILE*, so the JavaScript messages can refer to an open
27 * File. */
28static FILE* g_OpenFiles[MAX_OPEN_FILES];
29
30/**
31 * Add the file to the g_OpenFiles map.
32 * @param[in] file The file to add to g_OpenFiles.
33 * @return int The index of the FILE in g_OpenFiles, or -1 if there are too many
34 *     open files. */
35static int AddFileToMap(FILE* file) {
36  int i;
37  assert(file != NULL);
38  for (i = 0; i < MAX_OPEN_FILES; ++i) {
39    if (g_OpenFiles[i] == NULL) {
40      g_OpenFiles[i] = file;
41      return i;
42    }
43  }
44
45  return -1;
46}
47
48/**
49 * Remove the file from the g_OpenFiles map.
50 * @param[in] i The index of the file handle to remove. */
51static void RemoveFileFromMap(int i) {
52  assert(i >= 0 && i < MAX_OPEN_FILES);
53  g_OpenFiles[i] = NULL;
54}
55
56/**
57 * Get a file handle from the g_OpenFiles map.
58 * @param[in] i The index of the file handle to get.
59 * @return the FILE*, or NULL of there is no open file with that handle.
60 */
61static FILE* GetFileFromMap(int i) {
62  assert(i >= 0 && i < MAX_OPEN_FILES);
63  return g_OpenFiles[i];
64}
65
66/**
67 * Get a file, given a string containing the index.
68 * @param[in] s The string containing the file index.
69 * @param[out] file_index The file index of this file.
70 * @return The FILE* for this file, or NULL if the index is invalid. */
71static FILE* GetFileFromIndexString(const char* s, int* file_index) {
72  char* endptr;
73  int result = strtol(s, &endptr, 10);
74  if (endptr != s + strlen(s)) {
75    /* Garbage at the end of the number...? */
76    return NULL;
77  }
78
79  if (file_index)
80    *file_index = result;
81
82  return GetFileFromMap(result);
83}
84
85/**
86 * Handle a call to fopen() made by JavaScript.
87 *
88 * fopen expects 2 parameters:
89 *   0: the path of the file to open
90 *   1: the mode string
91 * on success, fopen returns a result in |output| separated by \1:
92 *   0: "fopen"
93 *   1: the filename opened
94 *   2: the file index
95 * on failure, fopen returns an error string in |output|.
96 *
97 * @param[in] num_params The number of params in |params|.
98 * @param[in] params An array of strings, parameters to this function.
99 * @param[out] output A string to write informational function output to.
100 * @return An errorcode; 0 means success, anything else is a failure. */
101int HandleFopen(int num_params, char** params, char** output) {
102  FILE* file;
103  int file_index;
104  const char* filename;
105  const char* mode;
106
107  if (num_params != 2) {
108    *output = PrintfToNewString("Error: fopen takes 2 parameters.");
109    return 1;
110  }
111
112  filename = params[0];
113  mode = params[1];
114
115  file = fopen(filename, mode);
116  if (!file) {
117    *output = PrintfToNewString("Error: fopen returned a NULL FILE*.");
118    return 2;
119  }
120
121  file_index = AddFileToMap(file);
122  if (file_index == -1) {
123    *output = PrintfToNewString(
124        "Error: Example only allows %d open file handles.", MAX_OPEN_FILES);
125    return 3;
126  }
127
128  *output = PrintfToNewString("fopen\1%s\1%d", filename, file_index);
129  return 0;
130}
131
132/**
133 * Handle a call to fwrite() made by JavaScript.
134 *
135 * fwrite expects 2 parameters:
136 *   0: The index of the file (which is mapped to a FILE*)
137 *   1: A string to write to the file
138 * on success, fwrite returns a result in |output| separated by \1:
139 *   0: "fwrite"
140 *   1: the file index
141 *   2: the number of bytes written
142 * on failure, fwrite returns an error string in |output|.
143 *
144 * @param[in] num_params The number of params in |params|.
145 * @param[in] params An array of strings, parameters to this function.
146 * @param[out] output A string to write informational function output to.
147 * @return An errorcode; 0 means success, anything else is a failure. */
148int HandleFwrite(int num_params, char** params, char** output) {
149  FILE* file;
150  const char* file_index_string;
151  const char* data;
152  size_t data_len;
153  size_t bytes_written;
154
155  if (num_params != 2) {
156    *output = PrintfToNewString("Error: fwrite takes 2 parameters.");
157    return 1;
158  }
159
160  file_index_string = params[0];
161  file = GetFileFromIndexString(file_index_string, NULL);
162  data = params[1];
163  data_len = strlen(data);
164
165  if (!file) {
166    *output =
167        PrintfToNewString("Error: Unknown file handle %s.", file_index_string);
168    return 2;
169  }
170
171  bytes_written = fwrite(data, 1, data_len, file);
172
173  if (ferror(file)) {
174    *output = PrintfToNewString(
175        "Error: Wrote %d bytes, but ferror() returns true.", bytes_written);
176    return 3;
177  }
178
179  *output =
180      PrintfToNewString("fwrite\1%s\1%d", file_index_string, bytes_written);
181  return 0;
182}
183
184/**
185 * Handle a call to fread() made by JavaScript.
186 *
187 * fread expects 2 parameters:
188 *   0: The index of the file (which is mapped to a FILE*)
189 *   1: The number of bytes to read from the file.
190 * on success, fread returns a result in |output| separated by \1:
191 *   0: "fread"
192 *   1: the file index
193 *   2: the data read from the file
194 * on failure, fread returns an error string in |output|.
195 *
196 * @param[in] num_params The number of params in |params|.
197 * @param[in] params An array of strings, parameters to this function.
198 * @param[out] output A string to write informational function output to.
199 * @return An errorcode; 0 means success, anything else is a failure. */
200int HandleFread(int num_params, char** params, char** output) {
201  FILE* file;
202  const char* file_index_string;
203  char* buffer;
204  size_t data_len;
205  size_t bytes_read;
206
207  if (num_params != 2) {
208    *output = PrintfToNewString("Error: fread takes 2 parameters.");
209    return 1;
210  }
211
212  file_index_string = params[0];
213  file = GetFileFromIndexString(file_index_string, NULL);
214  data_len = strtol(params[1], NULL, 10);
215
216  if (!file) {
217    *output =
218        PrintfToNewString("Error: Unknown file handle %s.", file_index_string);
219    return 2;
220  }
221
222  buffer = (char*)malloc(data_len + 1);
223  bytes_read = fread(buffer, 1, data_len, file);
224  buffer[bytes_read] = 0;
225
226  if (ferror(file)) {
227    *output = PrintfToNewString(
228        "Error: Read %d bytes, but ferror() returns true.", bytes_read);
229    return 3;
230  }
231
232  *output = PrintfToNewString("fread\1%s\1%s", file_index_string, buffer);
233  free(buffer);
234  return 0;
235}
236
237/**
238 * Handle a call to fseek() made by JavaScript.
239 *
240 * fseek expects 3 parameters:
241 *   0: The index of the file (which is mapped to a FILE*)
242 *   1: The offset to seek to
243 *   2: An integer representing the whence parameter of standard fseek.
244 *      whence = 0: seek from the beginning of the file
245 *      whence = 1: seek from the current file position
246 *      whence = 2: seek from the end of the file
247 * on success, fseek returns a result in |output| separated by \1:
248 *   0: "fseek"
249 *   1: the file index
250 *   2: The new file position
251 * on failure, fseek returns an error string in |output|.
252 *
253 * @param[in] num_params The number of params in |params|.
254 * @param[in] params An array of strings, parameters to this function.
255 * @param[out] output A string to write informational function output to.
256 * @return An errorcode; 0 means success, anything else is a failure. */
257int HandleFseek(int num_params, char** params, char** output) {
258  FILE* file;
259  const char* file_index_string;
260  long offset;
261  int whence;
262  int result;
263
264  if (num_params != 3) {
265    *output = PrintfToNewString("Error: fseek takes 3 parameters.");
266    return 1;
267  }
268
269  file_index_string = params[0];
270  file = GetFileFromIndexString(file_index_string, NULL);
271  offset = strtol(params[1], NULL, 10);
272  whence = strtol(params[2], NULL, 10);
273
274  if (!file) {
275    *output =
276        PrintfToNewString("Error: Unknown file handle %s.", file_index_string);
277    return 2;
278  }
279
280  result = fseek(file, offset, whence);
281  if (result) {
282    *output = PrintfToNewString("Error: fseek returned error %d.", result);
283    return 3;
284  }
285
286  offset = ftell(file);
287  if (offset < 0) {
288    *output = PrintfToNewString(
289        "Error: fseek succeeded, but ftell returned error %d.", offset);
290    return 4;
291  }
292
293  *output = PrintfToNewString("fseek\1%s\1%d", file_index_string, offset);
294  return 0;
295}
296
297/**
298 * Handle a call to fclose() made by JavaScript.
299 *
300 * fclose expects 1 parameter:
301 *   0: The index of the file (which is mapped to a FILE*)
302 * on success, fclose returns a result in |output| separated by \1:
303 *   0: "fclose"
304 *   1: the file index
305 * on failure, fclose returns an error string in |output|.
306 *
307 * @param[in] num_params The number of params in |params|.
308 * @param[in] params An array of strings, parameters to this function.
309 * @param[out] output A string to write informational function output to.
310 * @return An errorcode; 0 means success, anything else is a failure. */
311int HandleFclose(int num_params, char** params, char** output) {
312  FILE* file;
313  int file_index;
314  const char* file_index_string;
315  int result;
316
317  if (num_params != 1) {
318    *output = PrintfToNewString("Error: fclose takes 1 parameters.");
319    return 1;
320  }
321
322  file_index_string = params[0];
323  file = GetFileFromIndexString(file_index_string, &file_index);
324  if (!file) {
325    *output =
326        PrintfToNewString("Error: Unknown file handle %s.", file_index_string);
327    return 2;
328  }
329
330  result = fclose(file);
331  if (result) {
332    *output = PrintfToNewString("Error: fclose returned error %d.", result);
333    return 3;
334  }
335
336  RemoveFileFromMap(file_index);
337
338  *output = PrintfToNewString("fclose\1%s", file_index_string);
339  return 0;
340}
341
342/**
343 * Handle a call to stat() made by JavaScript.
344 *
345 * stat expects 1 parameter:
346 *   0: The name of the file
347 * on success, stat returns a result in |output| separated by \1:
348 *   0: "stat"
349 *   1: the file name
350 *   2: the size of the file
351 * on failure, stat returns an error string in |output|.
352 *
353 * @param[in] num_params The number of params in |params|.
354 * @param[in] params An array of strings, parameters to this function.
355 * @param[out] output A string to write informational function output to.
356 * @return An errorcode; 0 means success, anything else is a failure. */
357int HandleStat(int num_params, char** params, char** output) {
358  FILE* file;
359  int file_index;
360  const char* filename;
361  const char* mode;
362  int result;
363  struct stat buf;
364
365  if (num_params != 1) {
366    *output = PrintfToNewString("Error: stat takes 1 parameter.");
367    return 1;
368  }
369
370  filename = params[0];
371
372  memset(&buf, 0, sizeof(buf));
373  result = stat(filename, &buf);
374  if (result == -1) {
375    *output = PrintfToNewString("Error: stat returned error %d.", errno);
376    return 2;
377  }
378
379  *output = PrintfToNewString("stat\1%s\1%d", filename, buf.st_size);
380  return 0;
381}
382