root/trunk/src/apps/fuse/pvfs2fuse.c @ 9147

Revision 9147, 29.8 KB (checked in by k, 18 months ago)

mtab/fstab file handling:

- Fix segfault that could be triggered by commenting out lines in tab files
- Allow tab and space as tabfile delimiters (previously only allowed space)
- Support the case in which a fuse mount exists but does not have a static tab entry.

Line 
1/*
2 *   PVFS FUSE interface
3 *
4 *
5 *   (C) 2001 Clemson University and The University of Chicago
6 *
7 *   (C) 2007 University of Connecticut. All rights reserved.
8 *
9 *   Author: John A. Chandy
10 *           Sumit Narayan
11 *
12 *   $Date: 2010-12-21 15:34:13 $
13 *   $Revision: 1.3.8.2 $
14 *
15 *   Documentation: http://www.engr.uconn.edu/~sun03001/docs/pvfs2fuse-rpt.pdf
16 */
17
18/* char *pvfs2fuse_version = "$Id: pvfs2fuse.c,v 1.3.8.2 2010-12-21 15:34:13 mtmoore Exp $"; */
19char *pvfs2fuse_version = "0.01";
20
21#define FUSE_USE_VERSION 27
22
23#include <fuse/fuse.h>
24#include <fuse/fuse_opt.h>
25#include <stdlib.h>
26#include <errno.h>
27#include <string.h>
28#include <stdio.h>
29#include <utime.h>
30#include <unistd.h>
31
32#include "pvfs2-compat.h"
33#include "pint-dev-shared.h"
34#include "pint-util.h"
35#include "str-utils.h"
36
37typedef struct {
38          PVFS_object_ref       ref;
39          PVFS_credentials      creds;
40} pvfs_fuse_handle_t;
41
42struct pvfs2fuse {
43          char  *fs_spec;
44          char  *mntpoint;
45          PVFS_fs_id    fs_id;
46          struct PVFS_sys_mntent mntent;
47};
48
49static struct pvfs2fuse pvfs2fuse;
50
51#if __LP64__
52#define SET_FUSE_HANDLE( fi, pfh ) \
53        fi->fh = (uint64_t)pfh
54#define GET_FUSE_HANDLE( fi ) \
55        (pvfs_fuse_handle_t *)fi->fh
56#else
57#define SET_FUSE_HANDLE( fi, pfh ) \
58        *((pvfs_fuse_handle_t **)(&fi->fh)) = pfh
59#define GET_FUSE_HANDLE( fi ) \
60        *((pvfs_fuse_handle_t **)(&fi->fh))
61#endif
62
63#define PVFS_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
64#define THIS_PVFS_VERSION \
65     PVFS_VERSION(PVFS2_VERSION_MAJOR, PVFS2_VERSION_MINOR, PVFS2_VERSION_SUB)
66
67#if THIS_PVFS_VERSION > PVFS_VERSION(2,6,3)
68#define PVFS_ERROR_TO_ERRNO_N(x) (-1)*PVFS_ERROR_TO_ERRNO(x)
69#else
70#define PVFS_ERROR_TO_ERRNO_N(x) PVFS_ERROR_TO_ERRNO(x)
71#endif
72
73static void pvfs_fuse_gen_credentials(
74   PVFS_credentials *credentials)
75{
76   credentials->uid = fuse_get_context()->uid;
77   credentials->gid = fuse_get_context()->gid;
78}
79
80static int lookup( const char *path, pvfs_fuse_handle_t *pfh,
81                                   int32_t follow_link )
82{
83   PVFS_sysresp_lookup lk_response;
84   int                  ret;
85
86   /* we don't have to do a PVFS_util_resolve
87        * because FUSE resolves the path for us
88        */
89
90   pvfs_fuse_gen_credentials(&pfh->creds);
91
92   memset(&lk_response, 0, sizeof(lk_response));
93   ret = PVFS_sys_lookup(pvfs2fuse.fs_id,
94                                                 (char *)path,
95                                                 &pfh->creds,
96                                                 &lk_response,
97                                                 follow_link);
98   if ( ret < 0 ) {
99          return ret;
100   }
101
102   pfh->ref.handle = lk_response.ref.handle;
103   pfh->ref.fs_id  = pvfs2fuse.fs_id;
104
105   return 0;
106}
107
108static int pvfs_fuse_getattr_pfhp(pvfs_fuse_handle_t *pfhp, struct stat *stbuf)
109{
110   PVFS_sysresp_getattr getattr_response;
111   PVFS_sys_attr*       attrs;
112   int                  ret;
113   int                  perm_mode = 0;
114
115   memset(&getattr_response,0, sizeof(PVFS_sysresp_getattr));
116   
117   ret = PVFS_sys_getattr(pfhp->ref,
118                          PVFS_ATTR_SYS_ALL_NOHINT,
119                          (PVFS_credentials *) &pfhp->creds,
120                          &getattr_response);
121   if ( ret < 0 )
122          return PVFS_ERROR_TO_ERRNO_N( ret );
123   
124   memset(stbuf, 0, sizeof(struct stat));
125
126   /* Code copied from kernel/linux-2.x/pvfs2-utils.c */
127
128   /*
129         arbitrarily set the inode block size; FIXME: we need to
130         resolve the difference between the reported inode blocksize
131         and the PAGE_CACHE_SIZE, since our block count will always
132         be wrong.
133
134         For now, we're setting the block count to be the proper
135         number assuming the block size is 512 bytes, and the size is
136         rounded up to the nearest 4K.  This is apparently required
137         to get proper size reports from the 'du' shell utility.
138
139   */
140
141   attrs = &getattr_response.attr;
142   
143   if (attrs->objtype == PVFS_TYPE_METAFILE)
144   {
145          if (attrs->mask & PVFS_ATTR_SYS_SIZE)
146          {
147                 size_t inode_size = attrs->size;
148                 size_t rounded_up_size = (inode_size + (4096 - (inode_size % 4096)));
149
150                 stbuf->st_size = inode_size;
151                 stbuf->st_blocks = (unsigned long)(rounded_up_size / 512);
152          }
153   }
154   else if ((attrs->objtype == PVFS_TYPE_SYMLINK) &&
155                        (attrs->link_target != NULL))
156   {
157          stbuf->st_size = strlen(attrs->link_target);
158   }
159   else
160   {
161      /* what should this be??? */
162          unsigned long PAGE_CACHE_SIZE = 4096;
163          stbuf->st_blocks = (unsigned long)(PAGE_CACHE_SIZE / 512);
164          stbuf->st_size = PAGE_CACHE_SIZE;
165   }
166
167   stbuf->st_uid = attrs->owner;
168   stbuf->st_gid = attrs->group;
169
170   stbuf->st_atime = (time_t)attrs->atime;
171   stbuf->st_mtime = (time_t)attrs->mtime;
172   stbuf->st_ctime = (time_t)attrs->ctime;
173
174   stbuf->st_mode = 0;
175   if (attrs->perms & PVFS_O_EXECUTE)
176          perm_mode |= S_IXOTH;
177   if (attrs->perms & PVFS_O_WRITE)
178          perm_mode |= S_IWOTH;
179   if (attrs->perms & PVFS_O_READ)
180          perm_mode |= S_IROTH;
181
182   if (attrs->perms & PVFS_G_EXECUTE)
183          perm_mode |= S_IXGRP;
184   if (attrs->perms & PVFS_G_WRITE)
185          perm_mode |= S_IWGRP;
186   if (attrs->perms & PVFS_G_READ)
187          perm_mode |= S_IRGRP;
188
189   if (attrs->perms & PVFS_U_EXECUTE)
190          perm_mode |= S_IXUSR;
191   if (attrs->perms & PVFS_U_WRITE)
192          perm_mode |= S_IWUSR;
193   if (attrs->perms & PVFS_U_READ)
194          perm_mode |= S_IRUSR;
195
196   if (attrs->perms & PVFS_G_SGID)
197      perm_mode |= S_ISGID;
198
199   /* Should we honor the suid bit of the file? */
200   /* FIXME should we check the file system suid flag */
201   if ( /* get_suid_flag(inode) == 1 && */ (attrs->perms & PVFS_U_SUID))
202          perm_mode |= S_ISUID;
203
204   stbuf->st_mode |= perm_mode;
205
206   /* FIXME special case: mark the root inode as sticky
207          if (is_root_handle(inode))
208          {
209          inode->i_mode |= S_ISVTX;
210          }
211   */
212   switch (attrs->objtype)
213   {
214          case PVFS_TYPE_METAFILE:
215                 stbuf->st_mode |= S_IFREG;
216                 break;
217          case PVFS_TYPE_DIRECTORY:
218                 stbuf->st_mode |= S_IFDIR;
219                 /* NOTE: we have no good way to keep nlink consistent for
220                  * directories across clients; keep constant at 1.  Why 1?  If
221                  * we go with 2, then find(1) gets confused and won't work
222                  * properly withouth the -noleaf option */
223                 stbuf->st_nlink = 1;
224                 break;
225          case PVFS_TYPE_SYMLINK:
226                 stbuf->st_mode |= S_IFLNK;
227                 break;
228          default:
229                 break;
230   }
231
232   stbuf->st_dev = pfhp->ref.fs_id;
233   stbuf->st_ino = pfhp->ref.handle;
234
235   stbuf->st_rdev = 0;
236   stbuf->st_blksize = 4096;
237
238   PVFS_util_release_sys_attr(attrs);
239   
240   return 0;
241}
242
243static int pvfs_fuse_getattr(const char *path, struct stat *stbuf)
244{
245   int                  ret;
246   pvfs_fuse_handle_t   pfh;
247
248   ret = lookup( path, &pfh, PVFS2_LOOKUP_LINK_NO_FOLLOW );
249   if ( ret < 0 )
250          return PVFS_ERROR_TO_ERRNO_N( ret );
251
252   return pvfs_fuse_getattr_pfhp( &pfh, stbuf );
253}
254
255static int pvfs_fuse_fgetattr(const char *path, struct stat *stbuf,
256                                                          struct fuse_file_info *fi)
257{
258   return pvfs_fuse_getattr_pfhp( GET_FUSE_HANDLE( fi ), stbuf );
259}
260
261static int pvfs_fuse_readlink(const char *path, char *buf, size_t size)
262{
263   PVFS_sysresp_getattr getattr_response;
264   int                  ret;
265   size_t               len;
266   pvfs_fuse_handle_t   pfh;
267
268   ret = lookup( path, &pfh, PVFS2_LOOKUP_LINK_NO_FOLLOW );
269   if ( ret < 0 )
270          return PVFS_ERROR_TO_ERRNO_N( ret );
271   
272   ret = PVFS_sys_getattr(pfh.ref,
273                                                  PVFS_ATTR_SYS_ALL_NOHINT,
274                                                  (PVFS_credentials *) &pfh.creds,
275                                                  &getattr_response);
276   if ( ret < 0 )
277          return PVFS_ERROR_TO_ERRNO_N( ret );
278
279   if (getattr_response.attr.objtype != PVFS_TYPE_SYMLINK)
280          return -EINVAL;
281
282   len = strlen( getattr_response.attr.link_target );
283   if ( len < (size-1) )
284          size = len;
285
286   bcopy( getattr_response.attr.link_target, buf, size );
287
288   buf[len] = '\0';
289
290   return 0;
291}
292
293static int pvfs_fuse_mkdir(const char *path, mode_t mode)
294{
295   int rc;
296   int num_segs;
297   PVFS_sys_attr attr;
298   char parent[PVFS_NAME_MAX];
299   char dirname[PVFS_SEGMENT_MAX];
300   pvfs_fuse_handle_t   parent_pfh;
301
302   PVFS_sysresp_mkdir resp_mkdir;
303
304   /* Translate path into pvfs2 relative path */
305   rc = PINT_get_base_dir((char *)path, parent, PVFS_NAME_MAX);
306   num_segs = PINT_string_count_segments((char *)path);
307   rc = PINT_get_path_element((char *)path, num_segs - 1,
308                                                          dirname, PVFS_SEGMENT_MAX);
309
310   if (rc)
311   {
312          return PVFS_ERROR_TO_ERRNO_N( rc );
313   }
314
315   lookup( parent, &parent_pfh, PVFS2_LOOKUP_LINK_FOLLOW );
316
317   /* Set attributes */
318   memset(&attr, 0, sizeof(PVFS_sys_attr));
319   attr.owner = parent_pfh.creds.uid;
320   attr.group = parent_pfh.creds.gid;
321   attr.perms = mode;
322   attr.mask = PVFS_ATTR_SYS_ALL_SETABLE;
323
324   rc = PVFS_sys_mkdir(dirname,
325                                           parent_pfh.ref,
326                                           attr,
327                                           &parent_pfh.creds,
328                                           &resp_mkdir);
329   if (rc)
330   {
331          return PVFS_ERROR_TO_ERRNO_N( rc );
332   }
333
334   return 0;
335}
336
337static int pvfs_fuse_remove( const char *path )
338{
339   int rc;
340   int num_segs;
341   char parent[PVFS_NAME_MAX];
342   char filename[PVFS_SEGMENT_MAX];
343   pvfs_fuse_handle_t   parent_pfh;
344
345   /* Translate path into pvfs2 relative path */
346   rc = PINT_get_base_dir((char *)path, parent, PVFS_NAME_MAX);
347   num_segs = PINT_string_count_segments((char *)path);
348   rc = PINT_get_path_element((char *)path, num_segs - 1,
349                                                          filename, PVFS_SEGMENT_MAX);
350
351   if (rc)
352   {
353          return PVFS_ERROR_TO_ERRNO_N( rc );
354   }
355
356   lookup( parent, &parent_pfh, PVFS2_LOOKUP_LINK_FOLLOW );
357
358   rc = PVFS_sys_remove(filename, parent_pfh.ref, &parent_pfh.creds);
359   if (rc)
360   {
361          return PVFS_ERROR_TO_ERRNO_N( rc );
362   }
363
364   return 0;
365}
366
367static int pvfs_fuse_unlink(const char *path)
368{
369   return pvfs_fuse_remove(path);
370}
371
372static int pvfs_fuse_rmdir(const char *path)
373{
374   return pvfs_fuse_remove(path);
375}
376
377static int pvfs_fuse_symlink(const char *from, const char *to)
378{
379   int                  ret                        = 0;
380   PVFS_sys_attr        attr;
381   PVFS_sysresp_lookup  resp_lookup;
382   PVFS_object_ref      parent_ref;
383   PVFS_sysresp_symlink resp_sym;
384   PVFS_credentials    credentials;
385   pvfs_fuse_handle_t   dir_pfh;
386   char *tofile, *todir, *cp;
387
388   pvfs_fuse_gen_credentials(&credentials);
389
390   /* Initialize any variables */
391   memset(&attr,        0, sizeof(attr));
392   memset(&resp_lookup, 0, sizeof(resp_lookup));
393   memset(&parent_ref,  0, sizeof(parent_ref));
394   memset(&resp_sym,    0, sizeof(resp_sym));
395
396   /* Set the attributes for the new directory */
397   attr.owner = credentials.uid;
398   attr.group = credentials.gid;
399   attr.perms = 0777;             
400   attr.mask = (PVFS_ATTR_SYS_ALL_SETABLE);
401
402   todir = strdup( to );
403   if ( todir == NULL )
404          return -ENOMEM;
405
406   /* find the last / to get the parent directory */
407   cp = rindex( todir,  '/' );
408   if ( cp == NULL )
409   {
410          free( todir );
411          return -ENOTDIR;
412   }
413   tofile = strdup( cp+1 );
414   if ( cp == todir )
415   {
416          /* we're creating a link at the root, so keep the slash */
417          *(cp+1) = '\0';
418   }
419   else
420   {
421          *cp = '\0';
422   }
423
424   ret = lookup( todir, &dir_pfh, PVFS2_LOOKUP_LINK_FOLLOW );
425   if(ret < 0)
426   {
427          free( tofile );
428          free( todir );
429          PVFS_perror("lookup", ret);
430          return(-1);
431   }
432
433   ret = PVFS_sys_symlink(tofile,
434                                                  dir_pfh.ref,
435                                                  (char *) from,
436                                                  attr,
437                                                  &credentials,
438                                                  &resp_sym);
439
440   if (ret < 0)
441   {
442          PVFS_perror("PVFS_sys_symlink", ret);
443          return(ret);
444   }
445   else
446   {
447          ret = 0;
448   }
449   
450   free( tofile );
451   free( todir );
452   return(ret);
453}
454
455static int pvfs_fuse_rename(const char *from, const char *to)
456{
457   int rc;
458   int num_segs;
459   char fromdir[PVFS_NAME_MAX], todir[PVFS_NAME_MAX];
460   char fromname[PVFS_SEGMENT_MAX], toname[PVFS_SEGMENT_MAX];
461   pvfs_fuse_handle_t   todir_pfh, fromdir_pfh;
462
463   /* Translate path into pvfs2 relative path */
464   rc = PINT_get_base_dir((char *)from, fromdir, PVFS_NAME_MAX);
465   num_segs = PINT_string_count_segments((char *)from);
466   rc = PINT_get_path_element((char *)from, num_segs - 1,
467                                                          fromname, PVFS_SEGMENT_MAX);
468
469   if (rc)
470          return PVFS_ERROR_TO_ERRNO_N( rc );
471
472   rc = lookup( fromdir, &fromdir_pfh, PVFS2_LOOKUP_LINK_FOLLOW );
473   if (rc < 0)
474          return PVFS_ERROR_TO_ERRNO_N( rc );
475
476   /* Translate path into pvfs2 relative path */
477   rc = PINT_get_base_dir((char *)to, todir, PVFS_NAME_MAX);
478   num_segs = PINT_string_count_segments((char *)to);
479   rc = PINT_get_path_element((char *)to, num_segs - 1,
480                                                          toname, PVFS_SEGMENT_MAX);
481
482   if (rc)
483          return PVFS_ERROR_TO_ERRNO_N( rc );
484
485   lookup( todir, &todir_pfh, PVFS2_LOOKUP_LINK_FOLLOW );
486   if (rc < 0)
487          return PVFS_ERROR_TO_ERRNO_N( rc );
488
489   rc = PVFS_sys_rename(fromname,
490                                                fromdir_pfh.ref,
491                                                toname,
492                                                todir_pfh.ref,
493                                                &todir_pfh.creds);
494   if (rc)
495          return PVFS_ERROR_TO_ERRNO_N( rc );
496
497   return 0;
498}
499
500static int pvfs_fuse_chmod(const char *path, mode_t mode)
501{
502   int                  ret;
503   PVFS_sys_attr        new_attr;
504 
505   pvfs_fuse_handle_t   pfh;
506
507   ret = lookup( path, &pfh, PVFS2_LOOKUP_LINK_FOLLOW );
508   if ( ret < 0 )
509          return PVFS_ERROR_TO_ERRNO_N( ret );
510   
511   new_attr.perms = mode;
512   new_attr.mask = PVFS_ATTR_SYS_PERM;
513 
514   ret = PVFS_sys_setattr(pfh.ref,new_attr,&pfh.creds);
515   if (ret < 0)
516          return PVFS_ERROR_TO_ERRNO_N( ret );
517
518   return 0;
519}
520
521static int pvfs_fuse_chown(const char *path, uid_t uid, gid_t gid)
522{
523   int                  ret;
524   PVFS_sys_attr        new_attr;
525 
526   pvfs_fuse_handle_t   pfh;
527
528   ret = lookup( path, &pfh, PVFS2_LOOKUP_LINK_FOLLOW );
529   if ( ret < 0 )
530          return PVFS_ERROR_TO_ERRNO_N( ret );
531   
532   new_attr.owner = uid;
533   new_attr.group = gid;
534   new_attr.mask = PVFS_ATTR_SYS_UID | PVFS_ATTR_SYS_GID;
535 
536   ret = PVFS_sys_setattr(pfh.ref,new_attr,&pfh.creds);
537   if (ret < 0)
538          return PVFS_ERROR_TO_ERRNO_N( ret );
539
540   return 0;
541}
542
543static int pvfs_fuse_truncate(const char *path, off_t size)
544{
545   int                  ret;
546   pvfs_fuse_handle_t   pfh;
547
548   ret = lookup( path, &pfh, PVFS2_LOOKUP_LINK_FOLLOW );
549   if ( ret < 0 )
550          return PVFS_ERROR_TO_ERRNO_N( ret );
551   
552   ret = PVFS_sys_truncate(pfh.ref,size,&pfh.creds);
553   if (ret < 0)
554          return PVFS_ERROR_TO_ERRNO_N( ret );
555
556   return 0;
557}
558
559static int pvfs_fuse_utime(const char *path, struct utimbuf *timbuf)
560{
561   int                  ret;
562   PVFS_sys_attr        new_attr;
563 
564   pvfs_fuse_handle_t   pfh;
565
566   ret = lookup( path, &pfh, PVFS2_LOOKUP_LINK_FOLLOW );
567   if ( ret < 0 )
568          return PVFS_ERROR_TO_ERRNO_N( ret );
569   
570   new_attr.atime = (PVFS_time)timbuf->actime;
571   new_attr.mtime = (PVFS_time)timbuf->modtime;
572   new_attr.mask = PVFS_ATTR_SYS_ATIME | PVFS_ATTR_SYS_MTIME;
573 
574   ret = PVFS_sys_setattr(pfh.ref,new_attr,&pfh.creds);
575   if (ret < 0)
576          return PVFS_ERROR_TO_ERRNO_N( ret );
577
578   return 0;
579}
580
581static int pvfs_fuse_open(const char *path, struct fuse_file_info *fi)
582{
583   pvfs_fuse_handle_t *pfhp;
584   int                  ret;
585
586   pfhp = (pvfs_fuse_handle_t *)malloc( sizeof( pvfs_fuse_handle_t ) );
587   if (pfhp == NULL)
588   {
589          return -ENOMEM;
590   }
591
592   ret = lookup( path, pfhp, PVFS2_LOOKUP_LINK_FOLLOW );
593   if ( ret < 0 ) {
594      free( pfhp );
595      return PVFS_ERROR_TO_ERRNO_N( ret );
596   }
597
598   SET_FUSE_HANDLE( fi, pfhp );
599
600   return 0;
601}
602
603static int pvfs_fuse_read(const char *path, char *buf, size_t size, off_t offset,
604                                                  struct fuse_file_info *fi)
605{
606   PVFS_Request mem_req, file_req;
607   PVFS_sysresp_io      resp_io;
608   int                  ret;
609   pvfs_fuse_handle_t   *pfh = GET_FUSE_HANDLE( fi );
610 
611   file_req = PVFS_BYTE;
612   ret = PVFS_Request_contiguous(size, PVFS_BYTE, &mem_req);
613   if (ret < 0)
614          return PVFS_ERROR_TO_ERRNO_N( ret );
615
616   ret = PVFS_sys_read(pfh->ref, file_req, offset, buf,
617                                           mem_req, &pfh->creds, &resp_io);
618   if (ret == 0)
619   {
620          PVFS_Request_free(&mem_req);
621          return(resp_io.total_completed);
622   }
623   else
624          return PVFS_ERROR_TO_ERRNO_N( ret );
625}
626
627static int pvfs_fuse_write(const char *path, const char *buf, size_t size,
628                                                   off_t offset, struct fuse_file_info *fi)
629{
630   PVFS_Request mem_req, file_req;
631   PVFS_sysresp_io      resp_io;
632   int                  ret;
633   pvfs_fuse_handle_t   *pfh = GET_FUSE_HANDLE( fi );
634 
635   file_req = PVFS_BYTE;
636   ret = PVFS_Request_contiguous(size, PVFS_BYTE, &mem_req);
637   if (ret < 0)
638          return PVFS_ERROR_TO_ERRNO_N( ret );
639
640   ret = PVFS_sys_write(pfh->ref, file_req, offset, (char*)buf,
641                                                mem_req, &pfh->creds, &resp_io);
642   if (ret == 0)
643   {
644          PVFS_Request_free(&mem_req);
645          return(resp_io.total_completed);
646   }
647   else
648          return PVFS_ERROR_TO_ERRNO_N( ret );
649}
650
651static int pvfs_fuse_statfs(const char *path, struct statvfs *stbuf)
652{
653   int                  ret;
654   PVFS_credentials     creds;
655   PVFS_sysresp_statfs resp_statfs;
656
657   pvfs_fuse_gen_credentials(&creds);
658
659   /* gather normal statfs statistics from system interface */
660
661   ret = PVFS_sys_statfs(pvfs2fuse.fs_id, &creds, &resp_statfs);
662   if (ret < 0)
663   {
664          if(ret != ERANGE)
665                 return PVFS_ERROR_TO_ERRNO_N( ret );
666   }
667
668   memcpy(&stbuf->f_fsid, &resp_statfs.statfs_buf.fs_id,
669                  sizeof(resp_statfs.statfs_buf.fs_id));
670   /* FIXME is this bsize right? */
671
672   stbuf->f_bsize = PVFS2_BUFMAP_DEFAULT_DESC_SIZE;
673   stbuf->f_frsize = PVFS2_BUFMAP_DEFAULT_DESC_SIZE;
674   stbuf->f_namemax = PVFS_NAME_MAX;
675
676   stbuf->f_blocks = resp_statfs.statfs_buf.bytes_total / stbuf->f_bsize;
677   stbuf->f_bfree = resp_statfs.statfs_buf.bytes_available / stbuf->f_bsize;
678   stbuf->f_bavail = resp_statfs.statfs_buf.bytes_available / stbuf->f_bsize;
679   stbuf->f_files = resp_statfs.statfs_buf.handles_total_count;
680   stbuf->f_ffree = resp_statfs.statfs_buf.handles_available_count;
681   stbuf->f_favail = resp_statfs.statfs_buf.handles_available_count;
682
683   stbuf->f_flag = 0;
684
685   return 0;
686}
687
688static int pvfs_fuse_release(const char *path, struct fuse_file_info *fi)
689{
690   pvfs_fuse_handle_t *pfh = GET_FUSE_HANDLE( fi );
691 
692   if ( pfh != NULL ) {
693      free( pfh );
694      SET_FUSE_HANDLE( fi, NULL );
695   }
696
697   return 0;
698}
699
700static int pvfs_fuse_fsync(const char *path, int isdatasync,
701                                                   struct fuse_file_info *fi)
702{
703   /* Just a stub.  This method is optional and can safely be left
704          unimplemented */
705
706   (void) path;
707   (void) isdatasync;
708   (void) fi;
709
710   return 0;
711}
712
713#define MAX_NUM_DIRENTS    32
714
715static int pvfs_fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
716                                                         off_t offset, struct fuse_file_info *fi)
717{
718   int                  ret;
719   PVFS_ds_position     token;
720   pvfs_fuse_handle_t   pfh;
721   int                  pvfs_dirent_incount;
722   PVFS_sysresp_readdir rd_response;
723
724   ret = lookup( path, &pfh, PVFS2_LOOKUP_LINK_FOLLOW );
725   if ( ret < 0 )
726          return PVFS_ERROR_TO_ERRNO_N( ret );
727
728   pvfs_dirent_incount = MAX_NUM_DIRENTS;
729   token = 0;
730   do
731   {
732          char *cur_file = NULL;
733          int i;
734
735          memset(&rd_response, 0, sizeof(PVFS_sysresp_readdir));
736          ret = PVFS_sys_readdir(
737                 pfh.ref, (!token ? PVFS_READDIR_START : token),
738                 pvfs_dirent_incount, &pfh.creds, &rd_response);
739          if(ret < 0)
740                 return PVFS_ERROR_TO_ERRNO_N( ret );
741
742          for(i = 0; i < rd_response.pvfs_dirent_outcount; i++)
743          {
744                 cur_file = rd_response.dirent_array[i].d_name;
745
746                 if (filler(buf, cur_file, NULL, 0))
747                        break;
748          }
749          token += rd_response.pvfs_dirent_outcount;
750
751          if (rd_response.pvfs_dirent_outcount)
752          {
753                 free(rd_response.dirent_array);
754                 rd_response.dirent_array = NULL;
755          }
756
757   } while(rd_response.pvfs_dirent_outcount == pvfs_dirent_incount);
758
759   return 0;
760}
761
762static int pvfs_fuse_access(const char *path, int mask)
763{
764   PVFS_sysresp_getattr getattr_response;
765   PVFS_sys_attr*       attrs;
766   int                  ret;
767   pvfs_fuse_handle_t   pfh;
768   int                  in_group_flag = 0;
769
770   ret = lookup( path, &pfh, PVFS2_LOOKUP_LINK_FOLLOW );
771   if ( ret < 0 )
772          return PVFS_ERROR_TO_ERRNO_N( ret );
773
774   /* give root permission, no matter what */
775   if ( pfh.creds.uid == 0 )
776          return 0;
777
778   /* if checking for file existence, return 0 */
779   if ( mask == F_OK )
780          return 0;
781
782   ret = PVFS_sys_getattr(pfh.ref,
783                          PVFS_ATTR_SYS_ALL_NOHINT,
784                          (PVFS_credentials *) &pfh.creds,
785                          &getattr_response);
786   if ( ret < 0 )
787          return PVFS_ERROR_TO_ERRNO_N( ret );
788
789   attrs = &getattr_response.attr;
790
791   /* basic code is copied from PINT_check_mode() */
792
793   /* see if uid matches object owner */
794   if ( attrs->owner == pfh.creds.uid )
795   {
796          /* see if object user permissions match access type */
797          if( (mask & R_OK) && (attrs->perms & PVFS_U_READ))
798          {
799                 return(0);
800          }
801          if( (mask & W_OK) && (attrs->perms & PVFS_U_WRITE))
802          {
803                 return(0);
804          }
805          if( (mask & X_OK) && (attrs->perms & PVFS_U_EXECUTE))
806          {
807                 return(0);
808          }
809   }
810
811   /* see if other bits allow access */
812   if( (mask & R_OK) && (attrs->perms & PVFS_O_READ))
813   {
814          return(0);
815   }
816   if( (mask & W_OK) && (attrs->perms & PVFS_O_WRITE))
817   {
818          return(0);
819   }
820   if( (mask & X_OK) && (attrs->perms & PVFS_O_EXECUTE))
821   {
822          return(0);
823   }
824
825   /* see if gid matches object group */
826   if(attrs->group == pfh.creds.gid)
827   {
828          /* default group match */
829          in_group_flag = 1;
830   }
831   else
832   {
833#if 0
834          /* no default group match, check supplementary groups */
835          ret = PINT_check_group(pfh.creds.uid, attrs->group);
836          if(ret == 0)
837          {
838                 in_group_flag = 1;
839          }
840          else
841          {
842                 if(ret != -PVFS_ENOENT)
843                 {
844                        /* system error; not just failed match */
845                        return(ret);
846                 }
847          }
848#endif
849   }
850
851   if(in_group_flag)
852   {
853          /* see if object group permissions match access type */
854          if( (mask & R_OK) && (attrs->perms & PVFS_G_READ))
855          {
856                 return(0);
857          }
858          if( (mask & W_OK) && (attrs->perms & PVFS_G_WRITE))
859          {
860                 return(0);
861          }
862          if( (mask & X_OK) && (attrs->perms & PVFS_G_EXECUTE))
863          {
864                 return(0);
865          }
866   }
867 
868   /* default case: access denied */
869   return -EACCES;
870}
871
872static int pvfs_fuse_create(const char *path, mode_t mode,
873                                                        struct fuse_file_info *fi)
874{
875   int rc;
876   int num_segs;
877   PVFS_sys_attr attr;
878   char directory[PVFS_NAME_MAX];
879   char filename[PVFS_SEGMENT_MAX];
880   pvfs_fuse_handle_t   dir_pfh, *pfhp;
881
882   PVFS_sysresp_create resp_create;
883
884   /* Translate path into pvfs2 relative path */
885   rc = PINT_get_base_dir((char *)path, directory, PVFS_NAME_MAX);
886   num_segs = PINT_string_count_segments((char *)path);
887   rc = PINT_get_path_element((char *)path, num_segs - 1,
888                                                          filename, PVFS_SEGMENT_MAX);
889
890   if (rc)
891   {
892          return PVFS_ERROR_TO_ERRNO_N( rc );
893   }
894
895   rc = lookup( directory, &dir_pfh, PVFS2_LOOKUP_LINK_FOLLOW );
896   if ( rc < 0 )
897          return PVFS_ERROR_TO_ERRNO_N( rc );
898
899   /* Set attributes */
900   memset(&attr, 0, sizeof(PVFS_sys_attr));
901   attr.owner = dir_pfh.creds.uid;
902   attr.group = dir_pfh.creds.gid;
903   attr.perms = mode;
904   attr.atime = time(NULL);
905   attr.mtime = attr.atime;
906   attr.mask = PVFS_ATTR_SYS_ALL_SETABLE;
907   attr.dfile_count = 0;
908
909   rc = PVFS_sys_create(filename,
910                                                dir_pfh.ref,
911                                                attr,
912                                                &dir_pfh.creds,
913                                                NULL,
914                                                &resp_create);
915   if (rc)
916   {
917      /* FIXME
918       * the PVFS2 server code returns a ENOENT instead of an EACCES
919       * because it does a ACL lookup for the system.posix_acl_access
920       * which returns a ENOENT from the TROVE DBPF and that error is
921       * just passed up in prelude_check_acls (server/prelude.c).  I'm
922       * not sure that's the right thing to do.
923       */
924          if ( rc == -PVFS_ENOENT )
925          {
926                 return -EACCES;
927          }
928          return PVFS_ERROR_TO_ERRNO_N( rc );
929   }
930
931   pfhp = (pvfs_fuse_handle_t *)malloc( sizeof( pvfs_fuse_handle_t ) );
932   if (pfhp == NULL)
933   {
934          return -ENOMEM;
935   }
936
937   pfhp->ref = resp_create.ref;
938   pfhp->creds = dir_pfh.creds;
939
940   SET_FUSE_HANDLE( fi, pfhp );
941
942   return 0;
943}
944
945static struct fuse_operations pvfs_fuse_oper = {
946   .getattr     = pvfs_fuse_getattr,
947   .fgetattr    = pvfs_fuse_fgetattr,
948   .readlink    = pvfs_fuse_readlink,
949   .mkdir       = pvfs_fuse_mkdir,
950   .unlink      = pvfs_fuse_unlink,
951   .rmdir       = pvfs_fuse_rmdir,
952   .symlink     = pvfs_fuse_symlink,
953   .rename      = pvfs_fuse_rename,
954   /* .link     = pvfs_fuse_link, */ /* hard links not supported on PVFS */
955   .chmod       = pvfs_fuse_chmod,
956   .chown       = pvfs_fuse_chown,
957   .truncate    = pvfs_fuse_truncate,
958   .utime       = pvfs_fuse_utime,
959   .open        = pvfs_fuse_open,
960   .read        = pvfs_fuse_read,
961   .write       = pvfs_fuse_write,
962   .statfs      = pvfs_fuse_statfs,
963/*  .flush      = pvfs_fuse_flush, */
964   .release     = pvfs_fuse_release,
965   .fsync       = pvfs_fuse_fsync,
966   .readdir     = pvfs_fuse_readdir,
967   .access      = pvfs_fuse_access,
968   .create      = pvfs_fuse_create,
969};
970
971enum {
972   KEY_HELP,
973   KEY_VERSION,
974};
975
976#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
977#define PVFS2FUSE_OPT(t, p, v) { t, offsetof(struct pvfs2fuse, p), v }
978
979static struct fuse_opt pvfs2fuse_opts[] = {
980   PVFS2FUSE_OPT("fs_spec=%s",     fs_spec, 0),
981
982   FUSE_OPT_KEY("-V",             KEY_VERSION),
983   FUSE_OPT_KEY("--version",      KEY_VERSION),
984   FUSE_OPT_KEY("-h",             KEY_HELP),
985   FUSE_OPT_KEY("--help",         KEY_HELP),
986   FUSE_OPT_END
987};
988
989static void usage(const char *progname)
990{
991   fprintf(stderr,
992                   "usage: %s mountpoint [options]\n"
993                   "\n"
994                   "general options:\n"
995                   "    -o opt,[opt...]        mount options\n"
996                   "    -h   --help            print help\n"
997                   "    -V   --version         print version\n"
998                   "\n"
999                   "PVFS2FUSE options:\n"
1000                   "    -o fs_spec=FS_SPEC     PVFS2 fs_spec URI (eg. tcp://localhost:3334/pvfs2-fs)\n"
1001                   "\n", progname);
1002}
1003
1004static int pvfs_fuse_main(struct fuse_args *args)
1005{
1006#if FUSE_VERSION >= 26
1007   return fuse_main(args->argc, args->argv, &pvfs_fuse_oper, NULL);
1008#else
1009   return fuse_main(args->argc, args->argv, &pvfs_fuse_oper);
1010#endif
1011}
1012
1013static int pvfs2fuse_opt_proc(void *data, const char *arg, int key,
1014                                                          struct fuse_args *outargs)
1015{
1016   (void) data;
1017
1018   switch (key) {
1019          case FUSE_OPT_KEY_OPT:
1020                 return 1;
1021
1022          case FUSE_OPT_KEY_NONOPT:
1023                 if (!pvfs2fuse.mntpoint) {
1024                     if(!arg)
1025                     {
1026                         fprintf(stderr, "PVFS2FUSE requires mountpoint as argument\n");
1027                         abort();
1028                     }
1029
1030            pvfs2fuse.mntpoint = strdup(arg);
1031                 }
1032                 return 1;
1033
1034          case KEY_HELP:
1035                 usage(outargs->argv[0]);
1036                 /* FIXME don't show the FUSE arguments
1037                        fuse_opt_add_arg(outargs, "-ho");
1038                        pvfs_fuse_main(outargs); */
1039                 exit(1);
1040
1041          case KEY_VERSION:
1042                 fprintf(stderr, "PVFS2FUSE version %s (PVFS2 %s) (%s, %s)\n",
1043                                 pvfs2fuse_version, PVFS2_VERSION, __DATE__, __TIME__);
1044#if FUSE_VERSION >= 25
1045                 fuse_opt_add_arg(outargs, "--version");
1046                 pvfs_fuse_main(outargs);
1047#endif
1048                 exit(0);
1049
1050          default:
1051                 fprintf(stderr, "internal error\n");
1052                 abort();
1053   }
1054}
1055
1056int main(int argc, char *argv[])
1057{
1058   int ret;
1059   struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
1060
1061   umask(0);
1062
1063   if (fuse_opt_parse(&args, &pvfs2fuse, pvfs2fuse_opts,
1064                                          pvfs2fuse_opt_proc) == -1 )
1065          exit(1);
1066
1067   if (pvfs2fuse.fs_spec == NULL)
1068   {
1069          ret = PVFS_util_init_defaults();
1070          if(ret < 0)
1071          {
1072                 PVFS_perror("PVFS_util_init_defaults", ret);
1073                 return(-1);
1074          }
1075
1076          ret = PVFS_util_get_default_fsid(&pvfs2fuse.fs_id);
1077          if( ret < 0 )
1078          {
1079                 PVFS_perror("No default PVFS2 filesystem found", ret);
1080                 return(-1);
1081          }
1082
1083          PVFS_util_get_mntent_copy( pvfs2fuse.fs_id, &pvfs2fuse.mntent );
1084          /* Set timeouts for PVFS2's name cache and attribute cache */
1085          PVFS_sys_set_info(PVFS_SYS_ACACHE_TIMEOUT_MSECS, 0);
1086          PVFS_sys_set_info(PVFS_SYS_NCACHE_TIMEOUT_MSECS, 0);
1087   }
1088   else
1089   {
1090          struct PVFS_sys_mntent *me = &pvfs2fuse.mntent;
1091          char *cp;
1092          int cur_server;
1093
1094          /* the following is copied from PVFS_util_init_defaults()
1095                 in fuse/lib/pvfs2-util.c */
1096
1097          /* initialize pvfs system interface */
1098          ret = PVFS_sys_initialize(GOSSIP_NO_DEBUG);
1099          if (ret < 0)
1100          {
1101                 return(ret);
1102          }
1103
1104          /* the following is copied from PVFS_util_parse_pvfstab()
1105                 in fuse/lib/pvfs2-util.c */
1106          memset( me, 0, sizeof(pvfs2fuse.mntent) );
1107
1108          /* Enable integrity checks by default */
1109          me->integrity_check = 1;
1110          /* comma-separated list of ways to contact a config server */
1111          me->num_pvfs_config_servers = 1;
1112
1113          for (cp=pvfs2fuse.fs_spec; *cp; cp++)
1114                 if (*cp == ',')
1115                        ++me->num_pvfs_config_servers;
1116
1117          /* allocate room for our copies of the strings */
1118          me->pvfs_config_servers =
1119                 malloc(me->num_pvfs_config_servers *
1120                                sizeof(*me->pvfs_config_servers));
1121          if (!me->pvfs_config_servers)
1122                 exit(-1);
1123          memset(me->pvfs_config_servers, 0,
1124                         me->num_pvfs_config_servers * sizeof(*me->pvfs_config_servers));
1125
1126          me->mnt_dir = strdup(pvfs2fuse.mntpoint);
1127          me->mnt_opts = NULL;
1128
1129          cp = pvfs2fuse.fs_spec;
1130          cur_server = 0;
1131          for (;;) {
1132                 char *tok;
1133                 int slashcount;
1134                 char *slash;
1135                 char *last_slash;
1136
1137                 tok = strsep(&cp, ",");
1138                 if (!tok) break;
1139
1140                 slash = tok;
1141                 slashcount = 0;
1142                 while ((slash = index(slash, '/')))
1143                 {
1144                        slash++;
1145                        slashcount++;
1146                 }
1147                 if (slashcount != 3)
1148                 {
1149                        fprintf(stderr,"Error: invalid FS spec: %s\n",
1150                                        pvfs2fuse.fs_spec);
1151                        exit(-1);
1152                 }
1153
1154                 /* find a reference point in the string */
1155                 last_slash = rindex(tok, '/');
1156                 *last_slash = '\0';
1157
1158                 /* config server and fs name are a special case, take one
1159                  * string and split it in half on "/" delimiter
1160                  */
1161                 me->pvfs_config_servers[cur_server] = strdup(tok);
1162                 if (!me->pvfs_config_servers[cur_server])
1163                        exit(-1);
1164
1165                 ++last_slash;
1166
1167                 if (cur_server == 0) {
1168                        me->pvfs_fs_name = strdup(last_slash);
1169                        if (!me->pvfs_fs_name)
1170                           exit(-1);
1171                 } else {
1172                        if (strcmp(last_slash, me->pvfs_fs_name) != 0) {
1173                           fprintf(stderr,
1174                                           "Error: different fs names in server addresses: %s\n",
1175                                           pvfs2fuse.fs_spec);
1176                           exit(-1);
1177                        }
1178                 }
1179                 ++cur_server;
1180          }
1181       
1182          /* FIXME flowproto should be an option */
1183          me->flowproto = FLOWPROTO_DEFAULT;
1184
1185          /* FIXME encoding should be an option */
1186          me->encoding = PVFS2_ENCODING_DEFAULT;
1187
1188          /* FIXME default_num_dfiles should be an option */
1189
1190          ret = PVFS_sys_fs_add(me);
1191          if( ret < 0 )
1192          {
1193                 PVFS_perror("Could not add mnt entry", ret);
1194                 return(-1);
1195          }
1196          pvfs2fuse.fs_id = me->fs_id;
1197   }
1198
1199   /* FIXME should we allow all the FUSE options?  Maybe we should
1200        * pass only some of the FUSE options to fuse_main.  For now,
1201        * force the direct_io and allow_other options.  Also turn off
1202        * multithreaded operation since it doesnt work with PVFS.
1203        */
1204
1205   fuse_opt_insert_arg( &args, 1, "-odirect_io" );
1206   fuse_opt_insert_arg( &args, 1, "-oattr_timeout=0");
1207   fuse_opt_insert_arg( &args, 1, "-omax_write=524288");
1208   if ( getpid() == 0 )
1209          fuse_opt_insert_arg( &args, 1, "-oallow_other" );
1210   fuse_opt_insert_arg( &args, 1, "-s" );
1211   
1212   {
1213          /* set the fsname and volname */
1214          char name[200];
1215          char *config = pvfs2fuse.mntent.the_pvfs_config_server;
1216
1217          if ( !config )
1218                 config = pvfs2fuse.mntent.pvfs_config_servers[0];
1219
1220          snprintf( name, 200, "-ofsname=pvfs2fuse#%s/%s", config, pvfs2fuse.mntent.pvfs_fs_name );
1221          fuse_opt_insert_arg( &args, 1, name );
1222#if (__FreeBSD__ >= 10)
1223          snprintf( name, 200, "-ovolname=%s", pvfs2fuse.mntent.pvfs_fs_name );
1224          fuse_opt_insert_arg( &args, 1, name );
1225#endif
1226   }
1227   
1228#if (__FreeBSD__ >= 10)
1229   {
1230          /* MacFUSE has a bug where cached attributes
1231           * arent invalidated on direct_io writes
1232           */
1233          fuse_opt_insert_arg( &args, 1, "-oattr_timeout=0" );
1234   }
1235#endif
1236
1237   return pvfs_fuse_main(&args);
1238}
Note: See TracBrowser for help on using the browser.