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
RevLine 
[151]1/*
2 Netdrive Samba client plugin
3 samba library wrappers
[957]4 Copyright (C) netlabs.org 2003-2012
5 Copyright (C) bww bitwise works GmbH 2012-2016
[150]6
[151]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
[5]22#include "includes.h"
[883]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"
[966]28
29#include "dircache.h"
[5]30#include "smbwrp.h"
31
32/*
33 * Wrapper for cli_errno to return not connected error on negative fd
[147]34 * Now returns an OS/2 return code instead of lerrno.
[5]35 */
36int os2cli_errno(cli_state * cli)
37{
[959]38 if (cli->fd == -1)
39 return maperror(ENOTCONN);
40
41 return maperror(cli_errno(cli));
[5]42}
43
[960]44void smbwrp_Logging(Resource *pRes)
[448]45{
[960]46 if (pRes && pRes->loglevel > 0)
[959]47 {
[960]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();
[959]56 }
[448]57
[959]58 return;
[448]59}
[959]60
[448]61const char * smbwrp_getVersion()
62{
[959]63 return samba_version_string();
[448]64}
65
[5]66int _System smbwrp_getclisize(void)
67{
[959]68 return sizeof(struct cli_state);
[5]69}
70
[959]71/*
72 * initialise structures
73 */
[960]74int _System smbwrp_init(Resource *pRes)
[5]75{
[959]76 char *p;
[5]77
[960]78 if (pRes->smb_initialised)
[959]79 return 0;
[5]80
[960]81 pRes->smb_initialised = 1;
[297]82
[959]83 lp_set_in_client(true); // Make sure that we tell lp_load we are client
[5]84
[959]85 load_case_tables();
[6]86
[959]87 if (!lp_load(get_dyn_CONFIGFILE(),true,false,false,true))
[960]88 debuglocal(pRes, 0,("The initial smb.conf is missing, defaults are used!\n"));
[5]89
[959]90 load_interfaces();
[5]91
[959]92 if (!init_names())
93 return 1;
[441]94
[960]95 smbwrp_Logging(pRes);
[521]96
[960]97 debuglocal(pRes, 5,("smbwrp_init done\n"));
[959]98 /*
99 if ((p=smbw_getshared("RESOLVE_ORDER")))
100 lp_set_name_resolve_order(p);
101 */
102 return 0;
103
[521]104}
105
106void smbwrp_initthread(void)
107{
[959]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);
[960]113 return;
[5]114}
115
116#if 0
[959]117/*
118 * remove redundent stuff from a filename
119 */
[5]120void clean_fname(char *name)
121{
[959]122 char *p, *p2;
123 int l;
124 int modified = 1;
[5]125
[959]126 if (!name) return;
[5]127
[959]128 while (modified) {
129 modified = 0;
[5]130
[959]131 if ((p=strstr(name,"/./"))) {
132 modified = 1;
133 while (*p) {
134 p[0] = p[2];
135 p++;
136 }
137 }
[5]138
[959]139 if ((p=strstr(name,"//"))) {
140 modified = 1;
141 while (*p) {
142 p[0] = p[1];
143 p++;
144 }
145 }
[5]146
[959]147 if (strcmp(name,"/../")==0) {
148 modified = 1;
149 name[1] = 0;
150 }
[5]151
[959]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 }
[5]163
[959]164 if (strcmp(name,"/..")==0) {
165 modified = 1;
166 name[1] = 0;
167 }
[5]168
[959]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 }
[5]183
[959]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 }
[5]192
[959]193 if (strncmp(p=name,"./",2) == 0) {
194 modified = 1;
195 do {
196 p[0] = p[2];
197 } while (*p++);
198 }
[5]199
[959]200 l = strlen(p=name);
201 if (l > 1 && p[l-1] == '/') {
202 modified = 1;
203 p[l-1] = 0;
204 }
205 }
[5]206}
207#endif
208
[959]209/*
210 * return a connection to a server
211 */
[960]212int _System smbwrp_connect(Resource* pRes, cli_state ** cli)
[5]213{
[959]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;
[5]226
[959]227 zero_sockaddr(&ss);
[5]228
[960]229 debuglocal(pRes, 1,"Connecting to \\\\%s:*********@%s:%s\\%s. Master %s:%d\n", srv->username, workgroup, server, share, srv->master, srv->ifmastergroup);
[5]230
[959]231 if (!*server) {
232 struct sockaddr_storage sip;
[5]233
[959]234 if (*workgroup)
235 {
236 if (!find_master_ip(workgroup, &sip))
237 return 1;
[5]238
[959]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;
[5]247
[959]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
[5]260 again:
[959]261 zero_sockaddr(&ss);
[5]262
[959]263 // have to open a new connection
264 if (!(c=cli_initialise()))
265 return 2;
[5]266
[959]267 cli_set_timeout(c, 10000); // 10 seconds
[548]268
[959]269 if (pRes->krb5support == 1)
270 {
[960]271 debuglocal(pRes, 1,"Kerberos support enabled\n");
[959]272 c->use_kerberos = True;
273 }
[107]274
[959]275 if (!NT_STATUS_IS_OK(cli_connect(c, server_n, &ss)))
276 return 3;
[629]277
[959]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 }
[5]286
[960]287 debuglocal(pRes, 4,"session request ok\n");
[5]288
[959]289 if (!NT_STATUS_IS_OK(cli_negprot(c))) {
290 cli_shutdown(c);
291 return 5;
292 }
[5]293
[960]294 debuglocal(pRes, 4,"session setuping for <%s>/<********> in <%s> %08x %08x %08x\n", srv->username, workgroup, c->protocol, c->sec_mode, c->capabilities);
[5]295
[959]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 {
[960]301 debuglocal(pRes, 4,"%s/******** login failed\n", srv->username);
[959]302 loginerror = 1; // save the login error
[179]303
[959]304 // try an anonymous login if it failed
305 if (!NT_STATUS_IS_OK(cli_session_setup(c, "", "", 0,"", 0, workgroup))) {
[960]306 debuglocal(pRes, 4,"Anonymous login failed\n");
[959]307 cli_shutdown(c);
308 return 6;
309 }
[960]310 debuglocal(pRes, 4,"Anonymous login successful\n");
[959]311 status = cli_init_creds(c, "", lp_workgroup(), "");
312 } else {
313 status = cli_init_creds(c, srv->username, workgroup, srv->password);
314 }
[5]315
[959]316 if (!NT_STATUS_IS_OK(status)) {
[960]317 debuglocal(pRes, 4,"cli_init_creds() failed\n");
[959]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 }
[645]325
[960]326 debuglocal(pRes, 4,"session setup ok. Sending tconx <%s> <********>\n", share);
[5]327
[959]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:";
[128]334
[959]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 }
[5]345
[960]346 debuglocal(pRes, 4,"tconx ok. cli caps %08x\n", c->capabilities);
[150]347
[959]348 // save cli_state pointer
349 *cli = c;
[6]350
[959]351 return 0;
[5]352}
353
[959]354/*
355 * close a connection to a server
356 */
[960]357void _System smbwrp_disconnect(Resource* pRes, cli_state * cli)
[5]358{
[959]359 // this call will free all buffers, close handles and free cli mem
360 if (pRes && cli)
361 cli_shutdown( cli);
[5]362}
363
[959]364/*
365 * a wrapper for open()
366 */
[960]367int _System smbwrp_open(Resource *pRes, cli_state * cli, smbwrp_file * file)
[5]368{
[959]369 uint16_t fd = 0;
[5]370
[959]371 if (!cli || !file || !*file->fname)
372 return maperror(EINVAL);
[5]373
[959]374 if (file->denymode < DENY_ALL || file->denymode > DENY_NONE)
375 file->denymode = DENY_NONE;
376
[960]377 debuglocal(pRes, 4,"cli_open(%s) attr %08x mode %02x denymode %02x\n", file->fname, file->openattr, file->openmode, file->denymode);
[959]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;
[5]385}
386
[959]387/*
388 * a wrapper for read()
389 */
[960]390int _System smbwrp_read(Resource *pRes, cli_state * cli, smbwrp_file * file, void *buf, unsigned long count, unsigned long * result)
[5]391{
[959]392 int ret;
[5]393
[959]394 if (!cli || !file || !buf || !result)
395 return maperror(EINVAL);
[5]396
[959]397 *result = 0;
398 ret = cli_read(cli, file->fd, buf, file->offset, count);
399 if (ret == -1)
400 return os2cli_errno(cli);
[5]401
[959]402 file->offset += ret;
403 *result = ret;
404 return 0;
[5]405}
406
[959]407/*
408 * a wrapper for write()
409 */
[960]410int _System smbwrp_write(Resource *pRes, cli_state * cli, smbwrp_file * file, void *buf, unsigned long count, unsigned long * result)
[5]411{
[959]412 NTSTATUS status;
413 size_t ret;
[5]414
[959]415 if (!cli || !file || !buf || !result)
416 return maperror(EINVAL);
[5]417
[959]418 *result = 0;
[960]419 debuglocal(pRes, 10, "Write %x %d %lld %d\n", cli, file->fd, file->offset, count);
[959]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);
[5]423
[959]424 file->updatetime = 1;
425 file->offset += ret;
426 *result = ret;
427 return 0;
[5]428}
429
[959]430/*
431 * a wrapper for close()
432 */
[960]433int _System smbwrp_close(Resource *pRes, cli_state * cli, smbwrp_file * file)
[5]434{
[959]435 int rc = 0;
436 if (!cli || !file)
437 return maperror(EINVAL);
[5]438
[960]439 debuglocal(pRes, 4,"smpwrp_close updatetime: %d\n", file->updatetime);
[818]440
[959]441 if (file->updatetime == 1)
442 {
443 file->mtime = time(NULL);
[960]444 debuglocal(pRes, 4,"cli_close new mtime %lu\n", file->mtime);
[959]445 }
[5]446
[959]447 if (!NT_STATUS_IS_OK(cli_close(cli, file->fd)))
448 rc = os2cli_errno(cli);
[818]449
[959]450 if (!rc && (file->openattr || file->mtime || file->ctime))
451 {
[960]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 }
[959]457 }
[818]458
[959]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;
[5]467}
468
[960]469int _System smbwrp_setfilesize(Resource *pRes, cli_state * cli, smbwrp_file * file, long long newsize)
[5]470{
[959]471 int rc = 0;
472 if (!cli || !file)
473 return maperror(EINVAL);
[5]474
[960]475 debuglocal(pRes, 4,"cli_setnewfilesize(%s) %lld\n", file->fname, newsize);
[959]476 if (!NT_STATUS_IS_OK(cli_ftruncate(cli, file->fd, newsize)))
477 {
478 if (newsize)
479 rc = os2cli_errno(cli);
[5]480
[959]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;
[960]489 debuglocal(pRes, 4,"cli_setnewfileszie : cli_open(%s) attr %08x mode %02x denymode %02x\n", file->fname, file->openattr, file->openmode, file->denymode);
[959]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;
[5]496}
497
[959]498/*
499 * a wrapper for rename()
500 */
[960]501int _System smbwrp_rename(Resource *pRes, cli_state * cli, char *oldname, char *newname)
[5]502{
[959]503 if (!cli || !oldname || !newname)
504 return maperror(EINVAL);
[5]505
[960]506 debuglocal(pRes, 4,"Rename <%s> -> <%s>\n", oldname, newname);
[959]507 if (!NT_STATUS_IS_OK(cli_rename(cli, oldname, newname)))
508 return os2cli_errno(cli);
509
510 return 0;
[5]511}
512
513
[959]514/*
515 * a wrapper for chmod()
516 */
[960]517int _System smbwrp_setattr(Resource *pRes, cli_state * cli, smbwrp_fileinfo *finfo)
[5]518{
[959]519 if (!cli || !finfo || !*finfo->fname)
520 return maperror(EINVAL);
[5]521
[960]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));
[959]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;
[5]530}
531
[959]532/*
533 * a wrapper for unlink()
534 */
[960]535int _System smbwrp_unlink(Resource *pRes, cli_state * cli, const char *fname)
[5]536{
[959]537 if (!cli || !fname)
538 return maperror(EINVAL);
539
[5]540#if 0
[959]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
[5]551#endif
[959]552 if (!NT_STATUS_IS_OK(cli_unlink(cli, fname, aSYSTEM | aHIDDEN)))
553 return os2cli_errno(cli);
554
555 return 0;
[5]556}
557
[959]558/*
559 * a wrapper for lseek()
560 */
[960]561int _System smbwrp_lseek(Resource *pRes, cli_state * cli, smbwrp_file * file, int whence, long long offset)
[5]562{
[959]563 off_t size;
564 if (!cli || !file)
565 return maperror(EINVAL);
[5]566
[960]567 debuglocal(pRes, 4,"lseek %d %lld %lld\n", whence, offset, file->offset);
[5]568
[959]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 }
[5]591
[959]592 return 0;
[5]593}
594
[959]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 */
[960]599int _System smbwrp_getattr(Resource *pRes, smbwrp_server *srv, cli_state * cli, smbwrp_fileinfo *finfo)
[5]600{
[959]601 SMB_INO_T ino = 0;
602 struct timespec ctime;
603 struct timespec mtime;
604 struct timespec atime;
[883]605
[959]606 if (!cli || !finfo || !*finfo->fname)
607 return maperror(EINVAL);
[5]608
[960]609 debuglocal(pRes, 4,"getattr %d %d <%s>\n", cli->capabilities & CAP_NOPATHINFO2, cli->capabilities & CAP_NT_SMBS, finfo->fname);
[959]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 }
[548]621
[959]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 {
[960]636 debuglocal(pRes, 4,"getattr not a share.\n");
[959]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 }
[75]645
[959]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;
[5]657
[959]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 {
[960]663 debuglocal(pRes, 10,("gotattr1 %08x <%s>\n", finfo->attr, finfo->fname));
[959]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);
[5]672}
673
[959]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 */
[960]678int _System smbwrp_fgetattr(Resource *pRes, cli_state * cli, smbwrp_file *file, smbwrp_fileinfo *finfo)
[5]679{
[959]680 struct timespec ctime;
681 struct timespec mtime;
682 struct timespec atime;
683 SMB_INO_T ino = 0;
[883]684
[959]685 if (!cli || !file || !finfo)
686 return maperror(EINVAL);
[5]687
688
[959]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;
[5]714}
715
716// =============================DIRECTORY ROUTINES============================
[808]717
[959]718/*
719 * add a entry to a directory listing
720 */
[6]721static void smbwrp_dir_add(const char* mnt, smbwrp_fileinfo *finfo, const char *mask, void *state)
[5]722{
[959]723 if (state && finfo)
724 {
[960]725 filelist_state *st = (filelist_state *)state;
[959]726 char fullname[ _MAX_PATH] = {0};
[960]727 debuglocal(st->pConn->pRes, 8,"adding <%s> %d %d %d\n", finfo->fname, sizeof(st->finfo), st->datalen, sizeof(st->finfo.fname));
[959]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));
[976]732 addFindInfoL(st->pConn->pRes, st->plist, &st->finfo, st->ulAttribute, st->dir_mask);
[959]733 }
734 return;
[5]735}
[42]736
[6]737static void smbwrp_special_add(const char * name, void * state)
[5]738{
[959]739smbwrp_fileinfo finfo = {0};
[5]740
[959]741 if (!name)
742 return;
[5]743
[959]744 ZERO_STRUCT(finfo);
[5]745
[959]746 strncpy(finfo.fname, name, sizeof(finfo.fname) - 1);
747 finfo.attr = aRONLY | aDIR;
[5]748
[959]749 smbwrp_dir_add("", &finfo, NULL, state);
750 return;
[5]751}
752
753static void smbwrp_printjob_add(struct print_job_info *job, void * state)
754{
[959]755 smbwrp_fileinfo finfo = {0};
[5]756
[959]757 ZERO_STRUCT(finfo);
[5]758
[959]759 //printf("Printjob <%s>\n", job->name);
[5]760
[959]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;
[5]767
[959]768 smbwrp_dir_add("", &finfo, NULL, state);
769 return;
[5]770}
771
772static void smbwrp_share_add(const char *share, uint32 type,
773 const char *comment, void *state)
774{
[959]775 smbwrp_fileinfo finfo = {0};
[5]776
[959]777 // strip administrative names and printers from list
778 if (type == STYPE_PRINTQ || strcmp(share,"IPC$") == 0)
779 return;
[5]780
[959]781 ZERO_STRUCT(finfo);
[5]782
[959]783 strncpy(finfo.fname, share, sizeof(finfo.fname) - 1);
784 finfo.attr = aRONLY | aDIR;
[5]785
[959]786 smbwrp_dir_add("", &finfo, NULL, state);
787 return;
[5]788}
789
[959]790/*
791 * Do a directory listing, calling fn on each file found.
792 * Modified from cli_list
793 */
[883]794static int list_files(struct cli_state *cli, const char *mask, uint16 attribute,
795 void (*fn)(const char *, smbwrp_fileinfo *, const char *,
[960]796 void *), filelist_state *state)
[5]797{
[959]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;
[960]806 Resource *pRes = state->pConn->pRes;
[5]807
[959]808 // Try to get the listing from cache.
[976]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);
[959]814 return(num_finfo); // Got from cache
[976]815 }
[499]816
[959]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;
[444]827
[959]828 info_level = (cli->capabilities & CAP_NT_SMBS)
829 ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_EA_SIZE;
[5]830
[960]831 debuglocal(pRes, 4,"list_files level %d. mask <%s>\n", info_level, mask);
[297]832
[959]833 req = cli_list_send(frame, ev, cli, mask, attribute, info_level);
834 if (req == NULL)
835 goto fail;
[5]836
[959]837 if (!tevent_req_poll(req, ev)) {
838 status = map_nt_error_from_unix(errno);
839 goto fail;
840 }
[5]841
[959]842 status = cli_list_recv(req, frame, &finfo, &num_finfo);
843 if (!NT_STATUS_IS_OK(status))
844 goto fail;
[499]845
[976]846 dircachectx = dircache_write_begin(pRes->pdc, state->dir_mask,
[966]847 (char*) state->fullpath, num_finfo);
[535]848
[960]849 debuglocal(pRes, 4,"list_files: got %d files\n", num_finfo);
[499]850
[959]851 for (i=0; i<num_finfo; i++) {
[976]852 // dinamically allocate finfo data structure, cache can keep only pointers
853 smbwrp_fileinfo* wrpfinfo = (smbwrp_fileinfo*)malloc( sizeof(smbwrp_fileinfo));
[959]854 //as samba and this client have different finfo, we need to convert
[976]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);
[959]870 }
[499]871
[966]872 dircache_write_end(pRes->pdc, dircachectx);
873
[883]874 fail:
[959]875 TALLOC_FREE(frame);
876 return num_finfo;
[5]877}
878
[959]879/*
880 * open a directory on the server
881 */
[960]882int _System smbwrp_filelist(Resource *pRes, smbwrp_server *srv, cli_state * cli, filelist_state * state)
[5]883{
[959]884 if (!srv || !cli || !state || !*state->mask)
885 return maperror(EINVAL);
[5]886
[960]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);
[959]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 }
[52]921
[959]922 return 0;
[5]923}
924
[959]925/*
926 * a wrapper for chdir()
927 */
[960]928int _System smbwrp_chdir(Resource *pRes, smbwrp_server *srv, cli_state * cli, char *fname)
[5]929{
[959]930 unsigned short mode = aDIR;
931 smbwrp_fileinfo finfo = {0};
932 if (!cli || !fname)
933 return maperror(EINVAL);
[5]934
[959]935 strncpy(finfo.fname, fname, sizeof(finfo.fname) - 1);
[960]936 if (smbwrp_getattr(pRes, srv, cli, &finfo))
[959]937 return os2cli_errno(cli);
[5]938
939
[959]940 if (!(finfo.attr & aDIR))
941 return maperror(ENOTDIR);
942
943
944 return 0;
[5]945}
946
947
[959]948/*
949 * a wrapper for mkdir()
950 */
[960]951int _System smbwrp_mkdir(Resource *pRes, cli_state * cli, char *fname)
[5]952{
[959]953 if (!cli || !fname)
954 return maperror(EINVAL);
[5]955
[959]956 if (!NT_STATUS_IS_OK(cli_mkdir(cli, fname)))
957 return os2cli_errno(cli);
958
959 return 0;
[5]960}
961
[959]962/*
963 * a wrapper for rmdir()
964 */
[960]965int _System smbwrp_rmdir(Resource *pRes, cli_state * cli, char *fname)
[5]966{
[959]967 if (!cli || !fname)
968 return maperror(EINVAL);
[5]969
[959]970 if (!NT_STATUS_IS_OK(cli_rmdir(cli, fname)))
971 return os2cli_errno(cli);
972
973 return 0;
[5]974}
975
[959]976/*
977 * set EA for a path
978 */
[960]979int _System smbwrp_setea(Resource *pRes, cli_state * cli, char *fname, char * name, unsigned char * value, int size)
[5]980{
[959]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;
[5]988}
989
[959]990/*
991 * set EA for a file
992 */
[960]993int _System smbwrp_fsetea(Resource *pRes, cli_state * cli, smbwrp_file *file, char * name, unsigned char * value, int size)
[5]994{
[959]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;
[5]1002}
1003
1004
[960]1005static int unilistea(Resource *pRes, cli_state * cli, char *fname, void * buffer, unsigned long size)
[5]1006{
[959]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;
[5]1015
[959]1016 mem_ctx = talloc_init("%d: ealist", _gettid());
1017 pfealist = (FEALIST *)buffer;
1018 pfealist->cbList = 0;
[5]1019
[959]1020 if (!NT_STATUS_IS_OK(cli_get_ea_list_path(cli, fname, mem_ctx, &num_eas, &ea_list)))
1021 {
[960]1022 debuglocal(pRes, 4,"ea_get_file list failed - %s\n", cli_errstr(cli));
[959]1023 talloc_destroy(mem_ctx);
1024 return os2cli_errno(cli);
1025 }
[5]1026
[960]1027 debuglocal(pRes, 4,"num_eas = %d\n", num_eas);
[5]1028
[959]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);
[960]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);
[959]1035 if (namelen > 0xFF || ea_list[i].value.length > 0xFFFF)
1036 {
[960]1037 debuglocal(pRes, 4, "Skip EA <%s> with namelen %d, size %d\n", ea_list[i].name, namelen, ea_list[i].value.length);
[959]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;
[960]1054 debuglocal(pRes, 4,"ret size = %d\n", gotsize);
[5]1055
[959]1056 talloc_destroy(mem_ctx);
1057 return 0;
[5]1058}
1059
[959]1060/*
1061 * lists EA of a path
1062 */
[960]1063int _System smbwrp_listea(Resource *pRes, cli_state * cli, char *fname, void * buffer, unsigned long size)
[5]1064{
[959]1065 if (!cli || !fname || !buffer)
1066 return maperror(EINVAL);
[5]1067
[960]1068 debuglocal(pRes, 4,"EALIst for <%s>\n", fname);
1069 return unilistea(pRes, cli, fname, buffer, size);
[5]1070}
1071
[959]1072/*
1073 * lists EA of a file
1074 */
[960]1075int _System smbwrp_flistea(Resource *pRes, cli_state * cli, smbwrp_file *file, void * buffer, unsigned long size)
[5]1076{
[959]1077 if (!cli || !file || !buffer)
1078 return maperror(EINVAL);
[5]1079
[960]1080 debuglocal(pRes, 4,"FEALIst for <%s>\n", file->fname);
1081 return unilistea(pRes, cli, file->fname, buffer, size);
[5]1082}
1083
[959]1084/*
1085 * Check the space on a device.
1086 */
[960]1087int _System smbwrp_dskattr(Resource *pRes, cli_state * cli, FSALLOCATE *pfsa)
[5]1088{
[959]1089 int total, bsize, avail;
[5]1090
[959]1091 if (!cli || !pfsa)
1092 return maperror(EINVAL);
[5]1093
[959]1094 if (!NT_STATUS_IS_OK(cli_dskattr(cli, &bsize, &total, &avail)))
1095 {
[960]1096 debuglocal(pRes, 4,"Error in dskattr: %s\n",cli_errstr(cli));
[959]1097 return os2cli_errno(cli);
1098 }
[5]1099
[960]1100 debuglocal(pRes, 4,"\n\t\t%d blocks of size %d. %d blocks available\n",
[959]1101 total, bsize, avail);
[5]1102
[959]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 }
[5]1117
[959]1118 return 0;
[5]1119}
Note: See TracBrowser for help on using the repository browser.