コード例 #1
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Opens a file for read and write

    @param path             Path of the file to open
    @param fi               Informations about the opening action, and filled with addictional
                            data to handle while read(), write() and close()

    @return                 0 if successfull, a negative value otherwise
*/
static int ifs_open (const char *path, struct fuse_file_info *fi)
{
    int res;
    ItemHandler *target;
    OpenedItem *item;

    set_permissions ();

    target = verify_exposed_path (path);
    if (target == NULL)
        return -ENOENT;

    res = item_handler_open (target, fi->flags);
    if (res < 0)
        return res;

    item = allocate_opened_item (target, res);
    if (item == NULL) {
        /*
            In absence of a more specific error, here return the one which is fault by design :-P
            cfr. man 2 open
        */
        return -ENODEV;
    }

    OPENED_ITEM_TO_FI (item, fi);
    return 0;
}
コード例 #2
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Truncate a file to a specified length

    @param path             Path of the file to truncate
    @param size             New size for the file

    @return                 truncate()
*/
static int ifs_truncate (const char *path, off_t size)
{
    ItemHandler *target;

    set_permissions ();
    target = verify_exposed_path (path);
    return item_handler_truncate (target, size);
}
コード例 #3
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Change ownership for a file. This is possible only in temporary paths

    @param path             Path of the file for which modify owner
    @param uid              UID of the new user owner
    @param gid              GID of the new group owner

    @return                 chown(), or -EACCES if the directory is required outside permitted
                            hierarchy
*/
static int ifs_chown (const char *path, uid_t uid, gid_t gid)
{
    ItemHandler *target;

    set_permissions ();
    target = verify_exposed_path (path);
    return item_handler_chown (target, uid, gid);
}
コード例 #4
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Change permissions for a file. This is possible only in temporary paths

    @param path             Path of the file for which modify permissions
    @param mode             New privileges mask to apply

    @return                 chmod(), or -EACCES if the directory is required outside permitted
                            hierarchy
*/
static int ifs_chmod (const char *path, mode_t mode)
{
    ItemHandler *target;

    set_permissions ();
    target = verify_exposed_path (path);
    return item_handler_chmod (target, mode);
}
コード例 #5
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Check permissions for a file

    @param path             Path of the file for which check permissions
    @param mask             Permissions mask to check

    @return                 access()
*/
static int ifs_access (const char *path, int mask)
{
    ItemHandler *target;

    set_permissions ();
    target = verify_exposed_path (path);
    return item_handler_access (target, mask);
}
コード例 #6
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Read the contents of a symbolic link

    @param path             Path of the link to read
    @param buf              String filled with the path pointed by the link
    @param size             Size of the allocation of "buf"

    @return                 0 if successfull, or -EACCES if the directory is required outside
                            permitted hierarchy
*/
static int ifs_readlink (const char *path, char *buf, size_t size)
{
    ItemHandler *target;

    set_permissions ();
    target = verify_exposed_path (path);
    return item_handler_readlink (target, buf, size);
}
コード例 #7
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Retrieve informations about a file

    @param path             Path of the file to check out
    @param stbuf            Struct to fill with informations

    @return                 0 if successful, otherwise a negative value describing the error
*/
static int ifs_getattr (const char *path, struct stat *stbuf)
{
    ItemHandler *target;

    set_permissions ();
    target = verify_exposed_path (path);
    return item_handler_stat (target, stbuf);
}
コード例 #8
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Creates a new hard link. This is possible only in temporary paths

    @param from             Path of the linked file
    @param to               Path of the link

    @return                 link(), or -EACCES if the directory is required outside permitted
                            hierarchy
*/
static int ifs_link (const char *from, const char *to)
{
    set_permissions ();

    /**
        TODO    To be implemented
    */
    return -EACCES;
}
コード例 #9
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Retrieve contents for a folder

    @param path             Path in the filesystem to iterate
    @param buf              Buffer to fill, is used as parameter of "filler"
    @param filler           Callback to call for each found file
    @param offset           Starting offset for reading
    @param fi               Unused

    @return                 0 if successfull, or a negative value
