1 : /* -*- mode: C -*-
2 : *
3 : * File: pdf-fsys-disk.c
4 : * Date: Thu May 22 18:27:35 2008
5 : *
6 : * GNU PDF Library - Disk Filesystem Implementation
7 : *
8 : */
9 :
10 : /* Copyright (C) 2008 Free Software Foundation, Inc. */
11 :
12 : /* This program is free software: you can redistribute it and/or modify
13 : * it under the terms of the GNU General Public License as published by
14 : * the Free Software Foundation, either version 3 of the License, or
15 : * (at your option) any later version.
16 : *
17 : * This program is distributed in the hope that it will be useful,
18 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : * GNU General Public License for more details.
21 : *
22 : * You should have received a copy of the GNU General Public License
23 : * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : */
25 :
26 : #include <config.h>
27 :
28 : #include <errno.h>
29 : #include <stdio.h>
30 : #include <stdio-safer.h>
31 : #include <string.h>
32 : #include <sys/stat.h>
33 :
34 : #if defined PDF_HOST_WIN32 || defined PDF_HOST_BSD
35 : # include <sys/param.h>
36 : # if defined PDF_HOST_BSD
37 : # include <sys/mount.h>
38 : # endif /* PDF_HOST_BSD */
39 : #else
40 : # include <sys/statfs.h>
41 : #endif /* PDF_HOST_WIN32 | PDF_HOST_BSD */
42 :
43 : #if defined PDF_HOST_WIN32
44 : # include <windows.h>
45 : # include <wchar.h>
46 : #endif /* !PDF_HOST_WIN32 */
47 :
48 : #include <dirent.h>
49 : #include <unistd.h>
50 :
51 : #include <pdf-types.h>
52 : #include <pdf-error.h>
53 : #include <pdf-fsys-disk.h>
54 :
55 : /* Private function declarations */
56 :
57 : static pdf_status_t
58 : __pdf_fsys_disk_get_status_from_errno(int _errno);
59 : static pdf_status_t
60 : __pdf_fsys_disk_get_host_path (const pdf_text_t path,
61 : pdf_char_t **host_path,
62 : pdf_size_t *host_path_size);
63 : static pdf_status_t
64 : __pdf_fsys_disk_set_host_path (const pdf_char_t *host_path,
65 : const pdf_size_t host_path_size,
66 : pdf_text_t *p_path);
67 : static pdf_status_t
68 : __pdf_fsys_disk_is_writable_from_host_path(const pdf_char_t *host_path,
69 : pdf_bool_t *p_result);
70 : static pdf_status_t
71 : __pdf_fsys_disk_is_readable_from_host_path(const pdf_char_t *host_path,
72 : pdf_bool_t *p_result);
73 : static pdf_status_t
74 : __pdf_fsys_disk_file_get_size_from_host_path(const pdf_char_t *host_path,
75 : pdf_size_t *p_result);
76 : static const pdf_char_t *
77 : __pdf_fsys_disk_get_mode_string(const enum pdf_fsys_file_mode_e mode);
78 :
79 : #ifdef PDF_HOST_WIN32
80 : static pdf_bool_t
81 : __pdf_fsys_disk_win32_device_p (pdf_text_t path);
82 : #endif
83 :
84 : /*
85 : * Filesystem Interface Implementation
86 : */
87 :
88 : pdf_status_t
89 : pdf_fsys_disk_init (void **data)
90 0 : {
91 : /* Do nothing. */
92 0 : *data = NULL;
93 0 : return PDF_OK;
94 : }
95 :
96 : pdf_status_t
97 : pdf_fsys_disk_cleanup (void *data)
98 0 : {
99 : /* Do nothing. */
100 0 : return PDF_OK;
101 : }
102 :
103 : #ifdef PDF_HOST_WIN32
104 :
105 : pdf_i64_t
106 : pdf_fsys_disk_get_free_space (void *data,
107 : pdf_text_t path_name)
108 : {
109 : pdf_char_t *utf16le_path = NULL;
110 : pdf_u32_t utf16le_path_size = 0;
111 : ULARGE_INTEGER free_bytes;
112 : pdf_i64_t result = pdf_i64_new((32 << 1),1); /* (-1) */
113 :
114 : /* Note that as we get the string as UTF-16LE with LAST NUL suffix,
115 : * it's equivalent to a wchar_t in windows environments */
116 :
117 :
118 : if (pdf_text_get_unicode (&utf16le_path,
119 : &utf16le_path_size,
120 : path_name,
121 : PDF_TEXT_UTF16_LE,
122 : (PDF_TEXT_UNICODE_WITH_NUL_SUFFIX | \
123 : PDF_TEXT_UNICODE_WITH_BOM)) != PDF_OK)
124 : {
125 : PDF_DEBUG_BASE("Couldn't get UTF-16LE path");
126 : }
127 : else
128 : {
129 : /* No need to get the drive letter of the specified path:
130 : * This parameter does not have to specify the root directory on a disk.
131 : * The function accepts any directory on a disk.
132 : **/
133 :
134 :
135 : /* Get the information from the filesystem
136 : *
137 : * BOOL WINAPI GetDiskFreeSpaceEx(
138 : * __in_opt LPCTSTR lpDirectoryName,
139 : * __out_opt PULARGE_INTEGER lpFreeBytesAvailable,
140 : * __out_opt PULARGE_INTEGER lpTotalNumberOfBytes,
141 : * __out_opt PULARGE_INTEGER lpTotalNumberOfFreeBytes
142 : * );
143 : *
144 : **/
145 : if (GetDiskFreeSpaceExW ((LPCWSTR) utf16le_path,
146 : NULL,
147 : NULL,
148 : &free_bytes))
149 : {
150 : pdf_status_t i64_ret_code;
151 : /* Assign the number of bytes in the pdf_i64_t */
152 : pdf_i64_assign(&result,
153 : free_bytes.HighPart,
154 : free_bytes.LowPart,
155 : &i64_ret_code);
156 : }
157 :
158 : /* Cleanup */
159 : pdf_dealloc (utf16le_path);
160 : }
161 :
162 : /* Return the free space in octects */
163 : return result;
164 : }
165 :
166 : #else
167 :
168 : pdf_i64_t
169 : pdf_fsys_disk_get_free_space (void *data,
170 : pdf_text_t path_name)
171 2 : {
172 2 : pdf_i64_t result = pdf_i64_new((32 << 1),1); /* (-1) */
173 :
174 : /* Safety check that path_name is a valid pointer */
175 2 : if(path_name != NULL)
176 : {
177 : struct statfs fs_stats;
178 2 : pdf_char_t *host_path = NULL;
179 2 : pdf_size_t host_path_size = 0;
180 :
181 :
182 : /* We get the string in HOST-encoding (with NUL-suffix) */
183 2 : if (__pdf_fsys_disk_get_host_path (path_name,
184 : &host_path,
185 : &host_path_size) != PDF_OK)
186 : {
187 : PDF_DEBUG_BASE("Couldn't get host-encoded path");
188 : }
189 : else
190 : {
191 : PDF_DEBUG_BASE("Getting free bytes of FS at path '%s'...", host_path);
192 2 : if (statfs ((const char *) host_path, &fs_stats) == 0)
193 : {
194 1 : pdf_status_t i64_ret_code = PDF_OK;
195 : /* Compute the number of bytes in the pdf_i64_t */
196 1 : pdf_i64_assign_quick(&result,
197 : fs_stats.f_bfree,
198 : &i64_ret_code);
199 : /* Only continue operation if assign is OK */
200 1 : if(i64_ret_code == PDF_OK)
201 : {
202 1 : pdf_i64_mult_i32(&result,
203 : result,
204 : fs_stats.f_bsize,
205 : &i64_ret_code);
206 : }
207 : /* If any of the previous failed, reset return value */
208 1 : if(i64_ret_code != PDF_OK)
209 : {
210 : PDF_DEBUG_BASE("Couldn't compute bfree*bsize");
211 0 : pdf_i64_assign_quick(&result, -1, &i64_ret_code); /* (-1) */
212 : }
213 : }
214 : else
215 : {
216 : PDF_DEBUG_BASE("Statfs failed... at path: '%s'", host_path);
217 : }
218 :
219 : /* Cleanup */
220 2 : pdf_dealloc (host_path);
221 : }
222 : }
223 :
224 : /* Return the free space in octects */
225 2 : return result;
226 : }
227 :
228 : #endif /* !PDF_HOST_WIN32 */
229 :
230 :
231 :
232 : /* Private function to de-initialize and de-allocate base file data */
233 : static void
234 : __pdf_fsys_deinit_base_file_data(pdf_fsys_disk_file_t *p_file_data)
235 25 : {
236 25 : if((p_file_data != NULL) && \
237 : (*p_file_data != NULL))
238 : {
239 25 : if((*p_file_data)->unicode_path != NULL)
240 : {
241 25 : pdf_text_destroy ((*p_file_data)->unicode_path);
242 : }
243 25 : if((*p_file_data)->host_path != NULL)
244 : {
245 25 : pdf_dealloc((*p_file_data)->host_path);
246 : }
247 25 : pdf_dealloc (*p_file_data);
248 25 : *p_file_data = NULL;
249 : }
250 25 : }
251 :
252 :
253 : /* Private function to allocate and initialize base file data */
254 : static pdf_fsys_disk_file_t
255 : __pdf_fsys_init_base_file_data(const pdf_text_t path_name)
256 25 : {
257 25 : pdf_fsys_disk_file_t file_data = NULL;
258 25 : if(path_name != NULL)
259 : {
260 : /* Allocate private data storage for the file */
261 25 : file_data = (pdf_fsys_disk_file_t) pdf_alloc (sizeof(struct pdf_fsys_disk_file_s));
262 25 : if(file_data != NULL)
263 : {
264 25 : memset(file_data, 0, sizeof(struct pdf_fsys_disk_file_s));
265 :
266 : /* Make and store a copy of the unicode file path and get the host
267 : encoded path */
268 25 : file_data->unicode_path = pdf_text_dup (path_name);
269 25 : if(file_data->unicode_path != NULL)
270 : {
271 25 : if (__pdf_fsys_disk_get_host_path(file_data->unicode_path,
272 : &(file_data->host_path),
273 : &(file_data->host_path_size)) != PDF_OK)
274 : {
275 0 : pdf_text_destroy(file_data->unicode_path);
276 0 : pdf_dealloc(file_data);
277 0 : file_data = NULL;
278 : }
279 : }
280 : else
281 : {
282 0 : pdf_dealloc(file_data);
283 0 : file_data = NULL;
284 : }
285 : }
286 : }
287 25 : return file_data;
288 : }
289 :
290 :
291 :
292 : /* Host-dependent fopen() */
293 : #ifdef PDF_HOST_WIN32
294 : #define PDF_FOPEN(f,m) _wfopen((wchar_t *)f,(wchar_t *)m)
295 : #else
296 : #define PDF_FOPEN(f,m) fopen_safer((char *)f,(char *)m)
297 : #endif
298 :
299 :
300 : pdf_status_t
301 : pdf_fsys_disk_file_open (void *data,
302 : const pdf_text_t path_name,
303 : const enum pdf_fsys_file_mode_e mode,
304 : pdf_fsys_file_t *p_file)
305 24 : {
306 24 : pdf_status_t ret_status = PDF_EBADDATA;
307 :
308 24 : if((path_name != NULL) && \
309 : (p_file != NULL))
310 : {
311 24 : pdf_fsys_file_t file = NULL;
312 24 : pdf_fsys_disk_file_t file_data = NULL;
313 : const pdf_char_t * mode_str;
314 :
315 : /* Allocate file struct */
316 24 : file = (pdf_fsys_file_t)pdf_alloc(sizeof(struct pdf_fsys_file_s));
317 :
318 24 : if(file != NULL)
319 : {
320 : /* Get base data */
321 24 : file_data = __pdf_fsys_init_base_file_data(path_name);
322 :
323 : /* Get the mode string for fopen */
324 24 : mode_str =__pdf_fsys_disk_get_mode_string(mode);
325 :
326 : /* Only continue if previous operations went ok */
327 24 : if((file_data != NULL) && \
328 : (mode_str != NULL))
329 : {
330 : /* Open the file */
331 24 : file_data->file_descriptor = PDF_FOPEN(file_data->host_path, mode_str);
332 : /* If got a good FD, set output data */
333 24 : if (file_data->file_descriptor != NULL)
334 : {
335 : /* Store the mode */
336 22 : file_data->file_mode = mode;
337 : /* Store reference to the file data in the output variable*/
338 22 : file->data = (void *) file_data;
339 : /* Set the filesystem for the file */
340 22 : file->fs = NULL; /* This is the default filesystem */
341 :
342 : /* Finally, if everything went ok, put output element */
343 22 : *p_file = file;
344 :
345 : /* All ok ! */
346 22 : ret_status = PDF_OK;
347 : }
348 : else
349 : {
350 : PDF_DEBUG_BASE("fopen failed...");
351 : /* Deallocate and deinit base file data */
352 2 : __pdf_fsys_deinit_base_file_data(&file_data);
353 2 : pdf_dealloc(file);
354 : /* Get pdf_status_t code from errno */
355 2 : ret_status = __pdf_fsys_disk_get_status_from_errno(errno);
356 : }
357 : }
358 : else
359 : {
360 0 : pdf_dealloc(file);
361 : }
362 : }
363 : }
364 :
365 : /* All was ok */
366 24 : return ret_status;
367 : }
368 :
369 : pdf_status_t
370 : pdf_fsys_disk_file_open_tmp (void *data,
371 : pdf_fsys_file_t *p_file)
372 1 : {
373 : pdf_text_t path_name;
374 1 : pdf_status_t ret_status = PDF_ERROR;
375 1 : pdf_fsys_file_t file = NULL;
376 1 : pdf_fsys_disk_file_t file_data = NULL;
377 :
378 :
379 1 : file = (pdf_fsys_file_t) pdf_alloc (sizeof (struct pdf_fsys_file_s));
380 1 : file->fs = NULL; /* Default filesystem. */
381 :
382 1 : if (file != NULL)
383 : {
384 : /* Create a dummy path name, so we can manage the temporary file
385 : like an ordinary file. */
386 1 : if (pdf_text_new_from_unicode ((pdf_char_t *) "tmp",
387 : 3,
388 : PDF_TEXT_UTF8,
389 : &path_name)
390 : != PDF_OK)
391 : {
392 0 : ret_status = PDF_ENOMEM;
393 : }
394 : else
395 : {
396 : /* Get base data. */
397 1 : file_data = __pdf_fsys_init_base_file_data (path_name);
398 1 : file_data->file_mode = PDF_FSYS_OPEN_MODE_RW;
399 :
400 : /* Open a temporary file. */
401 1 : file_data->file_descriptor = tmpfile_safer ();
402 1 : if (file_data->file_descriptor != NULL)
403 : {
404 : /* Success. */
405 1 : file->data = (void *) file_data;
406 1 : *p_file = file;
407 1 : ret_status = PDF_OK;
408 : }
409 : else
410 : {
411 0 : pdf_text_destroy (path_name);
412 : }
413 : }
414 : }
415 :
416 1 : return ret_status;
417 : }
418 :
419 :
420 : pdf_status_t
421 : pdf_fsys_disk_file_close (pdf_fsys_file_t file)
422 23 : {
423 23 : pdf_status_t ret_code = PDF_EBADDATA;
424 23 : if((file != NULL) && \
425 : (file->data != NULL))
426 : {
427 23 : ret_code = PDF_OK;
428 : /* Close the I/O stream only if already open */
429 23 : if(((pdf_fsys_disk_file_t)(file->data))->file_descriptor != NULL)
430 : {
431 23 : if(fclose (((pdf_fsys_disk_file_t)(file->data))->file_descriptor) == EOF)
432 : {
433 : PDF_DEBUG_BASE("fclose returned an error");
434 : /* An error was detected closing the I/O stream */
435 0 : ret_code = PDF_ERROR;
436 : }
437 : PDF_DEBUG_BASE("Closed");
438 : /* Deallocate other internal contents */
439 23 : __pdf_fsys_deinit_base_file_data((pdf_fsys_disk_file_t *)&(file->data));
440 : }
441 : else
442 : {
443 : PDF_DEBUG_BASE("File is already closed");
444 : }
445 :
446 23 : if(file != NULL)
447 : {
448 23 : pdf_dealloc(file);
449 : }
450 : }
451 23 : return ret_code;
452 : }
453 :
454 :
455 :
456 : /* Host-dependent mkdir() */
457 : #ifdef PDF_HOST_WIN32
458 : #define PDF_MKDIR(f,m) _wmkdir((const wchar_t *)f)
459 : #else
460 : #define PDF_MKDIR(f,m) mkdir((const char *)f,m)
461 : #endif
462 :
463 : pdf_status_t
464 : pdf_fsys_disk_create_folder (void *data,
465 : const pdf_text_t path_name)
466 0 : {
467 0 : pdf_status_t ret_code = PDF_EBADDATA;
468 0 : if(path_name != NULL)
469 : {
470 : pdf_char_t *host_path;
471 : pdf_size_t host_path_size;
472 :
473 : /* Default return code */
474 0 : ret_code = PDF_OK;
475 :
476 : /* Get a host-encoded version of the path name */
477 0 : if (__pdf_fsys_disk_get_host_path(path_name,
478 : &host_path,
479 : &host_path_size) != PDF_OK)
480 : {
481 : PDF_DEBUG_BASE("Couldn't get host path to create the folder");
482 0 : ret_code = PDF_ERROR;
483 : }
484 : else
485 : {
486 : /* Set the permissions of the new directory (posix-only):
487 : rwxr_xr_x
488 : */
489 : /* Open the file */
490 0 : if (PDF_MKDIR(host_path, \
491 : (S_IRUSR | S_IWUSR | S_IXUSR | \
492 : S_IRGRP | S_IXGRP | \
493 : S_IROTH | S_IXOTH)) != 0)
494 : {
495 : PDF_DEBUG_BASE("mkdir failed with errno '%d'", errno);
496 0 : ret_code = __pdf_fsys_disk_get_status_from_errno(errno);
497 : }
498 : }
499 : }
500 :
501 0 : return ret_code;
502 : }
503 :
504 : /* Host-dependent opendir(), closedir() and friends*/
505 : #ifdef PDF_HOST_WIN32
506 : #define PDF_DIR _WDIR
507 : #define pdf_dirent_s _wdirent
508 : #define PDF_OPENDIR(f) _wopendir((const wchar_t *)f)
509 : #define PDF_READDIR(ds) _wreaddir((PDF_DIR *)ds)
510 : #define PDF_CLOSEDIR(ds) _wclosedir((PDF_DIR *)ds)
511 : /* In mingw dir_entry->d_namlen is an array of FILENAME_MAX
512 : octects long. The dir_entry->d_namlen contain the length of
513 : the name stored in d_name */
514 : #define PDF_NAMELEN(de) (de->d_namlen)
515 : #else
516 : #define PDF_DIR DIR
517 : #define pdf_dirent_s dirent
518 : #define PDF_OPENDIR(f) opendir((const char *)f)
519 : #define PDF_READDIR(ds) readdir((PDF_DIR *)ds)
520 : #define PDF_CLOSEDIR(ds) closedir((PDF_DIR *)ds)
521 : /* In POSIX systems dir_entry->d_name is a NULL-terminated
522 : string */
523 : #define PDF_NAMELEN(de) (strlen(de->d_name))
524 :
525 : #endif /* !PDF_HOST_WIN32 */
526 :
527 :
528 : pdf_status_t
529 : pdf_fsys_disk_get_folder_contents (void *data,
530 : const pdf_text_t path_name,
531 : pdf_list_t item_list)
532 0 : {
533 0 : pdf_status_t ret_code = PDF_EBADDATA;
534 0 : if(path_name != NULL)
535 : {
536 0 : PDF_DIR *dir_stream = NULL;
537 0 : pdf_char_t *host_path = NULL;
538 : pdf_size_t host_path_size;
539 0 : pdf_text_t entry_text = NULL;
540 : pdf_u32_t name_length;
541 :
542 : /* Default here is ok... */
543 0 : ret_code = PDF_OK;
544 :
545 : /* Get the pathname in the host encoding */
546 0 : if (__pdf_fsys_disk_get_host_path(path_name,
547 : &host_path,
548 : &host_path_size) != PDF_OK)
549 : {
550 : PDF_DEBUG_BASE("Couldn't get host path to get folder contents");
551 0 : ret_code = PDF_ERROR;
552 : }
553 : else
554 : {
555 : /* Open the directory stream */
556 0 : dir_stream = PDF_OPENDIR(host_path);
557 0 : if (dir_stream == NULL)
558 : {
559 : PDF_DEBUG_BASE("opendir failed with errno: '%d'",errno);
560 0 : ret_code = __pdf_fsys_disk_get_status_from_errno(errno);
561 : }
562 : else
563 : {
564 0 : struct pdf_dirent_s *dir_entry = NULL;
565 : /* Scan directory contents */
566 0 : while ((ret_code == PDF_OK) && \
567 : (dir_stream != NULL) && \
568 : (dir_entry = PDF_READDIR (dir_stream)) != NULL)
569 : {
570 : /* Note that dir_entry is statically allocated and can be
571 : rewritten by a subsequent call. Also, there is not need to
572 : free that structure */
573 :
574 : /* Get the length of the entry name */
575 0 : name_length = PDF_NAMELEN(dir_entry);
576 :
577 : /* Create the text object containing the entry name */
578 0 : if ((__pdf_fsys_disk_set_host_path((pdf_char_t *)(dir_entry->d_name),
579 : name_length,
580 : &entry_text) != PDF_OK) ||
581 : (pdf_list_add_last (item_list,
582 : (void *) entry_text, NULL) != PDF_OK))
583 : {
584 : /* Stop loop and report an error */
585 0 : ret_code = PDF_ERROR;
586 : }
587 : }
588 : /* Close dir... */
589 0 : PDF_CLOSEDIR(dir_stream);
590 : }
591 : }
592 : }
593 0 : return ret_code;
594 : }
595 :
596 :
597 : pdf_status_t
598 : pdf_fsys_disk_get_parent (void *data,
599 : const pdf_text_t path_name,
600 : pdf_text_t parent_path)
601 0 : {
602 0 : pdf_status_t ret_code = PDF_EBADDATA;
603 0 : if((path_name != NULL) && \
604 : (parent_path != NULL))
605 : {
606 : /* TODO: This involves getting an absolute path from a relative path */
607 : }
608 :
609 0 : return ret_code;
610 : }
611 :
612 :
613 : /* Host-dependent rmdir() */
614 : #ifdef PDF_HOST_WIN32
615 : #define PDF_RMDIR(f) _wrmdir((wchar_t *)f)
616 : #else
617 : #define PDF_RMDIR(f) rmdir((char *)f)
618 : #endif
619 :
620 : pdf_status_t
621 : pdf_fsys_disk_remove_folder (void *data,
622 : const pdf_text_t path_name)
623 0 : {
624 0 : pdf_status_t ret_code = PDF_EBADDATA;
625 0 : if(path_name != NULL)
626 : {
627 : pdf_char_t *host_path;
628 : pdf_size_t host_path_size;
629 :
630 : /* Get the pathname in the host encoding */
631 0 : if (__pdf_fsys_disk_get_host_path (path_name,
632 : &host_path,
633 : &host_path_size) != PDF_OK)
634 : {
635 0 : ret_code = PDF_ERROR;
636 : }
637 : else
638 : {
639 : /* Try to remove the directory */
640 0 : if (PDF_RMDIR(host_path) != 0)
641 : {
642 : /* Cleanup */
643 0 : pdf_dealloc (host_path);
644 :
645 0 : ret_code = __pdf_fsys_disk_get_status_from_errno(errno);
646 : }
647 : }
648 : /* Cleanup */
649 0 : pdf_dealloc (host_path);
650 : }
651 :
652 0 : return ret_code;
653 : }
654 :
655 : /* Host-dependent access() */
656 : #ifdef PDF_HOST_WIN32
657 : #define PDF_ACCESS(f,m) _waccess((wchar_t *)f,m)
658 : #else
659 : #define PDF_ACCESS(f,m) access((char *)f,m)
660 : #endif
661 :
662 :
663 : static pdf_status_t
664 : __pdf_fsys_disk_is_readable_from_host_path(const pdf_char_t *host_path,
665 : pdf_bool_t *p_result)
666 0 : {
667 0 : pdf_status_t ret_code = PDF_EBADDATA;
668 : /* Check if file can be read */
669 0 : if((host_path != NULL) && \
670 : (p_result != NULL))
671 : {
672 0 : if(PDF_ACCESS(host_path, R_OK) == -1)
673 : {
674 : /* Now, either is not readable, or another error happened */
675 0 : if(errno == EACCES)
676 : {
677 0 : *p_result = PDF_FALSE;
678 0 : ret_code = PDF_OK;
679 : }
680 : else
681 : {
682 0 : ret_code = __pdf_fsys_disk_get_status_from_errno(errno);
683 : }
684 : }
685 : else
686 : {
687 0 : *p_result = PDF_TRUE;
688 0 : ret_code = PDF_OK;
689 : }
690 : }
691 0 : return ret_code;
692 : }
693 :
694 : static pdf_status_t
695 : __pdf_fsys_disk_is_writable_from_host_path(const pdf_char_t *host_path,
696 : pdf_bool_t *p_result)
697 0 : {
698 0 : pdf_status_t ret_code = PDF_EBADDATA;
699 : /* Check if file can be written */
700 0 : if((host_path != NULL) && \
701 : (p_result != NULL))
702 : {
703 0 : if(PDF_ACCESS(host_path, W_OK) == -1)
704 : {
705 : /* Now, either is not readable, or another error happened */
706 0 : if(errno == EACCES)
707 : {
708 0 : *p_result = PDF_FALSE;
709 0 : ret_code = PDF_OK;
710 : }
711 : else
712 : {
713 0 : ret_code = __pdf_fsys_disk_get_status_from_errno(errno);
714 : }
715 : }
716 : else
717 : {
718 0 : *p_result = PDF_TRUE;
719 0 : ret_code = PDF_OK;
720 : }
721 : }
722 0 : return ret_code;
723 : }
724 :
725 : /* Host-dependent stat() */
726 : #ifdef PDF_HOST_WIN32
727 : #define PDF_STAT(f,s) _wstat((wchar_t *)f,s)
728 : typedef struct _stat pdf_stat_s;
729 : #else
730 : #define PDF_STAT(f,s) stat((char *)f,s)
731 : typedef struct stat pdf_stat_s;
732 : #endif
733 :
734 : static pdf_status_t
735 : __pdf_fsys_disk_file_get_size_from_host_path(const pdf_char_t *host_path,
736 : pdf_size_t *p_result)
737 3 : {
738 3 : pdf_status_t ret_code = PDF_EBADDATA;
739 : /* Check if file can be written */
740 3 : if((host_path != NULL) && \
741 : (p_result != NULL))
742 : {
743 :
744 : /* TODO:
745 : * If available, we should try to use the 64-bit versions of stat() */
746 :
747 : pdf_stat_s file_info;
748 6 : if (PDF_STAT(host_path, &file_info) != 0)
749 : {
750 0 : ret_code = __pdf_fsys_disk_get_status_from_errno(errno);
751 : }
752 : else
753 : {
754 3 : *p_result = file_info.st_size;
755 3 : ret_code = PDF_OK;
756 : }
757 : }
758 :
759 3 : return ret_code;
760 : }
761 :
762 :
763 :
764 : pdf_status_t
765 : pdf_fsys_disk_get_item_props (void *data,
766 : pdf_text_t path_name,
767 : struct pdf_fsys_item_props_s *item_props)
768 0 : {
769 0 : pdf_char_t* host_path = NULL;
770 0 : pdf_size_t host_path_len = 0;
771 0 : pdf_status_t ret_code = PDF_EBADDATA;
772 :
773 : /* Get host path */
774 0 : if((path_name != NULL) && \
775 : (item_props != NULL))
776 : {
777 0 : ret_code = __pdf_fsys_disk_get_host_path (path_name,
778 : &host_path,
779 : &host_path_len);
780 : }
781 :
782 : /* Is readable ? */
783 0 : if(ret_code == PDF_OK)
784 : {
785 0 : ret_code = __pdf_fsys_disk_is_readable_from_host_path(host_path, \
786 : &(item_props->is_readable));
787 : }
788 :
789 : /* Is writable ? */
790 0 : if(ret_code == PDF_OK)
791 : {
792 0 : ret_code = __pdf_fsys_disk_is_writable_from_host_path(host_path, \
793 : &(item_props->is_writable));
794 : }
795 :
796 : /* TODO: is hidden ? */
797 :
798 :
799 : /* TODO: Get creation date */
800 :
801 :
802 : /* TODO: Get modification date */
803 :
804 :
805 : /* Get file size */
806 0 : if(ret_code == PDF_OK)
807 : {
808 : pdf_size_t size;
809 :
810 0 : ret_code = __pdf_fsys_disk_file_get_size_from_host_path(host_path, &size);
811 0 : if(ret_code == PDF_OK)
812 : {
813 0 : item_props->file_size_high = 0;
814 0 : item_props->file_size_low = size;
815 : }
816 : }
817 :
818 :
819 : /* TODO: Get folder size */
820 :
821 :
822 : /* Clean aux host path */
823 0 : if (host_path != NULL)
824 : {
825 0 : pdf_dealloc (host_path);
826 : }
827 :
828 0 : return ret_code;
829 : }
830 :
831 :
832 : pdf_bool_t
833 : pdf_fsys_disk_item_p (void *data,
834 : pdf_text_t path_name)
835 0 : {
836 : struct pdf_fsys_item_props_s item_props;
837 : #ifdef PDF_HOST_WIN32
838 : if (__pdf_fsys_disk_win32_device_p(path_name) == PDF_TRUE)
839 : {
840 : return PDF_TRUE;
841 : }
842 : #endif
843 0 : return ((pdf_fsys_disk_get_item_props(data,
844 : path_name,
845 : &item_props) == PDF_OK) ?
846 : PDF_TRUE :
847 : PDF_FALSE);
848 : }
849 :
850 :
851 : pdf_bool_t
852 : pdf_fsys_disk_item_readable_p (void *data,
853 : pdf_text_t path_name)
854 0 : {
855 0 : pdf_bool_t result = PDF_FALSE;
856 0 : if(path_name != NULL)
857 : {
858 0 : pdf_char_t* host_path = NULL;
859 0 : pdf_size_t host_path_len = 0;
860 :
861 0 : if(__pdf_fsys_disk_get_host_path (path_name,
862 : &host_path,
863 : &host_path_len) == PDF_OK)
864 : {
865 0 : __pdf_fsys_disk_is_readable_from_host_path(host_path, &result);
866 0 : pdf_dealloc(host_path);
867 : }
868 : }
869 0 : return result;
870 : }
871 :
872 :
873 :
874 :
875 : pdf_bool_t
876 : pdf_fsys_disk_item_writable_p (void *data,
877 : pdf_text_t path_name)
878 0 : {
879 0 : pdf_bool_t result = PDF_FALSE;
880 0 : if(path_name != NULL)
881 : {
882 0 : pdf_char_t* host_path = NULL;
883 0 : pdf_size_t host_path_len = 0;
884 :
885 0 : if(__pdf_fsys_disk_get_host_path (path_name,
886 : &host_path,
887 : &host_path_len) == PDF_OK)
888 : {
889 0 : __pdf_fsys_disk_is_writable_from_host_path(host_path, &result);
890 0 : pdf_dealloc(host_path);
891 : }
892 : }
893 0 : return result;
894 : }
895 :
896 : pdf_status_t
897 : pdf_fsys_disk_build_path (void *data,
898 : pdf_text_t * output,
899 : pdf_text_t first_element,
900 : pdf_list_t rest)
901 1 : {
902 : pdf_list_iterator_t itr;
903 : pdf_text_t next, text_sep;
904 : pdf_status_t st, st2;
905 :
906 2 : st = pdf_list_iterator (rest, &itr);
907 1 : if (st != PDF_OK)
908 : {
909 0 : return st;
910 : }
911 :
912 1 : *output = pdf_text_dup (first_element);
913 1 : if (*output == NULL)
914 : {
915 : pdf_list_iterator_free (&itr);
916 0 : return PDF_ENOMEM;
917 : }
918 :
919 : #if FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR
920 : st = pdf_text_new_from_unicode ((pdf_char_t*)"\\",1,PDF_TEXT_UTF8, &text_sep);
921 : #else
922 1 : st = pdf_text_new_from_unicode ((pdf_char_t*)"/",1,PDF_TEXT_UTF8, &text_sep);
923 : #endif /* FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR */
924 :
925 1 : if (st != PDF_OK)
926 : {
927 : pdf_list_iterator_free (&itr);
928 0 : pdf_text_destroy(*output);
929 0 : return st;
930 : }
931 :
932 : /* Concatenate separator and next text object */
933 2 : st = pdf_list_iterator_next (&itr, (const void **) &next, NULL);
934 4 : while (st == PDF_OK)
935 : {
936 2 : st2 = pdf_text_concat (*output, text_sep, PDF_TRUE);
937 2 : if (st2 != PDF_OK)
938 : {
939 : pdf_list_iterator_free (&itr);
940 0 : pdf_text_destroy(*output);
941 0 : pdf_text_destroy (text_sep);
942 0 : return st2;
943 : }
944 :
945 2 : st2 = pdf_text_concat (*output, next, PDF_TRUE);
946 2 : if (st2 != PDF_OK)
947 : {
948 : pdf_list_iterator_free (&itr);
949 0 : pdf_text_destroy(*output);
950 0 : pdf_text_destroy (text_sep);
951 0 : return st2;
952 : }
953 4 : st = pdf_list_iterator_next (&itr, (const void **) &next, NULL);
954 : }
955 :
956 : pdf_list_iterator_free (&itr);
957 1 : pdf_text_destroy (text_sep);
958 1 : return PDF_OK;
959 : }
960 :
961 :
962 : /*
963 : * File Interface Implementation
964 : */
965 :
966 : enum pdf_fsys_file_mode_e
967 : pdf_fsys_disk_file_get_mode (pdf_fsys_file_t file)
968 0 : {
969 0 : return (((file != NULL) && (file->data != NULL)) ? \
970 : (((pdf_fsys_disk_file_t)file->data)->file_mode) : \
971 : PDF_FSYS_OPEN_MODE_INVALID);
972 : }
973 :
974 : pdf_text_t
975 : pdf_fsys_disk_file_get_url (pdf_fsys_file_t file)
976 0 : {
977 0 : if((file != NULL) && (file->data != NULL))
978 : {
979 : #ifdef PDF_HOST_WIN32
980 : /* In W32, we just copy the path string */
981 : return pdf_text_dup((((pdf_fsys_disk_file_t)file->data)->unicode_path));
982 : #else
983 : /* In POSIX, we return file:/ plus the path string */
984 0 : pdf_text_t url = NULL;
985 : #define PDF_DISK_URL_PREFIX (pdf_char_t *)"file:/"
986 0 : if(pdf_text_new_from_unicode(PDF_DISK_URL_PREFIX,
987 : strlen((char *) PDF_DISK_URL_PREFIX),
988 : PDF_TEXT_UTF8,
989 : &url) == PDF_OK)
990 : {
991 0 : if(pdf_text_concat(url,
992 : (((pdf_fsys_disk_file_t)file->data)->unicode_path),
993 : PDF_TRUE) == PDF_OK)
994 : {
995 0 : return url;
996 : }
997 : }
998 : #undef PDF_DISK_URL_PREFIX
999 0 : if(url != NULL)
1000 : {
1001 0 : pdf_text_destroy(url);
1002 : }
1003 0 : return NULL;
1004 : #endif
1005 : }
1006 : else
1007 0 : return NULL;
1008 : }
1009 :
1010 : pdf_status_t
1011 : pdf_fsys_disk_file_set_mode (pdf_fsys_file_t file,
1012 : enum pdf_fsys_file_mode_e new_mode)
1013 0 : {
1014 0 : pdf_status_t ret_code = PDF_EBADDATA;
1015 0 : if(file != NULL)
1016 : {
1017 0 : if(file->data == NULL)
1018 : {
1019 0 : ret_code = PDF_ECLOSED;
1020 : }
1021 : else
1022 : {
1023 0 : pdf_fsys_disk_file_t file_data = (pdf_fsys_disk_file_t)file->data;
1024 : /* If modes are different, call reopen */
1025 0 : if(file_data->file_mode != new_mode)
1026 : {
1027 0 : ret_code = pdf_fsys_disk_file_reopen(file,new_mode);
1028 : }
1029 : else
1030 : {
1031 : /* Same mode, so don't do anything */
1032 0 : ret_code = PDF_OK;
1033 : }
1034 : }
1035 : }
1036 0 : return ret_code;
1037 : }
1038 :
1039 : pdf_bool_t
1040 : pdf_fsys_disk_file_same_p (pdf_fsys_file_t file,
1041 : pdf_text_t path)
1042 0 : {
1043 : pdf_status_t stat;
1044 : pdf_i32_t ret;
1045 : pdf_bool_t case_sensitive;
1046 0 : pdf_fsys_disk_file_t work_file = (pdf_fsys_disk_file_t)file->data;
1047 :
1048 :
1049 :
1050 : /* TODO: Mac OS X should have a method in CoreFoundation libs to
1051 : * check if a the HFS+ filesystem is case-sensitive or not */
1052 :
1053 :
1054 : /* Unix-like systems have case sensitive paths, Windows doesn't. */
1055 : #ifndef PDF_HOST_WIN32
1056 0 : case_sensitive = PDF_TRUE;
1057 : #else
1058 : case_sensitive = PDF_FALSE;
1059 : #endif
1060 :
1061 :
1062 : /* TODO : We should be able to get the whole ABSOLUTE path of the
1063 : * files, before comparing the routes */
1064 :
1065 :
1066 :
1067 : /* Compare text strings */
1068 0 : ret = pdf_text_cmp(work_file->unicode_path, path, case_sensitive, &stat);
1069 :
1070 0 : return (((ret == 0 ) && (stat == PDF_OK)) ? PDF_TRUE : PDF_FALSE);
1071 : }
1072 :
1073 :
1074 : pdf_status_t
1075 : pdf_fsys_disk_file_get_pos (pdf_fsys_file_t file,
1076 : pdf_size_t *pos)
1077 24 : {
1078 24 : if((file != NULL) && \
1079 : (pos != NULL))
1080 : {
1081 : long cpos;
1082 24 : cpos = ftell (((pdf_fsys_disk_file_t)file->data)->file_descriptor);
1083 24 : if (cpos<0)
1084 : {
1085 0 : return __pdf_fsys_disk_get_status_from_errno (errno);
1086 : }
1087 : else
1088 : {
1089 24 : *pos = cpos;
1090 24 : return PDF_OK;
1091 : }
1092 : }
1093 : else
1094 : {
1095 0 : return PDF_EBADDATA;
1096 : }
1097 : }
1098 :
1099 : pdf_status_t
1100 : pdf_fsys_disk_file_set_pos (pdf_fsys_file_t file,
1101 : pdf_size_t new_pos)
1102 48 : {
1103 48 : if(file != NULL)
1104 : {
1105 : int st;
1106 96 : st = fseek (((pdf_fsys_disk_file_t)file->data)->file_descriptor,
1107 : new_pos, SEEK_SET);
1108 48 : if (st < 0)
1109 : {
1110 0 : return __pdf_fsys_disk_get_status_from_errno (errno);
1111 : }
1112 : else
1113 : {
1114 48 : return PDF_OK;
1115 : }
1116 : }
1117 : else
1118 : {
1119 0 : return PDF_EBADDATA;
1120 : }
1121 : }
1122 :
1123 : pdf_bool_t
1124 : pdf_fsys_disk_file_can_set_size_p (pdf_fsys_file_t file,
1125 : pdf_size_t size)
1126 0 : {
1127 : /* FIXME: Please implement me XD */
1128 0 : return PDF_TRUE;
1129 : }
1130 :
1131 : pdf_size_t
1132 : pdf_fsys_disk_file_get_size (pdf_fsys_file_t file)
1133 3 : {
1134 : pdf_size_t size;
1135 3 : if(__pdf_fsys_disk_file_get_size_from_host_path(((pdf_fsys_disk_file_t)file->data)->host_path,
1136 : &size) == PDF_OK)
1137 : {
1138 3 : return size;
1139 : }
1140 : else
1141 : {
1142 : /* Should we change the API to return pdf_status_t ? */
1143 0 : return 0;
1144 : }
1145 : }
1146 :
1147 : pdf_status_t
1148 : pdf_fsys_disk_file_set_size (pdf_fsys_file_t file,
1149 : pdf_size_t size)
1150 0 : {
1151 : /* FIXME: Please implement me :D */
1152 0 : return PDF_OK;
1153 : }
1154 :
1155 :
1156 : pdf_status_t
1157 : pdf_fsys_disk_file_read (pdf_fsys_file_t file, pdf_char_t *buf,
1158 : pdf_size_t bytes, pdf_size_t *read_bytes)
1159 24 : {
1160 24 : pdf_status_t ret = PDF_EBADDATA;
1161 24 : if((file != NULL) && \
1162 : (buf != NULL))
1163 : {
1164 24 : pdf_fsys_disk_file_t file_data = NULL;
1165 24 : file_data = (pdf_fsys_disk_file_t)(file->data);
1166 :
1167 : /* Check if the file is open. */
1168 24 : if(file_data == NULL)
1169 : {
1170 : PDF_DEBUG_BASE("File is closed! Can't read data");
1171 : }
1172 : else
1173 : {
1174 24 : *read_bytes = fread(buf,
1175 : 1,
1176 : bytes,
1177 : file_data->file_descriptor);
1178 24 : if (feof(file_data->file_descriptor))
1179 : {
1180 22 : ret = PDF_EEOF;
1181 : }
1182 2 : else if (ferror(file_data->file_descriptor))
1183 : {
1184 0 : ret = PDF_ERROR;
1185 : }
1186 : else
1187 : {
1188 2 : ret = PDF_OK;
1189 : }
1190 : }
1191 : }
1192 : else
1193 : {
1194 : PDF_DEBUG_BASE("Invalid inputs to file_read! (file:%p, buf:%p, size:%u)",
1195 : file,buf,bytes);
1196 : }
1197 24 : return ret;
1198 : }
1199 :
1200 :
1201 : pdf_status_t
1202 : pdf_fsys_disk_file_write (pdf_fsys_file_t file, pdf_char_t *buf,
1203 : pdf_size_t bytes, pdf_size_t *written_bytes)
1204 9 : {
1205 9 : pdf_status_t ret = PDF_EBADDATA;
1206 9 : if((file != NULL) && \
1207 : (buf != NULL))
1208 : {
1209 9 : pdf_fsys_disk_file_t file_data = NULL;
1210 9 : file_data = (pdf_fsys_disk_file_t)(file->data);
1211 :
1212 : /* Check if the file is open. */
1213 9 : if(file_data == NULL)
1214 : {
1215 : PDF_DEBUG_BASE("File is closed! Can't write data");
1216 : }
1217 : else
1218 : {
1219 9 : *written_bytes = fwrite(buf,
1220 : 1,
1221 : bytes,
1222 : file_data->file_descriptor);
1223 9 : if (ferror(file_data->file_descriptor))
1224 : {
1225 0 : if (errno == ENOSPC)
1226 : {
1227 0 : ret = PDF_ENOMEM;
1228 : }
1229 : else
1230 : {
1231 0 : ret = PDF_ERROR;
1232 : }
1233 : }
1234 : else
1235 : {
1236 9 : ret = PDF_OK;
1237 : }
1238 : }
1239 : }
1240 : else
1241 : {
1242 : PDF_DEBUG_BASE("Invalid inputs to file_write! (file:%p, buf:%p, size:%u)",
1243 : file,buf,bytes);
1244 : }
1245 9 : return ret;
1246 :
1247 : }
1248 :
1249 :
1250 : pdf_status_t
1251 : pdf_fsys_disk_file_flush (pdf_fsys_file_t file)
1252 0 : {
1253 : pdf_fsys_disk_file_t file_data;
1254 : pdf_status_t ret_code;
1255 :
1256 0 : file_data = (pdf_fsys_disk_file_t) file->data;
1257 :
1258 0 : if (fflush (file_data->file_descriptor) != 0)
1259 : {
1260 : /* On Windows platforms (excluding Cygwin), fflush does not
1261 : set errno upon failure. */
1262 : #ifndef PDF_HOST_WIN32
1263 0 : ret_code = __pdf_fsys_disk_get_status_from_errno(errno);
1264 : #else
1265 : ret_code = PDF_ERROR;
1266 : #endif
1267 : }
1268 : else
1269 : {
1270 0 : ret_code = PDF_OK;
1271 : }
1272 :
1273 0 : return ret_code;
1274 : }
1275 :
1276 :
1277 : pdf_status_t
1278 : pdf_fsys_disk_file_request_ria (pdf_fsys_file_t file,
1279 : pdf_size_t offset,
1280 : pdf_size_t count)
1281 0 : {
1282 : /* This filesystem implementation do not provide Read-In-Advance
1283 : * capabilities, so this function is a no-op */
1284 :
1285 0 : return PDF_OK;
1286 : }
1287 :
1288 : pdf_bool_t
1289 : pdf_fsys_disk_file_has_ria (pdf_fsys_file_t file)
1290 0 : {
1291 : /* This filesystem implementation do not provide Read-In-Advance
1292 : * capabilities */
1293 :
1294 0 : return PDF_FALSE;
1295 : }
1296 :
1297 : pdf_status_t
1298 : pdf_fsys_disk_file_cancel_ria (pdf_fsys_file_t file)
1299 0 : {
1300 : /* This filesystem implementation do not provide Read-In-Advance
1301 : * capabilities, so this function is a no-op */
1302 :
1303 0 : return PDF_OK;
1304 : }
1305 :
1306 :
1307 : /* Host-dependent freopen() */
1308 : #ifdef PDF_HOST_WIN32
1309 : #define PDF_FREOPEN(f,m,s) _wfreopen((wchar_t *)f,(wchar_t *)m,s)
1310 : #else
1311 : #define PDF_FREOPEN(f,m,s) freopen_safer ((char *)f,(char *)m,s)
1312 : #endif
1313 :
1314 :
1315 : pdf_status_t
1316 : pdf_fsys_disk_file_reopen (pdf_fsys_file_t file,
1317 : enum pdf_fsys_file_mode_e mode)
1318 0 : {
1319 0 : pdf_status_t ret_code = PDF_EBADDATA;
1320 0 : if(file != NULL)
1321 : {
1322 0 : pdf_fsys_disk_file_t file_data = NULL;
1323 :
1324 0 : file_data = (pdf_fsys_disk_file_t)(file->data);
1325 :
1326 : /* Check if the file is open. If it's closed, error must be returned
1327 : * as reopen doesn't have the file path input */
1328 : /* Check if file is closed (no valid data in object */
1329 0 : if(file_data == NULL)
1330 : {
1331 : PDF_DEBUG_BASE("File is closed! Can't re-open");
1332 0 : ret_code = PDF_ECLOSED;
1333 : }
1334 0 : else if(file_data->file_descriptor == NULL)
1335 : {
1336 : PDF_DEBUG_BASE("Invalid FD! Can't re-open");
1337 0 : ret_code = PDF_ECLOSED;
1338 : }
1339 0 : else if(file_data->host_path == NULL)
1340 : {
1341 : PDF_DEBUG_BASE("Invalid file object. FD not NULL but empty path");
1342 0 : ret_code = PDF_ERROR;
1343 : }
1344 : else
1345 : {
1346 0 : const pdf_char_t* mode_str = NULL;
1347 0 : ret_code = PDF_ERROR;
1348 : /* Get the new mode string for freopen */
1349 0 : mode_str =__pdf_fsys_disk_get_mode_string(mode);
1350 : PDF_DEBUG_BASE("Re-opening file '%s' with mode '%s'...",
1351 : file_data->host_path,
1352 : mode_str);
1353 :
1354 0 : if(mode_str != NULL)
1355 : {
1356 : /* re-open the file */
1357 0 : file_data->file_descriptor = PDF_FREOPEN(file_data->host_path, \
1358 : mode_str, \
1359 : file_data->file_descriptor);
1360 :
1361 : /* reset mode */
1362 0 : file_data->file_mode = mode;
1363 :
1364 : /* If got a good FD, set output data */
1365 0 : ret_code = ((file_data->file_descriptor != NULL) ? \
1366 : PDF_OK : \
1367 : __pdf_fsys_disk_get_status_from_errno(errno));
1368 : }
1369 : }
1370 : }
1371 0 : return ret_code;
1372 : }
1373 :
1374 : /*
1375 : * Private functions
1376 : */
1377 :
1378 : static pdf_status_t
1379 : __pdf_fsys_disk_get_host_path (pdf_text_t path,
1380 : pdf_char_t **host_path,
1381 : pdf_size_t *host_path_size)
1382 27 : {
1383 : #ifdef PDF_HOST_WIN32
1384 : /* For W32, we will always use widechar functions, so Windows' wchar_t
1385 : * implementation should be used (UTF-16LE) */
1386 : pdf_char_t *data = NULL;
1387 : pdf_size_t size = 0;
1388 :
1389 : if(pdf_text_get_unicode(&data,
1390 : &size,
1391 : path,
1392 : PDF_TEXT_UTF16_LE,
1393 : PDF_TEXT_UNICODE_WITH_NUL_SUFFIX) == PDF_OK)
1394 : {
1395 : *host_path = data;
1396 : *host_path_size = size;
1397 : return PDF_OK;
1398 : }
1399 : else
1400 : return PDF_ERROR;
1401 : #else
1402 : /* Call the pdf_text module to get a host-encoded version of the
1403 : * given path */
1404 27 : pdf_char_t *padded = NULL;
1405 27 : pdf_size_t padded_size = 0;
1406 :
1407 27 : if(pdf_text_get_host(&padded,
1408 : &padded_size,
1409 : path,
1410 : pdf_text_get_host_encoding ()) == PDF_OK)
1411 : {
1412 27 : *host_path = pdf_realloc(padded, padded_size+2);
1413 27 : if(*host_path != NULL)
1414 : {
1415 27 : *host_path_size = padded_size + 1;
1416 27 : (*host_path)[(*host_path_size)-1] = '\0';
1417 27 : return PDF_OK;
1418 : }
1419 : else
1420 0 : return PDF_ENOMEM;
1421 : }
1422 : else
1423 0 : return PDF_ERROR;
1424 : #endif
1425 : }
1426 :
1427 :
1428 : static pdf_status_t
1429 : __pdf_fsys_disk_set_host_path (const pdf_char_t *host_path,
1430 : const pdf_size_t host_path_size,
1431 : pdf_text_t *p_path)
1432 : {
1433 0 : if((host_path == NULL) || \
1434 : (host_path_size == 0) || \
1435 : (p_path == NULL))
1436 : {
1437 0 : return PDF_EBADDATA;
1438 : }
1439 :
1440 : #ifdef PDF_HOST_WIN32
1441 : /* For W32, we will always use widechar functions, so Windows' wchar_t
1442 : * implementation should be used (UTF-16LE) */
1443 : return pdf_text_new_from_unicode(host_path,
1444 : host_path_size,
1445 : PDF_TEXT_UTF16_LE,
1446 : p_path);
1447 : #else
1448 : /* Call the pdf_text module to get a host-encoded version of the
1449 : * given path */
1450 0 : return pdf_text_new_from_host(host_path,
1451 : host_path_size,
1452 : pdf_text_get_host_encoding (),
1453 : p_path);
1454 : #endif
1455 : }
1456 :
1457 :
1458 :
1459 :
1460 :
1461 : #ifndef PDF_HOST_WIN32
1462 : /* Posix-based open mode */
1463 : static const pdf_char_t *__pdf_fsys_open_mode_strings[PDF_FSYS_OPEN_MODE_MAX] = {
1464 : /* PDF_FSYS_OPEN_MODE_INVALID */ (pdf_char_t *)"",
1465 : /* PDF_FSYS_OPEN_MODE_READ */ (pdf_char_t *)"r",
1466 : /* PDF_FSYS_OPEN_MODE_WRITE */ (pdf_char_t *)"w",
1467 : /* PDF_FSYS_OPEN_MODE_RW */ (pdf_char_t *)"r+",
1468 : };
1469 : #else
1470 : /* Windows portability note:
1471 : *
1472 : * Files are opened in "text mode" (with crlf translation) by
1473 : * default.
1474 : *
1475 : * Although the "b" fopen option is supported by POSIX some old Unix
1476 : * systems may not implement it, so we should use that option to
1477 : * open files only while running in Windows.
1478 : *
1479 : * Also, note that the open modes are in UTF-16 for w32
1480 : */
1481 : static const pdf_char_t *__pdf_fsys_open_mode_strings[PDF_FSYS_OPEN_MODE_MAX] = {
1482 : /* PDF_FSYS_OPEN_MODE_INVALID */ (pdf_char_t *)"\x00\x00",
1483 : /* PDF_FSYS_OPEN_MODE_READ */ (pdf_char_t *)"\x72\x00\x62\x00\x00\x00",
1484 : /* PDF_FSYS_OPEN_MODE_WRITE */ (pdf_char_t *)"\x77\x00\x62\x00\x00\x00",
1485 : /* PDF_FSYS_OPEN_MODE_RW */ (pdf_char_t *)"\x72\x00\x62\x00\x2B\x00\x00\x00",
1486 : };
1487 : #endif
1488 :
1489 :
1490 :
1491 :
1492 : static const pdf_char_t *
1493 : __pdf_fsys_disk_get_mode_string(const enum pdf_fsys_file_mode_e mode)
1494 : {
1495 24 : return (((mode >= PDF_FSYS_OPEN_MODE_FIRST) && \
1496 : (mode <= PDF_FSYS_OPEN_MODE_LAST)) ? \
1497 : __pdf_fsys_open_mode_strings[mode] : \
1498 : NULL);
1499 : }
1500 :
1501 :
1502 :
1503 : #ifdef PDF_HOST_WIN32
1504 :
1505 : #define PDF_MAX_W32_DEVICE_NAMES 32
1506 : static const pdf_char_t *device_names[PDF_MAX_W32_DEVICE_NAMES] = {
1507 : (pdf_char_t *)"NUL",
1508 : (pdf_char_t *)"CON",
1509 : (pdf_char_t *)"PRN",
1510 : (pdf_char_t *)"AUX",
1511 : (pdf_char_t *)"COM1",
1512 : (pdf_char_t *)"COM2",
1513 : (pdf_char_t *)"COM3",
1514 : (pdf_char_t *)"COM4",
1515 : (pdf_char_t *)"COM5",
1516 : (pdf_char_t *)"COM6",
1517 : (pdf_char_t *)"COM7",
1518 : (pdf_char_t *)"COM8",
1519 : (pdf_char_t *)"COM9",
1520 : (pdf_char_t *)"LPT1",
1521 : (pdf_char_t *)"LPT2",
1522 : (pdf_char_t *)"LPT3",
1523 : (pdf_char_t *)"LPT4",
1524 : (pdf_char_t *)"LPT5",
1525 : (pdf_char_t *)"LPT6",
1526 : (pdf_char_t *)"LPT7",
1527 : (pdf_char_t *)"LPT8",
1528 : (pdf_char_t *)"LPT9"
1529 : };
1530 :
1531 : static pdf_bool_t
1532 : __pdf_fsys_disk_win32_device_p (pdf_text_t path)
1533 : {
1534 : /* The following special "files", which access devices, exist in all
1535 : directories, case-insensitively, and with all possible endings
1536 : after a period or colon, excpets in pathnames that start with
1537 : \\?\: */
1538 :
1539 : int i;
1540 : pdf_bool_t device_p = PDF_FALSE;
1541 : pdf_text_t device_name;
1542 : pdf_status_t ret_code;
1543 :
1544 : device_p = PDF_FALSE;
1545 : i = 0;
1546 : while((! device_p) && \
1547 : (i < PDF_MAX_W32_DEVICE_NAMES))
1548 : {
1549 : pdf_text_new_from_unicode (device_names[i],
1550 : strlen ((char *)device_names[i]),
1551 : PDF_TEXT_UTF8,
1552 : &device_name);
1553 :
1554 : if (pdf_text_cmp (path, device_name, PDF_FALSE, &ret_code) == 0)
1555 : {
1556 : device_p = PDF_TRUE;
1557 : }
1558 : else
1559 : {
1560 : i++;
1561 : }
1562 : pdf_text_destroy (device_name);
1563 : }
1564 :
1565 : return device_p;
1566 : }
1567 :
1568 : #endif /* !PDF_HOST_WIN32 */
1569 :
1570 : static pdf_status_t
1571 : __pdf_fsys_disk_get_status_from_errno(int _errno)
1572 2 : {
1573 2 : switch (_errno)
1574 : {
1575 : case EINVAL:
1576 : case ESPIPE:
1577 : case EOVERFLOW:
1578 : case EBADF:
1579 : case EFAULT:
1580 : case EFBIG:
1581 : /* Bad data */
1582 0 : return PDF_EBADDATA;
1583 : case EACCES:
1584 : case EPERM:
1585 : case EROFS:
1586 : case ETXTBSY:
1587 : /* Not enough permissions */
1588 1 : return PDF_EBADPERMS;
1589 : case EISDIR:
1590 : case ENAMETOOLONG:
1591 : case ENOENT:
1592 : case ENOTDIR:
1593 : #ifdef ELOOP
1594 : case ELOOP:
1595 : #endif
1596 : /* Invalid path name */
1597 1 : return PDF_EBADNAME;
1598 : case ENOMEM:
1599 : /* No memory */
1600 0 : return PDF_ENOMEM;
1601 : case EEXIST:
1602 : /* File Exists */
1603 0 : return PDF_EEXIST;
1604 : case ENOTEMPTY:
1605 : /* Not empty */
1606 0 : return PDF_ENOTEMPTY;
1607 : case EAGAIN:
1608 : /* non-blocking descriptor and blocking writing
1609 : requested */
1610 0 : return PDF_EAGAIN;
1611 : case ENOSPC:
1612 : /* Not enough room in disk */
1613 0 : return PDF_ENOSPC;
1614 : default:
1615 : /* Other error */
1616 0 : return PDF_ERROR;
1617 : }
1618 : }
1619 :
1620 :
1621 : /* End of pdf-fsys-disk.c */
|