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/file-name.h"
28 #include "data/variable.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 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);
121 /* Free HANDLE and remove it from the global list. */
123 free_handle (struct file_handle *handle)
125 /* Remove handle from global list. */
126 if (handle->id != NULL)
127 hmap_delete (&named_handles, &handle->name_node);
132 free (handle->file_name);
133 free (handle->file_name_encoding);
134 free (handle->encoding);
138 /* Make HANDLE unnamed, so that it can no longer be referenced by
139 name. The caller must hold a reference to HANDLE, which is
140 not affected by this function. */
142 unname_handle (struct file_handle *handle)
144 assert (handle->id != NULL);
147 hmap_delete (&named_handles, &handle->name_node);
149 /* Drop the reference held by the named_handles table. */
153 /* Increments HANDLE's reference count and returns HANDLE. */
155 fh_ref (struct file_handle *handle)
157 assert (handle->ref_cnt > 0);
162 /* Decrements HANDLE's reference count.
163 If the reference count drops to 0, HANDLE is destroyed. */
165 fh_unref (struct file_handle *handle)
169 assert (handle->ref_cnt > 0);
170 if (--handle->ref_cnt == 0)
171 free_handle (handle);
175 /* Make HANDLE unnamed, so that it can no longer be referenced by
176 name. The caller must hold a reference to HANDLE, which is
177 not affected by this function.
179 This function ignores a null pointer as input. It has no
180 effect on the inline handle, which is always named INLINE.*/
182 fh_unname (struct file_handle *handle)
184 assert (handle->ref_cnt > 1);
185 if (handle != fh_inline_file () && handle->id != NULL)
186 unname_handle (handle);
189 /* Returns the handle with the given ID, or a null pointer if
192 fh_from_id (const char *id)
194 struct file_handle *handle;
196 HMAP_FOR_EACH_WITH_HASH (handle, struct file_handle, name_node,
197 utf8_hash_case_string (id, 0), &named_handles)
198 if (!utf8_strcasecmp (id, handle->id))
200 return fh_ref (handle);
206 /* Creates a new handle with identifier ID (which may be null)
207 and name HANDLE_NAME that refers to REFERENT. Links the new
208 handle into the global list. Returns the new handle.
210 The new handle is not fully initialized. The caller is
211 responsible for completing its initialization. */
212 static struct file_handle *
213 create_handle (const char *id, char *handle_name, enum fh_referent referent,
214 const char *encoding)
216 struct file_handle *handle = xzalloc (sizeof *handle);
219 handle->id = id != NULL ? xstrdup (id) : NULL;
220 handle->name = handle_name;
221 handle->referent = referent;
222 handle->encoding = xstrdup (encoding);
226 hmap_insert (&named_handles, &handle->name_node,
227 utf8_hash_case_string (handle->id, 0));
233 /* Returns the unique handle of referent type FH_REF_INLINE,
234 which refers to the "inline file" that represents character
235 data in the command file between BEGIN DATA and END DATA. */
237 fh_inline_file (void)
242 /* Creates and returns a new file handle with the given ID, which may be null.
243 If it is non-null, it must be a UTF-8 encoded string that is unique among
244 existing file identifiers. The new handle is associated with file FILE_NAME
245 and the given PROPERTIES. */
247 fh_create_file (const char *id, const char *file_name, const char *file_name_encoding,
248 const struct fh_properties *properties)
251 struct file_handle *handle;
253 handle_name = id != NULL ? xstrdup (id) : xasprintf ("`%s'", file_name);
254 handle = create_handle (id, handle_name, FH_REF_FILE, properties->encoding);
255 handle->file_name = xstrdup (file_name);
256 handle->file_name_encoding = file_name_encoding ? xstrdup (file_name_encoding) : NULL;
257 handle->mode = properties->mode;
258 handle->line_ends = properties->line_ends;
259 handle->record_width = properties->record_width;
260 handle->tab_width = properties->tab_width;
264 /* Creates a new file handle with the given ID, which must be
265 unique among existing file identifiers. The new handle is
266 associated with a dataset file (initially empty). */
268 fh_create_dataset (struct dataset *ds)
271 struct file_handle *handle;
273 name = dataset_name (ds);
275 name = _("active dataset");
277 handle = create_handle (NULL, xstrdup (name), FH_REF_DATASET, C_ENCODING);
282 /* Returns a set of default properties for a file handle. */
283 const struct fh_properties *
284 fh_default_properties (void)
286 #if defined _WIN32 || defined __WIN32__
287 #define DEFAULT_LINE_ENDS FH_END_CRLF
289 #define DEFAULT_LINE_ENDS FH_END_LF
292 static const struct fh_properties default_properties
293 = {FH_MODE_TEXT, DEFAULT_LINE_ENDS, 1024, 4, (char *) "Auto"};
294 return &default_properties;
297 /* Returns the identifier that may be used in syntax to name the
298 given HANDLE, which takes the form of a PSPP identifier. If
299 HANDLE has no identifier, returns a null pointer.
301 Return value is owned by the file handle.*/
303 fh_get_id (const struct file_handle *handle)
308 /* Returns a user-friendly string to identify the given HANDLE.
309 If HANDLE was created by referring to a file name, returns the
310 file name, enclosed in double quotes. Return value is owned
313 Useful for printing error messages about use of file handles. */
315 fh_get_name (const struct file_handle *handle)
320 /* Returns the type of object that HANDLE refers to. */
322 fh_get_referent (const struct file_handle *handle)
324 return handle->referent;
327 /* Returns the name of the file associated with HANDLE. */
329 fh_get_file_name (const struct file_handle *handle)
331 assert (handle->referent == FH_REF_FILE);
332 return handle->file_name;
336 /* Returns the character encoding of the name of the file associated with HANDLE. */
338 fh_get_file_name_encoding (const struct file_handle *handle)
340 assert (handle->referent == FH_REF_FILE);
341 return handle->file_name_encoding;
345 /* Returns the mode of HANDLE. */
347 fh_get_mode (const struct file_handle *handle)
349 assert (handle->referent == FH_REF_FILE);
353 /* Returns the line ends of HANDLE, which must be a handle associated with a
356 fh_get_line_ends (const struct file_handle *handle)
358 assert (handle->referent == FH_REF_FILE);
359 return handle->line_ends;
362 /* Returns the width of a logical record on HANDLE. */
364 fh_get_record_width (const struct file_handle *handle)
366 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
367 return handle->record_width;
370 /* Returns the number of characters per tab stop for HANDLE, or
371 zero if tabs are not to be expanded. Applicable only to
372 FH_MODE_TEXT files. */
374 fh_get_tab_width (const struct file_handle *handle)
376 assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
377 return handle->tab_width;
380 /* Returns the encoding of characters read from HANDLE. */
382 fh_get_encoding (const struct file_handle *handle)
384 return handle->encoding;
387 /* Returns the dataset handle associated with HANDLE.
388 Applicable to only FH_REF_DATASET files. */
390 fh_get_dataset (const struct file_handle *handle)
392 assert (handle->referent == FH_REF_DATASET);
396 /* Returns the current default handle. */
398 fh_get_default_handle (void)
400 return default_handle ? default_handle : fh_inline_file ();
403 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
405 fh_set_default_handle (struct file_handle *new_default_handle)
407 assert (new_default_handle == NULL
408 || (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));
409 if (default_handle != NULL && default_handle != inline_file)
410 fh_unref (default_handle);
411 default_handle = new_default_handle;
412 if (default_handle != NULL)
413 fh_ref (default_handle);
416 /* Information about a file handle's readers or writers. */
419 struct hmap_node node; /* hmap_node member. */
422 enum fh_referent referent; /* Type of underlying file. */
425 struct file_identity *file; /* FH_REF_FILE only. */
426 unsigned int unique_id; /* FH_REF_DATASET only. */
429 enum fh_access access; /* Type of file access. */
431 /* Number of openers. */
434 /* Applicable only when open_cnt > 0. */
435 bool exclusive; /* No other openers allowed? */
436 const char *type; /* Human-readable type of file. */
437 void *aux; /* Owner's auxiliary data. */
441 static void make_key (struct fh_lock *, const struct file_handle *,
443 static void free_key (struct fh_lock *);
444 static int compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b);
445 static unsigned int hash_fh_lock (const struct fh_lock *lock);
447 /* Tries to lock handle H for the given kind of ACCESS and TYPE
448 of file. Returns a pointer to a struct fh_lock if successful,
449 otherwise a null pointer.
451 H's referent type must be one of the bits in MASK. The caller
452 must verify this ahead of time; we simply assert it here.
454 TYPE is the sort of file, e.g. "system file". Only one type
455 of access is allowed on a given file at a time for reading,
456 and similarly for writing. If successful, a reference to TYPE
457 is retained, so it should probably be a string literal.
459 TYPE should be marked with N_() in the caller: that is, the
460 caller should not translate it with gettext, but fh_lock will
463 ACCESS specifies whether the lock is for reading or writing.
464 EXCLUSIVE is true to require exclusive access, false to allow
465 sharing with other accessors. Exclusive read access precludes
466 other readers, but not writers; exclusive write access
467 precludes other writers, but not readers. A sharable read or
468 write lock precludes reader or writers, respectively, of a
471 A lock may be associated with auxiliary data. See
472 fh_lock_get_aux and fh_lock_set_aux for more details. */
474 fh_lock (struct file_handle *h, enum fh_referent mask UNUSED,
475 const char *type, enum fh_access access, bool exclusive)
477 struct fh_lock *key = NULL;
479 struct fh_lock *lock = NULL;
480 bool found_lock = false;
482 assert ((fh_get_referent (h) & mask) != 0);
483 assert (access == FH_ACC_READ || access == FH_ACC_WRITE);
485 key = xmalloc (sizeof *key);
487 make_key (key, h, access);
490 key->exclusive = exclusive;
494 hash = hash_fh_lock (key);
496 HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
498 if ( 0 == compare_fh_locks (lock, key))
507 if (strcmp (lock->type, type))
509 if (access == FH_ACC_READ)
510 msg (SE, _("Can't read from %s as a %s because it is "
511 "already being read as a %s."),
512 fh_get_name (h), gettext (type), gettext (lock->type));
514 msg (SE, _("Can't write to %s as a %s because it is "
515 "already being written as a %s."),
516 fh_get_name (h), gettext (type), gettext (lock->type));
519 else if (exclusive || lock->exclusive)
521 msg (SE, _("Can't re-open %s as a %s."),
522 fh_get_name (h), gettext (type));
533 hmap_insert (&locks, &key->node, hash);
535 HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
537 if ( 0 == compare_fh_locks (lock, key))
549 /* Releases LOCK that was acquired with fh_lock.
550 Returns true if LOCK is still locked, because other clients
553 Returns false if LOCK has now been destroyed. In this case
554 the caller must ensure that any auxiliary data associated with
555 LOCK is destroyed, to avoid a memory leak. The caller must
556 obtain a pointer to the auxiliary data, e.g. via
557 fh_lock_get_aux *before* calling fh_unlock (because it yields
558 undefined behavior to call fh_lock_get_aux on a destroyed
561 fh_unlock (struct fh_lock *lock)
565 assert (lock->open_cnt > 0);
566 if (--lock->open_cnt == 0)
568 hmap_delete (&locks, &lock->node);
577 /* Returns auxiliary data for LOCK.
579 Auxiliary data is shared by every client that holds LOCK (for
580 an exclusive lock, this is a single client). To avoid leaks,
581 auxiliary data must be released before LOCK is destroyed. */
583 fh_lock_get_aux (const struct fh_lock *lock)
588 /* Sets the auxiliary data for LOCK to AUX. */
590 fh_lock_set_aux (struct fh_lock *lock, void *aux)
595 /* Returns true if HANDLE is locked for the given type of ACCESS,
598 fh_is_locked (const struct file_handle *handle, enum fh_access access)
601 const struct fh_lock *k = NULL;
602 bool is_locked = false;
605 make_key (&key, handle, access);
607 hash = hash_fh_lock (&key);
610 HMAP_FOR_EACH_WITH_HASH (k, struct fh_lock, node, hash, &locks)
612 if ( 0 == compare_fh_locks (k, &key))
624 /* Initializes the key fields in LOCK for looking up or inserting
625 handle H for the given kind of ACCESS. */
627 make_key (struct fh_lock *lock, const struct file_handle *h,
628 enum fh_access access)
630 lock->referent = fh_get_referent (h);
631 lock->access = access;
632 if (lock->referent == FH_REF_FILE)
633 lock->u.file = fh_get_identity (h);
634 else if (lock->referent == FH_REF_DATASET)
635 lock->u.unique_id = dataset_seqno (fh_get_dataset (h));
638 /* Frees the key fields in LOCK. */
640 free_key (struct fh_lock *lock)
642 if (lock->referent == FH_REF_FILE)
643 fh_free_identity (lock->u.file);
646 /* Compares the key fields in struct fh_lock objects A and B and
647 returns a strcmp()-type result. */
649 compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b)
651 if (a->referent != b->referent)
652 return a->referent < b->referent ? -1 : 1;
653 else if (a->access != b->access)
654 return a->access < b->access ? -1 : 1;
655 else if (a->referent == FH_REF_FILE)
656 return fh_compare_file_identities (a->u.file, b->u.file);
657 else if (a->referent == FH_REF_DATASET)
658 return (a->u.unique_id < b->u.unique_id ? -1
659 : a->u.unique_id > b->u.unique_id);
664 /* Returns a hash value for LOCK. */
666 hash_fh_lock (const struct fh_lock *lock)
669 if (lock->referent == FH_REF_FILE)
670 basis = fh_hash_identity (lock->u.file);
671 else if (lock->referent == FH_REF_DATASET)
672 basis = lock->u.unique_id;
675 return hash_int ((lock->referent << 3) | lock->access, basis);
683 /* A file's identity:
685 - For a file that exists, this is its device and inode.
687 - For a file that does not exist, but which has a directory
688 name that exists, this is the device and inode of the
689 directory, plus the file's base name.
691 - For a file that does not exist and has a nonexistent
692 directory, this is the file name.
694 Windows doesn't have inode numbers, so we just use the name
698 unsigned long long device; /* Device number. */
699 unsigned long long inode; /* Inode number. */
700 char *name; /* File name, where needed, otherwise NULL. */
703 /* Returns a pointer to a dynamically allocated structure whose
704 value can be used to tell whether two files are actually the
705 same file. The caller is responsible for freeing the structure with
706 fh_free_identity() when finished. */
707 struct file_identity *
708 fh_get_identity (const struct file_handle *fh)
710 struct file_identity *identity = xmalloc (sizeof *identity);
712 const char *file_name = fh_get_file_name (fh);
714 #if !(defined _WIN32 || defined __WIN32__)
716 if (lstat (file_name, &s) == 0)
718 identity->device = s.st_dev;
719 identity->inode = s.st_ino;
720 identity->name = NULL;
724 char *dir = dir_name (file_name);
725 if (last_component (file_name) != NULL && stat (dir, &s) == 0)
727 identity->device = s.st_dev;
728 identity->inode = s.st_ino;
729 identity->name = base_name (file_name);
733 identity->device = 0;
735 identity->name = xstrdup (file_name);
741 HANDLE h = CreateFile (file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
742 if (h != INVALID_HANDLE_VALUE)
744 BY_HANDLE_FILE_INFORMATION fi;
745 ok = GetFileInformationByHandle (h, &fi);
748 identity->device = fi.dwVolumeSerialNumber;
749 identity->inode = fi.nFileIndexHigh;
750 identity->inode <<= (sizeof fi.nFileIndexLow) * CHAR_BIT;
751 identity->inode |= fi.nFileIndexLow;
759 identity->device = 0;
763 size_t pathlen = 255;
768 cname = xrealloc (cname, bufsize);
769 pathlen = GetFullPathName (file_name, bufsize, cname, NULL);
771 while (pathlen > bufsize);
772 identity->name = xstrdup (cname);
774 str_lowercase (identity->name);
781 /* Frees IDENTITY obtained from fh_get_identity(). */
783 fh_free_identity (struct file_identity *identity)
785 if (identity != NULL)
787 free (identity->name);
792 /* Compares A and B, returning a strcmp()-type result. */
794 fh_compare_file_identities (const struct file_identity *a,
795 const struct file_identity *b)
797 if (a->device != b->device)
798 return a->device < b->device ? -1 : 1;
799 else if (a->inode != b->inode)
800 return a->inode < b->inode ? -1 : 1;
801 else if (a->name != NULL)
802 return b->name != NULL ? strcmp (a->name, b->name) : 1;
804 return b->name != NULL ? -1 : 0;
807 /* Returns a hash value for IDENTITY. */
809 fh_hash_identity (const struct file_identity *identity)
811 unsigned int hash = hash_int (identity->device, identity->inode);
812 if (identity->name != NULL)
813 hash = hash_string (identity->name, hash);