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

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

Samba code changes for using new dircache API. ticket#274.

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