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