source: trunk/client/src/smbwrp.c

Last change on this file was 976, checked in by Yuri Dario, 9 years ago

Store samba data in dynamic allocated memory for new caching code. Added
deallocator code. ticket#274.

  • Property svn:eol-style set to native
File size: 33.6 KB
Line 
1/*
2 Netdrive Samba client plugin
3 samba library wrappers
4 Copyright (C) netlabs.org 2003-2012
5 Copyright (C) bww bitwise works GmbH 2012-2016
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#include "includes.h"
23#include "rpc_client/cli_pipe.h"
24#include "librpc/gen_ndr/ndr_srvsvc_c.h"
25#include "libsmb/libsmb.h"
26#include "libsmb/clirap.h"
27#include "trans2.h"
28
29#include "dircache.h"
30#include "smbwrp.h"
31
32/*
33 * Wrapper for cli_errno to return not connected error on negative fd
34 * Now returns an OS/2 return code instead of lerrno.
35 */
36int os2cli_errno(cli_state * cli)
37{
38 if (cli->fd == -1)
39 return maperror(ENOTCONN);
40
41 return maperror(cli_errno(cli));
42}
43
44void smbwrp_Logging(Resource *pRes)
45{
46 if (pRes && pRes->loglevel > 0)
47 {
48 // init samba for debug messages
49 setup_logging("ndpsmb", DEBUG_FILE);
50
51 char smblevel[3];
52 itoa(pRes->loglevel, smblevel, 10);
53 lp_set_logfile(pRes->smb_logfile);
54 lp_set_cmdline("log level", smblevel);
55 reopen_logs();
56 }
57
58 return;
59}
60
61const char * smbwrp_getVersion()
62{
63 return samba_version_string();
64}
65
66int _System smbwrp_getclisize(void)
67{
68 return sizeof(struct cli_state);
69}
70
71/*
72 * initialise structures
73 */
74int _System smbwrp_init(Resource *pRes)
75{
76 char *p;
77
78 if (pRes->smb_initialised)
79 return 0;
80
81 pRes->smb_initialised = 1;
82
83 lp_set_in_client(true); // Make sure that we tell lp_load we are client
84
85 load_case_tables();
86
87 if (!lp_load(get_dyn_CONFIGFILE(),true,false,false,true))
88 debuglocal(pRes, 0,("The initial smb.conf is missing, defaults are used!\n"));
89
90 load_interfaces();
91
92 if (!init_names())
93 return 1;
94
95 smbwrp_Logging(pRes);
96
97 debuglocal(pRes, 5,("smbwrp_init done\n"));
98 /*
99 if ((p=smbw_getshared("RESOLVE_ORDER")))
100 lp_set_name_resolve_order(p);
101 */
102 return 0;
103
104}
105
106void smbwrp_initthread(void)
107{
108 /*
109 * Block SIGPIPE (from lib/util_sock.c: write())
110 * It is not needed and should not stop execution
111 */
112 BlockSignals(True, SIGPIPE);
113 return;
114}
115
116#if 0
117/*
118 * remove redundent stuff from a filename
119 */
120void clean_fname(char *name)
121{
122 char *p, *p2;
123 int l;
124 int modified = 1;
125
126 if (!name) return;
127
128 while (modified) {
129 modified = 0;
130
131 if ((p=strstr(name,"/./"))) {
132 modified = 1;
133 while (*p) {
134 p[0] = p[2];
135 p++;
136 }
137 }
138
139 if ((p=strstr(name,"//"))) {
140 modified = 1;
141 while (*p) {
142 p[0] = p[1];
143 p++;
144 }
145 }
146
147 if (strcmp(name,"/../")==0) {
148 modified = 1;
149 name[1] = 0;
150 }
151
152 if ((p=strstr(name,"/../"))) {
153 modified = 1;
154 for (p2=(p>name?p-1:p);p2>name;p2--) {
155 if (p2[0] == '/')
156 break;
157 }
158 while (*p2) {
159 p2[0] = p2[3];
160 p2++;
161 }
162 }
163
164 if (strcmp(name,"/..")==0) {
165 modified = 1;
166 name[1] = 0;
167 }
168
169 l = strlen(name);
170 p = l >= 3 ? (name+l-3):name;
171 if (strcmp(p,"/..")==0) {
172 modified = 1;
173 for (p2=p-1;p2>name;p2--) {
174 if (p2[0] == '/')
175 break;
176 }
177 if (p2==name) {
178 p[0] = '/';
179 p[1] = 0;
180 } else
181 p2[0] = 0;
182 }
183
184 l = strlen(name);
185 p = l >= 2 ? (name+l-2):name;
186 if (strcmp(p,"/.")==0) {
187 if (p == name)
188 p[1] = 0;
189 else
190 p[0] = 0;
191 }
192
193 if (strncmp(p=name,"./",2) == 0) {
194 modified = 1;
195 do {
196 p[0] = p[2];
197 } while (*p++);
198 }
199
200 l = strlen(p=name);
201 if (l > 1 && p[l-1] == '/') {
202 modified = 1;
203 p[l-1] = 0;
204 }
205 }
206}
207#endif
208
209/*
210 * return a connection to a server
211 */
212int _System smbwrp_connect(Resource* pRes, cli_state ** cli)
213{
214 smbwrp_server * srv = &pRes->srv;
215 char * server = srv->server_name;
216 char * share = *(srv->share_name) ? srv->share_name : "IPC$";
217 char * workgroup = srv->workgroup;
218 struct nmb_name called, calling;
219 char *p, *server_n = server;
220 fstring group;
221 struct sockaddr_storage ss;
222 struct cli_state * c;
223 char* dev_type;
224 int loginerror = 0;
225 NTSTATUS status;
226
227 zero_sockaddr(&ss);
228
229 debuglocal(pRes, 1,"Connecting to \\\\%s:*********@%s:%s\\%s. Master %s:%d\n", srv->username, workgroup, server, share, srv->master, srv->ifmastergroup);
230
231 if (!*server) {
232 struct sockaddr_storage sip;
233
234 if (*workgroup)
235 {
236 if (!find_master_ip(workgroup, &sip))
237 return 1;
238
239 fstrcpy(group, inet_ntoa(sip.sin_addr));
240 server_n = group;
241 } else if (*srv->master)
242 {
243 if (srv->ifmastergroup)
244 {
245 if (!find_master_ip(srv->master, &sip))
246 return 11;
247
248 strncpy(srv->master, inet_ntoa(sip.sin_addr), sizeof(srv->master) - 1);
249 srv->ifmastergroup = 0;
250 }
251 server_n = srv->master;
252 } else
253 return 10;
254 }
255
256 make_nmb_name(&calling, global_myname(), 0x0);
257 //make_nmb_name(&calling, "WORK", 0x0); // this machine name
258 make_nmb_name(&called , server_n, 0x20);
259
260 again:
261 zero_sockaddr(&ss);
262
263 // have to open a new connection
264 if (!(c=cli_initialise()))
265 return 2;
266
267 cli_set_timeout(c, 10000); // 10 seconds
268
269 if (pRes->krb5support == 1)
270 {
271 debuglocal(pRes, 1,"Kerberos support enabled\n");
272 c->use_kerberos = True;
273 }
274
275 if (!NT_STATUS_IS_OK(cli_connect(c, server_n, &ss)))
276 return 3;
277
278 if (!cli_session_request(c, &calling, &called)) {
279 cli_shutdown(c);
280 if (strcmp(called.name, "*SMBSERVER")) {
281 make_nmb_name(&called , "*SMBSERVER", 0x20);
282 goto again;
283 }
284 return 4;
285 }
286
287 debuglocal(pRes, 4,"session request ok\n");
288
289 if (!NT_STATUS_IS_OK(cli_negprot(c))) {
290 cli_shutdown(c);
291 return 5;
292 }
293
294 debuglocal(pRes, 4,"session setuping for <%s>/<********> in <%s> %08x %08x %08x\n", srv->username, workgroup, c->protocol, c->sec_mode, c->capabilities);
295
296 if (!NT_STATUS_IS_OK(cli_session_setup(c, srv->username,
297 srv->password, strlen(srv->password),
298 srv->password, strlen(srv->password),
299 workgroup)))
300 {
301 debuglocal(pRes, 4,"%s/******** login failed\n", srv->username);
302 loginerror = 1; // save the login error
303
304 // try an anonymous login if it failed
305 if (!NT_STATUS_IS_OK(cli_session_setup(c, "", "", 0,"", 0, workgroup))) {
306 debuglocal(pRes, 4,"Anonymous login failed\n");
307 cli_shutdown(c);
308 return 6;
309 }
310 debuglocal(pRes, 4,"Anonymous login successful\n");
311 status = cli_init_creds(c, "", lp_workgroup(), "");
312 } else {
313 status = cli_init_creds(c, srv->username, workgroup, srv->password);
314 }
315
316 if (!NT_STATUS_IS_OK(status)) {
317 debuglocal(pRes, 4,"cli_init_creds() failed\n");
318 cli_shutdown(c);
319 // if loginerror is != 0 means normal login failed, but anonymous login worked
320 if (loginerror !=0)
321 return 6;
322 else
323 return 7;
324 }
325
326 debuglocal(pRes, 4,"session setup ok. Sending tconx <%s> <********>\n", share);
327
328 // YD ticket:58 we need to check resource type to avoid connecting to printers.
329 // dev type is set to IPC for IPC$, A: for everything else (printers use LPT1:)
330 if (!strcmp( share, "IPC$"))
331 dev_type = "IPC";
332 else
333 dev_type = "A:";
334
335 if (!NT_STATUS_IS_OK(cli_tcon_andx(c, share, dev_type,
336 srv->password, strlen(srv->password)+1)))
337 {
338 cli_shutdown(c);
339 // if loginerror is != 0 means normal login failed, but anonymous login worked
340 if (loginerror !=0)
341 return 6;
342 else
343 return 7;
344 }
345
346 debuglocal(pRes, 4,"tconx ok. cli caps %08x\n", c->capabilities);
347
348 // save cli_state pointer
349 *cli = c;
350
351 return 0;
352}
353
354/*
355 * close a connection to a server
356 */
357void _System smbwrp_disconnect(Resource* pRes, cli_state * cli)
358{
359 // this call will free all buffers, close handles and free cli mem
360 if (pRes && cli)
361 cli_shutdown( cli);
362}
363
364/*
365 * a wrapper for open()
366 */
367int _System smbwrp_open(Resource *pRes, cli_state * cli, smbwrp_file * file)
368{
369 uint16_t fd = 0;
370
371 if (!cli || !file || !*file->fname)
372 return maperror(EINVAL);
373
374 if (file->denymode < DENY_ALL || file->denymode > DENY_NONE)
375 file->denymode = DENY_NONE;
376
377 debuglocal(pRes, 4,"cli_open(%s) attr %08x mode %02x denymode %02x\n", file->fname, file->openattr, file->openmode, file->denymode);
378 if (!NT_STATUS_IS_OK(cli_open(cli, file->fname, file->openmode, file->denymode, &fd)))
379 return os2cli_errno(cli);
380
381 file->fd = fd;
382 file->updatetime = 0;
383 file->offset = 0;
384 return 0;
385}
386
387/*
388 * a wrapper for read()
389 */
390int _System smbwrp_read(Resource *pRes, cli_state * cli, smbwrp_file * file, void *buf, unsigned long count, unsigned long * result)
391{
392 int ret;
393
394 if (!cli || !file || !buf || !result)
395 return maperror(EINVAL);
396
397 *result = 0;
398 ret = cli_read(cli, file->fd, buf, file->offset, count);
399 if (ret == -1)
400 return os2cli_errno(cli);
401
402 file->offset += ret;
403 *result = ret;
404 return 0;
405}
406
407/*
408 * a wrapper for write()
409 */
410int _System smbwrp_write(Resource *pRes, cli_state * cli, smbwrp_file * file, void *buf, unsigned long count, unsigned long * result)
411{
412 NTSTATUS status;
413 size_t ret;
414
415 if (!cli || !file || !buf || !result)
416 return maperror(EINVAL);
417
418 *result = 0;
419 debuglocal(pRes, 10, "Write %x %d %lld %d\n", cli, file->fd, file->offset, count);
420 status = cli_writeall(cli, file->fd, 0, buf, file->offset, count, &ret);
421 if (!NT_STATUS_IS_OK(status))
422 return os2cli_errno(cli);
423
424 file->updatetime = 1;
425 file->offset += ret;
426 *result = ret;
427 return 0;
428}
429
430/*
431 * a wrapper for close()
432 */
433int _System smbwrp_close(Resource *pRes, cli_state * cli, smbwrp_file * file)
434{
435 int rc = 0;
436 if (!cli || !file)
437 return maperror(EINVAL);
438
439 debuglocal(pRes, 4,"smpwrp_close updatetime: %d\n", file->updatetime);
440
441 if (file->updatetime == 1)
442 {
443 file->mtime = time(NULL);
444 debuglocal(pRes, 4,"cli_close new mtime %lu\n", file->mtime);
445 }
446
447 if (!NT_STATUS_IS_OK(cli_close(cli, file->fd)))
448 rc = os2cli_errno(cli);
449
450 if (!rc && (file->openattr || file->mtime || file->ctime))
451 {
452 debuglocal(pRes, 4,"Set pathinfo on close %s %08x %d %d\n", file->fname, file->openattr, file->mtime, file->ctime);
453 if (!NT_STATUS_IS_OK(cli_setpathinfo_basic(cli, file->fname, file->ctime, 0, file->mtime, 0, file->openattr)))
454 {
455 debuglocal(pRes, 4,"Set pathinfo on close failed %d\n", os2cli_errno(cli));
456 }
457 }
458
459 file->openattr = 0;
460 file->mtime = 0;
461 file->ctime = 0;
462 file->updatetime = 0;
463 file->fd = -1;
464 file->offset = 0;
465 *file->fname = 0;
466 return rc;
467}
468
469int _System smbwrp_setfilesize(Resource *pRes, cli_state * cli, smbwrp_file * file, long long newsize)
470{
471 int rc = 0;
472 if (!cli || !file)
473 return maperror(EINVAL);
474
475 debuglocal(pRes, 4,"cli_setnewfilesize(%s) %lld\n", file->fname, newsize);
476 if (!NT_STATUS_IS_OK(cli_ftruncate(cli, file->fd, newsize)))
477 {
478 if (newsize)
479 rc = os2cli_errno(cli);
480
481 if (!NT_STATUS_IS_OK(cli_close(cli, file->fd)))
482 return os2cli_errno(cli);
483
484 uint16_t fd = 0;
485 file->fd = -1;
486 file->offset = 0;
487 file->openmode &= ~(O_CREAT | O_EXCL);
488 file->openmode |= O_TRUNC;
489 debuglocal(pRes, 4,"cli_setnewfileszie : cli_open(%s) attr %08x mode %02x denymode %02x\n", file->fname, file->openattr, file->openmode, file->denymode);
490 if (!NT_STATUS_IS_OK(cli_open(cli, file->fname, file->openmode, file->denymode, &fd)))
491 return os2cli_errno(cli);
492
493 file->fd = fd;
494 }
495 return 0;
496}
497
498/*
499 * a wrapper for rename()
500 */
501int _System smbwrp_rename(Resource *pRes, cli_state * cli, char *oldname, char *newname)
502{
503 if (!cli || !oldname || !newname)
504 return maperror(EINVAL);
505
506 debuglocal(pRes, 4,"Rename <%s> -> <%s>\n", oldname, newname);
507 if (!NT_STATUS_IS_OK(cli_rename(cli, oldname, newname)))
508 return os2cli_errno(cli);
509
510 return 0;
511}
512
513
514/*
515 * a wrapper for chmod()
516 */
517int _System smbwrp_setattr(Resource *pRes, cli_state * cli, smbwrp_fileinfo *finfo)
518{
519 if (!cli || !finfo || !*finfo->fname)
520 return maperror(EINVAL);
521
522 debuglocal(pRes, 4,"Setting on <%s> attr %04x, time %lu (timezone /%lu\n", finfo->fname, finfo->attr, finfo->mtime, finfo->mtime + get_time_zone(finfo->mtime));
523 // we already have gmt time, so no need to add timezone
524 // if (!cli_setatr(cli, finfo->fname, finfo->attr, finfo->mtime + (finfo->mtime == 0 ? 0 : get_time_zone(finfo->mtime)))
525 if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo->fname, finfo->attr, finfo->mtime))
526 && !NT_STATUS_IS_OK(cli_setatr(cli, finfo->fname, finfo->attr, 0)))
527 return os2cli_errno(cli);
528
529 return 0;
530}
531
532/*
533 * a wrapper for unlink()
534 */
535int _System smbwrp_unlink(Resource *pRes, cli_state * cli, const char *fname)
536{
537 if (!cli || !fname)
538 return maperror(EINVAL);
539
540#if 0
541 if (strncmp(cli->dev, "LPT", 3) == 0)
542 {
543 int job = smbw_stat_printjob(cli, fname, NULL, NULL);
544 if (job == -1)
545 goto failed;
546
547 if (cli_printjob_del(cli, job) != 0)
548 goto failed;
549
550 } else
551#endif
552 if (!NT_STATUS_IS_OK(cli_unlink(cli, fname, aSYSTEM | aHIDDEN)))
553 return os2cli_errno(cli);
554
555 return 0;
556}
557
558/*
559 * a wrapper for lseek()
560 */
561int _System smbwrp_lseek(Resource *pRes, cli_state * cli, smbwrp_file * file, int whence, long long offset)
562{
563 off_t size;
564 if (!cli || !file)
565 return maperror(EINVAL);
566
567 debuglocal(pRes, 4,"lseek %d %lld %lld\n", whence, offset, file->offset);
568
569 switch (whence) {
570 case SEEK_SET:
571 if (offset < 0)
572 return maperror(EINVAL);
573 file->offset = offset;
574 break;
575 case SEEK_CUR:
576 file->offset += offset;
577 break;
578 case SEEK_END:
579 if (offset > 0)
580 return maperror(EINVAL);
581 if (!NT_STATUS_IS_OK(cli_qfileinfo_basic(cli, file->fd,
582 NULL, &size, NULL, NULL, NULL,NULL, NULL)) &&
583 !NT_STATUS_IS_OK(cli_getattrE(cli, file->fd,
584 NULL, &size, NULL, NULL, NULL)))
585 return os2cli_errno(cli);
586 file->offset = size + offset;
587 break;
588 default:
589 return maperror(EINVAL);
590 }
591
592 return 0;
593}
594
595/*
596 * try to do a QPATHINFO and if that fails then do a getatr
597 * this is needed because win95 sometimes refuses the qpathinfo
598 */
599int _System smbwrp_getattr(Resource *pRes, smbwrp_server *srv, cli_state * cli, smbwrp_fileinfo *finfo)
600{
601 SMB_INO_T ino = 0;
602 struct timespec ctime;
603 struct timespec mtime;
604 struct timespec atime;
605
606 if (!cli || !finfo || !*finfo->fname)
607 return maperror(EINVAL);
608
609 debuglocal(pRes, 4,"getattr %d %d <%s>\n", cli->capabilities & CAP_NOPATHINFO2, cli->capabilities & CAP_NT_SMBS, finfo->fname);
610 if (!(cli->capabilities & CAP_NOPATHINFO2) &&
611 NT_STATUS_IS_OK(cli_qpathinfo2(cli, finfo->fname, &ctime, &atime,
612 &mtime, NULL, (off_t *)&finfo->size, (unsigned short *)&finfo->attr,
613 &ino)))
614 {
615 finfo->attr &= 0x7F;
616 finfo->ctime = convert_timespec_to_time_t(ctime);
617 finfo->atime = convert_timespec_to_time_t(atime);
618 finfo->mtime = convert_timespec_to_time_t(mtime);
619 return 0;
620 }
621
622 // fd == -1 means the connection is broken */
623 if (cli->fd == -1)
624 return maperror(ENOTCONN);
625
626 /* If the path is not on a share (it is a workgroup or a server),
627 * then cli_qpathinfo2 obviously fails. Return some fake information
628 * about the directory.
629 */
630 if (*srv->server_name == 0
631 || (strcmp(cli->dev,"IPC") == 0)
632 || *srv->share_name == 0
633 || (stricmp(srv->share_name,"IPC$") == 0)
634 || (strncmp(cli->dev,"LPT",3) == 0))
635 {
636 debuglocal(pRes, 4,"getattr not a share.\n");
637 *(time_t *)&finfo->ctime = time (NULL);
638 *(time_t *)&finfo->atime = time (NULL);
639 *(time_t *)&finfo->mtime = time (NULL);
640 finfo->size = 0;
641 finfo->easize = 0;
642 finfo->attr = aDIR;
643 return 0;
644 }
645
646 // if this is NT then don't bother with the getatr */
647 if (cli->capabilities & CAP_NT_SMBS && !(cli->capabilities & CAP_NOPATHINFO2))
648 {
649 int ret = cli_errno(cli);
650 /*
651 * cli_qpathinfo* reports EINVAL when path of given file not exists
652 * thus there is no real situation when EINVAL should be returned to
653 * client at this point, we just replace it to ENOTDIR
654 */
655 if (ret == EINVAL)
656 ret = ENOTDIR;
657
658 return maperror(ret);
659 }
660
661 if (NT_STATUS_IS_OK(cli_getatr(cli, finfo->fname, (unsigned short *)&finfo->attr, &finfo->size, (time_t *)&finfo->mtime)))
662 {
663 debuglocal(pRes, 10,("gotattr1 %08x <%s>\n", finfo->attr, finfo->fname));
664 finfo->mtime -= get_time_zone(finfo->mtime);
665 finfo->atime = finfo->atime; //was mtime
666 finfo->ctime = finfo->ctime; //was mtime
667 cli->capabilities &= CAP_NOPATHINFO2;
668 return 0;
669 }
670
671 return os2cli_errno(cli);
672}
673
674/*
675 * try to do a QPATHINFO and if that fails then do a getatr
676 * this is needed because win95 sometimes refuses the qpathinfo
677 */
678int _System smbwrp_fgetattr(Resource *pRes, cli_state * cli, smbwrp_file *file, smbwrp_fileinfo *finfo)
679{
680 struct timespec ctime;
681 struct timespec mtime;
682 struct timespec atime;
683 SMB_INO_T ino = 0;
684
685 if (!cli || !file || !finfo)
686 return maperror(EINVAL);
687
688
689 strncpy(finfo->fname, file->fname, sizeof(finfo->fname) - 1);
690 if (!NT_STATUS_IS_OK(cli_qfileinfo_basic(cli, file->fd,
691 (unsigned short *)&finfo->attr, (off_t *)&finfo->size, &ctime,
692 &atime, &mtime, NULL, &ino)))
693 {
694 if (!NT_STATUS_IS_OK(cli_getattrE(cli, file->fd,
695 (unsigned short *)&finfo->attr, (&finfo->size),
696 (time_t *)&finfo->ctime, (time_t *)&finfo->atime,
697 (time_t *)&finfo->mtime)))
698 return os2cli_errno(cli);
699 else
700 {
701 finfo->ctime -= get_time_zone(finfo->ctime);
702 finfo->atime -= get_time_zone(finfo->atime);
703 finfo->mtime -= get_time_zone(finfo->mtime);
704 }
705 }
706 else
707 {
708 finfo->ctime = convert_timespec_to_time_t(ctime);
709 finfo->atime = convert_timespec_to_time_t(atime);
710 finfo->mtime = convert_timespec_to_time_t(mtime);
711 }
712
713 return 0;
714}
715
716// =============================DIRECTORY ROUTINES============================
717
718/*
719 * add a entry to a directory listing
720 */
721static void smbwrp_dir_add(const char* mnt, smbwrp_fileinfo *finfo, const char *mask, void *state)
722{
723 if (state && finfo)
724 {
725 filelist_state *st = (filelist_state *)state;
726 char fullname[ _MAX_PATH] = {0};
727 debuglocal(st->pConn->pRes, 8,"adding <%s> %d %d %d\n", finfo->fname, sizeof(st->finfo), st->datalen, sizeof(st->finfo.fname));
728 memcpy(&st->finfo, finfo, sizeof(st->finfo));
729 strncpy(fullname, st->dir, strlen(st->dir));
730 strncat(fullname, finfo->fname, sizeof(fullname) - strlen(fullname) -1);
731 strncpy(st->finfo.fname, fullname, sizeof(st->finfo.fname));
732 addFindInfoL(st->pConn->pRes, st->plist, &st->finfo, st->ulAttribute, st->dir_mask);
733 }
734 return;
735}
736
737static void smbwrp_special_add(const char * name, void * state)
738{
739smbwrp_fileinfo finfo = {0};
740
741 if (!name)
742 return;
743
744 ZERO_STRUCT(finfo);
745
746 strncpy(finfo.fname, name, sizeof(finfo.fname) - 1);
747 finfo.attr = aRONLY | aDIR;
748
749 smbwrp_dir_add("", &finfo, NULL, state);
750 return;
751}
752
753static void smbwrp_printjob_add(struct print_job_info *job, void * state)
754{
755 smbwrp_fileinfo finfo = {0};
756
757 ZERO_STRUCT(finfo);
758
759 //printf("Printjob <%s>\n", job->name);
760
761 strncpy(finfo.fname, job->name, sizeof(finfo.fname) - 1);
762 finfo.mtime = job->t - get_time_zone(job->t);
763 finfo.atime = finfo.atime; //was mtime
764 finfo.ctime = finfo.ctime; //was mtime
765 finfo.attr = aRONLY;
766 finfo.size = job->size;
767
768 smbwrp_dir_add("", &finfo, NULL, state);
769 return;
770}
771
772static void smbwrp_share_add(const char *share, uint32 type,
773 const char *comment, void *state)
774{
775 smbwrp_fileinfo finfo = {0};
776
777 // strip administrative names and printers from list
778 if (type == STYPE_PRINTQ || strcmp(share,"IPC$") == 0)
779 return;
780
781 ZERO_STRUCT(finfo);
782
783 strncpy(finfo.fname, share, sizeof(finfo.fname) - 1);
784 finfo.attr = aRONLY | aDIR;
785
786 smbwrp_dir_add("", &finfo, NULL, state);
787 return;
788}
789
790/*
791 * Do a directory listing, calling fn on each file found.
792 * Modified from cli_list
793 */
794static int list_files(struct cli_state *cli, const char *mask, uint16 attribute,
795 void (*fn)(const char *, smbwrp_fileinfo *, const char *,
796 void *), filelist_state *state)
797{
798 TALLOC_CTX *frame = talloc_stackframe();
799 struct event_context *ev;
800 struct tevent_req *req;
801 NTSTATUS status = NT_STATUS_NO_MEMORY;
802 struct file_info *finfo;
803 size_t i, num_finfo;
804 uint16_t info_level;
805 void *dircachectx = NULL;
806 Resource *pRes = state->pConn->pRes;
807
808 // Try to get the listing from cache.
809 debuglocal(pRes, 9, "list_files: check cache %s\n", state->fullpath);
810 if (dircache_list_files(pRes->pdc, addFindInfoCachedL, state->plist,
811 state->dir_mask, (char*) state->fullpath, &num_finfo)) {
812 debuglocal(pRes, 9, "list_files: %s, got %d from cache\n",
813 state->fullpath, num_finfo);
814 return(num_finfo); // Got from cache
815 }
816
817 if (cli_has_async_calls(cli)) {
818 /*
819 * Can't use sync call while an async call is in flight
820 */
821 status = NT_STATUS_INVALID_PARAMETER;
822 goto fail;
823 }
824 ev = event_context_init(frame);
825 if (ev == NULL)
826 goto fail;
827
828 info_level = (cli->capabilities & CAP_NT_SMBS)
829 ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_EA_SIZE;
830
831 debuglocal(pRes, 4,"list_files level %d. mask <%s>\n", info_level, mask);
832
833 req = cli_list_send(frame, ev, cli, mask, attribute, info_level);
834 if (req == NULL)
835 goto fail;
836
837 if (!tevent_req_poll(req, ev)) {
838 status = map_nt_error_from_unix(errno);
839 goto fail;
840 }
841
842 status = cli_list_recv(req, frame, &finfo, &num_finfo);
843 if (!NT_STATUS_IS_OK(status))
844 goto fail;
845
846 dircachectx = dircache_write_begin(pRes->pdc, state->dir_mask,
847 (char*) state->fullpath, num_finfo);
848
849 debuglocal(pRes, 4,"list_files: got %d files\n", num_finfo);
850
851 for (i=0; i<num_finfo; i++) {
852 // dinamically allocate finfo data structure, cache can keep only pointers
853 smbwrp_fileinfo* wrpfinfo = (smbwrp_fileinfo*)malloc( sizeof(smbwrp_fileinfo));
854 //as samba and this client have different finfo, we need to convert
855 memset(wrpfinfo, 0, sizeof(smbwrp_fileinfo));
856 wrpfinfo->size = finfo[i].size;
857 wrpfinfo->attr = finfo[i].mode;
858 wrpfinfo->ctime = convert_timespec_to_time_t(finfo[i].ctime_ts);
859 wrpfinfo->mtime = convert_timespec_to_time_t(finfo[i].mtime_ts);
860 wrpfinfo->atime = convert_timespec_to_time_t(finfo[i].atime_ts);
861 wrpfinfo->easize = finfo[i].easize;
862 strncpy(wrpfinfo->fname, finfo[i].name, sizeof(wrpfinfo->fname) -1);
863 // add to netdrive plist
864 debuglocal(pRes, 9,"list_files: dircachectx %x, %s->%p\n",
865 dircachectx, wrpfinfo->fname, wrpfinfo);
866 addFindInfoCachedL(state->plist, wrpfinfo);
867 // Also add the entry to the cache, this pointer will be released
868 // when cache will be deleted
869 dircache_write_entry(pRes->pdc, dircachectx, wrpfinfo->fname, wrpfinfo);
870 }
871
872 dircache_write_end(pRes->pdc, dircachectx);
873
874 fail:
875 TALLOC_FREE(frame);
876 return num_finfo;
877}
878
879/*
880 * open a directory on the server
881 */
882int _System smbwrp_filelist(Resource *pRes, smbwrp_server *srv, cli_state * cli, filelist_state * state)
883{
884 if (!srv || !cli || !state || !*state->mask)
885 return maperror(EINVAL);
886
887 debuglocal(pRes, 1,"Filelist <%s> on master <%s> wgrp <%s> server <%s> share <%s> clidev <%s>\n", state->mask, srv->master, srv->workgroup, srv->server_name, srv->share_name, cli->dev);
888 if (*srv->workgroup == 0 && *srv->server_name == 0)
889 {
890 smbwrp_special_add(".", state);
891 smbwrp_special_add("..", state);
892 cli_NetServerEnum(cli, srv->master, SV_TYPE_DOMAIN_ENUM,
893 smbwrp_share_add, state);
894 } else if (*srv->server_name == 0)
895 {
896 smbwrp_special_add(".", state);
897 smbwrp_special_add("..", state);
898 cli_NetServerEnum(cli, srv->workgroup, SV_TYPE_ALL,
899 smbwrp_share_add, state);
900 } else if ((strcmp(cli->dev,"IPC") == 0) || *srv->share_name == 0 ||
901 (stricmp(srv->share_name,"IPC$") == 0))
902 {
903 smbwrp_special_add(".", state);
904 smbwrp_special_add("..", state);
905 if (net_share_enum_rpc(cli, smbwrp_share_add, state) < 0 &&
906 cli_RNetShareEnum(cli,smbwrp_share_add, state) < 0)
907 return os2cli_errno(cli);
908 } else if (strncmp(cli->dev,"LPT",3) == 0)
909 {
910 smbwrp_special_add(".", state);
911 smbwrp_special_add("..", state);
912 if (cli_print_queue_state(cli, smbwrp_printjob_add, state) < 0)
913 return os2cli_errno(cli);
914 }
915 else
916 {
917 if (list_files(cli, state->mask, aHIDDEN|aSYSTEM|aDIR,
918 smbwrp_dir_add, state) < 0)
919 return os2cli_errno(cli);
920 }
921
922 return 0;
923}
924
925/*
926 * a wrapper for chdir()
927 */
928int _System smbwrp_chdir(Resource *pRes, smbwrp_server *srv, cli_state * cli, char *fname)
929{
930 unsigned short mode = aDIR;
931 smbwrp_fileinfo finfo = {0};
932 if (!cli || !fname)
933 return maperror(EINVAL);
934
935 strncpy(finfo.fname, fname, sizeof(finfo.fname) - 1);
936 if (smbwrp_getattr(pRes, srv, cli, &finfo))
937 return os2cli_errno(cli);
938
939
940 if (!(finfo.attr & aDIR))
941 return maperror(ENOTDIR);
942
943
944 return 0;
945}
946
947
948/*
949 * a wrapper for mkdir()
950 */
951int _System smbwrp_mkdir(Resource *pRes, cli_state * cli, char *fname)
952{
953 if (!cli || !fname)
954 return maperror(EINVAL);
955
956 if (!NT_STATUS_IS_OK(cli_mkdir(cli, fname)))
957 return os2cli_errno(cli);
958
959 return 0;
960}
961
962/*
963 * a wrapper for rmdir()
964 */
965int _System smbwrp_rmdir(Resource *pRes, cli_state * cli, char *fname)
966{
967 if (!cli || !fname)
968 return maperror(EINVAL);
969
970 if (!NT_STATUS_IS_OK(cli_rmdir(cli, fname)))
971 return os2cli_errno(cli);
972
973 return 0;
974}
975
976/*
977 * set EA for a path
978 */
979int _System smbwrp_setea(Resource *pRes, cli_state * cli, char *fname, char * name, unsigned char * value, int size)
980{
981 if (!cli || !fname || !name)
982 return maperror(EINVAL);
983
984 if (!NT_STATUS_IS_OK(cli_set_ea_path(cli, fname, name, value, size)))
985 return os2cli_errno(cli);
986
987 return 0;
988}
989
990/*
991 * set EA for a file
992 */
993int _System smbwrp_fsetea(Resource *pRes, cli_state * cli, smbwrp_file *file, char * name, unsigned char * value, int size)
994{
995 if (!cli || !file || !name)
996 return maperror(EINVAL);
997
998 if (!NT_STATUS_IS_OK(cli_set_ea_fnum(cli, file->fd, name, value, size)))
999 return os2cli_errno(cli);
1000
1001 return 0;
1002}
1003
1004
1005static int unilistea(Resource *pRes, cli_state * cli, char *fname, void * buffer, unsigned long size)
1006{
1007 int fnum, i;
1008 int gotsize = sizeof(unsigned long);
1009 size_t num_eas;
1010 struct ea_struct *ea_list = NULL;
1011 TALLOC_CTX *mem_ctx;
1012 FEA * p;
1013 FEALIST * pfealist;
1014 char * q;
1015
1016 mem_ctx = talloc_init("%d: ealist", _gettid());
1017 pfealist = (FEALIST *)buffer;
1018 pfealist->cbList = 0;
1019
1020 if (!NT_STATUS_IS_OK(cli_get_ea_list_path(cli, fname, mem_ctx, &num_eas, &ea_list)))
1021 {
1022 debuglocal(pRes, 4,"ea_get_file list failed - %s\n", cli_errstr(cli));
1023 talloc_destroy(mem_ctx);
1024 return os2cli_errno(cli);
1025 }
1026
1027 debuglocal(pRes, 4,"num_eas = %d\n", num_eas);
1028
1029 // we will count that os/2 max EA size for file is 64kb
1030 p = pfealist->list;
1031 for (i = 0; i < num_eas; i++)
1032 {
1033 int namelen = strlen(ea_list[i].name);
1034 debuglocal(pRes, 4, "%d Got EA <%s> with namelen %d, size %d. Gross %d. Buf %d\n", i, ea_list[i].name, namelen, ea_list[i].value.length, gotsize, size);
1035 if (namelen > 0xFF || ea_list[i].value.length > 0xFFFF)
1036 {
1037 debuglocal(pRes, 4, "Skip EA <%s> with namelen %d, size %d\n", ea_list[i].name, namelen, ea_list[i].value.length);
1038 continue;
1039 }
1040 gotsize += sizeof(FEA) + namelen + ea_list[i].value.length + 1;
1041 if (size >= gotsize)
1042 {
1043 p->fEA = 0;
1044 p->cbName = namelen;
1045 p->cbValue = ea_list[i].value.length;
1046 q = (char *)(p + 1);
1047 strncpy(q, ea_list[i].name, namelen + 1);
1048 q += namelen + 1;
1049 memcpy(q, ea_list[i].value.data, ea_list[i].value.length);
1050 p = (FEA *)(q + ea_list[i].value.length);
1051 }
1052 }
1053 pfealist->cbList = gotsize;
1054 debuglocal(pRes, 4,"ret size = %d\n", gotsize);
1055
1056 talloc_destroy(mem_ctx);
1057 return 0;
1058}
1059
1060/*
1061 * lists EA of a path
1062 */
1063int _System smbwrp_listea(Resource *pRes, cli_state * cli, char *fname, void * buffer, unsigned long size)
1064{
1065 if (!cli || !fname || !buffer)
1066 return maperror(EINVAL);
1067
1068 debuglocal(pRes, 4,"EALIst for <%s>\n", fname);
1069 return unilistea(pRes, cli, fname, buffer, size);
1070}
1071
1072/*
1073 * lists EA of a file
1074 */
1075int _System smbwrp_flistea(Resource *pRes, cli_state * cli, smbwrp_file *file, void * buffer, unsigned long size)
1076{
1077 if (!cli || !file || !buffer)
1078 return maperror(EINVAL);
1079
1080 debuglocal(pRes, 4,"FEALIst for <%s>\n", file->fname);
1081 return unilistea(pRes, cli, file->fname, buffer, size);
1082}
1083
1084/*
1085 * Check the space on a device.
1086 */
1087int _System smbwrp_dskattr(Resource *pRes, cli_state * cli, FSALLOCATE *pfsa)
1088{
1089 int total, bsize, avail;
1090
1091 if (!cli || !pfsa)
1092 return maperror(EINVAL);
1093
1094 if (!NT_STATUS_IS_OK(cli_dskattr(cli, &bsize, &total, &avail)))
1095 {
1096 debuglocal(pRes, 4,"Error in dskattr: %s\n",cli_errstr(cli));
1097 return os2cli_errno(cli);
1098 }
1099
1100 debuglocal(pRes, 4,"\n\t\t%d blocks of size %d. %d blocks available\n",
1101 total, bsize, avail);
1102
1103 // YD currently Samba return it in MB!
1104 pfsa->cSectorUnit = 1;
1105 if (bsize >= 65536)
1106 {
1107 pfsa->cUnit = total*1024;
1108 pfsa->cUnitAvail = avail*1024;
1109 pfsa->cbSector = bsize/1024;
1110 }
1111 else
1112 {
1113 pfsa->cUnit = total;
1114 pfsa->cUnitAvail = avail;
1115 pfsa->cbSector = bsize;
1116 }
1117
1118 return 0;
1119}
Note: See TracBrowser for help on using the repository browser.