1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/fs.h>
24#include <linux/stat.h>
25#include <linux/slab.h>
26#include <linux/namei.h>
27#include <linux/mount.h>
28#include <linux/file.h>
29#include "cifsfs.h"
30#include "cifspdu.h"
31#include "cifsglob.h"
32#include "cifsproto.h"
33#include "cifs_debug.h"
34#include "cifs_fs_sb.h"
35
36static void
37renew_parental_timestamps(struct dentry *direntry)
38{
39
40
41 do {
42 direntry->d_time = jiffies;
43 direntry = direntry->d_parent;
44 } while (!IS_ROOT(direntry));
45}
46
47
48char *
49build_path_from_dentry(struct dentry *direntry)
50{
51 struct dentry *temp;
52 int namelen;
53 int pplen;
54 int dfsplen;
55 char *full_path;
56 char dirsep;
57 struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
58 struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
59
60 if (direntry == NULL)
61 return NULL;
62
63
64
65 dirsep = CIFS_DIR_SEP(cifs_sb);
66 pplen = cifs_sb->prepathlen;
67 if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
68 dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
69 else
70 dfsplen = 0;
71cifs_bp_rename_retry:
72 namelen = pplen + dfsplen;
73 for (temp = direntry; !IS_ROOT(temp);) {
74 namelen += (1 + temp->d_name.len);
75 temp = temp->d_parent;
76 if (temp == NULL) {
77 cERROR(1, "corrupt dentry");
78 return NULL;
79 }
80 }
81
82 full_path = kmalloc(namelen+1, GFP_KERNEL);
83 if (full_path == NULL)
84 return full_path;
85 full_path[namelen] = 0;
86 for (temp = direntry; !IS_ROOT(temp);) {
87 namelen -= 1 + temp->d_name.len;
88 if (namelen < 0) {
89 break;
90 } else {
91 full_path[namelen] = dirsep;
92 strncpy(full_path + namelen + 1, temp->d_name.name,
93 temp->d_name.len);
94 cFYI(0, "name: %s", full_path + namelen);
95 }
96 temp = temp->d_parent;
97 if (temp == NULL) {
98 cERROR(1, "corrupt dentry");
99 kfree(full_path);
100 return NULL;
101 }
102 }
103 if (namelen != pplen + dfsplen) {
104 cERROR(1, "did not end path lookup where expected namelen is %d",
105 namelen);
106
107
108
109 kfree(full_path);
110 goto cifs_bp_rename_retry;
111 }
112
113
114
115
116
117
118
119 if (dfsplen) {
120 strncpy(full_path, tcon->treeName, dfsplen);
121 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
122 int i;
123 for (i = 0; i < dfsplen; i++) {
124 if (full_path[i] == '\\')
125 full_path[i] = '/';
126 }
127 }
128 }
129 strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen);
130 return full_path;
131}
132
133
134
135int
136cifs_create(struct inode *inode, struct dentry *direntry, int mode,
137 struct nameidata *nd)
138{
139 int rc = -ENOENT;
140 int xid;
141 int create_options = CREATE_NOT_DIR;
142 __u32 oplock = 0;
143 int oflags;
144
145
146
147
148
149
150
151 int desiredAccess = GENERIC_READ | GENERIC_WRITE;
152 __u16 fileHandle;
153 struct cifs_sb_info *cifs_sb;
154 struct tcon_link *tlink;
155 struct cifsTconInfo *tcon;
156 char *full_path = NULL;
157 FILE_ALL_INFO *buf = NULL;
158 struct inode *newinode = NULL;
159 int disposition = FILE_OVERWRITE_IF;
160
161 xid = GetXid();
162
163 cifs_sb = CIFS_SB(inode->i_sb);
164 tlink = cifs_sb_tlink(cifs_sb);
165 if (IS_ERR(tlink)) {
166 FreeXid(xid);
167 return PTR_ERR(tlink);
168 }
169 tcon = tlink_tcon(tlink);
170
171 if (oplockEnabled)
172 oplock = REQ_OPLOCK;
173
174 if (nd && (nd->flags & LOOKUP_OPEN))
175 oflags = nd->intent.open.file->f_flags;
176 else
177 oflags = O_RDONLY | O_CREAT;
178
179 full_path = build_path_from_dentry(direntry);
180 if (full_path == NULL) {
181 rc = -ENOMEM;
182 goto cifs_create_out;
183 }
184
185 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
186 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
187 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
188 rc = cifs_posix_open(full_path, &newinode,
189 inode->i_sb, mode, oflags, &oplock, &fileHandle, xid);
190
191
192
193
194
195 if (rc == 0) {
196 if (newinode == NULL)
197 goto cifs_create_get_file_info;
198 else
199 goto cifs_create_set_dentry;
200 } else if ((rc != -EIO) && (rc != -EREMOTE) &&
201 (rc != -EOPNOTSUPP) && (rc != -EINVAL))
202 goto cifs_create_out;
203
204
205
206
207 }
208
209 if (nd && (nd->flags & LOOKUP_OPEN)) {
210
211
212 desiredAccess = 0;
213 if (OPEN_FMODE(oflags) & FMODE_READ)
214 desiredAccess |= GENERIC_READ;
215 if (OPEN_FMODE(oflags) & FMODE_WRITE)
216 desiredAccess |= GENERIC_WRITE;
217
218 if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
219 disposition = FILE_CREATE;
220 else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
221 disposition = FILE_OVERWRITE_IF;
222 else if ((oflags & O_CREAT) == O_CREAT)
223 disposition = FILE_OPEN_IF;
224 else
225 cFYI(1, "Create flag not set in create function");
226 }
227
228
229
230
231 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
232 if (buf == NULL) {
233 rc = -ENOMEM;
234 goto cifs_create_out;
235 }
236
237
238
239
240
241 if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
242 create_options |= CREATE_OPTION_READONLY;
243
244 if (tcon->ses->capabilities & CAP_NT_SMBS)
245 rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
246 desiredAccess, create_options,
247 &fileHandle, &oplock, buf, cifs_sb->local_nls,
248 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
249 else
250 rc = -EIO;
251
252 if (rc == -EIO) {
253
254 rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
255 desiredAccess, create_options,
256 &fileHandle, &oplock, buf, cifs_sb->local_nls,
257 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
258 }
259 if (rc) {
260 cFYI(1, "cifs_create returned 0x%x", rc);
261 goto cifs_create_out;
262 }
263
264
265
266 if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
267 struct cifs_unix_set_info_args args = {
268 .mode = mode,
269 .ctime = NO_CHANGE_64,
270 .atime = NO_CHANGE_64,
271 .mtime = NO_CHANGE_64,
272 .device = 0,
273 };
274
275 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
276 args.uid = (__u64) current_fsuid();
277 if (inode->i_mode & S_ISGID)
278 args.gid = (__u64) inode->i_gid;
279 else
280 args.gid = (__u64) current_fsgid();
281 } else {
282 args.uid = NO_CHANGE_64;
283 args.gid = NO_CHANGE_64;
284 }
285 CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle,
286 current->tgid);
287 } else {
288
289
290
291
292
293 }
294
295cifs_create_get_file_info:
296
297 if (tcon->unix_ext)
298 rc = cifs_get_inode_info_unix(&newinode, full_path,
299 inode->i_sb, xid);
300 else {
301 rc = cifs_get_inode_info(&newinode, full_path, buf,
302 inode->i_sb, xid, &fileHandle);
303 if (newinode) {
304 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
305 newinode->i_mode = mode;
306 if ((oplock & CIFS_CREATE_ACTION) &&
307 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
308 newinode->i_uid = current_fsuid();
309 if (inode->i_mode & S_ISGID)
310 newinode->i_gid = inode->i_gid;
311 else
312 newinode->i_gid = current_fsgid();
313 }
314 }
315 }
316
317cifs_create_set_dentry:
318 if (rc == 0)
319 d_instantiate(direntry, newinode);
320 else
321 cFYI(1, "Create worked, get_inode_info failed rc = %d", rc);
322
323 if (newinode && nd && (nd->flags & LOOKUP_OPEN)) {
324 struct cifsFileInfo *pfile_info;
325 struct file *filp;
326
327 filp = lookup_instantiate_filp(nd, direntry, generic_file_open);
328 if (IS_ERR(filp)) {
329 rc = PTR_ERR(filp);
330 CIFSSMBClose(xid, tcon, fileHandle);
331 goto cifs_create_out;
332 }
333
334 pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock);
335 if (pfile_info == NULL) {
336 fput(filp);
337 CIFSSMBClose(xid, tcon, fileHandle);
338 rc = -ENOMEM;
339 }
340 } else {
341 CIFSSMBClose(xid, tcon, fileHandle);
342 }
343
344cifs_create_out:
345 kfree(buf);
346 kfree(full_path);
347 cifs_put_tlink(tlink);
348 FreeXid(xid);
349 return rc;
350}
351
352int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
353 dev_t device_number)
354{
355 int rc = -EPERM;
356 int xid;
357 struct cifs_sb_info *cifs_sb;
358 struct tcon_link *tlink;
359 struct cifsTconInfo *pTcon;
360 char *full_path = NULL;
361 struct inode *newinode = NULL;
362 int oplock = 0;
363 u16 fileHandle;
364 FILE_ALL_INFO *buf = NULL;
365 unsigned int bytes_written;
366 struct win_dev *pdev;
367
368 if (!old_valid_dev(device_number))
369 return -EINVAL;
370
371 cifs_sb = CIFS_SB(inode->i_sb);
372 tlink = cifs_sb_tlink(cifs_sb);
373 if (IS_ERR(tlink))
374 return PTR_ERR(tlink);
375
376 pTcon = tlink_tcon(tlink);
377
378 xid = GetXid();
379
380 full_path = build_path_from_dentry(direntry);
381 if (full_path == NULL) {
382 rc = -ENOMEM;
383 goto mknod_out;
384 }
385
386 if (pTcon->unix_ext) {
387 struct cifs_unix_set_info_args args = {
388 .mode = mode & ~current_umask(),
389 .ctime = NO_CHANGE_64,
390 .atime = NO_CHANGE_64,
391 .mtime = NO_CHANGE_64,
392 .device = device_number,
393 };
394 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
395 args.uid = (__u64) current_fsuid();
396 args.gid = (__u64) current_fsgid();
397 } else {
398 args.uid = NO_CHANGE_64;
399 args.gid = NO_CHANGE_64;
400 }
401 rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
402 cifs_sb->local_nls,
403 cifs_sb->mnt_cifs_flags &
404 CIFS_MOUNT_MAP_SPECIAL_CHR);
405 if (rc)
406 goto mknod_out;
407
408 rc = cifs_get_inode_info_unix(&newinode, full_path,
409 inode->i_sb, xid);
410
411 if (rc == 0)
412 d_instantiate(direntry, newinode);
413 goto mknod_out;
414 }
415
416 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
417 goto mknod_out;
418
419
420 cFYI(1, "sfu compat create special file");
421
422 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
423 if (buf == NULL) {
424 kfree(full_path);
425 rc = -ENOMEM;
426 FreeXid(xid);
427 return rc;
428 }
429
430
431 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE,
432 GENERIC_WRITE, CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
433 &fileHandle, &oplock, buf, cifs_sb->local_nls,
434 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
435 if (rc)
436 goto mknod_out;
437
438
439
440
441 pdev = (struct win_dev *)buf;
442 if (S_ISCHR(mode)) {
443 memcpy(pdev->type, "IntxCHR", 8);
444 pdev->major =
445 cpu_to_le64(MAJOR(device_number));
446 pdev->minor =
447 cpu_to_le64(MINOR(device_number));
448 rc = CIFSSMBWrite(xid, pTcon,
449 fileHandle,
450 sizeof(struct win_dev),
451 0, &bytes_written, (char *)pdev,
452 NULL, 0);
453 } else if (S_ISBLK(mode)) {
454 memcpy(pdev->type, "IntxBLK", 8);
455 pdev->major =
456 cpu_to_le64(MAJOR(device_number));
457 pdev->minor =
458 cpu_to_le64(MINOR(device_number));
459 rc = CIFSSMBWrite(xid, pTcon,
460 fileHandle,
461 sizeof(struct win_dev),
462 0, &bytes_written, (char *)pdev,
463 NULL, 0);
464 }
465 CIFSSMBClose(xid, pTcon, fileHandle);
466 d_drop(direntry);
467
468
469
470mknod_out:
471 kfree(full_path);
472 kfree(buf);
473 FreeXid(xid);
474 cifs_put_tlink(tlink);
475 return rc;
476}
477
478struct dentry *
479cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
480 struct nameidata *nd)
481{
482 int xid;
483 int rc = 0;
484 __u32 oplock = 0;
485 __u16 fileHandle = 0;
486 bool posix_open = false;
487 struct cifs_sb_info *cifs_sb;
488 struct tcon_link *tlink;
489 struct cifsTconInfo *pTcon;
490 struct cifsFileInfo *cfile;
491 struct inode *newInode = NULL;
492 char *full_path = NULL;
493 struct file *filp;
494
495 xid = GetXid();
496
497 cFYI(1, "parent inode = 0x%p name is: %s and dentry = 0x%p",
498 parent_dir_inode, direntry->d_name.name, direntry);
499
500
501
502 cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
503 tlink = cifs_sb_tlink(cifs_sb);
504 if (IS_ERR(tlink)) {
505 FreeXid(xid);
506 return (struct dentry *)tlink;
507 }
508 pTcon = tlink_tcon(tlink);
509
510
511
512
513
514 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
515 int i;
516 for (i = 0; i < direntry->d_name.len; i++)
517 if (direntry->d_name.name[i] == '\\') {
518 cFYI(1, "Invalid file name");
519 rc = -EINVAL;
520 goto lookup_out;
521 }
522 }
523
524
525
526
527
528 if (nd && (nd->flags & LOOKUP_EXCL)) {
529 d_instantiate(direntry, NULL);
530 rc = 0;
531 goto lookup_out;
532 }
533
534
535
536
537 full_path = build_path_from_dentry(direntry);
538 if (full_path == NULL) {
539 rc = -ENOMEM;
540 goto lookup_out;
541 }
542
543 if (direntry->d_inode != NULL) {
544 cFYI(1, "non-NULL inode in lookup");
545 } else {
546 cFYI(1, "NULL inode in lookup");
547 }
548 cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode);
549
550
551
552
553
554
555
556
557
558
559
560 if (pTcon->unix_ext) {
561 if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
562 (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
563 (nd->intent.open.file->f_flags & O_CREAT)) {
564 rc = cifs_posix_open(full_path, &newInode,
565 parent_dir_inode->i_sb,
566 nd->intent.open.create_mode,
567 nd->intent.open.file->f_flags, &oplock,
568 &fileHandle, xid);
569
570
571
572
573
574
575
576 if ((rc == 0) || (rc == -ENOENT))
577 posix_open = true;
578 else if ((rc == -EINVAL) || (rc != -EOPNOTSUPP))
579 pTcon->broken_posix_open = true;
580 }
581 if (!posix_open)
582 rc = cifs_get_inode_info_unix(&newInode, full_path,
583 parent_dir_inode->i_sb, xid);
584 } else
585 rc = cifs_get_inode_info(&newInode, full_path, NULL,
586 parent_dir_inode->i_sb, xid, NULL);
587
588 if ((rc == 0) && (newInode != NULL)) {
589 d_add(direntry, newInode);
590 if (posix_open) {
591 filp = lookup_instantiate_filp(nd, direntry,
592 generic_file_open);
593 if (IS_ERR(filp)) {
594 rc = PTR_ERR(filp);
595 CIFSSMBClose(xid, pTcon, fileHandle);
596 goto lookup_out;
597 }
598
599 cfile = cifs_new_fileinfo(fileHandle, filp, tlink,
600 oplock);
601 if (cfile == NULL) {
602 fput(filp);
603 CIFSSMBClose(xid, pTcon, fileHandle);
604 rc = -ENOMEM;
605 goto lookup_out;
606 }
607 }
608
609
610 renew_parental_timestamps(direntry);
611
612 } else if (rc == -ENOENT) {
613 rc = 0;
614 direntry->d_time = jiffies;
615 d_add(direntry, NULL);
616
617
618 } else if (rc != -EACCES) {
619 cERROR(1, "Unexpected lookup error %d", rc);
620
621
622 }
623
624lookup_out:
625 kfree(full_path);
626 cifs_put_tlink(tlink);
627 FreeXid(xid);
628 return ERR_PTR(rc);
629}
630
631static int
632cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
633{
634 if (nd->flags & LOOKUP_RCU)
635 return -ECHILD;
636
637 if (direntry->d_inode) {
638 if (cifs_revalidate_dentry(direntry))
639 return 0;
640 else
641 return 1;
642 }
643
644
645
646
647
648 if (!nd)
649 return 0;
650
651
652
653
654
655
656 if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) {
657 if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
658 return 0;
659 }
660
661 if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled)
662 return 0;
663
664 return 1;
665}
666
667
668
669
670
671
672
673
674
675
676const struct dentry_operations cifs_dentry_ops = {
677 .d_revalidate = cifs_d_revalidate,
678 .d_automount = cifs_dfs_d_automount,
679
680};
681
682static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode,
683 struct qstr *q)
684{
685 struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls;
686 unsigned long hash;
687 int i;
688
689 hash = init_name_hash();
690 for (i = 0; i < q->len; i++)
691 hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
692 hash);
693 q->hash = end_name_hash(hash);
694
695 return 0;
696}
697
698static int cifs_ci_compare(const struct dentry *parent,
699 const struct inode *pinode,
700 const struct dentry *dentry, const struct inode *inode,
701 unsigned int len, const char *str, const struct qstr *name)
702{
703 struct nls_table *codepage = CIFS_SB(pinode->i_sb)->local_nls;
704
705 if ((name->len == len) &&
706 (nls_strnicmp(codepage, name->name, str, len) == 0))
707 return 0;
708 return 1;
709}
710
711const struct dentry_operations cifs_ci_dentry_ops = {
712 .d_revalidate = cifs_d_revalidate,
713 .d_hash = cifs_ci_hash,
714 .d_compare = cifs_ci_compare,
715 .d_automount = cifs_dfs_d_automount,
716};
717