file-handle-def: Style improvements.
[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 (handle != fh_inline_file () && handle->id != NULL)
195     unname_handle (handle);
196 }
197
198 /* Returns the handle with the given ID, or a null pointer if
199    there is none. */
200 struct file_handle *
201 fh_from_id (const char *id)
202 {
203   struct file_handle *handle;
204
205   HMAP_FOR_EACH_WITH_HASH (handle, struct file_handle, name_node,
206                            utf8_hash_case_string (id, 0), &named_handles)
207     if (!utf8_strcasecmp (id, handle->id))
208       return fh_ref (handle);
209
210   return NULL;
211 }
212
213 /* Creates a new handle with identifier ID (which may be null)
214    and name HANDLE_NAME that refers to REFERENT.  Links the new
215    handle into the global list.  Returns the new handle.
216
217    The new handle is not fully initialized.  The caller is
218    responsible for completing its initialization. */
219 static struct file_handle *
220 create_handle (const char *id, char *handle_name, enum fh_referent referent,
221                const char *encoding)
222 {
223   struct file_handle *handle = xmalloc (sizeof *handle);
224   *handle = (struct file_handle) {
225     .ref_cnt = 1,
226     .id = xstrdup_if_nonnull (id),
227     .name = handle_name,
228     .referent = referent,
229     .encoding = xstrdup (encoding),
230   };
231
232   if (id)
233     hmap_insert (&named_handles, &handle->name_node,
234                  utf8_hash_case_string (handle->id, 0));
235
236   return handle;
237 }
238
239 /* Returns the unique handle of referent type FH_REF_INLINE,
240    which refers to the "inline file" that represents character
241    data in the command file between BEGIN DATA and END DATA. */
242 struct file_handle *
243 fh_inline_file (void)
244 {
245   return inline_file;
246 }
247
248 /* Creates and returns a new file handle with the given ID, which may be null.
249    If it is non-null, it must be a UTF-8 encoded string that is unique among
250    existing file identifiers.  The new handle is associated with file FILE_NAME
251    and the given PROPERTIES. */
252 struct file_handle *
253 fh_create_file (const char *id, const char *file_name, const char *file_name_encoding,
254                 const struct fh_properties *properties)
255 {
256   char *handle_name = id ? xstrdup (id) : xasprintf ("`%s'", file_name);
257   struct file_handle *handle = create_handle (id, handle_name, FH_REF_FILE,
258                                               properties->encoding);
259   handle->file_name = xstrdup (file_name);
260   handle->file_name_encoding = xstrdup_if_nonnull (file_name_encoding);
261   handle->mode = properties->mode;
262   handle->line_ends = properties->line_ends;
263   handle->record_width = properties->record_width;
264   handle->tab_width = properties->tab_width;
265   return handle;
266 }
267
268 /* Creates a new file handle with the given ID, which must be
269    unique among existing file identifiers.  The new handle is
270    associated with a dataset file (initially empty). */
271 struct file_handle *
272 fh_create_dataset (struct dataset *ds)
273 {
274   const char *name;
275   struct file_handle *handle;
276
277   name = dataset_name (ds);
278   if (name[0] == '\0')
279     name = _("active dataset");
280
281   handle = create_handle (NULL, xstrdup (name), FH_REF_DATASET, C_ENCODING);
282   handle->ds = ds;
283   return handle;
284 }
285
286 /* Returns a set of default properties for a file handle. */
287 const struct fh_properties *
288 fh_default_properties (void)
289 {
290 #if defined _WIN32 || defined __WIN32__
291 #define DEFAULT_LINE_ENDS FH_END_CRLF
292 #else
293 #define DEFAULT_LINE_ENDS FH_END_LF
294 #endif
295
296   static const struct fh_properties default_properties
297     = {FH_MODE_TEXT, DEFAULT_LINE_ENDS, 1024, 4, (char *) "Auto"};
298   return &default_properties;
299 }
300
301 /* Returns the identifier that may be used in syntax to name the
302    given HANDLE, which takes the form of a PSPP identifier.  If
303    HANDLE has no identifier, returns a null pointer.
304
305    Return value is owned by the file handle.*/
306 const char *
307 fh_get_id (const struct file_handle *handle)
308 {
309   return handle->id;
310 }
311
312 /* Returns a user-friendly string to identify the given HANDLE.
313    If HANDLE was created by referring to a file name, returns the
314    file name, enclosed in double quotes.  Return value is owned
315    by the file handle.
316
317    Useful for printing error messages about use of file handles.  */
318 const char *
319 fh_get_name (const struct file_handle *handle)
320 {
321   return handle->name;
322 }
323
324 /* Returns the type of object that HANDLE refers to. */
325 enum fh_referent
326 fh_get_referent (const struct file_handle *handle)
327 {
328   return handle->referent;
329 }
330
331 /* Returns the name of the file associated with HANDLE. */
332 const char *
333 fh_get_file_name (const struct file_handle *handle)
334 {
335   assert (handle->referent == FH_REF_FILE);
336   return handle->file_name;
337 }
338
339
340 /* Returns the character encoding of the name of the file associated with HANDLE. */
341 const char *
342 fh_get_file_name_encoding (const struct file_handle *handle)
343 {
344   assert (handle->referent == FH_REF_FILE);
345   return handle->file_name_encoding;
346 }
347
348
349 /* Returns the mode of HANDLE. */
350 enum fh_mode
351 fh_get_mode (const struct file_handle *handle)
352 {
353   assert (handle->referent == FH_REF_FILE);
354   return handle->mode;
355 }
356
357 /* Returns the line ends of HANDLE, which must be a handle associated with a
358    file. */
359 enum fh_line_ends
360 fh_get_line_ends (const struct file_handle *handle)
361 {
362   assert (handle->referent == FH_REF_FILE);
363   return handle->line_ends;
364 }
365
366 /* Returns the width of a logical record on HANDLE. */
367 size_t
368 fh_get_record_width (const struct file_handle *handle)
369 {
370   assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
371   return handle->record_width;
372 }
373
374 /* Returns the number of characters per tab stop for HANDLE, or
375    zero if tabs are not to be expanded.  Applicable only to
376    FH_MODE_TEXT files. */
377 size_t
378 fh_get_tab_width (const struct file_handle *handle)
379 {
380   assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
381   return handle->tab_width;
382 }
383
384 /* Returns the encoding of characters read from HANDLE. */
385 const char *
386 fh_get_encoding (const struct file_handle *handle)
387 {
388   return handle->encoding;
389 }
390
391 /* Returns true if A and B refer to the same file or dataset, false
392    otherwise. */
393 bool
394 fh_equal (const struct file_handle *a, const struct file_handle *b)
395 {
396   if (a->referent != b->referent)
397     return false;
398
399   switch (a->referent)
400     {
401     case FH_REF_FILE:
402       {
403         struct file_identity *a_id = fh_get_identity (a);
404         struct file_identity *b_id = fh_get_identity (b);
405
406         int cmp = fh_compare_file_identities (a_id, b_id);
407
408         fh_free_identity (a_id);
409         fh_free_identity (b_id);
410
411         return cmp == 0;
412       }
413
414     case FH_REF_INLINE:
415       return true;
416
417     case FH_REF_DATASET:
418       return a->ds == b->ds;
419
420     default:
421       NOT_REACHED ();
422     }
423 }
424
425 /* Returns the dataset handle associated with HANDLE.
426    Applicable to only FH_REF_DATASET files. */
427 struct dataset *
428 fh_get_dataset (const struct file_handle *handle)
429 {
430   assert (handle->referent == FH_REF_DATASET);
431   return handle->ds;
432 }
433
434 /* Returns the current default handle. */
435 struct file_handle *
436 fh_get_default_handle (void)
437 {
438   return default_handle ? default_handle : fh_inline_file ();
439 }
440
441 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
442 void
443 fh_set_default_handle (struct file_handle *new_default_handle)
444 {
445   assert (new_default_handle == NULL
446           || (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));
447   if (default_handle != NULL && default_handle != inline_file)
448     fh_unref (default_handle);
449   default_handle = new_default_handle;
450   if (default_handle != NULL)
451     default_handle = fh_ref (default_handle);
452 }
453 \f
454 /* Information about a file handle's readers or writers. */
455 struct fh_lock
456   {
457     struct hmap_node node;      /* hmap_node member. */
458
459     /* Hash key. */
460     enum fh_referent referent;  /* Type of underlying file. */
461     union
462       {
463         struct file_identity *file; /* FH_REF_FILE only. */
464         unsigned int unique_id;    /* FH_REF_DATASET only. */
465       }
466     u;
467     enum fh_access access;      /* Type of file access. */
468
469     /* Number of openers. */
470     size_t open_cnt;
471
472     /* Applicable only when open_cnt > 0. */
473     bool exclusive;             /* No other openers allowed? */
474     const char *type;           /* Human-readable type of file. */
475     void *aux;                  /* Owner's auxiliary data. */
476   };
477
478
479 static void make_key (struct fh_lock *, const struct file_handle *,
480                       enum fh_access);
481 static void free_key (struct fh_lock *);
482 static int compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b);
483 static unsigned int hash_fh_lock (const struct fh_lock *lock);
484
485 /* Tries to lock handle H for the given kind of ACCESS and TYPE
486    of file.  Returns a pointer to a struct fh_lock if successful,
487    otherwise a null pointer.
488
489    H's referent type must be one of the bits in MASK.  The caller
490    must verify this ahead of time; we simply assert it here.
491
492    TYPE is the sort of file, e.g. "system file".  Only one type
493    of access is allowed on a given file at a time for reading,
494    and similarly for writing.  If successful, a reference to TYPE
495    is retained, so it should probably be a string literal.
496
497    TYPE should be marked with N_() in the caller: that is, the
498    caller should not translate it with gettext, but fh_lock will
499    do so.
500
501    ACCESS specifies whether the lock is for reading or writing.
502    EXCLUSIVE is true to require exclusive access, false to allow
503    sharing with other accessors.  Exclusive read access precludes
504    other readers, but not writers; exclusive write access
505    precludes other writers, but not readers.  A sharable read or
506    write lock precludes reader or writers, respectively, of a
507    different TYPE.
508
509    A lock may be associated with auxiliary data.  See
510    fh_lock_get_aux and fh_lock_set_aux for more details. */
511 struct fh_lock *
512 fh_lock (struct file_handle *h, enum fh_referent mask UNUSED,
513          const char *type, enum fh_access access, bool exclusive)
514 {
515   struct fh_lock *key = NULL;
516   size_t hash ;
517   struct fh_lock *lock = NULL;
518   bool found_lock = false;
519
520   assert ((fh_get_referent (h) & mask) != 0);
521   assert (access == FH_ACC_READ || access == FH_ACC_WRITE);
522
523   key = xmalloc (sizeof *key);
524
525   make_key (key, h, access);
526
527   key->open_cnt = 1;
528   key->exclusive = exclusive;
529   key->type = type;
530   key->aux = NULL;
531
532   hash = hash_fh_lock (key);
533
534   HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
535     {
536       if (0 == compare_fh_locks (lock, key))
537         {
538           found_lock = true;
539           break;
540         }
541     }
542
543   if (found_lock)
544     {
545       if (strcmp (lock->type, type))
546         {
547           if (access == FH_ACC_READ)
548             msg (SE, _("Can't read from %s as a %s because it is "
549                        "already being read as a %s."),
550                  fh_get_name (h), gettext (type), gettext (lock->type));
551           else
552             msg (SE, _("Can't write to %s as a %s because it is "
553                        "already being written as a %s."),
554                  fh_get_name (h), gettext (type), gettext (lock->type));
555           return NULL;
556         }
557       else if (exclusive || lock->exclusive)
558         {
559           msg (SE, _("Can't re-open %s as a %s."),
560                fh_get_name (h), gettext (type));
561           return NULL;
562         }
563       lock->open_cnt++;
564
565       free_key (key);
566       free (key);
567
568       return lock;
569     }
570
571   hmap_insert (&locks, &key->node, hash);
572   found_lock = false;
573   HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
574     {
575       if (0 == compare_fh_locks (lock, key))
576         {
577           found_lock = true;
578           break;
579         }
580     }
581
582   assert (found_lock);
583
584   return key;
585 }
586
587 /* Releases LOCK that was acquired with fh_lock.
588    Returns true if LOCK is still locked, because other clients
589    also had it locked.
590
591    Returns false if LOCK has now been destroyed.  In this case
592    the caller must ensure that any auxiliary data associated with
593    LOCK is destroyed, to avoid a memory leak.  The caller must
594    obtain a pointer to the auxiliary data, e.g. via
595    fh_lock_get_aux *before* calling fh_unlock (because it yields
596    undefined behavior to call fh_lock_get_aux on a destroyed
597    lock).  */
598 bool
599 fh_unlock (struct fh_lock *lock)
600 {
601   if (lock != NULL)
602     {
603       assert (lock->open_cnt > 0);
604       if (--lock->open_cnt == 0)
605         {
606           hmap_delete (&locks, &lock->node);
607           free_key (lock);
608           free (lock);
609           return false;
610         }
611     }
612   return true;
613 }
614
615 /* Returns auxiliary data for LOCK.
616
617    Auxiliary data is shared by every client that holds LOCK (for
618    an exclusive lock, this is a single client).  To avoid leaks,
619    auxiliary data must be released before LOCK is destroyed. */
620 void *
621 fh_lock_get_aux (const struct fh_lock *lock)
622 {
623   return lock->aux;
624 }
625
626 /* Sets the auxiliary data for LOCK to AUX. */
627 void
628 fh_lock_set_aux (struct fh_lock *lock, void *aux)
629 {
630   lock->aux = aux;
631 }
632
633 /* Returns true if HANDLE is locked for the given type of ACCESS,
634    false otherwise. */
635 bool
636 fh_is_locked (const struct file_handle *handle, enum fh_access access)
637 {
638   struct fh_lock key;
639   const struct fh_lock *k = NULL;
640   bool is_locked = false;
641   size_t hash ;
642
643   make_key (&key, handle, access);
644
645   hash = hash_fh_lock (&key);
646
647
648   HMAP_FOR_EACH_WITH_HASH (k, struct fh_lock, node, hash, &locks)
649     {
650       if (0 == compare_fh_locks (k, &key))
651         {
652           is_locked = true;
653           break;
654         }
655     }
656
657   free_key (&key);
658
659   return is_locked;
660 }
661
662 /* Initializes the key fields in LOCK for looking up or inserting
663    handle H for the given kind of ACCESS. */
664 static void
665 make_key (struct fh_lock *lock, const struct file_handle *h,
666           enum fh_access access)
667 {
668   lock->referent = fh_get_referent (h);
669   lock->access = access;
670   if (lock->referent == FH_REF_FILE)
671     lock->u.file = fh_get_identity (h);
672   else if (lock->referent == FH_REF_DATASET)
673     lock->u.unique_id = dataset_seqno (fh_get_dataset (h));
674 }
675
676 /* Frees the key fields in LOCK. */
677 static void
678 free_key (struct fh_lock *lock)
679 {
680   if (lock->referent == FH_REF_FILE)
681     fh_free_identity (lock->u.file);
682 }
683
684 /* Compares the key fields in struct fh_lock objects A and B and
685    returns a strcmp()-type result. */
686 static int
687 compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b)
688 {
689   if (a->referent != b->referent)
690     return a->referent < b->referent ? -1 : 1;
691   else if (a->access != b->access)
692     return a->access < b->access ? -1 : 1;
693   else if (a->referent == FH_REF_FILE)
694     return fh_compare_file_identities (a->u.file, b->u.file);
695   else if (a->referent == FH_REF_DATASET)
696     return (a->u.unique_id < b->u.unique_id ? -1
697             : a->u.unique_id > b->u.unique_id);
698   else
699     return 0;
700 }
701
702 /* Returns a hash value for LOCK. */
703 static unsigned int
704 hash_fh_lock (const struct fh_lock *lock)
705 {
706   unsigned int basis;
707   if (lock->referent == FH_REF_FILE)
708     basis = fh_hash_identity (lock->u.file);
709   else if (lock->referent == FH_REF_DATASET)
710     basis = lock->u.unique_id;
711   else
712     basis = 0;
713   return hash_int ((lock->referent << 3) | lock->access, basis);
714 }
715
716 \f
717
718
719
720
721 /* A file's identity:
722
723    - For a file that exists, this is its device and inode.
724
725    - For a file that does not exist, but which has a directory
726      name that exists, this is the device and inode of the
727      directory, plus the file's base name.
728
729    - For a file that does not exist and has a nonexistent
730      directory, this is the file name.
731
732    Windows doesn't have inode numbers, so we just use the name
733    there. */
734 struct file_identity
735 {
736   unsigned long long device;               /* Device number. */
737   unsigned long long inode;                /* Inode number. */
738   char *name;                 /* File name, where needed, otherwise NULL. */
739 };
740
741 /* Returns a pointer to a dynamically allocated structure whose
742    value can be used to tell whether two files are actually the
743    same file.  The caller is responsible for freeing the structure with
744    fh_free_identity() when finished. */
745 static struct file_identity *
746 fh_get_identity (const struct file_handle *fh)
747 {
748   struct file_identity *identity = xmalloc (sizeof *identity);
749
750   const char *file_name = fh_get_file_name (fh);
751
752 #if !(defined _WIN32 || defined __WIN32__)
753   struct stat s;
754   if (lstat (file_name, &s) == 0)
755     {
756       identity->device = s.st_dev;
757       identity->inode = s.st_ino;
758       identity->name = NULL;
759     }
760   else
761     {
762       char *dir = dir_name (file_name);
763       if (last_component (file_name) != NULL && stat (dir, &s) == 0)
764         {
765           identity->device = s.st_dev;
766           identity->inode = s.st_ino;
767           identity->name = base_name (file_name);
768         }
769       else
770         {
771           identity->device = 0;
772           identity->inode = 0;
773           identity->name = xstrdup (file_name);
774         }
775       free (dir);
776     }
777 #else /* Windows */
778   bool ok = false;
779   HANDLE h = CreateFile (file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
780   if (h != INVALID_HANDLE_VALUE)
781   {
782     BY_HANDLE_FILE_INFORMATION fi;
783     ok = GetFileInformationByHandle (h, &fi);
784     if (ok)
785       {
786         identity->device = fi.dwVolumeSerialNumber;
787         identity->inode = fi.nFileIndexHigh;
788         identity->inode <<= (sizeof fi.nFileIndexLow) * CHAR_BIT;
789         identity->inode |= fi.nFileIndexLow;
790         identity->name = 0;
791       }
792     CloseHandle (h);
793   }
794
795   if (!ok)
796     {
797       identity->device = 0;
798       identity->inode = 0;
799
800       size_t bufsize;
801       size_t pathlen = 255;
802       char *cname = NULL;
803       do
804       {
805         bufsize = pathlen;
806         cname = xrealloc (cname, bufsize);
807         pathlen = GetFullPathName (file_name, bufsize, cname, NULL);
808       }
809       while (pathlen > bufsize);
810       identity->name = xstrdup (cname);
811       free (cname);
812       str_lowercase (identity->name);
813     }
814 #endif /* Windows */
815
816   return identity;
817 }
818
819 /* Frees IDENTITY obtained from fh_get_identity(). */
820 void
821 fh_free_identity (struct file_identity *identity)
822 {
823   if (identity != NULL)
824     {
825       free (identity->name);
826       free (identity);
827     }
828 }
829
830 /* Compares A and B, returning a strcmp()-type result. */
831 int
832 fh_compare_file_identities (const struct file_identity *a,
833                             const struct file_identity *b)
834 {
835   if (a->device != b->device)
836     return a->device < b->device ? -1 : 1;
837   else if (a->inode != b->inode)
838     return a->inode < b->inode ? -1 : 1;
839   else if (a->name != NULL)
840     return b->name != NULL ? strcmp (a->name, b->name) : 1;
841   else
842     return b->name != NULL ? -1 : 0;
843 }
844
845 /* Returns a hash value for IDENTITY. */
846 unsigned int
847 fh_hash_identity (const struct file_identity *identity)
848 {
849   unsigned int hash = hash_int (identity->device, identity->inode);
850   if (identity->name != NULL)
851     hash = hash_string (identity->name, hash);
852   return hash;
853 }