*/
static int ifs_readdir (const char *path, void *buf, fuse_fill_dir_t filler,
                        off_t offset, struct fuse_file_info *fi)
{
    int ret;
    const gchar *name;
    gchar *file_path;
    struct stat st;
    struct stat *ptr_st;
    GList *items;
    GList *iter;
    ItemHandler *target;
    ItemHandler *child;
    NodesCache *cache;

    set_permissions ();
    target = verify_exposed_path (path);

    if (target == NULL) {
        ret = -ENOENT;
    }
    else {
        if (item_handler_is_folder (target) == FALSE) {
            ret = -ENOTDIR;
        }
        else {
            cache = get_cache_reference ();
            items = item_handler_get_children (target);

            for (iter = items; iter; iter = g_list_next (iter)) {
                child = (ItemHandler*) iter->data;

                if (item_handler_get_hidden (child) == TRUE)
                    continue;

                name = item_handler_exposed_name (child);
                if (name == NULL)
                    continue;

                if (item_handler_stat (child, &st) == 0)
                    ptr_st = &st;
                else
                    ptr_st = NULL;

                file_path = g_build_filename (path, name, NULL);
                nodes_cache_set_by_path (cache, child, file_path);

                if (filler (buf, name, ptr_st, 0))
                    break;
            }

            g_list_free (items);
            ret = 0;
        }
    }

    return ret;
}
コード例 #10
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Renames a file. This is possible only in temporary paths

    @param from             Original path of the file
    @param to               Destination path

    @return                 rename(), or -EACCES if the directory is required outside permitted
                            hierarchy
*/
static int ifs_rename (const char *from, const char *to)
{
    int res;
    CONTENT_TYPE start_type;
    ItemHandler *start;
    ItemHandler *target;
    HierarchyNode *start_level;
    HierarchyNode *target_level;

    set_permissions ();

    /*
        Into the effective hierarchy, an existing item can only be moved as another valid
        item. The procedure of metadata guessing in function of the hierarchy path is
        re-executed
    */
    start = verify_exposed_path (from);
    if (start == NULL)
        return -ENOENT;

    /*
        If both paths, origin and destination, refer to something into a mirror folder, so are
        just maps to the real filesystem, a normal rename() is called so to avoid many (useless)
        handling
    */
    start_type = item_handler_get_format (start);
    if ((start_type == ITEM_IS_MIRROR_ITEM || start_type == ITEM_IS_MIRROR_FOLDER)) {
        start_level = item_handler_get_logic_node (start);
        /**
            TODO    Actually this works only for "system_folders" nodes, provide to correct so to
                    be correct also for the "mirror_contents" case
        */
        if (strcmp (hierarchy_node_get_mirror_path (start_level), "/") == 0) {
            target_level = node_at_path (to);
            if (target_level == item_handler_get_logic_node (start)) {
                res = rename (from, to);
                if (res != 0)
                    return -errno;
            }
        }
    }

    target = verify_exposed_path (to);

    if (target == NULL) {
        res = create_item_by_path (to, item_handler_is_folder (start) ? NODE_IS_FOLDER : NODE_IS_FILE, &target);
        if (res != 0)
            return res;
    }

    replace_hierarchy_node (start, target);
    nodes_cache_remove_by_path (get_cache_reference (), from);
    return 0;
}
コード例 #11
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Requires a permanent write of buffered data on the disk

    @param path             Path of the file to sync
    @param isdatasync       Unused
    @param fi               Informations about the opened file
