Import Upstream version 1.8.5
[hcoop/debian/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 }