1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "data/file-handle-def.h"
26 #include "data/dataset.h"
27 #include "data/variable.h"
28 #include "libpspp/cast.h"
29 #include "libpspp/compiler.h"
30 #include "libpspp/hash-functions.h"
31 #include "libpspp/hmap.h"
32 #include "libpspp/i18n.h"
33 #include "libpspp/message.h"
34 #include "libpspp/str.h"
38 #include "gl/dirname.h"
39 #include "gl/xalloc.h"
42 #define _(msgid) gettext (msgid)
44 #if defined _WIN32 || defined __WIN32__
45 #define WIN32_LEAN_AND_MEAN /* avoid including junk */
52 struct hmap_node name_node; /* Element in named_handles hmap. */
53 size_t ref_cnt; /* Number of references. */
54 char *id; /* Identifier token, NULL if none. */
55 char *name; /* User-friendly identifying name. */
56 enum fh_referent referent; /* What the file handle refers to. */
58 /* FH_REF_FILE only. */
59 char *file_name; /* File name as provided by user. */
60 char *file_name_encoding; /* The character encoding of file_name,
61 This is NOT the encoding of the file contents! */
62 enum fh_mode mode; /* File mode. */
63 enum fh_line_ends line_ends; /* Line ends for text files. */
65 /* FH_REF_FILE and FH_REF_INLINE only. */
66 size_t record_width; /* Length of fixed-format records. */
67 size_t tab_width; /* Tab width, 0=do not expand tabs. */
68 char *encoding; /* Charset for contents. */
70 /* FH_REF_DATASET only. */
71 struct dataset *ds; /* Dataset. */
74 /* All "struct file_handle"s with nonnull 'id' member. */
75 static struct hmap named_handles = HMAP_INITIALIZER (named_handles);
77 /* Default file handle for DATA LIST, REREAD, REPEATING DATA
79 static struct file_handle *default_handle;
81 /* The "file" that reads from BEGIN DATA...END DATA. */
82 static struct file_handle *inline_file;
84 static struct file_handle *create_handle (const char *id,
85 char *name, enum fh_referent,
86 const char *encoding);
87 static void free_handle (struct file_handle *);
88 static void unname_handle (struct file_handle *);
90 /* Hash table of all active locks. */
91 static struct hmap locks = HMAP_INITIALIZER (locks);
93 static struct file_identity *fh_get_identity (const struct file_handle *);
94 static void fh_free_identity (struct file_identity *);
95 static int fh_compare_file_identities (const struct file_identity *,
96 const struct file_identity *);
97 static unsigned int fh_hash_identity (const struct file_identity *);
99 /* File handle initialization routine. */
103 inline_file = create_handle ("INLINE", xstrdup ("INLINE"), FH_REF_INLINE,
105 inline_file->record_width = 80;
106 inline_file->tab_width = 8;
109 /* Removes all named file handles from the global list. */
113 struct file_handle *handle, *next;
115 HMAP_FOR_EACH_SAFE (handle, next,
116 struct file_handle, name_node, &named_handles)
117 unname_handle (handle);
120 /* Free HANDLE and remove it from the global list. */
122 free_handle (struct file_handle *handle)
124 /* Remove handle from global list. */
125 if (handle->id != NULL)
126 hmap_delete (&named_handles, &handle->name_node);
131 free (handle->file_name);
132 free (handle->file_name_encoding);
133 free (handle->encoding);
137 /* Make HANDLE unnamed, so that it can no longer be referenced by
138 name. The caller must hold a reference to HANDLE, which is
139 not affected by this function. */
141 unname_handle (struct file_handle *handle)
143 assert (handle->id != NULL);
146 hmap_delete (&named_handles, &handle->name_node);
148 /* Drop the reference held by the named_handles table. */
152 /* Increments HANDLE's reference count and returns HANDLE. */
154 fh_ref (struct file_handle *handle)
156 assert (handle->ref_cnt > 0);
161 /* Decrements HANDLE's reference count.
162 If the reference count drops to 0, HANDLE is destroyed. */
164 fh_unref (struct file_handle *handle)
168 assert (handle->ref_cnt > 0);
169 if (--handle->ref_cnt == 0)
170 free_handle (handle);
174 /* Make HANDLE unnamed, so that it can no longer be referenced by
175 name. The caller must hold a reference to HANDLE, which is
176 not affected by this function.
178 This function ignores a null pointer as input. It has no
179 effect on the inline handle, which is always named INLINE.*/
181 fh_unname (struct file_handle *handle)
183 assert (handle->ref_cnt > 1);
184 if (handle != fh_inline_file () && handle->id != NULL)
185 unname_handle (handle);
188 /* Returns the handle with the given ID, or a null pointer if
191 fh_from_id (const char *id)
193 struct file_handle *handle;
195 HMAP_FOR_EACH_WITH_HASH (handle, struct file_handle, name_node,
196 utf8_hash_case_string (id, 0), &named_handles)
197 if (!utf8_strcasecmp (id, handle->id))
199 return fh_ref (handle);
205 /* Creates a new handle with identifier ID (which may be null)
206 and name HANDLE_NAME that refers to REFERENT. Links the new
207 handle into the global list. Returns the new handle.
209 The new handle is not fully initialized. The caller is
210 responsible for completing its initialization. */
211 static struct file_handle *
212 create_handle (const char *id, char *handle_name, enum fh_referent referent,
213 const char *encoding)
215 struct file_handle *handle = xzalloc (sizeof *handle);
218 handle->id = id != NULL ? xstrdup (id) : NULL;
219 handle->name = handle_name;
220 handle->referent = referent;
221 handle->encoding = xstrdup (encoding);
225 hmap_insert (&named_handles, &handle->name_node,
226 utf8_hash_case_string (handle->id, 0));
232 /* Returns the unique handle of referent type FH_REF_INLINE,
233 which refers to the "inline file" that represents character
234 data in the command file between BEGIN DATA and END DATA. */
236 fh_inline_file (void)
241 /* Creates and returns a new file handle with the given ID, which may be null.
242 If it is non-null, it must be a UTF-8 encoded string that is unique among
243 existing file identifiers. The new handle is associated with file FILE_NAME
244 and the given PROPERTIES. */
246 fh_create_file (const char *id, const char *file_name, const char *file_name_encoding,
247 const struct fh_properties *properties)
250 struct file_handle *handle;
252 handle_name = id != NULL ? xstrdup (id) : xasprintf ("`%s'", file_name);
253 handle = create_handle (id, handle_name, FH_REF_FILE, properties->encoding);
254 handle->file_name = xstrdup (file_name);
255 handle->file_name_encoding = file_name_encoding ? xstrdup (file_name_encoding) : NULL;
256 handle->mode = properties->mode;
257 handle->line_ends = properties->line_ends;
258 handle->record_width = properties->record_width;
259 handle->tab_width = properties->tab_width;
263 /* Creates a new file handle with the given ID, which must be
264 unique among existing file identifiers. The new handle is
265 associated with a dataset file (initially empty). */
267 fh_create_dataset (struct dataset *ds)
270 struct file_handle *handle;
272 name = dataset_name (ds);
274 name = _("active dataset");
276 handle = create_handle (NULL, xstrdup (name), FH_REF_DATASET, C_ENCODING);
281 /* Returns a set of default properties for a file handle. */
282 const struct fh_properties *
283 fh_default_properties (void)
285 #if defined _WIN32 || defined __WIN32__
286 #define DEFAULT_LINE_ENDS FH_END_CRLF
288 #define DEFAULT_LINE_ENDS FH_END_LF
291 static const struct fh_properties default_properties
292 = {FH_MODE_TEXT, DEFAULT_LINE_ENDS, 1024, 4, (char *) "Auto"};
293 return &default_properties;
296 /* Returns the identifier that may be used in syntax to name the
297 given HANDLE, which takes the form of a PSPP identifier. If
298 HANDLE has no identifier, returns a null pointer.
300 Return value is owned by the file handle.*/
302 fh_get_id (const struct file_handle *handle)
307 /* Returns a user-friendly string to identify the given HANDLE.
308 If HANDLE was created by referring to a file name, returns the
309 file name, enclosed in double quotes. Return value is owned
312 Useful for printing error messages about use of file handles. */
314 fh_get_name (const struct file_handle *handle)
319 /* Returns the type of object that HANDLE refers to. */
321 fh_get_referent (const struct file_handle *handle)
323 return handle->referent;
326 /* Returns the name of the file associated with HANDLE. */
328 fh_get_file_name (const struct file_handle *handle)
330 assert (handle->referent == FH_REF_FILE);
331 return handle->file_name;
335 /* Returns the character encoding of the name of the file associated with HANDLE. */
337 fh_get_file_name_encoding (const struct file_handle *handle)
339 assert (handle->referent == FH_REF_FILE);
340 return handle->file_name_encoding;
344 /* Returns the mode of HANDLE. */
346 fh_get_mode (const struct file_handle *handle)
348 assert (handle->referent == FH_REF_FILE);
352 /* Returns the line ends of HANDLE, which must be a handle associated with a
355 fh_get_line_ends (const struct file_handle *handle)
357 assert (handle->referent == FH_REF_FILE);
358 return handle->line_ends;
361 /* Returns the width of a logical record on HANDLE. */
363 fh_get_record_width (const struct file_handle *handle)
365 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
366 return handle->record_width;
369 /* Returns the number of characters per tab stop for HANDLE, or
370 zero if tabs are not to be expanded. Applicable only to
371 FH_MODE_TEXT files. */
373 fh_get_tab_width (const struct file_handle *handle)
375 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
376 return handle->tab_width;
379 /* Returns the encoding of characters read from HANDLE. */
381 fh_get_encoding (const struct file_handle *handle)
383 return handle->encoding;
386 /* Returns the dataset handle associated with HANDLE.
387 Applicable to only FH_REF_DATASET files. */
389 fh_get_dataset (const struct file_handle *handle)
391 assert (handle->referent == FH_REF_DATASET);
395 /* Returns the current default handle. */
397 fh_get_default_handle (void)
399 return default_handle ? default_handle : fh_inline_file ();
402 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
404 fh_set_default_handle (struct file_handle *new_default_handle)
406 assert (new_default_handle == NULL
407 || (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));
408 if (default_handle != NULL && default_handle != inline_file)
409 fh_unref (default_handle);
410 default_handle = new_default_handle;
411 if (default_handle != NULL)
412 fh_ref (default_handle);
415 /* Information about a file handle's readers or writers. */
418 struct hmap_node node; /* hmap_node member. */
421 enum fh_referent referent; /* Type of underlying file. */
424 struct file_identity *file; /* FH_REF_FILE only. */
425 unsigned int unique_id; /* FH_REF_DATASET only. */
428 enum fh_access access; /* Type of file access. */
430 /* Number of openers. */
433 /* Applicable only when open_cnt > 0. */
434 bool exclusive; /* No other openers allowed? */
435 const char *type; /* Human-readable type of file. */
436 void *aux; /* Owner's auxiliary data. */
440 static void make_key (struct fh_lock *, const struct file_handle *,
442 static void free_key (struct fh_lock *);
443 static int compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b);
444 static unsigned int hash_fh_lock (const struct fh_lock *lock);
446 /* Tries to lock handle H for the given kind of ACCESS and TYPE
447 of file. Returns a pointer to a struct fh_lock if successful,
448 otherwise a null pointer.
450 H's referent type must be one of the bits in MASK. The caller
451 must verify this ahead of time; we simply assert it here.
453 TYPE is the sort of file, e.g. "system file". Only one type
454 of access is allowed on a given file at a time for reading,
455 and similarly for writing. If successful, a reference to TYPE
456 is retained, so it should probably be a string literal.
458 TYPE should be marked with N_() in the caller: that is, the
459 caller should not translate it with gettext, but fh_lock will
462 ACCESS specifies whether the lock is for reading or writing.
463 EXCLUSIVE is true to require exclusive access, false to allow
464 sharing with other accessors. Exclusive read access precludes
465 other readers, but not writers; exclusive write access
466 precludes other writers, but not readers. A sharable read or
467 write lock precludes reader or writers, respectively, of a
470 A lock may be associated with auxiliary data. See
471 fh_lock_get_aux and fh_lock_set_aux for more details. */
473 fh_lock (struct file_handle *h, enum fh_referent mask UNUSED,
474 const char *type, enum fh_access access, bool exclusive)
476 struct fh_lock *key = NULL;
478 struct fh_lock *lock = NULL;
479 bool found_lock = false;
481 assert ((fh_get_referent (h) & mask) != 0);
482 assert (access == FH_ACC_READ || access == FH_ACC_WRITE);
484 key = xmalloc (sizeof *key);
486 make_key (key, h, access);
489 key->exclusive = exclusive;
493 hash = hash_fh_lock (key);
495 HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
497 if ( 0 == compare_fh_locks (lock, key))
506 if (strcmp (lock->type, type))
508 if (access == FH_ACC_READ)
509 msg (SE, _("Can't read from %s as a %s because it is "
510 "already being read as a %s."),
511 fh_get_name (h), gettext (type), gettext (lock->type));
513 msg (SE, _("Can't write to %s as a %s because it is "
514 "already being written as a %s."),
515 fh_get_name (h), gettext (type), gettext (lock->type));
518 else if (exclusive || lock->exclusive)
520 msg (SE, _("Can't re-open %s as a %s."),
521 fh_get_name (h), gettext (type));
532 hmap_insert (&locks, &key->node, hash);
534 HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
536 if ( 0 == compare_fh_locks (lock, key))
548 /* Releases LOCK that was acquired with fh_lock.
549 Returns true if LOCK is still locked, because other clients
552 Returns false if LOCK has now been destroyed. In this case
553 the caller must ensure that any auxiliary data associated with
554 LOCK is destroyed, to avoid a memory leak. The caller must
555 obtain a pointer to the auxiliary data, e.g. via
556 fh_lock_get_aux *before* calling fh_unlock (because it yields
557 undefined behavior to call fh_lock_get_aux on a destroyed
560 fh_unlock (struct fh_lock *lock)
564 assert (lock->open_cnt > 0);
565 if (--lock->open_cnt == 0)
567 hmap_delete (&locks, &lock->node);
576 /* Returns auxiliary data for LOCK.
578 Auxiliary data is shared by every client that holds LOCK (for
579 an exclusive lock, this is a single client). To avoid leaks,
580 auxiliary data must be released before LOCK is destroyed. */
582 fh_lock_get_aux (const struct fh_lock *lock)
587 /* Sets the auxiliary data for LOCK to AUX. */
589 fh_lock_set_aux (struct fh_lock *lock, void *aux)
594 /* Returns true if HANDLE is locked for the given type of ACCESS,
597 fh_is_locked (const struct file_handle *handle, enum fh_access access)
600 const struct fh_lock *k = NULL;
601 bool is_locked = false;
604 make_key (&key, handle, access);
606 hash = hash_fh_lock (&key);
609 HMAP_FOR_EACH_WITH_HASH (k, struct fh_lock, node, hash, &locks)
611 if ( 0 == compare_fh_locks (k, &key))
623 /* Initializes the key fields in LOCK for looking up or inserting
624 handle H for the given kind of ACCESS. */
626 make_key (struct fh_lock *lock, const struct file_handle *h,
627 enum fh_access access)
629 lock->referent = fh_get_referent (h);
630 lock->access = access;
631 if (lock->referent == FH_REF_FILE)
632 lock->u.file = fh_get_identity (h);
633 else if (lock->referent == FH_REF_DATASET)
634 lock->u.unique_id = dataset_seqno (fh_get_dataset (h));
637 /* Frees the key fields in LOCK. */
639 free_key (struct fh_lock *lock)
641 if (lock->referent == FH_REF_FILE)
642 fh_free_identity (lock->u.file);
645 /* Compares the key fields in struct fh_lock objects A and B and
646 returns a strcmp()-type result. */
648 compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b)
650 if (a->referent != b->referent)
651 return a->referent < b->referent ? -1 : 1;
652 else if (a->access != b->access)
653 return a->access < b->access ? -1 : 1;
654 else if (a->referent == FH_REF_FILE)
655 return fh_compare_file_identities (a->u.file, b->u.file);
656 else if (a->referent == FH_REF_DATASET)
657 return (a->u.unique_id < b->u.unique_id ? -1
658 : a->u.unique_id > b->u.unique_id);
663 /* Returns a hash value for LOCK. */
665 hash_fh_lock (const struct fh_lock *lock)
668 if (lock->referent == FH_REF_FILE)
669 basis = fh_hash_identity (lock->u.file);
670 else if (lock->referent == FH_REF_DATASET)
671 basis = lock->u.unique_id;
674 return hash_int ((lock->referent << 3) | lock->access, basis);
682 /* A file's identity:
684 - For a file that exists, this is its device and inode.
686 - For a file that does not exist, but which has a directory
687 name that exists, this is the device and inode of the
688 directory, plus the file's base name.
690 - For a file that does not exist and has a nonexistent
691 directory, this is the file name.
693 Windows doesn't have inode numbers, so we just use the name
697 unsigned long long device; /* Device number. */
698 unsigned long long inode; /* Inode number. */
699 char *name; /* File name, where needed, otherwise NULL. */
702 /* Returns a pointer to a dynamically allocated structure whose
703 value can be used to tell whether two files are actually the
704 same file. The caller is responsible for freeing the structure with
705 fh_free_identity() when finished. */
706 static struct file_identity *
707 fh_get_identity (const struct file_handle *fh)
709 struct file_identity *identity = xmalloc (sizeof *identity);
711 const char *file_name = fh_get_file_name (fh);
713 #if !(defined _WIN32 || defined __WIN32__)
715 if (lstat (file_name, &s) == 0)
717 identity->device = s.st_dev;
718 identity->inode = s.st_ino;
719 identity->name = NULL;
723 char *dir = dir_name (file_name);
724 if (last_component (file_name) != NULL && stat (dir, &s) == 0)
726 identity->device = s.st_dev;
727 identity->inode = s.st_ino;
728 identity->name = base_name (file_name);
732 identity->device = 0;
734 identity->name = xstrdup (file_name);
740 HANDLE h = CreateFile (file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
741 if (h != INVALID_HANDLE_VALUE)
743 BY_HANDLE_FILE_INFORMATION fi;
744 ok = GetFileInformationByHandle (h, &fi);
747 identity->device = fi.dwVolumeSerialNumber;
748 identity->inode = fi.nFileIndexHigh;
749 identity->inode <<= (sizeof fi.nFileIndexLow) * CHAR_BIT;
750 identity->inode |= fi.nFileIndexLow;
758 identity->device = 0;
762 size_t pathlen = 255;
767 cname = xrealloc (cname, bufsize);
768 pathlen = GetFullPathName (file_name, bufsize, cname, NULL);
770 while (pathlen > bufsize);
771 identity->name = xstrdup (cname);
773 str_lowercase (identity->name);
780 /* Frees IDENTITY obtained from fh_get_identity(). */
782 fh_free_identity (struct file_identity *identity)
784 if (identity != NULL)
786 free (identity->name);
791 /* Compares A and B, returning a strcmp()-type result. */
793 fh_compare_file_identities (const struct file_identity *a,
794 const struct file_identity *b)
796 if (a->device != b->device)
797 return a->device < b->device ? -1 : 1;
798 else if (a->inode != b->inode)
799 return a->inode < b->inode ? -1 : 1;
800 else if (a->name != NULL)
801 return b->name != NULL ? strcmp (a->name, b->name) : 1;
803 return b->name != NULL ? -1 : 0;
806 /* Returns a hash value for IDENTITY. */
808 fh_hash_identity (const struct file_identity *identity)
810 unsigned int hash = hash_int (identity->device, identity->inode);
811 if (identity->name != NULL)
812 hash = hash_string (identity->name, hash);