source: trunk/client/src/ndpsmb.c

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

Get plugin helper table pointer at init time. ticket#274.

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