Parent Directory
|
Revision Log
Update SpiderMonkey from Firefox 3.6rc1.
1 | siliconforks | 507 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 | siliconforks | 332 | * vim: set ts=8 sw=4 et tw=78: |
3 | * | ||
4 | * ***** BEGIN LICENSE BLOCK ***** | ||
5 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | ||
6 | * | ||
7 | * The contents of this file are subject to the Mozilla Public License Version | ||
8 | * 1.1 (the "License"); you may not use this file except in compliance with | ||
9 | * the License. You may obtain a copy of the License at | ||
10 | * http://www.mozilla.org/MPL/ | ||
11 | * | ||
12 | * Software distributed under the License is distributed on an "AS IS" basis, | ||
13 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | ||
14 | * for the specific language governing rights and limitations under the | ||
15 | * License. | ||
16 | * | ||
17 | * The Original Code is Mozilla Communicator client code, released | ||
18 | * March 31, 1998. | ||
19 | * | ||
20 | * The Initial Developer of the Original Code is | ||
21 | * Netscape Communications Corporation. | ||
22 | * Portions created by the Initial Developer are Copyright (C) 1998 | ||
23 | * the Initial Developer. All Rights Reserved. | ||
24 | * | ||
25 | * Contributor(s): | ||
26 | * | ||
27 | * Alternatively, the contents of this file may be used under the terms of | ||
28 | * either of the GNU General Public License Version 2 or later (the "GPL"), | ||
29 | * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), | ||
30 | * in which case the provisions of the GPL or the LGPL are applicable instead | ||
31 | * of those above. If you wish to allow use of your version of this file only | ||
32 | * under the terms of either the GPL or the LGPL, and not to allow others to | ||
33 | * use your version of this file under the terms of the MPL, indicate your | ||
34 | * decision by deleting the provisions above and replace them with the notice | ||
35 | * and other provisions required by the GPL or the LGPL. If you do not delete | ||
36 | * the provisions above, a recipient may use your version of this file under | ||
37 | * the terms of any one of the MPL, the GPL or the LGPL. | ||
38 | * | ||
39 | * ***** END LICENSE BLOCK ***** */ | ||
40 | |||
41 | /* | ||
42 | * JS File object | ||
43 | */ | ||
44 | #if JS_HAS_FILE_OBJECT | ||
45 | |||
46 | #include "jsfile.h" | ||
47 | siliconforks | 507 | #include "jsstdint.h" |
48 | siliconforks | 332 | |
49 | /* ----------------- Platform-specific includes and defines ----------------- */ | ||
50 | #if defined(XP_WIN) || defined(XP_OS2) | ||
51 | # include <direct.h> | ||
52 | # include <io.h> | ||
53 | # include <sys/types.h> | ||
54 | # include <sys/stat.h> | ||
55 | # define FILESEPARATOR '\\' | ||
56 | # define FILESEPARATOR2 '/' | ||
57 | # define CURRENT_DIR "c:\\" | ||
58 | # define POPEN _popen | ||
59 | # define PCLOSE _pclose | ||
60 | siliconforks | 460 | #elif defined(SYMBIAN) |
61 | # include <strings.h> | ||
62 | # include <stdio.h> | ||
63 | # include <stdlib.h> | ||
64 | # include <unistd.h> | ||
65 | # include <limits.h> | ||
66 | # define FILESEPARATOR '\\' | ||
67 | # define FILESEPARATOR2 '/' | ||
68 | # define CURRENT_DIR "c:\\" | ||
69 | # define POPEN popen | ||
70 | # define PCLOSE pclose | ||
71 | siliconforks | 332 | #elif defined(XP_UNIX) || defined(XP_BEOS) |
72 | # include <strings.h> | ||
73 | # include <stdio.h> | ||
74 | # include <stdlib.h> | ||
75 | # include <unistd.h> | ||
76 | siliconforks | 507 | # include <limits.h> |
77 | siliconforks | 332 | # define FILESEPARATOR '/' |
78 | # define FILESEPARATOR2 '\0' | ||
79 | # define CURRENT_DIR "/" | ||
80 | # define POPEN popen | ||
81 | # define PCLOSE pclose | ||
82 | #endif | ||
83 | |||
84 | /* --------------- Platform-independent includes and defines ---------------- */ | ||
85 | #include "jsapi.h" | ||
86 | #include "jsatom.h" | ||
87 | #include "jscntxt.h" | ||
88 | #include "jsdate.h" | ||
89 | #include "jsdbgapi.h" | ||
90 | #include "jsemit.h" | ||
91 | #include "jsfun.h" | ||
92 | #include "jslock.h" | ||
93 | #include "jsobj.h" | ||
94 | #include "jsparse.h" | ||
95 | #include "jsscan.h" | ||
96 | #include "jsscope.h" | ||
97 | #include "jsscript.h" | ||
98 | #include "jsstr.h" | ||
99 | #include "jsutil.h" /* Added by JSIFY */ | ||
100 | #include <string.h> | ||
101 | |||
102 | /* NSPR dependencies */ | ||
103 | #include "prio.h" | ||
104 | #include "prerror.h" | ||
105 | |||
106 | #define SPECIAL_FILE_STRING "Special File" | ||
107 | #define CURRENTDIR_PROPERTY "currentDir" | ||
108 | #define SEPARATOR_PROPERTY "separator" | ||
109 | #define FILE_CONSTRUCTOR "File" | ||
110 | #define PIPE_SYMBOL '|' | ||
111 | |||
112 | #define ASCII 0 | ||
113 | #define UTF8 1 | ||
114 | #define UCS2 2 | ||
115 | |||
116 | #define asciistring "text" | ||
117 | #define utfstring "binary" | ||
118 | #define unicodestring "unicode" | ||
119 | |||
120 | siliconforks | 507 | #ifdef PATH_MAX |
121 | #define MAX_PATH_LENGTH PATH_MAX | ||
122 | #else | ||
123 | siliconforks | 332 | #define MAX_PATH_LENGTH 1024 |
124 | siliconforks | 507 | #endif |
125 | siliconforks | 332 | #define MODE_SIZE 256 |
126 | #define NUMBER_SIZE 32 | ||
127 | #define MAX_LINE_LENGTH 256 | ||
128 | #define URL_PREFIX "file://" | ||
129 | |||
130 | #define STDINPUT_NAME "Standard input stream" | ||
131 | #define STDOUTPUT_NAME "Standard output stream" | ||
132 | #define STDERROR_NAME "Standard error stream" | ||
133 | |||
134 | #define RESOLVE_PATH js_canonicalPath /* js_absolutePath */ | ||
135 | |||
136 | /* Error handling */ | ||
137 | typedef enum JSFileErrNum { | ||
138 | #define MSG_DEF(name, number, count, exception, format) \ | ||
139 | name = number, | ||
140 | #include "jsfile.msg" | ||
141 | #undef MSG_DEF | ||
142 | JSFileErr_Limit | ||
143 | #undef MSGDEF | ||
144 | } JSFileErrNum; | ||
145 | |||
146 | #define JSFILE_HAS_DFLT_MSG_STRINGS 1 | ||
147 | |||
148 | JSErrorFormatString JSFile_ErrorFormatString[JSFileErr_Limit] = { | ||
149 | #if JSFILE_HAS_DFLT_MSG_STRINGS | ||
150 | #define MSG_DEF(name, number, count, exception, format) \ | ||
151 | { format, count }, | ||
152 | #else | ||
153 | #define MSG_DEF(name, number, count, exception, format) \ | ||
154 | { NULL, count }, | ||
155 | #endif | ||
156 | #include "jsfile.msg" | ||
157 | #undef MSG_DEF | ||
158 | }; | ||
159 | |||
160 | const JSErrorFormatString * | ||
161 | JSFile_GetErrorMessage(void *userRef, const char *locale, | ||
162 | const uintN errorNumber) | ||
163 | { | ||
164 | if ((errorNumber > 0) && (errorNumber < JSFileErr_Limit)) | ||
165 | return &JSFile_ErrorFormatString[errorNumber]; | ||
166 | else | ||
167 | return NULL; | ||
168 | } | ||
169 | |||
170 | #define JSFILE_CHECK_NATIVE(op) \ | ||
171 | if (file->isNative) { \ | ||
172 | JS_ReportWarning(cx, "Cannot call or access \"%s\" on native file %s",\ | ||
173 | op, file->path); \ | ||
174 | goto out; \ | ||
175 | } | ||
176 | |||
177 | #define JSFILE_CHECK_WRITE \ | ||
178 | if (!file->isOpen) { \ | ||
179 | JS_ReportWarning(cx, \ | ||
180 | "File %s is closed, will open it for writing, proceeding", \ | ||
181 | file->path); \ | ||
182 | js_FileOpen(cx, obj, file, "write,append,create"); \ | ||
183 | } \ | ||
184 | if (!js_canWrite(cx, file)) { \ | ||
185 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \ | ||
186 | JSFILEMSG_CANNOT_WRITE, file->path); \ | ||
187 | goto out; \ | ||
188 | } | ||
189 | |||
190 | #define JSFILE_CHECK_READ \ | ||
191 | if (!file->isOpen) { \ | ||
192 | JS_ReportWarning(cx, \ | ||
193 | "File %s is closed, will open it for reading, proceeding", \ | ||
194 | file->path); \ | ||
195 | js_FileOpen(cx, obj, file, "read"); \ | ||
196 | } \ | ||
197 | if (!js_canRead(cx, file)) { \ | ||
198 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \ | ||
199 | JSFILEMSG_CANNOT_READ, file->path); \ | ||
200 | goto out; \ | ||
201 | } | ||
202 | |||
203 | #define JSFILE_CHECK_OPEN(op) \ | ||
204 | if (!file->isOpen) { \ | ||
205 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \ | ||
206 | JSFILEMSG_FILE_MUST_BE_OPEN, op); \ | ||
207 | goto out; \ | ||
208 | } | ||
209 | |||
210 | #define JSFILE_CHECK_CLOSED(op) \ | ||
211 | if (file->isOpen) { \ | ||
212 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \ | ||
213 | JSFILEMSG_FILE_MUST_BE_CLOSED, op); \ | ||
214 | goto out; \ | ||
215 | } | ||
216 | |||
217 | #define JSFILE_CHECK_ONE_ARG(op) \ | ||
218 | if (argc != 1) { \ | ||
219 | char str[NUMBER_SIZE]; \ | ||
220 | sprintf(str, "%d", argc); \ | ||
221 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \ | ||
222 | JSFILEMSG_EXPECTS_ONE_ARG_ERROR, op, str); \ | ||
223 | goto out; \ | ||
224 | } | ||
225 | |||
226 | |||
227 | /* | ||
228 | Security mechanism, should define a callback for this. | ||
229 | The parameters are as follows: | ||
230 | SECURITY_CHECK(JSContext *cx, JSPrincipals *ps, char *op_name, JSFile *file) | ||
231 | XXX Should this be a real function returning a JSBool result (and getting | ||
232 | some typesafety help from the compiler?). | ||
233 | */ | ||
234 | #define SECURITY_CHECK(cx, ps, op, file) \ | ||
235 | /* Define a callback here... */ | ||
236 | |||
237 | |||
238 | /* Structure representing the file internally */ | ||
239 | typedef struct JSFile { | ||
240 | char *path; /* the path to the file. */ | ||
241 | JSBool isOpen; | ||
242 | int32 mode; /* mode used to open the file: read, write, append, create, etc.. */ | ||
243 | int32 type; /* Asciiz, utf, unicode */ | ||
244 | char byteBuffer[3]; /* bytes read in advance by js_FileRead ( UTF8 encoding ) */ | ||
245 | jsint nbBytesInBuf; /* number of bytes stored in the buffer above */ | ||
246 | jschar charBuffer; /* character read in advance by readln ( mac files only ) */ | ||
247 | JSBool charBufferUsed; /* flag indicating if the buffer above is being used */ | ||
248 | JSBool hasRandomAccess;/* can the file be randomly accessed? false for stdin, and | ||
249 | UTF-encoded files. */ | ||
250 | JSBool hasAutoflush; /* should we force a flush for each line break? */ | ||
251 | JSBool isNative; /* if the file is using OS-specific file FILE type */ | ||
252 | /* We can actually put the following two in a union since they should never be used at the same time */ | ||
253 | PRFileDesc *handle; /* the handle for the file, if open. */ | ||
254 | FILE *nativehandle; /* native handle, for stuff NSPR doesn't do. */ | ||
255 | JSBool isPipe; /* if the file is really an OS pipe */ | ||
256 | } JSFile; | ||
257 | |||
258 | /* a few forward declarations... */ | ||
259 | JS_PUBLIC_API(JSObject*) js_NewFileObject(JSContext *cx, char *filename); | ||
260 | static JSBool file_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); | ||
261 | static JSBool file_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); | ||
262 | |||
263 | /* New filename manipulation procesures */ | ||
264 | /* assumes we don't have leading/trailing spaces */ | ||
265 | static JSBool | ||
266 | js_filenameHasAPipe(const char *filename) | ||
267 | { | ||
268 | if (!filename) | ||
269 | return JS_FALSE; | ||
270 | |||
271 | return filename[0] == PIPE_SYMBOL || | ||
272 | filename[strlen(filename) - 1] == PIPE_SYMBOL; | ||
273 | } | ||
274 | |||
275 | static JSBool | ||
276 | js_isAbsolute(const char *name) | ||
277 | { | ||
278 | siliconforks | 460 | #if defined(XP_WIN) || defined(XP_OS2) || defined(SYMBIAN) |
279 | siliconforks | 332 | return *name && name[1] == ':'; |
280 | #else | ||
281 | return (name[0] | ||
282 | # if defined(XP_UNIX) || defined(XP_BEOS) | ||
283 | == | ||
284 | # else | ||
285 | != | ||
286 | # endif | ||
287 | FILESEPARATOR); | ||
288 | #endif | ||
289 | } | ||
290 | |||
291 | /* | ||
292 | * Concatenates base and name to produce a valid filename. | ||
293 | * Returned string must be freed. | ||
294 | */ | ||
295 | static char* | ||
296 | js_combinePath(JSContext *cx, const char *base, const char *name) | ||
297 | { | ||
298 | int len = strlen(base); | ||
299 | siliconforks | 507 | char* result = cx->malloc(len + strlen(name) + 2); |
300 | siliconforks | 332 | |
301 | if (!result) | ||
302 | return NULL; | ||
303 | |||
304 | strcpy(result, base); | ||
305 | |||
306 | if (base[len - 1] != FILESEPARATOR && base[len - 1] != FILESEPARATOR2) { | ||
307 | result[len] = FILESEPARATOR; | ||
308 | result[len + 1] = '\0'; | ||
309 | } | ||
310 | strcat(result, name); | ||
311 | return result; | ||
312 | } | ||
313 | |||
314 | /* Extract the last component from a path name. Returned string must be freed */ | ||
315 | static char * | ||
316 | js_fileBaseName(JSContext *cx, const char *pathname) | ||
317 | { | ||
318 | jsint index, aux; | ||
319 | char *result; | ||
320 | |||
321 | index = strlen(pathname)-1; | ||
322 | |||
323 | siliconforks | 507 | /* Chop off trailing separators. */ |
324 | siliconforks | 332 | while (index > 0 && (pathname[index]==FILESEPARATOR || |
325 | pathname[index]==FILESEPARATOR2)) { | ||
326 | --index; | ||
327 | } | ||
328 | |||
329 | aux = index; | ||
330 | |||
331 | /* Now find the next separator. */ | ||
332 | while (index >= 0 && pathname[index] != FILESEPARATOR && | ||
333 | pathname[index] != FILESEPARATOR2) { | ||
334 | --index; | ||
335 | } | ||
336 | |||
337 | /* Allocate and copy. */ | ||
338 | siliconforks | 507 | result = cx->malloc(aux - index + 1); |
339 | siliconforks | 332 | if (!result) |
340 | return NULL; | ||
341 | strncpy(result, pathname + index + 1, aux - index); | ||
342 | result[aux - index] = '\0'; | ||
343 | return result; | ||
344 | } | ||
345 | |||
346 | /* | ||
347 | * Returns everything but the last component from a path name. | ||
348 | * Returned string must be freed. | ||
349 | */ | ||
350 | static char * | ||
351 | js_fileDirectoryName(JSContext *cx, const char *pathname) | ||
352 | { | ||
353 | char *result; | ||
354 | const char *cp, *end; | ||
355 | size_t pathsize; | ||
356 | |||
357 | end = pathname + strlen(pathname); | ||
358 | cp = end - 1; | ||
359 | |||
360 | /* If this is already a directory, chop off the trailing /s. */ | ||
361 | while (cp >= pathname) { | ||
362 | if (*cp != FILESEPARATOR && *cp != FILESEPARATOR2) | ||
363 | break; | ||
364 | --cp; | ||
365 | } | ||
366 | |||
367 | if (cp < pathname && end != pathname) { | ||
368 | /* There were just /s, return the root. */ | ||
369 | siliconforks | 507 | result = cx->malloc(1 + 1); /* The separator + trailing NUL. */ |
370 | siliconforks | 332 | result[0] = FILESEPARATOR; |
371 | result[1] = '\0'; | ||
372 | return result; | ||
373 | } | ||
374 | |||
375 | /* Now chop off the last portion. */ | ||
376 | while (cp >= pathname) { | ||
377 | if (*cp == FILESEPARATOR || *cp == FILESEPARATOR2) | ||
378 | break; | ||
379 | --cp; | ||
380 | } | ||
381 | |||
382 | /* Check if this is a leaf. */ | ||
383 | if (cp < pathname) { | ||
384 | /* It is, return "pathname/". */ | ||
385 | if (end[-1] == FILESEPARATOR || end[-1] == FILESEPARATOR2) { | ||
386 | /* Already has its terminating /. */ | ||
387 | return JS_strdup(cx, pathname); | ||
388 | } | ||
389 | |||
390 | pathsize = end - pathname + 1; | ||
391 | siliconforks | 507 | result = cx->malloc(pathsize + 1); |
392 | siliconforks | 332 | if (!result) |
393 | return NULL; | ||
394 | |||
395 | strcpy(result, pathname); | ||
396 | result[pathsize - 1] = FILESEPARATOR; | ||
397 | result[pathsize] = '\0'; | ||
398 | |||
399 | return result; | ||
400 | } | ||
401 | |||
402 | /* Return everything up to and including the seperator. */ | ||
403 | pathsize = cp - pathname + 1; | ||
404 | siliconforks | 507 | result = cx->malloc(pathsize + 1); |
405 | siliconforks | 332 | if (!result) |
406 | return NULL; | ||
407 | |||
408 | strncpy(result, pathname, pathsize); | ||
409 | result[pathsize] = '\0'; | ||
410 | |||
411 | return result; | ||
412 | } | ||
413 | |||
414 | static char * | ||
415 | js_absolutePath(JSContext *cx, const char * path) | ||
416 | { | ||
417 | JSObject *obj; | ||
418 | JSString *str; | ||
419 | jsval prop; | ||
420 | |||
421 | if (js_isAbsolute(path)) { | ||
422 | return JS_strdup(cx, path); | ||
423 | } else { | ||
424 | obj = JS_GetGlobalObject(cx); | ||
425 | if (!JS_GetProperty(cx, obj, FILE_CONSTRUCTOR, &prop)) { | ||
426 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
427 | JSFILEMSG_FILE_CONSTRUCTOR_UNDEFINED_ERROR); | ||
428 | return JS_strdup(cx, path); | ||
429 | } | ||
430 | |||
431 | obj = JSVAL_TO_OBJECT(prop); | ||
432 | if (!JS_GetProperty(cx, obj, CURRENTDIR_PROPERTY, &prop)) { | ||
433 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
434 | JSFILEMSG_FILE_CURRENTDIR_UNDEFINED_ERROR); | ||
435 | return JS_strdup(cx, path); | ||
436 | } | ||
437 | |||
438 | str = JS_ValueToString(cx, prop); | ||
439 | if (!str) | ||
440 | return JS_strdup(cx, path); | ||
441 | |||
442 | /* should we have an array of curr dirs indexed by drive for windows? */ | ||
443 | return js_combinePath(cx, JS_GetStringBytes(str), path); | ||
444 | } | ||
445 | } | ||
446 | |||
447 | /* Side effect: will remove spaces in the beginning/end of the filename */ | ||
448 | static char * | ||
449 | js_canonicalPath(JSContext *cx, char *oldpath) | ||
450 | { | ||
451 | char *tmp; | ||
452 | char *path = oldpath; | ||
453 | char *base, *dir, *current, *result; | ||
454 | jsint c; | ||
455 | jsint back = 0; | ||
456 | unsigned int i = 0, j = strlen(path)-1; | ||
457 | |||
458 | /* This is probably optional */ | ||
459 | /* Remove possible spaces in the beginning and end */ | ||
460 | while (i < j && path[i] == ' ') | ||
461 | i++; | ||
462 | while (j >= 0 && path[j] == ' ') | ||
463 | j--; | ||
464 | |||
465 | siliconforks | 507 | tmp = cx->malloc(j-i+2); |
466 | siliconforks | 332 | if (!tmp) |
467 | return NULL; | ||
468 | |||
469 | strncpy(tmp, path + i, j - i + 1); | ||
470 | tmp[j - i + 1] = '\0'; | ||
471 | |||
472 | path = tmp; | ||
473 | |||
474 | /* Pipe support. */ | ||
475 | if (js_filenameHasAPipe(path)) | ||
476 | return path; | ||
477 | |||
478 | /* file:// support. */ | ||
479 | if (!strncmp(path, URL_PREFIX, strlen(URL_PREFIX))) { | ||
480 | tmp = js_canonicalPath(cx, path + strlen(URL_PREFIX)); | ||
481 | siliconforks | 507 | cx->free(path); |
482 | siliconforks | 332 | return tmp; |
483 | } | ||
484 | |||
485 | if (!js_isAbsolute(path)) { | ||
486 | tmp = js_absolutePath(cx, path); | ||
487 | if (!tmp) | ||
488 | return NULL; | ||
489 | siliconforks | 507 | cx->free(path); |
490 | siliconforks | 332 | path = tmp; |
491 | } | ||
492 | |||
493 | result = JS_strdup(cx, ""); | ||
494 | |||
495 | current = path; | ||
496 | |||
497 | base = js_fileBaseName(cx, current); | ||
498 | dir = js_fileDirectoryName(cx, current); | ||
499 | |||
500 | while (strcmp(dir, current)) { | ||
501 | if (!strcmp(base, "..")) { | ||
502 | back++; | ||
503 | } else { | ||
504 | if (back > 0) { | ||
505 | back--; | ||
506 | } else { | ||
507 | tmp = result; | ||
508 | siliconforks | 507 | result = cx->malloc(strlen(base) + 1 + strlen(tmp) + 1); |
509 | siliconforks | 332 | if (!result) |
510 | goto out; | ||
511 | |||
512 | strcpy(result, base); | ||
513 | c = strlen(result); | ||
514 | if (*tmp) { | ||
515 | result[c] = FILESEPARATOR; | ||
516 | result[c + 1] = '\0'; | ||
517 | strcat(result, tmp); | ||
518 | } | ||
519 | siliconforks | 507 | cx->free(tmp); |
520 | siliconforks | 332 | } |
521 | } | ||
522 | siliconforks | 507 | cx->free(current); |
523 | cx->free(base); | ||
524 | siliconforks | 332 | current = dir; |
525 | base = js_fileBaseName(cx, current); | ||
526 | dir = js_fileDirectoryName(cx, current); | ||
527 | } | ||
528 | |||
529 | tmp = result; | ||
530 | siliconforks | 507 | result = cx->malloc(strlen(dir) + 1 + strlen(tmp) + 1); |
531 | siliconforks | 332 | if (!result) |
532 | goto out; | ||
533 | |||
534 | strcpy(result, dir); | ||
535 | c = strlen(result); | ||
536 | if (tmp[0]!='\0') { | ||
537 | if ((result[c-1]!=FILESEPARATOR)&&(result[c-1]!=FILESEPARATOR2)) { | ||
538 | result[c] = FILESEPARATOR; | ||
539 | result[c+1] = '\0'; | ||
540 | } | ||
541 | strcat(result, tmp); | ||
542 | } | ||
543 | |||
544 | out: | ||
545 | if (tmp) | ||
546 | siliconforks | 507 | cx->free(tmp); |
547 | siliconforks | 332 | if (dir) |
548 | siliconforks | 507 | cx->free(dir); |
549 | siliconforks | 332 | if (base) |
550 | siliconforks | 507 | cx->free(base); |
551 | siliconforks | 332 | if (current) |
552 | siliconforks | 507 | cx->free(current); |
553 | siliconforks | 332 | |
554 | return result; | ||
555 | } | ||
556 | |||
557 | /* -------------------------- Text conversion ------------------------------- */ | ||
558 | /* The following is ripped from libi18n/unicvt.c and include files.. */ | ||
559 | |||
560 | /* | ||
561 | * UTF8 defines and macros | ||
562 | */ | ||
563 | #define ONE_OCTET_BASE 0x00 /* 0xxxxxxx */ | ||
564 | #define ONE_OCTET_MASK 0x7F /* x1111111 */ | ||
565 | #define CONTINUING_OCTET_BASE 0x80 /* 10xxxxxx */ | ||
566 | #define CONTINUING_OCTET_MASK 0x3F /* 00111111 */ | ||
567 | #define TWO_OCTET_BASE 0xC0 /* 110xxxxx */ | ||
568 | #define TWO_OCTET_MASK 0x1F /* 00011111 */ | ||
569 | #define THREE_OCTET_BASE 0xE0 /* 1110xxxx */ | ||
570 | #define THREE_OCTET_MASK 0x0F /* 00001111 */ | ||
571 | #define FOUR_OCTET_BASE 0xF0 /* 11110xxx */ | ||
572 | #define FOUR_OCTET_MASK 0x07 /* 00000111 */ | ||
573 | #define FIVE_OCTET_BASE 0xF8 /* 111110xx */ | ||
574 | #define FIVE_OCTET_MASK 0x03 /* 00000011 */ | ||
575 | #define SIX_OCTET_BASE 0xFC /* 1111110x */ | ||
576 | #define SIX_OCTET_MASK 0x01 /* 00000001 */ | ||
577 | |||
578 | #define IS_UTF8_1ST_OF_1(x) (( (x)&~ONE_OCTET_MASK ) == ONE_OCTET_BASE) | ||
579 | #define IS_UTF8_1ST_OF_2(x) (( (x)&~TWO_OCTET_MASK ) == TWO_OCTET_BASE) | ||
580 | #define IS_UTF8_1ST_OF_3(x) (( (x)&~THREE_OCTET_MASK) == THREE_OCTET_BASE) | ||
581 | #define IS_UTF8_1ST_OF_4(x) (( (x)&~FOUR_OCTET_MASK ) == FOUR_OCTET_BASE) | ||
582 | #define IS_UTF8_1ST_OF_5(x) (( (x)&~FIVE_OCTET_MASK ) == FIVE_OCTET_BASE) | ||
583 | #define IS_UTF8_1ST_OF_6(x) (( (x)&~SIX_OCTET_MASK ) == SIX_OCTET_BASE) | ||
584 | #define IS_UTF8_2ND_THRU_6TH(x) \ | ||
585 | (( (x)&~CONTINUING_OCTET_MASK ) == CONTINUING_OCTET_BASE) | ||
586 | #define IS_UTF8_1ST_OF_UCS2(x) \ | ||
587 | IS_UTF8_1ST_OF_1(x) \ | ||
588 | || IS_UTF8_1ST_OF_2(x) \ | ||
589 | || IS_UTF8_1ST_OF_3(x) | ||
590 | |||
591 | |||
592 | #define MAX_UCS2 0xFFFF | ||
593 | #define DEFAULT_CHAR 0x003F /* Default char is "?" */ | ||
594 | #define BYTE_MASK 0xBF | ||
595 | #define BYTE_MARK 0x80 | ||
596 | |||
597 | |||
598 | /* Function: one_ucs2_to_utf8_char | ||
599 | * | ||
600 | * Function takes one UCS-2 char and writes it to a UTF-8 buffer. | ||
601 | * We need a UTF-8 buffer because we don't know before this | ||
602 | * function how many bytes of utf-8 data will be written. It also | ||
603 | * takes a pointer to the end of the UTF-8 buffer so that we don't | ||
604 | * overwrite data. This function returns the number of UTF-8 bytes | ||
605 | * of data written, or -1 if the buffer would have been overrun. | ||
606 | */ | ||
607 | |||
608 | #define LINE_SEPARATOR 0x2028 | ||
609 | #define PARAGRAPH_SEPARATOR 0x2029 | ||
610 | static int16 one_ucs2_to_utf8_char(unsigned char *tobufp, | ||
611 | unsigned char *tobufendp, | ||
612 | uint16 onechar) | ||
613 | { | ||
614 | int16 numUTF8bytes = 0; | ||
615 | |||
616 | if (onechar == LINE_SEPARATOR || onechar == PARAGRAPH_SEPARATOR) { | ||
617 | strcpy((char*)tobufp, "\n"); | ||
618 | return strlen((char*)tobufp); | ||
619 | } | ||
620 | |||
621 | if (onechar < 0x80) { | ||
622 | numUTF8bytes = 1; | ||
623 | } else if (onechar < 0x800) { | ||
624 | numUTF8bytes = 2; | ||
625 | } else { | ||
626 | /* 0x800 >= onechar <= MAX_UCS2 */ | ||
627 | numUTF8bytes = 3; | ||
628 | } | ||
629 | |||
630 | tobufp += numUTF8bytes; | ||
631 | |||
632 | /* return error if we don't have space for the whole character */ | ||
633 | if (tobufp > tobufendp) { | ||
634 | return(-1); | ||
635 | } | ||
636 | |||
637 | switch(numUTF8bytes) { | ||
638 | case 3: *--tobufp = (onechar | BYTE_MARK) & BYTE_MASK; onechar >>=6; | ||
639 | *--tobufp = (onechar | BYTE_MARK) & BYTE_MASK; onechar >>=6; | ||
640 | *--tobufp = onechar | THREE_OCTET_BASE; | ||
641 | break; | ||
642 | |||
643 | case 2: *--tobufp = (onechar | BYTE_MARK) & BYTE_MASK; onechar >>=6; | ||
644 | *--tobufp = onechar | TWO_OCTET_BASE; | ||
645 | break; | ||
646 | |||
647 | case 1: *--tobufp = (unsigned char)onechar; | ||
648 | break; | ||
649 | } | ||
650 | |||
651 | return numUTF8bytes; | ||
652 | } | ||
653 | |||
654 | /* | ||
655 | * utf8_to_ucs2_char | ||
656 | * | ||
657 | * Convert a utf8 multibyte character to ucs2 | ||
658 | * | ||
659 | * inputs: pointer to utf8 character(s) | ||
660 | * length of utf8 buffer ("read" length limit) | ||
661 | * pointer to return ucs2 character | ||
662 | * | ||
663 | * outputs: number of bytes in the utf8 character | ||
664 | * -1 if not a valid utf8 character sequence | ||
665 | * -2 if the buffer is too short | ||
666 | */ | ||
667 | static int16 | ||
668 | utf8_to_ucs2_char(const unsigned char *utf8p, int16 buflen, uint16 *ucs2p) | ||
669 | { | ||
670 | uint16 lead, cont1, cont2; | ||
671 | |||
672 | /* | ||
673 | * Check for minimum buffer length | ||
674 | */ | ||
675 | if ((buflen < 1) || (utf8p == NULL)) { | ||
676 | return -2; | ||
677 | } | ||
678 | lead = (uint16) (*utf8p); | ||
679 | |||
680 | /* | ||
681 | * Check for a one octet sequence | ||
682 | */ | ||
683 | if (IS_UTF8_1ST_OF_1(lead)) { | ||
684 | *ucs2p = lead & ONE_OCTET_MASK; | ||
685 | return 1; | ||
686 | } | ||
687 | |||
688 | /* | ||
689 | * Check for a two octet sequence | ||
690 | */ | ||
691 | if (IS_UTF8_1ST_OF_2(*utf8p)) { | ||
692 | if (buflen < 2) | ||
693 | return -2; | ||
694 | cont1 = (uint16) *(utf8p+1); | ||
695 | if (!IS_UTF8_2ND_THRU_6TH(cont1)) | ||
696 | return -1; | ||
697 | *ucs2p = (lead & TWO_OCTET_MASK) << 6; | ||
698 | *ucs2p |= cont1 & CONTINUING_OCTET_MASK; | ||
699 | return 2; | ||
700 | } | ||
701 | |||
702 | /* | ||
703 | * Check for a three octet sequence | ||
704 | */ | ||
705 | else if (IS_UTF8_1ST_OF_3(lead)) { | ||
706 | if (buflen < 3) | ||
707 | return -2; | ||
708 | cont1 = (uint16) *(utf8p+1); | ||
709 | cont2 = (uint16) *(utf8p+2); | ||
710 | if ( (!IS_UTF8_2ND_THRU_6TH(cont1)) | ||
711 | || (!IS_UTF8_2ND_THRU_6TH(cont2))) | ||
712 | return -1; | ||
713 | *ucs2p = (lead & THREE_OCTET_MASK) << 12; | ||
714 | *ucs2p |= (cont1 & CONTINUING_OCTET_MASK) << 6; | ||
715 | *ucs2p |= cont2 & CONTINUING_OCTET_MASK; | ||
716 | return 3; | ||
717 | } | ||
718 | else { /* not a valid utf8/ucs2 character */ | ||
719 | return -1; | ||
720 | } | ||
721 | } | ||
722 | |||
723 | /* ----------------------------- Helper functions --------------------------- */ | ||
724 | /* Ripped off from lm_win.c .. */ | ||
725 | /* where is strcasecmp?.. for now, it's case sensitive.. | ||
726 | * | ||
727 | * strcasecmp is in strings.h, but on windows it's called _stricmp... | ||
728 | * will need to #ifdef this | ||
729 | */ | ||
730 | |||
731 | static int32 | ||
732 | js_FileHasOption(JSContext *cx, const char *oldoptions, const char *name) | ||
733 | { | ||
734 | char *comma, *equal, *current; | ||
735 | char *options = JS_strdup(cx, oldoptions); | ||
736 | int32 found = 0; | ||
737 | |||
738 | current = options; | ||
739 | for (;;) { | ||
740 | comma = strchr(current, ','); | ||
741 | if (comma) *comma = '\0'; | ||
742 | equal = strchr(current, '='); | ||
743 | if (equal) *equal = '\0'; | ||
744 | if (strcmp(current, name) == 0) { | ||
745 | if (!equal || strcmp(equal + 1, "yes") == 0) | ||
746 | found = 1; | ||
747 | else | ||
748 | found = atoi(equal + 1); | ||
749 | } | ||
750 | if (equal) *equal = '='; | ||
751 | if (comma) *comma = ','; | ||
752 | if (found || !comma) | ||
753 | break; | ||
754 | current = comma + 1; | ||
755 | } | ||
756 | siliconforks | 507 | cx->free(options); |
757 | siliconforks | 332 | return found; |
758 | } | ||
759 | |||
760 | /* empty the buffer */ | ||
761 | static void | ||
762 | js_ResetBuffers(JSFile * file) | ||
763 | { | ||
764 | file->charBufferUsed = JS_FALSE; | ||
765 | file->nbBytesInBuf = 0; | ||
766 | } | ||
767 | |||
768 | /* Reset file attributes */ | ||
769 | static void | ||
770 | js_ResetAttributes(JSFile * file) | ||
771 | { | ||
772 | file->mode = file->type = 0; | ||
773 | file->isOpen = JS_FALSE; | ||
774 | file->handle = NULL; | ||
775 | file->nativehandle = NULL; | ||
776 | file->hasRandomAccess = JS_TRUE; /* Innocent until proven guilty. */ | ||
777 | file->hasAutoflush = JS_FALSE; | ||
778 | file->isNative = JS_FALSE; | ||
779 | file->isPipe = JS_FALSE; | ||
780 | |||
781 | js_ResetBuffers(file); | ||
782 | } | ||
783 | |||
784 | static JSBool | ||
785 | js_FileOpen(JSContext *cx, JSObject *obj, JSFile *file, char *mode){ | ||
786 | JSString *type, *mask; | ||
787 | jsval v[2]; | ||
788 | jsval rval; | ||
789 | |||
790 | type = JS_InternString(cx, asciistring); | ||
791 | mask = JS_NewStringCopyZ(cx, mode); | ||
792 | v[0] = STRING_TO_JSVAL(mask); | ||
793 | v[1] = STRING_TO_JSVAL(type); | ||
794 | |||
795 | if (!file_open(cx, obj, 2, v, &rval)) | ||
796 | return JS_FALSE; | ||
797 | return JS_TRUE; | ||
798 | } | ||
799 | |||
800 | /* Buffered version of PR_Read. Used by js_FileRead */ | ||
801 | static int32 | ||
802 | js_BufferedRead(JSFile *f, unsigned char *buf, int32 len) | ||
803 | { | ||
804 | int32 count = 0; | ||
805 | |||
806 | while (f->nbBytesInBuf>0&&len>0) { | ||
807 | buf[0] = f->byteBuffer[0]; | ||
808 | f->byteBuffer[0] = f->byteBuffer[1]; | ||
809 | f->byteBuffer[1] = f->byteBuffer[2]; | ||
810 | f->nbBytesInBuf--; | ||
811 | len--; | ||
812 | buf+=1; | ||
813 | count++; | ||
814 | } | ||
815 | |||
816 | if (len > 0) { | ||
817 | count += (!f->isNative) | ||
818 | ? PR_Read(f->handle, buf, len) | ||
819 | : fread(buf, 1, len, f->nativehandle); | ||
820 | } | ||
821 | return count; | ||
822 | } | ||
823 | |||
824 | static int32 | ||
825 | js_FileRead(JSContext *cx, JSFile *file, jschar *buf, int32 len, int32 mode) | ||
826 | { | ||
827 | unsigned char *aux; | ||
828 | int32 count = 0, i; | ||
829 | jsint remainder; | ||
830 | unsigned char utfbuf[3]; | ||
831 | |||
832 | if (file->charBufferUsed) { | ||
833 | buf[0] = file->charBuffer; | ||
834 | buf++; | ||
835 | len--; | ||
836 | file->charBufferUsed = JS_FALSE; | ||
837 | } | ||
838 | |||
839 | switch (mode) { | ||
840 | case ASCII: | ||
841 | siliconforks | 507 | aux = (unsigned char*)cx->malloc(len); |
842 | siliconforks | 332 | if (!aux) |
843 | return 0; | ||
844 | |||
845 | count = js_BufferedRead(file, aux, len); | ||
846 | if (count == -1) { | ||
847 | siliconforks | 507 | cx->free(aux); |
848 | siliconforks | 332 | return 0; |
849 | } | ||
850 | |||
851 | for (i = 0; i < len; i++) | ||
852 | buf[i] = (jschar)aux[i]; | ||
853 | |||
854 | siliconforks | 507 | cx->free(aux); |
855 | siliconforks | 332 | break; |
856 | |||
857 | case UTF8: | ||
858 | remainder = 0; | ||
859 | for (count = 0;count<len;count++) { | ||
860 | i = js_BufferedRead(file, utfbuf+remainder, 3-remainder); | ||
861 | if (i<=0) { | ||
862 | return count; | ||
863 | } | ||
864 | i = utf8_to_ucs2_char(utfbuf, (int16)i, &buf[count] ); | ||
865 | if (i<0) { | ||
866 | return count; | ||
867 | } else { | ||
868 | if (i==1) { | ||
869 | utfbuf[0] = utfbuf[1]; | ||
870 | utfbuf[1] = utfbuf[2]; | ||
871 | remainder = 2; | ||
872 | } else if (i==2) { | ||
873 | utfbuf[0] = utfbuf[2]; | ||
874 | remainder = 1; | ||
875 | } else if (i==3) { | ||
876 | remainder = 0; | ||
877 | } | ||
878 | } | ||
879 | } | ||
880 | while (remainder>0) { | ||
881 | file->byteBuffer[file->nbBytesInBuf] = utfbuf[0]; | ||
882 | file->nbBytesInBuf++; | ||
883 | utfbuf[0] = utfbuf[1]; | ||
884 | utfbuf[1] = utfbuf[2]; | ||
885 | remainder--; | ||
886 | } | ||
887 | break; | ||
888 | |||
889 | case UCS2: | ||
890 | count = js_BufferedRead(file, (unsigned char *)buf, len * 2) >> 1; | ||
891 | if (count == -1) | ||
892 | return 0; | ||
893 | |||
894 | break; | ||
895 | |||
896 | default: | ||
897 | /* Not reached. */ | ||
898 | JS_ASSERT(0); | ||
899 | } | ||
900 | |||
901 | if(count == -1) { | ||
902 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
903 | JSFILEMSG_OP_FAILED, "read", file->path); | ||
904 | } | ||
905 | |||
906 | return count; | ||
907 | } | ||
908 | |||
909 | static int32 | ||
910 | js_FileSeek(JSContext *cx, JSFile *file, int32 len, int32 mode) | ||
911 | { | ||
912 | int32 count = 0, i; | ||
913 | jsint remainder; | ||
914 | unsigned char utfbuf[3]; | ||
915 | jschar tmp; | ||
916 | |||
917 | switch (mode) { | ||
918 | case ASCII: | ||
919 | count = PR_Seek(file->handle, len, PR_SEEK_CUR); | ||
920 | break; | ||
921 | |||
922 | case UTF8: | ||
923 | remainder = 0; | ||
924 | for (count = 0;count<len;count++) { | ||
925 | i = js_BufferedRead(file, utfbuf+remainder, 3-remainder); | ||
926 | if (i<=0) { | ||
927 | return 0; | ||
928 | } | ||
929 | i = utf8_to_ucs2_char(utfbuf, (int16)i, &tmp ); | ||
930 | if (i<0) { | ||
931 | return 0; | ||
932 | } else { | ||
933 | if (i==1) { | ||
934 | utfbuf[0] = utfbuf[1]; | ||
935 | utfbuf[1] = utfbuf[2]; | ||
936 | remainder = 2; | ||
937 | } else if (i==2) { | ||
938 | utfbuf[0] = utfbuf[2]; | ||
939 | remainder = 1; | ||
940 | } else if (i==3) { | ||
941 | remainder = 0; | ||
942 | } | ||
943 | } | ||
944 | } | ||
945 | while (remainder>0) { | ||
946 | file->byteBuffer[file->nbBytesInBuf] = utfbuf[0]; | ||
947 | file->nbBytesInBuf++; | ||
948 | utfbuf[0] = utfbuf[1]; | ||
949 | utfbuf[1] = utfbuf[2]; | ||
950 | remainder--; | ||
951 | } | ||
952 | break; | ||
953 | |||
954 | case UCS2: | ||
955 | count = PR_Seek(file->handle, len*2, PR_SEEK_CUR)/2; | ||
956 | break; | ||
957 | |||
958 | default: | ||
959 | /* Not reached. */ | ||
960 | JS_ASSERT(0); | ||
961 | } | ||
962 | |||
963 | if(count == -1) { | ||
964 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
965 | JSFILEMSG_OP_FAILED, "seek", file->path); | ||
966 | } | ||
967 | |||
968 | return count; | ||
969 | } | ||
970 | |||
971 | static int32 | ||
972 | js_FileWrite(JSContext *cx, JSFile *file, jschar *buf, int32 len, int32 mode) | ||
973 | { | ||
974 | unsigned char *aux; | ||
975 | int32 count = 0, i, j; | ||
976 | unsigned char *utfbuf; | ||
977 | |||
978 | switch (mode) { | ||
979 | case ASCII: | ||
980 | siliconforks | 507 | aux = (unsigned char*)cx->malloc(len); |
981 | siliconforks | 332 | if (!aux) |
982 | return 0; | ||
983 | |||
984 | for (i = 0; i<len; i++) | ||
985 | aux[i] = buf[i] % 256; | ||
986 | |||
987 | count = (!file->isNative) | ||
988 | ? PR_Write(file->handle, aux, len) | ||
989 | : fwrite(aux, 1, len, file->nativehandle); | ||
990 | |||
991 | if (count==-1) { | ||
992 | siliconforks | 507 | cx->free(aux); |
993 | siliconforks | 332 | return 0; |
994 | } | ||
995 | |||
996 | siliconforks | 507 | cx->free(aux); |
997 | siliconforks | 332 | break; |
998 | |||
999 | case UTF8: | ||
1000 | siliconforks | 507 | utfbuf = (unsigned char*)cx->malloc(len*3); |
1001 | siliconforks | 332 | if (!utfbuf) return 0; |
1002 | i = 0; | ||
1003 | for (count = 0;count<len;count++) { | ||
1004 | j = one_ucs2_to_utf8_char(utfbuf+i, utfbuf+len*3, buf[count]); | ||
1005 | if (j==-1) { | ||
1006 | siliconforks | 507 | cx->free(utfbuf); |
1007 | siliconforks | 332 | return 0; |
1008 | } | ||
1009 | i+=j; | ||
1010 | } | ||
1011 | j = (!file->isNative) | ||
1012 | ? PR_Write(file->handle, utfbuf, i) | ||
1013 | : fwrite(utfbuf, 1, i, file->nativehandle); | ||
1014 | |||
1015 | if (j<i) { | ||
1016 | siliconforks | 507 | cx->free(utfbuf); |
1017 | siliconforks | 332 | return 0; |
1018 | } | ||
1019 | siliconforks | 507 | cx->free(utfbuf); |
1020 | siliconforks | 332 | break; |
1021 | |||
1022 | case UCS2: | ||
1023 | count = (!file->isNative) | ||
1024 | ? PR_Write(file->handle, buf, len*2) >> 1 | ||
1025 | : fwrite(buf, 1, len*2, file->nativehandle) >> 1; | ||
1026 | |||
1027 | if (count == -1) | ||
1028 | return 0; | ||
1029 | break; | ||
1030 | |||
1031 | default: | ||
1032 | /* Not reached. */ | ||
1033 | JS_ASSERT(0); | ||
1034 | } | ||
1035 | |||
1036 | if(count == -1) { | ||
1037 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1038 | JSFILEMSG_OP_FAILED, "write", file->path); | ||
1039 | } | ||
1040 | |||
1041 | return count; | ||
1042 | } | ||
1043 | |||
1044 | /* ----------------------------- Property checkers -------------------------- */ | ||
1045 | static JSBool | ||
1046 | js_exists(JSContext *cx, JSFile *file) | ||
1047 | { | ||
1048 | if (file->isNative) { | ||
1049 | /* It doesn't make sense for a pipe of stdstream. */ | ||
1050 | return JS_FALSE; | ||
1051 | } | ||
1052 | |||
1053 | return PR_Access(file->path, PR_ACCESS_EXISTS) == PR_SUCCESS; | ||
1054 | } | ||
1055 | |||
1056 | static JSBool | ||
1057 | js_canRead(JSContext *cx, JSFile *file) | ||
1058 | { | ||
1059 | if (!file->isNative) { | ||
1060 | if (file->isOpen && !(file->mode & PR_RDONLY)) | ||
1061 | return JS_FALSE; | ||
1062 | return PR_Access(file->path, PR_ACCESS_READ_OK) == PR_SUCCESS; | ||
1063 | } | ||
1064 | |||
1065 | if (file->isPipe) { | ||
1066 | /* Is this pipe open for reading? */ | ||
1067 | return file->path[0] == PIPE_SYMBOL; | ||
1068 | } | ||
1069 | |||
1070 | return !strcmp(file->path, STDINPUT_NAME); | ||
1071 | } | ||
1072 | |||
1073 | static JSBool | ||
1074 | js_canWrite(JSContext *cx, JSFile *file) | ||
1075 | { | ||
1076 | if (!file->isNative) { | ||
1077 | if (file->isOpen && !(file->mode & PR_WRONLY)) | ||
1078 | return JS_FALSE; | ||
1079 | return PR_Access(file->path, PR_ACCESS_WRITE_OK) == PR_SUCCESS; | ||
1080 | } | ||
1081 | |||
1082 | if(file->isPipe) { | ||
1083 | /* Is this pipe open for writing? */ | ||
1084 | return file->path[strlen(file->path)-1] == PIPE_SYMBOL; | ||
1085 | } | ||
1086 | |||
1087 | return !strcmp(file->path, STDOUTPUT_NAME) || | ||
1088 | !strcmp(file->path, STDERROR_NAME); | ||
1089 | } | ||
1090 | |||
1091 | static JSBool | ||
1092 | js_isFile(JSContext *cx, JSFile *file) | ||
1093 | { | ||
1094 | if (!file->isNative) { | ||
1095 | PRFileInfo info; | ||
1096 | |||
1097 | if (file->isOpen | ||
1098 | ? PR_GetOpenFileInfo(file->handle, &info) | ||
1099 | : PR_GetFileInfo(file->path, &info) != PR_SUCCESS) { | ||
1100 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1101 | JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path); | ||
1102 | return JS_FALSE; | ||
1103 | } | ||
1104 | |||
1105 | return info.type == PR_FILE_FILE; | ||
1106 | } | ||
1107 | |||
1108 | /* This doesn't make sense for a pipe of stdstream. */ | ||
1109 | return JS_FALSE; | ||
1110 | } | ||
1111 | |||
1112 | static JSBool | ||
1113 | js_isDirectory(JSContext *cx, JSFile *file) | ||
1114 | { | ||
1115 | if(!file->isNative){ | ||
1116 | PRFileInfo info; | ||
1117 | |||
1118 | /* Hack needed to get get_property to work. */ | ||
1119 | if (!js_exists(cx, file)) | ||
1120 | return JS_FALSE; | ||
1121 | |||
1122 | if (file->isOpen | ||
1123 | ? PR_GetOpenFileInfo(file->handle, &info) | ||
1124 | : PR_GetFileInfo(file->path, &info) != PR_SUCCESS) { | ||
1125 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1126 | JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path); | ||
1127 | return JS_FALSE; | ||
1128 | } | ||
1129 | |||
1130 | return info.type == PR_FILE_DIRECTORY; | ||
1131 | } | ||
1132 | |||
1133 | /* This doesn't make sense for a pipe of stdstream. */ | ||
1134 | return JS_FALSE; | ||
1135 | } | ||
1136 | |||
1137 | static jsval | ||
1138 | js_size(JSContext *cx, JSFile *file) | ||
1139 | { | ||
1140 | PRFileInfo info; | ||
1141 | |||
1142 | JSFILE_CHECK_NATIVE("size"); | ||
1143 | |||
1144 | if (file->isOpen | ||
1145 | ? PR_GetOpenFileInfo(file->handle, &info) | ||
1146 | : PR_GetFileInfo(file->path, &info) != PR_SUCCESS) { | ||
1147 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1148 | JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path); | ||
1149 | return JSVAL_VOID; | ||
1150 | } | ||
1151 | |||
1152 | return INT_TO_JSVAL(info.size); | ||
1153 | |||
1154 | out: | ||
1155 | return JSVAL_VOID; | ||
1156 | } | ||
1157 | |||
1158 | /* | ||
1159 | * Return the parent object | ||
1160 | */ | ||
1161 | static JSBool | ||
1162 | js_parent(JSContext *cx, JSFile *file, jsval *resultp) | ||
1163 | { | ||
1164 | char *str; | ||
1165 | |||
1166 | /* Since we only care about pipes and native files, return NULL. */ | ||
1167 | if (file->isNative) { | ||
1168 | *resultp = JSVAL_VOID; | ||
1169 | return JS_TRUE; | ||
1170 | } | ||
1171 | |||
1172 | str = js_fileDirectoryName(cx, file->path); | ||
1173 | if (!str) | ||
1174 | return JS_FALSE; | ||
1175 | |||
1176 | /* If the directory is equal to the original path, we're at the root. */ | ||
1177 | if (!strcmp(file->path, str)) { | ||
1178 | *resultp = JSVAL_NULL; | ||
1179 | } else { | ||
1180 | JSObject *obj = js_NewFileObject(cx, str); | ||
1181 | if (!obj) { | ||
1182 | siliconforks | 507 | cx->free(str); |
1183 | siliconforks | 332 | return JS_FALSE; |
1184 | } | ||
1185 | *resultp = OBJECT_TO_JSVAL(obj); | ||
1186 | } | ||
1187 | |||
1188 | siliconforks | 507 | cx->free(str); |
1189 | siliconforks | 332 | return JS_TRUE; |
1190 | } | ||
1191 | |||
1192 | static JSBool | ||
1193 | js_name(JSContext *cx, JSFile *file, jsval *vp) | ||
1194 | { | ||
1195 | char *name; | ||
1196 | JSString *str; | ||
1197 | |||
1198 | if (file->isPipe) { | ||
1199 | *vp = JSVAL_VOID; | ||
1200 | return JS_TRUE; | ||
1201 | } | ||
1202 | |||
1203 | name = js_fileBaseName(cx, file->path); | ||
1204 | if (!name) | ||
1205 | return JS_FALSE; | ||
1206 | |||
1207 | str = JS_NewString(cx, name, strlen(name)); | ||
1208 | if (!str) { | ||
1209 | siliconforks | 507 | cx->free(name); |
1210 | siliconforks | 332 | return JS_FALSE; |
1211 | } | ||
1212 | |||
1213 | *vp = STRING_TO_JSVAL(str); | ||
1214 | return JS_TRUE; | ||
1215 | } | ||
1216 | |||
1217 | /* ------------------------------ File object methods ---------------------------- */ | ||
1218 | static JSBool | ||
1219 | file_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) | ||
1220 | { | ||
1221 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
1222 | JSString *strmode, *strtype; | ||
1223 | char *ctype, *mode; | ||
1224 | int32 mask, type; | ||
1225 | int len; | ||
1226 | |||
1227 | mode = NULL; | ||
1228 | |||
1229 | SECURITY_CHECK(cx, NULL, "open", file); | ||
1230 | |||
1231 | /* A native file that is already open */ | ||
1232 | if(file->isOpen && file->isNative) { | ||
1233 | JS_ReportWarning(cx, "Native file %s is already open, proceeding", | ||
1234 | file->path); | ||
1235 | goto good; | ||
1236 | } | ||
1237 | |||
1238 | /* Close before proceeding */ | ||
1239 | if (file->isOpen) { | ||
1240 | JS_ReportWarning(cx, "File %s is already open, we will close it and " | ||
1241 | "reopen, proceeding", file->path); | ||
1242 | if(!file_close(cx, obj, 0, NULL, rval)) | ||
1243 | goto out; | ||
1244 | } | ||
1245 | |||
1246 | if (js_isDirectory(cx, file)) { | ||
1247 | JS_ReportWarning(cx, "%s seems to be a directory, there is no point in " | ||
1248 | "trying to open it, proceeding", file->path); | ||
1249 | goto good; | ||
1250 | } | ||
1251 | |||
1252 | /* Path must be defined at this point */ | ||
1253 | len = strlen(file->path); | ||
1254 | |||
1255 | /* Mode */ | ||
1256 | if (argc >= 1) { | ||
1257 | strmode = JS_ValueToString(cx, argv[0]); | ||
1258 | if (!strmode) { | ||
1259 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1260 | JSFILEMSG_FIRST_ARGUMENT_OPEN_NOT_STRING_ERROR, | ||
1261 | argv[0]); | ||
1262 | goto out; | ||
1263 | } | ||
1264 | mode = JS_strdup(cx, JS_GetStringBytes(strmode)); | ||
1265 | } else { | ||
1266 | if(file->path[0]==PIPE_SYMBOL) { | ||
1267 | /* pipe default mode */ | ||
1268 | mode = JS_strdup(cx, "read"); | ||
1269 | } else if(file->path[len-1]==PIPE_SYMBOL) { | ||
1270 | /* pipe default mode */ | ||
1271 | mode = JS_strdup(cx, "write"); | ||
1272 | } else { | ||
1273 | /* non-destructive, permissive defaults. */ | ||
1274 | mode = JS_strdup(cx, "readWrite,append,create"); | ||
1275 | } | ||
1276 | } | ||
1277 | |||
1278 | /* Process the mode */ | ||
1279 | mask = 0; | ||
1280 | /* TODO: this is pretty ugly, we walk thru the string too many times */ | ||
1281 | mask |= js_FileHasOption(cx, mode, "read") ? PR_RDONLY : 0; | ||
1282 | mask |= js_FileHasOption(cx, mode, "write") ? PR_WRONLY : 0; | ||
1283 | mask |= js_FileHasOption(cx, mode, "readWrite")? PR_RDWR : 0; | ||
1284 | mask |= js_FileHasOption(cx, mode, "append") ? PR_APPEND : 0; | ||
1285 | mask |= js_FileHasOption(cx, mode, "create") ? PR_CREATE_FILE : 0; | ||
1286 | mask |= js_FileHasOption(cx, mode, "replace") ? PR_TRUNCATE : 0; | ||
1287 | |||
1288 | if (mask & PR_RDWR) | ||
1289 | mask |= (PR_RDONLY | PR_WRONLY); | ||
1290 | if ((mask & PR_RDONLY) && (mask & PR_WRONLY)) | ||
1291 | mask |= PR_RDWR; | ||
1292 | |||
1293 | file->hasAutoflush |= js_FileHasOption(cx, mode, "autoflush"); | ||
1294 | |||
1295 | /* Type */ | ||
1296 | if (argc > 1) { | ||
1297 | strtype = JS_ValueToString(cx, argv[1]); | ||
1298 | if (!strtype) { | ||
1299 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1300 | JSFILEMSG_SECOND_ARGUMENT_OPEN_NOT_STRING_ERROR, | ||
1301 | argv[1]); | ||
1302 | goto out; | ||
1303 | } | ||
1304 | ctype = JS_GetStringBytes(strtype); | ||
1305 | |||
1306 | if(!strcmp(ctype, utfstring)) { | ||
1307 | type = UTF8; | ||
1308 | } else if (!strcmp(ctype, unicodestring)) { | ||
1309 | type = UCS2; | ||
1310 | } else { | ||
1311 | if (strcmp(ctype, asciistring)) { | ||
1312 | JS_ReportWarning(cx, "File type %s is not supported, using " | ||
1313 | "'text' instead, proceeding", ctype); | ||
1314 | } | ||
1315 | type = ASCII; | ||
1316 | } | ||
1317 | } else { | ||
1318 | type = ASCII; | ||
1319 | } | ||
1320 | |||
1321 | /* Save the relevant fields */ | ||
1322 | file->type = type; | ||
1323 | file->mode = mask; | ||
1324 | file->nativehandle = NULL; | ||
1325 | file->hasRandomAccess = (type != UTF8); | ||
1326 | |||
1327 | /* | ||
1328 | * Deal with pipes here. We can't use NSPR for pipes, so we have to use | ||
1329 | * POPEN. | ||
1330 | */ | ||
1331 | if (file->path[0]==PIPE_SYMBOL || file->path[len-1]==PIPE_SYMBOL) { | ||
1332 | if (file->path[0] == PIPE_SYMBOL && file->path[len-1] == PIPE_SYMBOL) { | ||
1333 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1334 | JSFILEMSG_BIDIRECTIONAL_PIPE_NOT_SUPPORTED); | ||
1335 | goto out; | ||
1336 | } else { | ||
1337 | int i = 0; | ||
1338 | char pipemode[3]; | ||
1339 | SECURITY_CHECK(cx, NULL, "pipe_open", file); | ||
1340 | |||
1341 | if(file->path[0] == PIPE_SYMBOL){ | ||
1342 | if(mask & (PR_WRONLY | PR_APPEND | PR_CREATE_FILE | PR_TRUNCATE)){ | ||
1343 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1344 | JSFILEMSG_OPEN_MODE_NOT_SUPPORTED_WITH_PIPES, | ||
1345 | mode, file->path); | ||
1346 | goto out; | ||
1347 | } | ||
1348 | /* open(SPOOLER, "| cat -v | lpr -h 2>/dev/null") -- pipe for writing */ | ||
1349 | pipemode[i++] = 'r'; | ||
1350 | #ifndef XP_UNIX | ||
1351 | pipemode[i++] = file->type==UTF8 ? 'b' : 't'; | ||
1352 | #endif | ||
1353 | pipemode[i++] = '\0'; | ||
1354 | file->nativehandle = POPEN(&file->path[1], pipemode); | ||
1355 | } else if(file->path[len-1] == PIPE_SYMBOL) { | ||
1356 | siliconforks | 507 | char *command = cx->malloc(len); |
1357 | siliconforks | 332 | |
1358 | strncpy(command, file->path, len-1); | ||
1359 | command[len-1] = '\0'; | ||
1360 | /* open(STATUS, "netstat -an 2>&1 |") */ | ||
1361 | pipemode[i++] = 'w'; | ||
1362 | #ifndef XP_UNIX | ||
1363 | pipemode[i++] = file->type==UTF8 ? 'b' : 't'; | ||
1364 | #endif | ||
1365 | pipemode[i++] = '\0'; | ||
1366 | file->nativehandle = POPEN(command, pipemode); | ||
1367 | siliconforks | 507 | cx->free(command); |
1368 | siliconforks | 332 | } |
1369 | /* set the flags */ | ||
1370 | file->isNative = JS_TRUE; | ||
1371 | file->isPipe = JS_TRUE; | ||
1372 | file->hasRandomAccess = JS_FALSE; | ||
1373 | } | ||
1374 | } else { | ||
1375 | /* TODO: what about the permissions?? Java ignores the problem... */ | ||
1376 | file->handle = PR_Open(file->path, mask, 0644); | ||
1377 | } | ||
1378 | |||
1379 | js_ResetBuffers(file); | ||
1380 | siliconforks | 507 | cx->free(mode); |
1381 | siliconforks | 332 | mode = NULL; |
1382 | |||
1383 | /* Set the open flag and return result */ | ||
1384 | if (file->handle == NULL && file->nativehandle == NULL) { | ||
1385 | file->isOpen = JS_FALSE; | ||
1386 | |||
1387 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1388 | JSFILEMSG_OP_FAILED, "open", file->path); | ||
1389 | goto out; | ||
1390 | } | ||
1391 | |||
1392 | good: | ||
1393 | file->isOpen = JS_TRUE; | ||
1394 | *rval = JSVAL_TRUE; | ||
1395 | return JS_TRUE; | ||
1396 | |||
1397 | out: | ||
1398 | if(mode) | ||
1399 | siliconforks | 507 | cx->free(mode); |
1400 | siliconforks | 332 | return JS_FALSE; |
1401 | } | ||
1402 | |||
1403 | static JSBool | ||
1404 | file_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) | ||
1405 | { | ||
1406 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
1407 | |||
1408 | SECURITY_CHECK(cx, NULL, "close", file); | ||
1409 | |||
1410 | if(!file->isOpen){ | ||
1411 | JS_ReportWarning(cx, "File %s is not open, can't close it, proceeding", | ||
1412 | file->path); | ||
1413 | goto out; | ||
1414 | } | ||
1415 | |||
1416 | if(!file->isPipe){ | ||
1417 | if(file->isNative){ | ||
1418 | JS_ReportWarning(cx, "Unable to close a native file, proceeding", file->path); | ||
1419 | goto out; | ||
1420 | }else{ | ||
1421 | if(file->handle && PR_Close(file->handle)){ | ||
1422 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1423 | JSFILEMSG_OP_FAILED, "close", file->path); | ||
1424 | |||
1425 | goto out; | ||
1426 | } | ||
1427 | } | ||
1428 | }else{ | ||
1429 | if(PCLOSE(file->nativehandle)==-1){ | ||
1430 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1431 | JSFILEMSG_OP_FAILED, "pclose", file->path); | ||
1432 | goto out; | ||
1433 | } | ||
1434 | } | ||
1435 | |||
1436 | js_ResetAttributes(file); | ||
1437 | *rval = JSVAL_TRUE; | ||
1438 | return JS_TRUE; | ||
1439 | |||
1440 | out: | ||
1441 | return JS_FALSE; | ||
1442 | } | ||
1443 | |||
1444 | |||
1445 | static JSBool | ||
1446 | file_remove(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) | ||
1447 | { | ||
1448 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
1449 | |||
1450 | SECURITY_CHECK(cx, NULL, "remove", file); | ||
1451 | JSFILE_CHECK_NATIVE("remove"); | ||
1452 | JSFILE_CHECK_CLOSED("remove"); | ||
1453 | |||
1454 | if ((js_isDirectory(cx, file) ? | ||
1455 | PR_RmDir(file->path) : PR_Delete(file->path))==PR_SUCCESS) { | ||
1456 | js_ResetAttributes(file); | ||
1457 | *rval = JSVAL_TRUE; | ||
1458 | return JS_TRUE; | ||
1459 | } else { | ||
1460 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1461 | JSFILEMSG_OP_FAILED, "remove", file->path); | ||
1462 | goto out; | ||
1463 | } | ||
1464 | out: | ||
1465 | *rval = JSVAL_FALSE; | ||
1466 | return JS_FALSE; | ||
1467 | } | ||
1468 | |||
1469 | /* Raw PR-based function. No text processing. Just raw data copying. */ | ||
1470 | static JSBool | ||
1471 | file_copyTo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) | ||
1472 | { | ||
1473 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
1474 | char *dest = NULL; | ||
1475 | PRFileDesc *handle = NULL; | ||
1476 | char *buffer; | ||
1477 | jsval count, size; | ||
1478 | JSBool fileInitiallyOpen=JS_FALSE; | ||
1479 | |||
1480 | SECURITY_CHECK(cx, NULL, "copyTo", file); /* may need a second argument!*/ | ||
1481 | JSFILE_CHECK_ONE_ARG("copyTo"); | ||
1482 | JSFILE_CHECK_NATIVE("copyTo"); | ||
1483 | /* remeber the state */ | ||
1484 | fileInitiallyOpen = file->isOpen; | ||
1485 | JSFILE_CHECK_READ; | ||
1486 | |||
1487 | siliconforks | 507 | JSString *str = JS_ValueToString(cx, argv[0]); |
1488 | if (!str) | ||
1489 | goto out; | ||
1490 | siliconforks | 332 | |
1491 | siliconforks | 507 | dest = JS_GetStringBytes(str); |
1492 | |||
1493 | siliconforks | 332 | /* make sure we are not reading a file open for writing */ |
1494 | if (file->isOpen && !js_canRead(cx, file)) { | ||
1495 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1496 | JSFILEMSG_CANNOT_COPY_FILE_OPEN_FOR_WRITING_ERROR, file->path); | ||
1497 | goto out; | ||
1498 | } | ||
1499 | |||
1500 | if (file->handle==NULL){ | ||
1501 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1502 | JSFILEMSG_OP_FAILED, "open", file->path); | ||
1503 | goto out; | ||
1504 | } | ||
1505 | |||
1506 | handle = PR_Open(dest, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 0644); | ||
1507 | |||
1508 | if(!handle){ | ||
1509 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1510 | JSFILEMSG_OP_FAILED, "open", dest); | ||
1511 | goto out; | ||
1512 | } | ||
1513 | |||
1514 | if ((size=js_size(cx, file))==JSVAL_VOID) { | ||
1515 | goto out; | ||
1516 | } | ||
1517 | |||
1518 | siliconforks | 507 | buffer = cx->malloc(size); |
1519 | siliconforks | 332 | |
1520 | count = INT_TO_JSVAL(PR_Read(file->handle, buffer, size)); | ||
1521 | |||
1522 | /* reading panic */ | ||
1523 | if (count!=size) { | ||
1524 | siliconforks | 507 | cx->free(buffer); |
1525 | siliconforks | 332 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, |
1526 | JSFILEMSG_COPY_READ_ERROR, file->path); | ||
1527 | goto out; | ||
1528 | } | ||
1529 | |||
1530 | count = INT_TO_JSVAL(PR_Write(handle, buffer, JSVAL_TO_INT(size))); | ||
1531 | |||
1532 | /* writing panic */ | ||
1533 | if (count!=size) { | ||
1534 | siliconforks | 507 | cx->free(buffer); |
1535 | siliconforks | 332 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, |
1536 | JSFILEMSG_COPY_WRITE_ERROR, file->path); | ||
1537 | goto out; | ||
1538 | } | ||
1539 | |||
1540 | siliconforks | 507 | cx->free(buffer); |
1541 | siliconforks | 332 | |
1542 | if(!fileInitiallyOpen){ | ||
1543 | if(!file_close(cx, obj, 0, NULL, rval)) goto out; | ||
1544 | } | ||
1545 | |||
1546 | if(PR_Close(handle)!=PR_SUCCESS){ | ||
1547 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1548 | JSFILEMSG_OP_FAILED, "close", dest); | ||
1549 | goto out; | ||
1550 | } | ||
1551 | |||
1552 | *rval = JSVAL_TRUE; | ||
1553 | return JS_TRUE; | ||
1554 | out: | ||
1555 | if(file->isOpen && !fileInitiallyOpen){ | ||
1556 | if(PR_Close(file->handle)!=PR_SUCCESS){ | ||
1557 | JS_ReportWarning(cx, "Can't close %s, proceeding", file->path); | ||
1558 | } | ||
1559 | } | ||
1560 | |||
1561 | if(handle && PR_Close(handle)!=PR_SUCCESS){ | ||
1562 | JS_ReportWarning(cx, "Can't close %s, proceeding", dest); | ||
1563 | } | ||
1564 | |||
1565 | *rval = JSVAL_FALSE; | ||
1566 | return JS_FALSE; | ||
1567 | } | ||
1568 | |||
1569 | static JSBool | ||
1570 | file_renameTo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) | ||
1571 | { | ||
1572 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
1573 | char *dest; | ||
1574 | |||
1575 | SECURITY_CHECK(cx, NULL, "renameTo", file); /* may need a second argument!*/ | ||
1576 | JSFILE_CHECK_ONE_ARG("renameTo"); | ||
1577 | JSFILE_CHECK_NATIVE("renameTo"); | ||
1578 | JSFILE_CHECK_CLOSED("renameTo"); | ||
1579 | |||
1580 | siliconforks | 507 | JSString *str = JS_ValueToString(cx, argv[0]); |
1581 | if (!str) | ||
1582 | goto out; | ||
1583 | siliconforks | 332 | |
1584 | siliconforks | 507 | dest = RESOLVE_PATH(cx, JS_GetStringBytes(str)); |
1585 | |||
1586 | siliconforks | 332 | if (PR_Rename(file->path, dest)==PR_SUCCESS){ |
1587 | /* copy the new filename */ | ||
1588 | siliconforks | 507 | cx->free(file->path); |
1589 | siliconforks | 332 | file->path = dest; |
1590 | *rval = JSVAL_TRUE; | ||
1591 | return JS_TRUE; | ||
1592 | }else{ | ||
1593 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1594 | JSFILEMSG_RENAME_FAILED, file->path, dest); | ||
1595 | goto out; | ||
1596 | } | ||
1597 | out: | ||
1598 | *rval = JSVAL_FALSE; | ||
1599 | return JS_FALSE; | ||
1600 | } | ||
1601 | |||
1602 | static JSBool | ||
1603 | file_flush(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) | ||
1604 | { | ||
1605 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
1606 | |||
1607 | SECURITY_CHECK(cx, NULL, "flush", file); | ||
1608 | JSFILE_CHECK_NATIVE("flush"); | ||
1609 | JSFILE_CHECK_OPEN("flush"); | ||
1610 | |||
1611 | if (PR_Sync(file->handle)==PR_SUCCESS){ | ||
1612 | *rval = JSVAL_TRUE; | ||
1613 | return JS_TRUE; | ||
1614 | }else{ | ||
1615 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1616 | JSFILEMSG_OP_FAILED, "flush", file->path); | ||
1617 | goto out; | ||
1618 | } | ||
1619 | out: | ||
1620 | *rval = JSVAL_FALSE; | ||
1621 | return JS_FALSE; | ||
1622 | } | ||
1623 | |||
1624 | static JSBool | ||
1625 | file_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) | ||
1626 | { | ||
1627 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
1628 | JSString *str; | ||
1629 | int32 count; | ||
1630 | uintN i; | ||
1631 | |||
1632 | SECURITY_CHECK(cx, NULL, "write", file); | ||
1633 | JSFILE_CHECK_WRITE; | ||
1634 | |||
1635 | for (i = 0; i<argc; i++) { | ||
1636 | str = JS_ValueToString(cx, argv[i]); | ||
1637 | count = js_FileWrite(cx, file, JS_GetStringChars(str), | ||
1638 | JS_GetStringLength(str), file->type); | ||
1639 | if (count==-1){ | ||
1640 | *rval = JSVAL_FALSE; | ||
1641 | return JS_FALSE; | ||
1642 | } | ||
1643 | } | ||
1644 | |||
1645 | *rval = JSVAL_TRUE; | ||
1646 | return JS_TRUE; | ||
1647 | out: | ||
1648 | *rval = JSVAL_FALSE; | ||
1649 | return JS_FALSE; | ||
1650 | } | ||
1651 | |||
1652 | static JSBool | ||
1653 | file_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) | ||
1654 | { | ||
1655 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
1656 | JSString *str; | ||
1657 | |||
1658 | SECURITY_CHECK(cx, NULL, "writeln", file); | ||
1659 | JSFILE_CHECK_WRITE; | ||
1660 | |||
1661 | /* don't report an error here */ | ||
1662 | if(!file_write(cx, obj, argc, argv, rval)) return JS_FALSE; | ||
1663 | /* don't do security here -- we passed the check in file_write */ | ||
1664 | str = JS_NewStringCopyZ(cx, "\n"); | ||
1665 | |||
1666 | if (js_FileWrite(cx, file, JS_GetStringChars(str), JS_GetStringLength(str), | ||
1667 | file->type)==-1){ | ||
1668 | *rval = JSVAL_FALSE; | ||
1669 | return JS_FALSE; | ||
1670 | } | ||
1671 | |||
1672 | /* eol causes flush if hasAutoflush is turned on */ | ||
1673 | if (file->hasAutoflush) | ||
1674 | file_flush(cx, obj, 0, NULL, rval); | ||
1675 | |||
1676 | *rval = JSVAL_TRUE; | ||
1677 | return JS_TRUE; | ||
1678 | out: | ||
1679 | *rval = JSVAL_FALSE; | ||
1680 | return JS_FALSE; | ||
1681 | } | ||
1682 | |||
1683 | static JSBool | ||
1684 | file_writeAll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) | ||
1685 | { | ||
1686 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
1687 | jsuint i; | ||
1688 | jsuint limit; | ||
1689 | JSObject *array; | ||
1690 | JSObject *elem; | ||
1691 | jsval elemval; | ||
1692 | |||
1693 | SECURITY_CHECK(cx, NULL, "writeAll", file); | ||
1694 | JSFILE_CHECK_ONE_ARG("writeAll"); | ||
1695 | JSFILE_CHECK_WRITE; | ||
1696 | |||
1697 | if (!JS_IsArrayObject(cx, JSVAL_TO_OBJECT(argv[0]))) { | ||
1698 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1699 | JSFILEMSG_FIRST_ARGUMENT_WRITEALL_NOT_ARRAY_ERROR); | ||
1700 | goto out; | ||
1701 | } | ||
1702 | |||
1703 | array = JSVAL_TO_OBJECT(argv[0]); | ||
1704 | |||
1705 | JS_GetArrayLength(cx, array, &limit); | ||
1706 | |||
1707 | for (i = 0; i<limit; i++) { | ||
1708 | if (!JS_GetElement(cx, array, i, &elemval)) return JS_FALSE; | ||
1709 | elem = JSVAL_TO_OBJECT(elemval); | ||
1710 | file_writeln(cx, obj, 1, &elemval, rval); | ||
1711 | } | ||
1712 | |||
1713 | *rval = JSVAL_TRUE; | ||
1714 | return JS_TRUE; | ||
1715 | out: | ||
1716 | *rval = JSVAL_FALSE; | ||
1717 | return JS_FALSE; | ||
1718 | } | ||
1719 | |||
1720 | static JSBool | ||
1721 | file_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) | ||
1722 | { | ||
1723 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
1724 | JSString *str; | ||
1725 | int32 want, count; | ||
1726 | jschar *buf; | ||
1727 | |||
1728 | SECURITY_CHECK(cx, NULL, "read", file); | ||
1729 | JSFILE_CHECK_ONE_ARG("read"); | ||
1730 | JSFILE_CHECK_READ; | ||
1731 | |||
1732 | if (!JS_ValueToInt32(cx, argv[0], &want)){ | ||
1733 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1734 | JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_NUMBER, "read", argv[0]); | ||
1735 | goto out; | ||
1736 | } | ||
1737 | |||
1738 | /* want = (want>262144)?262144:want; * arbitrary size limitation */ | ||
1739 | |||
1740 | siliconforks | 507 | buf = cx->malloc(want*sizeof buf[0]); |
1741 | siliconforks | 332 | if (!buf) goto out; |
1742 | |||
1743 | count = js_FileRead(cx, file, buf, want, file->type); | ||
1744 | if (count>0) { | ||
1745 | str = JS_NewUCStringCopyN(cx, buf, count); | ||
1746 | *rval = STRING_TO_JSVAL(str); | ||
1747 | siliconforks | 507 | cx->free(buf); |
1748 | siliconforks | 332 | return JS_TRUE; |
1749 | } else { | ||
1750 | siliconforks | 507 | cx->free(buf); |
1751 | siliconforks | 332 | goto out; |
1752 | } | ||
1753 | out: | ||
1754 | *rval = JSVAL_FALSE; | ||
1755 | return JS_FALSE; | ||
1756 | } | ||
1757 | |||
1758 | static JSBool | ||
1759 | file_readln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) | ||
1760 | { | ||
1761 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
1762 | JSString *str; | ||
1763 | jschar *buf = NULL, *tmp; | ||
1764 | int32 offset, read; | ||
1765 | intN room; | ||
1766 | jschar data, data2; | ||
1767 | |||
1768 | SECURITY_CHECK(cx, NULL, "readln", file); | ||
1769 | JSFILE_CHECK_READ; | ||
1770 | |||
1771 | siliconforks | 507 | buf = cx->malloc(MAX_LINE_LENGTH * sizeof data); |
1772 | siliconforks | 332 | if (!buf) |
1773 | return JS_FALSE; | ||
1774 | |||
1775 | room = MAX_LINE_LENGTH - 1; | ||
1776 | offset = 0; | ||
1777 | |||
1778 | for (;;) { | ||
1779 | read = js_FileRead(cx, file, &data, 1, file->type); | ||
1780 | if (read < 0) | ||
1781 | goto out; | ||
1782 | if (read == 0) | ||
1783 | goto eof; | ||
1784 | |||
1785 | switch (data) { | ||
1786 | case '\r': | ||
1787 | read = js_FileRead(cx, file, &data2, 1, file->type); | ||
1788 | if (read < 0) | ||
1789 | goto out; | ||
1790 | |||
1791 | if (read == 1 && data2 != '\n') { | ||
1792 | /* We read one char too far. Buffer it. */ | ||
1793 | file->charBuffer = data2; | ||
1794 | file->charBufferUsed = JS_TRUE; | ||
1795 | } | ||
1796 | |||
1797 | /* Fall through. */ | ||
1798 | case '\n': | ||
1799 | goto done; | ||
1800 | |||
1801 | default: | ||
1802 | if (--room < 0) { | ||
1803 | siliconforks | 507 | tmp = cx->realloc(buf, (offset + MAX_LINE_LENGTH) * sizeof data); |
1804 | siliconforks | 332 | if (!tmp) |
1805 | goto out; | ||
1806 | |||
1807 | room = MAX_LINE_LENGTH - 1; | ||
1808 | buf = tmp; | ||
1809 | } | ||
1810 | |||
1811 | buf[offset++] = data; | ||
1812 | break; | ||
1813 | } | ||
1814 | } | ||
1815 | |||
1816 | eof: | ||
1817 | if (offset == 0) { | ||
1818 | *rval = JSVAL_NULL; | ||
1819 | return JS_TRUE; | ||
1820 | } | ||
1821 | |||
1822 | done: | ||
1823 | buf[offset] = 0; | ||
1824 | siliconforks | 507 | tmp = cx->realloc(buf, (offset + 1) * sizeof data); |
1825 | siliconforks | 332 | if (!tmp) |
1826 | goto out; | ||
1827 | |||
1828 | str = JS_NewUCString(cx, tmp, offset); | ||
1829 | if (!str) | ||
1830 | goto out; | ||
1831 | |||
1832 | *rval = STRING_TO_JSVAL(str); | ||
1833 | return JS_TRUE; | ||
1834 | |||
1835 | out: | ||
1836 | if (buf) | ||
1837 | siliconforks | 507 | cx->free(buf); |
1838 | siliconforks | 332 | |
1839 | return JS_FALSE; | ||
1840 | } | ||
1841 | |||
1842 | static JSBool | ||
1843 | file_readAll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) | ||
1844 | { | ||
1845 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
1846 | JSObject *array; | ||
1847 | jsint len; | ||
1848 | jsval line; | ||
1849 | JSBool lineok = JS_FALSE; | ||
1850 | |||
1851 | SECURITY_CHECK(cx, NULL, "readAll", file); | ||
1852 | JSFILE_CHECK_READ; | ||
1853 | |||
1854 | array = JS_NewArrayObject(cx, 0, NULL); | ||
1855 | if (!array) | ||
1856 | return JS_FALSE; | ||
1857 | *rval = OBJECT_TO_JSVAL(array); | ||
1858 | |||
1859 | len = 0; | ||
1860 | |||
1861 | lineok = file_readln(cx, obj, 0, NULL, &line); | ||
1862 | while (lineok && !JSVAL_IS_NULL(line)) { | ||
1863 | JS_SetElement(cx, array, len++, &line); | ||
1864 | lineok = file_readln(cx, obj, 0, NULL, &line); | ||
1865 | } | ||
1866 | |||
1867 | out: | ||
1868 | return lineok; | ||
1869 | } | ||
1870 | |||
1871 | static JSBool | ||
1872 | file_seek(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) | ||
1873 | { | ||
1874 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
1875 | int32 toskip; | ||
1876 | int32 pos; | ||
1877 | |||
1878 | SECURITY_CHECK(cx, NULL, "seek", file); | ||
1879 | JSFILE_CHECK_ONE_ARG("seek"); | ||
1880 | JSFILE_CHECK_NATIVE("seek"); | ||
1881 | JSFILE_CHECK_READ; | ||
1882 | |||
1883 | if (!JS_ValueToInt32(cx, argv[0], &toskip)){ | ||
1884 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1885 | JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_NUMBER, "seek", argv[0]); | ||
1886 | goto out; | ||
1887 | } | ||
1888 | |||
1889 | if(!file->hasRandomAccess){ | ||
1890 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1891 | JSFILEMSG_NO_RANDOM_ACCESS, file->path); | ||
1892 | goto out; | ||
1893 | } | ||
1894 | |||
1895 | if(js_isDirectory(cx, file)){ | ||
1896 | JS_ReportWarning(cx,"Seek on directories is not supported, proceeding"); | ||
1897 | goto out; | ||
1898 | } | ||
1899 | |||
1900 | pos = js_FileSeek(cx, file, toskip, file->type); | ||
1901 | |||
1902 | if (pos!=-1) { | ||
1903 | *rval = INT_TO_JSVAL(pos); | ||
1904 | return JS_TRUE; | ||
1905 | } | ||
1906 | out: | ||
1907 | *rval = JSVAL_VOID; | ||
1908 | return JS_FALSE; | ||
1909 | } | ||
1910 | |||
1911 | static JSBool | ||
1912 | file_list(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) | ||
1913 | { | ||
1914 | PRDir *dir; | ||
1915 | PRDirEntry *entry; | ||
1916 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
1917 | JSObject *array; | ||
1918 | JSObject *eachFile; | ||
1919 | jsint len; | ||
1920 | jsval v; | ||
1921 | JSRegExp *re = NULL; | ||
1922 | JSFunction *func = NULL; | ||
1923 | JSString *str; | ||
1924 | jsval args[1]; | ||
1925 | char *filePath; | ||
1926 | |||
1927 | SECURITY_CHECK(cx, NULL, "list", file); | ||
1928 | JSFILE_CHECK_NATIVE("list"); | ||
1929 | |||
1930 | if (argc==1) { | ||
1931 | if (VALUE_IS_REGEXP(cx, argv[0])) { | ||
1932 | re = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); | ||
1933 | }else | ||
1934 | if (VALUE_IS_FUNCTION(cx, argv[0])) { | ||
1935 | func = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); | ||
1936 | }else{ | ||
1937 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1938 | JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_FUNCTION_OR_REGEX, argv[0]); | ||
1939 | goto out; | ||
1940 | } | ||
1941 | } | ||
1942 | |||
1943 | if (!js_isDirectory(cx, file)) { | ||
1944 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1945 | JSFILEMSG_CANNOT_DO_LIST_ON_A_FILE, file->path); | ||
1946 | goto out; | ||
1947 | } | ||
1948 | |||
1949 | dir = PR_OpenDir(file->path); | ||
1950 | if(!dir){ | ||
1951 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
1952 | JSFILEMSG_OP_FAILED, "open", file->path); | ||
1953 | goto out; | ||
1954 | } | ||
1955 | |||
1956 | /* create JSArray here... */ | ||
1957 | array = JS_NewArrayObject(cx, 0, NULL); | ||
1958 | len = 0; | ||
1959 | |||
1960 | while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH))!=NULL) { | ||
1961 | /* first, check if we have a regexp */ | ||
1962 | if (re!=NULL) { | ||
1963 | size_t index = 0; | ||
1964 | |||
1965 | str = JS_NewStringCopyZ(cx, entry->name); | ||
1966 | if(!js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, &v)){ | ||
1967 | /* don't report anything here */ | ||
1968 | goto out; | ||
1969 | } | ||
1970 | /* not matched! */ | ||
1971 | if (JSVAL_IS_NULL(v)) { | ||
1972 | continue; | ||
1973 | } | ||
1974 | }else | ||
1975 | if (func!=NULL) { | ||
1976 | str = JS_NewStringCopyZ(cx, entry->name); | ||
1977 | args[0] = STRING_TO_JSVAL(str); | ||
1978 | if(!JS_CallFunction(cx, obj, func, 1, args, &v)){ | ||
1979 | goto out; | ||
1980 | } | ||
1981 | |||
1982 | if (v==JSVAL_FALSE) { | ||
1983 | continue; | ||
1984 | } | ||
1985 | } | ||
1986 | |||
1987 | filePath = js_combinePath(cx, file->path, (char*)entry->name); | ||
1988 | |||
1989 | eachFile = js_NewFileObject(cx, filePath); | ||
1990 | siliconforks | 507 | cx->free(filePath); |
1991 | siliconforks | 332 | if (!eachFile){ |
1992 | JS_ReportWarning(cx, "File %s cannot be retrieved", filePath); | ||
1993 | continue; | ||
1994 | } | ||
1995 | v = OBJECT_TO_JSVAL(eachFile); | ||
1996 | JS_SetElement(cx, array, len, &v); | ||
1997 | JS_SetProperty(cx, array, entry->name, &v); | ||
1998 | len++; | ||
1999 | } | ||
2000 | |||
2001 | if(PR_CloseDir(dir)!=PR_SUCCESS){ | ||
2002 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
2003 | JSFILEMSG_OP_FAILED, "close", file->path); | ||
2004 | goto out; | ||
2005 | } | ||
2006 | *rval = OBJECT_TO_JSVAL(array); | ||
2007 | return JS_TRUE; | ||
2008 | out: | ||
2009 | *rval = JSVAL_NULL; | ||
2010 | return JS_FALSE; | ||
2011 | } | ||
2012 | |||
2013 | static JSBool | ||
2014 | file_mkdir(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) | ||
2015 | { | ||
2016 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
2017 | |||
2018 | SECURITY_CHECK(cx, NULL, "mkdir", file); | ||
2019 | JSFILE_CHECK_ONE_ARG("mkdir"); | ||
2020 | JSFILE_CHECK_NATIVE("mkdir"); | ||
2021 | |||
2022 | /* if the current file is not a directory, find out the directory name */ | ||
2023 | if (!js_isDirectory(cx, file)) { | ||
2024 | char *dir = js_fileDirectoryName(cx, file->path); | ||
2025 | JSObject *dirObj = js_NewFileObject(cx, dir); | ||
2026 | |||
2027 | siliconforks | 507 | cx->free(dir); |
2028 | siliconforks | 332 | |
2029 | /* call file_mkdir with the right set of parameters if needed */ | ||
2030 | if (file_mkdir(cx, dirObj, argc, argv, rval)) | ||
2031 | return JS_TRUE; | ||
2032 | else | ||
2033 | goto out; | ||
2034 | }else{ | ||
2035 | siliconforks | 507 | JSString *str = JS_ValueToString(cx, argv[0]); |
2036 | if (!str) | ||
2037 | goto out; | ||
2038 | |||
2039 | char *dirName = JS_GetStringBytes(str); | ||
2040 | siliconforks | 332 | char *fullName; |
2041 | |||
2042 | fullName = js_combinePath(cx, file->path, dirName); | ||
2043 | if (PR_MkDir(fullName, 0755)==PR_SUCCESS){ | ||
2044 | *rval = JSVAL_TRUE; | ||
2045 | siliconforks | 507 | cx->free(fullName); |
2046 | siliconforks | 332 | return JS_TRUE; |
2047 | }else{ | ||
2048 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
2049 | JSFILEMSG_OP_FAILED, "mkdir", fullName); | ||
2050 | siliconforks | 507 | cx->free(fullName); |
2051 | siliconforks | 332 | goto out; |
2052 | } | ||
2053 | } | ||
2054 | out: | ||
2055 | *rval = JSVAL_FALSE; | ||
2056 | return JS_FALSE; | ||
2057 | } | ||
2058 | |||
2059 | static JSBool | ||
2060 | file_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval*rval) | ||
2061 | { | ||
2062 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
2063 | JSString *str; | ||
2064 | |||
2065 | str = JS_NewStringCopyZ(cx, file->path); | ||
2066 | if (!str) | ||
2067 | return JS_FALSE; | ||
2068 | *rval = STRING_TO_JSVAL(str); | ||
2069 | return JS_TRUE; | ||
2070 | } | ||
2071 | |||
2072 | static JSBool | ||
2073 | file_toURL(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) | ||
2074 | { | ||
2075 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
2076 | char url[MAX_PATH_LENGTH]; | ||
2077 | jschar *urlChars; | ||
2078 | size_t len; | ||
2079 | JSString *str; | ||
2080 | |||
2081 | JSFILE_CHECK_NATIVE("toURL"); | ||
2082 | |||
2083 | sprintf(url, "file://%s", file->path); | ||
2084 | |||
2085 | len = strlen(url); | ||
2086 | urlChars = js_InflateString(cx, url, &len); | ||
2087 | if (!urlChars) | ||
2088 | return JS_FALSE; | ||
2089 | str = js_NewString(cx, urlChars, len); | ||
2090 | if (!str) { | ||
2091 | siliconforks | 507 | cx->free(urlChars); |
2092 | siliconforks | 332 | return JS_FALSE; |
2093 | } | ||
2094 | *rval = STRING_TO_JSVAL(str); | ||
2095 | |||
2096 | /* TODO: js_escape in jsstr.h may go away at some point */ | ||
2097 | return js_str_escape(cx, obj, 0, rval, rval); | ||
2098 | |||
2099 | out: | ||
2100 | *rval = JSVAL_VOID; | ||
2101 | return JS_FALSE; | ||
2102 | } | ||
2103 | |||
2104 | |||
2105 | static void | ||
2106 | file_finalize(JSContext *cx, JSObject *obj) | ||
2107 | { | ||
2108 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
2109 | |||
2110 | if(file) { | ||
2111 | /* Close the file before exiting. */ | ||
2112 | if(file->isOpen && !file->isNative) { | ||
2113 | jsval vp; | ||
2114 | file_close(cx, obj, 0, NULL, &vp); | ||
2115 | } | ||
2116 | |||
2117 | if (file->path) | ||
2118 | siliconforks | 507 | cx->free(file->path); |
2119 | siliconforks | 332 | |
2120 | siliconforks | 507 | cx->free(file); |
2121 | siliconforks | 332 | } |
2122 | } | ||
2123 | |||
2124 | /* | ||
2125 | Allocates memory for the file object, sets fields to defaults. | ||
2126 | */ | ||
2127 | static JSFile* | ||
2128 | file_init(JSContext *cx, JSObject *obj, char *bytes) | ||
2129 | { | ||
2130 | JSFile *file; | ||
2131 | |||
2132 | siliconforks | 507 | file = cx->malloc(sizeof *file); |
2133 | siliconforks | 332 | if (!file) |
2134 | return NULL; | ||
2135 | memset(file, 0 , sizeof *file); | ||
2136 | |||
2137 | js_ResetAttributes(file); | ||
2138 | |||
2139 | file->path = RESOLVE_PATH(cx, bytes); | ||
2140 | |||
2141 | if (!JS_SetPrivate(cx, obj, file)) { | ||
2142 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
2143 | JSFILEMSG_CANNOT_SET_PRIVATE_FILE, file->path); | ||
2144 | siliconforks | 507 | cx->free(file); |
2145 | siliconforks | 332 | return NULL; |
2146 | } | ||
2147 | |||
2148 | return file; | ||
2149 | } | ||
2150 | |||
2151 | /* Returns a JSObject. This function is globally visible */ | ||
2152 | JS_PUBLIC_API(JSObject*) | ||
2153 | js_NewFileObject(JSContext *cx, char *filename) | ||
2154 | { | ||
2155 | JSObject *obj; | ||
2156 | JSFile *file; | ||
2157 | |||
2158 | obj = JS_NewObject(cx, &js_FileClass, NULL, NULL); | ||
2159 | if (!obj){ | ||
2160 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
2161 | JSFILEMSG_OBJECT_CREATION_FAILED, "js_NewFileObject"); | ||
2162 | return NULL; | ||
2163 | } | ||
2164 | file = file_init(cx, obj, filename); | ||
2165 | if(!file) return NULL; | ||
2166 | return obj; | ||
2167 | } | ||
2168 | |||
2169 | /* Internal function, used for cases which NSPR file support doesn't cover */ | ||
2170 | JSObject* | ||
2171 | js_NewFileObjectFromFILE(JSContext *cx, FILE *nativehandle, char *filename, | ||
2172 | int32 mode, JSBool open, JSBool randomAccess) | ||
2173 | { | ||
2174 | JSObject *obj; | ||
2175 | JSFile *file; | ||
2176 | |||
2177 | obj = JS_NewObject(cx, &js_FileClass, NULL, NULL); | ||
2178 | if (!obj){ | ||
2179 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
2180 | JSFILEMSG_OBJECT_CREATION_FAILED, "js_NewFileObjectFromFILE"); | ||
2181 | return NULL; | ||
2182 | } | ||
2183 | file = file_init(cx, obj, filename); | ||
2184 | if(!file) return NULL; | ||
2185 | |||
2186 | file->nativehandle = nativehandle; | ||
2187 | |||
2188 | /* free result of RESOLVE_PATH from file_init. */ | ||
2189 | JS_ASSERT(file->path != NULL); | ||
2190 | siliconforks | 507 | cx->free(file->path); |
2191 | siliconforks | 332 | |
2192 | file->path = strdup(filename); | ||
2193 | file->isOpen = open; | ||
2194 | file->mode = mode; | ||
2195 | file->hasRandomAccess = randomAccess; | ||
2196 | file->isNative = JS_TRUE; | ||
2197 | return obj; | ||
2198 | } | ||
2199 | |||
2200 | /* | ||
2201 | Real file constructor that is called from JavaScript. | ||
2202 | Basically, does error processing and calls file_init. | ||
2203 | */ | ||
2204 | static JSBool | ||
2205 | file_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, | ||
2206 | jsval *rval) | ||
2207 | { | ||
2208 | JSString *str; | ||
2209 | JSFile *file; | ||
2210 | |||
2211 | siliconforks | 460 | if (!JS_IsConstructing(cx)) { |
2212 | siliconforks | 332 | /* Replace obj with a new File object. */ |
2213 | obj = JS_NewObject(cx, &js_FileClass, NULL, NULL); | ||
2214 | if (!obj) | ||
2215 | return JS_FALSE; | ||
2216 | *rval = OBJECT_TO_JSVAL(obj); | ||
2217 | } | ||
2218 | |||
2219 | str = (argc == 0) | ||
2220 | ? JS_InternString(cx, "") | ||
2221 | : JS_ValueToString(cx, argv[0]); | ||
2222 | |||
2223 | if (!str) { | ||
2224 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
2225 | JSFILEMSG_FIRST_ARGUMENT_CONSTRUCTOR_NOT_STRING_ERROR, | ||
2226 | argv[0]); | ||
2227 | return JS_FALSE; | ||
2228 | } | ||
2229 | |||
2230 | file = file_init(cx, obj, JS_GetStringBytes(str)); | ||
2231 | if (!file) | ||
2232 | return JS_FALSE; | ||
2233 | |||
2234 | SECURITY_CHECK(cx, NULL, "constructor", file); | ||
2235 | |||
2236 | return JS_TRUE; | ||
2237 | } | ||
2238 | |||
2239 | /* -------------------- File methods and properties ------------------------- */ | ||
2240 | static JSFunctionSpec file_functions[] = { | ||
2241 | { "open", file_open, 0}, | ||
2242 | { "close", file_close, 0}, | ||
2243 | { "remove", file_remove, 0}, | ||
2244 | { "copyTo", file_copyTo, 0}, | ||
2245 | { "renameTo", file_renameTo, 0}, | ||
2246 | { "flush", file_flush, 0}, | ||
2247 | { "seek", file_seek, 0}, | ||
2248 | { "read", file_read, 0}, | ||
2249 | { "readln", file_readln, 0}, | ||
2250 | { "readAll", file_readAll, 0}, | ||
2251 | { "write", file_write, 0}, | ||
2252 | { "writeln", file_writeln, 0}, | ||
2253 | { "writeAll", file_writeAll, 0}, | ||
2254 | { "list", file_list, 0}, | ||
2255 | { "mkdir", file_mkdir, 0}, | ||
2256 | { "toString", file_toString, 0}, | ||
2257 | { "toURL", file_toURL, 0}, | ||
2258 | {0} | ||
2259 | }; | ||
2260 | |||
2261 | enum file_tinyid { | ||
2262 | FILE_LENGTH = -2, | ||
2263 | FILE_PARENT = -3, | ||
2264 | FILE_PATH = -4, | ||
2265 | FILE_NAME = -5, | ||
2266 | FILE_ISDIR = -6, | ||
2267 | FILE_ISFILE = -7, | ||
2268 | FILE_EXISTS = -8, | ||
2269 | FILE_CANREAD = -9, | ||
2270 | FILE_CANWRITE = -10, | ||
2271 | FILE_OPEN = -11, | ||
2272 | FILE_TYPE = -12, | ||
2273 | FILE_MODE = -13, | ||
2274 | FILE_CREATED = -14, | ||
2275 | FILE_MODIFIED = -15, | ||
2276 | FILE_SIZE = -16, | ||
2277 | FILE_RANDOMACCESS = -17, | ||
2278 | FILE_POSITION = -18, | ||
2279 | FILE_APPEND = -19, | ||
2280 | FILE_REPLACE = -20, | ||
2281 | FILE_AUTOFLUSH = -21, | ||
2282 | FILE_ISNATIVE = -22, | ||
2283 | }; | ||
2284 | |||
2285 | static JSPropertySpec file_props[] = { | ||
2286 | {"length", FILE_LENGTH, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2287 | {"parent", FILE_PARENT, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2288 | {"path", FILE_PATH, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2289 | {"name", FILE_NAME, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2290 | {"isDirectory", FILE_ISDIR, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2291 | {"isFile", FILE_ISFILE, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2292 | {"exists", FILE_EXISTS, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2293 | {"canRead", FILE_CANREAD, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2294 | {"canWrite", FILE_CANWRITE, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2295 | {"canAppend", FILE_APPEND, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2296 | {"canReplace", FILE_REPLACE, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2297 | {"isOpen", FILE_OPEN, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2298 | {"type", FILE_TYPE, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2299 | {"mode", FILE_MODE, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2300 | {"creationTime", FILE_CREATED, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2301 | {"lastModified", FILE_MODIFIED, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2302 | {"size", FILE_SIZE, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2303 | {"hasRandomAccess", FILE_RANDOMACCESS, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2304 | {"hasAutoFlush", FILE_AUTOFLUSH, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2305 | {"position", FILE_POSITION, JSPROP_ENUMERATE }, | ||
2306 | {"isNative", FILE_ISNATIVE, JSPROP_ENUMERATE | JSPROP_READONLY }, | ||
2307 | {0} | ||
2308 | }; | ||
2309 | |||
2310 | /* ------------------------- Property getter/setter ------------------------- */ | ||
2311 | static JSBool | ||
2312 | file_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) | ||
2313 | { | ||
2314 | JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL); | ||
2315 | char *bytes; | ||
2316 | JSString *str; | ||
2317 | jsint tiny; | ||
2318 | PRFileInfo info; | ||
2319 | JSBool flag; | ||
2320 | PRExplodedTime expandedTime; | ||
2321 | |||
2322 | tiny = JSVAL_TO_INT(id); | ||
2323 | if (!file) | ||
2324 | return JS_TRUE; | ||
2325 | |||
2326 | switch (tiny) { | ||
2327 | case FILE_PARENT: | ||
2328 | SECURITY_CHECK(cx, NULL, "parent", file); | ||
2329 | if (!js_parent(cx, file, vp)) | ||
2330 | return JS_FALSE; | ||
2331 | break; | ||
2332 | case FILE_PATH: | ||
2333 | str = JS_NewStringCopyZ(cx, file->path); | ||
2334 | if (!str) | ||
2335 | return JS_FALSE; | ||
2336 | *vp = STRING_TO_JSVAL(str); | ||
2337 | break; | ||
2338 | case FILE_NAME: | ||
2339 | if (!js_name(cx, file, vp)) | ||
2340 | return JS_FALSE; | ||
2341 | break; | ||
2342 | case FILE_ISDIR: | ||
2343 | SECURITY_CHECK(cx, NULL, "isDirectory", file); | ||
2344 | *vp = BOOLEAN_TO_JSVAL(js_isDirectory(cx, file)); | ||
2345 | break; | ||
2346 | case FILE_ISFILE: | ||
2347 | SECURITY_CHECK(cx, NULL, "isFile", file); | ||
2348 | *vp = BOOLEAN_TO_JSVAL(js_isFile(cx, file)); | ||
2349 | break; | ||
2350 | case FILE_EXISTS: | ||
2351 | SECURITY_CHECK(cx, NULL, "exists", file); | ||
2352 | *vp = BOOLEAN_TO_JSVAL(js_exists(cx, file)); | ||
2353 | break; | ||
2354 | case FILE_ISNATIVE: | ||
2355 | SECURITY_CHECK(cx, NULL, "isNative", file); | ||
2356 | *vp = BOOLEAN_TO_JSVAL(file->isNative); | ||
2357 | break; | ||
2358 | case FILE_CANREAD: | ||
2359 | SECURITY_CHECK(cx, NULL, "canRead", file); | ||
2360 | *vp = BOOLEAN_TO_JSVAL(js_canRead(cx, file)); | ||
2361 | break; | ||
2362 | case FILE_CANWRITE: | ||
2363 | SECURITY_CHECK(cx, NULL, "canWrite", file); | ||
2364 | *vp = BOOLEAN_TO_JSVAL(js_canWrite(cx, file)); | ||
2365 | break; | ||
2366 | case FILE_OPEN: | ||
2367 | SECURITY_CHECK(cx, NULL, "isOpen", file); | ||
2368 | *vp = BOOLEAN_TO_JSVAL(file->isOpen); | ||
2369 | break; | ||
2370 | case FILE_APPEND : | ||
2371 | SECURITY_CHECK(cx, NULL, "canAppend", file); | ||
2372 | JSFILE_CHECK_OPEN("canAppend"); | ||
2373 | *vp = BOOLEAN_TO_JSVAL(!file->isNative && | ||
2374 | (file->mode&PR_APPEND)==PR_APPEND); | ||
2375 | break; | ||
2376 | case FILE_REPLACE : | ||
2377 | SECURITY_CHECK(cx, NULL, "canReplace", file); | ||
2378 | JSFILE_CHECK_OPEN("canReplace"); | ||
2379 | *vp = BOOLEAN_TO_JSVAL(!file->isNative && | ||
2380 | (file->mode&PR_TRUNCATE)==PR_TRUNCATE); | ||
2381 | break; | ||
2382 | case FILE_AUTOFLUSH : | ||
2383 | SECURITY_CHECK(cx, NULL, "hasAutoFlush", file); | ||
2384 | JSFILE_CHECK_OPEN("hasAutoFlush"); | ||
2385 | *vp = BOOLEAN_TO_JSVAL(!file->isNative && file->hasAutoflush); | ||
2386 | break; | ||
2387 | case FILE_TYPE: | ||
2388 | SECURITY_CHECK(cx, NULL, "type", file); | ||
2389 | JSFILE_CHECK_OPEN("type"); | ||
2390 | if(js_isDirectory(cx, file)){ | ||
2391 | *vp = JSVAL_VOID; | ||
2392 | break; | ||
2393 | } | ||
2394 | |||
2395 | switch (file->type) { | ||
2396 | case ASCII: | ||
2397 | *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, asciistring)); | ||
2398 | break; | ||
2399 | case UTF8: | ||
2400 | *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, utfstring)); | ||
2401 | break; | ||
2402 | case UCS2: | ||
2403 | *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, unicodestring)); | ||
2404 | break; | ||
2405 | default: | ||
2406 | JS_ReportWarning(cx, "Unsupported file type %d, proceeding", | ||
2407 | file->type); | ||
2408 | } | ||
2409 | break; | ||
2410 | case FILE_MODE: | ||
2411 | SECURITY_CHECK(cx, NULL, "mode", file); | ||
2412 | JSFILE_CHECK_OPEN("mode"); | ||
2413 | siliconforks | 507 | bytes = cx->malloc(MODE_SIZE); |
2414 | siliconforks | 332 | bytes[0] = '\0'; |
2415 | flag = JS_FALSE; | ||
2416 | |||
2417 | if ((file->mode&PR_RDONLY)==PR_RDONLY) { | ||
2418 | if (flag) strcat(bytes, ","); | ||
2419 | strcat(bytes, "read"); | ||
2420 | flag = JS_TRUE; | ||
2421 | } | ||
2422 | if ((file->mode&PR_WRONLY)==PR_WRONLY) { | ||
2423 | if (flag) strcat(bytes, ","); | ||
2424 | strcat(bytes, "write"); | ||
2425 | flag = JS_TRUE; | ||
2426 | } | ||
2427 | if ((file->mode&PR_RDWR)==PR_RDWR) { | ||
2428 | if (flag) strcat(bytes, ","); | ||
2429 | strcat(bytes, "readWrite"); | ||
2430 | flag = JS_TRUE; | ||
2431 | } | ||
2432 | if ((file->mode&PR_APPEND)==PR_APPEND) { | ||
2433 | if (flag) strcat(bytes, ","); | ||
2434 | strcat(bytes, "append"); | ||
2435 | flag = JS_TRUE; | ||
2436 | } | ||
2437 | if ((file->mode&PR_CREATE_FILE)==PR_CREATE_FILE) { | ||
2438 | if (flag) strcat(bytes, ","); | ||
2439 | strcat(bytes, "create"); | ||
2440 | flag = JS_TRUE; | ||
2441 | } | ||
2442 | if ((file->mode&PR_TRUNCATE)==PR_TRUNCATE) { | ||
2443 | if (flag) strcat(bytes, ","); | ||
2444 | strcat(bytes, "replace"); | ||
2445 | flag = JS_TRUE; | ||
2446 | } | ||
2447 | if (file->hasAutoflush) { | ||
2448 | if (flag) strcat(bytes, ","); | ||
2449 | strcat(bytes, "hasAutoFlush"); | ||
2450 | flag = JS_TRUE; | ||
2451 | } | ||
2452 | *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, bytes)); | ||
2453 | siliconforks | 507 | cx->free(bytes); |
2454 | siliconforks | 332 | break; |
2455 | case FILE_CREATED: | ||
2456 | SECURITY_CHECK(cx, NULL, "creationTime", file); | ||
2457 | JSFILE_CHECK_NATIVE("creationTime"); | ||
2458 | if(((file->isOpen)? | ||
2459 | PR_GetOpenFileInfo(file->handle, &info): | ||
2460 | PR_GetFileInfo(file->path, &info))!=PR_SUCCESS){ | ||
2461 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
2462 | JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path); | ||
2463 | goto out; | ||
2464 | } | ||
2465 | |||
2466 | PR_ExplodeTime(info.creationTime, PR_LocalTimeParameters,&expandedTime); | ||
2467 | *vp = OBJECT_TO_JSVAL(js_NewDateObject(cx, expandedTime.tm_year, | ||
2468 | expandedTime.tm_month, | ||
2469 | expandedTime.tm_mday, | ||
2470 | expandedTime.tm_hour, | ||
2471 | expandedTime.tm_min, | ||
2472 | expandedTime.tm_sec)); | ||
2473 | break; | ||
2474 | case FILE_MODIFIED: | ||
2475 | SECURITY_CHECK(cx, NULL, "lastModified", file); | ||
2476 | JSFILE_CHECK_NATIVE("lastModified"); | ||
2477 | if(((file->isOpen)? | ||
2478 | PR_GetOpenFileInfo(file->handle, &info): | ||
2479 | PR_GetFileInfo(file->path, &info))!=PR_SUCCESS){ | ||
2480 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
2481 | JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path); | ||
2482 | goto out; | ||
2483 | } | ||
2484 | |||
2485 | PR_ExplodeTime(info.modifyTime, PR_LocalTimeParameters, &expandedTime); | ||
2486 | *vp = OBJECT_TO_JSVAL(js_NewDateObject(cx, expandedTime.tm_year, | ||
2487 | expandedTime.tm_month, | ||
2488 | expandedTime.tm_mday, | ||
2489 | expandedTime.tm_hour, | ||
2490 | expandedTime.tm_min, | ||
2491 | expandedTime.tm_sec)); | ||
2492 | break; | ||
2493 | case FILE_SIZE: | ||
2494 | SECURITY_CHECK(cx, NULL, "size", file); | ||
2495 | *vp = js_size(cx, file); | ||
2496 | break; | ||
2497 | case FILE_LENGTH: | ||
2498 | SECURITY_CHECK(cx, NULL, "length", file); | ||
2499 | JSFILE_CHECK_NATIVE("length"); | ||
2500 | |||
2501 | if (js_isDirectory(cx, file)) { /* XXX debug me */ | ||
2502 | PRDir *dir; | ||
2503 | PRDirEntry *entry; | ||
2504 | jsint count = 0; | ||
2505 | |||
2506 | if(!(dir = PR_OpenDir(file->path))){ | ||
2507 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
2508 | JSFILEMSG_CANNOT_OPEN_DIR, file->path); | ||
2509 | goto out; | ||
2510 | } | ||
2511 | |||
2512 | while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH))) { | ||
2513 | count++; | ||
2514 | } | ||
2515 | |||
2516 | if(!PR_CloseDir(dir)){ | ||
2517 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
2518 | JSFILEMSG_OP_FAILED, "close", file->path); | ||
2519 | |||
2520 | goto out; | ||
2521 | } | ||
2522 | |||
2523 | *vp = INT_TO_JSVAL(count); | ||
2524 | break; | ||
2525 | }else{ | ||
2526 | /* return file size */ | ||
2527 | *vp = js_size(cx, file); | ||
2528 | } | ||
2529 | break; | ||
2530 | case FILE_RANDOMACCESS: | ||
2531 | SECURITY_CHECK(cx, NULL, "hasRandomAccess", file); | ||
2532 | JSFILE_CHECK_OPEN("hasRandomAccess"); | ||
2533 | *vp = BOOLEAN_TO_JSVAL(file->hasRandomAccess); | ||
2534 | break; | ||
2535 | case FILE_POSITION: | ||
2536 | SECURITY_CHECK(cx, NULL, "position", file); | ||
2537 | JSFILE_CHECK_NATIVE("position"); | ||
2538 | JSFILE_CHECK_OPEN("position"); | ||
2539 | |||
2540 | if(!file->hasRandomAccess){ | ||
2541 | JS_ReportWarning(cx, "File %s doesn't support random access, can't report the position, proceeding"); | ||
2542 | *vp = JSVAL_VOID; | ||
2543 | break; | ||
2544 | } | ||
2545 | |||
2546 | if (file->isOpen && js_isFile(cx, file)) { | ||
2547 | int pos = PR_Seek(file->handle, 0, PR_SEEK_CUR); | ||
2548 | if(pos!=-1){ | ||
2549 | *vp = INT_TO_JSVAL(pos); | ||
2550 | }else{ | ||
2551 | JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, | ||
2552 | JSFILEMSG_CANNOT_REPORT_POSITION, file->path); | ||
2553 | goto out; | ||
2554 | } | ||
2555 | }else { | ||
2556 | JS_ReportWarning(cx, "File %s is closed or not a plain file," | ||
2557 | " can't report position, proceeding"); | ||
2558 | goto out; | ||
2559 | } | ||
2560 | break; | ||
2561 | default: | ||
2562 | SECURITY_CHECK(cx, NULL, "file_access", file); | ||
2563 | |||
2564 | /* this is some other property -- try to use the dir["file"] syntax */ | ||
2565 | if (js_isDirectory(cx, file)) { | ||
2566 | PRDir *dir = NULL; | ||
2567 | PRDirEntry *entry = NULL; | ||
2568 | char *prop_name; | ||
2569 | |||