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/assertion.h"
29 #include "libpspp/cast.h"
30 #include "libpspp/compiler.h"
31 #include "libpspp/hash-functions.h"
32 #include "libpspp/hmap.h"
33 #include "libpspp/i18n.h"
34 #include "libpspp/message.h"
35 #include "libpspp/str.h"
39 #include "gl/dirname.h"
40 #include "gl/xalloc.h"
43 #define _(msgid) gettext (msgid)
45 #if defined _WIN32 || defined __WIN32__
46 #define WIN32_LEAN_AND_MEAN /* avoid including junk */
53 struct hmap_node name_node; /* Element in named_handles hmap. */
54 size_t ref_cnt; /* Number of references. */
55 char *id; /* Identifier token, NULL if none. */
56 char *name; /* User-friendly identifying name. */
57 enum fh_referent referent; /* What the file handle refers to. */
59 /* FH_REF_FILE only. */
60 char *file_name; /* File name as provided by user. */
61 char *file_name_encoding; /* The character encoding of file_name,
62 This is NOT the encoding of the file contents! */
63 enum fh_mode mode; /* File mode. */
64 enum fh_line_ends line_ends; /* Line ends for text files. */
66 /* FH_REF_FILE and FH_REF_INLINE only. */
67 size_t record_width; /* Length of fixed-format records. */
68 size_t tab_width; /* Tab width, 0=do not expand tabs. */
69 char *encoding; /* Charset for contents. */
71 /* FH_REF_DATASET only. */
72 struct dataset *ds; /* Dataset. */
75 /* All "struct file_handle"s with nonnull 'id' member. */
76 static struct hmap named_handles = HMAP_INITIALIZER (named_handles);
78 /* Default file handle for DATA LIST, REREAD, REPEATING DATA
80 static struct file_handle *default_handle;
82 /* The "file" that reads from BEGIN DATA...END DATA. */
83 static struct file_handle *inline_file;
85 static struct file_handle *create_handle (const char *id,
86 char *name, enum fh_referent,
87 const char *encoding);
88 static void free_handle (struct file_handle *);
89 static void unname_handle (struct file_handle *);
91 /* Hash table of all active locks. */
92 static struct hmap locks = HMAP_INITIALIZER (locks);
94 static struct file_identity *fh_get_identity (const struct file_handle *);
95 static void fh_free_identity (struct file_identity *);
96 static int fh_compare_file_identities (const struct file_identity *,
97 const struct file_identity *);
98 static unsigned int fh_hash_identity (const struct file_identity *);
100 /* File handle initialization routine. */
104 inline_file = create_handle ("INLINE", xstrdup ("INLINE"), FH_REF_INLINE,
106 inline_file->record_width = 80;
107 inline_file->tab_width = 8;
110 /* Removes all named file handles from the global list. */
114 struct file_handle *handle, *next;
116 HMAP_FOR_EACH_SAFE (handle, next,
117 struct file_handle, name_node, &named_handles)
118 unname_handle (handle);
120 free_handle (inline_file);
123 /* Free HANDLE and remove it from the global list. */
125 free_handle (struct file_handle *handle)
130 /* Remove handle from global list. */
131 if (handle->id != NULL)
132 hmap_delete (&named_handles, &handle->name_node);
137 free (handle->file_name);
138 free (handle->file_name_encoding);
139 free (handle->encoding);
143 /* Make HANDLE unnamed, so that it can no longer be referenced by
144 name. The caller must hold a reference to HANDLE, which is
145 not affected by this function. */
147 unname_handle (struct file_handle *handle)
149 assert (handle->id != NULL);
152 hmap_delete (&named_handles, &handle->name_node);
154 /* Drop the reference held by the named_handles table. */
158 /* Increments HANDLE's reference count and returns HANDLE. */
160 fh_ref (struct file_handle *handle)
162 if (handle == fh_inline_file ())
164 assert (handle->ref_cnt > 0);
169 /* Decrements HANDLE's reference count.
170 If the reference count drops to 0, HANDLE is destroyed. */
172 fh_unref (struct file_handle *handle)
176 if (handle == fh_inline_file ())
178 assert (handle->ref_cnt > 0);
179 if (--handle->ref_cnt == 0)
180 free_handle (handle);
184 /* Make HANDLE unnamed, so that it can no longer be referenced by
185 name. The caller must hold a reference to HANDLE, which is
186 not affected by this function.
188 This function ignores a null pointer as input. It has no
189 effect on the inline handle, which is always named INLINE.*/
191 fh_unname (struct file_handle *handle)
193 assert (handle->ref_cnt > 1);
194 if (fh_get_default_handle () == handle)
195 fh_set_default_handle (NULL);
196 if (handle != fh_inline_file () && handle->id != NULL)
197 unname_handle (handle);
200 /* Returns the handle with the given ID, or a null pointer if
203 fh_from_id (const char *id)
205 struct file_handle *handle;
207 HMAP_FOR_EACH_WITH_HASH (handle, struct file_handle, name_node,
208 utf8_hash_case_string (id, 0), &named_handles)
209 if (!utf8_strcasecmp (id, handle->id))
210 return fh_ref (handle);
215 /* Creates a new handle with identifier ID (which may be null)
216 and name HANDLE_NAME that refers to REFERENT. Links the new
217 handle into the global list. Returns the new handle.
219 The new handle is not fully initialized. The caller is
220 responsible for completing its initialization. */
221 static struct file_handle *
222 create_handle (const char *id, char *handle_name, enum fh_referent referent,
223 const char *encoding)
225 struct file_handle *handle = xmalloc (sizeof *handle);
226 *handle = (struct file_handle) {
228 .id = xstrdup_if_nonnull (id),
230 .referent = referent,
231 .encoding = xstrdup (encoding),
235 hmap_insert (&named_handles, &handle->name_node,
236 utf8_hash_case_string (handle->id, 0));
241 /* Returns the unique handle of referent type FH_REF_INLINE,
242 which refers to the "inline file" that represents character
243 data in the command file between BEGIN DATA and END DATA. */
245 fh_inline_file (void)
250 /* Creates and returns a new file handle with the given ID, which may be null.
251 If it is non-null, it must be a UTF-8 encoded string that is unique among
252 existing file identifiers. The new handle is associated with file FILE_NAME
253 and the given PROPERTIES. */
255 fh_create_file (const char *id, const char *file_name, const char *file_name_encoding,
256 const struct fh_properties *properties)
258 char *handle_name = id ? xstrdup (id) : xasprintf ("`%s'", file_name);
259 struct file_handle *handle = create_handle (id, handle_name, FH_REF_FILE,
260 properties->encoding);
261 handle->file_name = xstrdup (file_name);
262 handle->file_name_encoding = xstrdup_if_nonnull (file_name_encoding);
263 handle->mode = properties->mode;
264 handle->line_ends = properties->line_ends;
265 handle->record_width = properties->record_width;
266 handle->tab_width = properties->tab_width;
270 /* Creates a new file handle with the given ID, which must be
271 unique among existing file identifiers. The new handle is
272 associated with a dataset file (initially empty). */
274 fh_create_dataset (struct dataset *ds)
277 struct file_handle *handle;
279 name = dataset_name (ds);
281 name = _("active dataset");
283 handle = create_handle (NULL, xstrdup (name), FH_REF_DATASET, C_ENCODING);
288 /* Returns a set of default properties for a file handle. */
289 const struct fh_properties *
290 fh_default_properties (void)
292 #if defined _WIN32 || defined __WIN32__
293 #define DEFAULT_LINE_ENDS FH_END_CRLF
295 #define DEFAULT_LINE_ENDS FH_END_LF
298 static const struct fh_properties default_properties
299 = {FH_MODE_TEXT, DEFAULT_LINE_ENDS, 1024, 4, (char *) "Auto"};
300 return &default_properties;
303 /* Returns the identifier that may be used in syntax to name the
304 given HANDLE, which takes the form of a PSPP identifier. If
305 HANDLE has no identifier, returns a null pointer.
307 Return value is owned by the file handle.*/
309 fh_get_id (const struct file_handle *handle)
314 /* Returns a user-friendly string to identify the given HANDLE.
315 If HANDLE was created by referring to a file name, returns the
316 file name, enclosed in double quotes. Return value is owned
319 Useful for printing error messages about use of file handles. */
321 fh_get_name (const struct file_handle *handle)
326 /* Returns the type of object that HANDLE refers to. */
328 fh_get_referent (const struct file_handle *handle)
330 return handle->referent;
333 /* Returns the name of the file associated with HANDLE. */
335 fh_get_file_name (const struct file_handle *handle)
337 assert (handle->referent == FH_REF_FILE);
338 return handle->file_name;
342 /* Returns the character encoding of the name of the file associated with HANDLE. */
344 fh_get_file_name_encoding (const struct file_handle *handle)
346 assert (handle->referent == FH_REF_FILE);
347 return handle->file_name_encoding;
351 /* Returns the mode of HANDLE. */
353 fh_get_mode (const struct file_handle *handle)
355 assert (handle->referent == FH_REF_FILE);
359 /* Returns the line ends of HANDLE, which must be a handle associated with a
362 fh_get_line_ends (const struct file_handle *handle)
364 assert (handle->referent == FH_REF_FILE);
365 return handle->line_ends;
368 /* Returns the width of a logical record on HANDLE. */
370 fh_get_record_width (const struct file_handle *handle)
372 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
373 return handle->record_width;
376 /* Returns the number of characters per tab stop for HANDLE, or
377 zero if tabs are not to be expanded. Applicable only to
378 FH_MODE_TEXT files. */
380 fh_get_tab_width (const struct file_handle *handle)
382 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
383 return handle->tab_width;
386 /* Returns the encoding of characters read from HANDLE. */
388 fh_get_encoding (const struct file_handle *handle)
390 return handle->encoding;
393 /* Returns true if A and B refer to the same file or dataset, false
396 fh_equal (const struct file_handle *a, const struct file_handle *b)
398 if (a->referent != b->referent)
405 struct file_identity *a_id = fh_get_identity (a);
406 struct file_identity *b_id = fh_get_identity (b);
408 int cmp = fh_compare_file_identities (a_id, b_id);
410 fh_free_identity (a_id);
411 fh_free_identity (b_id);
420 return a->ds == b->ds;
427 /* Returns the dataset handle associated with HANDLE.
428 Applicable to only FH_REF_DATASET files. */
430 fh_get_dataset (const struct file_handle *handle)
432 assert (handle->referent == FH_REF_DATASET);
436 /* Returns the current default handle. */
438 fh_get_default_handle (void)
440 return default_handle ? default_handle : fh_inline_file ();
443 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
445 fh_set_default_handle (struct file_handle *new_default_handle)
447 assert (new_default_handle == NULL
448 || (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));
449 if (default_handle != NULL && default_handle != inline_file)
450 fh_unref (default_handle);
451 default_handle = new_default_handle;
452 if (default_handle != NULL)
453 default_handle = fh_ref (default_handle);
456 /* Information about a file handle's readers or writers. */
459 struct hmap_node node; /* hmap_node member. */
462 enum fh_referent referent; /* Type of underlying file. */
465 struct file_identity *file; /* FH_REF_FILE only. */
466 unsigned int unique_id; /* FH_REF_DATASET only. */
469 enum fh_access access; /* Type of file access. */
471 /* Number of openers. */
474 /* Applicable only when open_cnt > 0. */
475 bool exclusive; /* No other openers allowed? */
476 const char *type; /* Human-readable type of file. */
477 void *aux; /* Owner's auxiliary data. */
481 static void make_key (struct fh_lock *, const struct file_handle *,
483 static void free_key (struct fh_lock *);
484 static int compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b);
485 static unsigned int hash_fh_lock (const struct fh_lock *lock);
487 /* Tries to lock handle H for the given kind of ACCESS and TYPE
488 of file. Returns a pointer to a struct fh_lock if successful,
489 otherwise a null pointer.
491 H's referent type must be one of the bits in MASK. The caller
492 must verify this ahead of time; we simply assert it here.
494 TYPE is the sort of file, e.g. "system file". Only one type
495 of access is allowed on a given file at a time for reading,
496 and similarly for writing. If successful, a reference to TYPE
497 is retained, so it should probably be a string literal.
499 TYPE should be marked with N_() in the caller: that is, the
500 caller should not translate it with gettext, but fh_lock will
503 ACCESS specifies whether the lock is for reading or writing.
504 EXCLUSIVE is true to require exclusive access, false to allow
505 sharing with other accessors. Exclusive read access precludes
506 other readers, but not writers; exclusive write access
507 precludes other writers, but not readers. A sharable read or
508 write lock precludes reader or writers, respectively, of a
511 A lock may be associated with auxiliary data. See
512 fh_lock_get_aux and fh_lock_set_aux for more details. */
514 fh_lock (struct file_handle *h, enum fh_referent mask UNUSED,
515 const char *type, enum fh_access access, bool exclusive)
517 struct fh_lock *key = NULL;
519 struct fh_lock *lock = NULL;
520 bool found_lock = false;
522 assert ((fh_get_referent (h) & mask) != 0);
523 assert (access == FH_ACC_READ || access == FH_ACC_WRITE);
525 key = xmalloc (sizeof *key);
527 make_key (key, h, access);
530 key->exclusive = exclusive;
534 hash = hash_fh_lock (key);
536 HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
538 if (0 == compare_fh_locks (lock, key))
547 if (strcmp (lock->type, type))
549 if (access == FH_ACC_READ)
550 msg (SE, _("Can't read from %s as a %s because it is "
551 "already being read as a %s."),
552 fh_get_name (h), gettext (type), gettext (lock->type));
554 msg (SE, _("Can't write to %s as a %s because it is "
555 "already being written as a %s."),
556 fh_get_name (h), gettext (type), gettext (lock->type));
559 else if (exclusive || lock->exclusive)
561 msg (SE, _("Can't re-open %s as a %s."),
562 fh_get_name (h), gettext (type));
573 hmap_insert (&locks, &key->node, hash);
575 HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
577 if (0 == compare_fh_locks (lock, key))
589 /* Releases LOCK that was acquired with fh_lock.
590 Returns true if LOCK is still locked, because other clients
593 Returns false if LOCK has now been destroyed. In this case
594 the caller must ensure that any auxiliary data associated with
595 LOCK is destroyed, to avoid a memory leak. The caller must
596 obtain a pointer to the auxiliary data, e.g. via
597 fh_lock_get_aux *before* calling fh_unlock (because it yields
598 undefined behavior to call fh_lock_get_aux on a destroyed
601 fh_unlock (struct fh_lock *lock)
605 assert (lock->open_cnt > 0);
606 if (--lock->open_cnt == 0)
608 hmap_delete (&locks, &lock->node);
617 /* Returns auxiliary data for LOCK.
619 Auxiliary data is shared by every client that holds LOCK (for
620 an exclusive lock, this is a single client). To avoid leaks,
621 auxiliary data must be released before LOCK is destroyed. */
623 fh_lock_get_aux (const struct fh_lock *lock)
628 /* Sets the auxiliary data for LOCK to AUX. */
630 fh_lock_set_aux (struct fh_lock *lock, void *aux)
635 /* Returns true if HANDLE is locked for the given type of ACCESS,
638 fh_is_locked (const struct file_handle *handle, enum fh_access access)
641 const struct fh_lock *k = NULL;
642 bool is_locked = false;
645 make_key (&key, handle, access);
647 hash = hash_fh_lock (&key);
650 HMAP_FOR_EACH_WITH_HASH (k, struct fh_lock, node, hash, &locks)
652 if (0 == compare_fh_locks (k, &key))
664 /* Initializes the key fields in LOCK for looking up or inserting
665 handle H for the given kind of ACCESS. */
667 make_key (struct fh_lock *lock, const struct file_handle *h,
668 enum fh_access access)
670 lock->referent = fh_get_referent (h);
671 lock->access = access;
672 if (lock->referent == FH_REF_FILE)
673 lock->u.file = fh_get_identity (h);
674 else if (lock->referent == FH_REF_DATASET)
675 lock->u.unique_id = dataset_seqno (fh_get_dataset (h));
678 /* Frees the key fields in LOCK. */
680 free_key (struct fh_lock *lock)
682 if (lock->referent == FH_REF_FILE)
683 fh_free_identity (lock->u.file);
686 /* Compares the key fields in struct fh_lock objects A and B and
687 returns a strcmp()-type result. */
689 compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b)
691 if (a->referent != b->referent)
692 return a->referent < b->referent ? -1 : 1;
693 else if (a->access != b->access)
694 return a->access < b->access ? -1 : 1;
695 else if (a->referent == FH_REF_FILE)
696 return fh_compare_file_identities (a->u.file, b->u.file);
697 else if (a->referent == FH_REF_DATASET)
698 return (a->u.unique_id < b->u.unique_id ? -1
699 : a->u.unique_id > b->u.unique_id);
704 /* Returns a hash value for LOCK. */
706 hash_fh_lock (const struct fh_lock *lock)
709 if (lock->referent == FH_REF_FILE)
710 basis = fh_hash_identity (lock->u.file);
711 else if (lock->referent == FH_REF_DATASET)
712 basis = lock->u.unique_id;
715 return hash_int ((lock->referent << 3) | lock->access, basis);
723 /* A file's identity:
725 - For a file that exists, this is its device and inode.
727 - For a file that does not exist, but which has a directory
728 name that exists, this is the device and inode of the
729 directory, plus the file's base name.
731 - For a file that does not exist and has a nonexistent
732 directory, this is the file name.
734 Windows doesn't have inode numbers, so we just use the name
738 unsigned long long device; /* Device number. */
739 unsigned long long inode; /* Inode number. */
740 char *name; /* File name, where needed, otherwise NULL. */
743 /* Returns a pointer to a dynamically allocated structure whose
744 value can be used to tell whether two files are actually the
745 same file. The caller is responsible for freeing the structure with
746 fh_free_identity() when finished. */
747 static struct file_identity *
748 fh_get_identity (const struct file_handle *fh)
750 struct file_identity *identity = xmalloc (sizeof *identity);
752 const char *file_name = fh_get_file_name (fh);
754 #if !(defined _WIN32 || defined __WIN32__)
756 if (lstat (file_name, &s) == 0)
758 identity->device = s.st_dev;
759 identity->inode = s.st_ino;
760 identity->name = NULL;
764 char *dir = dir_name (file_name);
765 if (last_component (file_name) != NULL && stat (dir, &s) == 0)
767 identity->device = s.st_dev;
768 identity->inode = s.st_ino;
769 identity->name = base_name (file_name);
773 identity->device = 0;
775 identity->name = xstrdup (file_name);
781 HANDLE h = CreateFile (file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
782 if (h != INVALID_HANDLE_VALUE)
784 BY_HANDLE_FILE_INFORMATION fi;
785 ok = GetFileInformationByHandle (h, &fi);
788 identity->device = fi.dwVolumeSerialNumber;
789 identity->inode = fi.nFileIndexHigh;
790 identity->inode <<= (sizeof fi.nFileIndexLow) * CHAR_BIT;
791 identity->inode |= fi.nFileIndexLow;
799 identity->device = 0;
803 size_t pathlen = 255;
808 cname = xrealloc (cname, bufsize);
809 pathlen = GetFullPathName (file_name, bufsize, cname, NULL);
811 while (pathlen > bufsize);
812 identity->name = xstrdup (cname);
814 str_lowercase (identity->name);
821 /* Frees IDENTITY obtained from fh_get_identity(). */
823 fh_free_identity (struct file_identity *identity)
825 if (identity != NULL)
827 free (identity->name);
832 /* Compares A and B, returning a strcmp()-type result. */
834 fh_compare_file_identities (const struct file_identity *a,
835 const struct file_identity *b)
837 if (a->device != b->device)
838 return a->device < b->device ? -1 : 1;
839 else if (a->inode != b->inode)
840 return a->inode < b->inode ? -1 : 1;
841 else if (a->name != NULL)
842 return b->name != NULL ? strcmp (a->name, b->name) : 1;
844 return b->name != NULL ? -1 : 0;
847 /* Returns a hash value for IDENTITY. */
849 fh_hash_identity (const struct file_identity *identity)
851 unsigned int hash = hash_int (identity->device, identity->inode);
852 if (identity->name != NULL)
853 hash = hash_string (identity->name, hash);