source: trunk/client/src/ndpsmb.c@ 961

Last change on this file since 961 was 960, checked in by Silvan Scherrer, 9 years ago

samba client: add the possibility to have logfiles per share

  • Property svn:eol-style set to native
File size: 67.7 KB
Line 
1/*
2 Netdrive Samba client plugin
3 plugin API
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 <stdio.h>
23#include <stdlib.h>
24#include <stdarg.h>
25#include <string.h>
26#include <time.h>
27
28#define NDPL_LARGEFILES
29#define INCL_LONGLONG
30#include <ndextpl2.h>
31#include "smbwrp.h"
32#include "util.h"
33
34// -------------------------------------------------------------
35
36/* time conversion functions: SMB protocol sends timestamps in GMT time,
37 * os2 api uses localtime,
38 * emx/klibc uses timezone and daylight saving to convert GMT timestamps,
39 * so only the timezone must be counted in conversion.
40 */
41void fsphUnixTimeToDosDate(Resource *pRes, time_t time, FDATE* fdate, FTIME *ftime)
42{
43 struct tm* gmt = localtime( &time);
44#if 0 // as localtime() already does dst we don't need to add something
45 if (gmt->tm_isdst>0)
46 {
47 debuglocal(pRes, 9, "daylight saving in effect %d, timezone %d\n",gmt->tm_isdst, timezone);
48 time -= 3600;
49 gmt = localtime( &time);
50 }
51#endif
52 fdate->day = gmt->tm_mday;
53 fdate->month = gmt->tm_mon+1;
54 fdate->year = gmt->tm_year + 1900 - 1980;
55 ftime->twosecs = gmt->tm_sec/2;
56 ftime->minutes = gmt->tm_min;
57 ftime->hours = gmt->tm_hour;
58 return;
59}
60
61void fsphDosDateToUnixTime(Resource *pRes, FDATE fdate, FTIME ftime, ULONG* time)
62{
63 struct tm gmtime = { 0 };
64
65 debuglocal(pRes, 9, "fsphDosDateToUnixTime time %02d:%02d:%02d\n", ftime.hours, ftime.minutes, ftime.twosecs*2);
66 gmtime.tm_mday = fdate.day;
67 gmtime.tm_mon = fdate.month-1;
68 gmtime.tm_year = fdate.year + 1980 - 1900;
69 gmtime.tm_sec = ftime.twosecs*2;
70 gmtime.tm_min = ftime.minutes;
71 gmtime.tm_hour = ftime.hours;
72 gmtime.tm_isdst = -1; // force libc to check dst saving
73
74 *time = mktime( &gmtime);
75 debuglocal(pRes, 9, "fsphDosDateToUnixTime time1 %d %s", *time, ctime( (time_t*)time));
76#if 0 // as mktime() already does dst we don't need to add something
77 struct tm* gmt;
78 gmt = localtime( (time_t*) time);
79 if (gmt->tm_isdst>0)
80 {
81 debuglocal(pRes, 9, "fsphDosDateToUnixTime daylight saving in effect %d, timezone %d\n",gmt->tm_isdst, timezone);
82 *time += 3600;
83 }
84 debuglocal(pRes, 9, "fsphDosDateToUnixTime time2 %d %s", *time, ctime( (time_t*)time));
85#endif
86 return;
87}
88
89// -------------------------------------------------------------
90
91/* uppercased type of resource */
92const char *NdpTypes[] =
93{
94 "SMBFS",
95 NULL
96}
97;
98
99/* Properties of supported resource types */
100
101/* Properties of resource */
102static const NDPROPERTYINFO smbProperties[] =
103{
104 {ND_PROP_STRING, 0, "WORKGROUP", ""},
105 {ND_PROP_STRING, 0, "SERVER", ""},
106 {ND_PROP_STRING, 0, "SHARE", ""},
107 {ND_PROP_STRING, 0, "USER", "guest"},
108 {ND_PROP_STRING, 0, "PASSWORD", ""},
109 {ND_PROP_STRING, 0, "SPASSWORD", ""},
110 {ND_PROP_STRING, 0, "MASTER", "WORKGROUP"},
111 {ND_PROP_ULONG, 0, "MASTERTYPE", "1"},
112 {ND_PROP_ULONG, 0, "CTO", "10"},
113 {ND_PROP_ULONG, 0, "CLD", "32"},
114 {ND_PROP_ULONG, 0, "EASUPPORT", "1"},
115 {ND_PROP_ULONG, 0, "LOGLEVEL", "0"},
116 {ND_PROP_STRING, 0, NULL, NULL}
117};
118
119
120/* Exported array of properties */
121const NDPROPERTYINFO *NdpPropertiesInfo[] =
122{
123 smbProperties
124};
125
126
127PLUGINHELPERTABLE2L *ph;
128static int ifL;
129
130/* A mutex to serialize plugin calls because libsmb may not be thread safe. */
131static NDMUTEX mutex;
132
133static int lockInit (void)
134{
135 return ph->fsphCreateMutex (&mutex);
136}
137
138static void lockClose (void)
139{
140 ph->fsphCloseMutex (mutex);
141}
142
143static int lockRequest (void)
144{
145 return ph->fsphRequestMutex (mutex, SEM_INDEFINITE_WAIT);
146}
147
148static void lockRelease (void)
149{
150 ph->fsphReleaseMutex (mutex);
151}
152
153#if LIBSMB_THREAD_SAFE==0
154
155#define ENTER() do { \
156 int rcLock = lockRequest(); \
157 if (rcLock != NO_ERROR) \
158 return rcLock; \
159 smbwrp_Logging(pRes); \
160} while (0)
161
162#define LEAVE() do { \
163 lockRelease(); \
164} while (0)
165
166#else
167#define ENTER() do { /* nothing */ } while (0)
168#define LEAVE() do { /* nothing */ } while (0)
169#endif
170
171int helperEASet (Resource *pRes, cli_state *cli, FEALIST *pFEAList, char *path)
172{
173 int rc = 0;
174
175 if (!path || !pFEAList || pFEAList->cbList <= sizeof(long))
176 return ERROR_EAS_NOT_SUPPORTED;
177
178 ENTER();
179
180 do {
181 // got FEA there
182 FEA * pfea;
183 unsigned long done = sizeof(long);
184 pfea = pFEAList->list;
185 while (done < pFEAList->cbList)
186 {
187 rc = smbwrp_setea(pRes, cli, path, (char*)(pfea + 1), pfea->cbValue ? (char *)(pfea + 1) + pfea->cbName + 1: NULL, pfea->cbValue);
188 if (rc)
189 break;
190 pfea = (FEA *)((char *)(pfea + 1) + pfea->cbName + 1 + pfea->cbValue);
191 done += sizeof(FEA) + pfea->cbName + 1 + pfea->cbValue;
192 }
193 } while (0);
194
195 LEAVE();
196 return rc;
197}
198
199int APIENTRY NdpPluginLoad (PLUGINHELPERTABLE2L *pPHT)
200{
201 ph = pPHT;
202 ifL = 0;
203 if (ph->cb >= sizeof (PLUGINHELPERTABLE2L))
204 ifL = 1;
205
206 lockInit();
207 return NO_ERROR;
208}
209
210
211int APIENTRY NdpPluginFree (void)
212{
213 debugDelete();
214 lockClose();
215 return NO_ERROR;
216}
217
218
219void getfindinfo(Connection * pConn, FILEFINDBUF3 * stat, smbwrp_fileinfo * finfo)
220{
221 char * name = ph->fsphStrRChr(finfo->fname, '\\');
222
223 if (name)
224 name++;
225 else
226 name = finfo->fname;
227
228 if (!*name)
229 name = pConn->pRes->srv.share_name;
230
231 strncpy(stat->achName, name, CCHMAXPATHCOMP - 1);
232 stat->cbFile = finfo->size;
233 stat->cbFileAlloc = stat->cbFile;
234 stat->oNextEntryOffset = 0ul;
235 stat->cchName = strlen(stat->achName);
236 stat->attrFile = (finfo->attr & 0x37);
237
238 fsphUnixTimeToDosDate(pConn->pRes, finfo->mtime, &stat->fdateLastWrite, &stat->ftimeLastWrite);
239 fsphUnixTimeToDosDate(pConn->pRes, finfo->ctime, &stat->fdateCreation, &stat->ftimeCreation);
240 fsphUnixTimeToDosDate(pConn->pRes, finfo->atime, &stat->fdateLastAccess, &stat->ftimeLastAccess);
241 return;
242}
243
244int getfindinfoL(Connection * pConn, void * plist, smbwrp_fileinfo * finfo, ULONG ulAttribute, char * mask)
245{
246 FILESTATUS3L stat = {0};
247 char * name = ph->fsphStrRChr(finfo->fname, '\\');
248 if (name)
249 name++;
250 else
251 name = finfo->fname;
252
253 if (!*name)
254 name = pConn->pRes->srv.share_name;
255
256 if (mask && (!ph->fsphAttrMatch(ulAttribute, finfo->attr & 0x37) || !ph->fsphWildMatch(mask, name, ND_IGNORE_CASE)))
257 return 0;
258
259 stat.cbFile = finfo->size;
260 stat.cbFileAlloc = stat.cbFile;
261 stat.attrFile = (finfo->attr & 0x37);
262
263 fsphUnixTimeToDosDate(pConn->pRes, finfo->mtime, &stat.fdateLastWrite, &stat.ftimeLastWrite);
264 fsphUnixTimeToDosDate(pConn->pRes, finfo->ctime, &stat.fdateCreation, &stat.ftimeCreation);
265 fsphUnixTimeToDosDate(pConn->pRes, finfo->atime, &stat.fdateLastAccess, &stat.ftimeLastAccess);
266 debuglocal(pConn->pRes, 9, "fname %s\n", finfo->fname);
267 debuglocal(pConn->pRes, 9, "mtime %d %s", finfo->mtime, ctime( (time_t*)&finfo->mtime));
268 debuglocal(pConn->pRes, 9, "ftimeLastAccess %02d:%02d:%02d\n", stat.ftimeLastWrite.hours, stat.ftimeLastWrite.minutes, stat.ftimeLastWrite.twosecs*2);
269
270 ph->fsphAddFile32L(plist, &stat, name, strlen(name), finfo, sizeof(*finfo), 0);
271 return 1;
272}
273
274static unsigned char fromhex (char c)
275{
276 if ('0' <= c && c <= '9')
277 return c - '0';
278
279 if ('A' <= c && c <= 'F')
280 return c - 'A' + 0xA;
281
282 if ('a' <= c && c <= 'f')
283 return c - 'a' + 0xA;
284
285 return 0;
286}
287
288static char tohex (unsigned char b)
289{
290 b &= 0xF;
291
292 if (b <= 9)
293 return b + '0';
294
295 return 'A' + (b - 0xA);
296}
297
298static void decryptPassword (const char *pszCrypt, char *pszPlain)
299{
300 // A simple "decryption", character from the hex value.
301 const char *s = pszCrypt;
302 char *d = pszPlain;
303
304 while (*s)
305 {
306 *d++ = (char)((fromhex (*s++) << 4) + fromhex (*s++));
307 }
308
309 *d++ = 0;
310 return;
311}
312
313static void encryptPassword (const char *pszPlain, char *pszCrypt)
314{
315 // A simple "encryption" encode each character as hex value. */
316 const char *s = pszPlain;
317 char *d = pszCrypt;
318
319 while (*s)
320 {
321 *d++ = tohex ((*s) >> 4);
322 *d++ = tohex (*s);
323 s++;
324 }
325
326 *d++ = 0;
327 return;
328}
329
330/* accept parameters in form
331 * [filename][;name=filename]
332 */
333int initResource (Resource *pRes, NDPROPERTYHANDLE properties)
334{
335 int rc = NO_ERROR;
336 unsigned long t;
337 const char * q = NULL;
338 int defaultPassword = 1;
339
340 pRes->rootlevel = 0;
341 pRes->easupport = 1;
342#ifdef HAVE_KRB5_H
343 pRes->krb5support = 1;
344#else
345 pRes->krb5support = 0;
346#endif
347 pRes->pdc = NULL;
348 pRes->loglevel = 0;
349
350 t = 0, q = NULL;
351 rc = ph->fsphQueryStringProperty (properties, "WORKGROUP", &q, &t);
352 if (!rc && t && *q)
353 {
354 strncpy(pRes->srv.workgroup, q, sizeof(pRes->srv.workgroup) - 1);
355 pRes->rootlevel = 1;
356 }
357
358 t = 0, q = NULL;
359 rc = ph->fsphQueryStringProperty (properties, "SERVER", &q, &t);
360 if (!rc && t && *q)
361 {
362 strncpy(pRes->srv.server_name, q, sizeof(pRes->srv.server_name) - 1);
363 pRes->rootlevel = 2;
364 }
365
366 t = 0, q = NULL;
367 rc = ph->fsphQueryStringProperty (properties, "SHARE", &q, &t);
368 if (!rc && t && *q)
369 {
370 strncpy(pRes->srv.share_name, q, sizeof(pRes->srv.share_name) - 1);
371 pRes->rootlevel = 3;
372 }
373
374 t = 0, q = NULL;
375 rc = ph->fsphQueryStringProperty (properties, "USER", &q, &t);
376 if (!rc && t && *q)
377 strncpy(pRes->srv.username, q, sizeof(pRes->srv.username) - 1);
378
379 t = 0, q = NULL;
380 rc = ph->fsphQueryStringProperty (properties, "PASSWORD", &q, &t);
381 if (!rc && t && *q)
382 {
383 strncpy(pRes->srv.password, q, sizeof(pRes->srv.password) - 1);
384 defaultPassword = 0;
385 }
386
387 t = 0, q = NULL;
388 rc = ph->fsphQueryStringProperty (properties, "SPASSWORD", &q, &t);
389 if (rc == NO_ERROR && *q != '\0' && defaultPassword)
390 {
391 char p[1024];
392 p[0] = 0;
393
394 decryptPassword (q, p);
395 if (*p)
396 {
397 strncpy(pRes->srv.password, p, sizeof(pRes->srv.password) - 1);
398 // clear the plain password
399 ph->fsphSetProperty (properties, "PASSWORD", "");
400 }
401 }
402 else
403 {
404 char c[1024];
405 encryptPassword (pRes->srv.password, c);
406 ph->fsphSetProperty (properties, "SPASSWORD", c);
407 // clear the plain password
408 ph->fsphSetProperty (properties, "PASSWORD", "");
409 }
410
411 t = 0, q = NULL;
412 rc = ph->fsphQueryStringProperty (properties, "MASTER", &q, &t);
413 if (!rc && t && *q)
414 strncpy(pRes->srv.master, q, sizeof(pRes->srv.master) - 1);
415
416 t = 0;
417 rc = ph->fsphQueryUlongProperty (properties, "MASTERTYPE", &t);
418 if (!rc)
419 {
420 if (t > 1)
421 rc = ERROR_INVALID_PARAMETER;
422 else
423 pRes->srv.ifmastergroup = t;
424 }
425
426 t = 0;
427 rc = ph->fsphQueryUlongProperty (properties, "EASUPPORT", &t);
428 if (!rc)
429 {
430 if (t > 1)
431 rc = ERROR_INVALID_PARAMETER;
432 else
433 pRes->easupport = t;
434 }
435
436 t = 0;
437 rc = ph->fsphQueryUlongProperty (properties, "CTO", &t);
438 if (!rc)
439 {
440 if (t > 600)
441 rc = ERROR_INVALID_PARAMETER;
442 else
443 pRes->cachetimeout = t;
444 }
445
446 t = 0;
447 rc = ph->fsphQueryUlongProperty (properties, "CLD", &t);
448 if (!rc)
449 {
450 if (t > 96)
451 rc = ERROR_INVALID_PARAMETER;
452 else
453 pRes->cachedepth = t;
454 }
455
456 t = 0;
457 rc = ph->fsphQueryUlongProperty (properties, "LOGLEVEL", &t);
458 if (!rc)
459 {
460 if (t > 10)
461 rc = ERROR_INVALID_PARAMETER;
462 else
463 pRes->loglevel = t;
464 }
465
466 // figure out the used share/server/workgroup
467 char *logfileext = '\0';
468 if (pRes->srv.share_name)
469 logfileext = pRes->srv.share_name;
470 if (!logfileext && pRes->srv.server_name)
471 logfileext = pRes->srv.server_name;
472 if (!logfileext && pRes->srv.workgroup)
473 logfileext = pRes->srv.workgroup;
474
475 // init debug and write the very first message
476 debugInit(pRes, logfileext, ifL);
477 debuglocal(pRes, 9, "NdpMountResource initResource\n");
478
479 // init code
480 smbwrp_init(pRes);
481
482 /*
483 * Create a directory cache with expiration time and cache listings
484 * the above values come from the gui. default: timeout 10; listings: 32
485 */
486 dircache_create(pRes);
487
488 return rc;
489}
490
491int iftestpath(char * path)
492{
493 char * p = path;
494 if (!path)
495 return 0;
496
497 while ((p = ph->fsphStrChr(p, 'A')) != NULL)
498 {
499 if (ph->fsphStrNCmp(p, "A.+,;=[].B", 10) == 0)
500 return 1;
501 p++;
502 }
503 return 0;
504}
505
506int pathparser(Resource *pRes, Connection * pConn, char * path, char * result)
507{
508 int rootlevel;
509 int rc = NO_ERROR;
510 if (!pRes || !path || !result)
511 return ERROR_INVALID_PARAMETER;
512
513 /* handle special case when someone wants to test support of
514 * LFN or smth similar
515 */
516 if (iftestpath(path))
517 {
518 strcpy(result, "\\A.+,;=[].B");
519 return NO_ERROR;
520 }
521
522 rootlevel = pRes->rootlevel;
523 if (*path == '\\') path++;
524
525 if (rootlevel < 3)
526 {
527 char * p;
528 // flag: 1 parameters changed, reconnection required, 0 do nothing
529 int newlevel = 0;
530 // use a temporary resource to test disconnection/reconnection
531 Resource tmpRes;
532 // copy exising data
533 memcpy( &tmpRes, pRes, sizeof( tmpRes));
534 // pointer to new connection fields
535 smbwrp_server * tmp = &tmpRes.srv;
536 if (rootlevel == 0)
537 {
538 p = ph->fsphStrChr(path, '\\');
539 if (!p)
540 p = path + strlen(path);
541
542 if (strlen(tmp->workgroup) != p - path ||
543 (p == path ||
544 ph->fsphStrNICmp(path, tmp->workgroup, p - path)))
545 {
546 strncpy(tmp->workgroup, path, p - path);
547 tmp->workgroup[p - path] = 0;
548 newlevel = 1;
549 }
550 path = *p == '\\' ? p + 1 : p;
551 rootlevel = 1;
552 }
553
554 if (rootlevel == 1) // root path starts from server name
555 {
556 p = ph->fsphStrChr(path, '\\');
557 if (!p)
558 p = path + strlen(path);
559
560 if (strlen(tmp->server_name) != p - path ||
561 (p == path ||
562 ph->fsphStrNICmp(path, tmp->server_name, p - path)))
563 {
564 strncpy(tmp->server_name, path, p - path);
565 tmp->server_name[p - path] = 0;
566 newlevel = 1;
567 }
568 path = *p == '\\' ? p + 1 : p;
569 rootlevel = 2;
570 }
571
572 if (rootlevel == 2) // root path starts from share name
573 {
574 p = ph->fsphStrChr(path, '\\');
575 if (!p)
576 p = path + strlen(path);
577
578 if (strlen(tmp->share_name) != (p - path) ||
579 (p == path ||
580 ph->fsphStrNICmp(path, tmp->share_name, p - path)))
581 {
582 strncpy(tmp->share_name, path, p - path);
583 tmp->share_name[p - path] = 0;
584 newlevel = 1;
585 }
586 path = *p == '\\' ? p + 1 : p;
587 }
588
589 if (newlevel)
590 {
591 // reconnect to server here, first test new connection
592 cli_state* tmp_cli = NULL;
593 rc = smbwrp_connect(&tmpRes, &tmp_cli);
594 if (!rc)
595 {
596 // new connection is ok, disconnect old one
597 cli_state* cli = pConn->cli;
598 smbwrp_disconnect(pRes, cli);
599 // save tmp data structure
600 memcpy( pRes, &tmpRes, sizeof( tmpRes));
601 // save new connection handle
602 pConn->cli = tmp_cli;
603 }
604 }
605 }
606
607 strcpy(result, "\\");
608 strncat(result, path, CCHMAXPATH);
609 return rc;
610}
611
612/* check if the requested resource is available */
613static int checkMountResource(Resource* pRes)
614{
615 int rc;
616 unsigned long action;
617 cli_state* cli = NULL;
618
619 debuglocal(pRes, 9, "checkMountResource in tid#%d\n", _gettid());
620 rc = smbwrp_connect(pRes, &cli);
621 switch (rc)
622 {
623 case 0:
624 rc = NO_ERROR;
625 break;
626 case 1:
627 case 10:
628 case 11:
629 rc = ERROR_BAD_NET_NAME;
630 break;
631 case 2:
632 rc = ERROR_INIT_ROUTINE_FAILED;
633 break;
634 case 3:
635 rc = ERROR_BAD_NET_RESP;
636 break;
637 case 4:
638 rc = ERROR_NETWORK_BUSY;
639 break;
640 case 6:
641 rc = ERROR_NETWORK_ACCESS_DENIED;
642 break;
643 case 7:
644 rc = ERROR_BAD_NETPATH;
645 break;
646 default:
647 rc = ERROR_UNEXP_NET_ERR;
648 break;
649 } /* endswitch */
650
651 smbwrp_disconnect(pRes, cli);
652 return rc;
653}
654
655int APIENTRY NdpMountResource (HRESOURCE *presource, int type, NDPROPERTYHANDLE properties)
656{
657 int rc = NO_ERROR;
658 unsigned long objany = OBJ_ANY;
659 Resource *pRes = NULL;
660
661 ENTER();
662
663 /*
664 * since samba plugin support only 1 type of resources we do not need
665 * to check what the found type really is
666 */
667 pRes = malloc( sizeof(Resource));
668 if (pRes == NULL)
669 rc = ERROR_NOT_ENOUGH_MEMORY;
670 else
671 {
672 memset(pRes, 0, sizeof(Resource));
673 // parse init string
674 rc = initResource (pRes, properties);
675 /*
676 * try to connect to resource (check type) only if thread!=1,
677 * so ndctl startup is not slowed down by network connections.
678 * ndctl does mounting on main thread (#1)
679 * nd/ndpm do not use main thread
680 */
681 if (!rc && _gettid()!=1)
682 rc = checkMountResource( pRes);
683 if (!rc)
684 {
685 // store resource data
686 *presource = (HRESOURCE)pRes;
687 }
688 else
689 free(pRes);
690
691 }
692
693 debuglocal(pRes, 9, "NdpMountResource rc=%d\n", rc);
694 LEAVE();
695 return rc;
696}
697
698int APIENTRY NdpFreeResource (HRESOURCE resource)
699{
700 Resource *pRes = (Resource *)resource;
701 ENTER();
702 dircache_delete(pRes);
703 memset(&pRes->srv, 0, sizeof(pRes->srv));
704 debuglocal(pRes, 9, "NdpFreeResource %d\n", NO_ERROR);
705 debugClose(pRes);
706 free(pRes);
707 LEAVE();
708 return NO_ERROR;
709}
710
711int APIENTRY NdpRsrcCompare (HRESOURCE resource, HRESOURCE resource2)
712{
713 Resource *pRes = (Resource *)resource;
714 Resource *pRes2 = (Resource *)resource2;
715 int rc = ND_RSRC_DIFFERENT;
716
717 debuglocal(pRes, 9, "NdpRsrcCompare in\n");
718 if (ph->fsphStrICmp(pRes->srv.server_name, pRes2->srv.server_name) == 0
719 && ph->fsphStrICmp(pRes->srv.share_name, pRes2->srv.share_name) == 0
720 && ph->fsphStrICmp(pRes->srv.username, pRes2->srv.username) == 0
721 && ph->fsphStrICmp(pRes->srv.workgroup, pRes2->srv.workgroup) == 0)
722 {
723 // resources are equal
724 rc = ND_RSRC_EQUAL;
725 }
726
727 debuglocal(pRes, 9, "NdpRsrcCompare %d\n", rc);
728 return rc;
729}
730
731int APIENTRY NdpRsrcUpdate (HRESOURCE resource, HRESOURCE resource2)
732{
733 // do nothing
734 Resource *pRes = (Resource *)resource;
735 debuglocal(pRes, 9, "NdpRsrcUpdate %d\n", NO_ERROR);
736 return NO_ERROR;
737}
738
739int APIENTRY NdpRsrcQueryInfo (HRESOURCE resource, ULONG *pulFlags, void *pdata, ULONG insize, ULONG *poutlen)
740{
741 Resource *pRes = (Resource *)resource;
742 int rc = NO_ERROR;
743 char s[4096];
744
745 debuglocal(pRes, 9, "NdpRsrcQueryInfo in\n");
746
747 switch (pRes->rootlevel)
748 {
749 case 0:
750 ph->fsph_snprintf(s, sizeof(s) - 1, "SMBFS%s \\\\@%s", ifL ? "64" : "32", pRes->srv.username);
751 break;
752 case 1:
753 ph->fsph_snprintf(s, sizeof(s) - 1, "SMBFS%s %s: \\\\@%s", ifL ? "64" : "32", pRes->srv.workgroup, pRes->srv.username);
754 break;
755 case 2:
756 ph->fsph_snprintf(s, sizeof(s) - 1, "SMBFS%s \\\\%s%s%s@%s", ifL ? "64" : "32", *pRes->srv.workgroup ? pRes->srv.workgroup : "", *pRes->srv.workgroup ? ":" : "", pRes->srv.server_name, pRes->srv.username);
757 break;
758 default:
759 ph->fsph_snprintf(s, sizeof(s) - 1, "SMBFS%s \\\\%s%s%s\\%s@%s", ifL ? "64" : "32", *pRes->srv.workgroup ? pRes->srv.workgroup : "", *pRes->srv.workgroup ? ":" : "", pRes->srv.server_name, pRes->srv.share_name, pRes->srv.username);
760 break;
761 }
762 *poutlen = strlen(s) + 1;
763 if (*poutlen > insize)
764 rc = ERROR_BUFFER_OVERFLOW;
765 else
766 memcpy(pdata, s, *poutlen);
767
768 debuglocal(pRes, 9, "NdpRsrcQueryInfo %d\n", rc);
769 return rc;
770}
771
772int APIENTRY NdpRsrcQueryFSAttach (HRESOURCE resource, void *pdata, ULONG insize, ULONG *poutlen)
773{
774 ULONG ulDummy = 0;
775 // just return the resource info string
776 return NdpRsrcQueryInfo (resource, &ulDummy, pdata, insize, poutlen);
777}
778
779int APIENTRY NdpRsrcQueryFSAllocate (HRESOURCE resource, NDFSALLOCATE *pfsa)
780{
781 Resource *pRes = (Resource *)resource;
782 int rc = NO_ERROR, rc1;
783 unsigned long action = 0;
784 cli_state* cli = NULL;
785 FSALLOCATE fsa;
786
787 ENTER();
788 debuglocal(pRes, 9, "NdpRsrcQueryFSAllocate %08x\n", pfsa);
789
790 if (!pfsa)
791 {
792 LEAVE();
793 return NO_ERROR;
794 }
795
796 debuglocal(pRes, 9, "NdpRsrcQueryFSAllocate in tid#%d\n", _gettid());
797 rc = smbwrp_connect(pRes, &cli);
798 if (rc)
799 {
800 debuglocal(pRes, 9, "NdpRsrcQueryFSAllocate smbwrp_connect failed rc=%d\n", rc);
801 pfsa->cSectorUnit = 1;
802 pfsa->cUnit = 123456;
803 pfsa->cUnitAvail = 123456;
804 pfsa->cbSector = 2048;
805 rc = (rc == 7 ? ERROR_BAD_DEV_TYPE : ERROR_ACCESS_DENIED);
806 LEAVE();
807 return rc;
808 }
809
810 rc = smbwrp_dskattr(pRes, cli, &fsa);
811 if (rc)
812 {
813 pfsa->cSectorUnit = 1;
814 pfsa->cUnit = 123456;
815 pfsa->cUnitAvail = 123456;
816 pfsa->cbSector = 2048;
817 //rc = rc ? rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER);
818 }
819 else
820 {
821 pfsa->cSectorUnit = fsa.cSectorUnit;
822 pfsa->cUnit = fsa.cUnit;
823 pfsa->cUnitAvail = fsa.cUnitAvail;
824 pfsa->cbSector = fsa.cbSector;
825 }
826
827 smbwrp_disconnect(pRes, cli);
828 debuglocal(pRes, 9, "NdpRsrcQueryFSAllocate %d/%d (cUnit = %d/cUnitAvail = %d/cbSector = %d)\n", rc, rc1, pfsa->cUnit, pfsa->cUnitAvail, pfsa->cbSector);
829
830 LEAVE();
831 return rc;
832}
833
834int APIENTRY NdpCreateConnection (HRESOURCE resource, HCONNECTION *pconn)
835{
836 int rc = 0;
837 Resource * pRes = (Resource *)resource;
838 unsigned long action;
839 Connection *pConn = NULL;
840
841 ENTER();
842
843 debuglocal(pRes, 9, "NdpCreateConnection in\n");
844
845 pConn = malloc( sizeof(Connection));
846 if (pConn == NULL)
847 rc = ERROR_NOT_ENOUGH_MEMORY;
848
849 if (rc)
850 {
851 debuglocal(pRes, 9, "NdpCreateConnection ERROR_NOT_ENOUGH_MEMORY %d\n", rc);
852 LEAVE();
853 return rc;
854 }
855
856 memset(pConn, 0, sizeof(Connection));
857 pConn->pRes = pRes;
858 pConn->file.fd = -1;
859
860 debuglocal(pRes, 9, "NdpCreateConnection send CONNECT\n");
861 rc = smbwrp_connect(pRes, &pConn->cli);
862 if (rc)
863 {
864 free(pConn);
865 pConn = NULL;
866 rc = (rc == 7 ? ERROR_BAD_DEV_TYPE : ERROR_INVALID_PARAMETER);
867 }
868
869 *pconn = (HCONNECTION)pConn;
870 debuglocal(pRes, 9, "NdpCreateConnection [%p] %d\n", pConn, rc);
871
872 LEAVE();
873 return rc;
874}
875
876int APIENTRY NdpFreeConnection (HCONNECTION conn)
877{
878 Connection *pConn = (Connection *)conn;
879 Resource *pRes = pConn->pRes;
880 int rc;
881
882 ENTER();
883
884 debuglocal(pRes, 9, "NdpFreeConnection in [%p]\n", pConn);
885 if (pConn->file.fd >= 0)
886 {
887 rc = smbwrp_close(pRes, pConn->cli, &pConn->file);
888 pConn->file.fd = -1;
889 }
890
891 smbwrp_disconnect(pRes, pConn->cli);
892
893 debuglocal(pRes, 9, "NdpFreeConnection %d\n", NO_ERROR);
894 free(pConn);
895
896 LEAVE();
897 return NO_ERROR;
898}
899
900/*
901 * NdpQueryPathInfo is the most important function :) netdrive always calls
902 * the function before every operation to find out the path status:
903 * does it exist, is it a file, does a parent directory exist, etc.
904 * Plugin must return one of the following error codes:
905 * NO_ERROR - path exists and the path information have been successfully
906 * retrieved.
907 * ERROR_FILE_NOT_FOUND - all but the last component of the path exist and the
908 * path without the last component is a directory. dir1_ok\dir2_ok\does_not_exist.
909 * the wildcard can not exist, so the plugin returns FILE_NOT_FOUND, if the parent
910 * directory exist.
911 * ERROR_PATH_NOT_FOUND - any of not last path components does not exist, or all
912 * but the last component exist and is a file: \dir_ok\dir2_ok\file_ok\non_existing.
913 * ERROR_REM_NOT_LIST - resource is temporarily unavailable for some reasons.
914 * Any other error codes means an internal plugin error, not related to the status
915 * of the path queried.
916 */
917int APIENTRY NdpQueryPathInfo (HCONNECTION conn, void *plist, char *szPath)
918{
919 Connection *pConn = (Connection *)conn;
920 Resource *pRes = pConn->pRes;
921 smbwrp_fileinfo finfo;
922 int rc = 0;
923 int rcCon = 0;
924 unsigned long action;
925 char path[CCHMAXPATH+1] = {0};
926
927 ENTER();
928
929 debuglocal(pRes, 9, "NdpQueryPathInfo in [%p] <%s>\n", pConn, szPath);
930
931 /*
932 * if wildcard is specified, we suppose parent dir exist,
933 * so exit immediately
934 */
935 if (ph->fsphStrChr(szPath, '*') || ph->fsphStrChr(szPath, '?'))
936 {
937 LEAVE();
938 return ERROR_FILE_NOT_FOUND;
939 }
940
941 do {
942 // First check if there is information in the directory cache.
943 unsigned long ulAge = 0;
944 if (dircache_find_path(pRes, szPath, &finfo, &ulAge))
945 {
946 if (ulAge <= 15) /* @todo configurable. */
947 {
948 rc = NO_ERROR;
949 finfo.easize = -1;
950 getfindinfoL(pConn, plist, &finfo, 0, NULL);
951 break;
952 }
953 }
954
955 rc = pathparser(pRes, pConn, szPath, path);
956 debuglocal(pRes, 9, "NdpQueryPathInfo pathparser for <%s> rc=%d\n", path, rc);
957 switch (rc)
958 {
959 case NO_ERROR :
960 case ERROR_FILE_NOT_FOUND:
961 case ERROR_PATH_NOT_FOUND:
962 case ERROR_ACCESS_DENIED:
963 case ERROR_INVALID_PARAMETER:
964 break;
965 default :
966 rc = ERROR_PATH_NOT_FOUND;
967 }
968
969 if (rc)
970 break;
971
972 strncpy(finfo.fname, path, sizeof(finfo.fname) - 1);
973 debuglocal(pRes, 9, "NdpQueryPathInfo smbwrp_getattr for <%s>\n", path);
974 rc = smbwrp_getattr(pRes, &pRes->srv, pConn->cli, &finfo);
975 if (rc)
976 {
977 // remote server not available for first time?
978 if (rc == ERROR_REM_NOT_LIST)
979 {
980 // free current cli resources
981 smbwrp_disconnect(pRes, pConn->cli);
982 // reconnect
983 rcCon = smbwrp_connect(pRes, &pConn->cli);
984 if (rcCon != NO_ERROR)
985 debuglocal(pRes, 9, "NdpQueryPathInfo smbwrp_connect rc = %d\n", rcCon);
986 // try file list again if reconnecting worked
987 if (rcCon == NO_ERROR)
988 rc = smbwrp_getattr(pRes, &pRes->srv, pConn->cli, &finfo);
989 }
990
991 debuglocal(pRes, 9, "NdpQueryPathInfo smbwrp_getattr, rc = %d\n", rc);
992 switch (rc)
993 {
994 case NO_ERROR :
995 case ERROR_FILE_NOT_FOUND:
996 case ERROR_PATH_NOT_FOUND:
997 case ERROR_ACCESS_DENIED:
998 case ERROR_INVALID_PARAMETER:
999 case ERROR_REM_NOT_LIST:
1000 break;
1001 default :
1002 rc = ERROR_PATH_NOT_FOUND;
1003 }
1004 }
1005
1006 if (rc == NO_ERROR)
1007 {
1008 finfo.easize = -1;
1009 getfindinfoL(pConn, plist, &finfo, 0, NULL);
1010 }
1011 else if (rc == ERROR_FILE_NOT_FOUND)
1012 {
1013 // now try the upper path
1014 char * p = ph->fsphStrRChr(finfo.fname, '\\');
1015 if (p && p > finfo.fname)
1016 {
1017 *p = 0;
1018 rc = smbwrp_getattr(pRes, &pRes->srv, pConn->cli, &finfo);
1019 debuglocal(pRes, 9, "NdpQueryPathInfo upper path in <%s>, rc = %d\n", finfo.fname, rc);
1020 if (rc == NO_ERROR)
1021 rc = (finfo.attr & FILE_DIRECTORY) !=0 ? ERROR_FILE_NOT_FOUND:ERROR_PATH_NOT_FOUND;
1022 else if (rc != ERROR_REM_NOT_LIST)
1023 rc = ERROR_PATH_NOT_FOUND;
1024 }
1025 }
1026 } while (0);
1027 debuglocal(pRes, 9, "NdpQueryPathInfo <%s> (%s) %d\n", szPath, path, rc);
1028
1029 LEAVE();
1030 return rc;
1031}
1032
1033int APIENTRY NdpFindStart (HCONNECTION conn, void *plist, NDFILEINFOL *pfiparent, char *szPath, ULONG ulAttribute)
1034{
1035 Connection *pConn = (Connection *)conn;
1036 Resource *pRes = pConn->pRes;
1037 int rc = NO_ERROR, count = 0;
1038 unsigned long action;
1039 char *mask = "*";
1040 char dir[CCHMAXPATH+1] = {0};
1041 char path[CCHMAXPATH+1] = {0};
1042 smbwrp_fileinfo * data;
1043 NDPATHELEMENT *pel = ph->fsphNameElem(0);
1044 filelist_state state;
1045 char * p;
1046
1047 ENTER();
1048
1049 debuglocal(pRes, 9, "NdpFindStart in [%p]\n", pConn);
1050
1051 strncpy(dir, szPath, sizeof(dir) - 1);
1052 if (pel)
1053 {
1054 mask = pel->name;
1055 dir[strlen(szPath) - pel->length] = 0;
1056 }
1057 action = strlen(dir) - 1;
1058 if (dir[action] == '\\')
1059 dir[action] = 0;
1060
1061 rc = pathparser(pRes, pConn, dir, path);
1062 if (rc)
1063 return rc;
1064
1065 action = strlen(path) - 1;
1066 if (path[action] != '\\')
1067 strncat(path, "\\", sizeof(path) - 1);
1068
1069 strcpy(dir, path);
1070 strncat(path, mask, sizeof(path) - 1);
1071
1072 /*
1073 * this structure will be used by libsmb callbacks,
1074 * so we store here all we need to fill netdrive structures
1075 */
1076 state.pConn = pConn;
1077 state.plist = plist;
1078 state.ulAttribute = ulAttribute;
1079 strcpy(state.dir, dir);
1080 strcpy(state.dir_mask, mask);
1081 strcpy(state.mask, path);
1082 state.fullpath = szPath;
1083 /*
1084 * This plugin always reads a complete directory listing and
1085 * filters results using actual mask (state.dir_mask) in getfindinfoL.
1086 * May be this was a workaround for some server bug.
1087 * If this will be changed, then directory listing cache must
1088 * be changed too, and must remember the mask, which was used to
1089 * obtain a listing. Now the directory cache saves complete directory
1090 * listings and then uses them to find information about single files.
1091 * However, with a directory cache, it is probably faster to get a full
1092 * listing and then use it to obtain info about separate files than to
1093 * perform a network list query operation using actual wild cards for
1094 * each file. Some application, for example OpenOffice, do this.
1095 */
1096 p = getlastslash(state.mask);
1097 if (p)
1098 {
1099 *(p + 1) = '*';
1100 *(p + 2) = 0;
1101 }
1102 else
1103 strcpy(state.mask, "\\*");
1104
1105 debuglocal(pRes, 9, "NdpFindStart: dir [%s], dir_mask [%s], mask [%s], szPath [%s]\n",
1106 state.dir, state.dir_mask, state.mask, state.fullpath);
1107 rc = smbwrp_filelist(pRes, &pRes->srv, pConn->cli, &state);
1108 /*
1109 * we need to handle reconnection also here, because NdpQueryPathInfo
1110 * could be called with '*' and exit then immediately
1111 * (without calling libsmb)
1112 */
1113 if (rc == ERROR_REM_NOT_LIST)
1114 {
1115 // free current cli resources
1116 smbwrp_disconnect(pRes, pConn->cli);
1117 // reconnect
1118 smbwrp_connect(pRes, &pConn->cli);
1119 // try file list again next loop
1120 rc = smbwrp_filelist(pRes, &pRes->srv, pConn->cli, &state);
1121 debuglocal(pRes, 9, "NdpFindStart remote connection lost, rc = %d\n", rc);
1122 }
1123
1124 debuglocal(pRes, 9, "NdpFindStart <%s> (%s) cnt %d %d\n", szPath, path, count, rc);
1125
1126 LEAVE();
1127 return rc;
1128}
1129
1130int APIENTRY NdpDeletePathInfo (HRESOURCE resource, NDFILEINFOL *pfi)
1131{
1132 Resource * pRes = (Resource *)resource;
1133 debuglocal(pRes, 9, "NdpDeletePathInfo %d\n", 0);
1134 return NO_ERROR;
1135}
1136
1137int APIENTRY NdpRefresh (HCONNECTION conn, char *path, int tree)
1138{
1139 Connection *pConn = (Connection *)conn;
1140 debuglocal(pConn->pRes, 9, "NdpRefresh <%s> %d\n", path, 0);
1141 return NO_ERROR;
1142}
1143
1144int APIENTRY NdpDiscardResourceData (HRESOURCE resource, NDDATABUF *pdatabuf)
1145{
1146 /*
1147 * The plugin do not have to deallocate anything, because
1148 * resource data did not contain any pointers to plugins data.
1149 * Data stored by fsphSetResourceData will be deallocated by NetDrive.
1150 */
1151
1152 Resource * pRes = (Resource *)resource;
1153 debuglocal(pRes, 9, "NdpDicardresourceData %d\n", 0);
1154 return NO_ERROR;
1155}
1156
1157int APIENTRY NdpSetPathInfo (HCONNECTION conn, NDFILEINFOL *pfi, char *szPathName)
1158{
1159 Connection *pConn = (Connection *)conn;
1160 Resource *pRes = pConn->pRes;
1161 int rc = 0;
1162 unsigned long action;
1163 char path[CCHMAXPATH+1] = {0};
1164 smbwrp_fileinfo finfo;
1165
1166 ENTER();
1167
1168 debuglocal(pRes, 9, "NdpSetPathInfo in [%p]\n", pConn);
1169
1170 // delete the dir cache
1171 dircache_invalidate(szPathName, pRes, 1);
1172
1173 do {
1174 rc = pathparser(pRes, pConn, szPathName, path);
1175 if (rc)
1176 break;
1177
1178 memset(&finfo, 0, sizeof(finfo));
1179 strncpy(finfo.fname, path, sizeof(finfo.fname) - 1);
1180 fsphDosDateToUnixTime(pRes, pfi->stat.fdateLastWrite, pfi->stat.ftimeLastWrite, &(finfo.mtime));
1181 finfo.attr = pfi->stat.attrFile & 0x37;
1182 rc = smbwrp_setattr(pRes, pConn->cli, &finfo);
1183 } while (0);
1184
1185 debuglocal(pRes, 9, "NdpSetPathInfo <%s> (%s) %d\n", szPathName, path, rc);
1186
1187 LEAVE();
1188 return rc;
1189}
1190
1191int buildFEALIST(Resource *pRes, FEALIST *pFEASrc, GEALIST *pGEAList, FEALIST *pFEAList)
1192{
1193 int rc = 0;
1194 FEA * pfea;
1195 FEA * pfeadest;
1196 unsigned long size;
1197 unsigned long done = sizeof(pFEAList->cbList);
1198 unsigned long dsize;
1199 unsigned long ddone = sizeof(pFEAList->cbList);
1200
1201 size = pFEASrc->cbList;
1202 pfea = pFEASrc->list;
1203 pfeadest = pFEAList->list;
1204 dsize = pFEAList->cbList;
1205 //debuglocal(pRes, 9,"buildFEALIST in destsize %d srcsize %d pGEAList=%08x pGEAList->cbList=%d\n", dsize, ddone, size, pGEAList, pGEAList ? pGEAList->cbList : 0);
1206
1207 while (done < size)
1208 {
1209 char * name = (char *)(pfea + 1);
1210 int insert = 1;
1211 if (pGEAList && pGEAList->cbList > sizeof(pGEAList->cbList))
1212 {
1213 GEA * pgea = pGEAList->list;
1214 unsigned long size = pGEAList->cbList - sizeof(pGEAList->cbList);
1215 unsigned long done = 0;
1216 insert = 0;
1217 while (done < size)
1218 {
1219 //debuglocal(pRes, 9,"comp <%s> <%s>\n", name, pgea->szName);
1220 if (!ph->fsphStrNCmp(name, pgea->szName, pgea->cbName))
1221 {
1222 insert = 1;
1223 break;
1224 }
1225 done += pgea->cbName + 2;
1226 pgea = (GEA *)((char *)pgea + pgea->cbName + 2);
1227 }
1228 }
1229 if (insert)
1230 {
1231 ddone += sizeof(FEA) + pfea->cbName + 1 + pfea->cbValue;
1232 if (ddone <= dsize)
1233 {
1234 pfeadest->cbName = pfea->cbName;
1235 pfeadest->cbValue = pfea->cbValue;
1236 pfeadest->fEA = 0;
1237 strcpy((char *)(pfeadest + 1), name);
1238 memcpy((char *)(pfeadest + 1) + pfea->cbName + 1, (char *)(pfea + 1) + pfea->cbName + 1, pfea->cbValue);
1239 pfeadest = (FEA *)((char *)pFEAList + ddone);
1240 }
1241 }
1242 done += sizeof(FEA) + pfea->cbName + 1 + pfea->cbValue;
1243 //debuglocal(pRes, 9,"buuildfea <%s> insert=%d pfea->cbName=%d pfea->cbValue=%d srcdone=%d destdone=%d pfeadest=%08x pfea=%08x\n", name, insert, pfea->cbName, pfea->cbValue, done, ddone, pfeadest, pfea);
1244 pfea = (FEA *)((char *)pFEASrc + done);
1245 }
1246
1247 pFEAList->cbList = ddone;
1248 if (ddone > dsize && dsize > sizeof(pFEAList->cbList))
1249 rc = ERROR_BUFFER_OVERFLOW;
1250
1251 debuglocal(pRes, 9, "buildFEALIST rc=%d destsize=%d destdone=%d srcsize=%d pGEAList=%08x\n", rc, dsize, ddone, size, pGEAList);
1252 return rc;
1253}
1254
1255int APIENTRY NdpEAQuery (HCONNECTION conn, GEALIST *pGEAList, NDFILEINFOL *pfi, FEALIST *pFEAList)
1256{
1257 Connection *pConn = (Connection *)conn;
1258 Resource *pRes = pConn->pRes;
1259 int rc = 0;
1260 unsigned long action;
1261 char * path = NULL;
1262 FEALIST * pFEASrc;
1263 NDDATABUF fdata = {0};
1264 smbwrp_fileinfo *finfo;
1265 const int cbBuffer = 64*1024;
1266
1267 if (!pfi || !pfi->pszName || !pFEAList)
1268 return ERROR_EAS_NOT_SUPPORTED;
1269
1270 if (!pRes->easupport)
1271 return ERROR_EAS_NOT_SUPPORTED;
1272
1273 rc = ph->fsphGetFileInfoData(pfi, &fdata, 0);
1274 if (rc || !fdata.ulSize || !fdata.pData)
1275 {
1276 debuglocal(pRes, 9, "NdpEAQuery: ph->fsphGetFileInfoData = %d/%d %08x\n", rc, fdata.ulSize, fdata.pData);
1277 return ERROR_EAS_NOT_SUPPORTED;
1278 }
1279
1280 ENTER();
1281
1282 finfo = (smbwrp_fileinfo *)fdata.pData;
1283 path = finfo->fname;
1284 debuglocal(pRes, 9, "NdpEAQuery in [%p] <%s> %08x %d\n", pConn, path, pGEAList, pGEAList ? pGEAList->cbList : 0);
1285
1286 char *pchBuffer = (char *)malloc(cbBuffer);
1287 if (!pchBuffer)
1288 {
1289 LEAVE();
1290 return ERROR_NOT_ENOUGH_MEMORY;
1291 }
1292
1293 do {
1294 rc = smbwrp_listea(pRes, pConn->cli, path, pchBuffer, cbBuffer);
1295 pFEASrc = (FEALIST*) pchBuffer;
1296 if (rc)
1297 {
1298 switch (rc)
1299 {
1300 case ERROR_FILE_NOT_FOUND :
1301 case ERROR_PATH_NOT_FOUND :
1302 pFEAList->cbList = sizeof(pFEAList->cbList);
1303 rc = NO_ERROR;
1304 break;
1305 case ERROR_BUFFER_OVERFLOW :
1306 pFEAList->cbList = pFEASrc->cbList;
1307 break;
1308 default :
1309 rc = ERROR_EAS_NOT_SUPPORTED;
1310 }
1311 }
1312 else
1313 rc = buildFEALIST(pRes, (FEALIST *)pFEASrc, pGEAList, pFEAList);
1314 } while (0);
1315
1316 free(pchBuffer);
1317 debuglocal(pRes, 9, "NdpEAQuery <%s> %d %d %d\n", pfi->pszName, rc, pFEASrc->cbList, pFEAList->cbList);
1318
1319 LEAVE();
1320 return rc;
1321}
1322
1323int APIENTRY NdpEASet (HCONNECTION conn, FEALIST *pFEAList, NDFILEINFOL *pfi)
1324{
1325 Connection *pConn = (Connection *)conn;
1326 Resource *pRes = pConn->pRes;
1327 int rc = 0;
1328 char * path;
1329 unsigned long action;
1330 NDDATABUF fdata = {0};
1331 smbwrp_fileinfo *finfo;
1332
1333 debuglocal(pRes, 9, "NdpEASet in [%p]\n", pConn);
1334
1335 if (!pfi || !pfi->pszName)
1336 return ERROR_EAS_NOT_SUPPORTED;
1337
1338 if (!pRes->easupport)
1339 return ERROR_EAS_NOT_SUPPORTED;
1340
1341 rc = ph->fsphGetFileInfoData(pfi, &fdata, 0);
1342 if (rc || !fdata.ulSize || !fdata.pData)
1343 {
1344 debuglocal(pRes, 9, "NdpEASet: ph->fsphGetFileInfoData = %d/%d/%08x\n", rc, fdata.ulSize, fdata.pData);
1345 return ERROR_EAS_NOT_SUPPORTED;
1346 }
1347
1348 finfo = (smbwrp_fileinfo *)fdata.pData;
1349 path = finfo->fname;
1350
1351 rc = helperEASet(pRes, pConn->cli, pFEAList, path);
1352 debuglocal(pRes, 9, "NdpEASet %d\n", rc);
1353 return rc;
1354}
1355
1356int APIENTRY NdpEASize (HCONNECTION conn, NDFILEINFOL *pfi, ULONG *pulEASize)
1357{
1358 Connection *pConn = (Connection *)conn;
1359 Resource *pRes = pConn->pRes;
1360 int rc = 0;
1361 unsigned long action;
1362 char * path = NULL;
1363 FEALIST * pfealist;
1364 NDDATABUF fdata = {0};
1365 smbwrp_fileinfo *finfo;
1366 const int cbBuffer = 64*1024;
1367 int easize;
1368
1369 if (!pfi || !pulEASize)
1370 return ERROR_EAS_NOT_SUPPORTED;
1371
1372 if (!pRes->easupport)
1373 return ERROR_EAS_NOT_SUPPORTED;
1374
1375 rc = ph->fsphGetFileInfoData(pfi, &fdata, 0);
1376 if (rc || !fdata.ulSize || !fdata.pData)
1377 {
1378 debuglocal(pRes, 9, "NdpEASize: ph->fsphGetFileInfoData = %d/%d/%08x\n", rc, fdata.ulSize, fdata.pData);
1379 return ERROR_EAS_NOT_SUPPORTED;
1380 }
1381
1382 ENTER();
1383
1384 finfo = (smbwrp_fileinfo *)fdata.pData;
1385 easize = finfo->easize;
1386 finfo->easize = -1;
1387 path = finfo->fname;
1388 if (easize >= 0)
1389 {
1390 *pulEASize = easize;
1391 debuglocal(pRes, 9, "NdpEASize <%s> cached %d\n", path, easize);
1392 LEAVE();
1393 return NO_ERROR;
1394 }
1395
1396 debuglocal(pRes, 9, "NdpEASize in [%p] <%s> \n", pConn, path);
1397
1398 char *pchBuffer = (char *)malloc(cbBuffer);
1399 if (!pchBuffer)
1400 {
1401 LEAVE();
1402 return ERROR_NOT_ENOUGH_MEMORY;
1403 }
1404
1405 do {
1406 rc = smbwrp_listea(pRes, pConn->cli, path, pchBuffer, cbBuffer);
1407 pfealist = (FEALIST*)pchBuffer;
1408 if (rc)
1409 {
1410 switch (rc)
1411 {
1412 case ERROR_FILE_NOT_FOUND :
1413 case ERROR_PATH_NOT_FOUND :
1414 pfealist->cbList = sizeof(pfealist->cbList); // Fall through */
1415 case ERROR_BUFFER_OVERFLOW :
1416 rc = NO_ERROR;
1417 break;
1418 default :
1419 rc = ERROR_EAS_NOT_SUPPORTED;
1420 }
1421 }
1422 *pulEASize = pfealist->cbList;
1423 } while (0);
1424
1425 free(pchBuffer);
1426 debuglocal(pRes, 9, "NdpEASize <%s> %d %d\n", pfi->pszName, *pulEASize, rc);
1427
1428 LEAVE();
1429 return rc;
1430}
1431
1432int APIENTRY NdpSetCurrentDir (HCONNECTION conn, NDFILEINFOL *pfi, char *szPath)
1433{
1434 Connection *pConn = (Connection *)conn;
1435 Resource *pRes = pConn->pRes;
1436 int rc = 0;
1437 unsigned long action;
1438 char path[CCHMAXPATH+1] = {0};
1439
1440 debuglocal(pRes, 9, "NdpSetCurrentDir in [%p]\n", pConn);
1441
1442 ENTER();
1443
1444 do {
1445 rc = pathparser(pRes, pConn, szPath, path);
1446 if (rc)
1447 break;
1448
1449 rc = smbwrp_chdir(pRes, &pRes->srv, pConn->cli, path);
1450 } while (0);
1451
1452 debuglocal(pRes, 9, "NdpSetCurrentDir <%s> (%s) %d\n", szPath, path, rc);
1453
1454 LEAVE();
1455 return rc;
1456}
1457
1458int APIENTRY NdpCopy (HCONNECTION conn, NDFILEINFOL *pfiDst, char *szDst, NDFILEINFOL *pfiSrc, char *szSrc, ULONG ulOption)
1459{
1460 Connection *pConn = (Connection *)conn;
1461 Resource *pRes = pConn->pRes;
1462 debuglocal(pRes, 9, "NdpCopy <%s> -> <%s> %d\n", szSrc, szDst, ERROR_CANNOT_COPY);
1463 return ERROR_CANNOT_COPY;
1464}
1465
1466int APIENTRY NdpCopy2 (HCONNECTION conn, HRESOURCE resDst, NDFILEINFOL *pfiDst, char *szDst, NDFILEINFOL *pfiSrc, char *szSrc, ULONG ulOption)
1467{
1468 Connection *pConn = (Connection *)conn;
1469 Resource *pRes = pConn->pRes;
1470 debuglocal(pRes, 9, "NdpCopy2 <%s> -> <%s> %d\n", szSrc, szDst, ERROR_CANNOT_COPY);
1471 return ERROR_CANNOT_COPY;
1472}
1473
1474int APIENTRY NdpForceDelete (HCONNECTION conn, NDFILEINFOL *pfi, char *szFile)
1475{
1476 Connection *pConn = (Connection *)conn;
1477 Resource *pRes = pConn->pRes;
1478 int rc = 0;
1479 unsigned long action;
1480 char path[CCHMAXPATH+1] = {0};
1481
1482 ENTER();
1483
1484 debuglocal(pRes, 9, "NdpForceDelete in [%p]\n", pConn);
1485
1486 dircache_invalidate(szFile, pRes, 1);
1487
1488 do {
1489 rc = pathparser(pRes, pConn, szFile, path);
1490 if (rc)
1491 break;
1492
1493 rc = smbwrp_unlink(pRes, pConn->cli, path);
1494 } while (0);
1495
1496 debuglocal(pRes, 9, "NdpForceDelete <%s> (%s) %d\n", szFile, path, rc);
1497
1498 LEAVE();
1499 return rc;
1500}
1501
1502int APIENTRY NdpCreateDir (HCONNECTION conn, NDFILEINFOL *pfiparent, char *szDirName, FEALIST *pFEAList)
1503{
1504 Connection *pConn = (Connection *)conn;
1505 Resource *pRes = pConn->pRes;
1506 int rc = 0;
1507 int rcEASet = 0;
1508 unsigned long action;
1509 char path[CCHMAXPATH+1] = {0};
1510
1511 ENTER();
1512
1513 debuglocal(pRes, 9, "NdpCreateDir in [%p]\n", pConn);
1514
1515 dircache_invalidate(szDirName, pRes, 1);
1516
1517 do {
1518 rc = pathparser(pRes, pConn, szDirName, path);
1519 if (rc)
1520 break;
1521
1522 rc = smbwrp_mkdir(pRes, pConn->cli, path);
1523 } while (0);
1524
1525 LEAVE();
1526
1527 if (path && pRes->easupport)
1528 rcEASet = helperEASet(pRes, pConn->cli, pFEAList, path);
1529
1530 debuglocal(pRes, 9, "NdpCreateDir <%s> (%s) rc=%d, EASupport=%s rc=%d\n", szDirName, path, rc, pRes->easupport?"yes":"no", rcEASet);
1531
1532 return rc;
1533}
1534
1535int APIENTRY NdpDeleteDir (HCONNECTION conn, NDFILEINFOL *pfi, char *szDir)
1536{
1537 Connection *pConn = (Connection *)conn;
1538 Resource *pRes = pConn->pRes;
1539 int rc = 0;
1540 unsigned long action;
1541 char path[CCHMAXPATH+1] = {0};
1542
1543 ENTER();
1544
1545 debuglocal(pRes, 9, "NdpDeleteDir in [%p]\n", pConn);
1546
1547 dircache_invalidate(szDir, pRes, 1);
1548
1549 do {
1550 rc = pathparser(pRes, pConn, szDir, path);
1551 if (rc)
1552 break;
1553
1554 rc = smbwrp_rmdir(pRes, pConn->cli, path);
1555 } while (0);
1556
1557 debuglocal(pRes, 9, "NdpDeleteDir <%s> (%s) %d\n", szDir, path, rc);
1558
1559 LEAVE();
1560 return rc;
1561}
1562
1563int APIENTRY NdpMove (HCONNECTION conn, NDFILEINFOL *pfiDst, char *szDst, NDFILEINFOL *pfiSrc, char *szSrc)
1564{
1565 Connection *pConn = (Connection *)conn;
1566 Resource *pRes = pConn->pRes;
1567 int rc = 0;
1568 unsigned long action;
1569 char src[CCHMAXPATH+1] = {0};
1570 int l1, l2;
1571 char * p = szDst;
1572
1573 ENTER();
1574
1575 debuglocal(pRes, 9, "NdpMove in [%p] from <%s> to <%s>\n", pConn, szSrc, szDst);
1576
1577 dircache_invalidate(szSrc, pRes, 1);
1578 dircache_invalidate(szDst, pRes, 1);
1579
1580 do
1581 {
1582 rc = pathparser(pRes, pConn, szSrc, src);
1583 if (rc)
1584 break;
1585
1586 l1 = strlen(szSrc);
1587 l2 = strlen(src);
1588 if (l1 > l2)
1589 {
1590 if (ph->fsphStrNICmp(szSrc, szDst, l1 - l2))
1591 {
1592 /*
1593 * the file moved accross different shares or servers or
1594 * workgroups
1595 */
1596 rc = ERROR_WRITE_PROTECT;
1597 break;
1598 }
1599 p = szDst + l1 - l2 + 1;
1600 }
1601 rc = smbwrp_rename(pRes, pConn->cli, src, p);
1602 } while (0);
1603
1604 debuglocal(pRes, 9, "NdpMove <%s> -> <%s> (%s) %d\n", szSrc, szDst, src, rc);
1605
1606 LEAVE();
1607 return rc;
1608}
1609
1610int APIENTRY NdpMove2 (HCONNECTION conn, HRESOURCE resDst, NDFILEINFOL *pfiDst, char *szDst, NDFILEINFOL *pfiSrc, char *szSrc)
1611{
1612 Connection *pConn = (Connection *)conn;
1613 Resource *pRes = pConn->pRes;
1614 debuglocal(pRes, 9, "NdpMove2 <%s> -> <%s> %d\n", szSrc, szDst, ERROR_WRITE_PROTECT);
1615 return ERROR_WRITE_PROTECT;
1616}
1617
1618
1619int APIENTRY NdpChangeCase (HCONNECTION conn, char *szDst, NDFILEINFOL *pfiSrc, char *szSrc, char *szNewName, ULONG ulNameLen)
1620{
1621 return NdpMove (conn, pfiSrc, szDst, pfiSrc, szSrc);
1622}
1623
1624int APIENTRY NdpRename (HCONNECTION conn, char *szDst, NDFILEINFOL *pfiSrc, char *szSrc, char *szNewName, ULONG ulNameLen)
1625{
1626 return NdpMove (conn, pfiSrc, szDst, pfiSrc, szSrc);
1627}
1628
1629int smbopen(Connection *pConn, char *szFileName, int flags, ULONG ulOpenMode, ULONG ulAttribute, FEALIST *pFEAList)
1630{
1631 Resource *pRes = pConn->pRes;
1632 unsigned long action;
1633 int rc = 0;
1634 char path[CCHMAXPATH+1] = {0};
1635
1636 ENTER();
1637
1638 debuglocal(pRes, 9, "smbopen in [%p] %d\n", pConn, pConn->file.fd);
1639
1640 if (flags & O_CREAT)
1641 dircache_invalidate(szFileName, pRes, 1);
1642
1643 do {
1644 if (pConn->file.fd > 0)
1645 {
1646 rc = ERROR_TOO_MANY_OPEN_FILES;
1647 break;
1648 }
1649
1650 rc = pathparser(pRes, pConn, szFileName, path);
1651 if (rc)
1652 break;
1653
1654 strncpy(pConn->file.fullname, szFileName, sizeof(pConn->file.fullname) - 1);
1655 strncpy(pConn->file.fname, path, sizeof(pConn->file.fname) - 1);
1656 flags |= O_BINARY;
1657 switch (ulOpenMode & 3)
1658 {
1659 case OPEN_ACCESS_READONLY :
1660 flags |= O_RDONLY;
1661 break;
1662 case OPEN_ACCESS_WRITEONLY :
1663 flags |= O_WRONLY;
1664 break;
1665 case OPEN_ACCESS_READWRITE :
1666 flags |= O_RDWR;
1667 break;
1668 default :
1669 flags |= O_RDWR;
1670 }
1671
1672 pConn->file.openmode = flags;
1673 pConn->file.openattr = ulAttribute & 0x37;
1674 pConn->file.denymode = (ulOpenMode & 0x70) >> 4;
1675 rc = smbwrp_open(pConn->pRes, pConn->cli, &pConn->file);
1676 } while (0);
1677
1678 debuglocal(pRes, 9, "smbopen <%s> (%s) %08x %08x %08x %d. file = %d\n", szFileName, path, flags, ulOpenMode, ulAttribute, rc, pConn->file.fd);
1679 if (!rc && pFEAList)
1680 {
1681 int rc1 = NdpFileEASet((HCONNECTION)pConn, (NDFILEHANDLE)0, pFEAList);
1682 debuglocal(pRes, 9, "smbopen NdpFileEASet %d. pFEAList->cbList %d\n", rc1, pFEAList->cbList);
1683 }
1684
1685 LEAVE();
1686 return rc;
1687}
1688
1689int APIENTRY NdpOpenReplace (HCONNECTION conn, NDFILEINFOL *pfi, NDFILEHANDLE *phandle, char *szFileName, ULONG ulSize, ULONG ulOpenMode, ULONG ulAttribute, FEALIST *pFEAList)
1690{
1691 return smbopen((Connection *)conn, szFileName, O_TRUNC, ulOpenMode, ulAttribute, pFEAList);
1692}
1693
1694int APIENTRY NdpOpenReplaceL(HCONNECTION conn, NDFILEINFO *pfi, NDFILEHANDLE *phandle, char *szFileName, LONGLONG llSize, ULONG ulOpenMode, ULONG ulAttribute, FEALIST *pFEAList)
1695{
1696 return smbopen((Connection *)conn, szFileName, O_TRUNC, ulOpenMode, ulAttribute, pFEAList);
1697}
1698
1699int APIENTRY NdpOpenCreate (HCONNECTION conn, NDFILEINFOL *pfiparent, NDFILEHANDLE *phandle, char *szFileName, ULONG ulSize, ULONG ulOpenMode, ULONG ulAttribute, FEALIST *pFEAList)
1700{
1701 return smbopen((Connection *)conn, szFileName, O_CREAT | O_EXCL, ulOpenMode, ulAttribute, pFEAList);
1702}
1703
1704int APIENTRY NdpOpenCreateL(HCONNECTION conn, NDFILEINFO *pfiparent, NDFILEHANDLE *phandle, char *szFileName, LONGLONG llSize, ULONG ulOpenMode, ULONG ulAttribute, FEALIST *pFEAList)
1705{
1706 return smbopen((Connection *)conn, szFileName, O_CREAT | O_EXCL, ulOpenMode, ulAttribute, pFEAList);
1707}
1708
1709int APIENTRY NdpOpenExisting (HCONNECTION conn, NDFILEINFOL *pfi, NDFILEHANDLE *phandle, char *szFileName, ULONG ulOpenMode, USHORT *pfNeedEA)
1710{
1711 if (pfNeedEA)
1712 *pfNeedEA = 0; // wtf is this ?
1713 return smbopen((Connection *)conn, szFileName, 0, ulOpenMode, 0, NULL);
1714}
1715
1716int APIENTRY NdpSetFileAttribute (HCONNECTION conn, NDFILEINFOL *pfi, char *szFileName, USHORT usAttr)
1717{
1718 Connection *pConn = (Connection *)conn;
1719 Resource *pRes = pConn->pRes;
1720 int rc = 0;
1721 unsigned long action;
1722
1723 smbwrp_fileinfo finfo;
1724 char path[CCHMAXPATH+1] = {0};
1725
1726 ENTER();
1727
1728 debuglocal(pRes, 9, "NdpSetFileAttribute in [%p]\n", pConn);
1729 do {
1730 rc = pathparser(pRes, pConn, szFileName, path);
1731 if (rc)
1732 break;
1733
1734 memset(&finfo, 0, sizeof(finfo));
1735 strncpy(finfo.fname, path, sizeof(finfo.fname) - 1);
1736 finfo.attr = usAttr & 0x37;
1737 rc = smbwrp_setattr(pRes, pConn->cli, &finfo);
1738 } while (0);
1739
1740 debuglocal(pRes, 9, "NdpSetFileAttribute <%s> (%s) %04x %d\n", szFileName, path, usAttr, rc);
1741
1742 LEAVE();
1743 return rc;
1744}
1745
1746int APIENTRY NdpFlush (HRESOURCE resource)
1747{
1748 Resource *pRes = (Resource *)resource;
1749 debuglocal(pRes, 9, "NdpFlush %d\n", ERROR_NOT_SUPPORTED);
1750 return ERROR_NOT_SUPPORTED;
1751}
1752
1753/*
1754 * Called when a new thread will call the plugin.
1755 * Allows to do per thread init, like disable signals.
1756*/
1757#define ND_PL_INIT_THREAD 0xFFFF0000
1758
1759int APIENTRY NdpIOCTL (int type, HRESOURCE resource, char *path, int function, void *in, ULONG insize, PULONG poutlen)
1760{
1761 Resource *pRes = (Resource *)resource;
1762 if (function == ND_PL_INIT_THREAD)
1763 {
1764 smbwrp_initthread();
1765 debuglocal(pRes, 9, "NdpIOCTL init thread\n");
1766 return NO_ERROR;
1767 }
1768
1769 debuglocal(pRes, 9, "NdpIOCTL <%s> %d\n", path, function);
1770
1771 if (in && insize > 4096)
1772 {
1773 char out[4096];
1774 sprintf (out, "SAMBA IOCTL function = %d, parms [%s] insize = %d, *poutlen = %d", function, in, insize, *poutlen);
1775 *poutlen = strlen(out);
1776 strcpy (in, out);
1777 return NO_ERROR;
1778 }
1779
1780 return ERROR_NOT_SUPPORTED;
1781}
1782
1783int APIENTRY NdpFileQueryInfo (HCONNECTION conn, NDFILEHANDLE handle, void *plist)
1784{
1785 Connection *pConn = (Connection *)conn;
1786 Resource *pRes = pConn->pRes;
1787 int rc = 0;
1788 unsigned long action;
1789 smbwrp_fileinfo finfo;
1790
1791 ENTER();
1792
1793 debuglocal(pRes, 9, "NdpFileQueryInfo in [%p]\n", pConn);
1794 do {
1795 if (pConn->file.fd < 0 || !*pConn->file.fname)
1796 {
1797 rc = ERROR_INVALID_HANDLE;
1798 break;
1799 }
1800 strncpy(finfo.fname, pConn->file.fname, sizeof(finfo.fname) - 1);
1801 rc = smbwrp_fgetattr(pRes, pConn->cli, &pConn->file, &finfo);
1802 if (!rc)
1803 {
1804 finfo.easize = -1;
1805 getfindinfoL(pConn, plist, &finfo, 0, NULL);
1806 }
1807 } while (0);
1808
1809 debuglocal(pRes, 9, "NdpFileQueryInfo <%s> %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, rc);
1810
1811 LEAVE();
1812 return rc;
1813}
1814
1815int APIENTRY NdpFileEAQuery (HCONNECTION conn, NDFILEHANDLE handle, GEALIST *pGEAList, FEALIST *pFEAList)
1816{
1817 Connection *pConn = (Connection *)conn;
1818 Resource *pRes = pConn->pRes;
1819 int rc = 0;
1820 unsigned long action;
1821 const int cbBuffer = 64*1024;
1822 FEALIST * pFEASrc;
1823
1824 if (!pFEAList)
1825 return ERROR_EAS_NOT_SUPPORTED;
1826 if (!pRes->easupport)
1827 return ERROR_EAS_NOT_SUPPORTED;
1828
1829 debuglocal(pRes, 9, "NdpFileEAQuery in [%p] <%s>/%d pGEAList=%08x\n", pConn, pConn->file.fname, pConn->file.fd, pGEAList);
1830
1831 char *pchBuffer = (char *)malloc(cbBuffer);
1832 if (!pchBuffer)
1833 return ERROR_NOT_ENOUGH_MEMORY;
1834
1835 ENTER();
1836
1837 do {
1838 if (pConn->file.fd < 0)
1839 {
1840 rc = ERROR_INVALID_HANDLE;
1841 break;
1842 }
1843 rc = smbwrp_flistea(pRes, pConn->cli, &pConn->file, pchBuffer, cbBuffer);
1844 pFEASrc = (FEALIST *)pchBuffer;
1845 if (rc)
1846 {
1847 switch (rc)
1848 {
1849 case ERROR_FILE_NOT_FOUND :
1850 case ERROR_PATH_NOT_FOUND :
1851 pFEAList->cbList = sizeof(pFEAList->cbList);
1852 rc = NO_ERROR;
1853 break;
1854 case ERROR_BUFFER_OVERFLOW :
1855 pFEAList->cbList = pFEASrc->cbList;
1856 break;
1857 default :
1858 rc = ERROR_EAS_NOT_SUPPORTED;
1859 }
1860 }
1861 else
1862 rc = buildFEALIST(pRes, pFEASrc, pGEAList, pFEAList);
1863
1864 } while (0);
1865
1866 free(pchBuffer);
1867 debuglocal(pRes, 9, "NdpFileEAQuery out <%s>/%d pFEASrc->cbList=%d pFEAList->cbList=%d rc=%d\n", pConn->file.fname, pConn->file.fd, pFEASrc->cbList, pFEAList->cbList, rc);
1868
1869 LEAVE();
1870 return rc;
1871}
1872
1873int APIENTRY NdpFileEASet (HCONNECTION conn, NDFILEHANDLE handle, FEALIST *pFEAList)
1874{
1875 Connection *pConn = (Connection *)conn;
1876 Resource *pRes = pConn->pRes;
1877 int rc = 0;
1878 unsigned long action;
1879
1880 debuglocal(pRes, 9, "NdpFileEASet in [%p]\n", pConn);
1881
1882 if (!pFEAList || pFEAList->cbList <= sizeof(long))
1883 return ERROR_EAS_NOT_SUPPORTED;
1884
1885 if (!pRes->easupport)
1886 return ERROR_EAS_NOT_SUPPORTED;
1887
1888 ENTER();
1889
1890 do {
1891 // got FEA there
1892 FEA * pfea;
1893 unsigned long done = sizeof(long);
1894 if (pConn->file.fd < 0)
1895 {
1896 rc = ERROR_INVALID_HANDLE;
1897 break;
1898 }
1899
1900 pfea = pFEAList->list;
1901 while (done < pFEAList->cbList)
1902 {
1903 rc = smbwrp_fsetea(pRes, pConn->cli, &pConn->file, (char *)(pfea + 1), pfea->cbValue ? (char *)(pfea + 1) + pfea->cbName + 1: NULL, pfea->cbValue);
1904 if (rc)
1905 break;
1906
1907 pfea = (FEA *)((char *)(pfea + 1) + pfea->cbName + 1 + pfea->cbValue);
1908 done += sizeof(FEA) + pfea->cbName + 1 + pfea->cbValue;
1909 }
1910
1911 } while (0);
1912
1913 debuglocal(pRes, 9, "NdpFileEASet %d\n", rc);
1914
1915 LEAVE();
1916 return rc;
1917}
1918
1919int APIENTRY NdpFileEASize (HCONNECTION conn, NDFILEHANDLE handle, ULONG *pulEASize)
1920{
1921 Connection *pConn = (Connection *)conn;
1922 Resource *pRes = pConn->pRes;
1923 int rc = 0;
1924 unsigned long action;
1925 char path[CCHMAXPATH+1] = {0};
1926 FEALIST * pFEAList;
1927 const int cbBuffer = 64*1024;
1928
1929 if (!pulEASize)
1930 return ERROR_EAS_NOT_SUPPORTED;
1931
1932 if (!pRes->easupport)
1933 return ERROR_EAS_NOT_SUPPORTED;
1934
1935 debuglocal(pRes, 9, "NdpFileEASize in [%p] <%s>/%d \n", pConn, pConn->file.fname, pConn->file.fd);
1936
1937 char *pchBuffer = (char *)malloc(cbBuffer);
1938 if (!pchBuffer)
1939 return ERROR_NOT_ENOUGH_MEMORY;
1940
1941 ENTER();
1942
1943 do {
1944 if (pConn->file.fd < 0)
1945 {
1946 rc = ERROR_INVALID_HANDLE;
1947 break;
1948 }
1949 rc = smbwrp_flistea(pRes, pConn->cli, &pConn->file, pchBuffer, cbBuffer);
1950 pFEAList = (FEALIST*)pchBuffer;
1951 if (rc)
1952 {
1953 switch (rc)
1954 {
1955 case ERROR_FILE_NOT_FOUND :
1956 case ERROR_PATH_NOT_FOUND :
1957 pFEAList->cbList = sizeof(pFEAList->cbList);// Fall through */
1958 case ERROR_BUFFER_OVERFLOW :
1959 rc = NO_ERROR;
1960 break;
1961 default :
1962 rc = ERROR_EAS_NOT_SUPPORTED;
1963 }
1964 }
1965 *pulEASize = pFEAList->cbList;
1966 } while (0);
1967
1968 free(pchBuffer);
1969 debuglocal(pRes, 9, "NdpFileEASize %d %d\n", *pulEASize, rc);
1970
1971 LEAVE();
1972 return rc;
1973}
1974
1975int APIENTRY NdpFileSetInfo (HCONNECTION conn, NDFILEHANDLE handle, NDFILEINFOL *pfi)
1976{
1977 Connection *pConn = (Connection *)conn;
1978 Resource *pRes = pConn->pRes;
1979 int rc = 0;
1980 unsigned long action, attrFile;
1981
1982 ENTER();
1983
1984 debuglocal(pRes, 9, "NdpFileSetInfo in [%p]\n", pConn);
1985
1986 // delete the dir cache
1987 dircache_invalidate(pConn->file.fullname, pRes, 1);
1988
1989 do {
1990 if (pConn->file.fd < 0 || !*pConn->file.fname)
1991 {
1992 rc = ERROR_INVALID_HANDLE;
1993 break;
1994 }
1995 attrFile = pfi->stat.attrFile;
1996 // deferred setinfo - on closing the file
1997 pConn->file.openattr = attrFile;
1998 fsphDosDateToUnixTime(pRes, pfi->stat.fdateLastWrite, pfi->stat.ftimeLastWrite, &(pConn->file.mtime));
1999 fsphDosDateToUnixTime(pRes, pfi->stat.fdateCreation, pfi->stat.ftimeCreation, &(pConn->file.ctime));
2000 pConn->file.updatetime = 2;
2001 debuglocal(pRes, 9, "NdpFileSetInfo mtime %d\n", pConn->file.mtime);
2002 } while (0);
2003
2004 debuglocal(pRes, 9, "NdpFileSetInfo <%s> %08x %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, attrFile, rc);
2005
2006 LEAVE();
2007 return NO_ERROR;
2008}
2009
2010int APIENTRY NdpFileSetFilePtrL(HCONNECTION conn, NDFILEHANDLE handle, LONGLONG llOffset, ULONG ulMethod, LONGLONG *pllActual)
2011{
2012 Connection *pConn = (Connection *)conn;
2013 Resource *pRes = pConn->pRes;
2014 int rc = 0;
2015 unsigned long action;
2016
2017 ENTER();
2018
2019 debuglocal(pRes, 9, "NdpFileSetFilePtrL in [%p]\n", pConn);
2020
2021 do {
2022 if (pConn->file.fd < 0)
2023 {
2024 rc = ERROR_INVALID_HANDLE;
2025 break;
2026 }
2027
2028 rc = smbwrp_lseek(pRes, pConn->cli, &pConn->file, ulMethod, llOffset);
2029 if (!rc)
2030 *pllActual = pConn->file.offset;
2031
2032 } while (0);
2033
2034 debuglocal(pRes, 9, "NdpFileSetFilePtrL <%s> %lld %lu %lld %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, llOffset, ulMethod, *pllActual, rc);
2035
2036 LEAVE();
2037 return rc;
2038}
2039
2040int APIENTRY NdpFileSetFilePtr (HCONNECTION conn, NDFILEHANDLE handle, LONG lOffset, ULONG ulMethod, ULONG *pulActual)
2041{
2042 Connection *pConn = (Connection *)conn;
2043 LONGLONG llActual;
2044 int rc = NdpFileSetFilePtrL(conn, handle, lOffset, ulMethod, &llActual);
2045 *pulActual = llActual & 0xFFFFFFFF;
2046 debuglocal(pConn->pRes, 9, "NdpFileSetFilePtr %ld %lu %ld %d\n", lOffset, ulMethod, *pulActual, rc);
2047 return rc;
2048}
2049
2050int APIENTRY NdpFileClose (HCONNECTION conn, NDFILEHANDLE handle)
2051{
2052 Connection *pConn = (Connection *)conn;
2053 Resource *pRes = pConn->pRes;
2054 int rc = 0;
2055 unsigned long action;
2056
2057 ENTER();
2058
2059 debuglocal(pRes, 9, "NdpFileClose in [%p] %d <%s>\n", pConn, pConn->file.fd, pConn->file.fd < 0 ? "!null!" : pConn->file.fname);
2060
2061 do {
2062 if (pConn->file.fd < 0)
2063 {
2064 rc = ERROR_INVALID_HANDLE;
2065 break;
2066 }
2067
2068 rc = smbwrp_close(pRes, pConn->cli, &pConn->file);
2069
2070 } while (0);
2071
2072 debuglocal(pRes, 9, "NdpFileClose %d %d\n", pConn->file.fd, rc);
2073 pConn->file.fd = -1;
2074
2075 LEAVE();
2076 return rc;
2077}
2078
2079int APIENTRY NdpFileCommit (HCONNECTION conn, NDFILEHANDLE handle)
2080{
2081 Connection *pConn = (Connection *)conn;
2082 debuglocal(pConn->pRes, 9, "NdpFileCommit %d\n", NO_ERROR);
2083 return NO_ERROR;
2084}
2085
2086int APIENTRY NdpFileNewSize (HCONNECTION conn, NDFILEHANDLE handle, ULONG ulLen)
2087{
2088 Connection *pConn = (Connection *)conn;
2089 int rc = NdpFileNewSizeL(conn, handle, ulLen);
2090 debuglocal(pConn->pRes, 9, "NdpFileNewSize %ld %d\n", ulLen, rc);
2091 return rc;
2092}
2093
2094int APIENTRY NdpFileNewSizeL(HCONNECTION conn, NDFILEHANDLE handle, LONGLONG llLen)
2095{
2096 Connection *pConn = (Connection *)conn;
2097 Resource *pRes = pConn->pRes;
2098 int rc = 0;
2099 unsigned long action;
2100
2101 ENTER();
2102
2103 debuglocal(pRes, 9, "NdpFileNewSizeL in [%p]\n", pConn);
2104
2105 do {
2106 if (pConn->file.fd < 0)
2107 {
2108 rc = ERROR_INVALID_HANDLE;
2109 break;
2110 }
2111
2112 rc = smbwrp_setfilesize(pRes, pConn->cli, &pConn->file, llLen);
2113
2114 } while (0);
2115
2116 debuglocal(pRes, 9, "NdpFileNewSizeL <%s> %lld %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, llLen, rc);
2117
2118 LEAVE();
2119 return rc;
2120}
2121
2122#define NDPSMB_READ_MAX_SIZE (65536 - 4096)
2123
2124int APIENTRY NdpFileRead (HCONNECTION conn, NDFILEHANDLE handle, void *pBuffer, ULONG ulRead, ULONG *pulActual)
2125{
2126 Connection *pConn = (Connection *)conn;
2127 Resource *pRes = pConn->pRes;
2128 int rc = 0;
2129 unsigned long done = 0;
2130 unsigned long onedone;
2131 unsigned long action;
2132 ULONG ulReadCompleted = 0;
2133
2134 ENTER();
2135
2136 debuglocal(pRes, 9, "NdpFileRead in [%p]\n", pConn);
2137
2138 do {
2139 if (pConn->file.fd < 0)
2140 {
2141 rc = ERROR_INVALID_HANDLE;
2142 break;
2143 }
2144
2145 while (ulReadCompleted < ulRead)
2146 {
2147 ULONG ulActual;
2148 ULONG ulToRead = ulRead - ulReadCompleted;
2149 debuglocal(pRes, 9, "NdpFileRead completed %d, to read %d\n", ulReadCompleted, ulToRead);
2150
2151 if (ulToRead > NDPSMB_READ_MAX_SIZE)
2152 ulToRead = NDPSMB_READ_MAX_SIZE;
2153
2154 rc = smbwrp_read(pRes, pConn->cli, &pConn->file, (char *)pBuffer + ulReadCompleted, ulToRead, &ulActual);
2155 if (ulActual == 0 || rc != NO_ERROR)
2156 break;
2157
2158 ulReadCompleted += ulActual;
2159 }
2160 } while (0);
2161
2162 if (ulReadCompleted > 0)
2163 rc = NO_ERROR; // Still were able to read some data.
2164
2165 if (rc == NO_ERROR)
2166 *pulActual = ulReadCompleted;
2167
2168 debuglocal(pRes, 9, "NdpFileRead <%s> %lu %lu %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, ulRead, *pulActual, rc);
2169
2170 LEAVE();
2171 return rc;
2172}
2173
2174int APIENTRY NdpFileWrite (HCONNECTION conn, NDFILEHANDLE handle, void *pBuffer, ULONG ulWrite, ULONG *pulActual)
2175{
2176 Connection *pConn = (Connection *)conn;
2177 Resource *pRes = pConn->pRes;
2178 int rc = 0;
2179 unsigned long done = 0;
2180 unsigned long onedone;
2181 unsigned long action;
2182
2183 ENTER();
2184
2185 debuglocal(pRes, 9, "NdpFileWrite in [%p]\n", pConn);
2186
2187 /*
2188 * delete the dir cache
2189 * This was moved from NdpFileClose() becasue if there are a lot files
2190 * in the tree, all are reread. The problem when moved to here is, that
2191 * the last accessed time is not refreshed. If this is needed,
2192 * a new function needs to be done to update only one file in the cache
2193 */
2194 dircache_invalidate(pConn->file.fullname, pRes, 1);
2195
2196 do {
2197 if (pConn->file.fd < 0)
2198 {
2199 rc = ERROR_INVALID_HANDLE;
2200 break;
2201 }
2202 rc = smbwrp_write(pRes, pConn->cli, &pConn->file, pBuffer, ulWrite, pulActual);
2203
2204 } while (0);
2205
2206 debuglocal(pRes, 9, "NdpFileWrite <%s> %lu %lu %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, ulWrite, *pulActual, rc);
2207
2208 LEAVE();
2209 return rc;
2210}
Note: See TracBrowser for help on using the repository browser.