1%%	options
2
3copyright owner	=	Dirk Krause
4copyright year	=	2015-xxxx
5SPDX-License-Identifier:	BSD-3-Clause
6
7%%	header
8
9/**	@file
10	Obtain unique file identifier for path specified as char string.
11	On non-Windows systems the UFI consists of inode number and
12	device number. On Windows systems the volume serial number,
13	higher index number and lower index number are used.
14
15	CRT on Windows: Not used.
16*/
17
18#ifndef	DK4CONF_H_INCLUDED
19#if DK4_BUILDING_DKTOOLS4
20#include "dk4conf.h"
21#else
22#include <dktools-4/dk4conf.h>
23#endif
24#endif
25
26#ifndef DK4UFI_H_INCLUDED
27#if DK4_BUILDING_DKTOOLS4
28#include <libdk4c/dk4ufit.h>
29#else
30#include <dktools-4/dk4ufit.h>
31#endif
32#endif
33
34#ifndef DK4ERROR_H_INCLUDED
35#if DK4_BUILDING_DKTOOLS4
36#include <libdk4base/dk4error.h>
37#else
38#include <dktools-4/dk4error.h>
39#endif
40#endif
41
42#ifdef __cplusplus
43extern "C" {
44#endif
45
46/**	Retrieve unique file identifier.
47	For symbolic links on non-Windows systems, retrieve
48	information about the link target.
49	@param	dptr	Destination buffer.
50	@param	fn	File name.
51	@param	erp	Error report, may be NULL.
52	@return	1 on success, 0 on error.
53
54	Error codes:
55	- DK4_E_INVALID_ARGUMENTS<br>
56	  if dptr or fn is NULL,
57	- DK4_E_SYSTEM<br>
58	  with errno value stored in iDetails1 if the stat() function fails on
59	  non-Windows systems,
60	- DK4_E_CREATE_FILE_FAILED<br>
61	  with GetLastError() result in lDetails1 if the CreateFile() function
62	  fails on Windows,
63	- DK4_E_FILE_INFORMATION_FAILED<br>
64	  with GetLastError() result in lDetails1 if the
65	  GetFileInformationByHandle() function fails on Windows.
66	- DK4_E_NOT_FOUND<br>
67	  if the GetFileAttributes() function fails to retrieve file
68	  attributes on Windows.
69
70
71*/
72int
73dk4ufi_get_c8(dk4_ufi_t *dptr, const char *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() function
91	  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
97	  file attributes on Windows.
98
99*/
100int
101dk4ufi_get_l_c8(dk4_ufi_t *dptr, const char *fn, dk4_er_t *erp);
102
103#ifdef __cplusplus
104}
105#endif
106
107%%	module
108
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#else
118#include <libdk4c/dk4stat8.h>
119#endif
120
121#include <libdk4c/dk4ufi08.h>
122
123#if	DK4_HAVE_ASSERT_H
124#ifndef	ASSERT_H_INCLUDED
125#include <assert.h>
126#define	ASSERT_H_INCLUDED 1
127#endif
128#endif
129
130
131$!trace-include
132
133
134
135int
136dk4ufi_get_c8(dk4_ufi_t *dptr, const char *fn, dk4_er_t *erp)
137{
138#if DK4_ON_WINDOWS
139  BY_HANDLE_FILE_INFORMATION	bhfi;
140  WIN32_FIND_DATAA		ffdata;
141  HANDLE			han;
142  DWORD				dwattr;
143  int				i;
144  int				back = 0;
145#if	DK4_USE_ASSERT
146  assert(NULL != dptr);
147  assert(NULL != fn);
148#endif
149  if ((NULL != dptr) && (NULL != fn)) {
150    dwattr = GetFileAttributesA(fn);
151    if (INVALID_FILE_ATTRIBUTES == dwattr) {
152      han = FindFirstFileA(fn, &ffdata);
153      if (INVALID_HANDLE_VALUE != han) {
154        dwattr = ffdata.dwFileAttributes;
155        FindClose(han);
156      }
157    }
158    if (INVALID_FILE_ATTRIBUTES != dwattr) {
159      if (0 != (FILE_ATTRIBUTE_DIRECTORY & dwattr)) {
160        dwattr |= FILE_FLAG_BACKUP_SEMANTICS;
161      }
162      for (i = 0; ((2 > i) && (0 == back)); i++) {
163        han = CreateFileA(
164          fn,
165	  ((0 == i) ? (0) : (GENERIC_READ)),
166	  (FILE_SHARE_READ | FILE_SHARE_WRITE),
167	  NULL,
168	  OPEN_EXISTING,
169	  dwattr,
170	  NULL
171        );
172        if (INVALID_HANDLE_VALUE != han) {
173          if (GetFileInformationByHandle(han, &bhfi)) {
174	    back = 1;
175	    dptr->ser = bhfi.dwVolumeSerialNumber;
176	    dptr->inh = bhfi.nFileIndexHigh;
177	    dptr->inl = bhfi.nFileIndexLow;
178	  } else {
179	    if (1 == i) {
180	      /* ERROR: Failed */
181	      dk4error_set_ldetails(
182	        erp, DK4_E_FILE_INFORMATION_FAILED,
183	        (long)((unsigned long)GetLastError())
184	      );
185	    }
186	  }
187          CloseHandle(han);
188        } else {
189          if (1 == i) {
190	    /* ERROR: Failed */
191	    dk4error_set_ldetails(
192	      erp, DK4_E_CREATE_FILE_FAILED,
193	      (long)((unsigned long)GetLastError())
194	    );
195	  }
196        }
197      }
198    }
199
200  } else {
201    dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
202  }
203  return back;
204#else
205  dk4_stat_t	 stb;
206  int		 back = 0;
207  $? "+ dk4ufi_get_c8 \"%!8s\"", TR_8STR(fn)
208#if	DK4_USE_ASSERT
209  assert(NULL != dptr);
210  assert(NULL != fn);
211#endif
212  if ((NULL != dptr) && (NULL != fn)) {
213    if (0 != dk4stat_c8(&stb, fn, erp)) {
214      dptr->dev = stb.st_dev;	$? ". dev = %lu", (unsigned long)(stb.st_dev)
215      dptr->ino = stb.st_ino;	$? ". ino = %lu", (unsigned long)(stb.st_ino)
216      back = 1;
217    }
218  } else {
219    dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
220  }
221  $? "- dk4ufi_get_c8 %d", back
222  return back;
223#endif
224}
225
226
227
228int
229dk4ufi_get_l_c8(dk4_ufi_t *dptr, const char *fn, dk4_er_t *erp)
230{
231#if DK4_ON_WINDOWS
232  BY_HANDLE_FILE_INFORMATION	bhfi;
233  WIN32_FIND_DATAA		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 = GetFileAttributesA(fn);
244    if (INVALID_FILE_ATTRIBUTES == dwattr) {
245      han = FindFirstFileA(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 = CreateFileA(
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: Failed */
275	      dk4error_set_ldetails(
276	        erp, DK4_E_FILE_INFORMATION_FAILED,
277	        (long)((unsigned long)GetLastError())
278	      );
279	    }
280	  }
281          CloseHandle(han);
282        } else {
283          if (1 == i) {
284	    /* ERROR: Failed */
285	    dk4error_set_ldetails(
286	      erp, DK4_E_CREATE_FILE_FAILED,
287	      (long)((unsigned long)GetLastError())
288	    );
289	  }
290        }
291      }
292    }
293  } else {
294    dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
295  }
296  return back;
297#else
298  dk4_stat_t	 stb;
299  int		 back = 0;
300  $? "+ dk4ufi_get_l_c8 \"%!8s\"", TR_8STR(fn)
301#if	DK4_USE_ASSERT
302  assert(NULL != dptr);
303  assert(NULL != fn);
304#endif
305  if ((NULL != dptr) && (NULL != fn)) {
306    if (0 != dk4stat_l_c8(&stb, fn, erp)) {
307      dptr->dev = stb.st_dev;	$? ". dev = %lu", (unsigned long)(stb.st_dev)
308      dptr->ino = stb.st_ino;	$? ". dev = %lu", (unsigned long)(stb.st_ino)
309      back = 1;
310    }
311  } else {
312    dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
313  }
314  $? "- dk4ufi_get_l_c8 %d", back
315  return back;
316#endif
317}
318
319
320