*/
static int ifs_fsync (const char *path, int isdatasync, struct fuse_file_info *fi)
{
    OpenedItem *item;

    FI_TO_OPENED_ITEM (fi, item);
    if (item == NULL)
        return -EBADF;

    set_permissions ();
    return fsync (item->fd);
}
コード例 #12
0
ファイル: qset-acl.c プロジェクト: cooljeanius/emacs
int
qset_acl (char const *name, int desc, mode_t mode)
{
  struct permission_context ctx;
  int ret;

  memset (&ctx, 0, sizeof ctx);
  ctx.mode = mode;
  ret = set_permissions (&ctx, name, desc);
  free_permission_context (&ctx);
  return ret;
}
コード例 #13
0
ファイル: misc.c プロジェクト: balabit/syslog-ng-3.3
/**
 *
 * This function receives a complete path (directory + filename) and creates
 * the directory portion if it does not exist. The point is that the caller
 * wants to ensure that the given filename can be opened after this function
 * returns. (at least it won't fail because of missing directories).
 **/
gboolean
create_containing_directory(gchar *name, gint dir_uid, gint dir_gid, gint dir_mode)
{
  gchar *dirname;
  struct stat st;
  gint rc;
  gchar *p;
  cap_t saved_caps;
  
  /* check that the directory exists */
  dirname = g_path_get_dirname(name);
  rc = stat(dirname, &st);
  g_free(dirname);
  
  if (rc == 0)
    {
      /* directory already exists */
      return TRUE;
    }
  else if (rc < 0 && errno != ENOENT)
    {
      /* some real error occurred */
      return FALSE;
    }
    
  /* directory does not exist */
  p = name + 1;
  
  p = strchr(p, '/');
  while (p) 
    {
      *p = 0;
      if (stat(name, &st) == 0) 
        {
          if (!S_ISDIR(st.st_mode))
            return FALSE;
        }
      else if (errno == ENOENT) 
        {
          if (mkdir(name, dir_mode < 0 ? 0700 : (mode_t) dir_mode) == -1)
            return FALSE;
          saved_caps = g_process_cap_save();
          g_process_cap_modify(CAP_CHOWN, TRUE);
          g_process_cap_modify(CAP_FOWNER, TRUE);
          set_permissions(name, dir_uid, dir_gid, dir_mode);
          g_process_cap_restore(saved_caps);
        }
      *p = '/';
      p = strchr(p + 1, '/');
    }
  return TRUE;
}
コード例 #14
0
ファイル: qcopy-acl.c プロジェクト: 7696122/emacs
int
qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
           int dest_desc, mode_t mode)
{
  struct permission_context ctx;
  int ret;

  ret = get_permissions (src_name, source_desc, mode, &ctx);
  if (ret != 0)
    return -2;
  ret = set_permissions (&ctx, dst_name, dest_desc);
  free_permission_context (&ctx);
  return ret;
}
コード例 #15
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Change file last access and modification times

    @param path             Path of the file for which modify times
    @param ts               New times

    @return                 utimes()
*/
static int ifs_utimens (const char *path, const struct timespec ts[2])
{
    struct timeval tv [2];
    ItemHandler *target;

    tv [0].tv_sec = ts [0].tv_sec;
    tv [0].tv_usec = ts [0].tv_nsec / 1000;
    tv [1].tv_sec = ts [1].tv_sec;
    tv [1].tv_usec = ts [1].tv_nsec / 1000;

    set_permissions ();
    target = verify_exposed_path (path);
    return item_handler_utimes (target, tv);
}
コード例 #16
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    To flush an opened file

    @param path             Path of the file to flush
    @param fi               Informations about the opened file

    @return                 0 if successful, otherwise a negative value describing the error
*/
static int ifs_flush (const char *path, struct fuse_file_info *fi)
{
    OpenedItem *item;

    FI_TO_OPENED_ITEM (fi, item);
    if (item == NULL)
        return -EBADF;

    set_permissions ();

    if (fsync (item->fd) != 0)
        return errno * -1;

    return 0;
}
コード例 #17
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Retrieve informations about the filesystem

    @param path             Path of a reference file
    @param stbuf            Structure to be filled with informations about the filesystem
