| 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 $"; */ |
|---|
| 19 | char *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 | |
|---|
| 37 | typedef struct { |
|---|
| 38 | PVFS_object_ref ref; |
|---|
| 39 | PVFS_credentials creds; |
|---|
| 40 | } pvfs_fuse_handle_t; |
|---|
| 41 | |
|---|
| 42 | struct pvfs2fuse { |
|---|
| 43 | char *fs_spec; |
|---|
| 44 | char *mntpoint; |
|---|
| 45 | PVFS_fs_id fs_id; |
|---|
| 46 | struct PVFS_sys_mntent mntent; |
|---|
| 47 | }; |
|---|
| 48 | |
|---|
| 49 | static 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 | |
|---|
| 73 | static 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 | |
|---|
| 80 | static 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 | |
|---|
| 108 | static 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 | |
|---|
| 243 | static 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 | |
|---|
| 255 | static 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 | |
|---|
| 261 | static 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 | |
|---|
| 293 | static 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 | |
|---|
| 337 | static 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 | |
|---|
| 367 | static int pvfs_fuse_unlink(const char *path) |
|---|
| 368 | { |
|---|
| 369 | return pvfs_fuse_remove(path); |
|---|
| 370 | } |
|---|
| 371 | |
|---|
| 372 | static int pvfs_fuse_rmdir(const char *path) |
|---|
| 373 | { |
|---|
| 374 | return pvfs_fuse_remove(path); |
|---|
| 375 | } |
|---|
| 376 | |
|---|
| 377 | static 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 | |
|---|
| 455 | static 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 | |
|---|
| 500 | static 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 | |
|---|
| 521 | static 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 | |
|---|
| 543 | static 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 | |
|---|
| 559 | static 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 | |
|---|
| 581 | static 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 | |
|---|
| 603 | static 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 | |
|---|
| 627 | static 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 | |
|---|
| 651 | static 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 | |
|---|
| 688 | static 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 | |
|---|
| 700 | static 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 | |
|---|
| 715 | static 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 | |
|---|
| 762 | static 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 | |
|---|
| 872 | static 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 | |
|---|
| 945 | static 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 | |
|---|
| 971 | enum { |
|---|
| 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 | |
|---|
| 979 | static 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 | |
|---|
| 989 | static 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 | |
|---|
| 1004 | static 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 | |
|---|
| 1013 | static 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 | |
|---|
| 1056 | int 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 | } |
|---|