at v2.6.13 443 lines 12 kB view raw
1/* 2 * fs/cifs/dir.c 3 * 4 * vfs operations that deal with dentries 5 * 6 * Copyright (C) International Business Machines Corp., 2002,2003 7 * Author(s): Steve French (sfrench@us.ibm.com) 8 * 9 * This library is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU Lesser General Public License as published 11 * by the Free Software Foundation; either version 2.1 of the License, or 12 * (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 17 * the GNU Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public License 20 * along with this library; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23#include <linux/fs.h> 24#include <linux/stat.h> 25#include <linux/slab.h> 26#include <linux/namei.h> 27#include "cifsfs.h" 28#include "cifspdu.h" 29#include "cifsglob.h" 30#include "cifsproto.h" 31#include "cifs_debug.h" 32#include "cifs_fs_sb.h" 33 34void 35renew_parental_timestamps(struct dentry *direntry) 36{ 37 /* BB check if there is a way to get the kernel to do this or if we really need this */ 38 do { 39 direntry->d_time = jiffies; 40 direntry = direntry->d_parent; 41 } while (!IS_ROOT(direntry)); 42} 43 44/* Note: caller must free return buffer */ 45char * 46build_path_from_dentry(struct dentry *direntry) 47{ 48 struct dentry *temp; 49 int namelen = 0; 50 char *full_path; 51 52 if(direntry == NULL) 53 return NULL; /* not much we can do if dentry is freed and 54 we need to reopen the file after it was closed implicitly 55 when the server crashed */ 56 57cifs_bp_rename_retry: 58 for (temp = direntry; !IS_ROOT(temp);) { 59 namelen += (1 + temp->d_name.len); 60 temp = temp->d_parent; 61 if(temp == NULL) { 62 cERROR(1,("corrupt dentry")); 63 return NULL; 64 } 65 } 66 67 full_path = kmalloc(namelen+1, GFP_KERNEL); 68 if(full_path == NULL) 69 return full_path; 70 full_path[namelen] = 0; /* trailing null */ 71 72 for (temp = direntry; !IS_ROOT(temp);) { 73 namelen -= 1 + temp->d_name.len; 74 if (namelen < 0) { 75 break; 76 } else { 77 full_path[namelen] = '\\'; 78 strncpy(full_path + namelen + 1, temp->d_name.name, 79 temp->d_name.len); 80 cFYI(0, (" name: %s ", full_path + namelen)); 81 } 82 temp = temp->d_parent; 83 if(temp == NULL) { 84 cERROR(1,("corrupt dentry")); 85 kfree(full_path); 86 return NULL; 87 } 88 } 89 if (namelen != 0) { 90 cERROR(1, 91 ("We did not end path lookup where we expected namelen is %d", 92 namelen)); 93 /* presumably this is only possible if we were racing with a rename 94 of one of the parent directories (we can not lock the dentries 95 above us to prevent this, but retrying should be harmless) */ 96 kfree(full_path); 97 namelen = 0; 98 goto cifs_bp_rename_retry; 99 } 100 101 return full_path; 102} 103 104/* char * build_wildcard_path_from_dentry(struct dentry *direntry) 105{ 106 if(full_path == NULL) 107 return full_path; 108 109 full_path[namelen] = '\\'; 110 full_path[namelen+1] = '*'; 111 full_path[namelen+2] = 0; 112BB remove above eight lines BB */ 113 114/* Inode operations in similar order to how they appear in the Linux file fs.h */ 115 116int 117cifs_create(struct inode *inode, struct dentry *direntry, int mode, 118 struct nameidata *nd) 119{ 120 int rc = -ENOENT; 121 int xid; 122 int oplock = 0; 123 int desiredAccess = GENERIC_READ | GENERIC_WRITE; 124 __u16 fileHandle; 125 struct cifs_sb_info *cifs_sb; 126 struct cifsTconInfo *pTcon; 127 char *full_path = NULL; 128 FILE_ALL_INFO * buf = NULL; 129 struct inode *newinode = NULL; 130 struct cifsFileInfo * pCifsFile = NULL; 131 struct cifsInodeInfo * pCifsInode; 132 int disposition = FILE_OVERWRITE_IF; 133 int write_only = FALSE; 134 135 xid = GetXid(); 136 137 cifs_sb = CIFS_SB(inode->i_sb); 138 pTcon = cifs_sb->tcon; 139 140 down(&direntry->d_sb->s_vfs_rename_sem); 141 full_path = build_path_from_dentry(direntry); 142 up(&direntry->d_sb->s_vfs_rename_sem); 143 if(full_path == NULL) { 144 FreeXid(xid); 145 return -ENOMEM; 146 } 147 148 if(nd) { 149 if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY) 150 desiredAccess = GENERIC_READ; 151 else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY) { 152 desiredAccess = GENERIC_WRITE; 153 write_only = TRUE; 154 } else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) { 155 /* GENERIC_ALL is too much permission to request */ 156 /* can cause unnecessary access denied on create */ 157 /* desiredAccess = GENERIC_ALL; */ 158 desiredAccess = GENERIC_READ | GENERIC_WRITE; 159 } 160 161 if((nd->intent.open.flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) 162 disposition = FILE_CREATE; 163 else if((nd->intent.open.flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) 164 disposition = FILE_OVERWRITE_IF; 165 else if((nd->intent.open.flags & O_CREAT) == O_CREAT) 166 disposition = FILE_OPEN_IF; 167 else { 168 cFYI(1,("Create flag not set in create function")); 169 } 170 } 171 172 /* BB add processing to set equivalent of mode - e.g. via CreateX with ACLs */ 173 if (oplockEnabled) 174 oplock = REQ_OPLOCK; 175 176 buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); 177 if(buf == NULL) { 178 kfree(full_path); 179 FreeXid(xid); 180 return -ENOMEM; 181 } 182 183 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, 184 desiredAccess, CREATE_NOT_DIR, 185 &fileHandle, &oplock, buf, cifs_sb->local_nls, 186 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 187 if (rc) { 188 cFYI(1, ("cifs_create returned 0x%x ", rc)); 189 } else { 190 /* If Open reported that we actually created a file 191 then we now have to set the mode if possible */ 192 if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) && 193 (oplock & CIFS_CREATE_ACTION)) 194 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 195 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, 196 (__u64)current->euid, 197 (__u64)current->egid, 198 0 /* dev */, 199 cifs_sb->local_nls, 200 cifs_sb->mnt_cifs_flags & 201 CIFS_MOUNT_MAP_SPECIAL_CHR); 202 } else { 203 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, 204 (__u64)-1, 205 (__u64)-1, 206 0 /* dev */, 207 cifs_sb->local_nls, 208 cifs_sb->mnt_cifs_flags & 209 CIFS_MOUNT_MAP_SPECIAL_CHR); 210 } 211 else { 212 /* BB implement via Windows security descriptors */ 213 /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ 214 /* could set r/o dos attribute if mode & 0222 == 0 */ 215 } 216 217 /* BB server might mask mode so we have to query for Unix case*/ 218 if (pTcon->ses->capabilities & CAP_UNIX) 219 rc = cifs_get_inode_info_unix(&newinode, full_path, 220 inode->i_sb,xid); 221 else { 222 rc = cifs_get_inode_info(&newinode, full_path, 223 buf, inode->i_sb,xid); 224 if(newinode) 225 newinode->i_mode = mode; 226 } 227 228 if (rc != 0) { 229 cFYI(1,("Create worked but get_inode_info failed with rc = %d", 230 rc)); 231 } else { 232 direntry->d_op = &cifs_dentry_ops; 233 d_instantiate(direntry, newinode); 234 } 235 if((nd->flags & LOOKUP_OPEN) == FALSE) { 236 /* mknod case - do not leave file open */ 237 CIFSSMBClose(xid, pTcon, fileHandle); 238 } else if(newinode) { 239 pCifsFile = 240 kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); 241 242 if(pCifsFile == NULL) 243 goto cifs_create_out; 244 memset((char *)pCifsFile, 0, 245 sizeof (struct cifsFileInfo)); 246 pCifsFile->netfid = fileHandle; 247 pCifsFile->pid = current->tgid; 248 pCifsFile->pInode = newinode; 249 pCifsFile->invalidHandle = FALSE; 250 pCifsFile->closePend = FALSE; 251 init_MUTEX(&pCifsFile->fh_sem); 252 /* set the following in open now 253 pCifsFile->pfile = file; */ 254 write_lock(&GlobalSMBSeslock); 255 list_add(&pCifsFile->tlist,&pTcon->openFileList); 256 pCifsInode = CIFS_I(newinode); 257 if(pCifsInode) { 258 /* if readable file instance put first in list*/ 259 if (write_only == TRUE) { 260 list_add_tail(&pCifsFile->flist, 261 &pCifsInode->openFileList); 262 } else { 263 list_add(&pCifsFile->flist, 264 &pCifsInode->openFileList); 265 } 266 if((oplock & 0xF) == OPLOCK_EXCLUSIVE) { 267 pCifsInode->clientCanCacheAll = TRUE; 268 pCifsInode->clientCanCacheRead = TRUE; 269 cFYI(1,("Exclusive Oplock for inode %p", 270 newinode)); 271 } else if((oplock & 0xF) == OPLOCK_READ) 272 pCifsInode->clientCanCacheRead = TRUE; 273 } 274 write_unlock(&GlobalSMBSeslock); 275 } 276 } 277cifs_create_out: 278 kfree(buf); 279 kfree(full_path); 280 FreeXid(xid); 281 return rc; 282} 283 284int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t device_number) 285{ 286 int rc = -EPERM; 287 int xid; 288 struct cifs_sb_info *cifs_sb; 289 struct cifsTconInfo *pTcon; 290 char *full_path = NULL; 291 struct inode * newinode = NULL; 292 293 if (!old_valid_dev(device_number)) 294 return -EINVAL; 295 296 xid = GetXid(); 297 298 cifs_sb = CIFS_SB(inode->i_sb); 299 pTcon = cifs_sb->tcon; 300 301 down(&direntry->d_sb->s_vfs_rename_sem); 302 full_path = build_path_from_dentry(direntry); 303 up(&direntry->d_sb->s_vfs_rename_sem); 304 if(full_path == NULL) 305 rc = -ENOMEM; 306 307 if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) { 308 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 309 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, 310 mode,(__u64)current->euid,(__u64)current->egid, 311 device_number, cifs_sb->local_nls, 312 cifs_sb->mnt_cifs_flags & 313 CIFS_MOUNT_MAP_SPECIAL_CHR); 314 } else { 315 rc = CIFSSMBUnixSetPerms(xid, pTcon, 316 full_path, mode, (__u64)-1, (__u64)-1, 317 device_number, cifs_sb->local_nls, 318 cifs_sb->mnt_cifs_flags & 319 CIFS_MOUNT_MAP_SPECIAL_CHR); 320 } 321 322 if(!rc) { 323 rc = cifs_get_inode_info_unix(&newinode, full_path, 324 inode->i_sb,xid); 325 direntry->d_op = &cifs_dentry_ops; 326 if(rc == 0) 327 d_instantiate(direntry, newinode); 328 } 329 } 330 331 kfree(full_path); 332 FreeXid(xid); 333 return rc; 334} 335 336 337struct dentry * 338cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct nameidata *nd) 339{ 340 int xid; 341 int rc = 0; /* to get around spurious gcc warning, set to zero here */ 342 struct cifs_sb_info *cifs_sb; 343 struct cifsTconInfo *pTcon; 344 struct inode *newInode = NULL; 345 char *full_path = NULL; 346 347 xid = GetXid(); 348 349 cFYI(1, 350 (" parent inode = 0x%p name is: %s and dentry = 0x%p", 351 parent_dir_inode, direntry->d_name.name, direntry)); 352 353 /* BB Add check of incoming data - e.g. frame not longer than maximum SMB - let server check the namelen BB */ 354 355 /* check whether path exists */ 356 357 cifs_sb = CIFS_SB(parent_dir_inode->i_sb); 358 pTcon = cifs_sb->tcon; 359 360 /* can not grab the rename sem here since it would 361 deadlock in the cases (beginning of sys_rename itself) 362 in which we already have the sb rename sem */ 363 full_path = build_path_from_dentry(direntry); 364 if(full_path == NULL) { 365 FreeXid(xid); 366 return ERR_PTR(-ENOMEM); 367 } 368 369 if (direntry->d_inode != NULL) { 370 cFYI(1, (" non-NULL inode in lookup")); 371 } else { 372 cFYI(1, (" NULL inode in lookup")); 373 } 374 cFYI(1, 375 (" Full path: %s inode = 0x%p", full_path, direntry->d_inode)); 376 377 if (pTcon->ses->capabilities & CAP_UNIX) 378 rc = cifs_get_inode_info_unix(&newInode, full_path, 379 parent_dir_inode->i_sb,xid); 380 else 381 rc = cifs_get_inode_info(&newInode, full_path, NULL, 382 parent_dir_inode->i_sb,xid); 383 384 if ((rc == 0) && (newInode != NULL)) { 385 direntry->d_op = &cifs_dentry_ops; 386 d_add(direntry, newInode); 387 388 /* since paths are not looked up by component - the parent directories are presumed to be good here */ 389 renew_parental_timestamps(direntry); 390 391 } else if (rc == -ENOENT) { 392 rc = 0; 393 d_add(direntry, NULL); 394 } else { 395 cERROR(1,("Error 0x%x on cifs_get_inode_info in lookup of %s", 396 rc,full_path)); 397 /* BB special case check for Access Denied - watch security 398 exposure of returning dir info implicitly via different rc 399 if file exists or not but no access BB */ 400 } 401 402 kfree(full_path); 403 FreeXid(xid); 404 return ERR_PTR(rc); 405} 406 407static int 408cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) 409{ 410 int isValid = 1; 411 412/* lock_kernel(); *//* surely we do not want to lock the kernel for a whole network round trip which could take seconds */ 413 414 if (direntry->d_inode) { 415 if (cifs_revalidate(direntry)) { 416 /* unlock_kernel(); */ 417 return 0; 418 } 419 } else { 420 cFYI(1, 421 ("In cifs_d_revalidate with no inode but name = %s and dentry 0x%p", 422 direntry->d_name.name, direntry)); 423 } 424 425/* unlock_kernel(); */ 426 427 return isValid; 428} 429 430/* static int cifs_d_delete(struct dentry *direntry) 431{ 432 int rc = 0; 433 434 cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name)); 435 436 return rc; 437} */ 438 439struct dentry_operations cifs_dentry_ops = { 440 .d_revalidate = cifs_d_revalidate, 441/* d_delete: cifs_d_delete, *//* not needed except for debugging */ 442 /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */ 443};