Exemple #1
0
Fichier : fs.cpp Projet : 8l/vdev
// callback to be fed int vdev_load_all_at.
// builds up the children listing of vdevfs_scandirat_context.parent_dir.
// if we find a directory, open it and enqueue its file descriptor to dir_queue.
// return 0 on success
// return -ENOMEM on OOM
static int vdevfs_scandirat_context_callback( int dirfd, struct dirent* dent, void* cls ) {
   
   struct vdevfs_scandirat_context* ctx = (struct vdevfs_scandirat_context*)cls;
   
   int rc = 0;
   int fd = 0;
   struct stat sb;
   struct fskit_entry* child;
   char linkbuf[8193];            // for resolving an underlying symlink
   char const* method_name;       // for logging
   char* joined_path = NULL;
   
   // skip . and ..
   if( strcmp( dent->d_name, "." ) == 0 || strcmp( dent->d_name, ".." ) == 0 ) {
      return 0;
   }
   
   // learn more...
   rc = fstatat( dirfd, dent->d_name, &sb, AT_SYMLINK_NOFOLLOW );
   if( rc != 0 ) {
      
      rc = -errno;
      
      // mask errors; just log the serious ones
      if( rc != -ENOENT && rc != -EACCES ) {
         
         vdev_error("fstatat(%d, '%s') rc = %d\n", dirfd, dent->d_name, rc );
      }
      
      return 0;
   }
   
   // directory?  get an fd to it if so, so we can keep scanning
   if( S_ISDIR( sb.st_mode ) ) {
      
      // try to get at it 
      fd = openat( dirfd, dent->d_name, O_RDONLY );
      if( fd < 0 ) {
         
         rc = -errno;
         
         // mask errors; just log the serious ones 
         if( rc != -ENOENT && rc != -EACCES ) {
            
            vdev_error("openat(%d, '%s') rc = %d\n", dirfd, dent->d_name, rc );
         }
         
         return 0;
      }
      
      // woo! save it 
      joined_path = vdev_fullpath( ctx->parent_path, dent->d_name, NULL );
      if( joined_path == NULL ) {
         
         close( fd );
         return -ENOMEM;
      }
      
      try {
         
         ctx->dir_paths->push( joined_path );
      }
      catch( bad_alloc& ba ) {
         
         // OOM
         free( joined_path );
         return -ENOMEM;
      }
      
      try {
         
         ctx->dir_queue->push( fd );
      }
      catch( bad_alloc& ba ) {
         
         // OOM 
         close( fd );
         return -ENOMEM;
      }
   }
   
   // construct an inode for this entry 
   child = VDEV_CALLOC( struct fskit_entry, 1 );
   if( child == NULL ) {
      
      return -ENOMEM;
   }
   
   // regular file?
   if( S_ISREG( sb.st_mode ) ) {
      
      method_name = "fskit_entry_init_file";
      rc = fskit_entry_init_file( child, sb.st_ino, dent->d_name, sb.st_uid, sb.st_gid, sb.st_mode & 0777 );
   }
   
   // directory?
   else if( S_ISDIR( sb.st_mode ) ) {
      
      method_name = "fskit_entry_init_dir";
      rc = fskit_entry_init_dir( child, ctx->parent_dir, sb.st_ino, dent->d_name, sb.st_uid, sb.st_gid, sb.st_mode & 0777 );
   }
   
   // named pipe?
   else if( S_ISFIFO( sb.st_mode ) ) {
      
      method_name = "fskit_entry_init_fifo";
      rc = fskit_entry_init_fifo( child, sb.st_ino, dent->d_name, sb.st_uid, sb.st_gid, sb.st_mode & 0777 );
   }
   
   // unix domain socket?
   else if( S_ISSOCK( sb.st_mode ) ) {
      
      method_name = "fskit_entry_init_sock";
      rc = fskit_entry_init_sock( child, sb.st_ino, dent->d_name, sb.st_uid, sb.st_gid, sb.st_mode & 0777 );
   }
   
   // character device?
   else if( S_ISCHR( sb.st_mode ) ) {
      
      method_name = "fskit_entry_init_chr";
      rc = fskit_entry_init_chr( child, sb.st_ino, dent->d_name, sb.st_uid, sb.st_gid, sb.st_mode, sb.st_rdev );
   }
   
   // block device?
   else if( S_ISBLK( sb.st_mode ) ) {
      
      method_name = "fskit_entry_init_blk";
      rc = fskit_entry_init_blk( child, sb.st_ino, dent->d_name, sb.st_uid, sb.st_gid, sb.st_mode, sb.st_rdev );
   }
   
   // symbolic link?
   else if( S_ISLNK( sb.st_mode ) ) {
      
      // read the link first...
      memset( linkbuf, 0, 8193 );
      
      rc = readlinkat( dirfd, dent->d_name, linkbuf, 8192 );
      if( rc < 0 ) {
         
         rc = -errno;
         
         // mask error, but log serious ones.  this link will not appear in the listing 
         if( rc != -ENOENT && rc != -EACCES ) {
            
            vdev_error("readlinkat(%d, '%s') rc = %d\n", dirfd, dent->d_name, rc );
         }
         
         free( child );
         child = NULL;
         
         return 0;
      }
      
      method_name = "fskit_entry_init_symlink";
      rc = fskit_entry_init_symlink( child, sb.st_ino, dent->d_name, linkbuf );
   }
   
   // success?
   if( rc != 0 ) {
      
      vdev_error("%s( on %d, '%s' ) rc = %d\n", method_name, dirfd, dent->d_name, rc );
      
      free( child );
      child = NULL;
      
      return rc;
   }
   
   // insert into parent 
   rc = fskit_entry_attach_lowlevel( ctx->parent_dir, child );
   if( rc != 0 ) {
      
      // OOM 
      fskit_entry_destroy( ctx->core, child, false );
      
      free( child );
      child = NULL;
      
      return rc;
   }
   
   // success!
   return rc;
}
Exemple #2
0
// low-level mkdir: create a child and insert it into the parent.
// parent must be a directory
// parent must be write-locked
// return -EEXIST if an entry with the given name (path_basename) already exists in parent.
// return -EIO if we couldn't allocate an inode
// return -ENOMEM if we couldn't allocate memory
static int fskit_mkdir_lowlevel( struct fskit_core* core, char const* path, struct fskit_entry* parent, char const* path_basename, mode_t mode, uint64_t user, uint64_t group, void* cls ) {

   // resolve the child within the parent
   struct fskit_entry* child = fskit_entry_set_find_name( parent->children, path_basename );
   int err = 0;
   void* app_dir_data = NULL;

   if( child != NULL ) {

      fskit_entry_wlock( child );

      err = fskit_entry_try_garbage_collect( core, path, parent, child );

      if( err >= 0 ) {

         if( err == 0 ) {
            
            // detached but not destroyed
            fskit_entry_unlock( child );
         }

         // name is free
         child = NULL;
      }
      else {
         
         fskit_entry_unlock( child );
         if( err == -EEXIST ) {

            // still exists; can't be garbage-collected
            return -EEXIST;
         }
         else {

            // shouldn't happen
            fskit_error("BUG: fskit_entry_try_garbage_collect(%s) rc = %d\n", path, err );
            return -EIO;
         }
      }
   }

   if( child == NULL ) {

      // create an fskit_entry and attach it
      child = CALLOC_LIST( struct fskit_entry, 1 );
      if( child == NULL ) {
         return -ENOMEM;
      }

      // get an inode for this child
      uint64_t child_inode = fskit_core_inode_alloc( core, parent, child );
      if( child_inode == 0 ) {

         // error in allocation
         fskit_error("fskit_core_inode_alloc(%s) failed\n", path );

         fskit_safe_free( child );

         return -EIO;
      }
      
      // set up the directory
      err = fskit_entry_init_dir( child, parent, child_inode, user, group, mode );
      if( err != 0 ) {
         fskit_error("fskit_entry_init_dir(%s) rc = %d\n", path, err );

         fskit_safe_free( child );
         return err;
      }

      // reference this directory, so it won't disappear during the user's route
      child->open_count++;
      
      // almost done.  run the route callback for this path if needed
      err = fskit_run_user_mkdir( core, path, parent, child, mode, cls, &app_dir_data );
      
      child->open_count--;
      
      if( err != 0 ) {

         // user route failed
         fskit_error("fskit_run_user_mkdir(%s) rc = %d\n", path, err );

         fskit_entry_destroy( core, child, false );
         fskit_safe_free( child );
      }
      else {

         fskit_entry_set_user_data( child, app_dir_data );

         // attach to parent
         fskit_entry_attach_lowlevel( parent, child, path_basename );
      }
   }