Whamcloud - gitweb
LU-1347 build: remove the vim/emacs modelines
[fs/lustre-release.git] / lustre / obdclass / acl.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  */
30 /*
31  * This file is part of Lustre, http://www.lustre.org/
32  * Lustre is a trademark of Sun Microsystems, Inc.
33  *
34  * lustre/obdclass/acl.c
35  *
36  * Lustre Access Control List.
37  *
38  * Author: Fan Yong <fanyong@clusterfs.com>
39  */
40
41 #ifndef EXPORT_SYMTAB
42 # define EXPORT_SYMTAB
43 #endif
44
45 #define DEBUG_SUBSYSTEM S_SEC
46
47 #include <lustre_acl.h>
48 #include <lustre_eacl.h>
49 #include <obd_support.h>
50
51 #ifdef CONFIG_FS_POSIX_ACL
52
53 #define CFS_ACL_XATTR_VERSION POSIX_ACL_XATTR_VERSION
54
55 enum {
56         ES_UNK  = 0,    /* unknown stat */
57         ES_UNC  = 1,    /* ACL entry is not changed */
58         ES_MOD  = 2,    /* ACL entry is modified */
59         ES_ADD  = 3,    /* ACL entry is added */
60         ES_DEL  = 4     /* ACL entry is deleted */
61 };
62
63 static inline void lustre_ext_acl_le_to_cpu(ext_acl_xattr_entry *d,
64                                             ext_acl_xattr_entry *s)
65 {
66         d->e_tag        = le16_to_cpu(s->e_tag);
67         d->e_perm       = le16_to_cpu(s->e_perm);
68         d->e_id         = le32_to_cpu(s->e_id);
69         d->e_stat       = le32_to_cpu(s->e_stat);
70 }
71
72 static inline void lustre_ext_acl_cpu_to_le(ext_acl_xattr_entry *d,
73                                             ext_acl_xattr_entry *s)
74 {
75         d->e_tag        = cpu_to_le16(s->e_tag);
76         d->e_perm       = cpu_to_le16(s->e_perm);
77         d->e_id         = cpu_to_le32(s->e_id);
78         d->e_stat       = cpu_to_le32(s->e_stat);
79 }
80
81 static inline void lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry *d,
82                                               posix_acl_xattr_entry *s)
83 {
84         d->e_tag        = le16_to_cpu(s->e_tag);
85         d->e_perm       = le16_to_cpu(s->e_perm);
86         d->e_id         = le32_to_cpu(s->e_id);
87 }
88
89 static inline void lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry *d,
90                                               posix_acl_xattr_entry *s)
91 {
92         d->e_tag        = cpu_to_le16(s->e_tag);
93         d->e_perm       = cpu_to_le16(s->e_perm);
94         d->e_id         = cpu_to_le32(s->e_id);
95 }
96
97 /*
98  * Check permission based on POSIX ACL.
99  */
100 int lustre_posix_acl_permission(struct md_ucred *mu, struct lu_attr *la,
101                                 int want, posix_acl_xattr_entry *entry,
102                                 int count)
103 {
104         posix_acl_xattr_entry *pa, *pe, *mask_obj;
105         posix_acl_xattr_entry ae, me;
106         int found = 0;
107
108         if (count <= 0)
109                 return -EACCES;
110
111         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
112                 lustre_posix_acl_le_to_cpu(&ae, pa);
113                 switch (ae.e_tag) {
114                 case ACL_USER_OBJ:
115                         /* (May have been checked already) */
116                         if (la->la_uid == mu->mu_fsuid)
117                                 goto check_perm;
118                         break;
119                 case ACL_USER:
120                         if (ae.e_id == mu->mu_fsuid)
121                                 goto mask;
122                         break;
123                 case ACL_GROUP_OBJ:
124                         if (lustre_in_group_p(mu, la->la_gid)) {
125                                 found = 1;
126                                 if ((ae.e_perm & want) == want)
127                                         goto mask;
128                         }
129                         break;
130                 case ACL_GROUP:
131                         if (lustre_in_group_p(mu, ae.e_id)) {
132                                 found = 1;
133                                 if ((ae.e_perm & want) == want)
134                                         goto mask;
135                         }
136                         break;
137                 case ACL_MASK:
138                         break;
139                 case ACL_OTHER:
140                         if (found)
141                                 return -EACCES;
142                         else
143                                 goto check_perm;
144                 default:
145                         return -EIO;
146                 }
147         }
148         return -EIO;
149
150 mask:
151         for (mask_obj = pa + 1; mask_obj <= pe; mask_obj++) {
152                 lustre_posix_acl_le_to_cpu(&me, mask_obj);
153                 if (me.e_tag == ACL_MASK) {
154                         if ((ae.e_perm & me.e_perm & want) == want)
155                                 return 0;
156
157                         return -EACCES;
158                 }
159         }
160
161 check_perm:
162         if ((ae.e_perm & want) == want)
163                 return 0;
164
165         return -EACCES;
166 }
167 EXPORT_SYMBOL(lustre_posix_acl_permission);
168
169 /*
170  * Modify the ACL for the chmod.
171  */
172 int lustre_posix_acl_chmod_masq(posix_acl_xattr_entry *entry, __u32 mode,
173                                 int count)
174 {
175         posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
176
177         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
178                 switch (le16_to_cpu(pa->e_tag)) {
179                 case ACL_USER_OBJ:
180                         pa->e_perm = cpu_to_le16((mode & S_IRWXU) >> 6);
181                         break;
182                 case ACL_USER:
183                 case ACL_GROUP:
184                         break;
185                 case ACL_GROUP_OBJ:
186                         group_obj = pa;
187                         break;
188                 case ACL_MASK:
189                         mask_obj = pa;
190                         break;
191                 case ACL_OTHER:
192                         pa->e_perm = cpu_to_le16(mode & S_IRWXO);
193                         break;
194                 default:
195                         return -EIO;
196                 }
197         }
198
199         if (mask_obj) {
200                 mask_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
201         } else {
202                 if (!group_obj)
203                         return -EIO;
204                 group_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
205         }
206
207         return 0;
208 }
209 EXPORT_SYMBOL(lustre_posix_acl_chmod_masq);
210
211 /*
212  * Modify acl when creating a new object.
213  */
214 int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry, __u32 *pmode,
215                                  int count)
216 {
217         posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
218         posix_acl_xattr_entry ae;
219         __u32 mode = *pmode;
220         int not_equiv = 0;
221
222         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
223                 lustre_posix_acl_le_to_cpu(&ae, pa);
224                 switch (ae.e_tag) {
225                 case ACL_USER_OBJ:
226                         ae.e_perm &= (mode >> 6) | ~S_IRWXO;
227                         pa->e_perm = cpu_to_le16(ae.e_perm);
228                         mode &= (ae.e_perm << 6) | ~S_IRWXU;
229                         break;
230                 case ACL_USER:
231                 case ACL_GROUP:
232                         not_equiv = 1;
233                         break;
234                 case ACL_GROUP_OBJ:
235                         group_obj = pa;
236                         break;
237                 case ACL_OTHER:
238                         ae.e_perm &= mode | ~S_IRWXO;
239                         pa->e_perm = cpu_to_le16(ae.e_perm);
240                         mode &= ae.e_perm | ~S_IRWXO;
241                         break;
242                 case ACL_MASK:
243                         mask_obj = pa;
244                         not_equiv = 1;
245                         break;
246                 default:
247                         return -EIO;
248                 }
249         }
250
251         if (mask_obj) {
252                 ae.e_perm = le16_to_cpu(mask_obj->e_perm) &
253                             ((mode >> 3) | ~S_IRWXO);
254                 mode &= (ae.e_perm << 3) | ~S_IRWXG;
255                 mask_obj->e_perm = cpu_to_le16(ae.e_perm);
256         } else {
257                 if (!group_obj)
258                         return -EIO;
259                 ae.e_perm = le16_to_cpu(group_obj->e_perm) &
260                             ((mode >> 3) | ~S_IRWXO);
261                 mode &= (ae.e_perm << 3) | ~S_IRWXG;
262                 group_obj->e_perm = cpu_to_le16(ae.e_perm);
263         }
264
265         *pmode = (*pmode & ~S_IRWXUGO) | mode;
266         return not_equiv;
267 }
268 EXPORT_SYMBOL(lustre_posix_acl_create_masq);
269
270 /* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */
271 static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header,
272                                                int old_count, int new_count)
273 {
274         int old_size = CFS_ACL_XATTR_SIZE(old_count, posix_acl_xattr);
275         int new_size = CFS_ACL_XATTR_SIZE(new_count, posix_acl_xattr);
276         posix_acl_xattr_header *new;
277
278         if (unlikely(old_count <= new_count))
279                 return old_size;
280
281         OBD_ALLOC(new, new_size);
282         if (unlikely(new == NULL))
283                 return -ENOMEM;
284
285         memcpy(new, *header, new_size);
286         OBD_FREE(*header, old_size);
287         *header = new;
288         return new_size;
289 }
290
291 /* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */
292 static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header,
293                                              int old_count)
294 {
295         int ext_count = le32_to_cpu((*header)->a_count);
296         int ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
297         int old_size = CFS_ACL_XATTR_SIZE(old_count, ext_acl_xattr);
298         ext_acl_xattr_header *new;
299
300         if (unlikely(old_count <= ext_count))
301                 return 0;
302
303         OBD_ALLOC(new, ext_size);
304         if (unlikely(new == NULL))
305                 return -ENOMEM;
306
307         memcpy(new, *header, ext_size);
308         OBD_FREE(*header, old_size);
309         *header = new;
310         return 0;
311 }
312
313 /*
314  * Generate new extended ACL based on the posix ACL.
315  */
316 ext_acl_xattr_header *
317 lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
318 {
319         int count, i, esize;
320         ext_acl_xattr_header *new;
321         ENTRY;
322
323         if (unlikely(size < 0))
324                 RETURN(ERR_PTR(-EINVAL));
325         else if (!size)
326                 count = 0;
327         else
328                 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
329         esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr);
330         OBD_ALLOC(new, esize);
331         if (unlikely(new == NULL))
332                 RETURN(ERR_PTR(-ENOMEM));
333
334         new->a_count = cpu_to_le32(count);
335         for (i = 0; i < count; i++) {
336                 new->a_entries[i].e_tag  = header->a_entries[i].e_tag;
337                 new->a_entries[i].e_perm = header->a_entries[i].e_perm;
338                 new->a_entries[i].e_id   = header->a_entries[i].e_id;
339                 new->a_entries[i].e_stat = cpu_to_le32(ES_UNK);
340         }
341
342         RETURN(new);
343 }
344 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
345
346 /*
347  * Filter out the "nobody" entries in the posix ACL.
348  */
349 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int size,
350                                   posix_acl_xattr_header **out)
351 {
352         int count, i, j, rc = 0;
353         __u32 id;
354         posix_acl_xattr_header *new;
355         ENTRY;
356
357         if (unlikely(size < 0))
358                 RETURN(-EINVAL);
359         else if (!size)
360                 RETURN(0);
361
362         OBD_ALLOC(new, size);
363         if (unlikely(new == NULL))
364                 RETURN(-ENOMEM);
365
366         new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
367         count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
368         for (i = 0, j = 0; i < count; i++) {
369                 id = le32_to_cpu(header->a_entries[i].e_id);
370                 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
371                 case ACL_USER_OBJ:
372                 case ACL_GROUP_OBJ:
373                 case ACL_MASK:
374                 case ACL_OTHER:
375                         if (id != ACL_UNDEFINED_ID)
376                                 GOTO(_out, rc = -EIO);
377
378                         memcpy(&new->a_entries[j++], &header->a_entries[i],
379                                sizeof(posix_acl_xattr_entry));
380                         break;
381                 case ACL_USER:
382                         if (id != NOBODY_UID)
383                                 memcpy(&new->a_entries[j++],
384                                        &header->a_entries[i],
385                                        sizeof(posix_acl_xattr_entry));
386                         break;
387                 case ACL_GROUP:
388                         if (id != NOBODY_GID)
389                                 memcpy(&new->a_entries[j++],
390                                        &header->a_entries[i],
391                                        sizeof(posix_acl_xattr_entry));
392                         break;
393                 default:
394                         GOTO(_out, rc = -EIO);
395                 }
396         }
397
398         /* free unused space. */
399         rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
400         if (rc >= 0) {
401                 size = rc;
402                 *out = new;
403                 rc = 0;
404         }
405         EXIT;
406
407 _out:
408         if (rc) {
409                 OBD_FREE(new, size);
410                 size = rc;
411         }
412         return size;
413 }
414 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
415
416 /*
417  * Convert server-side uid/gid in the posix ACL items to the client-side ones.
418  * convert rule:
419  * @CFS_IC_NOTHING
420  *  nothing to be converted.
421  * @CFS_IC_ALL
422  *  mapped ids are converted to client-side ones,
423  *  unmapped ones are converted to "nobody".
424  * @CFS_IC_MAPPED
425  *  only mapped ids are converted to "nobody".
426  * @CFS_IC_UNMAPPED
427  *  only unmapped ids are converted to "nobody".
428  */
429 int lustre_posix_acl_xattr_id2client(struct md_ucred *mu,
430                                      struct lustre_idmap_table *t,
431                                      posix_acl_xattr_header *header,
432                                      int size, int flags)
433 {
434         int count, i;
435         __u32 id;
436         ENTRY;
437
438         if (unlikely(size < 0))
439                 RETURN(-EINVAL);
440         else if (!size)
441                 RETURN(0);
442
443         if (unlikely(flags == CFS_IC_NOTHING))
444                 RETURN(0);
445
446         count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
447         for (i = 0; i < count; i++) {
448                 id = le32_to_cpu(header->a_entries[i].e_id);
449                 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
450                 case ACL_USER_OBJ:
451                 case ACL_GROUP_OBJ:
452                 case ACL_MASK:
453                 case ACL_OTHER:
454                         if (id != ACL_UNDEFINED_ID)
455                                 RETURN(-EIO);
456                         break;
457                 case ACL_USER:
458                         id = lustre_idmap_lookup_uid(mu, t, 1, id);
459                         if (flags == CFS_IC_ALL) {
460                                 if (id == CFS_IDMAP_NOTFOUND)
461                                         id = NOBODY_UID;
462                                 header->a_entries[i].e_id = cpu_to_le32(id);
463                         } else if (flags == CFS_IC_MAPPED) {
464                                 if (id != CFS_IDMAP_NOTFOUND)
465                                         header->a_entries[i].e_id =
466                                                         cpu_to_le32(NOBODY_UID);
467                         } else if (flags == CFS_IC_UNMAPPED) {
468                                 if (id == CFS_IDMAP_NOTFOUND)
469                                         header->a_entries[i].e_id =
470                                                         cpu_to_le32(NOBODY_UID);
471                         }
472                         break;
473                 case ACL_GROUP:
474                         id = lustre_idmap_lookup_gid(mu, t, 1, id);
475                         if (flags == CFS_IC_ALL) {
476                                 if (id == CFS_IDMAP_NOTFOUND)
477                                         id = NOBODY_GID;
478                                 header->a_entries[i].e_id = cpu_to_le32(id);
479                         } else if (flags == CFS_IC_MAPPED) {
480                                 if (id != CFS_IDMAP_NOTFOUND)
481                                         header->a_entries[i].e_id =
482                                                         cpu_to_le32(NOBODY_GID);
483                         } else if (flags == CFS_IC_UNMAPPED) {
484                                 if (id == CFS_IDMAP_NOTFOUND)
485                                         header->a_entries[i].e_id =
486                                                         cpu_to_le32(NOBODY_GID);
487                         }
488                         break;
489                  default:
490                         RETURN(-EIO);
491                 }
492         }
493     RETURN(0);
494 }
495 EXPORT_SYMBOL(lustre_posix_acl_xattr_id2client);
496
497 /*
498  * Release the posix ACL space.
499  */
500 void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
501 {
502         OBD_FREE(header, size);
503 }
504 EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
505
506 /*
507  * Converts client-side uid/gid in the extended ACL items to server-side ones.
508  * convert rule:
509  *  mapped ids are converted to server-side ones,
510  *  unmapped ones cause "EPERM" error.
511  */
512 int lustre_ext_acl_xattr_id2server(struct md_ucred *mu,
513                                    struct lustre_idmap_table *t,
514                                    ext_acl_xattr_header *header)
515
516 {
517         int i, count = le32_to_cpu(header->a_count);
518         __u32 id;
519         ENTRY;
520
521         for (i = 0; i < count; i++) {
522                 id = le32_to_cpu(header->a_entries[i].e_id);
523                 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
524                 case ACL_USER_OBJ:
525                 case ACL_GROUP_OBJ:
526                 case ACL_MASK:
527                 case ACL_OTHER:
528                         if (id != ACL_UNDEFINED_ID)
529                                 RETURN(-EIO);
530                         break;
531                 case ACL_USER:
532                         id = lustre_idmap_lookup_uid(mu, t, 0, id);
533                         if (id == CFS_IDMAP_NOTFOUND)
534                                 RETURN(-EPERM);
535                         else
536                                 header->a_entries[i].e_id = cpu_to_le32(id);
537                         break;
538                 case ACL_GROUP:
539                         id = lustre_idmap_lookup_gid(mu, t, 0, id);
540                         if (id == CFS_IDMAP_NOTFOUND)
541                                 RETURN(-EPERM);
542                         else
543                                 header->a_entries[i].e_id = cpu_to_le32(id);
544                         break;
545                 default:
546                         RETURN(-EIO);
547                 }
548         }
549         RETURN(0);
550 }
551 EXPORT_SYMBOL(lustre_ext_acl_xattr_id2server);
552
553 /*
554  * Release the extended ACL space.
555  */
556 void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
557 {
558         OBD_FREE(header, CFS_ACL_XATTR_SIZE(le32_to_cpu(header->a_count), \
559                                             ext_acl_xattr));
560 }
561 EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
562
563 static ext_acl_xattr_entry *
564 lustre_ext_acl_xattr_search(ext_acl_xattr_header *header,
565                             posix_acl_xattr_entry *entry, int *pos)
566 {
567         int once, start, end, i, j, count = le32_to_cpu(header->a_count);
568
569         once = 0;
570         start = *pos;
571         end = count;
572
573 again:
574         for (i = start; i < end; i++) {
575                 if (header->a_entries[i].e_tag == entry->e_tag &&
576                     header->a_entries[i].e_id == entry->e_id) {
577                         j = i;
578                         if (++i >= count)
579                                 i = 0;
580                         *pos = i;
581                         return &header->a_entries[j];
582                 }
583         }
584
585         if (!once) {
586                 once = 1;
587                 start = 0;
588                 end = *pos;
589                 goto again;
590         }
591
592         return NULL;
593 }
594
595 /*
596  * Merge the posix ACL and the extended ACL into new posix ACL.
597  */
598 int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
599                                  ext_acl_xattr_header *ext_header,
600                                  posix_acl_xattr_header **out)
601 {
602         int posix_count, posix_size, i, j;
603         int ext_count = le32_to_cpu(ext_header->a_count), pos = 0, rc = 0;
604         posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID};
605         posix_acl_xattr_header *new;
606         ext_acl_xattr_entry *ee, ae;
607         ENTRY;
608
609         lustre_posix_acl_cpu_to_le(&pe, &pe);
610         ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos);
611         if (ee == NULL || le32_to_cpu(ee->e_stat) == ES_DEL) {
612                 /* there are only base ACL entries at most. */
613                 posix_count = 3;
614                 posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
615                 OBD_ALLOC(new, posix_size);
616                 if (unlikely(new == NULL))
617                         RETURN(-ENOMEM);
618
619                 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
620                 for (i = 0, j = 0; i < ext_count; i++) {
621                         lustre_ext_acl_le_to_cpu(&ae,
622                                                  &ext_header->a_entries[i]);
623                         switch (ae.e_tag) {
624                         case ACL_USER_OBJ:
625                         case ACL_GROUP_OBJ:
626                         case ACL_OTHER:
627                                 if (ae.e_id != ACL_UNDEFINED_ID)
628                                         GOTO(_out, rc = -EIO);
629
630                                 if (ae.e_stat != ES_DEL) {
631                                         new->a_entries[j].e_tag =
632                                                 ext_header->a_entries[i].e_tag;
633                                         new->a_entries[j].e_perm =
634                                                 ext_header->a_entries[i].e_perm;
635                                         new->a_entries[j++].e_id =
636                                                 ext_header->a_entries[i].e_id;
637                                 }
638                                 break;
639                         case ACL_MASK:
640                         case ACL_USER:
641                         case ACL_GROUP:
642                                 if (ae.e_stat == ES_DEL)
643                                         break;
644                         default:
645                                 GOTO(_out, rc = -EIO);
646                         }
647                 }
648         } else {
649                 /* maybe there are valid ACL_USER or ACL_GROUP entries in the
650                  * original server-side ACL, they are regarded as ES_UNC stat.*/
651                 int ori_posix_count;
652
653                 if (unlikely(size < 0))
654                         RETURN(-EINVAL);
655                 else if (!size)
656                         ori_posix_count = 0;
657                 else
658                         ori_posix_count =
659                                 CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
660                 posix_count = ori_posix_count + ext_count;
661                 posix_size =
662                         CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
663                 OBD_ALLOC(new, posix_size);
664                 if (unlikely(new == NULL))
665                         RETURN(-ENOMEM);
666
667                 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
668                 /* 1. process the unchanged ACL entries
669                  *    in the original server-side ACL. */
670                 pos = 0;
671                 for (i = 0, j = 0; i < ori_posix_count; i++) {
672                         ee = lustre_ext_acl_xattr_search(ext_header,
673                                         &posix_header->a_entries[i], &pos);
674                         if (ee == NULL)
675                                 memcpy(&new->a_entries[j++],
676                                        &posix_header->a_entries[i],
677                                        sizeof(posix_acl_xattr_entry));
678                 }
679
680                 /* 2. process the non-deleted entries
681                  *    from client-side extended ACL. */
682                 for (i = 0; i < ext_count; i++) {
683                         if (le16_to_cpu(ext_header->a_entries[i].e_stat) !=
684                             ES_DEL) {
685                                 new->a_entries[j].e_tag =
686                                                 ext_header->a_entries[i].e_tag;
687                                 new->a_entries[j].e_perm =
688                                                 ext_header->a_entries[i].e_perm;
689                                 new->a_entries[j++].e_id =
690                                                 ext_header->a_entries[i].e_id;
691                         }
692                 }
693         }
694
695         /* free unused space. */
696         rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j);
697         if (rc >= 0) {
698                 posix_size = rc;
699                 *out = new;
700                 rc = 0;
701         }
702         EXIT;
703
704 _out:
705         if (rc) {
706                 OBD_FREE(new, posix_size);
707                 posix_size = rc;
708         }
709         return posix_size;
710 }
711 EXPORT_SYMBOL(lustre_acl_xattr_merge2posix);
712
713 /*
714  * Merge the posix ACL and the extended ACL into new extended ACL.
715  */
716 ext_acl_xattr_header *
717 lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
718                            ext_acl_xattr_header *ext_header)
719 {
720         int ori_ext_count, posix_count, ext_count, ext_size;
721         int i, j, pos = 0, rc = 0;
722         posix_acl_xattr_entry pae;
723         ext_acl_xattr_header *new;
724         ext_acl_xattr_entry *ee, eae;
725         ENTRY;
726
727         if (unlikely(size < 0))
728                 RETURN(ERR_PTR(-EINVAL));
729         else if (!size)
730                 posix_count = 0;
731         else
732                 posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
733         ori_ext_count = le32_to_cpu(ext_header->a_count);
734         ext_count = posix_count + ori_ext_count;
735         ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
736
737         OBD_ALLOC(new, ext_size);
738         if (unlikely(new == NULL))
739                 RETURN(ERR_PTR(-ENOMEM));
740
741         for (i = 0, j = 0; i < posix_count; i++) {
742                 lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
743                 switch (pae.e_tag) {
744                 case ACL_USER_OBJ:
745                 case ACL_GROUP_OBJ:
746                 case ACL_MASK:
747                 case ACL_OTHER:
748                         if (pae.e_id != ACL_UNDEFINED_ID)
749                                 GOTO(out, rc = -EIO);
750                 case ACL_USER:
751                         /* ignore "nobody" entry. */
752                         if (pae.e_id == NOBODY_UID)
753                                 break;
754
755                         new->a_entries[j].e_tag =
756                                         posix_header->a_entries[i].e_tag;
757                         new->a_entries[j].e_perm =
758                                         posix_header->a_entries[i].e_perm;
759                         new->a_entries[j].e_id =
760                                         posix_header->a_entries[i].e_id;
761                         ee = lustre_ext_acl_xattr_search(ext_header,
762                                         &posix_header->a_entries[i], &pos);
763                         if (ee) {
764                                 if (posix_header->a_entries[i].e_perm !=
765                                                                 ee->e_perm)
766                                         /* entry modified. */
767                                         ee->e_stat =
768                                         new->a_entries[j++].e_stat =
769                                                         cpu_to_le32(ES_MOD);
770                                 else
771                                         /* entry unchanged. */
772                                         ee->e_stat =
773                                         new->a_entries[j++].e_stat =
774                                                         cpu_to_le32(ES_UNC);
775                         } else {
776                                 /* new entry. */
777                                 new->a_entries[j++].e_stat =
778                                                         cpu_to_le32(ES_ADD);
779                         }
780                         break;
781                 case ACL_GROUP:
782                         /* ignore "nobody" entry. */
783                         if (pae.e_id == NOBODY_GID)
784                                 break;
785                         new->a_entries[j].e_tag =
786                                         posix_header->a_entries[i].e_tag;
787                         new->a_entries[j].e_perm =
788                                         posix_header->a_entries[i].e_perm;
789                         new->a_entries[j].e_id =
790                                         posix_header->a_entries[i].e_id;
791                         ee = lustre_ext_acl_xattr_search(ext_header,
792                                         &posix_header->a_entries[i], &pos);
793                         if (ee) {
794                                 if (posix_header->a_entries[i].e_perm !=
795                                                                 ee->e_perm)
796                                         /* entry modified. */
797                                         ee->e_stat =
798                                         new->a_entries[j++].e_stat =
799                                                         cpu_to_le32(ES_MOD);
800                                 else
801                                         /* entry unchanged. */
802                                         ee->e_stat =
803                                         new->a_entries[j++].e_stat =
804                                                         cpu_to_le32(ES_UNC);
805                         } else {
806                                 /* new entry. */
807                                 new->a_entries[j++].e_stat =
808                                                         cpu_to_le32(ES_ADD);
809                         }
810                         break;
811                 default:
812                         GOTO(out, rc = -EIO);
813                 }
814         }
815
816         /* process deleted entries. */
817         for (i = 0; i < ori_ext_count; i++) {
818                 lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]);
819                 if (eae.e_stat == ES_UNK) {
820                         /* ignore "nobody" entry. */
821                         if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) ||
822                             (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID))
823                                 continue;
824
825                         new->a_entries[j].e_tag =
826                                                 ext_header->a_entries[i].e_tag;
827                         new->a_entries[j].e_perm =
828                                                 ext_header->a_entries[i].e_perm;
829                         new->a_entries[j].e_id = ext_header->a_entries[i].e_id;
830                         new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL);
831                 }
832         }
833
834         new->a_count = cpu_to_le32(j);
835         /* free unused space. */
836         rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
837         EXIT;
838
839 out:
840         if (rc) {
841                 OBD_FREE(new, ext_size);
842                 new = ERR_PTR(rc);
843         }
844         return new;
845 }
846 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);
847
848 #endif