fbuf: New data structure for buffered file I/O.
[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/cast.h"
29 #include "libpspp/compiler.h"
30 #include "libpspp/hash-functions.h"
31 #include "libpspp/hmap.h"
32 #include "libpspp/i18n.h"
33 #include "libpspp/message.h"
34 #include "libpspp/str.h"
35
36 #include <sys/stat.h>
37
38 #include "gl/dirname.h"
39 #include "gl/xalloc.h"
40
41 #include "gettext.h"
42 #define _(msgid) gettext (msgid)
43
44 #if defined _WIN32 || defined __WIN32__
45 #define WIN32_LEAN_AND_MEAN  /* avoid including junk */
46 #include <windows.h>
47 #endif
48
49 /* File handle. */
50 struct file_handle
51   {
52     struct hmap_node name_node; /* Element in named_handles hmap. */
53     size_t ref_cnt;             /* Number of references. */
54     char *id;                   /* Identifier token, NULL if none. */
55     char *name;                 /* User-friendly identifying name. */
56     enum fh_referent referent;  /* What the file handle refers to. */
57
58     /* FH_REF_FILE only. */
59     char *file_name;            /* File name as provided by user. */
60     char *file_name_encoding;   /* The character encoding of file_name,
61                                    This is NOT the encoding of the file contents! */
62     enum fh_mode mode;          /* File mode. */
63     enum fh_line_ends line_ends; /* Line ends for text files. */
64
65     /* FH_REF_FILE and FH_REF_INLINE only. */
66     size_t record_width;        /* Length of fixed-format records. */
67     size_t tab_width;           /* Tab width, 0=do not expand tabs. */
68     char *encoding;             /* Charset for contents. */
69
70     /* FH_REF_DATASET only. */
71     struct dataset *ds;         /* Dataset. */
72   };
73
74 /* All "struct file_handle"s with nonnull 'id' member. */
75 static struct hmap named_handles = HMAP_INITIALIZER (named_handles);
76
77 /* Default file handle for DATA LIST, REREAD, REPEATING DATA
78    commands. */
79 static struct file_handle *default_handle;
80
81 /* The "file" that reads from BEGIN DATA...END DATA. */
82 static struct file_handle *inline_file;
83
84 static struct file_handle *create_handle (const char *id,
85                                           char *name, enum fh_referent,
86                                           const char *encoding);
87 static void free_handle (struct file_handle *);
88 static void unname_handle (struct file_handle *);
89
90 /* Hash table of all active locks. */
91 static struct hmap locks = HMAP_INITIALIZER (locks);
92
93 static struct file_identity *fh_get_identity (const struct file_handle *);
94 static void fh_free_identity (struct file_identity *);
95 static int fh_compare_file_identities (const struct file_identity *,
96                                 const struct file_identity *);
97 static unsigned int fh_hash_identity (const struct file_identity *);
98
99 /* File handle initialization routine. */
100 void
101 fh_init (void)
102 {
103   inline_file = create_handle ("INLINE", xstrdup ("INLINE"), FH_REF_INLINE,
104                                "Auto");
105   inline_file->record_width = 80;
106   inline_file->tab_width = 8;
107 }
108
109 /* Removes all named file handles from the global list. */
110 void
111 fh_done (void)
112 {
113   struct file_handle *handle, *next;
114
115   HMAP_FOR_EACH_SAFE (handle, next,
116                       struct file_handle, name_node, &named_handles)
117     unname_handle (handle);
118 }
119
120 /* Free HANDLE and remove it from the global list. */
121 static void
122 free_handle (struct file_handle *handle)
123 {
124   /* Remove handle from global list. */
125   if (handle->id != NULL)
126     hmap_delete (&named_handles, &handle->name_node);
127
128   /* Free data. */
129   free (handle->id);
130   free (handle->name);
131   free (handle->file_name);
132   free (handle->file_name_encoding);
133   free (handle->encoding);
134   free (handle);
135 }
136
137 /* Make HANDLE unnamed, so that it can no longer be referenced by
138    name.  The caller must hold a reference to HANDLE, which is
139    not affected by this function. */
140 static void
141 unname_handle (struct file_handle *handle)
142 {
143   assert (handle->id != NULL);
144   free (handle->id);
145   handle->id = NULL;
146   hmap_delete (&named_handles, &handle->name_node);
147
148   /* Drop the reference held by the named_handles table. */
149   fh_unref (handle);
150 }
151
152 /* Increments HANDLE's reference count and returns HANDLE. */
153 struct file_handle *
154 fh_ref (struct file_handle *handle)
155 {
156   assert (handle->ref_cnt > 0);
157   handle->ref_cnt++;
158   return handle;
159 }
160
161 /* Decrements HANDLE's reference count.
162    If the reference count drops to 0, HANDLE is destroyed. */
163 void
164 fh_unref (struct file_handle *handle)
165 {
166   if (handle != NULL)
167     {
168       assert (handle->ref_cnt > 0);
169       if (--handle->ref_cnt == 0)
170         free_handle (handle);
171     }
172 }
173
174 /* Make HANDLE unnamed, so that it can no longer be referenced by
175    name.  The caller must hold a reference to HANDLE, which is
176    not affected by this function.
177
178    This function ignores a null pointer as input.  It has no
179    effect on the inline handle, which is always named INLINE.*/
180 void
181 fh_unname (struct file_handle *handle)
182 {
183   assert (handle->ref_cnt > 1);
184   if (handle != fh_inline_file () && handle->id != NULL)
185     unname_handle (handle);
186 }
187
188 /* Returns the handle with the given ID, or a null pointer if
189    there is none. */
190 struct file_handle *
191 fh_from_id (const char *id)
192 {
193   struct file_handle *handle;
194
195   HMAP_FOR_EACH_WITH_HASH (handle, struct file_handle, name_node,
196                            utf8_hash_case_string (id, 0), &named_handles)
197     if (!utf8_strcasecmp (id, handle->id))
198       {
199         return fh_ref (handle);
200       }
201
202   return NULL;
203 }
204
205 /* Creates a new handle with identifier ID (which may be null)
206    and name HANDLE_NAME that refers to REFERENT.  Links the new
207    handle into the global list.  Returns the new handle.
208
209    The new handle is not fully initialized.  The caller is
210    responsible for completing its initialization. */
211 static struct file_handle *
212 create_handle (const char *id, char *handle_name, enum fh_referent referent,
213                const char *encoding)
214 {
215   struct file_handle *handle = xzalloc (sizeof *handle);
216
217   handle->ref_cnt = 1;
218   handle->id = id != NULL ? xstrdup (id) : NULL;
219   handle->name = handle_name;
220   handle->referent = referent;
221   handle->encoding = xstrdup (encoding);
222
223   if (id != NULL)
224     {
225       hmap_insert (&named_handles, &handle->name_node,
226                    utf8_hash_case_string (handle->id, 0));
227     }
228
229   return handle;
230 }
231
232 /* Returns the unique handle of referent type FH_REF_INLINE,
233    which refers to the "inline file" that represents character
234    data in the command file between BEGIN DATA and END DATA. */
235 struct file_handle *
236 fh_inline_file (void)
237 {
238   return inline_file;
239 }
240
241 /* Creates and returns a new file handle with the given ID, which may be null.
242    If it is non-null, it must be a UTF-8 encoded string that is unique among
243    existing file identifiers.  The new handle is associated with file FILE_NAME
244    and the given PROPERTIES. */
245 struct file_handle *
246 fh_create_file (const char *id, const char *file_name, const char *file_name_encoding,
247                 const struct fh_properties *properties)
248 {
249   char *handle_name;
250   struct file_handle *handle;
251
252   handle_name = id != NULL ? xstrdup (id) : xasprintf ("`%s'", file_name);
253   handle = create_handle (id, handle_name, FH_REF_FILE, properties->encoding);
254   handle->file_name = xstrdup (file_name);
255   handle->file_name_encoding = file_name_encoding ? xstrdup (file_name_encoding) : NULL;
256   handle->mode = properties->mode;
257   handle->line_ends = properties->line_ends;
258   handle->record_width = properties->record_width;
259   handle->tab_width = properties->tab_width;
260   return handle;
261 }
262
263 /* Creates a new file handle with the given ID, which must be
264    unique among existing file identifiers.  The new handle is
265    associated with a dataset file (initially empty). */
266 struct file_handle *
267 fh_create_dataset (struct dataset *ds)
268 {
269   const char *name;
270   struct file_handle *handle;
271
272   name = dataset_name (ds);
273   if (name[0] == '\0')
274     name = _("active dataset");
275
276   handle = create_handle (NULL, xstrdup (name), FH_REF_DATASET, C_ENCODING);
277   handle->ds = ds;
278   return handle;
279 }
280
281 /* Returns a set of default properties for a file handle. */
282 const struct fh_properties *
283 fh_default_properties (void)
284 {
285 #if defined _WIN32 || defined __WIN32__
286 #define DEFAULT_LINE_ENDS FH_END_CRLF
287 #else
288 #define DEFAULT_LINE_ENDS FH_END_LF
289 #endif
290
291   static const struct fh_properties default_properties
292     = {FH_MODE_TEXT, DEFAULT_LINE_ENDS, 1024, 4, (char *) "Auto"};
293   return &default_properties;
294 }
295
296 /* Returns the identifier that may be used in syntax to name the
297    given HANDLE, which takes the form of a PSPP identifier.  If
298    HANDLE has no identifier, returns a null pointer.
299
300    Return value is owned by the file handle.*/
301 const char *
302 fh_get_id (const struct file_handle *handle)
303 {
304   return handle->id;
305 }
306
307 /* Returns a user-friendly string to identify the given HANDLE.
308    If HANDLE was created by referring to a file name, returns the
309    file name, enclosed in double quotes.  Return value is owned
310    by the file handle.
311
312    Useful for printing error messages about use of file handles.  */
313 const char *
314 fh_get_name (const struct file_handle *handle)
315 {
316   return handle->name;
317 }
318
319 /* Returns the type of object that HANDLE refers to. */
320 enum fh_referent
321 fh_get_referent (const struct file_handle *handle)
322 {
323   return handle->referent;
324 }
325
326 /* Returns the name of the file associated with HANDLE. */
327 const char *
328 fh_get_file_name (const struct file_handle *handle)
329 {
330   assert (handle->referent == FH_REF_FILE);
331   return handle->file_name;
332 }
333
334
335 /* Returns the character encoding of the name of the file associated with HANDLE. */
336 const char *
337 fh_get_file_name_encoding (const struct file_handle *handle)
338 {
339   assert (handle->referent == FH_REF_FILE);
340   return handle->file_name_encoding;
341 }
342
343
344 /* Returns the mode of HANDLE. */
345 enum fh_mode
346 fh_get_mode (const struct file_handle *handle)
347 {
348   assert (handle->referent == FH_REF_FILE);
349   return handle->mode;
350 }
351
352 /* Returns the line ends of HANDLE, which must be a handle associated with a
353    file. */
354 enum fh_line_ends
355 fh_get_line_ends (const struct file_handle *handle)
356 {
357   assert (handle->referent == FH_REF_FILE);
358   return handle->line_ends;
359 }
360
361 /* Returns the width of a logical record on HANDLE. */
362 size_t
363 fh_get_record_width (const struct file_handle *handle)
364 {
365   assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
366   return handle->record_width;
367 }
368
369 /* Returns the number of characters per tab stop for HANDLE, or
370    zero if tabs are not to be expanded.  Applicable only to
371    FH_MODE_TEXT files. */
372 size_t
373 fh_get_tab_width (const struct file_handle *handle)
374 {
375   assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
376   return handle->tab_width;
377 }
378
379 /* Returns the encoding of characters read from HANDLE. */
380 const char *
381 fh_get_encoding (const struct file_handle *handle)
382 {
383   return handle->encoding;
384 }
385
386 /* Returns the dataset handle associated with HANDLE.
387    Applicable to only FH_REF_DATASET files. */
388 struct dataset *
389 fh_get_dataset (const struct file_handle *handle)
390 {
391   assert (handle->referent == FH_REF_DATASET);
392   return handle->ds;
393 }
394
395 /* Returns the current default handle. */
396 struct file_handle *
397 fh_get_default_handle (void)
398 {
399   return default_handle ? default_handle : fh_inline_file ();
400 }
401
402 /* Sets NEW_DEFAULT_HANDLE as the default handle. */
403 void
404 fh_set_default_handle (struct file_handle *new_default_handle)
405 {
406   assert (new_default_handle == NULL
407           || (new_default_handle->referent & (FH_REF_INLINE | FH_REF_FILE)));
408   if (default_handle != NULL && default_handle != inline_file)
409     fh_unref (default_handle);
410   default_handle = new_default_handle;
411   if (default_handle != NULL)
412     fh_ref (default_handle);
413 }
414 \f
415 /* Information about a file handle's readers or writers. */
416 struct fh_lock
417   {
418     struct hmap_node node;      /* hmap_node member. */
419
420     /* Hash key. */
421     enum fh_referent referent;  /* Type of underlying file. */
422     union
423       {
424         struct file_identity *file; /* FH_REF_FILE only. */
425         unsigned int unique_id;    /* FH_REF_DATASET only. */
426       }
427     u;
428     enum fh_access access;      /* Type of file access. */
429
430     /* Number of openers. */
431     size_t open_cnt;
432
433     /* Applicable only when open_cnt > 0. */
434     bool exclusive;             /* No other openers allowed? */
435     const char *type;           /* Human-readable type of file. */
436     void *aux;                  /* Owner's auxiliary data. */
437   };
438
439
440 static void make_key (struct fh_lock *, const struct file_handle *,
441                       enum fh_access);
442 static void free_key (struct fh_lock *);
443 static int compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b);
444 static unsigned int hash_fh_lock (const struct fh_lock *lock);
445
446 /* Tries to lock handle H for the given kind of ACCESS and TYPE
447    of file.  Returns a pointer to a struct fh_lock if successful,
448    otherwise a null pointer.
449
450    H's referent type must be one of the bits in MASK.  The caller
451    must verify this ahead of time; we simply assert it here.
452
453    TYPE is the sort of file, e.g. "system file".  Only one type
454    of access is allowed on a given file at a time for reading,
455    and similarly for writing.  If successful, a reference to TYPE
456    is retained, so it should probably be a string literal.
457
458    TYPE should be marked with N_() in the caller: that is, the
459    caller should not translate it with gettext, but fh_lock will
460    do so.
461
462    ACCESS specifies whether the lock is for reading or writing.
463    EXCLUSIVE is true to require exclusive access, false to allow
464    sharing with other accessors.  Exclusive read access precludes
465    other readers, but not writers; exclusive write access
466    precludes other writers, but not readers.  A sharable read or
467    write lock precludes reader or writers, respectively, of a
468    different TYPE.
469
470    A lock may be associated with auxiliary data.  See
471    fh_lock_get_aux and fh_lock_set_aux for more details. */
472 struct fh_lock *
473 fh_lock (struct file_handle *h, enum fh_referent mask UNUSED,
474          const char *type, enum fh_access access, bool exclusive)
475 {
476   struct fh_lock *key = NULL;
477   size_t hash ;
478   struct fh_lock *lock = NULL;
479   bool found_lock = false;
480
481   assert ((fh_get_referent (h) & mask) != 0);
482   assert (access == FH_ACC_READ || access == FH_ACC_WRITE);
483
484   key = xmalloc (sizeof *key);
485
486   make_key (key, h, access);
487
488   key->open_cnt = 1;
489   key->exclusive = exclusive;
490   key->type = type;
491   key->aux = NULL;
492
493   hash = hash_fh_lock (key);
494
495   HMAP_FOR_EACH_WITH_HASH (lock, struct fh_lock, node, hash, &locks)
496     {
497       if ( 0 == compare_fh_locks (lock, key))
498         {
499           found_lock = true;
500           break;
501         }
502     }
503
504   if ( found_lock )
505     {
506       if (strcmp (lock->type, type))
507         {
508           if (access == FH_ACC_READ)
509             msg (SE, _("Can't read from %s as a %s because it is "
510                        "already being read as a %s."),
511                  fh_get_name (h), gettext (type), gettext (lock->type));
512           else
513             msg (SE, _("Can't write to %s as a %s because it is "
514                        "already being written as a %s."),
515                  fh_get_name (h), gettext (type), gettext (lock->type));
516           return NULL;
517         }
518       else if (exclusive || lock->exclusive)
519         {
520           msg (SE, _("Can't re-open %s as a %s."),
521                fh_get_name (h), gettext (type));
522           return NULL;
523         }
524       lock->open_cnt++;
525
526       free_key (key);
527       free (key);
528
529       return lock;
530     }
531
532   hmap_insert (&locks, &key->node, hash);
533   found_lock = false;
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   assert (found_lock);
544
545   return key;
546 }
547
548 /* Releases LOCK that was acquired with fh_lock.
549    Returns true if LOCK is still locked, because other clients
550    also had it locked.
551
552    Returns false if LOCK has now been destroyed.  In this case
553    the caller must ensure that any auxiliary data associated with
554    LOCK is destroyed, to avoid a memory leak.  The caller must
555    obtain a pointer to the auxiliary data, e.g. via
556    fh_lock_get_aux *before* calling fh_unlock (because it yields
557    undefined behavior to call fh_lock_get_aux on a destroyed
558    lock).  */
559 bool
560 fh_unlock (struct fh_lock *lock)
561 {
562   if (lock != NULL)
563     {
564       assert (lock->open_cnt > 0);
565       if (--lock->open_cnt == 0)
566         {
567           hmap_delete (&locks, &lock->node);
568           free_key (lock);
569           free (lock);
570           return false;
571         }
572     }
573   return true;
574 }
575
576 /* Returns auxiliary data for LOCK.
577
578    Auxiliary data is shared by every client that holds LOCK (for
579    an exclusive lock, this is a single client).  To avoid leaks,
580    auxiliary data must be released before LOCK is destroyed. */
581 void *
582 fh_lock_get_aux (const struct fh_lock *lock)
583 {
584   return lock->aux;
585 }
586
587 /* Sets the auxiliary data for LOCK to AUX. */
588 void
589 fh_lock_set_aux (struct fh_lock *lock, void *aux)
590 {
591   lock->aux = aux;
592 }
593
594 /* Returns true if HANDLE is locked for the given type of ACCESS,
595    false otherwise. */
596 bool
597 fh_is_locked (const struct file_handle *handle, enum fh_access access)
598 {
599   struct fh_lock key;
600   const struct fh_lock *k = NULL;
601   bool is_locked = false;
602   size_t hash ;
603
604   make_key (&key, handle, access);
605
606   hash = hash_fh_lock (&key);
607
608
609   HMAP_FOR_EACH_WITH_HASH (k, struct fh_lock, node, hash, &locks)
610     {
611       if ( 0 == compare_fh_locks (k, &key))
612         {
613           is_locked = true;
614           break;
615         }
616     }
617
618   free_key (&key);
619
620   return is_locked;
621 }
622
623 /* Initializes the key fields in LOCK for looking up or inserting
624    handle H for the given kind of ACCESS. */
625 static void
626 make_key (struct fh_lock *lock, const struct file_handle *h,
627           enum fh_access access)
628 {
629   lock->referent = fh_get_referent (h);
630   lock->access = access;
631   if (lock->referent == FH_REF_FILE)
632     lock->u.file = fh_get_identity (h);
633   else if (lock->referent == FH_REF_DATASET)
634     lock->u.unique_id = dataset_seqno (fh_get_dataset (h));
635 }
636
637 /* Frees the key fields in LOCK. */
638 static void
639 free_key (struct fh_lock *lock)
640 {
641   if (lock->referent == FH_REF_FILE)
642     fh_free_identity (lock->u.file);
643 }
644
645 /* Compares the key fields in struct fh_lock objects A and B and
646    returns a strcmp()-type result. */
647 static int
648 compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b)
649 {
650   if (a->referent != b->referent)
651     return a->referent < b->referent ? -1 : 1;
652   else if (a->access != b->access)
653     return a->access < b->access ? -1 : 1;
654   else if (a->referent == FH_REF_FILE)
655     return fh_compare_file_identities (a->u.file, b->u.file);
656   else if (a->referent == FH_REF_DATASET)
657     return (a->u.unique_id < b->u.unique_id ? -1
658             : a->u.unique_id > b->u.unique_id);
659   else
660     return 0;
661 }
662
663 /* Returns a hash value for LOCK. */
664 static unsigned int
665 hash_fh_lock (const struct fh_lock *lock)
666 {
667   unsigned int basis;
668   if (lock->referent == FH_REF_FILE)
669     basis = fh_hash_identity (lock->u.file);
670   else if (lock->referent == FH_REF_DATASET)
671     basis = lock->u.unique_id;
672   else
673     basis = 0;
674   return hash_int ((lock->referent << 3) | lock->access, basis);
675 }
676
677 \f
678
679
680
681
682 /* A file's identity:
683
684    - For a file that exists, this is its device and inode.
685
686    - For a file that does not exist, but which has a directory
687      name that exists, this is the device and inode of the
688      directory, plus the file's base name.
689
690    - For a file that does not exist and has a nonexistent
691      directory, this is the file name.
692
693    Windows doesn't have inode numbers, so we just use the name
694    there. */
695 struct file_identity
696 {
697   unsigned long long device;               /* Device number. */
698   unsigned long long inode;                /* Inode number. */
699   char *name;                 /* File name, where needed, otherwise NULL. */
700 };
701
702 /* Returns a pointer to a dynamically allocated structure whose
703    value can be used to tell whether two files are actually the
704    same file.  The caller is responsible for freeing the structure with
705    fh_free_identity() when finished. */
706 static struct file_identity *
707 fh_get_identity (const struct file_handle *fh)
708 {
709   struct file_identity *identity = xmalloc (sizeof *identity);
710
711   const char *file_name = fh_get_file_name (fh);
712
713 #if !(defined _WIN32 || defined __WIN32__)
714   struct stat s;
715   if (lstat (file_name, &s) == 0)
716     {
717       identity->device = s.st_dev;
718       identity->inode = s.st_ino;
719       identity->name = NULL;
720     }
721   else
722     {
723       char *dir = dir_name (file_name);
724       if (last_component (file_name) != NULL && stat (dir, &s) == 0)
725         {
726           identity->device = s.st_dev;
727           identity->inode = s.st_ino;
728           identity->name = base_name (file_name);
729         }
730       else
731         {
732           identity->device = 0;
733           identity->inode = 0;
734           identity->name = xstrdup (file_name);
735         }
736       free (dir);
737     }
738 #else /* Windows */
739   bool ok = false;
740   HANDLE h = CreateFile (file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
741   if (h != INVALID_HANDLE_VALUE)
742   {
743     BY_HANDLE_FILE_INFORMATION fi;
744     ok = GetFileInformationByHandle (h, &fi);
745     if (ok)
746       {
747         identity->device = fi.dwVolumeSerialNumber;
748         identity->inode = fi.nFileIndexHigh;
749         identity->inode <<= (sizeof fi.nFileIndexLow) * CHAR_BIT;
750         identity->inode |= fi.nFileIndexLow;
751         identity->name = 0;
752       }
753     CloseHandle (h);
754   }
755
756   if (!ok)
757     {
758       identity->device = 0;
759       identity->inode = 0;
760
761       size_t bufsize;
762       size_t pathlen = 255;
763       char *cname = NULL;
764       do
765       {
766         bufsize = pathlen;
767         cname = xrealloc (cname, bufsize);
768         pathlen = GetFullPathName (file_name, bufsize, cname, NULL);
769       }
770       while (pathlen > bufsize);
771       identity->name = xstrdup (cname);
772       free (cname);
773       str_lowercase (identity->name);
774     }
775 #endif /* Windows */
776
777   return identity;
778 }
779
780 /* Frees IDENTITY obtained from fh_get_identity(). */
781 void
782 fh_free_identity (struct file_identity *identity)
783 {
784   if (identity != NULL)
785     {
786       free (identity->name);
787       free (identity);
788     }
789 }
790
791 /* Compares A and B, returning a strcmp()-type result. */
792 int
793 fh_compare_file_identities (const struct file_identity *a,
794                             const struct file_identity *b)
795 {
796   if (a->device != b->device)
797     return a->device < b->device ? -1 : 1;
798   else if (a->inode != b->inode)
799     return a->inode < b->inode ? -1 : 1;
800   else if (a->name != NULL)
801     return b->name != NULL ? strcmp (a->name, b->name) : 1;
802   else
803     return b->name != NULL ? -1 : 0;
804 }
805
806 /* Returns a hash value for IDENTITY. */
807 unsigned int
808 fh_hash_identity (const struct file_identity *identity)
809 {
810   unsigned int hash = hash_int (identity->device, identity->inode);
811   if (identity->name != NULL)
812     hash = hash_string (identity->name, hash);
813   return hash;
814 }