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	Functions for file information.
12*/
13
14#ifndef	DK4CONF_H_INCLUDED
15#if DK4_BUILDING_DKTOOLS4
16#include "dk4conf.h"
17#else
18#include <dktools-4/dk4conf.h>
19#endif
20#endif
21
22#ifndef DK4FILEIT_H_INCLUDED
23#if DK4_BUILDING_DKTOOLS4
24#include <libdk4c/dk4fileit.h>
25#else
26#include <dktools-4/dk4fileit.h>
27#endif
28#endif
29
30#ifndef DK4UFI_H_INCLUDED
31#if DK4_BUILDING_DKTOOLS4
32#include <libdk4c/dk4ufi.h>
33#else
34#include <dktools-4/dk4ufi.h>
35#endif
36#endif
37
38#ifndef DK4ERROR_H_INCLUDED
39#if DK4_BUILDING_DKTOOLS4
40#include <libdk4base/dk4error.h>
41#else
42#include <dktools-4/dk4error.h>
43#endif
44#endif
45
46#ifdef __cplusplus
47extern "C" {
48#endif
49
50/**	Initialize a file information structure.
51	@param	dptr	File information structure to initialize.
52*/
53void
54dk4fileinfo_init(dk4_file_info_t *dptr);
55
56/**	Retrieve full information for a path name.
57	For symbolic links attempt to retrieve information both
58	about the link and about the link target.
59
60	CRT on Windows: Not used.
61	@param	dptr	Pointer to result structure.
62	@param	fn	File path name.
63	@param	erp	Error report, may be NULL.
64	@return	1 if information is found, 0 otherwise.
65	If information about the link is found and no information about
66	the target, the function returns 1 as we can recognize the
67	directory item as a dangling link (link with non-existing target).
68
69	Error codes:
70	- DK4_E_INVALID_ARGUMENTS<br>
71	  if dptr or fn is NULL,
72	- DK4_E_SYSTEM<br>
73	  with errno value stored in iDetails1 if the stat() function
74	  fails on non-Windows systems.
75	- DK4_E_SYSTEM<br>
76	  with GetLastError() value stored in lDetails1 if the
77	  GetFileAttributes() function failed,
78	- DK4_E_CREATE_FILE_FAILED<br>
79	  with GetLastError() value stored in lDetails1 if the
80	  CreateFile() function failed on Windows systems,
81	- DK4_E_FILE_INFORMATION_FAILED<br>
82	  with GetLastError() value stored in lDetails1 if the
83	  GetFileInformationByHandle() function failed on Windows systems,
84	- DK4_E_FINDFIRSTFILE_FAILED<br>
85	  with GetLastError() value stored in lDetails1 if the
86	  FindFirstFile() function failed on Windows systems.
87*/
88int
89dk4fileinfo_c8(dk4_file_info_t *dptr, const char *fn, dk4_er_t *erp);
90
91/**	Retrieve full information for a path name.
92	For symbolic links attempt to retrieve information both
93	about the link and about the link target.
94
95	CRT on Windows: Not used.
96	@param	dptr	Pointer to result structure.
97	@param	fn	File path name.
98	@param	erp	Error report, may be NULL.
99	@return	1 if information is found, 0 otherwise.
100	If information about the link is found and no information about
101	the target, the function returns 1 as we can recognize the
102	directory item as a dangling link (link with non-existing target).
103
104	Error codes:
105	- DK4_E_INVALID_ARGUMENTS<br>
106	  if dptr or fn is NULL,
107	- DK4_E_SYSTEM<br>
108	  with errno value stored in iDetails1 if the stat() function
109	  fails on non-Windows systems.
110	- DK4_E_SYSTEM<br>
111	  with GetLastError() value stored in lDetails1 if the
112	  GetFileAttributes() function failed,
113	- DK4_E_CREATE_FILE_FAILED<br>
114	  with GetLastError() value stored in lDetails1 if the
115	  CreateFile() function failed on Windows systems,
116	- DK4_E_FILE_INFORMATION_FAILED<br>
117	  with GetLastError() value stored in lDetails1 if the
118	  GetFileInformationByHandle() function failed on Windows systems,
119	- DK4_E_FINDFIRSTFILE_FAILED<br>
120	  with GetLastError() value stored in lDetails1 if the
121	  FindFirstFile() function failed on Windows systems.
122*/
123int
124dk4fileinfo_wc(dk4_file_info_t *dptr, const wchar_t *fn, dk4_er_t *erp);
125
126/**	Retrieve full information for a path name.
127	For symbolic links attempt to retrieve information both
128	about the link and about the link target.
129
130	CRT on Windows: Not used.
131	@param	dptr	Pointer to result structure.
132	@param	fn	File path name.
133	@param	erp	Error report, may be NULL.
134	@return	1 if information is found, 0 otherwise.
135	If information about the link is found and no information about
136	the target, the function returns 1 as we can recognize the
137	directory item as a dangling link (link with non-existing target).
138
139	Error codes:
140	- DK4_E_INVALID_ARGUMENTS<br>
141	  if dptr or fn is NULL,
142	- DK4_E_SYSTEM<br>
143	  with errno value stored in iDetails1 if the stat() function
144	  fails on non-Windows systems.
145	- DK4_E_SYSTEM<br>
146	  with GetLastError() value stored in lDetails1 if the
147	  GetFileAttributes() function failed,
148	- DK4_E_CREATE_FILE_FAILED<br>
149	  with GetLastError() value stored in lDetails1 if the
150	  CreateFile() function failed on Windows systems,
151	- DK4_E_FILE_INFORMATION_FAILED<br>
152	  with GetLastError() value stored in lDetails1 if the
153	  GetFileInformationByHandle() function failed on Windows systems,
154	- DK4_E_FINDFIRSTFILE_FAILED<br>
155	  with GetLastError() value stored in lDetails1 if the
156	  FindFirstFile() function failed on Windows systems.
157*/
158int
159dk4fileinfo(dk4_file_info_t *dptr, const dkChar *fn, dk4_er_t *erp);
160
161/**	Retrieve timestamp from file information structure.
162	@param	dptr	Destination buffer pointer.
163	@param	szdptr	Destination buffer size.
164	@param	fi	File information structure.
165	@param	chfile	For symolic links, choose information source:
166			DK4_FILE_INFO_CONTENTS_DATA_LINK for the link
167			itself,
168			DK4_FILE_INFO_CONTENTS_DATA_TARGET for the link target.
169	@param	chtime	Choose timestamp:
170			DK4_FILE_INFO_TIME_CREATE for creation time,
171			DK4_FILE_INFO_TIME_MODIFY for modification time,
172			DK4_FILE_INFO_TIME_ACCESS for last access time.
173	@param	erp	Error report, may be NULL.
174	@return	1 on success, 0 on error.
175
176	Error codes:
177	- DK4_E_INVALID_ARGUMENTS<br>
178	  if dptr or fi is NULL or szdptr is 0,
179	- DK4_E_NOT_FOUND<br>
180	  if the required information is not found in the file information
181	  structure.
182*/
183int
184dk4fileinfo_timestamp_c8(
185  char			*dptr,
186  size_t		 szdptr,
187  const dk4_file_info_t	*fi,
188  int			 chfile,
189  int			 chtime,
190  dk4_er_t		*erp
191);
192
193/**	Retrieve timestamp from file information structure.
194	@param	dptr	Destination buffer pointer.
195	@param	szdptr	Destination buffer size (number of wchar_t).
196	@param	fi	File information structure.
197	@param	chfile	For symolic links, choose information source:
198			DK4_FILE_INFO_CONTENTS_DATA_LINK for the link
199			itself,
200			DK4_FILE_INFO_CONTENTS_DATA_TARGET for the link target.
201	@param	chtime	Choose timestamp:
202			DK4_FILE_INFO_TIME_CREATE for creation time,
203			DK4_FILE_INFO_TIME_MODIFY for modification time,
204			DK4_FILE_INFO_TIME_ACCESS for last access time.
205	@param	erp	Error report, may be NULL.
206	@return	1 on success, 0 on error.
207
208	Error codes:
209	- DK4_E_INVALID_ARGUMENTS<br>
210	  if dptr or fi is NULL or szdptr is 0,
211	- DK4_E_NOT_FOUND<br>
212	  if the required information is not found in the file information
213	  structure.
214*/
215int
216dk4fileinfo_timestamp_wc(
217  wchar_t		*dptr,
218  size_t		 szdptr,
219  const dk4_file_info_t	*fi,
220  int			 chfile,
221  int			 chtime,
222  dk4_er_t		*erp
223);
224
225/**	Retrieve timestamp from file information structure.
226	@param	dptr	Destination buffer pointer.
227	@param	szdptr	Destination buffer size (number of dkChar).
228	@param	fi	File information structure.
229	@param	chfile	For symolic links, choose information source:
230			DK4_FILE_INFO_CONTENTS_DATA_LINK for the link
231			itself,
232			DK4_FILE_INFO_CONTENTS_DATA_TARGET for the link target.
233	@param	chtime	Choose timestamp:
234			DK4_FILE_INFO_TIME_CREATE for creation time,
235			DK4_FILE_INFO_TIME_MODIFY for modification time,
236			DK4_FILE_INFO_TIME_ACCESS for last access time.
237	@param	erp	Error report, may be NULL.
238	@return	1 on success, 0 on error.
239
240	Error codes:
241	- DK4_E_INVALID_ARGUMENTS<br>
242	  if dptr or fi is NULL or szdptr is 0,
243	- DK4_E_NOT_FOUND<br>
244	  if the required information is not found in the file information
245	  structure.
246*/
247int
248dk4fileinfo_timestamp(
249  dkChar		*dptr,
250  size_t		 szdptr,
251  const dk4_file_info_t	*fi,
252  int			 chfile,
253  int			 chtime,
254  dk4_er_t		*erp
255);
256
257/**	Retrieve file type and attributes (file attributes on Windows,
258	permissions on other systems).
259	@param	dptr	Destination buffer address.
260	@param	szdptr	Destination buffer size.
261	@param	fi	File information structure.
262	@param	erp	Error report, may be NULL.
263	@return	1 on success, 0 on error.
264
265	Error codes:
266	- DK4_E_INVALID_ARGUMENTS<br>
267	  if dptr or fi is NULL or szdptr is 0,
268	- DK4_E_NOT_FOUND<br>
269	  if the required information is not available in the file information.
270*/
271int
272dk4fileinfo_type_attributes_c8(
273  char			*dptr,
274  size_t		 szdptr,
275  dk4_file_info_t const	*fi,
276  dk4_er_t		*erp
277);
278
279/**	Retrieve file type and attributes (file attributes on Windows,
280	permissions on other systems).
281	@param	dptr	Destination buffer address.
282	@param	szdptr	Destination buffer size (number of wchar_t).
283	@param	fi	File information structure.
284	@param	erp	Error report, may be NULL.
285	@return	1 on success, 0 on error.
286
287	Error codes:
288	- DK4_E_INVALID_ARGUMENTS<br>
289	  if dptr or fi is NULL or szdptr is 0,
290	- DK4_E_NOT_FOUND<br>
291	  if the required information is not available in the file information.
292*/
293int
294dk4fileinfo_type_attributes_wc(
295  wchar_t		*dptr,
296  size_t		 szdptr,
297  dk4_file_info_t const	*fi,
298  dk4_er_t		*erp
299);
300
301/**	Retrieve file type and attributes (file attributes on Windows,
302	permissions on other systems).
303	@param	dptr	Destination buffer address.
304	@param	szdptr	Destination buffer size (number of dkChar).
305	@param	fi	File information structure.
306	@param	erp	Error report, may be NULL.
307	@return	1 on success, 0 on error.
308
309	Error codes:
310	- DK4_E_INVALID_ARGUMENTS<br>
311	  if dptr or fi is NULL or szdptr is 0,
312	- DK4_E_NOT_FOUND<br>
313	  if the required information is not available in the file information.
314*/
315int
316dk4fileinfo_type_attributes(
317  dkChar		*dptr,
318  size_t		 szdptr,
319  dk4_file_info_t const	*fi,
320  dk4_er_t		*erp
321);
322
323/**	Retrieve unique file identifier from file information structure.
324	@param	dptr	Pointer to destination variable.
325	@param	src	File information structure to retrieve information from.
326	@param	ch	For symbolic links choose between information
327			for link itself (DK4_FILE_INFO_CONTENTS_DATA_LINK)
328			or link target (DK4_FILE_INFO_CONTENTS_DATA_TARGET).
329	@param	erp	Error report, may be NULL.
330	@return	1 on success, 0 on error.
331
332	Error codes:
333	- DK4_E_INVALID_ARGUMENTS<br>
334	  if dptr or src is NULL,
335	- DK4_E_NOT_FOUND<br>
336	  if the information is not present in the file information structure.
337*/
338int
339dk4fileinfo_ufi(
340  dk4_ufi_t *dptr, const dk4_file_info_t *src, int ch, dk4_er_t *erp
341);
342
343/**	Check whether the file information structure represents a
344	symbolic link.
345	@param	dptr	File information structure to check.
346	@return	1 for symbolic links, 0 otherwise.
347*/
348int
349dk4fileinfo_is_symlink(const dk4_file_info_t *dptr);
350
351/**	Retrieve file size.
352	@param	dptr	Pointer to result variable.
353	@param	fi	File information structure.
354	@param	ch	Choose information source for symbolic links:
355			DK4_FILE_INFO_CONTENTS_DATA_LINK for the size
356			of the link itself,
357			DK4_FILE_INFO_CONTENTS_DATA_TARGET for the size
358			of the link target.
359	@param	erp	Error report, may be NULL.
360	@return	1 on success, 0 on error.
361
362	Error codes:
363	- DK4_E_INVALID_ARGUMENTS<br>
364	  if dptr or fi is NULL,
365	- DK4_E_NOT_FOUND<br>
366	  if the required information is not available in the file
367	  information structure,
368	- DK4_E_MATH_OVERFLOW<br>
369	  if the size calculation results in a numeric overflow.
370*/
371int
372dk4fileinfo_size(
373  dk4_um_t		*dptr,
374  const dk4_file_info_t *fi,
375  int			 ch,
376  dk4_er_t		*erp
377);
378
379/**	Check whether the file exists and is a regular file.
380	For a symbolic link, the target must exist and be a regular file.
381	@param	fi	File information already obtained for the file.
382	@param	erp	Error report, may be NULL.
383	@return	1 if the file exists and is a regular file.
384
385	Error codes:
386	- DK4_E_INVALID_ARGUMENTS<br>
387	  if fi is NULL.
388*/
389int
390dk4fileinfo_exists_and_is_regular(const dk4_file_info_t *fi, dk4_er_t *erp);
391
392#ifdef __cplusplus
393}
394#endif
395
396
397
398%%	module
399
400#include "dk4conf.h"
401#include <libdk4c/dk4filei.h>
402
403#ifndef DK4MEM_H_INCLUDED
404#include <libdk4base/dk4mem.h>
405#endif
406
407#ifndef DK4MAADU_H_INCLUDED
408#include <libdk4ma/dk4maadu.h>
409#endif
410
411
412#include <libdk4base/dk4unused.h>
413
414#if DK4_HAVE_ASSERT_H
415#ifndef	ASSERT_H_INCLUDED
416#include <assert.h>
417#define	ASSERT_H_INCLUDED 1
418#endif
419#endif
420
421
422
423$!trace-include
424
425
426
427void
428dk4fileinfo_init(dk4_file_info_t *dptr)
429{
430#if	DK4_USE_ASSERT
431  assert(NULL != dptr);
432#endif
433  if (NULL != dptr) {
434    DK4_MEMRES(dptr, sizeof(dk4_file_info_t));
435    dptr->contents = 0;
436  }
437}
438
439
440
441int
442dk4fileinfo_is_symlink(const dk4_file_info_t *dptr)
443{
444  int		 back = 0;
445#if	DK4_USE_ASSERT
446  assert(NULL != dptr);
447#endif
448  if (NULL != dptr) {
449    if (0 != (DK4_FILE_INFO_CONTENTS_DATA_LINK & (dptr->contents))) {
450#if DK4_ON_WINDOWS
451      if (0 != (FILE_ATTRIBUTE_REPARSE_POINT & (dptr->fattr))) {
452        if (IO_REPARSE_TAG_MOUNT_POINT == dptr->rppnt) {
453	  back = 1;
454	}
455	if (IO_REPARSE_TAG_SYMLINK == dptr->rppnt) {
456	  back = 1;
457	}
458      }
459#else
460#if defined(S_IFMT) && defined (S_IFLNK)
461      if (S_IFLNK == (S_IFMT & ((dptr->lstb).st_mode))) {
462        back = 1;
463      }
464#endif
465#endif
466    }
467  }
468  return back;
469}
470
471
472
473#if DK4_ON_WINDOWS
474static
475int
476dk4fileinfo_copy_size(
477  dk4_um_t				*dptr,
478  const BY_HANDLE_FILE_INFORMATION	*bhfi,
479  dk4_er_t				*erp
480)
481{
482  dk4_er_t	 er;
483  dk4_um_t	 val;
484  int	 	 back = 0;
485  $? "+ dk4fileinfo_copy_size"
486#if	DK4_USE_ASSERT
487  assert(NULL != dptr);
488  assert(NULL != bhfi);
489#endif
490  dk4error_init(&er);
491  $? ". high %lu", (0xFFFFFFFFUL & ((unsigned long)(bhfi->nFileSizeHigh)))
492  $? ". low  %lu", (0xFFFFFFFFUL & ((unsigned long)(bhfi->nFileSizeLow)))
493  if ((DWORD)0UL != bhfi->nFileSizeHigh) {
494    val = dk4ma_um_add(
495      dk4ma_um_mul(
496        dk4ma_um_add(
497          (dk4_um_t)0xFFFFFFFFUL,
498	  (dk4_um_t)1UL,
499	  &er
500        ),
501        (dk4_um_t)(bhfi->nFileSizeHigh),
502        &er
503      ),
504      (dk4_um_t)(bhfi->nFileSizeLow),
505      &er
506    );
507  } else {
508    val = (dk4_um_t)(bhfi->nFileSizeLow);
509  }
510  if (DK4_E_NONE == er.ec) {	$? ". no overflow"
511    back = 1;
512    *dptr = val;
513  } else {			$? "! overflow"
514    dk4error_copy(erp, &er);
515  }
516  $? "- dk4fileinfo_copy_size %d", back
517  return back;
518}
519#else
520static
521int
522dk4fileinfo_copy_size(
523  dk4_um_t				*dptr,
524  const dk4_stat_t			*stb,
525  dk4_er_t				* DK4_ARG_UNUSED(erp)
526)
527{
528  DK4_UNUSED_ARG(erp)
529#if	DK4_USE_ASSERT
530  assert(NULL != dptr);
531  assert(NULL != stb);
532#endif
533  *dptr = (dk4_um_t)(stb->st_size);
534  return 1;
535}
536#endif
537
538
539int
540dk4fileinfo_size(
541  dk4_um_t		*dptr,
542  const dk4_file_info_t *fi,
543  int			 ch,
544  dk4_er_t		*erp
545)
546{
547  dk4_er_t	 er;
548  int		 back = 0;
549  $? "+ dk4fileinfo_size"
550#if	DK4_USE_ASSERT
551  assert(NULL != dptr);
552  assert(NULL != fi);
553#endif
554  if ((NULL != dptr) && (NULL != fi)) {		$? ". args ok"
555    dk4error_init(&er);
556    switch (ch) {
557      case DK4_FILE_INFO_CONTENTS_DATA_LINK: {
558	$? ". link"
559        if (0 != ((fi->contents) & DK4_FILE_INFO_CONTENTS_DATA_LINK)) {
560#if DK4_ON_WINDOWS
561	  $? ". windows"
562	  back = dk4fileinfo_copy_size(dptr, &(fi->linfo), &er);
563#else
564	  $? ". non-Windows"
565	  back = dk4fileinfo_copy_size(dptr, &(fi->lstb), &er);
566#endif
567	} else {	$? "! no data stored"
568	  dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND);
569	}
570      } break;
571      default: {
572	$? ". link target"
573        if (0 != ((fi->contents) & DK4_FILE_INFO_CONTENTS_DATA_TARGET)) {
574#if DK4_ON_WINDOWS
575	  $? ". Windows"
576	  back = dk4fileinfo_copy_size(dptr, &(fi->tinfo), &er);
577#else
578	  $? ". non-Windows"
579	  back = dk4fileinfo_copy_size(dptr, &(fi->tstb), &er);
580#endif
581	} else {		$? "! no data stored"
582	  dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND);
583	}
584      } break;
585    }
586    if (0 != back) {
587      dk4error_copy(erp, &er);
588    }
589  } else {
590    dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
591  } $? "- dk4fileinfo_size %d", back
592  return back;
593}
594
595
596
597int
598dk4fileinfo_exists_and_is_regular(const dk4_file_info_t *fi, dk4_er_t *erp)
599{
600  int		 back = 0;
601#if	DK4_USE_ASSERT
602  assert(NULL != fi);
603#endif
604  if (NULL != fi) {
605#if DK4_ON_WINDOWS
606    if (0 != (DK4_FILE_INFO_CONTENTS_DATA_LINK & (fi->contents))) {
607      if ((DWORD)0UL == (FILE_ATTRIBUTE_DIRECTORY & fi->fattr)) {
608        if ((DWORD)0UL == (FILE_ATTRIBUTE_DEVICE & fi->fattr)) {
609	  back = 1;
610	}
611      }
612    }
613#else
614    if (0 != (DK4_FILE_INFO_CONTENTS_DATA_TARGET & (fi->contents))) {
615      if (S_IFREG == (S_IFMT & ((fi->tstb).st_mode))) {
616        back = 1;
617      }
618    }
619#endif
620  } else {
621    dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
622  }
623  return back;
624}
625
626