/*===========================================================================* * verify_path * *===========================================================================*/ int verify_path(char path[PATH_MAX], struct inode *ino, struct sffs_attr *attr, int *stale) { /* Given a path, and the inode associated with that path, verify if the inode * still matches the real world. Obtain the attributes of the file identified * by the given path, and see if they match. If not, possibly mark the inode * as deleted and return an error. Only upon success is the inode guaranteed * to be usable. * * The caller must set the a_mask field of the passed attr struct. * If 'stale' is not NULL, the value it points to must be initialized to 0, * and will be set to 1 if the path was valid but the inode wasn't. */ int r; attr->a_mask |= SFFS_ATTR_MODE; r = sffs_table->t_getattr(path, attr); dprintf(("%s: verify_path: getattr('%s') returned %d\n", sffs_name, path, r)); if (r != OK) { /* If we are told that the path does not exist, delete the inode */ if (r == ENOENT || r == ENOTDIR) del_dentry(ino); return r; /* path isn't valid */ } /* If the file type (reg, dir) isn't what we thought, delete the inode */ if ((ino->i_flags & I_DIR) != MODE_TO_DIRFLAG(attr->a_mode)) { del_dentry(ino); if (stale != NULL) *stale = 1; return ENOENT; /* path is valid, inode wasn't */ } return OK; /* path and inode are valid */ }
/*===========================================================================* * do_mkdir * *===========================================================================*/ PUBLIC int do_mkdir() { /* Make a new directory. */ char path[PATH_MAX], name[NAME_MAX+1]; struct inode *parent, *ino; int r; /* We cannot create directories on a read-only file system. */ if (state.read_only) return EROFS; /* Get the path string and possibly an inode for the given path. */ if ((r = get_name(m_in.REQ_GRANT, m_in.REQ_PATH_LEN, name)) != OK) return r; if (!strcmp(name, ".") || !strcmp(name, "..")) return EEXIST; if ((parent = find_inode(m_in.REQ_INODE_NR)) == NULL) return EINVAL; if ((r = verify_dentry(parent, name, path, &ino)) != OK) return r; /* Perform the actual mkdir call. */ r = hgfs_mkdir(path, m_in.REQ_MODE); if (r != OK) { if (ino != NULL) put_inode(ino); return r; } /* If we thought the new dentry already existed, it was apparently gone * already. Delete it. */ if (ino != NULL) { del_dentry(ino); put_inode(ino); } return OK; }
/*===========================================================================* * do_create * *===========================================================================*/ PUBLIC int do_create() { /* Create a new file. */ char path[PATH_MAX], name[NAME_MAX+1]; struct inode *parent, *ino; struct hgfs_attr attr; hgfs_file_t handle; int r; /* We cannot create files on a read-only file system. */ if (state.read_only) return EROFS; /* Get path, name, parent inode and possibly inode for the given path. */ if ((r = get_name(m_in.REQ_GRANT, m_in.REQ_PATH_LEN, name)) != OK) return r; if (!strcmp(name, ".") || !strcmp(name, "..")) return EEXIST; if ((parent = find_inode(m_in.REQ_INODE_NR)) == NULL) return EINVAL; if ((r = verify_dentry(parent, name, path, &ino)) != OK) return r; /* Are we going to need a new inode upon success? * Then make sure there is one available before trying anything. */ if (ino == NULL || ino->i_ref > 1 || HAS_CHILDREN(ino)) { if (!have_free_inode()) { if (ino != NULL) put_inode(ino); return ENFILE; } } /* Perform the actual create call. */ r = hgfs_open(path, O_CREAT | O_EXCL | O_RDWR, m_in.REQ_MODE, &handle); if (r != OK) { /* Let's not try to be too clever with error codes here. If something * is wrong with the directory, we'll find out later anyway. */ if (ino != NULL) put_inode(ino); return r; } /* Get the created file's attributes. */ attr.a_mask = HGFS_ATTR_MODE | HGFS_ATTR_SIZE; r = hgfs_getattr(path, &attr); /* If this fails, or returns a directory, we have a problem. This * scenario is in fact possible with race conditions. * Simulate a close and return a somewhat appropriate error. */ if (r != OK || S_ISDIR(attr.a_mode)) { printf("HGFS: lost file after creation!\n"); hgfs_close(handle); if (ino != NULL) { del_dentry(ino); put_inode(ino); } return (r == OK) ? EEXIST : r; } /* We do assume that the HGFS open(O_CREAT|O_EXCL) did its job. * If we previousy found an inode, get rid of it now. It's old. */ if (ino != NULL) { del_dentry(ino); put_inode(ino); } /* Associate the open file handle with an inode, and reply with its details. */ ino = get_free_inode(); assert(ino != NULL); /* we checked before whether we had a free one */ ino->i_file = handle; ino->i_flags = I_HANDLE; add_dentry(parent, name, ino); m_out.RES_INODE_NR = INODE_NR(ino); m_out.RES_MODE = get_mode(ino, attr.a_mode); m_out.RES_FILE_SIZE_HI = ex64hi(attr.a_size); m_out.RES_FILE_SIZE_LO = ex64lo(attr.a_size); m_out.RES_UID = opt.uid; m_out.RES_GID = opt.gid; m_out.RES_DEV = NO_DEV; return OK; }