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

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

Use a better name for getfindinfoL() since its task changed. Remove
getfindinfo().

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