Whamcloud - gitweb
import libsysio for b_newsysio
[fs/lustre-release.git] / libsysio / drivers / native / fs_native.c
1 /*
2  *    This Cplant(TM) source code is the property of Sandia National
3  *    Laboratories.
4  *
5  *    This Cplant(TM) source code is copyrighted by Sandia National
6  *    Laboratories.
7  *
8  *    The redistribution of this Cplant(TM) source code is subject to the
9  *    terms of the GNU Lesser General Public License
10  *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
11  *
12  *    Cplant(TM) Copyright 1998-2004 Sandia Corporation. 
13  *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
14  *    license for use of this work by or on behalf of the US Government.
15  *    Export of this program may require a license from the United States
16  *    Government.
17  */
18
19 /*
20  * This library is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU Lesser General Public
22  * License as published by the Free Software Foundation; either
23  * version 2.1 of the License, or (at your option) any later version.
24  * 
25  * This library is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28  * Lesser General Public License for more details.
29  * 
30  * You should have received a copy of the GNU Lesser General Public
31  * License along with this library; if not, write to the Free Software
32  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33  *
34  * Questions or comments about this library should be sent to:
35  *
36  * Lee Ward
37  * Sandia National Laboratories, New Mexico
38  * P.O. Box 5800
39  * Albuquerque, NM 87185-1110
40  *
41  * lee@sandia.gov
42  */
43
44 #ifdef __linux__
45 #define _BSD_SOURCE
46 #endif
47
48 #include <stdio.h>                                      /* for NULL */
49 #include <stdlib.h>
50 #ifdef __linux__
51 #include <string.h>
52 #endif
53 #include <unistd.h>
54 #if !(defined(REDSTORM) || defined(MAX_IOVEC))
55 #include <limits.h>
56 #endif
57 #include <errno.h>
58 #include <assert.h>
59 #include <syscall.h>
60 #include <sys/types.h>
61 #include <sys/stat.h>
62 #include <sys/fcntl.h>
63 #if 0
64 #include <sys/vfs.h>
65 #endif
66 #ifdef _HAVE_STATVFS
67 #include <sys/statvfs.h>
68 #include <sys/statfs.h>
69 #endif
70 #include <utime.h>
71 #include <sys/uio.h>
72 #include <sys/queue.h>
73
74 #include "xtio.h"
75 #include "sysio.h"
76 #include "fs.h"
77 #include "mount.h"
78 #include "inode.h"
79
80 #include "fs_native.h"
81
82 #ifdef REDSTORM
83 #include <sys/uio.h>
84 #endif
85
86 #if defined(SYS_getdirentries)
87 #define DIR_STREAMED 0
88 #define DIR_CVT_64 0
89 #elif defined(SYS_getdents64)
90 #define DIR_STREAMED 1
91 #define DIR_CVT_64 0
92 #elif defined(SYS_getdents)
93 #define DIR_STREAMED 1
94 #if defined(_LARGEFILE64_SOURCE)
95 #define DIR_CVT_64 1
96 /*
97  * Kernel version of directory entry.
98  */
99 struct linux_dirent {
100         unsigned long ld_ino;
101         unsigned long ld_off;
102         unsigned short ld_reclen;
103         char    ld_name[1];
104 };
105 #include <dirent.h>
106 #else /* !defined(_LARGEFILE64_SOURCE) */
107 #define DIR_CVT_64 0
108 #endif /* defined(_LARGEFILE64_SOURCE) */
109 #else /* catch-none */
110 #error No usable directory fill entries interface available
111 #endif
112
113 /*
114  * Local host file system driver.
115  */
116
117 #if defined(ALPHA_LINUX)
118
119 /* stat struct from asm/stat.h, as returned 
120  * by alpha linux kernel
121  */
122 struct __native_stat {
123         unsigned int    st_dev;
124         unsigned int    st_ino;
125         unsigned int    st_mode;
126         unsigned int    st_nlink;
127         unsigned int    st_uid;
128         unsigned int    st_gid;
129         unsigned int    st_rdev;
130         long            st_size;
131         unsigned long   st_atime;
132         unsigned long   st_mtime;
133         unsigned long   st_ctime;
134         unsigned int    st_blksize;
135         int             st_blocks;
136         unsigned int    st_flags;
137         unsigned int    st_gen;
138 };
139
140 #define COPY_STAT(src, dest)                    \
141 do {                                            \
142         memset((dest), 0, sizeof((*dest)));     \
143         (dest)->st_dev     = (src)->st_dev;     \
144         (dest)->st_ino     = (src)->st_ino;     \
145         (dest)->st_mode    = (src)->st_mode;    \
146         (dest)->st_nlink   = (src)->st_nlink;   \
147         (dest)->st_uid     = (src)->st_uid;     \
148         (dest)->st_gid     = (src)->st_gid;     \
149         (dest)->st_rdev    = (src)->st_rdev;    \
150         (dest)->st_size    = (src)->st_size;    \
151         (dest)->st_atime   = (src)->st_atime;   \
152         (dest)->st_mtime   = (src)->st_mtime;   \
153         (dest)->st_ctime   = (src)->st_ctime;   \
154         (dest)->st_blksize = (src)->st_blksize; \
155         (dest)->st_blocks  = (src)->st_blocks;  \
156         (dest)->st_flags   = (src)->st_flags;   \
157         (dest)->st_gen     = (src)->st_gen;     \
158 } while (0);
159
160 #else 
161 #define __native_stat intnl_stat
162 #define COPY_STAT(src, dest) *(dest) = *(src) 
163 #endif
164
165 #if defined(USE_NATIVE_STAT)
166 #define __SYS_STAT SYS_lstat
167 #define __SYS_FSTAT SYS_fstat
168 #define __SYS_TRUNCATE SYS_truncate
169 #define __SYS_FTRUNCATE SYS_ftruncate
170 #else
171 #define __SYS_STAT SYS_lstat64
172 #define __SYS_FSTAT SYS_fstat64
173 #define __SYS_TRUNCATE SYS_truncate64
174 #define __SYS_FTRUNCATE SYS_ftruncate64
175 #endif
176
177 #if defined(USE_NATIVE_FDATASYNC)
178 #define __SYS_FDATASYNC SYS_osf_fdatasync
179 #else
180 #define __SYS_FDATASYNC SYS_fdatasync
181 #endif
182
183 #if defined(USE_NATIVE_UTIME)
184 #define __SYS_UTIME SYS_utimes
185 #else
186 #define __SYS_UTIME SYS_utime
187 #endif
188
189 /*
190  * Native file identifiers format.
191  */
192 struct native_inode_identifier {
193         dev_t   dev;                                    /* device number */
194         ino_t   ino;                                    /* i-number */
195 #ifdef HAVE_GENERATION
196         unsigned int gen;                               /* generation number */
197 #endif
198 };
199
200 /*
201  * Driver-private i-node information we keep about local host file
202  * system objects.
203  */
204 struct native_inode {
205         unsigned
206                 ni_seekok               : 1;            /* can seek? */
207         struct native_inode_identifier ni_ident;        /* unique identifier */
208         struct file_identifier ni_fileid;               /* ditto */
209         int     ni_fd;                                  /* host fildes */
210         int     ni_oflags;                              /* flags, from open */
211         unsigned ni_nopens;                             /* soft ref count */
212         _SYSIO_OFF_T ni_fpos;                           /* current pos */
213         struct intnl_stat ni_stat;                      /* cached attrs */
214 };
215
216 /*
217  * Native IO path arguments.
218  */
219 struct native_io {
220         char    nio_op;                                 /* 'r' or 'w' */
221         struct native_inode *nio_nino;                  /* native ino */
222 };
223
224 static int native_inop_lookup(struct pnode *pno,
225                               struct inode **inop,
226                               struct intent *intnt,
227                               const char *path);
228 static int native_inop_getattr(struct pnode *pno,
229                                struct inode *ino,
230                                struct intnl_stat *stbuf);
231 static int native_inop_setattr(struct pnode *pno,
232                                struct inode *ino,
233                                unsigned mask,
234                                struct intnl_stat *stbuf);
235 static ssize_t native_getdirentries(struct inode *ino,
236                                     char *buf,
237                                     size_t nbytes,
238                                     _SYSIO_OFF_T *basep);
239 static int native_inop_mkdir(struct pnode *pno, mode_t mode);
240 static int native_inop_rmdir(struct pnode *pno);
241 static int native_inop_symlink(struct pnode *pno, const char *data);
242 static int native_inop_readlink(struct pnode *pno, char *buf, size_t bufsiz);
243 static int native_inop_open(struct pnode *pno, int flags, mode_t mode);
244 static int native_inop_close(struct inode *ino);
245 static int native_inop_link(struct pnode *old, struct pnode *new);
246 static int native_inop_unlink(struct pnode *pno);
247 static int native_inop_rename(struct pnode *old, struct pnode *new);
248 static int native_inop_read(struct inode *ino, struct ioctx *ioctx);
249 static int native_inop_write(struct inode *ino, struct ioctx *ioctx);
250 static _SYSIO_OFF_T native_inop_pos(struct inode *ino, _SYSIO_OFF_T off);
251 static int native_inop_iodone(struct ioctx *ioctx);
252 static int native_inop_fcntl(struct inode *ino, int cmd, va_list ap, int *rtn);
253 static int native_inop_sync(struct inode *ino);
254 static int native_inop_datasync(struct inode *ino);
255 static int native_inop_ioctl(struct inode *ino,
256                              unsigned long int request,
257                              va_list ap);
258 static int native_inop_mknod(struct pnode *pno, mode_t mode, dev_t dev);
259 #ifdef _HAVE_STATVFS
260 static int native_inop_statvfs(struct pnode *pno,
261                                struct inode *ino,
262                                struct intnl_statvfs *buf);
263 #endif
264 static void native_inop_gone(struct inode *ino);
265
266 static struct inode_ops native_i_ops = {
267         native_inop_lookup,
268         native_inop_getattr,
269         native_inop_setattr,
270         native_getdirentries,
271         native_inop_mkdir,
272         native_inop_rmdir,
273         native_inop_symlink,
274         native_inop_readlink,
275         native_inop_open,
276         native_inop_close,
277         native_inop_link,
278         native_inop_unlink,
279         native_inop_rename,
280         native_inop_read,
281         native_inop_write,
282         native_inop_pos,
283         native_inop_iodone,
284         native_inop_fcntl,
285         native_inop_sync,
286         native_inop_datasync,
287         native_inop_ioctl,
288         native_inop_mknod,
289 #ifdef _HAVE_STATVFS
290         native_inop_statvfs,
291 #endif
292         native_inop_gone
293 };
294
295 static int native_fsswop_mount(const char *source,
296                                unsigned flags,
297                                const void *data,
298                                struct pnode *tocover,
299                                struct mount **mntp);
300
301 static struct fssw_ops native_fssw_ops = {
302         native_fsswop_mount
303 };
304
305 static void native_fsop_gone(struct filesys *fs);
306
307 static struct filesys_ops native_inodesys_ops = {
308         native_fsop_gone,
309 };
310
311 /*
312  * This example driver plays a strange game. It maintains a private,
313  * internal mount -- It's own separate, rooted, name space. The local
314  * file system's entire name space is available via this tree.
315  *
316  * This simplifies the implementation. At mount time, we need to generate
317  * a path-node to be used as a root. This allows us to look up the needed
318  * node in the host name space and leverage a whole lot of support from
319  * the system.
320  */
321 static struct mount *native_internal_mount = NULL;
322
323 /*
324  * Given i-node, return driver private part.
325  */
326 #define I2NI(ino)       ((struct native_inode *)((ino)->i_private))
327
328 /*
329  * stat -- by path.
330  */
331 static int
332 native_stat(const char *path, struct native_inode *nino, struct intnl_stat *buf)
333 {
334         int     err;
335         struct __native_stat stbuf;
336
337         err = syscall(__SYS_STAT, path, &stbuf);
338         if (err) {
339                 err = -errno;
340                 goto out;
341         }
342         if (!nino) {
343                 COPY_STAT(&stbuf, buf);
344                 goto out;
345         }
346         COPY_STAT(&stbuf, &nino->ni_stat);
347         if (&nino->ni_stat != buf)
348                 (void )memcpy(buf, &nino->ni_stat, sizeof(struct intnl_stat));
349
350 out:
351         return err;
352 }
353
354 /*
355  * stat -- by fildes
356  */
357 static int
358 native_fstat(int fd, struct native_inode *nino, struct intnl_stat *buf)
359 {
360         int     err;
361         struct __native_stat stbuf;
362
363         err = syscall(__SYS_FSTAT, fd, &stbuf);
364         if (err) {
365                 err = -errno;
366                 goto out;
367         }
368         if (!nino) {
369                 COPY_STAT(&stbuf, buf);
370                 goto out;
371         }
372         COPY_STAT(&stbuf, &nino->ni_stat);
373         if (&nino->ni_stat != buf)
374                 (void )memcpy(buf, &nino->ni_stat, sizeof(struct intnl_stat));
375
376 out:
377         return err;
378 }
379
380 /*
381  * Introduce an i-node to the system.
382  */
383 static struct inode *
384 native_i_new(struct filesys *fs, struct intnl_stat *buf)
385 {
386         struct native_inode *nino;
387         struct inode *ino;
388
389         nino = malloc(sizeof(struct native_inode));
390         if (!nino)
391                 return NULL;
392         bzero(&nino->ni_ident, sizeof(nino->ni_ident));
393         nino->ni_ident.dev = buf->st_dev;
394         nino->ni_ident.ino = buf->st_ino;
395 #ifdef HAVE_GENERATION
396         nino->ni_ident.gen = buf->st_gen;
397 #endif
398         nino->ni_fileid.fid_data = &nino->ni_ident;
399         nino->ni_fileid.fid_len = sizeof(nino->ni_ident);
400         nino->ni_fd = -1;
401         nino->ni_oflags = 0;
402         nino->ni_nopens = 0;
403         nino->ni_fpos = 0;
404         (void )memcpy(&nino->ni_stat, buf, sizeof(struct intnl_stat));
405         ino =
406             _sysio_i_new(fs,
407                          &nino->ni_fileid,
408 #ifndef AUTOMOUNT_FILE_NAME
409                          buf->st_mode & S_IFMT,
410 #else
411                          buf->st_mode,                  /* all of the bits! */
412 #endif
413                          buf->st_rdev,
414                          0,
415                          &native_i_ops,
416                          nino);
417         if (!ino)
418                 free(nino);
419         return ino;
420 }
421
422 /*
423  * Initialize this driver.
424  */
425 int
426 _sysio_native_init()
427 {
428
429         /*
430          * Capture current process umask and reset our process umask to
431          * zero. All permission bits to open/creat/setattr are absolute --
432          * They've already had a umask applied, when appropriate.
433          */
434         _sysio_umask = syscall(SYS_umask, 0);
435
436         return _sysio_fssw_register("native", &native_fssw_ops);
437 }
438
439 /*
440  * Create private, internal, view of the hosts name space.
441  */
442 static int
443 create_internal_namespace()
444 {
445         int     err;
446         struct mount *mnt;
447         struct inode *rootino;
448         struct pnode_base *rootpb;
449         static struct qstr noname = { NULL, 0, 0 };
450         struct filesys *fs;
451         struct intnl_stat stbuf;
452
453         if (native_internal_mount) {
454                 /*
455                  * Reentered!
456                  */
457                 abort();
458         }
459
460         /*
461          * We maintain an artificial, internal, name space in order to
462          * have access to fully qualified path names in the various routines.
463          * Initialize that name space now.
464          */
465         mnt = NULL;
466         rootino = NULL;
467         rootpb = NULL;
468         fs = _sysio_fs_new(&native_inodesys_ops, 0, NULL);
469         if (!fs) {
470                 err = -ENOMEM;
471                 goto error;
472         }
473
474         /*
475          * Get root i-node.
476          */
477         err = native_stat("/", NULL, &stbuf);
478         if (err)
479                 goto error;
480         rootino = native_i_new(fs, &stbuf);
481         if (!rootino) {
482                 err = -ENOMEM;
483                 goto error;
484         }
485
486         /*
487          * Generate base path-node for root.
488          */
489         rootpb = _sysio_pb_new(&noname, NULL, rootino);
490         if (!rootpb) {
491                 err = -ENOMEM;
492                 goto error;
493         }
494
495         /*
496          * Mount it. This name space is disconnected from the
497          * rest of the system -- Only available within this driver.
498          */
499         err = _sysio_do_mount(fs, rootpb, 0, NULL, &mnt);
500         if (err)
501                 goto error;
502
503         native_internal_mount = mnt;
504         return 0;
505 error:
506         if (mnt) {
507                 if (_sysio_do_unmount(mnt) != 0)
508                         abort();
509                 fs = NULL;
510                 rootpb = NULL;
511                 rootino = NULL;
512         }
513         if (rootpb)
514                 _sysio_pb_gone(rootpb);
515         if (fs) {
516                 FS_RELE(fs);
517                 _sysio_fs_gone(fs);
518         }
519
520         return err;
521 }
522
523 static int
524 native_fsswop_mount(const char *source,
525                     unsigned flags,
526                     const void *data __IS_UNUSED,
527                     struct pnode *tocover,
528                     struct mount **mntp)
529 {
530         int     err;
531         struct nameidata nameidata;
532         struct mount *mnt;
533
534         /*
535          * Caller must use fully qualified path names when specifying
536          * the source.
537          */
538         if (*source != '/')
539                 return -ENOENT;
540
541         if (!native_internal_mount) {
542                 err = create_internal_namespace();
543                 if (err)
544                         return err;
545         }
546
547         /*
548          * Lookup the source in the internally maintained name space.
549          */
550         ND_INIT(&nameidata, 0, source, native_internal_mount->mnt_root, NULL);
551         err = _sysio_path_walk(native_internal_mount->mnt_root, &nameidata);
552         if (err)
553                 return err;
554
555         /*
556          * Have path-node specified by the given source argument. Let the
557          * system finish the job, now.
558          */
559         err =
560             _sysio_do_mount(native_internal_mount->mnt_fs,
561                             nameidata.nd_pno->p_base,
562                             flags,
563                             tocover,
564                             &mnt);
565         /*
566          * Release the internal name space pnode and clean up any
567          * aliases we might have generated. We really don't need to cache them
568          * as they are only used at mount time..
569          */
570         P_RELE(nameidata.nd_pno);
571         (void )_sysio_p_prune(native_internal_mount->mnt_root);
572
573         if (!err) {
574                 FS_REF(native_internal_mount->mnt_fs);
575                 *mntp = mnt;
576         }
577         return err;
578 }
579
580 static int
581 native_i_invalid(struct inode *inop, struct intnl_stat stbuf)
582 {
583         /*
584          * Validate passed in inode against stat struct info
585          */
586         struct native_inode *nino = I2NI(inop);
587         
588         if ((nino->ni_ident.dev != stbuf.st_dev ||
589              nino->ni_ident.ino != stbuf.st_ino ||
590 #ifdef HAVE_GENERATION
591              nino->ni_ident.gen != stbuf.st_gen ||
592 #endif
593              ((inop)->i_mode & S_IFMT) != (stbuf.st_mode & S_IFMT)) ||
594             (((inop)->i_rdev != stbuf.st_rdev) &&
595                (S_ISCHR((inop)->i_mode) || S_ISBLK((inop)->i_mode))))
596                 return 1;
597         
598         return 0;
599 }
600
601 /*
602  * Find, and validate, or create i-node by host-relative path. Returned i-node
603  * is referenced.
604  */
605 static int
606 native_iget(struct filesys *fs,
607             const char *path,
608             struct inode **inop,
609             int forced)
610 {
611         int     err;
612         struct inode *ino;
613         struct intnl_stat stbuf;
614         struct native_inode_identifier ident;
615         struct file_identifier fileid;
616
617         /*
618          * Get file status.
619          */
620         err = native_stat(path, *inop ? I2NI(*inop) : NULL, &stbuf);
621         if (err) {
622                 *inop = NULL;
623                 return err;
624         }
625
626         /* 
627          * Validate?
628          */
629         if (*inop) {
630                 if (!native_i_invalid(*inop, stbuf))
631                         return 0;
632                 /*
633                  * Invalidate.
634                  */
635                 *inop = NULL;
636         }
637
638         /*
639          * I-node is not already known. Find or create it.
640          */
641         bzero(&ident, sizeof(ident)); 
642         ident.dev = stbuf.st_dev;
643         ident.ino = stbuf.st_ino;
644 #ifdef HAVE_GENERATION
645         ident.gen = stbuf.st_gen;
646 #endif
647         fileid.fid_data = &ident;
648         fileid.fid_len = sizeof(ident);
649         ino = _sysio_i_find(fs, &fileid);
650         if (ino &&
651             (forced || (ino->i_mode & S_IFMT) != (stbuf.st_mode & S_IFMT))) {
652                 /*
653                  * Insertion was forced or dup inum but it's already present!
654                  */
655                 if (native_i_invalid(ino, stbuf)) {
656                         /* 
657                          * Cached inode has stale attrs
658                          * make way for the new one
659                          */
660                         I_GONE(ino);
661                         ino = NULL;
662                 } else
663                         /* 
664                          * OK to reuse cached inode
665                          */
666                         goto out;
667         }
668
669         if (!ino) {
670                 ino = native_i_new(fs, &stbuf);
671                 if (!ino)
672                         err = -ENOMEM;
673         }
674 out:
675         if (!err)
676                 *inop = ino;
677         return err;
678 }
679
680 /*
681  * Look up named object in host's name space by path.
682  */
683 static int
684 native_path_lookup(struct filesys *fs, const char *path, struct inode **inop)
685 {
686
687         return native_iget(fs, path, inop, 0);
688 }
689
690 /*
691  * Look up object by it's path node.
692  */
693 static int
694 native_i_lookup(struct filesys *fs, struct pnode_base *pb, struct inode **inop)
695 {
696         int     err;
697         char    *path;
698
699         path = _sysio_pb_path(pb, '/');
700         if (!path)
701                 return -ENOMEM;
702         err = native_path_lookup(fs, path, inop);
703         free(path);
704         return err;
705 }
706
707 static int
708 native_inop_lookup(struct pnode *pno,
709                    struct inode **inop,
710                    struct intent *intnt __IS_UNUSED,
711                    const char *path __IS_UNUSED)
712 {
713         int     err;
714
715         *inop = pno->p_base->pb_ino;
716
717         /*
718          * Don't have an inode yet. Because we translate everything back to
719          * a single name space for the host, we will assume the object the
720          * caller is looking for has no existing alias in our internal
721          * name space. We don't see the same file on different mounts in the
722          * underlying host FS as the same file.
723          *
724          * The file identifier *will* be unique. It's got to have a different
725          * dev.
726          */
727         err = native_i_lookup(pno->p_mount->mnt_fs, pno->p_base, inop);
728         if (err)
729                 *inop = NULL;
730         return err;
731 }
732
733 static int
734 native_inop_getattr(struct pnode *pno,
735                     struct inode *ino,
736                     struct intnl_stat *stbuf)
737 {
738         char    *path;
739         struct native_inode *nino;
740         int     err;
741
742         nino = ino ? I2NI(ino) : NULL;
743         err = 0;                                        /* compiler cookie */
744         if (!ino) {
745                 path = _sysio_pb_path(pno->p_base, '/');
746                 if (!path)
747                         return -ENOMEM;
748                 err = native_stat(path, nino, stbuf);
749                 free(path);
750         } else if (nino->ni_fd >= 0)
751                 err = native_fstat(nino->ni_fd, nino, stbuf);
752         else {
753                 /*
754                  * Dev inodes don't open in this driver. We won't have
755                  * a file descriptor with which to do the deed then. Satisfy
756                  * the request from the cached copy of the attributes.
757                  */
758                 (void )memcpy(stbuf,
759                               &nino->ni_stat,
760                               sizeof(struct intnl_stat));
761                 err = 0;
762         }
763         
764         return err;
765 }
766
767 static int
768 native_inop_setattr(struct pnode *pno,
769                     struct inode *ino,
770                     unsigned mask,
771                     struct intnl_stat *stbuf)
772 {
773         char    *path;
774         struct native_inode *nino;
775         int     fd;
776         struct intnl_stat *stbp, _stbuf;
777         int     err;
778
779         path = NULL;
780         nino = ino ? I2NI(ino) : NULL;
781         fd = -1;
782         stbp = &_stbuf;
783         if (nino) {
784                 fd = nino->ni_fd;
785                 stbp = &nino->ni_stat;
786         }
787         if (fd < 0 || mask & (SETATTR_MTIME|SETATTR_ATIME)) {
788                 if (!pno)
789                         return -EEXIST;
790                 path = _sysio_pb_path(pno->p_base, '/');
791                 if (!path)
792                         return -ENOMEM;
793         }
794
795         /*
796          * Get current status for undo.
797          */
798         err =
799             fd < 0
800               ? native_stat(path, nino, stbp)
801               : native_fstat(fd, nino, stbp);
802         if (err)
803                 goto out;
804
805         if (mask & SETATTR_MODE) {
806                 mode_t  mode;
807
808                 /*
809                  * Alter permissions attribute.
810                  */
811                 mode = stbuf->st_mode & 07777;
812                 err =
813                     fd < 0
814                       ? syscall(SYS_chmod, path, mode)
815                       : syscall(SYS_fchmod, fd, mode);
816                 if (err)
817                         err = -errno;
818         }
819         if (err)
820                 mask &= ~SETATTR_MODE;
821         else if (mask & (SETATTR_MTIME|SETATTR_ATIME)) {
822                 struct utimbuf ut;
823
824                 /*
825                  * Alter access and/or modify time attributes.
826                  */
827                 ut.actime = stbuf->st_atime;
828                 ut.modtime = stbuf->st_mtime;
829                 if (mask & SETATTR_MTIME)
830                         ut.modtime = stbuf->st_mtime;
831                 if (mask & SETATTR_ATIME)
832                         ut.actime = stbuf->st_atime;
833                 err = syscall(__SYS_UTIME, path, &ut);
834                 if (err)
835                         err = -errno;
836         }
837         if (err)
838                 mask &= ~(SETATTR_MTIME|SETATTR_ATIME);
839         else if (mask & (SETATTR_UID|SETATTR_GID)) {
840
841                 /*
842                  * Alter owner and/or group identifiers.
843                  */
844                 err =
845                     fd < 0
846                       ? syscall(SYS_chown,
847                                 path,
848                                 mask & SETATTR_UID
849                                   ? stbuf->st_uid
850                                   : (uid_t )-1,
851                                 mask & SETATTR_GID
852                                   ? stbuf->st_gid
853                                   : (gid_t )-1)
854                       : syscall(SYS_fchown,
855                                 fd,
856                                 mask & SETATTR_UID
857                                   ? stbuf->st_uid
858                                   : (uid_t )-1,
859                                 mask & SETATTR_GID
860                                   ? stbuf->st_gid
861                                   : (gid_t )-1);
862                 if (err)
863                         err = -errno;
864         }
865         if (err)
866                 mask &= ~(SETATTR_UID|SETATTR_GID);
867         else if (mask & SETATTR_LEN) {
868                 /*
869                  * Do the truncate last. It can't be undone.
870                  */
871                  (void )(fd < 0
872                            ? syscall(__SYS_TRUNCATE, path, stbuf->st_size)
873                            : syscall(__SYS_FTRUNCATE, fd, stbuf->st_size));
874         }
875         if (!err)
876                 goto out;
877         /*
878          * Undo after error. Some or all of this might not work... We
879          * can but try.
880          */
881         if (mask & (SETATTR_UID|SETATTR_GID)) {
882                  (void )(fd < 0
883                            ? syscall(SYS_chown,
884                                      path,
885                                      mask & SETATTR_UID
886                                        ? stbp->st_uid
887                                        : (uid_t )-1,
888                                      mask & SETATTR_GID
889                                        ? stbp->st_gid
890                                        : (gid_t )-1)
891                            : syscall(SYS_fchown,
892                                      fd,
893                                      mask & SETATTR_UID
894                                        ? stbp->st_uid
895                                        : (uid_t )-1,
896                                      mask & SETATTR_GID
897                                        ? stbp->st_gid
898                                        : (gid_t )-1));
899         }
900         if (mask & (SETATTR_MTIME|SETATTR_ATIME)) {
901                 struct utimbuf ut;
902
903                 ut.actime = stbp->st_atime;
904                 ut.modtime = stbp->st_mtime;
905                 (void )syscall(__SYS_UTIME, path, &ut);
906         }
907         if (mask & SETATTR_MODE) {
908                 fd < 0
909                   ? syscall(SYS_chmod, path, stbp->st_mode & 07777)
910                   : syscall(SYS_fchmod, stbp->st_mode & 07777);
911         }
912 out:
913         /*
914          * We must refresh the cached attributes on success.
915          */
916         if (!err && (fd < 0
917                        ? native_stat(path, nino, stbp)
918                        : native_fstat(fd, nino, stbp)) != 0)
919                 abort();
920         if (path)
921                 free(path);
922         return err;
923 }
924
925 static int
926 native_pos(int fd, _SYSIO_OFF_T *offset, int whence)
927 {
928         _SYSIO_OFF_T off;
929
930         assert(fd >= 0);
931         assert(*offset >= 0);
932
933         off = *offset;
934 #if _LARGEFILE64_SOURCE && defined(SYS__llseek)
935         {
936                 int     err;
937                 err =
938                     syscall(SYS__llseek,
939                             (unsigned int)fd,
940                             (unsigned int)(off >> 32),
941                             (unsigned int)off,
942                             &off,
943                             whence);
944                 if (err == -1)
945                         return -errno;
946         }
947 #else
948         off =
949             syscall(SYS_lseek,
950                     fd,
951                     off,
952                     whence);
953         if (off == -1)
954                 return -errno;
955 #endif
956         *offset = off;
957
958         return 0;
959 }
960
961 static ssize_t
962 native_filldirentries(struct native_inode *nino,
963                       char *buf,
964                       size_t nbytes,
965                       _SYSIO_OFF_T *basep)
966 {
967         int     err;
968         ssize_t cc;
969
970         if (*basep < 0)
971                 return -EINVAL;
972
973 #if DIR_STREAMED
974         /*
975          * Stream-oriented access requires that we reposition prior to the
976          * fill call.
977          */
978         if ((err = native_pos(nino->ni_fd, basep, SEEK_SET)) != 0)
979                 return err;
980 #endif
981         nino->ni_fpos = *basep;
982
983         cc =
984 #if defined(SYS_getdirentries)
985             syscall(SYS_getdirentries,
986                     nino->ni_fd,
987                     buf,
988                     nbytes,
989                     basep);
990 #elif defined(SYS_getdents64)
991             syscall(SYS_getdents64, nino->ni_fd, buf, nbytes);
992 #elif defined(SYS_getdents)
993             syscall(SYS_getdents, nino->ni_fd, buf, nbytes);
994 #endif
995
996         if (cc < 0)
997                 return -errno;
998 #if DIR_STREAMED
999         /*
1000          * Stream-oriented access requires that we discover where we are
1001          * after the call.
1002          */
1003         *basep = 0;
1004         if ((err = native_pos(nino->ni_fd, basep, SEEK_CUR)) != 0)
1005                 return err;
1006 #endif
1007         nino->ni_fpos = *basep;
1008         return cc;
1009 }
1010
1011 static ssize_t
1012 native_getdirentries(struct inode *ino,
1013                      char *buf,
1014                      size_t nbytes,
1015                      _SYSIO_OFF_T *basep)
1016 {
1017         struct native_inode *nino = I2NI(ino);
1018 #if DIR_CVT_64
1019         char    *bp;
1020         size_t  count;
1021         struct linux_dirent *ldp;
1022         struct dirent64 *d64p;
1023         size_t  namlen;
1024         size_t  reclen;
1025 #else
1026 #define bp buf
1027 #define count nbytes
1028 #endif
1029         ssize_t cc;
1030
1031         assert(nino->ni_fd >= 0);
1032
1033 #if DIR_CVT_64
1034         count = nbytes;
1035         while (!(bp = malloc(count))) {
1036                 count /= 2;
1037                 if (count < sizeof(struct dirent))
1038                         return -ENOMEM;
1039         }
1040 #endif
1041         cc = native_filldirentries(nino, bp, count, basep);
1042         if (cc < 0) {
1043 #if DIR_CVT_64
1044                 free(bp);
1045 #endif
1046                 return cc;
1047         }
1048 #if DIR_CVT_64
1049         ldp = (struct linux_dirent *)bp;
1050         d64p = (struct dirent64 *)buf;
1051         for (;;) {
1052                 if (cc < 0 || (size_t )cc <= sizeof(*ldp))
1053                         break;
1054                 namlen = strlen(ldp->ld_name);
1055                 reclen = sizeof(*d64p) - sizeof(d64p->d_name) + namlen + 1;
1056                 if (nbytes < reclen)
1057                         break;
1058                 d64p->d_ino = ldp->ld_ino;
1059                 d64p->d_off = ldp->ld_off;
1060                 d64p->d_reclen = 
1061                     (((reclen + sizeof(long) - 1)) / sizeof(long)) *
1062                     sizeof(long);
1063                 if (nbytes < d64p->d_reclen)
1064                         d64p->d_reclen = reclen;
1065                 d64p->d_type = DT_UNKNOWN;              /* you lose -- sorry. */
1066                 (void )strncpy(d64p->d_name, ldp->ld_name, namlen);
1067                 *(d64p->d_name + namlen) = '\0';
1068                 cc -= ldp->ld_reclen;
1069                 ldp = (struct linux_dirent *)((char *)ldp + ldp->ld_reclen);
1070                 nbytes -= d64p->d_reclen;
1071                 d64p = (struct dirent64 *)((char *)d64p + d64p->d_reclen);
1072         }
1073         free(bp);
1074         if (d64p == (struct dirent64 *)buf && cc)
1075                 cc = -EINVAL;                           /* buf too small */
1076         cc = (char *)d64p - buf;
1077 #else
1078 #undef bp
1079 #undef count
1080 #endif
1081         return cc;
1082 }
1083
1084 static int
1085 native_inop_mkdir(struct pnode *pno, mode_t mode)
1086 {
1087         char    *path;
1088         int     err;
1089
1090         path = _sysio_pb_path(pno->p_base, '/');
1091         if (!path)
1092                 return -ENOMEM;
1093
1094         err = syscall(SYS_mkdir, path, mode);
1095         if (err != 0)
1096                 err = -errno;
1097         free(path);
1098         return err;
1099 }
1100
1101 static int
1102 native_inop_rmdir(struct pnode *pno)
1103 {
1104         char    *path;
1105         int     err;
1106
1107         path = _sysio_pb_path(pno->p_base, '/');
1108         if (!path)
1109                 return -ENOMEM;
1110
1111         err = syscall(SYS_rmdir, path);
1112         if (err != 0)
1113                 err = -errno;
1114         free(path);
1115         return err;
1116 }
1117
1118 static int
1119 native_inop_symlink(struct pnode *pno, const char *data)
1120 {
1121         char    *path;
1122         int     err;
1123
1124         path = _sysio_pb_path(pno->p_base, '/');
1125         if (!path)
1126                 return -ENOMEM;
1127
1128         err = syscall(SYS_symlink, data, path);
1129         if (err != 0)
1130                 err = -errno;
1131         free(path);
1132         return err;
1133 }
1134
1135 static int
1136 native_inop_readlink(struct pnode *pno, char *buf, size_t bufsiz)
1137 {
1138         char    *path;
1139         int     i;
1140
1141         path = _sysio_pb_path(pno->p_base, '/');
1142         if (!path)
1143                 return -ENOMEM;
1144         i = syscall(SYS_readlink, path, buf, bufsiz);
1145         if (i < 0)
1146                 i = -errno;
1147         free(path);
1148         return i;
1149 }
1150
1151 static int 
1152 native_inop_open(struct pnode *pno, int flags, mode_t mode)
1153 {
1154         struct native_inode *nino;
1155         char    *path;
1156         int     fd;
1157
1158         path = _sysio_pb_path(pno->p_base, '/');
1159         if (!path)
1160                 return -ENOMEM;
1161
1162         /*
1163          * Whether the file is already open, or not, makes no difference.
1164          * Want to always give the host OS a chance to authorize in case
1165          * something has changed underneath us.
1166          */
1167         if (flags & O_WRONLY) {
1168                 /*
1169                  * Promote write-only attempt to RW.
1170                  */
1171                 flags &= ~O_WRONLY;
1172                 flags |= O_RDWR;
1173         }
1174 #ifdef O_LARGEFILE
1175         flags |= O_LARGEFILE;
1176 #endif
1177         fd = syscall(SYS_open, path, flags, mode);
1178         if (!pno->p_base->pb_ino && fd >= 0) {
1179                 int     err;
1180
1181                 /*
1182                  * Success but we need to return an i-node.
1183                  */
1184                 err =
1185                     native_iget(pno->p_mount->mnt_fs,
1186                                 path,
1187                                 &pno->p_base->pb_ino,
1188                                 1);
1189                 if (err) {
1190                         (void )syscall(SYS_close, fd);
1191                         if (err == -EEXIST)
1192                                 abort();
1193                         fd = err;
1194                 }
1195         }
1196         free(path);
1197         if (fd < 0)
1198                 return -errno;
1199
1200         /*
1201          * Remember this new open.
1202          */
1203         nino = I2NI(pno->p_base->pb_ino);
1204         nino->ni_nopens++;
1205         assert(nino->ni_nopens);
1206
1207         if (nino->ni_fd >= 0) {
1208                 if ((nino->ni_oflags & O_RDWR) ||
1209                     (flags & (O_RDONLY|O_WRONLY|O_RDWR)) == O_RDONLY) {
1210                         /*
1211                          * Keep existing.
1212                          */
1213                         (void )syscall(SYS_close, fd);
1214                         return 0;
1215                 }
1216                 (void )syscall(SYS_close, nino->ni_fd);
1217         }
1218         /*
1219          * Invariant; First open. Must init.
1220          */
1221         nino->ni_fpos = 0;
1222         nino->ni_fd = fd;
1223         /*
1224          * Need to know whether we can seek on this
1225          * descriptor.
1226          */
1227         nino->ni_seekok =
1228             native_pos(nino->ni_fd, &nino->ni_fpos, SEEK_CUR) != 0 ? 0 : 1;
1229
1230         return 0;
1231 }
1232
1233 static int
1234 native_inop_close(struct inode *ino)
1235 {
1236         struct native_inode *nino = I2NI(ino);
1237         int     err;
1238
1239         if (nino->ni_fd < 0)
1240                 abort();
1241
1242         assert(nino->ni_nopens);
1243         if (--nino->ni_nopens) {
1244                 /*
1245                  * Hmmm. We really don't need anything else. However, some
1246                  * filesystems try to implement a sync-on-close semantic.
1247                  * As this appears now, that is lost. Might want to change
1248                  * it somehow in the future?
1249                  */
1250                 return 0;
1251         }
1252
1253         err = syscall(SYS_close, nino->ni_fd);
1254         if (err)
1255                 return -errno;
1256
1257         nino->ni_fd = -1;
1258         nino->ni_fpos = 0;
1259         return 0;
1260 }
1261
1262 static int
1263 native_inop_link(struct pnode *old, struct pnode *new)
1264 {
1265         int     err;
1266         char    *opath, *npath;
1267
1268         err = 0;
1269
1270         opath = _sysio_pb_path(old->p_base, '/');
1271         npath = _sysio_pb_path(new->p_base, '/');
1272         if (!(opath && npath)) {
1273                 err = -ENOMEM;
1274                 goto out;
1275         }
1276
1277         err = syscall(SYS_link, opath, npath);
1278         if (err != 0)
1279                 err = -errno;
1280
1281 out:
1282         if (opath)
1283                 free(opath);
1284         if (npath)
1285                 free(npath);
1286
1287         return err;
1288 }
1289
1290 static int
1291 native_inop_unlink(struct pnode *pno)
1292 {
1293         char    *path;
1294         int     err = 0;
1295
1296         path = _sysio_pb_path(pno->p_base, '/');
1297         if (!path)
1298                 return -ENOMEM;
1299
1300         /*
1301          * For this driver, unlink is easy with open files. Since the
1302          * file remains open to the system, too, the descriptors are still
1303          * valid.
1304          *
1305          * Other drivers will have some difficulty here as the entry in the
1306          * file system name space must be removed without sacrificing access
1307          * to the file itself. In NFS this is done with a mechanism referred
1308          * to as a `silly delete'. The file is moved to a temporary name
1309          * (usually .NFSXXXXXX, where the X's are replaced by the PID and some
1310          * unique characters) in order to simulate the proper semantic.
1311          */
1312         if (syscall(SYS_unlink, path) != 0)
1313                 err = -errno;
1314         free(path);
1315         return err;
1316 }
1317
1318 static int
1319 native_inop_rename(struct pnode *old, struct pnode *new)
1320 {
1321         int     err;
1322         char    *opath, *npath;
1323
1324         opath = _sysio_pb_path(old->p_base, '/');
1325         npath = _sysio_pb_path(new->p_base, '/');
1326         if (!(opath && npath)) {
1327                 err = -ENOMEM;
1328                 goto out;
1329         }
1330
1331         err = syscall(SYS_rename, opath, npath);
1332         if (err != 0)
1333                 err = -errno;
1334
1335 out:
1336         if (opath)
1337                 free(opath);
1338         if (npath)
1339                 free(npath);
1340
1341         return err;
1342 }
1343
1344 static ssize_t
1345 dopio(void *buf, size_t count, _SYSIO_OFF_T off, struct native_io *nio)
1346 {
1347 #if defined(_LARGEFILE64_SOURCE) && \
1348     defined(SYS_pread64) && \
1349     defined(SYS_pwrite64)
1350 #define _NATIVE_SYSCALL_PREAD SYS_pread64
1351 #define _NATIVE_SYSCALL_PWRITE SYS_pwrite64
1352 #else
1353 #define _NATIVE_SYSCALL_PREAD SYS_pread
1354 #define _NATIVE_SYSCALL_PWRITE SYS_pwrite
1355 #endif
1356         ssize_t cc;
1357
1358         if (!(off == nio->nio_nino->ni_fpos || nio->nio_nino->ni_seekok))
1359                 return -ESPIPE;
1360                 
1361         if (!nio->nio_nino->ni_seekok) {
1362                 if (off != nio->nio_nino->ni_fpos) {
1363                         /*
1364                          * They've done a p{read,write} or somesuch. Can't
1365                          * seek on this descriptor so we err out now.
1366                          */
1367                         errno = ESPIPE;
1368                         return -1;
1369                 }
1370                 cc =
1371                     syscall(nio->nio_op == 'r' ? SYS_read : SYS_write,
1372                             nio->nio_nino->ni_fd,
1373                             buf,
1374                             count);
1375                 if (cc > 0)
1376                         nio->nio_nino->ni_fpos += cc;
1377         } else
1378                 cc =
1379                     syscall((nio->nio_op == 'r'
1380                                ? _NATIVE_SYSCALL_PREAD
1381                                : _NATIVE_SYSCALL_PWRITE),
1382                             nio->nio_nino->ni_fd,
1383                             buf,
1384                             count,
1385                             off);
1386
1387         return cc;
1388 #undef _NATIVE_SYSCALL_PREAD
1389 #undef _NATIVE_SYSCALL_PWRITE
1390 }
1391
1392 static ssize_t
1393 doiov(const struct iovec *iov,
1394       int count,
1395       _SYSIO_OFF_T off,
1396       ssize_t limit,
1397       struct native_io *nio)
1398 {
1399         ssize_t cc;
1400
1401 #if !(defined(REDSTORM) || defined(MAX_IOVEC))
1402 #define MAX_IOVEC       INT_MAX
1403 #endif
1404
1405         if (count <= 0)
1406                 return -EINVAL;
1407
1408         /*
1409          * Avoid the reposition call if we're already at the right place.
1410          * Allows us to access pipes and fifos.
1411          */
1412         if (off != nio->nio_nino->ni_fpos) {
1413                 int     err;
1414
1415                 err = native_pos(nio->nio_nino->ni_fd, &off, SEEK_SET);
1416                 if (err)
1417                         return err;
1418                 nio->nio_nino->ni_fpos = off;
1419         }
1420
1421         /*
1422          * The {read,write}v is safe as this routine is only ever called
1423          * by _sysio_enumerate_extents() and that routine is exact. It never
1424          * passes iovectors including tails.
1425          */
1426         cc =
1427 #ifndef REDSTORM
1428             count <= MAX_IOVEC
1429               ? syscall(nio->nio_op == 'r' ? SYS_readv : SYS_writev,
1430                         nio->nio_nino->ni_fd,
1431                         iov,
1432                         count)
1433               :
1434 #endif
1435                 _sysio_enumerate_iovec(iov,
1436                                        count,
1437                                        off,
1438                                        limit,
1439                                        (ssize_t (*)(void *,
1440                                                     size_t,
1441                                                     _SYSIO_OFF_T,
1442                                                     void *))dopio,
1443                                        nio);
1444         if (cc < 0)
1445                 cc = -errno;
1446         else
1447                 nio->nio_nino->ni_fpos += cc;
1448         return cc;
1449
1450 #if !(defined(REDSTORM) || defined(MAX_IOVEC))
1451 #undef MAX_IOVEC
1452 #endif
1453 }
1454
1455 #if 0
1456 static int
1457 lockop_all(struct native_inode *nino,
1458            struct intnl_xtvec *xtv,
1459            size_t count,
1460            short op)
1461 {
1462         struct flock flock;
1463         int     err;
1464
1465         if (!count)
1466                 return -EINVAL;
1467         flock.l_type = op;
1468         flock.l_whence = SEEK_SET;
1469         while (count--) {
1470                 flock.l_start = xtv->xtv_off;
1471                 flock.l_len = xtv->xtv_len;
1472                 xtv++;
1473                 err =
1474                     syscall(
1475 #if !_LARGEFILE64_SOURCE
1476                             SYS_fcntl64
1477 #else
1478                             SYS_fcntl
1479 #endif
1480                             ,
1481                             nino->ni_fd,
1482                             F_SETLK,
1483                             &flock);
1484                 if (err != 0)
1485                         return -errno;
1486         }
1487         return 0;
1488 }
1489
1490 static int
1491 order_xtv(const struct intnl_xtvec *xtv1, const struct intnl_xtvec *xtv2)
1492 {
1493
1494         if (xtv1->xtv_off < xtv2->xtv_off)
1495                 return -1;
1496         if (xtv1->xtv_off > xtv2->xtv_off)
1497                 return 1;
1498         return 0;
1499 }
1500 #endif
1501
1502 static int
1503 doio(char op, struct ioctx *ioctx)
1504 {
1505         struct native_inode *nino;
1506 #if 0
1507         int     dolocks;
1508         struct intnl_xtvec *oxtv;
1509         int     err;
1510 #endif
1511         struct native_io arguments;
1512         ssize_t cc;
1513 #if 0
1514         struct intnl_xtvec *front, *rear, tmp;
1515 #endif
1516
1517         nino = I2NI(ioctx->ioctx_ino);
1518 #if 0
1519         dolocks = ioctx->ioctx_xtvlen > 1 && nino->ni_seekok;
1520         if (dolocks) {
1521                 /*
1522                  * Must lock the regions (in order!) since we can't do
1523                  * strided-IO as a single atomic operation.
1524                  */
1525                 oxtv = malloc(ioctx->ioctx_xtvlen * sizeof(struct intnl_xtvec));
1526                 if (!oxtv)
1527                         return -ENOMEM;
1528                 (void )memcpy(oxtv,
1529                               ioctx->ioctx_xtv, 
1530                               ioctx->ioctx_xtvlen * sizeof(struct intnl_xtvec));
1531                 qsort(oxtv,
1532                       ioctx->ioctx_xtvlen,
1533                       sizeof(struct intnl_xtvec),
1534                       (int (*)(const void *, const void *))order_xtv);
1535                 err =
1536                     lockop_all(nino,
1537                                oxtv, ioctx->ioctx_xtvlen,
1538                                op == 'r' ? F_RDLCK : F_WRLCK);
1539                 if (err) {
1540                         free(oxtv);
1541                         return err;
1542                 }
1543         }
1544 #endif
1545         arguments.nio_op = op;
1546         arguments.nio_nino = nino;
1547         cc =
1548             _sysio_enumerate_extents(ioctx->ioctx_xtv, ioctx->ioctx_xtvlen, 
1549                                      ioctx->ioctx_iov, ioctx->ioctx_iovlen,
1550                                      (ssize_t (*)(const struct iovec *,
1551                                                   int,
1552                                                   _SYSIO_OFF_T,
1553                                                   ssize_t,
1554                                                   void *))doiov,
1555                                      &arguments);
1556 #if 0
1557         if (dolocks) {
1558                 /*
1559                  * Must unlock in reverse order.
1560                  */
1561                 front = oxtv;
1562                 rear = front + ioctx->ioctx_xtvlen - 1;
1563                 while (front < rear) {
1564                         tmp = *front;
1565                         *front++ = *rear;
1566                         *rear-- = tmp;
1567                 }
1568                 if (lockop_all(nino, oxtv, ioctx->ioctx_xtvlen, F_UNLCK) != 0)
1569                         abort();
1570                 free(oxtv);
1571         }
1572 #endif
1573         if ((ioctx->ioctx_cc = cc) < 0) {
1574                 ioctx->ioctx_errno = -ioctx->ioctx_cc;
1575                 ioctx->ioctx_cc = -1;
1576         }
1577         return 0;
1578 }
1579
1580 static int
1581 native_inop_read(struct inode *ino __IS_UNUSED, struct ioctx *ioctx)
1582 {
1583
1584         return doio('r', ioctx);
1585 }
1586
1587 static int
1588 native_inop_write(struct inode *ino __IS_UNUSED, struct ioctx *ioctx)
1589 {
1590
1591         return doio('w', ioctx);
1592 }
1593
1594 static _SYSIO_OFF_T
1595 native_inop_pos(struct inode *ino, _SYSIO_OFF_T off)
1596 {
1597         struct native_inode *nino = I2NI(ino);
1598         int     err;
1599
1600         err = native_pos(nino->ni_fd, &off, SEEK_SET);
1601         return err < 0 ? err : off;
1602 }
1603
1604 static int
1605 native_inop_iodone(struct ioctx *ioctxp __IS_UNUSED)
1606 {
1607
1608         /*
1609          * It's always done in this driver. It completed when posted.
1610          */
1611         return 1;
1612 }
1613
1614 static int
1615 native_inop_fcntl(struct inode *ino,
1616                   int cmd,
1617                   va_list ap,
1618                   int *rtn)
1619 {
1620         struct native_inode *nino = I2NI(ino);
1621         long    arg;
1622         int     err;
1623
1624         if (nino->ni_fd < 0)
1625                 abort();
1626
1627         err = 0;
1628         switch (cmd) {
1629         case F_GETFD:
1630         case F_GETFL:
1631 #ifdef F_GETOWN
1632         case F_GETOWN:
1633 #endif
1634                 *rtn = syscall(SYS_fcntl, nino->ni_fd, cmd);
1635                 if (*rtn == -1)
1636                         err = -errno;
1637                 break;
1638         case F_DUPFD:
1639         case F_SETFD:
1640         case F_SETFL:
1641         case F_GETLK:
1642         case F_SETLK:
1643         case F_SETLKW:
1644 #ifdef F_SETOWN
1645         case F_SETOWN:
1646 #endif
1647                 arg = va_arg(ap, long);
1648                 *rtn = syscall(SYS_fcntl, nino->ni_fd, cmd, arg);
1649                 if (*rtn == -1)
1650                         err = -errno;
1651                 break;
1652         default:
1653                 *rtn = -1;
1654                 err = -EINVAL;
1655         }
1656         return err;
1657 }
1658
1659 static int
1660 native_inop_mknod(struct pnode *pno __IS_UNUSED,
1661                   mode_t mode __IS_UNUSED,
1662                   dev_t dev __IS_UNUSED)
1663 {
1664
1665         return -ENOSYS;
1666 }
1667
1668 #ifdef _HAVE_STATVFS
1669 static int
1670 native_inop_statvfs(struct pnode *pno,
1671                     struct inode *ino,
1672                     struct intnl_statvfs *buf)
1673 {
1674         char    *path;
1675         int    rc;
1676         struct statfs fs;
1677
1678         path = NULL;
1679         if (!ino || I2NI(ino)->ni_fd < 0) {
1680                 path = _sysio_pb_path(pno->p_base, '/');
1681                 if (!path)
1682                         return -ENOMEM;
1683         }
1684
1685         /*
1686          * The syscall interface does not support SYS_fstatvfs.
1687          * Should possibly return ENOSYS, but thought it
1688          * better to use SYS_fstatfs and fill in as much of
1689          * the statvfs structure as possible.  This allows
1690          * for more of a test of the sysio user interface.
1691          */
1692         rc =
1693             path
1694               ? syscall(SYS_statfs, path, &fs)
1695               : syscall(SYS_fstatfs, I2NI(ino)->ni_fd, &fs);
1696         if (path)
1697                 free(path);
1698         if (rc < 0)
1699                 return -errno;
1700
1701         buf->f_bsize = fs.f_bsize;  /* file system block size */
1702         buf->f_frsize = fs.f_bsize; /* file system fundamental block size */
1703         buf->f_blocks = fs.f_blocks;
1704         buf->f_bfree = fs.f_bfree;
1705         buf->f_bavail = fs.f_bavail;
1706         buf->f_files = fs.f_files;  /* Total number serial numbers */
1707         buf->f_ffree = fs.f_ffree;  /* Number free serial numbers */
1708         buf->f_favail = fs.f_ffree; /* Number free ser num for non-privileged*/
1709         buf->f_fsid = fs.f_fsid.__val[1];
1710         buf->f_flag = 0;            /* No equiv in statfs; maybe use type? */
1711         buf->f_namemax = fs.f_namelen;
1712         return 0;
1713 }
1714 #endif
1715
1716 static int
1717 native_inop_sync(struct inode *ino)
1718 {
1719         int     err;
1720
1721         assert(I2NI(ino)->ni_fd >= 0);
1722
1723         err = syscall(SYS_fsync, I2NI(ino)->ni_fd);
1724         if (err)
1725                 err = -errno;
1726         return err;
1727 }
1728
1729 static int
1730 native_inop_datasync(struct inode *ino)
1731 {
1732         int     err;
1733
1734         assert(I2NI(ino)->ni_fd >= 0);
1735
1736 #ifdef NATIVE_FDATASYNC
1737         err = syscall(NATIVE_FDATASYNC, I2NI(ino)->ni_fd);
1738 #else
1739 #if 0
1740 #warning No fdatasync system call -- Using fsync instead!
1741 #endif
1742         err = syscall(SYS_fsync, I2NI(ino)->ni_fd);
1743 #endif
1744         if (err)
1745                 err = -errno;
1746         return err;
1747 }
1748
1749 #ifdef HAVE_LUSTRE_HACK
1750 static int
1751 native_inop_ioctl(struct inode *ino,
1752                   unsigned long int request,
1753                   va_list ap)
1754 {
1755         long arg1, arg2, arg3, arg4;
1756
1757         assert(I2NI(ino)->ni_fd >= 0);
1758
1759         arg1 = va_arg(ap, long);
1760         arg2 = va_arg(ap, long);
1761         arg3 = va_arg(ap, long);
1762         arg4 = va_arg(ap, long);
1763
1764         return syscall(SYS_ioctl, I2NI(ino)->ni_fd, request,
1765                        arg1, arg2, arg3, arg4);
1766 }
1767 #else
1768 static int
1769 native_inop_ioctl(struct inode *ino __IS_UNUSED,
1770                   unsigned long int request __IS_UNUSED,
1771                   va_list ap __IS_UNUSED)
1772 {
1773
1774         /*
1775          * I'm lazy. Maybe implemented later.
1776          */
1777         errno = ENOTTY;
1778         return -1;
1779 }
1780 #endif
1781
1782 static void
1783 native_inop_gone(struct inode *ino)
1784 {
1785         struct native_inode *nino = I2NI(ino);
1786
1787         if (nino->ni_fd >= 0)
1788                 (void )syscall(SYS_close, nino->ni_fd);
1789
1790         free(ino->i_private);
1791 }
1792
1793 static void
1794 native_fsop_gone(struct filesys *fs __IS_UNUSED)
1795 {
1796
1797         /*
1798          * Do nothing. There is no private part maintained for the
1799          * native file interface.
1800          */
1801 }