int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t device_number) { int rc = -EPERM; int xid; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; struct inode * newinode = NULL; if (!old_valid_dev(device_number)) return -EINVAL; xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; down(&direntry->d_sb->s_vfs_rename_sem); full_path = build_path_from_dentry(direntry); up(&direntry->d_sb->s_vfs_rename_sem); if(full_path == NULL) rc = -ENOMEM; if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) { if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,(__u64)current->euid,(__u64)current->egid, device_number, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } else { rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)-1, (__u64)-1, device_number, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } if(!rc) { rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,xid); direntry->d_op = &cifs_dentry_ops; if(rc == 0) d_instantiate(direntry, newinode); } } kfree(full_path); FreeXid(xid); return rc; }
int cifs_create(struct inode *inode, struct dentry *direntry, int mode, struct nameidata *nd) { int rc = -ENOENT; int xid; int oplock = 0; int desiredAccess = GENERIC_READ | GENERIC_WRITE; __u16 fileHandle; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; FILE_ALL_INFO * buf = NULL; struct inode *newinode = NULL; struct cifsFileInfo * pCifsFile = NULL; struct cifsInodeInfo * pCifsInode; int disposition = FILE_OVERWRITE_IF; int write_only = FALSE; xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; down(&direntry->d_sb->s_vfs_rename_sem); full_path = build_path_from_dentry(direntry); up(&direntry->d_sb->s_vfs_rename_sem); if(full_path == NULL) { FreeXid(xid); return -ENOMEM; } if(nd && (nd->flags & LOOKUP_OPEN)) { int oflags = nd->intent.open.flags; desiredAccess = 0; if (oflags & FMODE_READ) desiredAccess |= GENERIC_READ; if (oflags & FMODE_WRITE) { desiredAccess |= GENERIC_WRITE; if (!(oflags & FMODE_READ)) write_only = TRUE; } if((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) disposition = FILE_CREATE; else if((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) disposition = FILE_OVERWRITE_IF; else if((oflags & O_CREAT) == O_CREAT) disposition = FILE_OPEN_IF; else { cFYI(1,("Create flag not set in create function")); } } /* BB add processing to set equivalent of mode - e.g. via CreateX with ACLs */ if (oplockEnabled) oplock = REQ_OPLOCK; buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); if(buf == NULL) { kfree(full_path); FreeXid(xid); return -ENOMEM; } rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, CREATE_NOT_DIR, &fileHandle, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { cFYI(1, ("cifs_create returned 0x%x ", rc)); } else { /* If Open reported that we actually created a file then we now have to set the mode if possible */ if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) && (oplock & CIFS_CREATE_ACTION)) if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)current->euid, (__u64)current->egid, 0 /* dev */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } else { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)-1, (__u64)-1, 0 /* dev */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } else { /* BB implement via Windows security descriptors */ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ /* could set r/o dos attribute if mode & 0222 == 0 */ } /* BB server might mask mode so we have to query for Unix case*/ if (pTcon->ses->capabilities & CAP_UNIX) rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,xid); else { rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb,xid); if(newinode) newinode->i_mode = mode; } if (rc != 0) { cFYI(1,("Create worked but get_inode_info failed with rc = %d", rc)); } else { direntry->d_op = &cifs_dentry_ops; d_instantiate(direntry, newinode); } if((nd->flags & LOOKUP_OPEN) == FALSE) { /* mknod case - do not leave file open */ CIFSSMBClose(xid, pTcon, fileHandle); } else if(newinode) { pCifsFile = kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); if(pCifsFile == NULL) goto cifs_create_out; memset((char *)pCifsFile, 0, sizeof (struct cifsFileInfo)); pCifsFile->netfid = fileHandle; pCifsFile->pid = current->tgid; pCifsFile->pInode = newinode; pCifsFile->invalidHandle = FALSE; pCifsFile->closePend = FALSE; init_MUTEX(&pCifsFile->fh_sem); /* set the following in open now pCifsFile->pfile = file; */ write_lock(&GlobalSMBSeslock); list_add(&pCifsFile->tlist,&pTcon->openFileList); pCifsInode = CIFS_I(newinode); if(pCifsInode) { /* if readable file instance put first in list*/ if (write_only == TRUE) { list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList); } else { list_add(&pCifsFile->flist, &pCifsInode->openFileList); } if((oplock & 0xF) == OPLOCK_EXCLUSIVE) { pCifsInode->clientCanCacheAll = TRUE; pCifsInode->clientCanCacheRead = TRUE; cFYI(1,("Exclusive Oplock for inode %p", newinode)); } else if((oplock & 0xF) == OPLOCK_READ) pCifsInode->clientCanCacheRead = TRUE; } write_unlock(&GlobalSMBSeslock); } } cifs_create_out: kfree(buf); kfree(full_path); FreeXid(xid); return rc; }
int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) { int rc = 0; int xid; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; struct inode *newinode = NULL; cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode)); xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; down(&inode->i_sb->s_vfs_rename_sem); full_path = build_path_from_dentry(direntry); up(&inode->i_sb->s_vfs_rename_sem); if(full_path == NULL) { FreeXid(xid); return -ENOMEM; } /* BB add setting the equivalent of mode via CreateX w/ACLs */ rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls); if (rc) { cFYI(1, ("cifs_mkdir returned 0x%x ", rc)); d_drop(direntry); } else { inode->i_nlink++; if (pTcon->ses->capabilities & CAP_UNIX) rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,xid); else rc = cifs_get_inode_info(&newinode, full_path,NULL, inode->i_sb,xid); direntry->d_op = &cifs_dentry_ops; d_instantiate(direntry, newinode); if(direntry->d_inode) direntry->d_inode->i_nlink = 2; if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)current->euid, (__u64)current->egid, 0 /* dev_t */, cifs_sb->local_nls); } else { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)-1, (__u64)-1, 0 /* dev_t */, cifs_sb->local_nls); } else { /* BB to be implemented via Windows secrty descriptors*/ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ } } if (full_path) kfree(full_path); FreeXid(xid); return rc; }
int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t device_number) { int rc = -EPERM; int xid; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; struct inode * newinode = NULL; if (!old_valid_dev(device_number)) return -EINVAL; xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; full_path = build_path_from_dentry(direntry); if (full_path == NULL) rc = -ENOMEM; else if (pTcon->ses->capabilities & CAP_UNIX) { mode &= ~current->fs->umask; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)current->fsuid, (__u64)current->fsgid, device_number, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } else { rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)-1, (__u64)-1, device_number, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } if (!rc) { rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, xid); if (pTcon->nocase) direntry->d_op = &cifs_ci_dentry_ops; else direntry->d_op = &cifs_dentry_ops; if (rc == 0) d_instantiate(direntry, newinode); } } else { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { int oplock = 0; u16 fileHandle; FILE_ALL_INFO * buf; cFYI(1, ("sfu compat create special file")); buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); if (buf == NULL) { kfree(full_path); FreeXid(xid); return -ENOMEM; } rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE, /* fail if exists */ GENERIC_WRITE /* BB would WRITE_OWNER | WRITE_DAC be better? */, /* Create a file and set the file attribute to SYSTEM */ CREATE_NOT_DIR | CREATE_OPTION_SPECIAL, &fileHandle, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); /* BB FIXME - add handling for backlevel servers which need legacy open and check for all calls to SMBOpen for fallback to SMBLeagcyOpen */ if (!rc) { /* BB Do not bother to decode buf since no local inode yet to put timestamps in, but we can reuse it safely */ int bytes_written; struct win_dev *pdev; pdev = (struct win_dev *)buf; if (S_ISCHR(mode)) { memcpy(pdev->type, "IntxCHR", 8); pdev->major = cpu_to_le64(MAJOR(device_number)); pdev->minor = cpu_to_le64(MINOR(device_number)); rc = CIFSSMBWrite(xid, pTcon, fileHandle, sizeof(struct win_dev), 0, &bytes_written, (char *)pdev, NULL, 0); } else if (S_ISBLK(mode)) { memcpy(pdev->type, "IntxBLK", 8); pdev->major = cpu_to_le64(MAJOR(device_number)); pdev->minor = cpu_to_le64(MINOR(device_number)); rc = CIFSSMBWrite(xid, pTcon, fileHandle, sizeof(struct win_dev), 0, &bytes_written, (char *)pdev, NULL, 0); } /* else if(S_ISFIFO */ CIFSSMBClose(xid, pTcon, fileHandle); d_drop(direntry); } kfree(buf); /* add code here to set EAs */ } } kfree(full_path); FreeXid(xid); return rc; }
int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) { int rc = 0; int xid; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; struct inode *newinode = NULL; cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode)); xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; full_path = build_path_from_dentry(direntry); if (full_path == NULL) { FreeXid(xid); return -ENOMEM; } if ((pTcon->ses->capabilities & CAP_UNIX) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & le64_to_cpu(pTcon->fsUnixInfo.Capability))) { u32 oplock = 0; FILE_UNIX_BASIC_INFO *pInfo = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); if (pInfo == NULL) { rc = -ENOMEM; goto mkdir_out; } mode &= ~current->fs->umask; rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode, NULL /* netfid */, pInfo, &oplock, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc == -EOPNOTSUPP) { kfree(pInfo); goto mkdir_retry_old; } else if (rc) { cFYI(1, ("posix mkdir returned 0x%x", rc)); d_drop(direntry); } else { if (pInfo->Type == cpu_to_le32(-1)) { /* no return info, go query for it */ kfree(pInfo); goto mkdir_get_info; } /*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */ inc_nlink(inode); if (pTcon->nocase) direntry->d_op = &cifs_ci_dentry_ops; else direntry->d_op = &cifs_dentry_ops; newinode = new_inode(inode->i_sb); if (newinode == NULL) { kfree(pInfo); goto mkdir_get_info; } /* Is an i_ino of zero legal? */ /* Are there sanity checks we can use to ensure that the server is really filling in that field? */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { newinode->i_ino = (unsigned long)pInfo->UniqueId; } /* note ino incremented to unique num in new_inode */ if (inode->i_sb->s_flags & MS_NOATIME) newinode->i_flags |= S_NOATIME | S_NOCMTIME; newinode->i_nlink = 2; insert_inode_hash(newinode); d_instantiate(direntry, newinode); /* we already checked in POSIXCreate whether frame was long enough */ posix_fill_in_inode(direntry->d_inode, pInfo, 1 /* NewInode */); #ifdef CONFIG_CIFS_DEBUG2 cFYI(1, ("instantiated dentry %p %s to inode %p", direntry, direntry->d_name.name, newinode)); if (newinode->i_nlink != 2) cFYI(1, ("unexpected number of links %d", newinode->i_nlink)); #endif } kfree(pInfo); goto mkdir_out; } mkdir_retry_old: /* BB add setting the equivalent of mode via CreateX w/ACLs */ rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { cFYI(1, ("cifs_mkdir returned 0x%x", rc)); d_drop(direntry); } else { mkdir_get_info: inc_nlink(inode); if (pTcon->unix_ext) rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, xid); else rc = cifs_get_inode_info(&newinode, full_path, NULL, inode->i_sb, xid, NULL); if (pTcon->nocase) direntry->d_op = &cifs_ci_dentry_ops; else direntry->d_op = &cifs_dentry_ops; d_instantiate(direntry, newinode); /* setting nlink not necessary except in cases where we * failed to get it from the server or was set bogus */ if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) direntry->d_inode->i_nlink = 2; if (pTcon->unix_ext) { mode &= ~current->fs->umask; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)current->fsuid, (__u64)current->fsgid, 0 /* dev_t */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } else { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)-1, (__u64)-1, 0 /* dev_t */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } } else { /* BB to be implemented via Windows secrty descriptors eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, -1, -1, local_nls); */ if (direntry->d_inode) { direntry->d_inode->i_mode = mode; direntry->d_inode->i_mode |= S_IFDIR; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { direntry->d_inode->i_uid = current->fsuid; direntry->d_inode->i_gid = current->fsgid; } } } } mkdir_out: kfree(full_path); FreeXid(xid); return rc; }