/* Netdrive Samba client plugin plugin API Copyright (C) netlabs.org 2003-2008 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #define NDPL_LARGEFILES #define INCL_LONGLONG #include #include "smbwrp.h" #include "util.h" #ifndef DEBUG_PRINTF #define debug_printf( ...) #endif #define log debug_printf #if 0 void log(const char *fmt, ...) { char *ndpsmb_debug = getenv("NDPSMB_DEBUG"); if (ndpsmb_debug != NULL) { FILE * logfile = NULL; va_list args; time_t t = time(NULL); char timebuf[80] = {0}; strftime(timebuf,sizeof(timebuf)-1,"%Y/%m/%d %H:%M:%S", localtime(&t)); logfile = fopen("smblog","a"); if (logfile == NULL) { DosBeep(400,400); } else { fprintf(logfile, "%s: (%02d) ", timebuf, _gettid()); va_start(args, fmt); vfprintf(logfile, fmt, args); va_end(args); fclose(logfile); } } } #endif // ------------------------------------------------------------- /* time conversion functions: SMB protocol sends timestamps in GMT time, * os2 api uses localtime, * emx/klibc uses timezone and daylight saving to convert GMT timestamps, * so only the timezone must be counted in conversion. */ void fsphUnixTimeToDosDate( time_t time, FDATE* fdate, FTIME *ftime) { struct tm* gmt = localtime( &time); if (gmt->tm_isdst>0) { debug_printf( "daylight saving in effect %d, timezone %d\n",gmt->tm_isdst, timezone); time -= 3600; gmt = localtime( &time); } fdate->day = gmt->tm_mday; fdate->month = gmt->tm_mon+1; fdate->year = gmt->tm_year + 1900 - 1980; ftime->twosecs = gmt->tm_sec/2; ftime->minutes = gmt->tm_min; ftime->hours = gmt->tm_hour; } void fsphDosDateToUnixTime( FDATE fdate, FTIME ftime, unsigned long* time) { struct tm gmtime = { 0 }; struct tm* gmt; debug_printf( "fsphDosDateToUnixTime time %02d:%02d\n", ftime.hours, ftime.minutes); gmtime.tm_mday = fdate.day; gmtime.tm_mon = fdate.month-1; gmtime.tm_year = fdate.year + 1980 - 1900; gmtime.tm_sec = ftime.twosecs*2; gmtime.tm_min = ftime.minutes; gmtime.tm_hour = ftime.hours; gmtime.tm_isdst = -1; // force libc to check dst saving *time = mktime( &gmtime); debug_printf( "fsphDosDateToUnixTime time1 %d %s", *time, ctime( time)); gmt = localtime( (time_t*) time); if (gmt->tm_isdst>0) { debug_printf( "fsphDosDateToUnixTime daylight saving in effect %d, timezone %d\n",gmt->tm_isdst, timezone); *time += 3600; } debug_printf( "fsphDosDateToUnixTime time2 %d %s", *time, ctime( time)); } // ------------------------------------------------------------- int StrLen(char * s) { char * p; if (!s) { return 0; } for (p = s; *p; p++); return (p - s); } char * StrNCat(char *dst, const char *src, int count) { int i; if (!dst || !src || count <= 0) { return dst; } for (i = 0; dst[i]; i++); for (;i < count && *src; i++, src++) { dst[i] = *src; } dst[i] = 0; return dst; } char * StrNCpy(char *dst, const char *src, int count) { if (!dst || !src || count <= 0) { return dst; } *dst = 0; return StrNCat(dst, src, count); } char * StrCpy(char *dst, const char *src) { char * p; if (!dst || !src) { return dst; } p = dst; while (*p++ = *src++); return dst; } char * StrCat(char *dst, const char *src) { int i; if (!dst || !src) { return dst; } for (i = 0; dst[i]; i++); for (; *src; i++, src++) { dst[i] = *src; } dst[i] = 0; return dst; } void * MemCpy(void * dst, const void * src, int len) { int i; if (!src || !dst || len <= 0) { return dst; } for (i = 0; i < len; i++) { ((char *)dst)[i] = ((char *)src)[i]; } return dst; } void *MemSet(void *dst, char c, int len) { int i; if (!dst || len <= 0) { return dst; } for (i = 0; i < len; i++) { ((char *)dst)[i] = c; } return dst; } // ------------------------------------------------------------- /* uppercased type of resource */ const char *NdpTypes[] = { "SMBFS", NULL } ; /* Properties of supported resource types */ /* Properties of resource */ static const NDPROPERTYINFO smbProperties[] = { {ND_PROP_STRING, 0, "WORKGROUP", ""}, {ND_PROP_STRING, 0, "SERVER", ""}, {ND_PROP_STRING, 0, "SHARE", ""}, {ND_PROP_STRING, 0, "USER", "guest"}, {ND_PROP_STRING, 0, "PASSWORD", ""}, {ND_PROP_STRING, 0, "SPASSWORD", ""}, {ND_PROP_STRING, 0, "MASTER", "WORKGROUP"}, { ND_PROP_ULONG, 0, "MASTERTYPE", "1"}, { ND_PROP_ULONG, 0, "MEMLEN", "2"}, {ND_PROP_STRING, 0, "LOGFILE", ""}, { ND_PROP_ULONG, 0, "LOGLEVEL", "0"}, { ND_PROP_ULONG, 0, "EASUPPORT", "1"}, {ND_PROP_STRING, 0, NULL, NULL} }; /* Exported array of properties */ const NDPROPERTYINFO *NdpPropertiesInfo[] = { smbProperties }; static PLUGINHELPERTABLE2L *ph; static int ifL; int APIENTRY NdpPluginLoad (PLUGINHELPERTABLE2L *pPHT) { int rc; HPIPE pipe; unsigned long action; ph = pPHT; ifL = 0; /* if (ph->cb < sizeof (PLUGINHELPERTABLE2)) { return ERROR_INVALID_FUNCTION; } */ if (ph->cb >= sizeof (PLUGINHELPERTABLE2L)) { ifL = 1; } log("Working with %s bit fileio NDFS\n", ifL ? "64" : "32"); return NO_ERROR; } int APIENTRY NdpPluginFree (void) { return NO_ERROR; } void getfindinfo(Connection * pConn, FILEFINDBUF3 * stat, smbwrp_fileinfo * finfo) { char * name = ph->fsphStrRChr(finfo->fname, '\\'); if (name) { name++; } else { name = finfo->fname; } if (!*name) { name = pConn->pRes->srv.share_name; } StrNCpy(stat->achName, name, CCHMAXPATHCOMP - 1); stat->cbFile = finfo->size; stat->cbFileAlloc = stat->cbFile; stat->oNextEntryOffset = 0ul; stat->cchName = StrLen(stat->achName); stat->attrFile = (finfo->attr & 0x37); fsphUnixTimeToDosDate(finfo->mtime, &stat->fdateLastWrite, &stat->ftimeLastWrite); fsphUnixTimeToDosDate(finfo->ctime, &stat->fdateCreation, &stat->ftimeCreation); fsphUnixTimeToDosDate(finfo->atime, &stat->fdateLastAccess, &stat->ftimeLastAccess); } int getfindinfoL(Connection * pConn, void * plist, smbwrp_fileinfo * finfo, ULONG ulAttribute, char * mask) { FILESTATUS3L stat = {0}; char * name = ph->fsphStrRChr(finfo->fname, '\\'); if (name) { name++; } else { name = finfo->fname; } if (!*name) { name = pConn->pRes->srv.share_name; } if (mask && (!ph->fsphAttrMatch(ulAttribute, finfo->attr & 0x37) || !ph->fsphWildMatch(mask, name, ND_IGNORE_CASE))) { return 0; } stat.cbFile = finfo->size; stat.cbFileAlloc = stat.cbFile; stat.attrFile = (finfo->attr & 0x37); fsphUnixTimeToDosDate(finfo->mtime, &stat.fdateLastWrite, &stat.ftimeLastWrite); fsphUnixTimeToDosDate(finfo->ctime, &stat.fdateCreation, &stat.ftimeCreation); fsphUnixTimeToDosDate(finfo->atime, &stat.fdateLastAccess, &stat.ftimeLastAccess); debug_printf( "fname %s\n", finfo->fname); debug_printf( "mtime %d %s", finfo->mtime, ctime( &finfo->mtime)); debug_printf( "ftimeLastAccess %02d:%02d:%02d\n", stat.ftimeLastWrite.hours, stat.ftimeLastWrite.minutes, stat.ftimeLastWrite.twosecs*2); ph->fsphAddFile32L(plist, &stat, name, StrLen(name), finfo, sizeof(*finfo), 0); return 1; } static unsigned char fromhex (char c) { if ('0' <= c && c <= '9') { return c - '0'; } if ('A' <= c && c <= 'F') { return c - 'A' + 0xA; } if ('a' <= c && c <= 'f') { return c - 'a' + 0xA; } return 0; } static char tohex (unsigned char b) { b &= 0xF; if (b <= 9) { return b + '0'; } return 'A' + (b - 0xA); } static void decryptPassword (const char *pszCrypt, char *pszPlain) { /* A simple "decryption", character from the hex value. */ const char *s = pszCrypt; char *d = pszPlain; while (*s) { *d++ = (char)((fromhex (*s++) << 4) + fromhex (*s++)); } *d++ = 0; } static void encryptPassword (const char *pszPlain, char *pszCrypt) { /* A simple "encryption" encode each character as hex value. */ const char *s = pszPlain; char *d = pszCrypt; while (*s) { *d++ = tohex ((*s) >> 4); *d++ = tohex (*s); s++; } *d++ = 0; } /* accept parameters in form * [filename][;name=filename] */ int initResource (Resource *pRes, NDPROPERTYHANDLE properties) { int rc = NO_ERROR; unsigned long t; const unsigned char * q = NULL; int defaultPassword = 1; pRes->rootlevel = 0; *pRes->logfile = 0; pRes->loglevel = 0; pRes->easupport = 1; #ifdef HAVE_KRB5_H pRes->krb5support = 1; #else pRes->krb5support = 0; #endif t = 0, q = NULL; rc = ph->fsphQueryStringProperty (properties, "WORKGROUP", &q, &t); if (!rc && t && *q) { StrNCpy(pRes->srv.workgroup, q, sizeof(pRes->srv.workgroup) - 1); pRes->rootlevel = 1; } t = 0, q = NULL; rc = ph->fsphQueryStringProperty (properties, "SERVER", &q, &t); if (!rc && t && *q) { StrNCpy(pRes->srv.server_name, q, sizeof(pRes->srv.server_name) - 1); pRes->rootlevel = 2; } t = 0, q = NULL; rc = ph->fsphQueryStringProperty (properties, "SHARE", &q, &t); if (!rc && t && *q) { StrNCpy(pRes->srv.share_name, q, sizeof(pRes->srv.share_name) - 1); pRes->rootlevel = 3; } t = 0, q = NULL; rc = ph->fsphQueryStringProperty (properties, "USER", &q, &t); if (!rc && t && *q) { StrNCpy(pRes->srv.username, q, sizeof(pRes->srv.username) - 1); } t = 0, q = NULL; rc = ph->fsphQueryStringProperty (properties, "PASSWORD", &q, &t); if (!rc && t && *q) { StrNCpy(pRes->srv.password, q, sizeof(pRes->srv.password) - 1); defaultPassword = 0; } t = 0, q = NULL; rc = ph->fsphQueryStringProperty (properties, "SPASSWORD", &q, &t); if ( rc == NO_ERROR && *q != '\0' && defaultPassword) { char p[1024]; p[0] = 0; decryptPassword (q, p); if (*p) { StrNCpy(pRes->srv.password, p, sizeof(pRes->srv.password) - 1); /* clear the plain password */ ph->fsphSetProperty (properties, "PASSWORD", ""); } } else { char c[1024]; encryptPassword (pRes->srv.password, c); ph->fsphSetProperty (properties, "SPASSWORD", c); // clear the plain password ph->fsphSetProperty (properties, "PASSWORD", ""); } t = 0, q = NULL; rc = ph->fsphQueryStringProperty (properties, "MASTER", &q, &t); if (!rc && t && *q) { StrNCpy(pRes->srv.master, q, sizeof(pRes->srv.master) - 1); } t = 0, q = NULL; rc = ph->fsphQueryStringProperty (properties, "LOGFILE", &q, &t); if (!rc && t && *q) { StrNCpy(pRes->logfile, q, sizeof(pRes->logfile) - 1); } t = 0; rc = ph->fsphQueryUlongProperty (properties, "LOGLEVEL", &t); if (!rc) { if (t > 9) { t = 9; rc = ERROR_INVALID_PARAMETER; } pRes->loglevel = t; } t = 0; rc = ph->fsphQueryUlongProperty (properties, "MASTERTYPE", &t); if (!rc) { if (t > 1) { rc = ERROR_INVALID_PARAMETER; } else { pRes->srv.ifmastergroup = t; } } t = 0; rc = ph->fsphQueryUlongProperty (properties, "EASUPPORT", &t); if (!rc) { if (t > 1) { rc = ERROR_INVALID_PARAMETER; } else { pRes->easupport = t; } } #if 0 t = 0; rc = ph->fsphQueryUlongProperty (properties, "MEMLEN", &t); if (!rc) { if (t <= (pRes->easupport ? 1 : 0) || t > 10) { rc = ERROR_INVALID_PARAMETER; } else { pRes->memlen = t * 65536; } } #endif return rc; } int iftestpath(char * path) { char * p = path; if (!path) { return 0; } while ((p = ph->fsphStrChr(p, 'A')) != NULL) { if (ph->fsphStrNCmp(p, "A.+,;=[].B", 10) == 0) { return 1; } p++; } return 0; } int pathparser(Resource *pRes, Connection * pConn, char * path, char * result) { int rootlevel; int rc = NO_ERROR; if (!pRes || !path || !result) { return ERROR_INVALID_PARAMETER; } // handle special case when someone wants to test support of LFN or smth similar if (iftestpath(path)) { StrCpy(result, "\\A.+,;=[].B"); return NO_ERROR; } rootlevel = pRes->rootlevel; if (*path == '\\') path++; if (rootlevel < 3) { char * p; // flag: 1 parameters changed, reconnection required, 0 do nothing int newlevel = 0; // use a temporary resource to test disconnection/reconnection Resource tmpRes; // copy exising data memcpy( &tmpRes, pRes, sizeof( tmpRes)); // pointer to new connection fields smbwrp_server * tmp = &tmpRes.srv; if (rootlevel == 0) { p = ph->fsphStrChr(path, '\\'); if (!p) { p = path + StrLen(path); } if (StrLen(tmp->workgroup) != p - path || (p == path || ph->fsphStrNICmp(path, tmp->workgroup, p - path))) { StrNCpy(tmp->workgroup, path, p - path); tmp->workgroup[p - path] = 0; newlevel = 1; } path = *p == '\\' ? p + 1 : p; rootlevel = 1; } if (rootlevel == 1) // root path starts from server name { p = ph->fsphStrChr(path, '\\'); if (!p) { p = path + StrLen(path); } if (StrLen(tmp->server_name) != p - path || (p == path || ph->fsphStrNICmp(path, tmp->server_name, p - path))) { StrNCpy(tmp->server_name, path, p - path); tmp->server_name[p - path] = 0; newlevel = 1; } path = *p == '\\' ? p + 1 : p; rootlevel = 2; } if (rootlevel == 2) // root path starts from share name { p = ph->fsphStrChr(path, '\\'); if (!p) { p = path + StrLen(path); } if (StrLen(tmp->share_name) != (p - path) || (p == path || ph->fsphStrNICmp(path, tmp->share_name, p - path))) { StrNCpy(tmp->share_name, path, p - path); tmp->share_name[p - path] = 0; newlevel = 1; } path = *p == '\\' ? p + 1 : p; } if (newlevel) { // reconnect to server here, first test new connection cli_state* tmp_cli = NULL; rc = smbwrp_connect( &tmpRes, &tmp_cli); if (!rc) { // new connection is ok, disconnect old one cli_state* cli = pConn->cli; smbwrp_disconnect( pRes, cli); // save tmp data structure memcpy( pRes, &tmpRes, sizeof( tmpRes)); // save new connection handle pConn->cli = tmp_cli; } } } StrCpy(result, "\\"); StrNCat(result, path, CCHMAXPATH); return rc; } // ------------------------------------------------------------- /* check if the requested resource is available */ static int checkMountResource( Resource* pRes) { int rc; unsigned long action; cli_state* cli = NULL; smbwrp_file file; debug_printf("checkMountResource in tid#%d\n", _gettid()); rc = smbwrp_connect( pRes, &cli); /* changed to real error codes SCS if (rc) rc = (rc == 7 ? ERROR_BAD_DEV_TYPE : ERROR_ACCESS_DENIED); */ switch (rc) { case 0: rc = NO_ERROR; break; case 1: case 10: case 11: rc = ERROR_BAD_NET_NAME; break; case 2: rc = ERROR_INIT_ROUTINE_FAILED; break; case 3: rc = ERROR_BAD_NET_RESP; break; case 4: rc = ERROR_NETWORK_BUSY; break; case 6: rc = ERROR_NETWORK_ACCESS_DENIED; break; case 7: rc = ERROR_BAD_NETPATH; break; default: rc = ERROR_UNEXP_NET_ERR; break; } /* endswitch */ smbwrp_disconnect( pRes, cli); return rc; } int APIENTRY NdpMountResource (HRESOURCE *presource, int type, NDPROPERTYHANDLE properties) { int rc = NO_ERROR; unsigned long objany = OBJ_ANY; Resource *pRes = NULL; log("NdpMountResource in\n"); // init code smbwrp_init(); /* since samba plugin support only 1 type of resources we do not need */ /* to check what the found type really is */ pRes = malloc( sizeof(Resource)); if (pRes == NULL) { rc = ERROR_NOT_ENOUGH_MEMORY; } else { MemSet(pRes, 0, sizeof(Resource)); //pRes->objany = objany; // parse init string rc = initResource (pRes, properties); // try to connect to resource (check type) only if thread!=1, so ndctl startup // is not slowed down by network connections. // ndctl does mounting on main thread (#1) // nd/ndpm do not use main thread if (!rc && _gettid()!=1) rc = checkMountResource( pRes); if (!rc) { // store resource data *presource = (HRESOURCE)pRes; } else { free(pRes); } } log("NdpMountResource rc=%d\n", rc); return rc; } // ------------------------------------------------------------- int APIENTRY NdpFreeResource (HRESOURCE resource) { Resource *pRes = (Resource *)resource; MemSet(&pRes->srv, 0, sizeof(pRes->srv)); free(pRes); log("NdpFreeResource %d\n", NO_ERROR); return NO_ERROR; } // ------------------------------------------------------------- int APIENTRY NdpRsrcCompare (HRESOURCE resource, HRESOURCE resource2) { Resource *pRes = (Resource *)resource; Resource *pRes2 = (Resource *)resource2; int rc = ND_RSRC_DIFFERENT; log("NdpRsrcCompare in\n"); if (ph->fsphStrICmp(pRes->srv.server_name, pRes2->srv.server_name) == 0 && ph->fsphStrICmp(pRes->srv.share_name, pRes2->srv.share_name) == 0 && ph->fsphStrICmp(pRes->srv.username, pRes2->srv.username) == 0 && ph->fsphStrICmp(pRes->srv.workgroup, pRes2->srv.workgroup) == 0) { // resources are equal rc = ND_RSRC_EQUAL; } log("NdpRsrcCompare %d\n", rc); return rc; } int APIENTRY NdpRsrcUpdate (HRESOURCE resource, HRESOURCE resource2) { // do nothing log("NdpRsrcUpdate %d\n", NO_ERROR); return NO_ERROR; } int APIENTRY NdpRsrcQueryInfo (HRESOURCE resource, ULONG *pulFlags, void *pdata, ULONG insize, ULONG *poutlen) { Resource *pRes = (Resource *)resource; int rc = NO_ERROR; char s[4096]; log("NdpRsrcQueryInfo in\n"); switch (pRes->rootlevel) { case 0: { ph->fsph_snprintf(s, sizeof(s) - 1, "SMBFS%s \\\\@%s", ifL ? "64" : "32", pRes->srv.username); } break; case 1: { ph->fsph_snprintf(s, sizeof(s) - 1, "SMBFS%s %s: \\\\@%s", ifL ? "64" : "32", pRes->srv.workgroup, pRes->srv.username); } break; case 2: { 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); } break; default: { 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); } break; } *poutlen = StrLen(s) + 1; if (*poutlen > insize) { rc = ERROR_BUFFER_OVERFLOW; } else { MemCpy(pdata, s, *poutlen); } log("NdpRsrcQueryInfo %d\n", rc); return rc; } int APIENTRY NdpRsrcQueryFSAttach (HRESOURCE resource, void *pdata, ULONG insize, ULONG *poutlen) { ULONG ulDummy = 0; /* just return the resource info string */ return NdpRsrcQueryInfo (resource, &ulDummy, pdata, insize, poutlen); } int APIENTRY NdpRsrcQueryFSAllocate (HRESOURCE resource, NDFSALLOCATE *pfsa) { Resource *pRes = (Resource *)resource; int rc = NO_ERROR, rc1; unsigned long action = 0; smbwrp_file file; cli_state* cli = NULL; FSALLOCATE fsa; log("NdpRsrcQueryFSAllocate %08x\n", pfsa); if (!pfsa) { return NO_ERROR; } debug_printf("checkMountResource in tid#%d\n", _gettid()); rc = smbwrp_connect( pRes, &cli); if (rc) { log("NdpCreateConnection failed rc=%d\n", rc); pfsa->cSectorUnit = 1; pfsa->cUnit = 123456; pfsa->cUnitAvail = 123456; pfsa->cbSector = 2048; rc = (rc == 7 ? ERROR_BAD_DEV_TYPE : ERROR_ACCESS_DENIED); return rc; } rc = smbwrp_dskattr( cli, &fsa); if (rc) { pfsa->cSectorUnit = 1; pfsa->cUnit = 123456; pfsa->cUnitAvail = 123456; pfsa->cbSector = 2048; //rc = rc ? rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } else { pfsa->cSectorUnit = fsa.cSectorUnit; pfsa->cUnit = fsa.cUnit; pfsa->cUnitAvail = fsa.cUnitAvail; pfsa->cbSector = fsa.cbSector; } smbwrp_disconnect( pRes, cli); log("NdpRsrcQueryFSAllocate %d/%d (cUnit = %d/cUnitAvail = %d/cbSector = %d)\n", rc, rc1, pfsa->cUnit, pfsa->cUnitAvail, pfsa->cbSector); return rc; } // ------------------------------------------------------------- int APIENTRY NdpCreateConnection (HRESOURCE resource, HCONNECTION *pconn) { int rc = 0; Resource * pRes = (Resource *)resource; unsigned long action; Connection *pConn = NULL; log("NdpCreateConnection in\n"); pConn = malloc( sizeof(Connection)); if (pConn == NULL) { rc = ERROR_NOT_ENOUGH_MEMORY; } if (rc) { log("NdpCreateConnection ERROR_NOT_ENOUGH_MEMORY %d\n", rc); return rc; } MemSet(pConn, 0, sizeof(Connection)); pConn->pRes = pRes; pConn->file.fd = -1; log("NdpCreateConnection send CONNECT\n"); rc = smbwrp_connect( pRes, &pConn->cli); if (rc) { free(pConn); pConn = NULL; rc = (rc == 7 ? ERROR_BAD_DEV_TYPE : ERROR_INVALID_PARAMETER); } *pconn = (HCONNECTION)pConn; log("NdpCreateConnection %d\n", rc); return rc; } // ------------------------------------------------------------- int APIENTRY NdpFreeConnection (HCONNECTION conn) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc; log("NdpFreeConnection in\n"); if (pConn->file.fd >= 0) { rc = smbwrp_close( pConn->cli, &pConn->file); pConn->file.fd = -1; } smbwrp_disconnect( pRes, pConn->cli); free(pConn); log("NdpFreeConnection %d\n", NO_ERROR); return NO_ERROR; } // ------------------------------------------------------------- /* * NdpQueryPathInfo is the most important function :) netdrive always calls * the function before every operation to find out the path status: does it exist, is it a file, does a * parent directory exist, etc. * Plugin must return one of the following error codes: * NO_ERROR - path exists and the path information have been successfully retrieved. * ERROR_FILE_NOT_FOUND - all but the last component of the path exist and the * path without the last component is a directory. dir1_ok\dir2_ok\does_not_exist. * the wildcard can not exist, so the plugin returns FILE_NOT_FOUND, if the parent * directory exist. * ERROR_PATH_NOT_FOUND - any of not last path components does not exist, or all * but the last component exist and is a file: \dir_ok\dir2_ok\file_ok\non_existing. * ERROR_REM_NOT_LIST - resource is temporarily unavailable for some reasons. * Any other error codes means an internal plugin error, not related to the status * of the path queried. */ int APIENTRY NdpQueryPathInfo (HCONNECTION conn, void *plist, char *szPath) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; smbwrp_fileinfo finfo; int rc = 0; unsigned long action; char path[CCHMAXPATH+1] = {0}; int retry = 0; log("NdpQueryPathInfo in <%s>, retry = %d\n", szPath, retry); // is wildcard is specified, we suppose parent dir exist, so exit immediately if (ph->fsphStrChr(szPath, '*') || ph->fsphStrChr(szPath, '?')) { return ERROR_FILE_NOT_FOUND; } do { rc = pathparser(pRes, pConn, szPath, path); log("NdpQueryPathInfo pathparser for <%s> rc=%d\n", path, rc); switch (rc) { case NO_ERROR : case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: case ERROR_ACCESS_DENIED: case ERROR_INVALID_PARAMETER: { break; } default : { rc = ERROR_PATH_NOT_FOUND; } } if (rc) { break; } StrNCpy(finfo.fname, path, sizeof(finfo.fname) - 1); log("NdpQueryPathInfo smbwrp_getattr for <%s>\n", path); rc = smbwrp_getattr( &pRes->srv, pConn->cli, &finfo); if (rc) { // remote server not available for first time? if (rc == ERROR_REM_NOT_LIST && retry == 0) { // free current cli resources smbwrp_disconnect( pRes, pConn->cli); // reconnect smbwrp_connect( pRes, &pConn->cli); // try file list again rc = smbwrp_getattr( &pRes->srv, pConn->cli, &finfo); log("NdpQueryPathInfo remote connection lost, retry rc = %d\n", rc); } switch (rc) { case NO_ERROR : case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: case ERROR_ACCESS_DENIED: case ERROR_INVALID_PARAMETER: case ERROR_REM_NOT_LIST: break; default : { rc = ERROR_PATH_NOT_FOUND; } } } else { finfo.easize = -1; getfindinfoL(pConn, plist, &finfo, 0, NULL); } if (rc == ERROR_FILE_NOT_FOUND) { // now try the upper path char * p = ph->fsphStrChr(finfo.fname, '\\'); if (p && p > finfo.fname) { *p = 0; rc = smbwrp_getattr( &pRes->srv, pConn->cli, &finfo); if (rc) { log("NdpQueryPathInfo upper path in <%s>, retry = %d\n", finfo.fname, retry); rc = rc ? ERROR_PATH_NOT_FOUND : ERROR_INVALID_PARAMETER; } } } } while (0); log("NdpQueryPathInfo <%s> (%s) %d\n", szPath, path, rc); return rc; } // ------------------------------------------------------------- int APIENTRY NdpFindStart (HCONNECTION conn, void *plist, NDFILEINFOL *pfiparent, char *szPath, ULONG ulAttribute) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = NO_ERROR, count = 0; unsigned long action; char *mask = "*"; char dir[CCHMAXPATH+1] = {0}; char path[CCHMAXPATH+1] = {0}; smbwrp_fileinfo * data; NDPATHELEMENT *pel = ph->fsphNameElem(0); filelist_state state; char * p; debug_printf("NdpFindStart in\n"); StrNCpy(dir, szPath, sizeof(dir) - 1); if (pel) { mask = pel->name; dir[StrLen(szPath) - pel->length] = 0; } action = StrLen(dir) - 1; if (dir[action] == '\\') { dir[action] = 0; } rc = pathparser(pRes, pConn, dir, path); if (rc) { return rc; } action = StrLen(path) - 1; if (path[action] != '\\') { StrNCat(path, "\\", sizeof(path) - 1); } StrCpy(dir, path); StrNCat(path, mask, sizeof(path) - 1); // this structure will be used by libsmb callbacks, so we store here all we need // to fill netdrive structures state.pConn = pConn; state.plist = plist; state.ulAttribute = ulAttribute; strcpy( state.dir, dir); strcpy( state.dir_mask, mask); strcpy( state.mask, path); p = getlastslash(state.mask); if (p) { *(p + 1) = '*'; *(p + 2) = 0; } else { strcpy(state.mask, "\\*"); } rc = smbwrp_filelist( &pRes->srv, pConn->cli, &state); // we need to handle reconnection also here, because NdpQueryPathInfo // could be called with '*' and exit then immediately (without calling libsmb) if (rc == ERROR_REM_NOT_LIST) { // free current cli resources smbwrp_disconnect( pRes, pConn->cli); // reconnect smbwrp_connect( pRes, &pConn->cli); // try file list again next loop rc = smbwrp_filelist( &pRes->srv, pConn->cli, &state); log("NdpFindStart remote connection lost, retry rc = %d\n", rc); } log("NdpFindStart <%s> (%s) cnt %d %d\n", szPath, path, count, rc); return rc; } int APIENTRY NdpDeletePathInfo (HRESOURCE resource, NDFILEINFOL *pfi) { // log("NdpDeletePathInfo %d\n", 0); return NO_ERROR; } int APIENTRY NdpRefresh (HCONNECTION conn, char *path, int tree) { log("NdpRefresh <%s> %d\n", path, 0); return NO_ERROR; } int APIENTRY NdpDiscardResourceData (HRESOURCE resource, NDDATABUF *pdatabuf) { // The plugin do not have to deallocate anything // because resource data did not contain any pointers // to plugins data. // Data stored by fsphSetResourceData will be // deallocated by NetDrive. log("NdpDicardresourceData %d\n", 0); return NO_ERROR; } int APIENTRY NdpSetPathInfo (HCONNECTION conn, NDFILEINFOL *pfi, char *szPathName) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; char path[CCHMAXPATH+1] = {0}; smbwrp_fileinfo finfo; debug_printf("NdpSetPathInfo in FIXME\n"); do { rc = pathparser(pRes, pConn, szPathName, path); if (rc) { break; } MemSet(&finfo, 0, sizeof(finfo)); StrNCpy(finfo.fname, path, sizeof(finfo.fname) - 1); fsphDosDateToUnixTime(pfi->stat.fdateLastWrite, pfi->stat.ftimeLastWrite, &(finfo.mtime)); finfo.attr = pfi->stat.attrFile & 0x37; rc = smbwrp_setattr(pConn->cli, &finfo); } while (0); log("NdpSetPathInfo <%s> (%s) %d\n", szPathName, path, rc); return rc; } int buildFEALIST(FEALIST *pFEASrc, GEALIST *pGEAList, FEALIST *pFEAList) { int rc = 0; FEA * pfea; FEA * pfeadest; unsigned long size, done = sizeof(pFEAList->cbList), dsize, ddone = sizeof(pFEAList->cbList); size = pFEASrc->cbList; pfea = pFEASrc->list; pfeadest = pFEAList->list; dsize = pFEAList->cbList; //log("buildFEALIST in destsize %d srcsize %d pGEAList=%08x pGEAList->cbList=%d\n", dsize, ddone, size, pGEAList, pGEAList ? pGEAList->cbList : 0); while (done < size) { char * name = (char *)(pfea + 1); int insert = 1; if (pGEAList && pGEAList->cbList > sizeof(pGEAList->cbList)) { GEA * pgea = pGEAList->list; unsigned long size = pGEAList->cbList - sizeof(pGEAList->cbList), done = 0; insert = 0; while (done < size) { //log("comp <%s> <%s>\n", name, pgea->szName); if (!ph->fsphStrNCmp(name, pgea->szName, pgea->cbName)) { insert = 1; break; } done += pgea->cbName + 2; pgea = (GEA *)((char *)pgea + pgea->cbName + 2); } } if (insert) { ddone += sizeof(FEA) + pfea->cbName + 1 + pfea->cbValue; if (ddone <= dsize) { pfeadest->cbName = pfea->cbName; pfeadest->cbValue = pfea->cbValue; pfeadest->fEA = 0; StrCpy((char *)(pfeadest + 1), name); MemCpy((char *)(pfeadest + 1) + pfea->cbName + 1, (char *)(pfea + 1) + pfea->cbName + 1, pfea->cbValue); pfeadest = (FEA *)((char *)pFEAList + ddone); } } done += sizeof(FEA) + pfea->cbName + 1 + pfea->cbValue; //log("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); pfea = (FEA *)((char *)pFEASrc + done); } pFEAList->cbList = ddone; if (ddone > dsize && dsize > sizeof(pFEAList->cbList)) { rc = ERROR_BUFFER_OVERFLOW; } log("buildFEALIST rc=%d destsize=%d destdone=%d srcsize=%d pGEAList=%08x\n", rc, dsize, ddone, size, pGEAList); return rc; } int APIENTRY NdpEAQuery (HCONNECTION conn, GEALIST *pGEAList, NDFILEINFOL *pfi, FEALIST *pFEAList) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; char * path = NULL; FEALIST * pFEASrc; NDDATABUF fdata = {0}; smbwrp_fileinfo *finfo; char pBuffer[64*1024]; if (!pfi || !pfi->pszName || !pFEAList) { return ERROR_EAS_NOT_SUPPORTED; } if (!pRes->easupport) { return ERROR_EAS_NOT_SUPPORTED; } rc = ph->fsphGetFileInfoData(pfi, &fdata, 0); if (rc || !fdata.ulSize || !fdata.pData) { log("NdpEAQuery: ph->fsphGetFileInfoData = %d/%d %08x\n", rc, fdata.ulSize, fdata.pData); return ERROR_EAS_NOT_SUPPORTED; } finfo = (smbwrp_fileinfo *)fdata.pData; path = finfo->fname; log("NdpEAQuery in <%s> %08x %d\n", path, pGEAList, pGEAList ? pGEAList->cbList : 0); do { rc = smbwrp_listea( pConn->cli, path, pBuffer, sizeof( pBuffer)); pFEASrc = (FEALIST*) pBuffer; if (rc) { //rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); switch (rc) { case ERROR_FILE_NOT_FOUND : case ERROR_PATH_NOT_FOUND : { pFEAList->cbList = sizeof(pFEAList->cbList); rc = NO_ERROR; } break; case ERROR_BUFFER_OVERFLOW : { pFEAList->cbList = pFEASrc->cbList; } break; default : { rc = ERROR_EAS_NOT_SUPPORTED; } } } else { rc = buildFEALIST((FEALIST *)pFEASrc, pGEAList, pFEAList); } } while (0); log("NdpEAQuery <%s> %d %d %d\n", pfi->pszName, rc, pFEASrc->cbList, pFEAList->cbList); return rc; } int APIENTRY NdpEASet (HCONNECTION conn, FEALIST *pFEAList, NDFILEINFOL *pfi) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; char * path; unsigned long action; NDDATABUF fdata = {0}; smbwrp_fileinfo *finfo; log("NdpEASet in\n"); if (!pfi || !pfi->pszName || !pFEAList || pFEAList->cbList <= sizeof(long)) { return ERROR_EAS_NOT_SUPPORTED; } if (!pRes->easupport) { return ERROR_EAS_NOT_SUPPORTED; } rc = ph->fsphGetFileInfoData(pfi, &fdata, 0); if (rc || !fdata.ulSize || !fdata.pData) { log("NdpEASet: ph->fsphGetFileInfoData = %d/%d/%08x\n", rc, fdata.ulSize, fdata.pData); return ERROR_EAS_NOT_SUPPORTED; } finfo = (smbwrp_fileinfo *)fdata.pData; path = finfo->fname; do { // got FEA there FEA * pfea; unsigned long done = sizeof(long); pfea = pFEAList->list; while (done < pFEAList->cbList) { rc = smbwrp_setea(pConn->cli, path, (char*)(pfea + 1), pfea->cbValue ? (char *)(pfea + 1) + pfea->cbName + 1: NULL, pfea->cbValue); if (rc) { break; } pfea = (FEA *)((char *)(pfea + 1) + pfea->cbName + 1 + pfea->cbValue); done += sizeof(FEA) + pfea->cbName + 1 + pfea->cbValue; } } while (0); log("NdpEASet %d\n", rc); return rc; } int APIENTRY NdpEASize (HCONNECTION conn, NDFILEINFOL *pfi, ULONG *pulEASize) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; char * path = NULL; FEALIST * pfealist; NDDATABUF fdata = {0}; smbwrp_fileinfo *finfo; char pBuffer[64*1024]; int easize; if (!pfi || !pulEASize) { return ERROR_EAS_NOT_SUPPORTED; } if (!pRes->easupport) { return ERROR_EAS_NOT_SUPPORTED; } rc = ph->fsphGetFileInfoData(pfi, &fdata, 0); if (rc || !fdata.ulSize || !fdata.pData) { log("NdpEASize: ph->fsphGetFileInfoData = %d/%d/%08x\n", rc, fdata.ulSize, fdata.pData); return ERROR_EAS_NOT_SUPPORTED; } finfo = (smbwrp_fileinfo *)fdata.pData; easize = finfo->easize; finfo->easize = -1; path = finfo->fname; if (easize >= 0) { *pulEASize = easize; log("NdpEASize <%s> cached %d\n", path, easize); return NO_ERROR; } log("NdpEASize in <%s> \n", path); do { rc = smbwrp_listea(pConn->cli, path, pBuffer, sizeof( pBuffer)); pfealist = (FEALIST*)pBuffer; if (rc) { //rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); switch (rc) { case ERROR_FILE_NOT_FOUND : case ERROR_PATH_NOT_FOUND : { pfealist->cbList = sizeof(pfealist->cbList); } /* Fall through */ case ERROR_BUFFER_OVERFLOW : { rc = NO_ERROR; } break; default : { rc = ERROR_EAS_NOT_SUPPORTED; } } } *pulEASize = pfealist->cbList; } while (0); log("NdpEASize <%s> %d %d\n", pfi->pszName, *pulEASize, rc); return rc; } int APIENTRY NdpSetCurrentDir (HCONNECTION conn, NDFILEINFOL *pfi, char *szPath) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; char path[CCHMAXPATH+1] = {0}; log("NdpSetCurrentDir in\n"); do { rc = pathparser(pRes, pConn, szPath, path); if (rc) { break; } rc = smbwrp_chdir(&pRes->srv, pConn->cli, path); } while (0); log("NdpSetCurrentDir <%s> (%s) %d\n", szPath, path, rc); return rc; } int APIENTRY NdpCopy (HCONNECTION conn, NDFILEINFOL *pfiDst, char *szDst, NDFILEINFOL *pfiSrc, char *szSrc, ULONG ulOption) { log("NdpCopy <%s> -> <%s> %d\n", szSrc, szDst, ERROR_CANNOT_COPY); return ERROR_CANNOT_COPY; } int APIENTRY NdpCopy2 (HCONNECTION conn, HRESOURCE resDst, NDFILEINFOL *pfiDst, char *szDst, NDFILEINFOL *pfiSrc, char *szSrc, ULONG ulOption) { log("NdpCopy2 <%s> -> <%s> %d\n", szSrc, szDst, ERROR_CANNOT_COPY); return ERROR_CANNOT_COPY; } int APIENTRY NdpForceDelete (HCONNECTION conn, NDFILEINFOL *pfi, char *szFile) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; char path[CCHMAXPATH+1] = {0}; log("NdpForceDelete in\n"); do { rc = pathparser(pRes, pConn, szFile, path); if (rc) { break; } rc = smbwrp_unlink(pConn->cli, path); } while (0); log("NdpForceDelete <%s> (%s) %d\n", szFile, path, rc); return rc; } int APIENTRY NdpCreateDir (HCONNECTION conn, NDFILEINFOL *pfiparent, char *szDirName, FEALIST *pFEAList) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; char path[CCHMAXPATH+1] = {0}; log("NdpCreateDir in\n"); do { rc = pathparser(pRes, pConn, szDirName, path); if (rc) { break; } rc = smbwrp_mkdir(pConn->cli, path); } while (0); log("NdpCreateDir <%s> (%s) %d\n", szDirName, path, rc); return rc; } int APIENTRY NdpDeleteDir (HCONNECTION conn, NDFILEINFOL *pfi, char *szDir) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; char path[CCHMAXPATH+1] = {0}; log("NdpDeleteDir in\n"); do { rc = pathparser(pRes, pConn, szDir, path); if (rc) { break; } rc = smbwrp_rmdir(pConn->cli, path); } while (0); log("NdpDeleteDir <%s> (%s) %d\n", szDir, path, rc); return rc; } int APIENTRY NdpMove (HCONNECTION conn, NDFILEINFOL *pfiDst, char *szDst, NDFILEINFOL *pfiSrc, char *szSrc) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; char src[CCHMAXPATH+1] = {0}; int l1, l2; char * p = szDst; log("NdpMove in from <%s> to <%s>\n", szSrc, szDst); do { rc = pathparser(pRes, pConn, szSrc, src); if (rc) { break; } l1 = StrLen(szSrc); l2 = StrLen(src); if (l1 > l2) { if (ph->fsphStrNICmp(szSrc, szDst, l1 - l2)) { // the file moved accross different shares or servers or workgroups rc = ERROR_WRITE_PROTECT; break; } p = szDst + l1 - l2 + 1; } //pConn->mem[CCHMAXPATH + 1] = '\\'; rc = smbwrp_rename(pConn->cli, src, p); } while (0); log("NdpMove <%s> -> <%s> (%s) %d\n", szSrc, szDst, src, rc); return rc; } int APIENTRY NdpMove2 (HCONNECTION conn, HRESOURCE resDst, NDFILEINFOL *pfiDst, char *szDst, NDFILEINFOL *pfiSrc, char *szSrc) { log("NdpMove2 <%s> -> <%s> %d\n", szSrc, szDst, ERROR_WRITE_PROTECT); return ERROR_WRITE_PROTECT; } int APIENTRY NdpChangeCase (HCONNECTION conn, char *szDst, NDFILEINFOL *pfiSrc, char *szSrc, char *szNewName, ULONG ulNameLen) { return NdpMove (conn, pfiSrc, szDst, pfiSrc, szSrc); } int APIENTRY NdpRename (HCONNECTION conn, char *szDst, NDFILEINFOL *pfiSrc, char *szSrc, char *szNewName, ULONG ulNameLen) { return NdpMove (conn, pfiSrc, szDst, pfiSrc, szSrc); } int smbopen(Connection *pConn, char *szFileName, int flags, ULONG ulOpenMode, ULONG ulAttribute, FEALIST *pFEAList) { Resource *pRes = pConn->pRes; unsigned long action; int rc = 0; char path[CCHMAXPATH+1] = {0}; log("smbopen in %d\n", pConn->file.fd); do { if (pConn->file.fd > 0) { rc = ERROR_TOO_MANY_OPEN_FILES; break; } rc = pathparser(pRes, pConn, szFileName, path); if (rc) { break; } StrNCpy(pConn->file.fullname, szFileName, sizeof(pConn->file.fullname) - 1); StrNCpy(pConn->file.fname, path, sizeof(pConn->file.fname) - 1); flags |= O_BINARY; switch (ulOpenMode & 3) { case OPEN_ACCESS_READONLY : flags |= O_RDONLY; break; case OPEN_ACCESS_WRITEONLY : flags |= O_WRONLY; break; case OPEN_ACCESS_READWRITE : flags |= O_RDWR; break; default : flags |= O_RDWR; } pConn->file.openmode = flags; pConn->file.openattr = ulAttribute & 0x37; pConn->file.denymode = (ulOpenMode & 0x70) >> 4; rc = smbwrp_open(pConn->cli, &pConn->file); } while (0); log("smbopen <%s> (%s) %08x %08x %08x %d. file = %d\n", szFileName, path, flags, ulOpenMode, ulAttribute, rc, pConn->file.fd); if (!rc && pFEAList) { int rc1 = NdpFileEASet((HCONNECTION)pConn, (NDFILEHANDLE)0, pFEAList); log("smbopen NdpFileEASet %d. pFEAList->cbList %d\n", rc1, pFEAList->cbList); } return rc; } int APIENTRY NdpOpenReplace (HCONNECTION conn, NDFILEINFOL *pfi, NDFILEHANDLE *phandle, char *szFileName, ULONG ulSize, ULONG ulOpenMode, ULONG ulAttribute, FEALIST *pFEAList) { return smbopen((Connection *)conn, szFileName, O_TRUNC, ulOpenMode, ulAttribute, pFEAList); } int APIENTRY NdpOpenReplaceL(HCONNECTION conn, NDFILEINFO *pfi, NDFILEHANDLE *phandle, char *szFileName, LONGLONG llSize, ULONG ulOpenMode, ULONG ulAttribute, FEALIST *pFEAList) { return smbopen((Connection *)conn, szFileName, O_TRUNC, ulOpenMode, ulAttribute, pFEAList); } int APIENTRY NdpOpenCreate (HCONNECTION conn, NDFILEINFOL *pfiparent, NDFILEHANDLE *phandle, char *szFileName, ULONG ulSize, ULONG ulOpenMode, ULONG ulAttribute, FEALIST *pFEAList) { // return smbopen((Connection *)conn, szFileName, O_CREAT, ulOpenMode, ulAttribute); return smbopen((Connection *)conn, szFileName, O_CREAT | O_EXCL, ulOpenMode, ulAttribute, pFEAList); } int APIENTRY NdpOpenCreateL(HCONNECTION conn, NDFILEINFO *pfiparent, NDFILEHANDLE *phandle, char *szFileName, LONGLONG llSize, ULONG ulOpenMode, ULONG ulAttribute, FEALIST *pFEAList) { return smbopen((Connection *)conn, szFileName, O_CREAT | O_EXCL, ulOpenMode, ulAttribute, pFEAList); } int APIENTRY NdpOpenExisting (HCONNECTION conn, NDFILEINFOL *pfi, NDFILEHANDLE *phandle, char *szFileName, ULONG ulOpenMode, USHORT *pfNeedEA) { if (pfNeedEA) *pfNeedEA = 0; // wtf is this ? return smbopen((Connection *)conn, szFileName, 0, ulOpenMode, 0, NULL); } int APIENTRY NdpSetFileAttribute (HCONNECTION conn, NDFILEINFOL *pfi, char *szFileName, USHORT usAttr) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; smbwrp_fileinfo finfo; char path[CCHMAXPATH+1] = {0}; log("NdpSetFileAttribute in\n"); do { rc = pathparser(pRes, pConn, szFileName, path); if (rc) { break; } MemSet(&finfo, 0, sizeof(finfo)); StrNCpy(finfo.fname, path, sizeof(finfo.fname) - 1); finfo.attr = usAttr & 0x37; rc = smbwrp_setattr(pConn->cli, &finfo); } while (0); log("NdpSetFileAttribute <%s> (%s) %04x %d\n", szFileName, path, usAttr, rc); return rc; } int APIENTRY NdpFlush (HRESOURCE resource) { log("NdpFlush %d\n", ERROR_NOT_SUPPORTED); return ERROR_NOT_SUPPORTED; } int APIENTRY NdpIOCTL (int type, HRESOURCE resource, char *path, int function, void *in, ULONG insize, PULONG poutlen) { log("NdpIOCTL <%s> %d\n", path, function); if (in && insize > 4096) { char out[4096]; sprintf (out, "SAMBA IOCTL function = %d, parms [%s] insize = %d, *poutlen = %d", function, in, insize, *poutlen); *poutlen = strlen(out); strcpy (in, out); return NO_ERROR; } return ERROR_NOT_SUPPORTED; } int APIENTRY NdpFileQueryInfo (HCONNECTION conn, NDFILEHANDLE handle, void *plist) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; smbwrp_fileinfo finfo; debug_printf("NdpFileQueryInfo in\n"); do { if (pConn->file.fd < 0 || !*pConn->file.fname) { rc = ERROR_INVALID_HANDLE; break; } StrNCpy(finfo.fname, pConn->file.fname, sizeof(finfo.fname) - 1); rc = smbwrp_fgetattr(pConn->cli, &pConn->file, &finfo); if (!rc) { finfo.easize = -1; getfindinfoL(pConn, plist, &finfo, 0, NULL); } } while (0); log("NdpFileQueryInfo <%s> %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, rc); return rc; } int APIENTRY NdpFileEAQuery (HCONNECTION conn, NDFILEHANDLE handle, GEALIST *pGEAList, FEALIST *pFEAList) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; char pBuffer[64*1024]; FEALIST * pFEASrc; if (!pFEAList) { return ERROR_EAS_NOT_SUPPORTED; } if (!pRes->easupport) { return ERROR_EAS_NOT_SUPPORTED; } log("NdpFileEAQuery in <%s>/%d pGEAList=%08x\n", pConn->file.fname, pConn->file.fd, pGEAList); do { if (pConn->file.fd < 0) { rc = ERROR_INVALID_HANDLE; break; } rc = smbwrp_flistea(pConn->cli, &pConn->file, pBuffer, sizeof( pBuffer)); pFEASrc = (FEALIST *) pBuffer; if (rc) { //rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); switch (rc) { case ERROR_FILE_NOT_FOUND : case ERROR_PATH_NOT_FOUND : { pFEAList->cbList = sizeof(pFEAList->cbList); rc = NO_ERROR; } break; case ERROR_BUFFER_OVERFLOW : { pFEAList->cbList = pFEASrc->cbList; } break; default : { rc = ERROR_EAS_NOT_SUPPORTED; } } } else { rc = buildFEALIST(pFEASrc, pGEAList, pFEAList); } } while (0); log("NdpFileEAQuery out <%s>/%d pFEASrc->cbList=%d pFEAList->cbList=%d rc=%d\n", pConn->file.fname, pConn->file.fd, pFEASrc->cbList, pFEAList->cbList, rc); return rc; } int APIENTRY NdpFileEASet (HCONNECTION conn, NDFILEHANDLE handle, FEALIST *pFEAList) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; log("NdpFileEASet in\n"); if (!pFEAList || pFEAList->cbList <= sizeof(long)) { return ERROR_EAS_NOT_SUPPORTED; } if (!pRes->easupport) { return ERROR_EAS_NOT_SUPPORTED; } do { // got FEA there FEA * pfea; unsigned long done = sizeof(long); if (pConn->file.fd < 0) { rc = ERROR_INVALID_HANDLE; break; } pfea = pFEAList->list; while (done < pFEAList->cbList) { rc = smbwrp_fsetea(pConn->cli, &pConn->file, (char *)(pfea + 1), pfea->cbValue ? (char *)(pfea + 1) + pfea->cbName + 1: NULL, pfea->cbValue); if (rc) { break; } pfea = (FEA *)((char *)(pfea + 1) + pfea->cbName + 1 + pfea->cbValue); done += sizeof(FEA) + pfea->cbName + 1 + pfea->cbValue; } } while (0); log("NdpFileEASet %d\n", rc); return rc; } int APIENTRY NdpFileEASize (HCONNECTION conn, NDFILEHANDLE handle, ULONG *pulEASize) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; char path[CCHMAXPATH+1] = {0}; FEALIST * pFEAList; char pBuffer[64*1024]; if (!pulEASize) { return ERROR_EAS_NOT_SUPPORTED; } if (!pRes->easupport) { return ERROR_EAS_NOT_SUPPORTED; } log("NdpFileEASize in <%s>/%d \n", pConn->file.fname, pConn->file.fd); do { if (pConn->file.fd < 0) { rc = ERROR_INVALID_HANDLE; break; } rc = smbwrp_flistea(pConn->cli, &pConn->file, pBuffer, sizeof(pBuffer)); pFEAList = (FEALIST*) pBuffer; if (rc) { //rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); switch (rc) { case ERROR_FILE_NOT_FOUND : case ERROR_PATH_NOT_FOUND : { pFEAList->cbList = sizeof(pFEAList->cbList); } /* Fall through */ case ERROR_BUFFER_OVERFLOW : { rc = NO_ERROR; } break; default : { rc = ERROR_EAS_NOT_SUPPORTED; } } } *pulEASize = pFEAList->cbList; } while (0); log("NdpFileEASize %d %d\n", *pulEASize, rc); return rc; } int APIENTRY NdpFileSetInfo (HCONNECTION conn, NDFILEHANDLE handle, NDFILEINFOL *pfi) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action, attrFile; debug_printf("NdpFileSetInfo in\n"); do { if (pConn->file.fd < 0 || !*pConn->file.fname) { rc = ERROR_INVALID_HANDLE; break; } attrFile = pfi->stat.attrFile; // deferred setinfo - on closing the file pConn->file.openattr = attrFile; fsphDosDateToUnixTime(pfi->stat.fdateLastWrite, pfi->stat.ftimeLastWrite, &(pConn->file.mtime)); debug_printf("NdpFileSetInfo mtime %d\n", pConn->file.mtime); } while (0); log("NdpFileSetInfo <%s> %08x %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, attrFile, rc); return NO_ERROR; } int APIENTRY NdpFileSetFilePtrL(HCONNECTION conn, NDFILEHANDLE handle, LONGLONG llOffset, ULONG ulMethod, LONGLONG *pllActual) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; log("NdpFileSetFilePtrl in\n"); do { if (pConn->file.fd < 0) { rc = ERROR_INVALID_HANDLE; break; } rc = smbwrp_lseek(pConn->cli, &pConn->file, ulMethod, llOffset); if (!rc) *pllActual = pConn->file.offset; } while (0); log("NdpFileSetFilePtrL <%s> %lld %lu %lld %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, llOffset, ulMethod, *pllActual, rc); return rc; } int APIENTRY NdpFileSetFilePtr (HCONNECTION conn, NDFILEHANDLE handle, LONG lOffset, ULONG ulMethod, ULONG *pulActual) { LONGLONG llActual; int rc = NdpFileSetFilePtrL(conn, handle, lOffset, ulMethod, &llActual); *pulActual = llActual & 0xFFFFFFFF; log("NdpFileSetFilePtr %ld %lu %ld %d\n", lOffset, ulMethod, *pulActual, rc); return rc; } int APIENTRY NdpFileClose (HCONNECTION conn, NDFILEHANDLE handle) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; log("NdpFileClose in %d <%s>\n", pConn->file.fd, pConn->file.fd < 0 ? "!null!" : pConn->file.fname); do { if (pConn->file.fd < 0) { rc = ERROR_INVALID_HANDLE; break; } rc = smbwrp_close(pConn->cli, &pConn->file); } while (0); log("NdpFileClose %d %d\n", pConn->file.fd, rc); pConn->file.fd = -1; return rc; } int APIENTRY NdpFileCommit (HCONNECTION conn, NDFILEHANDLE handle) { log("NdpFileCommit %d\n", NO_ERROR); return NO_ERROR; } int APIENTRY NdpFileNewSize (HCONNECTION conn, NDFILEHANDLE handle, ULONG ulLen) { int rc = NdpFileNewSizeL(conn, handle, ulLen); log("NdpFileNewSize %ld %d\n", ulLen, rc); return rc; } int APIENTRY NdpFileNewSizeL(HCONNECTION conn, NDFILEHANDLE handle, LONGLONG llLen) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; log("NdpFileNewSizeL in\n"); do { if (pConn->file.fd < 0) { rc = ERROR_INVALID_HANDLE; break; } rc = smbwrp_setfilesize(pConn->cli, &pConn->file, llLen); } while (0); log("NdpFileNewSizeL <%s> %lld %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, llLen, rc); return rc; } int APIENTRY NdpFileRead (HCONNECTION conn, NDFILEHANDLE handle, void *pBuffer, ULONG ulRead, ULONG *pulActual) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long done = 0; unsigned long onedone; unsigned long action; log("NdpFileRead in\n"); do { if (pConn->file.fd < 0) { rc = ERROR_INVALID_HANDLE; break; } rc = smbwrp_read(pConn->cli, &pConn->file, pBuffer, ulRead, pulActual); //*pulActual = ulRead; //DosSleep(0); } while (0); log("NdpFileRead <%s> %lu %lu %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, ulRead, *pulActual, rc); return rc; } int APIENTRY NdpFileWrite (HCONNECTION conn, NDFILEHANDLE handle, void *pBuffer, ULONG ulWrite, ULONG *pulActual) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long done = 0; unsigned long onedone; unsigned long action; log("NdpFileWrite in\n"); do { if (pConn->file.fd < 0) { rc = ERROR_INVALID_HANDLE; break; } rc = smbwrp_write(pConn->cli, &pConn->file, pBuffer, ulWrite, pulActual); } while (0); log("NdpFileWrite <%s> %lu %lu %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, ulWrite, *pulActual, rc); return rc; }