venus: Remove dedebug
[openafs.git] / src / afs / IRIX / osi_inode.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * IRIX inode operations
12  *
13  * Implements:
14  * afsidestroy
15  * getinode
16  * igetinode
17  * xfs_getinode
18  * xfs_igetinode
19  * icreate
20  * afs_syscall_icreate
21  * xfs_icreatename64
22  * afs_syscall_icreatename64
23  * iopenargs64
24  * afs_syscall_iopen
25  * iopen
26  * iopen64
27  * xfs_iincdec64
28  * iincdec64
29  * afs_syscall_idec64
30  * afs_syscall_iinc64
31  * iincdec
32  * iinc
33  * idec
34  * afs_syscall_iincdec
35  * afs_syscall_ilistinode64
36  *
37  */
38
39 #include <afsconfig.h>
40 #include "afs/param.h"
41
42
43 #include "afs/sysincludes.h"    /* Standard vendor system headers */
44 #include "afsincludes.h"        /* Afs-based standard headers */
45 #include "afs/osi_inode.h"
46 #include "afs/afs_stats.h"      /* statistics stuff */
47
48 #define BAD_IGET        -1000
49
50 /*
51  * SGI dependent system calls
52  */
53 #ifndef INODESPECIAL
54 /*
55  * `INODESPECIAL' type inodes are ones that describe volumes.
56  */
57 #define INODESPECIAL    0xffffffff      /* ... from ../vol/viceinode.h  */
58 #endif
59
60 void
61 afsidestroy(struct inode *ip)
62 {
63     if (ip->i_afs) {
64         kmem_free(ip->i_afs, sizeof(struct afsparms));
65         ip->i_afs = NULL;
66     }
67 }
68
69 extern int xfs_fstype;
70
71 int
72 getinode(struct vfs *vfsp, dev_t dev, ino_t inode, struct inode **ipp)
73 {
74     return ENOSYS;
75 }
76
77 int
78 igetinode(struct vfs *vfsp, dev_t dev, ino_t inode, struct inode **ipp)
79 {
80     return ENOSYS;
81 }
82
83 int XFS_IGET_EPOS;
84 ino_t XFS_IGET_INO;
85 dev_t XFS_IGET_DEV;
86 #define SET_XFS_ERROR(POS, DEV, INO) \
87         XFS_IGET_EPOS = (POS), XFS_IGET_DEV = (DEV), XFS_IGET_INO = (INO)
88
89 int
90 xfs_getinode(struct vfs *vfsp, dev_t dev, ino_t inode, struct xfs_inode **ipp)
91 {
92     struct xfs_inode *ip;
93     int error;
94
95     if (!vfsp) {
96         vfsp = vfs_devsearch(dev, xfs_fstype);
97         if (!vfsp) {
98             SET_XFS_ERROR(1, dev, inode);
99             return ENXIO;
100         }
101     }
102
103     if (error = xfs_iget((((struct mount *)
104                            ((vfsp)->vfs_bh.bh_first)->bd_pdata)), (void *)0,
105                          (xfs_ino_t) inode, XFS_ILOCK_SHARED, &ip,
106                          (daddr_t) 0)) {
107         SET_XFS_ERROR(3, vfsp->vfs_dev, inode);
108         return error;
109     }
110
111     *ipp = ip;
112     return 0;
113 }
114
115 /* xfs_igetinode now returns an unlocked inode. This is fine, since we
116  * have a refcount on the holding vnode.
117  */
118 int
119 xfs_igetinode(struct vfs *vfsp, dev_t dev, ino_t inode,
120               struct xfs_inode **ipp)
121 {
122     struct xfs_inode *ip;
123     vnode_t *vp;
124     vattr_t vattr;
125     int error;
126
127     AFS_STATCNT(igetinode);
128
129     *ipp = NULL;
130     if (error = xfs_getinode(vfsp, dev, inode, &ip)) {
131         return error;
132     }
133
134     xfs_iunlock(ip, XFS_ILOCK_SHARED);
135     vp = XFS_ITOV(ip);
136     vattr.va_mask = AT_STAT;
137     AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), error);
138     if (error) {
139         SET_XFS_ERROR(4, vp->v_vfsp->vfs_dev, inode);
140         VN_RELE(vp);
141         return error;
142     }
143     if (vattr.va_nlink == 0 || vattr.va_type != VREG) {
144         SET_XFS_ERROR(5, vp->v_vfsp->vfs_dev, inode);
145         VN_RELE(vp);
146         return ENOENT;
147     }
148
149     *ipp = ip;
150     return 0;
151 }
152
153 /**************************************************************************
154  * inode creation routines.
155  *
156  ***************************************************************************/
157 struct icreateargs {
158     sysarg_t dev;
159     sysarg_t near_inode;
160     sysarg_t param1;
161     sysarg_t param2;
162     sysarg_t param3;
163     sysarg_t param4;
164 };
165
166 int
167 icreate(struct icreateargs *uap, rval_t * rvp)
168 {
169     return ENOSYS;
170 }
171
172 int
173 afs_syscall_icreate(dev, near_inode, param1, param2, param3, param4, rvp)
174      afs_uint32 dev, near_inode, param1, param2, param3, param4;
175      rval_t *rvp;
176 {
177     return ENOSYS;
178 }
179
180 /* inode creation routines for icreatename64 entry point. 
181  * Create a name in the namespace as well as the inode.
182  */
183
184 #include <afs/xfsattrs.h>
185 #include <sys/attributes.h>
186
187 extern char *int_to_base64(char *, int);
188
189 /* Lock against races creating/removing directory - vos zap RO, vos create RW*/
190 kmutex_t afs_vol_create_lock;
191 int afs_vol_create_lock_inited = 0;
192 #define AFS_LOCK_VOL_CREATE() { \
193         if (!afs_vol_create_lock_inited) { \
194             mutex_init(&afs_vol_create_lock, MUTEX_DEFAULT, \
195                        "afs_vol_create_lock"); \
196             afs_vol_create_lock_inited = 1; \
197         } \
198         mutex_enter(&afs_vol_create_lock); \
199                                  }
200 #define AFS_UNLOCK_VOL_CREATE() mutex_exit(&afs_vol_create_lock)
201
202
203 /* xfs_icreatename64
204  * Create an AFS inode in the XFS name space. If required create the proper
205  * containing directory. See sys/xfsattrs.h for the details on the naming
206  * conventions and the usage of file and directory attributes.
207  *
208  * The inode parameters are stored in an XFS attribute called "AFS". In
209  * addition gid is set to XFS_VICEMAGIC and uid is set to the low 31 bits
210  * of the RW volume id. This is so inode verification in iinc and idec
211  * don't need to get the attribute. Note that only the low 31 bits are set.
212  * This is because chmod only accepts up to MAX_UID and chmod is used
213  * to correct these values in xfs_ListViceInodes.
214  */
215 int
216 xfs_icreatename64(struct vfs *vfsp, int datap, int datalen,
217                   afs_inode_params_t params, ino_t * inop)
218 {
219 #define AFS_PNAME_SIZE 16
220     char path[64];
221     char name[64];
222     b64_string_t stmp1, stmp2;
223     afs_xfs_attr_t attrs;
224     struct vattr vattr;
225     int name_version = AFS_XFS_NAME_VERS;
226     int code = 0, unused;
227     struct vnode *vp;
228     struct vnode *dvp;
229     int rw_vno;                 /* volume ID of parent volume */
230     int i;
231     int createdDir = 0;
232     size_t junk;
233     char *s;
234
235
236     /* Get vnode for directory which will contain new inode. */
237     if (datalen >= AFS_PNAME_SIZE)
238         return E2BIG;
239
240     AFS_COPYINSTR((char *)datap, path, AFS_PNAME_SIZE - 1, &junk, unused);
241     if (*path != '/') {
242         return EINVAL;
243     }
244
245     rw_vno = (params[1] == INODESPECIAL) ? params[3] : params[0];
246
247     /* directory name */
248     strcat(path, "/");
249     strcat(path, AFS_INODE_DIR_NAME);
250     strcat(path, int_to_base64(stmp1, rw_vno));
251
252     if (params[1] == INODESPECIAL)
253         AFS_LOCK_VOL_CREATE();
254
255     code = gop_lookupname(path, AFS_UIOSYS, FOLLOW, &dvp);
256     if (code == ENOENT) {
257         /* Maybe it's an old directory name format. */
258         AFS_COPYINSTR((char *)datap, name, AFS_PNAME_SIZE - 1, &junk, unused);
259         strcat(name, "/.");
260         strcat(name, int_to_base64(stmp1, rw_vno));
261         code = gop_lookupname(name, AFS_UIOSYS, FOLLOW, &dvp);
262         if (!code) {
263             /* Use old name format. */
264             strcpy(path, name);
265             name_version = AFS_XFS_NAME_VERS1;
266         }
267     }
268
269     if (code == ENOENT) {
270         afs_xfs_dattr_t dattr;
271         /* make directory. */
272
273         code =
274             AFS_VN_OPEN(path, UIO_SYSSPACE, FCREAT | FEXCL, 0700, &dvp,
275                         CRMKDIR);
276         if (code) {
277             if (code == EEXIST) {
278                 /* someone beat us to it? */
279                 code = gop_lookupname(path, AFS_UIOSYS, NO_FOLLOW, &dvp);
280             }
281             if (code) {
282                 AFS_UNLOCK_VOL_CREATE();
283                 return code;
284             }
285         } else
286             createdDir = 1;
287         memset(&dattr, 0, sizeof(dattr));
288         dattr.atd_version = AFS_XFS_ATD_VERS;
289         dattr.atd_volume = rw_vno;
290         AFS_VOP_ATTR_SET(dvp, AFS_XFS_DATTR, (char *)&dattr,
291                          SIZEOF_XFS_DATTR_T, ATTR_ROOT | ATTR_CREATE,
292                          OSI_GET_CURRENT_CRED(), code);
293         if (code) {
294             VN_RELE(dvp);
295             if (createdDir)
296                 (void)vn_remove(path, UIO_SYSSPACE, RMDIRECTORY);
297             AFS_UNLOCK_VOL_CREATE();
298             return code;
299         }
300     }
301
302     vattr.va_mask = AT_FSID | AT_NODEID;        /* gets a guick return using FSID */
303     AFS_VOP_GETATTR(dvp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
304     if (code) {
305         VN_RELE(dvp);
306         return code;
307     }
308
309     memset(&attrs, 0, sizeof(attrs));
310     attrs.at_pino = vattr.va_nodeid;
311     VN_RELE(dvp);
312
313     /* Create the desired file. Use up to ten tries to create a unique name. */
314     (void)strcpy(name, path);
315     (void)strcat(name, "/.");
316     (void)strcat(name, int_to_base64(stmp2, params[2]));
317     s = &name[strlen(name)];
318
319     attrs.at_tag = 0;           /* Initial guess at a unique tag. */
320     for (i = 0; i < 10; i++) {
321         *s = '\0';
322         strcat(s, ".");
323         strcat(s, int_to_base64(stmp1, attrs.at_tag));
324         code =
325             AFS_VN_OPEN(name, UIO_SYSSPACE, FCREAT | FEXCL, 0600, &vp,
326                         CRCREAT);
327         if (!code || code != EEXIST)
328             break;
329
330         attrs.at_tag++;
331     }
332     /* Unlock the creation process since the directory now has a file in it. */
333     if (params[1] == INODESPECIAL)
334         AFS_UNLOCK_VOL_CREATE();
335
336     if (!code) {
337         /* Set attributes. */
338         memcpy((char *)attrs.at_param, (char *)params,
339                sizeof(afs_inode_params_t));
340         attrs.at_attr_version = AFS_XFS_ATTR_VERS;
341         attrs.at_name_version = name_version;
342         AFS_VOP_ATTR_SET(vp, AFS_XFS_ATTR, (char *)&attrs, SIZEOF_XFS_ATTR_T,
343                          ATTR_ROOT | ATTR_CREATE, OSI_GET_CURRENT_CRED(),
344                          code);
345         if (!code) {
346             vattr.va_mode = 1;
347             vattr.va_uid = AFS_XFS_VNO_CLIP(params[0]);
348             vattr.va_gid = XFS_VICEMAGIC;
349             vattr.va_mask = AT_MODE | AT_UID | AT_GID;
350             AFS_VOP_SETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
351         }
352         if (!code) {
353             vattr.va_mask = AT_NODEID;
354             AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
355         }
356         if (!code)
357             *inop = vattr.va_nodeid;
358         VN_RELE(vp);
359     }
360
361     if (code) {
362         /* remove partially created file. */
363         (void)vn_remove(name, UIO_SYSSPACE, RMFILE);
364
365         /* and directory if volume special file. */
366         if (createdDir) {
367             AFS_LOCK_VOL_CREATE();
368             (void)vn_remove(path, UIO_SYSSPACE, RMDIRECTORY);
369             AFS_UNLOCK_VOL_CREATE();
370         }
371     }
372     return code;
373 }
374
375 /* afs_syscall_icreatename64
376  * This is the icreatename64 entry point used by the XFS
377  * fileserver suite.
378  */
379 int
380 afs_syscall_icreatename64(int dev, int datap, int datalen, int paramp,
381                           int inop)
382 {
383     struct vfs *vfsp;
384     afs_inode_params_t param;
385     int code;
386     rval_t rval;
387     ino_t ino;
388
389
390     if (!afs_suser(NULL))
391         return EPERM;
392
393     vfsp = vfs_devsearch(dev, VFS_FSTYPE_ANY);
394     if (vfsp == NULL) {
395         return ENXIO;
396     }
397
398     AFS_COPYIN((char *)paramp, (char *)param, sizeof(afs_inode_params_t),
399                code);
400     if (vfsp->vfs_fstype == xfs_fstype) {
401         code = xfs_icreatename64(vfsp, datap, datalen, param, &ino);
402         if (code)
403             return code;
404         else {
405             AFS_COPYOUT((char *)&ino, (char *)inop, sizeof(ino_t), code);
406             return code;
407         }
408     }
409     return ENXIO;
410 }
411
412 /*
413  * iopen system calls -- open an inode for reading/writing
414  * Restricted to super user.
415  * Any IFREG files.
416  */
417 struct iopenargs {
418     sysarg_t dev;
419     sysarg_t inode;
420     sysarg_t usrmod;
421 };
422
423 struct iopenargs64 {
424     sysarg_t dev;
425     sysarg_t inode_hi;
426     sysarg_t inode_lo;
427     sysarg_t usrmod;
428 };
429
430 int
431 afs_syscall_iopen(int dev, ino_t inode, int usrmod, rval_t * rvp)
432 {
433     struct file *fp;
434     int fd;
435     int error;
436     struct vfs *vfsp;
437     struct vnode *vp;
438
439     AFS_STATCNT(afs_syscall_iopen);
440     if (!afs_suser(NULL))
441         return EPERM;
442     vfsp = vfs_devsearch(dev, xfs_fstype);
443     if (!vfsp)
444         return ENXIO;
445
446     if (vfsp->vfs_fstype == xfs_fstype) {
447         struct xfs_inode *xip;
448         if (error = xfs_igetinode(vfsp, (dev_t) dev, inode, &xip))
449             return error;
450         vp = XFS_ITOV(xip);
451         if (error = vfile_alloc((usrmod + 1) & (FMASK), &fp, &fd)) {
452             VN_RELE(vp);
453             return error;
454         }
455     } else {
456         osi_Panic("afs_syscall_iopen: bad fstype = %d\n", vfsp->vfs_fstype);
457     }
458     vfile_ready(fp, vp);
459     rvp->r_val1 = fd;
460     return 0;
461 }
462
463 int
464 iopen(struct iopenargs *uap, rval_t * rvp)
465 {
466     AFS_STATCNT(iopen);
467     return (afs_syscall_iopen
468             (uap->dev, (ino_t) uap->inode, uap->usrmod, rvp));
469 }
470
471 int
472 iopen64(struct iopenargs64 *uap, rval_t * rvp)
473 {
474     AFS_STATCNT(iopen);
475     return (afs_syscall_iopen
476             (uap->dev, (ino_t) ((uap->inode_hi << 32) | uap->inode_lo),
477              uap->usrmod, rvp));
478 }
479
480 /*
481  * Support for iinc() and idec() system calls--increment or decrement
482  * count on inode.
483  * Restricted to super user.
484  * Only VICEMAGIC type inodes.
485  */
486
487 /* xfs_iincdec
488  *
489  * XFS iinc/idec code. Uses 64 bit inode numbers. 
490  */
491 static int
492 xfs_iincdec64(struct vfs *vfsp, ino_t inode, int inode_p1, int amount)
493 {
494     vnode_t *vp;
495     xfs_inode_t *ip;
496     int code = 0;
497     afs_xfs_attr_t attrs;
498     int length = SIZEOF_XFS_ATTR_T;
499     afs_xfs_dattr_t dattr;
500     struct vattr vattr;
501     int nlink;
502     int vol;
503
504     code =
505         xfs_iget((((struct mount *)((vfsp)->vfs_bh.bh_first)->bd_pdata)),
506                  (void *)0, (xfs_ino_t) inode, XFS_ILOCK_SHARED, &ip,
507                  (daddr_t) 0);
508     if (code)
509         return code;
510
511     vp = XFS_ITOV(ip);
512     xfs_iunlock(ip, XFS_ILOCK_SHARED);
513
514     vattr.va_mask = AT_GID | AT_UID | AT_MODE;
515     AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
516     if (code)
517         code = EPERM;
518
519     if (!code && (vattr.va_gid != XFS_VICEMAGIC))
520         code = EPERM;
521
522     if (!code && (AFS_XFS_VNO_CLIP(inode_p1) != vattr.va_uid))
523         code = ENXIO;
524
525     if (code) {
526         VN_RELE(vp);
527         return code;
528     }
529
530     nlink = vattr.va_mode & AFS_XFS_MODE_LINK_MASK;
531     nlink += amount;
532     if (nlink > 07) {
533         code = EOVERFLOW;
534     }
535     if (nlink > 0) {
536         vattr.va_mode &= ~AFS_XFS_MODE_LINK_MASK;
537         vattr.va_mode |= nlink;
538         vattr.va_mask = AT_MODE;
539         AFS_VOP_SETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
540         VN_RELE(vp);
541         return code;
542     } else {
543         char path[64];
544         b64_string_t stmp1, stmp2;
545         vnode_t *dvp;
546         xfs_inode_t *ip;
547
548         length = SIZEOF_XFS_ATTR_T;
549         AFS_VOP_ATTR_GET(vp, AFS_XFS_ATTR, (char *)&attrs, &length, ATTR_ROOT,
550                          OSI_GET_CURRENT_CRED(), code);
551         VN_RELE(vp);
552         if (!code) {
553             if (length != SIZEOF_XFS_ATTR_T
554                 || attrs.at_attr_version != AFS_XFS_ATTR_VERS)
555                 return EINVAL;
556         }
557         /* Get the vnode for the directory this file is in. */
558         if (!attrs.at_pino)
559             return ENOENT;
560
561         code = xfs_getinode(vp->v_vfsp, NULL, attrs.at_pino, &ip);
562         if (code)
563             return code;
564
565         dvp = XFS_ITOV(ip);
566         xfs_iunlock(ip, XFS_ILOCK_SHARED);
567
568         /* Verify directory attributes. */
569         length = SIZEOF_XFS_DATTR_T;
570         AFS_VOP_ATTR_GET(dvp, AFS_XFS_DATTR, (char *)&dattr, &length,
571                          ATTR_ROOT, OSI_GET_CURRENT_CRED(), code);
572         if (!code) {
573             if (length != SIZEOF_XFS_DATTR_T
574                 || dattr.atd_version != AFS_XFS_ATD_VERS)
575                 code = ENXIO;
576         }
577         if (code) {
578             VN_RELE(dvp);
579             return code;
580         }
581
582         strcpy(path, ".");
583         strcat(path, int_to_base64(stmp1, attrs.at_param[2]));
584         strcat(path, ".");
585         strcat(path, int_to_base64(stmp1, attrs.at_tag));
586
587         AFS_VOP_REMOVE(dvp, path, OSI_GET_CURRENT_CRED(), code);
588
589         if (!code) {
590             int code2;
591             vattr.va_mask = AT_NLINK;
592             AFS_VOP_GETATTR(dvp, &vattr, 0, OSI_GET_CURRENT_CRED(), code2);
593             if (!code2) {
594                 if (vattr.va_nlink == 2) {
595                     vnode_t *ddvp;      /* parent of volume directory. */
596                     /* Try to remove the directory if this is a volume
597                      * special file. It's ok to fail.
598                      */
599                     AFS_VOP_LOOKUP(dvp, "..", &ddvp, NULL,
600                                    0, OSI_GET_CURRENT_RDIR(),
601                                    OSI_GET_CURRENT_CRED(), code2);
602                     if (!code2) {
603                         VN_RELE(dvp);
604                         dvp = (vnode_t *) 0;
605                         strcpy(path, ".");
606                         if (attrs.at_name_version == AFS_XFS_NAME_VERS2)
607                             strcpy(path, AFS_INODE_DIR_NAME);
608                         else
609                             strcpy(path, ".");
610                         int_to_base64(stmp1,
611                                       (attrs.at_param[1] ==
612                                        INODESPECIAL) ? attrs.
613                                       at_param[3] : attrs.at_param[0]);
614                         strcat(path, stmp1);
615                         AFS_LOCK_VOL_CREATE();
616                         AFS_VOP_RMDIR(ddvp, path, OSI_GET_CURRENT_CDIR(),
617                                       OSI_GET_CURRENT_CRED(), code2);
618                         AFS_UNLOCK_VOL_CREATE();
619                         VN_RELE(ddvp);
620                     }
621                 }
622             }
623         }
624         if (dvp)
625             VN_RELE(dvp);
626     }
627     return code;
628 }
629
630 int
631 iincdec64(int dev, int inode_hi, int inode_lo, int inode_p1, int amount)
632 {
633     struct vfs *vfsp;
634
635     if (!afs_suser(NULL))
636         return EPERM;
637     vfsp = vfs_devsearch(dev, VFS_FSTYPE_ANY);
638     if (!vfsp) {
639         return ENXIO;
640     }
641
642     if (vfsp->vfs_fstype == xfs_fstype) {
643         ino_t inode;
644         inode = inode_hi;
645         inode <<= 32;
646         inode |= inode_lo;
647         return xfs_iincdec64(vfsp, inode, inode_p1, amount);
648     }
649     return ENXIO;
650 }
651
652 int
653 afs_syscall_idec64(int dev, int inode_hi, int inode_lo, int inode_p1)
654 {
655     return iincdec64(dev, inode_hi, inode_lo, inode_p1, -1);
656 }
657
658 int
659 afs_syscall_iinc64(int dev, int inode_hi, int inode_lo, int inode_p1)
660 {
661     return iincdec64(dev, inode_hi, inode_lo, inode_p1, 1);
662 }
663
664 struct iincargs {
665     sysarg_t dev;
666     sysarg_t inode;
667     sysarg_t inode_p1;
668 };
669
670 int
671 iinc(struct iincargs *uap, rval_t * rvp)
672 {
673     AFS_STATCNT(iinc);
674     return ENOTSUP;
675 }
676
677 int
678 idec(struct iincargs *uap, rval_t * rvp)
679 {
680     AFS_STATCNT(idec);
681     return ENOTSUP;
682 }
683
684 /* afs_syscall_ilistinode64
685  * Gathers up all required info for ListViceInodes in one system call.
686  */
687 int
688 afs_syscall_ilistinode64(int dev, int inode_hi, int inode_lo, int datap,
689                          int datalenp)
690 {
691     int code = 0;
692     ino_t inode;
693     xfs_inode_t *ip;
694     vfs_t *vfsp;
695     vnode_t *vp;
696     struct vattr vattr;
697     afs_xfs_attr_t attrs;
698     int length;
699     i_list_inode_t data;
700     int idatalen;
701
702     if (!afs_suser(NULL))
703         return EPERM;
704     vfsp = vfs_devsearch(dev, xfs_fstype);
705     if (!vfsp) {
706         return ENXIO;
707     }
708
709     AFS_COPYIN((char *)datalenp, &idatalen, sizeof(int), code);
710     if (idatalen < sizeof(i_list_inode_t)) {
711         idatalen = sizeof(i_list_inode_t);
712         AFS_COPYOUT((char *)datalenp, (char *)&idatalen, sizeof(int), code);
713         return E2BIG;
714     }
715     idatalen = sizeof(i_list_inode_t);
716     AFS_COPYOUT((char *)datalenp, (char *)&idatalen, sizeof(int), code);
717
718     AFS_COPYIN((char *)datap, (char *)&data, sizeof(i_list_inode_t), code);
719     if (data.ili_version != AFS_XFS_ILI_VERSION) {
720         data.ili_version = AFS_XFS_ILI_VERSION;
721         AFS_COPYOUT((char *)&data, (char *)datap, sizeof(i_list_inode_t),
722                     code);
723         return EINVAL;
724     }
725
726
727     inode = inode_hi;
728     inode <<= 32;
729     inode |= inode_lo;
730     code =
731         xfs_iget((((struct mount *)((vfsp)->vfs_bh.bh_first)->bd_pdata)),
732                  (void *)0, (xfs_ino_t) inode, XFS_ILOCK_SHARED, &ip,
733                  (daddr_t) 0);
734     if (code)
735         return code;
736
737     vp = XFS_ITOV(ip);
738     xfs_iunlock(ip, XFS_ILOCK_SHARED);
739
740     length = SIZEOF_XFS_ATTR_T;
741
742     AFS_VOP_ATTR_GET(vp, AFS_XFS_ATTR, (char *)&attrs, &length, ATTR_ROOT,
743                      OSI_GET_CURRENT_CRED(), code);
744     if (code) {
745         code = EPERM;
746     }
747
748     if (!code) {
749         if (attrs.at_attr_version != AFS_XFS_ATTR_VERS)
750             code = EINVAL;
751     }
752
753     if (!code) {
754         vattr.va_mask = AT_STAT;
755         AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
756     }
757
758     if (!code) {
759         memset(&data, 0, sizeof(data));
760         data.ili_info.inodeNumber = inode;
761         data.ili_info.byteCount = vattr.va_size;
762         data.ili_info.linkCount = (vattr.va_mode & AFS_XFS_MODE_LINK_MASK);
763         memcpy((char *)data.ili_info.param, (char *)attrs.at_param,
764                sizeof(data.ili_info.param));
765         data.ili_attr_version = attrs.at_attr_version;
766         data.ili_name_version = attrs.at_name_version;
767         data.ili_tag = attrs.at_tag;
768         data.ili_pino = attrs.at_pino;
769         data.ili_vno = vattr.va_uid;
770         data.ili_magic = vattr.va_gid;
771         AFS_COPYOUT((char *)&data, (char *)datap, sizeof(data), code);
772     }
773     VN_RELE(vp);
774     return code;
775 }