*/
static int ifs_statfs (const char *path, struct statvfs *stbuf)
{
    int res;

    set_permissions ();

    /**
        TODO    Customize data into stbuf
    */

    res = statvfs(path, stbuf);
    if (res == -1)
        return -errno;

    return 0;
}
コード例 #18
0
AditionalFileDialog::AditionalFileDialog(QWidget *parent, QString a_file, QMap<PisiSPBase::AFileAttr, QString> attr) :
    QDialog(parent),
    ui(new Ui::AditionalFileDialog),
    a_file(a_file),
    attr(attr)
{
    ui->setupUi(this);

    ui->le_file->setText(a_file);
    ui->le_target->setText(attr.value(PisiSPBase::TARGET));
    set_permissions(attr.value(PisiSPBase::PERMISSION));
    ui->le_owner->setText(attr.value(PisiSPBase::OWNER));
    ui->le_group->setText(attr.value(PisiSPBase::GROUP));

    connect(this, SIGNAL(accepted()), SLOT(dialog_accepted()));
}
コード例 #19
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Read bytes from an opened file

    @param path             Path of the file from which read data
    @param buf              Buffer to fill with read bytes
    @param size             Size of the allocation of "buf"
    @param offset           Starting position for the read
    @param fi               Contains informations about the opened file, such as assigned in
                            ifs_open() or ifs_create()

    @return                 pread()
*/
static int ifs_read (const char *path, char *buf, size_t size, off_t offset,
                     struct fuse_file_info *fi)
{
    int res;
    OpenedItem *item;

    set_permissions ();

    FI_TO_OPENED_ITEM (fi, item);
    if (item == NULL)
        return -EBADF;

    res = pread (item->fd, buf, size, offset);
    if (res == -1)
        res = -errno;

    return res;
}
コード例 #20
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Removes a folder and all its contents. This is possible only in temporary paths

    @param path             Path of the directory to remove

    @return                 rmdir(), or -EACCES if the directory is required outside permitted
                            hierarchy
*/
static int ifs_rmdir (const char *path)
{
    int ret;
    ItemHandler *target;

    set_permissions ();
    target = verify_exposed_path (path);

    if (target != NULL && item_handler_is_folder (target)) {
        item_handler_remove (target);
        nodes_cache_remove_by_path (get_cache_reference (), path);
        ret = 0;
    }
    else {
        ret = -ENOTDIR;
    }

    return ret;
}
コード例 #21
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Truncate a file to a specified length

    @param path             Path of the file to truncate
    @param size             New size for the file
    @param fi               Informations about the file to truncate

    @return                 ftruncate()
*/
static int ifs_ftruncate (const char *path, off_t size, struct fuse_file_info *fi)
{
    int ret;
    OpenedItem *item;

    FI_TO_OPENED_ITEM (fi, item);

    if (item == NULL) {
        /*
            Just as a safety belt: if something happened to the file
            descriptor, lets truncate the file using the path
        */
        ret = ifs_truncate (path, size);
    }
    else {
        set_permissions ();
        ret = ftruncate (item->fd, size);
    }

    return ret;
}
コード例 #22
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Write bytes to an opened file

    @param path             Path of the file in which write data
    @param buf              Buffer with bytes to write
    @param size             Size of the allocation of "buf"
    @param offset           Starting position for the write
    @param fi               Contains informations about the opened file, such as assigned in
                            ifs_open() or ifs_create()

    @return                 pwrite()
*/
static int ifs_write (const char *path, const char *buf, size_t size, off_t offset,
                      struct fuse_file_info *fi)
{
    int res;
    OpenedItem *item;

    set_permissions ();

    FI_TO_OPENED_ITEM (fi, item);
    if (item == NULL)
        return -EBADF;

    /*
        Remember about splice(2) for future COW implementation
    */

    res = pwrite (item->fd, buf, size, offset);
    if (res == -1)
        res = -errno;

    return res;
}
コード例 #23
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Creates a new file

    @param path             Path for the new file
    @param mask             Permissions mask for the new element
    @param fi               Informations about the creating action, and filled with addictional
                            data to handle while read(), write() and close()

    @return                 0 if successfull, a negative value otherwise
