1%%	options
2
3copyright owner	=	Dirk Krause
4copyright year	=	2015-xxxx
5SPDX-License-Identifier:	BSD-3-Clause
6
7
8%%	header
9
10/**	@file
11	Obtain unique file identifier for path specified as wchar_t string.
12	On non-Windows systems the UFI consists of inode number and
13	device number. On Windows systems the volume serial number,
14	higher index number and lower index number are used.
15
16	CRT on Windows: Not used.
17*/
18
19#ifndef	DK4CONF_H_INCLUDED
20#if DK4_BUILDING_DKTOOLS4
21#include "dk4conf.h"
22#else
23#include <dktools-4/dk4conf.h>
24#endif
25#endif
26
27#ifndef DK4UFI_H_INCLUDED
28#if DK4_BUILDING_DKTOOLS4
29#include <libdk4c/dk4ufit.h>
30#else
31#include <dktools-4/dk4ufit.h>
32#endif
33#endif
34
35#ifndef DK4ERROR_H_INCLUDED
36#if DK4_BUILDING_DKTOOLS4
37#include <libdk4base/dk4error.h>
38#else
39#include <dktools-4/dk4error.h>
40#endif
41#endif
42
43#ifdef __cplusplus
44extern "C" {
45#endif
46
47/**	Retrieve unique file identifier.
48	For symbolic links on non-Windows systems, retrieve
49	information about the link target.
50	@param	dptr	Destination buffer.
51	@param	fn	File name.
52	@param	erp	Error report, may be NULL.
53	@return	1 on success, 0 on error.
54
55	Error codes:
56	- DK4_E_INVALID_ARGUMENTS<br>
57	  if dptr or fn is NULL,
58	- DK4_E_SYSTEM<br>
59	  with errno value stored in iDetails1 if the stat() function fails
60	  on non-Windows systems,
61	- DK4_E_CREATE_FILE_FAILED<br>
62	  with GetLastError() result in lDetails1 if the CreateFile()
63	  function fails on Windows,
64	- DK4_E_FILE_INFORMATION_FAILED<br>
65	  with GetLastError() result in lDetails1 if the
66	  GetFileInformationByHandle() function fails on Windows.
67	- DK4_E_NOT_FOUND<br>
68	  if the GetFileAttributes() function fails to retrieve file
69	  attributes on Windows.
70
71*/
72int
73dk4ufi_get_wc(dk4_ufi_t *dptr, const wchar_t *fn, dk4_er_t *erp);
74
75/**	Retrieve unique file identifier.
76	For symbolic links on non-Windows systems, retrieve
77	information about the link.
78	@param	dptr	Destination buffer.
79	@param	fn	File name.
80	@param	erp	Error report, may be NULL.
81	@return	1 on success, 0 on error.
82
83	Error codes:
84	- DK4_E_INVALID_ARGUMENTS<br>
85	  if dptr or fn is NULL,
86	- DK4_E_SYSTEM<br>
87	  with errno value stored in iDetails1 if the lstat() function fails
88	  on non-Windows systems,
89	- DK4_E_CREATE_FILE_FAILED<br>
90	  with GetLastError() result in lDetails1 if the CreateFile()
91	  function fails on Windows,
92	- DK4_E_FILE_INFORMATION_FAILED<br>
93	  with GetLastError() result in lDetails1 if the
94	  GetFileInformationByHandle() function fails on Windows.
95	- DK4_E_NOT_FOUND<br>
96	  if the GetFileAttributes() function fails to retrieve file
97	  attributes on Windows.
98*/
99int
100dk4ufi_get_l_wc(dk4_ufi_t *dptr, const wchar_t *fn, dk4_er_t *erp);
101
102#ifdef __cplusplus
103}
104#endif
105
106
107
108%%	module
109
110#include "dk4conf.h"
111
112#if DK4_ON_WINDOWS
113#ifndef WINDOWS_H_INCLUDED
114#include <windows.h>
115#define	WINDOWS_H_INCLUDED 1
116#endif
117#endif
118
119#if	DK4_HAVE_ASSERT_H
120#ifndef	ASSERT_H_INCLUDED
121#include <assert.h>
122#define	ASSERT_H_INCLUDED 1
123#endif
124#endif
125
126#include <libdk4c/dk4ufiwc.h>
127#include <libdk4base/dk4unused.h>
128
129
130
131int
132dk4ufi_get_wc(
133#if DK4_ON_WINDOWS
134  dk4_ufi_t	*dptr,
135  const wchar_t	*fn,
136#else
137  dk4_ufi_t	* DK4_ARG_UNUSED(dptr),
138  const wchar_t	* DK4_ARG_UNUSED(fn),
139#endif
140  dk4_er_t	*erp
141)
142{
143#if DK4_ON_WINDOWS
144  BY_HANDLE_FILE_INFORMATION	bhfi;
145  WIN32_FIND_DATAW		ffdata;
146  HANDLE			han;
147  DWORD				dwattr;
148  int				i;
149  int				back = 0;
150#if	DK4_USE_ASSERT
151  assert(NULL != dptr);
152  assert(NULL != fn);
153#endif
154  if ((NULL != dptr) && (NULL != fn)) {
155    dwattr = GetFileAttributesW(fn);
156    if (INVALID_FILE_ATTRIBUTES == dwattr) {
157      han = FindFirstFileW(fn, &ffdata);
158      if (INVALID_HANDLE_VALUE != han) {
159        dwattr = ffdata.dwFileAttributes;
160        FindClose(han);
161      }
162    }
163    if (INVALID_FILE_ATTRIBUTES != dwattr) {
164      if (0 != (FILE_ATTRIBUTE_DIRECTORY & dwattr)) {
165        dwattr |= FILE_FLAG_BACKUP_SEMANTICS;
166      }
167      for (i = 0; ((2 > i) && (0 == back)); i++) {
168        han = CreateFileW(
169          fn,
170	  ((0 == i) ? (0) : (GENERIC_READ)),
171	  (FILE_SHARE_READ | FILE_SHARE_WRITE),
172	  NULL,
173	  OPEN_EXISTING,
174	  dwattr,
175	  NULL
176        );
177        if (INVALID_HANDLE_VALUE != han) {
178          if (GetFileInformationByHandle(han, &bhfi)) {
179	    back = 1;
180	    dptr->ser = bhfi.dwVolumeSerialNumber;
181	    dptr->inh = bhfi.nFileIndexHigh;
182	    dptr->inl = bhfi.nFileIndexLow;
183	  } else {
184	    if (1 == i) {
185	      /* ERROR */
186	      dk4error_set_ldetails(
187	        erp, DK4_E_FILE_INFORMATION_FAILED,
188	        (long)((unsigned long)GetLastError())
189	      );
190	    }
191	  }
192        } else {
193          if (1 == i) {
194	    /* ERROR */
195	    dk4error_set_ldetails(
196	      erp, DK4_E_CREATE_FILE_FAILED,
197	      (long)((unsigned long)GetLastError())
198	    );
199	  }
200        }
201      }
202    } else {
203      dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND);
204    }
205  } else {
206    dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
207  }
208  return back;
209#else
210  DK4_UNUSED_ARG(dptr)
211  DK4_UNUSED_ARG(fn)
212  dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
213  return 0;
214#endif
215}
216
217
218
219int
220dk4ufi_get_l_wc(
221#if DK4_ON_WINDOWS
222  dk4_ufi_t	*dptr,
223  const wchar_t	*fn,
224#else
225  dk4_ufi_t	* DK4_ARG_UNUSED(dptr),
226  const wchar_t	* DK4_ARG_UNUSED(fn),
227#endif
228  dk4_er_t	*erp
229)
230{
231#if DK4_ON_WINDOWS
232  BY_HANDLE_FILE_INFORMATION	bhfi;
233  WIN32_FIND_DATAW		ffdata;
234  HANDLE			han;
235  DWORD				dwattr;
236  int				i;
237  int				back = 0;
238#if	DK4_USE_ASSERT
239  assert(NULL != dptr);
240  assert(NULL != fn);
241#endif
242  if ((NULL != dptr) && (NULL != fn)) {
243    dwattr = GetFileAttributesW(fn);
244    if (INVALID_FILE_ATTRIBUTES == dwattr) {
245      han = FindFirstFileW(fn, &ffdata);
246      if (INVALID_HANDLE_VALUE != han) {
247        dwattr = ffdata.dwFileAttributes;
248        FindClose(han);
249      }
250    }
251    if (INVALID_FILE_ATTRIBUTES != dwattr) {
252      if (0 != (FILE_ATTRIBUTE_DIRECTORY & dwattr)) {
253        dwattr |= FILE_FLAG_BACKUP_SEMANTICS;
254      }
255      dwattr |= FILE_FLAG_OPEN_REPARSE_POINT;
256      for (i = 0; ((2 > i) && (0 == back)); i++) {
257        han = CreateFileW(
258          fn,
259	  ((0 == i) ? (0) : (GENERIC_READ)),
260	  (FILE_SHARE_READ | FILE_SHARE_WRITE),
261	  NULL,
262	  OPEN_EXISTING,
263	  dwattr,
264	  NULL
265        );
266        if (INVALID_HANDLE_VALUE != han) {
267          if (GetFileInformationByHandle(han, &bhfi)) {
268	    back = 1;
269	    dptr->ser = bhfi.dwVolumeSerialNumber;
270	    dptr->inh = bhfi.nFileIndexHigh;
271	    dptr->inl = bhfi.nFileIndexLow;
272	  } else {
273	    if (1 == i) {
274	      /* ERROR */
275	      dk4error_set_ldetails(
276	        erp, DK4_E_FILE_INFORMATION_FAILED,
277	        (long)((unsigned long)GetLastError())
278	      );
279	    }
280	  }
281        } else {
282          if (1 == i) {
283	    /* ERROR */
284	    dk4error_set_ldetails(
285	      erp, DK4_E_CREATE_FILE_FAILED,
286	      (long)((unsigned long)GetLastError())
287	    );
288	  }
289        }
290      }
291    } else {
292      dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND);
293    }
294  } else {
295    dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
296  }
297  return back;
298#else
299  DK4_UNUSED_ARG(dptr)
300  DK4_UNUSED_ARG(fn)
301  dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
302  return 0;
303#endif
304}
305
306