Rename tests/test-copy-file-sameacls.c to tests/test-sameacls.c.
[gnulib.git] / tests / test-sameacls.c
1 /* Test whether two files have the same ACLs.
2    Copyright (C) 2008 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 /* Written by Bruno Haible <bruno@clisp.org>, 2008.  */
18
19 #include <config.h>
20
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/stat.h>
26
27 #if HAVE_ACL_GET_FILE || HAVE_ACL || HAVE_ACLX_GET || HAVE_STATACL
28 # include <sys/types.h>
29 # include <sys/acl.h>
30 #endif
31
32 #include "read-file.h"
33 #include "xalloc.h"
34
35 #define ASSERT(expr) \
36   do                                                                         \
37     {                                                                        \
38       if (!(expr))                                                           \
39         {                                                                    \
40           fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
41           fflush (stderr);                                                   \
42           abort ();                                                          \
43         }                                                                    \
44     }                                                                        \
45   while (0)
46
47 int
48 main (int argc, char *argv[])
49 {
50   const char *file1;
51   const char *file2;
52
53   ASSERT (argc == 3);
54
55   file1 = argv[1];
56   file2 = argv[2];
57
58   /* Compare the contents of the two files.  */
59   {
60     size_t size1;
61     char *contents1;
62     size_t size2;
63     char *contents2;
64
65     contents1 = read_file (file1, &size1);
66     if (contents1 == NULL)
67       {
68         fprintf (stderr, "error reading file %s: errno = %d\n", file1, errno);
69         fflush (stderr);
70         abort ();
71       }
72     contents2 = read_file (file2, &size2);
73     if (contents2 == NULL)
74       {
75         fprintf (stderr, "error reading file %s: errno = %d\n", file2, errno);
76         fflush (stderr);
77         abort ();
78       }
79
80     if (size2 != size1)
81       {
82         fprintf (stderr, "files %s and %s have different sizes\n",
83                  file1, file2);
84         fflush (stderr);
85         abort ();
86       }
87     if (memcmp (contents1, contents2, size1) != 0)
88       {
89         fprintf (stderr, "files %s and %s have different contents\n",
90                  file1, file2);
91         fflush (stderr);
92         abort ();
93       }
94   }
95
96   /* Compare the access permissions of the two files, including ACLs.  */
97   {
98     struct stat statbuf1;
99     struct stat statbuf2;
100
101     if (stat (file1, &statbuf1) < 0)
102       {
103         fprintf (stderr, "error accessing file %s: errno = %d\n", file1, errno);
104         fflush (stderr);
105         abort ();
106       }
107     if (stat (file2, &statbuf2) < 0)
108       {
109         fprintf (stderr, "error accessing file %s: errno = %d\n", file2, errno);
110         fflush (stderr);
111         abort ();
112       }
113     if (statbuf1.st_mode != statbuf2.st_mode)
114       {
115         fprintf (stderr, "files %s and %s have different access modes: %03o and %03o\n",
116                  file1, file2,
117                 (unsigned int) statbuf1.st_mode, (unsigned int) statbuf2.st_mode);
118         return 1;
119       }
120   }
121   {
122 #if HAVE_ACL_GET_FILE /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
123     acl_t acl1;
124     char *text1;
125     int errno1;
126     acl_t acl2;
127     char *text2;
128     int errno2;
129
130     acl1 = acl_get_file (file1, ACL_TYPE_ACCESS);
131     if (acl1 == (acl_t)NULL)
132       {
133         text1 = NULL;
134         errno1 = errno;
135       }
136     else
137       {
138         text1 = acl_to_text (acl1, NULL);
139         if (text1 == NULL)
140           errno1 = errno;
141         else
142           errno1 = 0;
143       }
144     acl2 = acl_get_file (file2, ACL_TYPE_ACCESS);
145     if (acl2 == (acl_t)NULL)
146       {
147         text2 = NULL;
148         errno2 = errno;
149       }
150     else
151       {
152         text2 = acl_to_text (acl2, NULL);
153         if (text2 == NULL)
154           errno2 = errno;
155         else
156           errno2 = 0;
157       }
158
159     if (acl1 != (acl_t)NULL)
160       {
161         if (acl2 != (acl_t)NULL)
162           {
163             if (text1 != NULL)
164               {
165                 if (text2 != NULL)
166                   {
167                     if (strcmp (text1, text2) != 0)
168                       {
169                         fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n",
170                                  file1, file2, text1, text2);
171                         return 1;
172                       }
173                   }
174                 else
175                   {
176                     fprintf (stderr, "file %s has a valid ACL, but file %s has an invalid ACL\n",
177                              file1, file2);
178                     return 1;
179                   }
180               }
181             else
182               {
183                 if (text2 != NULL)
184                   {
185                     fprintf (stderr, "file %s has an invalid ACL, but file %s has a valid ACL\n",
186                              file1, file2);
187                     return 1;
188                   }
189                 else
190                   {
191                     if (errno1 != errno2)
192                       {
193                         fprintf (stderr, "files %s and %s have differently invalid ACLs, errno = %d vs. %d\n",
194                                  file1, file2, errno1, errno2);
195                         return 1;
196                       }
197                   }
198               }
199           }
200         else
201           {
202             fprintf (stderr, "file %s has an ACL, but file %s has no ACL\n",
203                      file1, file2);
204             return 1;
205           }
206       }
207     else
208       {
209         if (acl2 != (acl_t)NULL)
210           {
211             fprintf (stderr, "file %s has no ACL, but file %s has an ACL\n",
212                      file1, file2);
213             return 1;
214           }
215       }
216 #elif HAVE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
217   int count1;
218   int count2;
219
220   count1 = acl (file1, GETACLCNT, 0, NULL);
221   count2 = acl (file2, GETACLCNT, 0, NULL);
222
223   if (count1 != count2)
224     {
225       if (count1 < 0)
226         {
227           fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
228           fflush (stderr);
229           abort ();
230         }
231       if (count2 < 0)
232         {
233           fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
234           fflush (stderr);
235           abort ();
236         }
237       fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
238                file1, file2, count1, count2);
239       return 1;
240     }
241   else
242     {
243       aclent_t *entries1 = XNMALLOC (count1, aclent_t);
244       aclent_t *entries2 = XNMALLOC (count2, aclent_t);
245       int i;
246
247       if (acl (file1, GETACL, count1, entries1) < count1)
248         {
249           fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
250           fflush (stderr);
251           abort ();
252         }
253       if (acl (file2, GETACL, count2, entries2) < count1)
254         {
255           fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
256           fflush (stderr);
257           abort ();
258         }
259       for (i = 0; i < count1; i++)
260         {
261           if (entries1[i].a_type != entries2[i].a_type)
262             {
263               fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n",
264                        file1, file2, i, entries1[i].a_type, entries2[i].a_type);
265               return 1;
266             }
267           if (entries1[i].a_id != entries2[i].a_id)
268             {
269               fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n",
270                        file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id);
271               return 1;
272             }
273           if (entries1[i].a_perm != entries2[i].a_perm)
274             {
275               fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
276                        file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm);
277               return 1;
278             }
279         }
280     }
281 # ifdef ACE_GETACL
282   count1 = acl (file1, ACE_GETACLCNT, 0, NULL);
283   count2 = acl (file2, ACE_GETACLCNT, 0, NULL);
284   if (count1 != count2)
285     {
286       if (count1 < 0)
287         {
288           fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file1);
289           fflush (stderr);
290           abort ();
291         }
292       if (count2 < 0)
293         {
294           fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file2);
295           fflush (stderr);
296           abort ();
297         }
298       fprintf (stderr, "files %s and %s have different number of ACE-ACLs: %d and %d\n",
299                file1, file2, count1, count2);
300       return 1;
301     }
302   else if (count1 > 0)
303     {
304       ace_t *entries1 = XNMALLOC (count1, ace_t);
305       ace_t *entries2 = XNMALLOC (count2, ace_t);
306       int i;
307
308       if (acl (file1, ACE_GETACL, count1, entries1) < count1)
309         {
310           fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file1);
311           fflush (stderr);
312           abort ();
313         }
314       if (acl (file2, ACE_GETACL, count2, entries2) < count1)
315         {
316           fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file2);
317           fflush (stderr);
318           abort ();
319         }
320       for (i = 0; i < count1; i++)
321         {
322           if (entries1[i].a_type != entries2[i].a_type)
323             {
324               fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different types %d and %d\n",
325                        file1, file2, i, entries1[i].a_type, entries2[i].a_type);
326               return 1;
327             }
328           if (entries1[i].a_who != entries2[i].a_who)
329             {
330               fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different ids %d and %d\n",
331                        file1, file2, i, (int)entries1[i].a_who, (int)entries2[i].a_who);
332               return 1;
333             }
334           if (entries1[i].a_access_mask != entries2[i].a_access_mask)
335             {
336               fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different access masks %03o and %03o\n",
337                        file1, file2, i, (unsigned int) entries1[i].a_access_mask, (unsigned int) entries2[i].a_access_mask);
338               return 1;
339             }
340           if (entries1[i].a_flags != entries2[i].a_flags)
341             {
342               fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different flags 0x%x and 0x%x\n",
343                        file1, file2, i, (unsigned int) entries1[i].a_flags, (unsigned int) entries2[i].a_flags);
344               return 1;
345             }
346         }
347     }
348 # endif
349 #elif HAVE_GETACL /* HP-UX */
350   int count1;
351   int count2;
352
353   count1 = getacl (file1, 0, NULL);
354   count2 = getacl (file2, 0, NULL);
355
356   if (count1 != count2)
357     {
358       if (count1 < 0)
359         {
360           fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
361           fflush (stderr);
362           abort ();
363         }
364       if (count2 < 0)
365         {
366           fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
367           fflush (stderr);
368           abort ();
369         }
370       fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n",
371                file1, file2, count1, count2);
372       return 1;
373     }
374   else
375     {
376       struct acl_entry *entries1 = XNMALLOC (count1, struct acl_entry);
377       struct acl_entry *entries2 = XNMALLOC (count2, struct acl_entry);
378       int i;
379
380       if (getacl (file1, count1, entries1) < count1)
381         {
382           fprintf (stderr, "error retrieving the ACLs of file %s\n", file1);
383           fflush (stderr);
384           abort ();
385         }
386       if (getacl (file2, count2, entries2) < count1)
387         {
388           fprintf (stderr, "error retrieving the ACLs of file %s\n", file2);
389           fflush (stderr);
390           abort ();
391         }
392       for (i = 0; i < count1; i++)
393         {
394           if (entries1[i].uid != entries2[i].uid)
395             {
396               fprintf (stderr, "files %s and %s: different ACL entry #%d: different uids %d and %d\n",
397                        file1, file2, i, (int)entries1[i].uid, (int)entries2[i].uid);
398               return 1;
399             }
400           if (entries1[i].gid != entries2[i].gid)
401             {
402               fprintf (stderr, "files %s and %s: different ACL entry #%d: different gids %d and %d\n",
403                        file1, file2, i, (int)entries1[i].gid, (int)entries2[i].gid);
404               return 1;
405             }
406           if (entries1[i].mode != entries2[i].mode)
407             {
408               fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n",
409                        file1, file2, i, (unsigned int) entries1[i].mode, (unsigned int) entries2[i].mode);
410               return 1;
411             }
412         }
413     }
414 #elif HAVE_ACLX_GET /* AIX */
415   acl_type_t type1;
416   char acl1[1000];
417   size_t aclsize1 = sizeof (acl1);
418   mode_t mode1;
419   char text1[1000];
420   acl_type_t type2;
421   char acl2[1000];
422   size_t aclsize2 = sizeof (acl2);
423   mode_t mode2;
424   char text2[1000];
425
426   if (aclx_get (file1, 0, &type1, acl1, &aclsize1, &mode1) < 0)
427     {
428       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
429       fflush (stderr);
430       abort ();
431     }
432   if (aclx_printStr (text1, sizeof (text1), acl1, aclsize1, type1, file1, 0) < 0)
433     {
434       fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file1);
435       fflush (stderr);
436       abort ();
437     }
438
439   if (aclx_get (file2, 0, &type2, acl2, &aclsize2, &mode2) < 0)
440     {
441       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
442       fflush (stderr);
443       abort ();
444     }
445   if (aclx_printStr (text2, sizeof (text2), acl2, aclsize2, type2, file2, 0) < 0)
446     {
447       fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file2);
448       fflush (stderr);
449       abort ();
450     }
451
452   if (strcmp (text1, text2) != 0)
453     {
454       fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n",
455                file1, file2, text1, text2);
456       return 1;
457     }
458 #elif HAVE_STATACL /* older AIX */
459   union { struct acl a; char room[4096]; } acl1;
460   union { struct acl a; char room[4096]; } acl2;
461   unsigned int i;
462
463   if (statacl (file1, STX_NORMAL, &acl1.a, sizeof (acl1)) < 0)
464     {
465       fprintf (stderr, "error accessing the ACLs of file %s\n", file1);
466       fflush (stderr);
467       abort ();
468     }
469   if (statacl (file2, STX_NORMAL, &acl2.a, sizeof (acl2)) < 0)
470     {
471       fprintf (stderr, "error accessing the ACLs of file %s\n", file2);
472       fflush (stderr);
473       abort ();
474     }
475
476   if (acl1.a.acl_len != acl2.a.acl_len)
477     {
478       fprintf (stderr, "files %s and %s have different ACL lengths: %u and %u\n",
479                file1, file2, acl1.a.acl_len, acl2.a.acl_len);
480       return 1;
481     }
482   if (acl1.a.acl_mode != acl2.a.acl_mode)
483     {
484       fprintf (stderr, "files %s and %s have different ACL modes: %03o and %03o\n",
485                file1, file2, acl1.a.acl_mode, acl2.a.acl_mode);
486       return 1;
487     }
488   if (acl1.a.u_access != acl2.a.u_access
489       || acl1.a.g_access != acl2.a.g_access
490       || acl1.a.o_access != acl2.a.o_access)
491     {
492       fprintf (stderr, "files %s and %s have different ACL access masks: %03o %03o %03o and %03o %03o %03o\n",
493                file1, file2,
494                acl1.a.u_access, acl1.a.g_access, acl1.a.o_access,
495                acl2.a.u_access, acl2.a.g_access, acl2.a.o_access);
496       return 1;
497     }
498   if (memcmp (acl1.a.acl_ext, acl2.a.acl_ext, acl1.a.acl_len) != 0)
499     {
500       fprintf (stderr, "files %s and %s have different ACL entries\n",
501                file1, file2);
502       return 1;
503     }
504 #endif
505   }
506
507   return 0;
508 }