*/
static int ifs_create (const char *path, mode_t mask, struct fuse_file_info *fi)
{
    int res;
    ItemHandler *target;
    OpenedItem *item;

    set_permissions ();
    res = create_item_by_path (path, NODE_IS_FILE, &target);
    if (res != 0)
        return res;

    res = item_handler_open (target, fi->flags & ~O_CREAT);
    if (res < 0)
        return res;

    item = allocate_opened_item (target, res);
    if (item == NULL)
        return -ENODEV;

    OPENED_ITEM_TO_FI (item, fi);
    return 0;
}
コード例 #24
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Closes a file opened with ifs_open() or ifs_create()

    @param path             Path of the file to close
    @param fi               Informations about the opened file

    @return                 close()
*/
static int ifs_release (const char *path, struct fuse_file_info *fi)
{
    int res;
    OpenedItem *item;

    FI_TO_OPENED_ITEM (fi, item);
    if (item == NULL)
        return -EBADF;

    set_permissions ();

    if (item->item != NULL) {
        item_handler_close (item->item, item->fd);
        res = 0;
    }
    else {
        res = close (item->fd);
    }

    free_opened_item (item);
    fi->fh = 0;
    return res;
}
コード例 #25
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Removes a file. This is possible only in temporary paths

    @param path             Path of the file to remove

    @return                 unlink(), or -EACCES if the directory is required outside permitted
                            hierarchy
