aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/dir.c')
-rw-r--r--fs/cifs/dir.c149
1 files changed, 74 insertions, 75 deletions
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 578d88c5b46..f17d50047f0 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -496,6 +496,11 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
496 struct cifsTconInfo *pTcon; 496 struct cifsTconInfo *pTcon;
497 char *full_path = NULL; 497 char *full_path = NULL;
498 struct inode *newinode = NULL; 498 struct inode *newinode = NULL;
499 int oplock = 0;
500 u16 fileHandle;
501 FILE_ALL_INFO *buf = NULL;
502 unsigned int bytes_written;
503 struct win_dev *pdev;
499 504
500 if (!old_valid_dev(device_number)) 505 if (!old_valid_dev(device_number))
501 return -EINVAL; 506 return -EINVAL;
@@ -506,9 +511,12 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
506 pTcon = cifs_sb->tcon; 511 pTcon = cifs_sb->tcon;
507 512
508 full_path = build_path_from_dentry(direntry); 513 full_path = build_path_from_dentry(direntry);
509 if (full_path == NULL) 514 if (full_path == NULL) {
510 rc = -ENOMEM; 515 rc = -ENOMEM;
511 else if (pTcon->unix_ext) { 516 goto mknod_out;
517 }
518
519 if (pTcon->unix_ext) {
512 struct cifs_unix_set_info_args args = { 520 struct cifs_unix_set_info_args args = {
513 .mode = mode & ~current_umask(), 521 .mode = mode & ~current_umask(),
514 .ctime = NO_CHANGE_64, 522 .ctime = NO_CHANGE_64,
@@ -527,87 +535,78 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
527 cifs_sb->local_nls, 535 cifs_sb->local_nls,
528 cifs_sb->mnt_cifs_flags & 536 cifs_sb->mnt_cifs_flags &
529 CIFS_MOUNT_MAP_SPECIAL_CHR); 537 CIFS_MOUNT_MAP_SPECIAL_CHR);
538 if (rc)
539 goto mknod_out;
530 540
531 if (!rc) { 541 rc = cifs_get_inode_info_unix(&newinode, full_path,
532 rc = cifs_get_inode_info_unix(&newinode, full_path,
533 inode->i_sb, xid); 542 inode->i_sb, xid);
534 if (pTcon->nocase) 543 if (pTcon->nocase)
535 direntry->d_op = &cifs_ci_dentry_ops; 544 direntry->d_op = &cifs_ci_dentry_ops;
536 else 545 else
537 direntry->d_op = &cifs_dentry_ops; 546 direntry->d_op = &cifs_dentry_ops;
538 if (rc == 0)
539 d_instantiate(direntry, newinode);
540 }
541 } else {
542 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
543 int oplock = 0;
544 u16 fileHandle;
545 FILE_ALL_INFO *buf;
546 547
547 cFYI(1, "sfu compat create special file"); 548 if (rc == 0)
549 d_instantiate(direntry, newinode);
550 goto mknod_out;
551 }
548 552
549 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); 553 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
550 if (buf == NULL) { 554 goto mknod_out;
551 kfree(full_path);
552 rc = -ENOMEM;
553 FreeXid(xid);
554 return rc;
555 }
556 555
557 rc = CIFSSMBOpen(xid, pTcon, full_path, 556
558 FILE_CREATE, /* fail if exists */ 557 cFYI(1, "sfu compat create special file");
559 GENERIC_WRITE /* BB would 558
560 WRITE_OWNER | WRITE_DAC be better? */, 559 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
561 /* Create a file and set the 560 if (buf == NULL) {
562 file attribute to SYSTEM */ 561 kfree(full_path);
563 CREATE_NOT_DIR | CREATE_OPTION_SPECIAL, 562 rc = -ENOMEM;
564 &fileHandle, &oplock, buf, 563 FreeXid(xid);
565 cifs_sb->local_nls, 564 return rc;
566 cifs_sb->mnt_cifs_flags &
567 CIFS_MOUNT_MAP_SPECIAL_CHR);
568
569 /* BB FIXME - add handling for backlevel servers
570 which need legacy open and check for all
571 calls to SMBOpen for fallback to SMBLeagcyOpen */
572 if (!rc) {
573 /* BB Do not bother to decode buf since no
574 local inode yet to put timestamps in,
575 but we can reuse it safely */
576 unsigned int bytes_written;
577 struct win_dev *pdev;
578 pdev = (struct win_dev *)buf;
579 if (S_ISCHR(mode)) {
580 memcpy(pdev->type, "IntxCHR", 8);
581 pdev->major =
582 cpu_to_le64(MAJOR(device_number));
583 pdev->minor =
584 cpu_to_le64(MINOR(device_number));
585 rc = CIFSSMBWrite(xid, pTcon,
586 fileHandle,
587 sizeof(struct win_dev),
588 0, &bytes_written, (char *)pdev,
589 NULL, 0);
590 } else if (S_ISBLK(mode)) {
591 memcpy(pdev->type, "IntxBLK", 8);
592 pdev->major =
593 cpu_to_le64(MAJOR(device_number));
594 pdev->minor =
595 cpu_to_le64(MINOR(device_number));
596 rc = CIFSSMBWrite(xid, pTcon,
597 fileHandle,
598 sizeof(struct win_dev),
599 0, &bytes_written, (char *)pdev,
600 NULL, 0);
601 } /* else if(S_ISFIFO */
602 CIFSSMBClose(xid, pTcon, fileHandle);
603 d_drop(direntry);
604 }
605 kfree(buf);
606 /* add code here to set EAs */
607 }
608 } 565 }
609 566
567 /* FIXME: would WRITE_OWNER | WRITE_DAC be better? */
568 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE,
569 GENERIC_WRITE, CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
570 &fileHandle, &oplock, buf, cifs_sb->local_nls,
571 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
572 if (rc)
573 goto mknod_out;
574
575 /* BB Do not bother to decode buf since no local inode yet to put
576 * timestamps in, but we can reuse it safely */
577
578 pdev = (struct win_dev *)buf;
579 if (S_ISCHR(mode)) {
580 memcpy(pdev->type, "IntxCHR", 8);
581 pdev->major =
582 cpu_to_le64(MAJOR(device_number));
583 pdev->minor =
584 cpu_to_le64(MINOR(device_number));
585 rc = CIFSSMBWrite(xid, pTcon,
586 fileHandle,
587 sizeof(struct win_dev),
588 0, &bytes_written, (char *)pdev,
589 NULL, 0);
590 } else if (S_ISBLK(mode)) {
591 memcpy(pdev->type, "IntxBLK", 8);
592 pdev->major =
593 cpu_to_le64(MAJOR(device_number));
594 pdev->minor =
595 cpu_to_le64(MINOR(device_number));
596 rc = CIFSSMBWrite(xid, pTcon,
597 fileHandle,
598 sizeof(struct win_dev),
599 0, &bytes_written, (char *)pdev,
600 NULL, 0);
601 } /* else if (S_ISFIFO) */
602 CIFSSMBClose(xid, pTcon, fileHandle);
603 d_drop(direntry);
604
605 /* FIXME: add code here to set EAs */
606
607mknod_out:
610 kfree(full_path); 608 kfree(full_path);
609 kfree(buf);
611 FreeXid(xid); 610 FreeXid(xid);
612 return rc; 611 return rc;
613} 612}