Line data Source code
1 : #include "testitall.h"
2 :
3 : /*
4 : * Modification bits
5 : *
6 : */
7 : typedef enum
8 : {
9 : IDENTICAL = 0x00, // 00000
10 : NOT_EQUAL = 0x01, // 00001
11 : SIZE_CHANGED = 0x02, // 00010
12 : STATUS_CHANGED_TIME = 0x04, // 00100
13 : MODIFICATION_TIME_CHANGED = 0x08, // 01000
14 : COMPARE_FAILED = 0x10 // 10000
15 :
16 : } Changed;
17 :
18 : /**
19 : * @brief Compares basic file metadata fields (size, mtime, ctime).
20 : *
21 : * @param source First stat structure
22 : * @param destination Second stat structure
23 : *
24 : * @return Bitmask with IDENTICAL (0) when equal or a combination of:
25 : * - SIZE_CHANGED
26 : * - MODIFICATION_TIME_CHANGED
27 : * - STATUS_CHANGED_TIME (uses ctime/status-change time)
28 : * Returns FAILURE on invalid parameters.
29 : */
30 8 : static int compare_file_metadata_equivalence(
31 : const struct stat *source,
32 : const struct stat *destination)
33 : {
34 : /* Validate input parameters */
35 8 : if(NULL == source || NULL == destination)
36 : {
37 0 : return(COMPARE_FAILED);
38 : }
39 :
40 8 : int changes = IDENTICAL;
41 :
42 : /* Size of file, in bytes. */
43 8 : if(source->st_size != destination->st_size)
44 : {
45 0 : changes |= SIZE_CHANGED;
46 :
47 : }
48 :
49 : /* Modified timestamp */
50 8 : if(!(source->st_mtim.tv_sec == destination->st_mtim.tv_sec &&
51 8 : source->st_mtim.tv_nsec == destination->st_mtim.tv_nsec))
52 : {
53 0 : changes |= MODIFICATION_TIME_CHANGED;
54 :
55 : }
56 :
57 : /* Time of last status change */
58 8 : if(!(source->st_ctim.tv_sec == destination->st_ctim.tv_sec &&
59 8 : source->st_ctim.tv_nsec == destination->st_ctim.tv_nsec))
60 : {
61 0 : changes |= STATUS_CHANGED_TIME;
62 :
63 : }
64 :
65 8 : return(changes);
66 : }
67 :
68 : /**
69 : * @brief Prints all fields of the stat structure
70 : *
71 : * @param[in] st Pointer to the stat structure to print
72 : * @return Return Status of the operation
73 : */
74 0 : Return print_stat(const struct stat *st)
75 : {
76 0 : Return status = SUCCESS;
77 : char time_str[20]; /* "YYYY-MM-DD HH:MM:SS" + NUL */
78 : struct tm *tm_info;
79 :
80 0 : if(SUCCESS == status)
81 : {
82 0 : if(NULL == st)
83 : {
84 0 : status = FAILURE;
85 : }
86 : }
87 :
88 0 : if(SUCCESS == status)
89 : {
90 0 : echo(STDERR,"----------------\n");
91 0 : echo(STDERR,"File information:\n");
92 0 : echo(STDERR,"Device ID: %lu\n",(unsigned long)st->st_dev);
93 0 : echo(STDERR,"Inode number: %lu\n",(unsigned long)st->st_ino);
94 0 : echo(STDERR,"Mode: %o (octal)\n",(unsigned int)st->st_mode);
95 0 : echo(STDERR,"Hard links: %lu\n",(unsigned long)st->st_nlink);
96 0 : echo(STDERR,"User ID: %u\n",st->st_uid);
97 0 : echo(STDERR,"Group ID: %u\n",st->st_gid);
98 0 : echo(STDERR,"Device ID (if special file): %lu\n",(unsigned long)st->st_rdev);
99 0 : echo(STDERR,"Total size: %ld bytes\n",(long)st->st_size);
100 0 : echo(STDERR,"Block size: %ld\n",(long)st->st_blksize);
101 0 : echo(STDERR,"Number of blocks: %ld\n",(long)st->st_blocks);
102 :
103 : // Access time
104 0 : tm_info = localtime(&st->st_atim.tv_sec);
105 0 : strftime(time_str,sizeof(time_str),"%Y-%m-%d %H:%M:%S",tm_info);
106 0 : echo(STDERR,"Last access: %s.%09ld\n",time_str,st->st_atim.tv_nsec);
107 :
108 : // Modification time
109 0 : tm_info = localtime(&st->st_mtim.tv_sec);
110 0 : strftime(time_str,sizeof(time_str),"%Y-%m-%d %H:%M:%S",tm_info);
111 0 : echo(STDERR,"Last modification: %s.%09ld\n",time_str,st->st_mtim.tv_nsec);
112 :
113 : // Status change time
114 0 : tm_info = localtime(&st->st_ctim.tv_sec);
115 0 : strftime(time_str,sizeof(time_str),"%Y-%m-%d %H:%M:%S",tm_info);
116 0 : echo(STDERR,"Last status change: %s.%09ld\n",time_str,st->st_ctim.tv_nsec);
117 :
118 : // Print file type
119 0 : echo(STDERR,"File type: ");
120 :
121 0 : switch(st->st_mode & S_IFMT)
122 : {
123 0 : case S_IFBLK:
124 0 : echo(STDERR,"block device\n");
125 0 : break;
126 0 : case S_IFCHR:
127 0 : echo(STDERR,"character device\n");
128 0 : break;
129 0 : case S_IFDIR:
130 0 : echo(STDERR,"directory\n");
131 0 : break;
132 0 : case S_IFIFO:
133 0 : echo(STDERR,"FIFO/pipe\n");
134 0 : break;
135 0 : case S_IFLNK:
136 0 : echo(STDERR,"symlink\n");
137 0 : break;
138 0 : case S_IFREG:
139 0 : echo(STDERR,"regular file\n");
140 0 : break;
141 0 : case S_IFSOCK:
142 0 : echo(STDERR,"socket\n");
143 0 : break;
144 0 : default:
145 0 : echo(STDERR,"unknown\n");
146 0 : break;
147 : }
148 :
149 : // Print permissions
150 0 : echo(STDERR,"Permissions: ");
151 0 : echo(STDERR,(st->st_mode & S_IRUSR) ? "r" : "-");
152 0 : echo(STDERR,(st->st_mode & S_IWUSR) ? "w" : "-");
153 0 : echo(STDERR,(st->st_mode & S_IXUSR) ? "x" : "-");
154 0 : echo(STDERR,(st->st_mode & S_IRGRP) ? "r" : "-");
155 0 : echo(STDERR,(st->st_mode & S_IWGRP) ? "w" : "-");
156 0 : echo(STDERR,(st->st_mode & S_IXGRP) ? "x" : "-");
157 0 : echo(STDERR,(st->st_mode & S_IROTH) ? "r" : "-");
158 0 : echo(STDERR,(st->st_mode & S_IWOTH) ? "w" : "-");
159 0 : echo(STDERR,(st->st_mode & S_IXOTH) ? "x" : "-");
160 0 : echo(STDERR,"\n");
161 : }
162 :
163 0 : return(status);
164 : }
165 :
166 : /**
167 : * @brief Reports whether two stat structures describe the same file metadata.
168 : *
169 : * Prints both structures to STDERR when any tracked field differs.
170 : *
171 : * @param stat1 First stat structure
172 : * @param stat2 Second stat structure
173 : * @return SUCCESS when metadata matches; FAILURE otherwise
174 : */
175 8 : Return check_file_identity(
176 : const struct stat *stat1,
177 : const struct stat *stat2)
178 : {
179 8 : Return status = SUCCESS;
180 :
181 8 : if(IDENTICAL != compare_file_metadata_equivalence(stat1,stat2))
182 : {
183 0 : print_stat(stat1);
184 0 : print_stat(stat2);
185 0 : status = FAILURE;
186 : }
187 :
188 8 : return(status);
189 : }
|