*/
static int ifs_unlink (const char *path)
{
    int ret;
    ItemHandler *target;

    set_permissions ();
    target = verify_exposed_path (path);

    if (target != NULL) {
        if (item_handler_is_folder (target) == FALSE) {
            item_handler_remove (target);
            nodes_cache_remove_by_path (get_cache_reference (), path);
            ret = 0;
        }
        else {
            ret = -EISDIR;
        }
    }
    else {
        ret = -ENOENT;
    }

    return ret;
}
コード例 #26
0
ファイル: rsv-respawn.c プロジェクト: ta0kira/rservr
static int process_line()
{
	const char *config_segment = NULL;
	char *shell = NULL;

	if (current_argument(&config_segment) < 0 || !config_segment) return 0;

	     if (strcmp(config_segment, "execute") == 0)
	{
	if (next_argument(&config_segment) < 0) return -1;
	shell = strdup(config_segment);
	int outcome = add_execute_respawn(shell);
	free(shell);
	if (outcome < 0) return -1;
	}


	else if (strcmp(config_segment, "execute_critical") == 0)
	{
	if (next_argument(&config_segment) < 0) return -1;
	shell = strdup(config_segment);
	int outcome = add_execute_critical_respawn(shell);
	free(shell);
	if (outcome < 0) return -1;
	}


	else if (strcmp(config_segment, "system") == 0)
	{
	if (next_argument(&config_segment) < 0) return -1;
	shell = strdup(config_segment);
	int outcome = add_system_respawn(shell);
	free(shell);
	if (outcome < 0) return -1;
	}


	else if (strcmp(config_segment, "system_critical") == 0)
	{
	if (next_argument(&config_segment) < 0) return -1;
	shell = strdup(config_segment);
	int outcome = add_system_critical_respawn(shell);
	free(shell);
	if (outcome < 0) return -1;
	}


	else if (strcmp(config_segment, "limit") == 0)
	{
	if (remaining_line(&config_segment) < 0 || !config_segment) return -1;
	int new_limit = 0;
	if (!parse_integer10(config_segment, &new_limit) || new_limit < 0) return -1;
	set_limit(new_limit);
	}


	else if (strcmp(config_segment, "security") == 0)
	{
	if (remaining_line(&config_segment) < 0 || !config_segment) return -1;
	permission_mask new_permissions = 0;
	if (!parse_permissions(config_segment, &new_permissions)) return -1;
	set_permissions(new_permissions);
	}


	else if (strcmp(config_segment, "priority") == 0)
	{
	if (remaining_line(&config_segment) < 0 || !config_segment) return -1;
	int new_priority = 0;
	if ( !parse_integer10(config_segment, &new_priority) || new_priority < 0 ||
	     new_priority > 255 )
	return -1;
	set_priority(new_priority);
	}


	else if (strcmp(config_segment, "log_mode") == 0)
	{
	if (remaining_line(&config_segment) < 0 || !config_segment) return -1;
	logging_mode mode_mask = logging_none;
	if (!parse_logging_mode(config_segment, &mode_mask)) return -1;
	set_logging_mode(mode_mask);
	}


	else return -1;

	return 0;
}
コード例 #27
0
ファイル: fuse.c プロジェクト: netvandal/FSter
/**
    Creates a new folder. This is possible only in temporary paths

    @param path             Path of the new folder
    @param mode             Permissions for the newly created folder

    @return                 mkdir(), or -EACCES if the directory is required outside permitted
                            hierarchy
*/
static int ifs_mkdir (const char *path, mode_t mode)
{
    set_permissions ();
    return create_item_by_path (path, NODE_IS_FOLDER, NULL);
}
コード例 #28
0
ファイル: fileops.c プロジェクト: linkedinyou/blender-git
static int copy_single_file(const char *from, const char *to)
{
	FILE *from_stream, *to_stream;
	struct stat st;
	char buf[4096];
	size_t len;

	if (check_the_same(from, to)) {
		fprintf(stderr, "%s: '%s' is the same as '%s'\n", __func__, from, to);
		return RecursiveOp_Callback_Error;
	}

	if (lstat(from, &st)) {
		perror("lstat");
		return RecursiveOp_Callback_Error;
	}

	if (S_ISLNK(st.st_mode)) {
		/* symbolic links should be copied in special way */
		char *link_buffer;
		int need_free;
		ssize_t link_len;

		/* get large enough buffer to read link content */
		if (st.st_size < sizeof(buf)) {
			link_buffer = buf;
			need_free = 0;
		}
		else {
			link_buffer = MEM_callocN(st.st_size + 2, "copy_single_file link_buffer");
			need_free = 1;
		}

		link_len = readlink(from, link_buffer, st.st_size + 1);
		if (link_len < 0) {
			perror("readlink");

			if (need_free) MEM_freeN(link_buffer);

			return RecursiveOp_Callback_Error;
		}

		link_buffer[link_len] = 0;

		if (symlink(link_buffer, to)) {
			perror("symlink");
			if (need_free) MEM_freeN(link_buffer);
			return RecursiveOp_Callback_Error;
		}

		if (need_free)
			MEM_freeN(link_buffer);

		return RecursiveOp_Callback_OK;
	}
	else if (S_ISCHR(st.st_mode) ||
	         S_ISBLK(st.st_mode) ||
	         S_ISFIFO(st.st_mode) ||
	         S_ISSOCK(st.st_mode))
	{
		/* copy special type of file */
		if (mknod(to, st.st_mode, st.st_rdev)) {
			perror("mknod");
			return RecursiveOp_Callback_Error;
		}

		if (set_permissions(to, &st))
			return RecursiveOp_Callback_Error;

		return RecursiveOp_Callback_OK;
	}
	else if (!S_ISREG(st.st_mode)) {
		fprintf(stderr, "Copying of this kind of files isn't supported yet\n");
		return RecursiveOp_Callback_Error;
	}

	from_stream = fopen(from, "rb");
	if (!from_stream) {
		perror("fopen");
		return RecursiveOp_Callback_Error;
	}

	to_stream = fopen(to, "wb");
	if (!to_stream) {
		perror("fopen");
		fclose(from_stream);
		return RecursiveOp_Callback_Error;
	}

	while ((len = fread(buf, 1, sizeof(buf), from_stream)) > 0) {
		fwrite(buf, 1, len, to_stream);
	}

	fclose(to_stream);
	fclose(from_stream);

	if (set_permissions(to, &st))
		return RecursiveOp_Callback_Error;

	return RecursiveOp_Callback_OK;
}
コード例 #29
0
ファイル: ownership.c プロジェクト: mrosensweig/6828project
int
receive_message (int sender_id, struct Message *m) {
    printf("%d: received message from %d of type %c\n", thisid, sender_id,
            m->msg_type);
    int result;
    switch (m->msg_type) {
        case (REQUEST_PAGE): {
            pthread_mutex_lock(&locks[m->page_number]);
            void *pageaddr = (void *) get_pageaddr(m->page_number);
            result = set_permissions(pageaddr, PGSIZE, m->permissions);
            if (result < 0) break;
            struct Message response = create_message(SEND_PAGE, READING,
                    m->page_number);
            if (m->index == NO_RESPONSE) {
                result = E_INCONSISTENT_STATE;
                break;
            }
            response.index = m->index;
            response.is_response = 1;
            memcpy((void *) response.page, pageaddr, PGSIZE);
            result = send_to(sender_id, &response);
            pthread_mutex_lock(&locks[m->page_number]);
            break;
        }
        case (SEND_PAGE): {
            pthread_mutex_lock(&locks[m->page_number]);
            void *pageaddr = (void *) get_pageaddr(m->page_number);
            result = set_permissions(pageaddr, PGSIZE, PROT_READ_WRITE);
            if (result < 0) break;
            memcpy(pageaddr, (void *) m->page, PGSIZE);
            result = set_permissions(pageaddr, PGSIZE, m->permissions);
            if (m->is_response) {
                pthread_cond_signal(&waits[m->index]);
            }
            pthread_mutex_unlock(&locks[m->page_number]);
            break;
        }
        case (SET_PERMISSION): {
            pthread_mutex_lock(&locks[m->page_number]);
            void *pageaddr = (void *) get_pageaddr(m->page_number);
            result = set_permissions(pageaddr, PGSIZE, m->permissions);
            if (m->is_response) {
                pthread_cond_signal(&waits[m->index]);
            }
            pthread_mutex_unlock(&locks[m->page_number]);
            break;
        }
        case (REQUEST_PERMISSION): {
            if (m->permissions = READING) {
                give_read_copy(sender_id, m->index, m->page_number);
            } else if (m->permissions = MODIFYING) {
                give_write_copy(sender_id, m->index, m->page_number);
            } else {
                result = -E_UNHANDLED_PAGE_STATUS;
                break;
            }
            break;
        }
        default: {
            printf("Unhandled message type in give_read_copy: %c\n", m->msg_type);
            exit(-E_UNHANDLED_MESSAGE_TYPE);
        }
    }
    return result;
}
コード例 #30
0
ファイル: ownership.c プロジェクト: mrosensweig/6828project
static int
give_write_copy (int requester_id, int request_id, int page_number) {
    int result;
    printf("%d: pre-lock\n", thisid);
    pthread_mutex_lock(&locks[page_number]);
    printf("%d: post-lock\n", thisid);
    int owner_id = get_owner(page_number);
    if (owner_id != thisid) {
        printf("%d: wtf\n", thisid);
        pthread_mutex_unlock(&locks[page_number]);
        return -E_INCORRECT_OWNER;
    }
    struct PageStatus *page_status = get_page_status(page_number);
    printf("%d: page_status->status: %d\n", thisid, page_status->status);
    switch (page_status->status) {
        case READABLE: {
            int i;
            int had_read_only;
            for (i = 0; i < nowners; i++) {
                if (i == requester_id) {
                    had_read_only = (page_status->status_by_owner[i] == READING);
                    continue;
                }
                if (i == thisid) {
                    if (page_status->status_by_owner[i] == READING) {
                        // Set local page to PROT_NONE at end of function
                        continue;
                    } else {
                        // This shouldn't happen - the local copy should become
                        //   readable as soon the page status becomes READABLE
                        result = -E_INCONSISTENT_STATE;
                        break;
                    }
                }
                if (page_status->status_by_owner[i] == READING) {
                    // Tell i that it is INVALIDATED
                    printf("%d: Telling %d that it is INVALIDATED\n", thisid, i);
                    struct Message m = create_message(SET_PERMISSION,
                            INVALIDATED, page_number);
                    printf("%d: sending message of type %c\n", thisid, m.msg_type);
                    result = send_to(i, &m);
                    if (result < 0) break;
                    page_status->status_by_owner[i] = INVALIDATED;
                }
            }
            page_status->status_by_owner[requester_id] = MODIFYING;
            page_status->modifying_owner = requester_id;
            page_status->status = MODIFIED;
            if (requester_id == thisid) {
                // Set local page to PROT_READ_WRITE
                printf("%d: Setting local page %d to PROT_READ_WRITE\n", thisid,
                        page_number);
                result = set_permissions((void *) get_pageaddr(page_number),
                        PGSIZE, PROT_READ_WRITE);
                if (result < 0) break;
            } else {
                if (had_read_only) {
                    // Tell requester_id that it has PROT_READ_WRITE access
                    struct Message m = create_message(SET_PERMISSION,
                            MODIFYING, page_number);
                    m.is_response = 1;
                    if (request_id == NO_RESPONSE) {
                        result = E_INCONSISTENT_STATE;
                        break;
                    }
                    m.index = request_id;
                    result = send_to(requester_id, &m);
                    if (result < 0) break;
                } else {
                    // Transfer page over network to requester_id and tell it
                    //   it has PROT_READ_WRITE access
                    struct Message m = create_message(SEND_PAGE, MODIFYING,
                            page_number);
                    memcpy((void *) m.page, (void *) get_pageaddr(page_number),
                            PGSIZE);
                    m.is_response = 1;
                    if (request_id == NO_RESPONSE) {
                        result = E_INCONSISTENT_STATE;
                        break;
                    }
                    m.index = request_id;
                    result = send_to(requester_id, &m);
                    if (result < 0) break;
                }
            }
            // Set local page to PROT_NONE
            result = set_permissions((void *) get_pageaddr(page_number),
                    PGSIZE, PROT_NONE);
            if (result < 0) break;
            page_status->status_by_owner[thisid] = INVALIDATED;
            result = 0;
            break;
        }
        case MODIFIED: {
            int modifier = page_status->modifying_owner;
            if (modifier == requester_id) {
                // The modifier should have read-write permissions, in which
                //   case a page not fault should not be thrown and this
                //   should never be called.
                result = -E_INCONSISTENT_STATE;
                break;
            }
            if (modifier == thisid) {
                // Set local page to PROT_NONE at end of method
            } else {
                // Tell modifier that it is INVALIDATED
                // Get modified page from modifier
                struct Message m = create_message(REQUEST_PAGE, INVALIDATED,
                        page_number);
                // Upon receiving the message we should map the page locally
                result = send_and_wait_for_response(modifier, &m);
                if (result < 0) break;
                // Local page should already be set PROT_READ
            }
            page_status->status_by_owner[modifier] = INVALIDATED;
            page_status->status_by_owner[requester_id] = MODIFYING;
            page_status->modifying_owner = requester_id;
            if (requester_id == thisid) {
                // Set local page to PROT_READ_WRITE
                result = set_permissions((void *) get_pageaddr(page_number),
                        PGSIZE, PROT_READ_WRITE);
                if (result < 0) break;
            } else {
                // Transfer page over network to requester_id and tell it it has
                //   PROT_READ_WRITE access
                struct Message m = create_message(SEND_PAGE, MODIFYING,
                        page_number);
                memcpy((void *) m.page, (void *) get_pageaddr(page_number),
                        PGSIZE);
                m.is_response = 1;
                if (request_id == NO_RESPONSE) {
                    result = E_INCONSISTENT_STATE;
                    break;
                }
                m.index = request_id;
                result = send_to(requester_id, &m);
                if (result < 0) break;
                // Set local page to PROT_NONE
                result = set_permissions((void *) get_pageaddr(page_number),
                        PGSIZE, PROT_NONE);
                if (result < 0) break;
            }
            result = 0;
            break;
        }
        default: {
            printf("Unhandled page status in give_write_copy.\n");
            exit(-E_UNHANDLED_PAGE_STATUS);
        }
    }
    pthread_mutex_unlock(&locks[page_number]);
    return result;
}