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

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

Store full path of connection in the resource data structure.
ticket#274.

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