work on lexer
[pspp] / src / data / file-handle-def.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include "data/file-handle-def.h"
20
21 #include <assert.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25
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"
36
37 #include <sys/stat.h>
38
39 #include "gl/dirname.h"
40 #include "gl/xalloc.h"
41
42 #include "gettext.h"
43 #define _(msgid) gettext (msgid)
44
45 #if defined _WIN32 || defined __WIN32__
46 #define WIN32_LEAN_AND_MEAN  /* avoid including junk */
47 #include <windows.h>
48 #endif
49
50 /* File handle. */
51 struct file_handle
52   {
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. */
58
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. */
65
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. */
70
71     /* FH_REF_DATASET only. */
72     struct dataset *ds;         /* Dataset. */
73   };
74
75 /* All "struct file_handle"s with nonnull 'id' member. */
76 static struct hmap named_handles = HMAP_INITIALIZER (named_handles);
77
78 /* Default file handle for DATA LIST, REREAD, REPEATING DATA
79    commands. */
80 static struct file_handle *default_handle;
81
82 /* The "file" that reads from BEGIN DATA...END DATA. */
83 static struct file_handle *inline_file;
84
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 *);
90
91 /* Hash table of all active locks. */
92 static struct hmap locks = HMAP_INITIALIZER (locks);
93
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 *);
99
100 /* File handle initialization routine. */
101 void
102 fh_init (void)
103 {
104   inline_file = create_handle ("INLINE", xstrdup ("INLINE"), FH_REF_INLINE,
105                                "Auto");
106   inline_file->record_width = 80;
107   inline_file->tab_width = 8;
108 }
109
110 /* Removes all named file handles from the global list. */
111 void
112 fh_done (void)
113 {
114   struct file_handle *handle, *next;
115
116   HMAP_FOR_EACH_SAFE (handle, next,
117                       struct file_handle, name_node, &named_handles)
118     unname_handle (handle);
119
120   free_handle (inline_file);
121 }
122
123 /* Free HANDLE and remove it from the global list. */
124 static void
125 free_handle (struct file_handle *handle)
126 {
127   if (handle == NULL)
128     return;
129
130   /* Remove handle from global list. */
131   if (handle->id != NULL)
132     hmap_delete (&named_handles, &handle->name_node);
133
134   /* Free data. */
135   free (handle->id);
136   free (handle->name);
137   free (handle->file_name);
138   free (handle->file_name_encoding);
139   free (handle->encoding);
140   free (handle);
141 }
142
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. */
146 static void
147 unname_handle (struct file_handle *handle)
148 {
149   assert (handle->id != NULL);
150   free (handle->id);
151   handle->id = NULL;
152   hmap_delete (&named_handles, &handle->name_node);
153
154   /* Drop the reference held by the named_handles table. */
155   fh_unref (handle);
156 }
157
158 /* Increments HANDLE's reference count and returns HANDLE. */
159 struct file_handle *
160 fh_ref (struct file_handle *handle)
161 {
162   if (handle == fh_inline_file ())
163     return handle;
164   assert (handle->ref_cnt > 0);
165   handle->ref_cnt++;
166   return handle;
167 }
168
169 /* Decrements HANDLE's reference count.
170    If the reference count drops to 0, HANDLE is destroyed. */
171 void
172 fh_unref (struct file_handle *handle)
173 {
174   if (handle != NULL)
175     {
176       if (handle == fh_inline_file ())
177         return;
178       assert (handle->ref_cnt > 0);
179       if (--handle->ref_cnt == 0)
180         free_handle (handle);
181     }
182 }
183
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.
187
188    This function ignores a null pointer as input.  It has no
189    effect on the inline handle, which is always named INLINE.*/
190 void
191 fh_unname (struct file_handle *handle)
192 {
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);
198 }
199
200 /* Returns the handle with the given ID, or a null pointer if
201    there is none. */
202 struct file_handle *
203 fh_from_id (const char *id)
204 {
205   struct file_handle *handle;
206
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);
211
212   return NULL;
213 }
214
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.
218
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)
224 {
225   struct file_handle *handle = xmalloc (sizeof *handle);
226   *handle = (struct file_handle) {
227     .ref_cnt = 1,
228     .id = xstrdup_if_nonnull (id),
229     .name = handle_name,
230     .referent = referent,
231     .encoding = xstrdup (encoding),
232   };
233
234   if (id)
235     hmap_insert (&named_handles, &handle->name_node,
236                  utf8_hash_case_string (handle->id, 0));
237
238   return handle;
239 }
240
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. */
244 struct file_handle *
245 fh_inline_file (void)
246 {
247   return inline_file;
248 }
249
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. */
254 struct file_handle *
255 fh_create_file (const char *id, const char *file_name, const char *file_name_encoding,
256                 const struct fh_properties *properties)
257 {
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;
267   return handle;
268 }
269
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). */
273 struct file_handle *
274 fh_create_dataset (struct dataset *ds)
275 {
276   const char *name;
277   struct file_handle *handle;
278
279   name = dataset_name (ds);
280   if (name[0] == '\0')
281     name = _("active dataset");
282
283   handle = create_handle (NULL, xstrdup (name), FH_REF_DATASET, C_ENCODING);
284   handle->ds = ds;
285   return handle;
286 }
287
288 /* Returns a set of default properties for a file handle. */
289 const struct fh_properties *
290 fh_default_properties (void)
291 {
292 #if defined _WIN32 || defined __WIN32__
293 #define DEFAULT_LINE_ENDS FH_END_CRLF
294 #else
295 #define DEFAULT_LINE_ENDS FH_END_LF
296 #endif
297
298   static const struct fh_properties default_properties
299     = {FH_MODE_TEXT, DEFAULT_LINE_ENDS, 1024, 4, (char *) "Auto"};
300   return &default_properties;
301 }
302
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.
306
307    Return value is owned by the file handle.*/
308 const char *
309 fh_get_id (const struct file_handle *handle)
310 {
311   return handle->id;
312 }
313
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
317    by the file handle.
318
319    Useful for printing error messages about use of file handles.  */
320 const char *
321 fh_get_name (const struct file_handle *handle)
322 {
323   return handle->name;
324 }
325
326 /* Returns the type of object that HANDLE refers to. */
327 enum fh_referent
328 fh_get_referent (const struct file_handle *handle)
329 {
330   return handle->referent;
331 }
332
333 /* Returns the name of the file associated with HANDLE. */
334 const char *
335 fh_get_file_name (const struct file_handle *handle)
336 {
337   assert (handle->referent == FH_REF_FILE);
338   return handle->file_name;
339 }
340
341
342 /* Returns the character encoding of the name of the file associated with HANDLE. */
343 const char *
344 fh_get_file_name_encoding (const struct file_handle *handle)
345 {
346   assert (handle->referent == FH_REF_FILE);
347   return handle->file_name_encoding;
348 }
349
350
351 /* Returns the mode of HANDLE. */
352 enum fh_mode
353 fh_get_mode (const struct file_handle *handle)
354 {
355   assert (handle->referent == FH_REF_FILE);
356   return handle->mode;
357 }
358
359 /* Returns the line ends of HANDLE, which must be a handle associated with a
360    file. */
361 enum fh_line_ends
362 fh_get_line_ends (const struct file_handle *handle)
363 {
364   assert (handle->referent == FH_REF_FILE);
365   return handle->line_ends;
366 }
367
368 /* Returns the width of a logical record on HANDLE. */
369 size_t
370 fh_get_record_width (const struct file_handle *handle)
371 {
372   assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
373   return handle->record_width;
374 }
375
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. */
379 size_t
380 fh_get_tab_width (const struct file_handle *handle)
381 {
382   assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
383   return handle->tab_width;
384 }
385
386 /* Returns the encoding of characters read from HANDLE. */
387 const char *
388 fh_get_encoding (const struct file_handle *handle)
389 {
390   return handle->encoding;
391 }
392
393 /* Returns true if A and B refer to the same file or dataset, false
394    otherwise. */
395 bool
396 fh_equal (const struct file_handle *a, const struct file_handle *b)
397 {
398   if (a->referent != b->referent)
399     return false;
400
401   switch (a->referent)
402     {
403     case FH_REF_FILE:
404       {
405         struct file_identity *a_id = fh_get_identity (a);
406         struct file_identity *b_id = fh_get_identity (b);
407
408         int cmp = fh_compare_file_identities (a_id, b_id);
409
410         fh_free_identity (a_id);
411         fh_free_identity (b_id);
412
413         return cmp == 0;
414       }
415
416     case FH_REF_INLINE:
417       return true;
418
419     case FH_REF_DATASET:
420       return a->ds == b->ds;
421
422     default:
423       NOT_REACHED ();
424     }
425 }
426
427 /* Returns the dataset handle associated with HANDLE.
428    Applicable to only FH_REF_DATASET files. */
429 struct dataset *
430 fh_get_dataset (const struct file_handle *handle)
431 {
432   assert (handle->referent == FH_REF_DATASET);
433   return handle->ds;
434 }
435
436 /* Returns the current default handle. */
437 struct file_handle *
438 fh_get_default_handle (void)
439 {
440   return default_handle ? default_handle : fh_inline_file ();
441 }
442
443 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
444 void
445 fh_set_default_handle (struct file_handle *new_default_handle)
446 {
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);
454 }
455 \f
456 /* Information about a file handle's readers or writers. */
457 struct fh_lock
458   {
459     struct hmap_node node;      /* hmap_node member. */
460
461     /* Hash key. */
462     enum fh_referent referent;  /* Type of underlying file. */
463     union
464       {
465         struct file_identity *file; /* FH_REF_FILE only. */
466         unsigned int unique_id;    /* FH_REF_DATASET only. */
467       }
468     u;
469     enum fh_access access;      /* Type of file access. */
470
471     /* Number of openers. */
472     size_t open_cnt;
473
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. */
478   };
479
480
481 static void make_key (struct fh_lock *, const struct file_handle *,
482                       enum fh_access);
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);
486
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.
490
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.
493
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.
498
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
501    do so.
502
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
509    different TYPE.
510
511    A lock may be associated with auxiliary data.  See
512    fh_lock_get_aux and fh_lock_set_aux for more details. */
513 struct fh_lock *
514 fh_lock (struct file_handle *h, enum fh_referent mask UNUSED,
515          const char *type, enum fh_access access, bool exclusive)
516 {
517   struct fh_lock *key = NULL;
518   size_t hash ;
519   struct fh_lock *lock = NULL;
520   bool found_lock = false;
521
522   assert ((fh_get_referent (h) & mask) != 0);
523   assert (access == FH_ACC_READ || access == FH_ACC_WRITE);
524
525   key = xmalloc (sizeof *key);
526
527   make_key (key, h, access);
528
529   key->open_cnt = 1;
530   key->exclusive = exclusive;
531   key->type = type;
532   key->aux = NULL;
533
534   hash = hash_fh_lock (key);
535
536   HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
537     {
538       if (0 == compare_fh_locks (lock, key))
539         {
540           found_lock = true;
541           break;
542         }
543     }
544
545   if (found_lock)
546     {
547       if (strcmp (lock->type, type))
548         {
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));
553           else
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));
557           return NULL;
558         }
559       else if (exclusive || lock->exclusive)
560         {
561           msg (SE, _("Can't re-open %s as a %s."),
562                fh_get_name (h), gettext (type));
563           return NULL;
564         }
565       lock->open_cnt++;
566
567       free_key (key);
568       free (key);
569
570       return lock;
571     }
572
573   hmap_insert (&locks, &key->node, hash);
574   found_lock = false;
575   HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
576     {
577       if (0 == compare_fh_locks (lock, key))
578         {
579           found_lock = true;
580           break;
581         }
582     }
583
584   assert (found_lock);
585
586   return key;
587 }
588
589 /* Releases LOCK that was acquired with fh_lock.
590    Returns true if LOCK is still locked, because other clients
591    also had it locked.
592
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
599    lock).  */
600 bool
601 fh_unlock (struct fh_lock *lock)
602 {
603   if (lock != NULL)
604     {
605       assert (lock->open_cnt > 0);
606       if (--lock->open_cnt == 0)
607         {
608           hmap_delete (&locks, &lock->node);
609           free_key (lock);
610           free (lock);
611           return false;
612         }
613     }
614   return true;
615 }
616
617 /* Returns auxiliary data for LOCK.
618
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. */
622 void *
623 fh_lock_get_aux (const struct fh_lock *lock)
624 {
625   return lock->aux;
626 }
627
628 /* Sets the auxiliary data for LOCK to AUX. */
629 void
630 fh_lock_set_aux (struct fh_lock *lock, void *aux)
631 {
632   lock->aux = aux;
633 }
634
635 /* Returns true if HANDLE is locked for the given type of ACCESS,
636    false otherwise. */
637 bool
638 fh_is_locked (const struct file_handle *handle, enum fh_access access)
639 {
640   struct fh_lock key;
641   const struct fh_lock *k = NULL;
642   bool is_locked = false;
643   size_t hash ;
644
645   make_key (&key, handle, access);
646
647   hash = hash_fh_lock (&key);
648
649
650   HMAP_FOR_EACH_WITH_HASH (k, struct fh_lock, node, hash, &locks)
651     {
652       if (0 == compare_fh_locks (k, &key))
653         {
654           is_locked = true;
655           break;
656         }
657     }
658
659   free_key (&key);
660
661   return is_locked;
662 }
663
664 /* Initializes the key fields in LOCK for looking up or inserting
665    handle H for the given kind of ACCESS. */
666 static void
667 make_key (struct fh_lock *lock, const struct file_handle *h,
668           enum fh_access access)
669 {
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));
676 }
677
678 /* Frees the key fields in LOCK. */
679 static void
680 free_key (struct fh_lock *lock)
681 {
682   if (lock->referent == FH_REF_FILE)
683     fh_free_identity (lock->u.file);
684 }
685
686 /* Compares the key fields in struct fh_lock objects A and B and
687    returns a strcmp()-type result. */
688 static int
689 compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b)
690 {
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);
700   else
701     return 0;
702 }
703
704 /* Returns a hash value for LOCK. */
705 static unsigned int
706 hash_fh_lock (const struct fh_lock *lock)
707 {
708   unsigned int basis;
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;
713   else
714     basis = 0;
715   return hash_int ((lock->referent << 3) | lock->access, basis);
716 }
717
718 \f
719
720
721
722
723 /* A file's identity:
724
725    - For a file that exists, this is its device and inode.
726
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.
730
731    - For a file that does not exist and has a nonexistent
732      directory, this is the file name.
733
734    Windows doesn't have inode numbers, so we just use the name
735    there. */
736 struct file_identity
737 {
738   unsigned long long device;               /* Device number. */
739   unsigned long long inode;                /* Inode number. */
740   char *name;                 /* File name, where needed, otherwise NULL. */
741 };
742
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)
749 {
750   struct file_identity *identity = xmalloc (sizeof *identity);
751
752   const char *file_name = fh_get_file_name (fh);
753
754 #if !(defined _WIN32 || defined __WIN32__)
755   struct stat s;
756   if (lstat (file_name, &s) == 0)
757     {
758       identity->device = s.st_dev;
759       identity->inode = s.st_ino;
760       identity->name = NULL;
761     }
762   else
763     {
764       char *dir = dir_name (file_name);
765       if (last_component (file_name) != NULL && stat (dir, &s) == 0)
766         {
767           identity->device = s.st_dev;
768           identity->inode = s.st_ino;
769           identity->name = base_name (file_name);
770         }
771       else
772         {
773           identity->device = 0;
774           identity->inode = 0;
775           identity->name = xstrdup (file_name);
776         }
777       free (dir);
778     }
779 #else /* Windows */
780   bool ok = false;
781   HANDLE h = CreateFile (file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
782   if (h != INVALID_HANDLE_VALUE)
783   {
784     BY_HANDLE_FILE_INFORMATION fi;
785     ok = GetFileInformationByHandle (h, &fi);
786     if (ok)
787       {
788         identity->device = fi.dwVolumeSerialNumber;
789         identity->inode = fi.nFileIndexHigh;
790         identity->inode <<= (sizeof fi.nFileIndexLow) * CHAR_BIT;
791         identity->inode |= fi.nFileIndexLow;
792         identity->name = 0;
793       }
794     CloseHandle (h);
795   }
796
797   if (!ok)
798     {
799       identity->device = 0;
800       identity->inode = 0;
801
802       size_t bufsize;
803       size_t pathlen = 255;
804       char *cname = NULL;
805       do
806       {
807         bufsize = pathlen;
808         cname = xrealloc (cname, bufsize);
809         pathlen = GetFullPathName (file_name, bufsize, cname, NULL);
810       }
811       while (pathlen > bufsize);
812       identity->name = xstrdup (cname);
813       free (cname);
814       str_lowercase (identity->name);
815     }
816 #endif /* Windows */
817
818   return identity;
819 }
820
821 /* Frees IDENTITY obtained from fh_get_identity(). */
822 void
823 fh_free_identity (struct file_identity *identity)
824 {
825   if (identity != NULL)
826     {
827       free (identity->name);
828       free (identity);
829     }
830 }
831
832 /* Compares A and B, returning a strcmp()-type result. */
833 int
834 fh_compare_file_identities (const struct file_identity *a,
835                             const struct file_identity *b)
836 {
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;
843   else
844     return b->name != NULL ? -1 : 0;
845 }
846
847 /* Returns a hash value for IDENTITY. */
848 unsigned int
849 fh_hash_identity (const struct file_identity *identity)
850 {
851   unsigned int hash = hash_int (identity->device, identity->inode);
852   if (identity->name != NULL)
853     hash = hash_string (identity->name, hash);
854   return hash;
855 }