#define NDPL_LARGEFILES #define INCL_LONGLONG #include #include #include #include #include #include #include #define NULL ((void *)0) #ifndef DEBUG_PRINTF #define debug_printf( ...) #endif 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); } } } // ------------------------------------------------------------- /* 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; } typedef struct _Resource { /* NetDrive information */ NDPROPERTYHANDLE properties; /* access handle for the properties */ int rootlevel; unsigned long memlen; unsigned long objany; smbwrp_server srv; char logfile[CCHMAXPATH + 1]; char loglevel; int easupport; } Resource; typedef struct _Connection { Resource *pRes; HPIPE pipe; char * mem; int clientpid; int rc; smbwrp_server srv; smbwrp_file file; } Connection; int openpipe(Resource * pRes, HPIPE * ppipe) { HPIPE pipe = 0; unsigned long rc = 0, action; if (!pRes) { return ERROR_INVALID_PARAMETER; } rc = DosOpen(PIPENAME, &pipe, &action, 0, 0, OPEN_ACTION_OPEN_IF_EXISTS, OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, NULL); log("DosOpen1 rc %d\n", rc); if (rc) { unsigned long sid = 0, pid = 0; STARTDATA sd; char params[CCHMAXPATH * 2] = {0}; MemSet(&sd, 0, sizeof(sd)); sd.Length = sizeof(sd); sd.Related = SSF_RELATED_INDEPENDENT; sd.FgBg = SSF_FGBG_BACK; sd.PgmName = EXECNAME; if (pRes->loglevel) { char level[2]; level[0] = pRes->loglevel + '0'; level[1] = 0; StrNCat(params, " -d ", sizeof(params) - 1); StrNCat(params, level, sizeof(params) - 1); } if (*pRes->logfile) { StrNCat(params, " -l ", sizeof(params) - 1); StrNCat(params, pRes->logfile, sizeof(params) - 1); } log("params <%s>\n", params); sd.PgmInputs = *params ? params : NULL; sd.SessionType = SSF_TYPE_WINDOWABLEVIO; rc = DosStartSession(&sd, &sid, &pid); log("smbcd startsession pid %d sid %d rc %d\n", pid, sid, rc); if (rc == ERROR_SMG_INVALID_CALL) { // ndfs started ndctl detached, so we have to use dosexecpgm char failed[CCHMAXPATH + 1] = {0}; RESULTCODES res = {0}; char * p = params; StrCpy(p, EXECNAME); p += StrLen(p) + 1; if (*pRes->logfile) { StrCpy(p, "-l "); StrNCat(p, pRes->logfile, sizeof(params) - (p - (char *)params)); p += StrLen(p) + 1; if (pRes->loglevel) { char level[2]; level[0] = pRes->loglevel + '0'; level[1] = 0; StrCpy(p, "-d "); StrNCat(p, level, sizeof(params) - (p - (char *)params)); p += StrLen(p) + 1; } } else { StrCpy(p, "-q"); p += StrLen(p) + 1; } *p = 0; rc = DosExecPgm(failed, sizeof(failed), EXEC_BACKGROUND, params, NULL, &res, EXECNAME); log("smbcd DosExecPgm codeTerminate %d codeResult %d rc %d\n", res.codeTerminate, res.codeResult, rc); } if (!rc) { DosSleep(500); rc = DosOpen(PIPENAME, &pipe, &action, 0, 0, OPEN_ACTION_OPEN_IF_EXISTS, OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, NULL); log("DosOpen2 rc %d\n", rc); } } if (!rc) { if (ppipe) { *ppipe = pipe; } else { DosClose(pipe); } } return rc; } 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->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->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) { int rc = NO_ERROR; unsigned long t; const unsigned char * q = NULL; HPIPE pipe; int defaultPassword = 1; pRes->memlen = 1 << 18; pRes->rootlevel = 0; *pRes->logfile = 0; pRes->loglevel = 0; pRes->easupport = 1; t = 0, q = NULL; rc = ph->fsphQueryStringProperty (pRes->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 (pRes->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 (pRes->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 (pRes->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 (pRes->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 (pRes->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 (pRes->properties, "PASSWORD", ""); } } else { char c[1024]; encryptPassword (pRes->srv.password, c); ph->fsphSetProperty (pRes->properties, "SPASSWORD", c); // clear the plain password ph->fsphSetProperty (pRes->properties, "PASSWORD", ""); } t = 0, q = NULL; rc = ph->fsphQueryStringProperty (pRes->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 (pRes->properties, "LOGFILE", &q, &t); if (!rc && t && *q) { StrNCpy(pRes->logfile, q, sizeof(pRes->logfile) - 1); } t = 0; rc = ph->fsphQueryUlongProperty (pRes->properties, "LOGLEVEL", &t); if (!rc) { if (t > 9) { t = 9; rc = ERROR_INVALID_PARAMETER; } pRes->loglevel = t; } t = 0; rc = ph->fsphQueryUlongProperty (pRes->properties, "MASTERTYPE", &t); if (!rc) { if (t > 1) { rc = ERROR_INVALID_PARAMETER; } else { pRes->srv.ifmastergroup = t; } } t = 0; rc = ph->fsphQueryUlongProperty (pRes->properties, "EASUPPORT", &t); if (!rc) { if (t > 1) { rc = ERROR_INVALID_PARAMETER; } else { pRes->easupport = t; } } t = 0; rc = ph->fsphQueryUlongProperty (pRes->properties, "MEMLEN", &t); if (!rc) { if (t <= (pRes->easupport ? 1 : 0) || t > 10) { rc = ERROR_INVALID_PARAMETER; } else { pRes->memlen = t * 65536; } } return rc; } int checkconnection(Connection * pConn) { int rc = NO_ERROR; unsigned long action; smb_request req = {0}; smb_response resp = {0}; char* mem; if (!pConn) { return ERROR_INVALID_PARAMETER; } log("checkconnection pconnrc %d pipe %d\n", pConn->rc, pConn->pipe); // YD this code need probably to be removed (reworked), since DosQueryNPHState, // DosQueryNPipeInfo, DosPeekNPipe, DosResetBuffer, are all returning // NO_ERROR even if the other pipe end is closed (smbcd crash). // // YD TODO probably checkconnection() call can be removed since we // detect broken pipes inside _DosTransactNPipe if (!pConn->rc) { unsigned long state = 0; rc = DosQueryNPHState(pConn->pipe, &state); log("DosQueryNPHstate(pConn->pipe) = %d (%08x)\n", pConn->rc, pConn->pipe, rc, state); if (!rc) { return pConn->rc; } } // there were error on pipe, reopen it and restore connection if (pConn->pipe) { DosClose(pConn->pipe); pConn->pipe = 0; } rc = openpipe(pConn->pRes, &pConn->pipe); if (rc) { log("checkconnection openpipe %d\n", rc); pConn->pipe = 0; DosSleep(1000); return ERROR_PIPE_NOT_CONNECTED; } // if we are reconnecting pipe because of a broken pipe, we // need to save shared memory content to allow operation retry mem = malloc( pConn->pRes->memlen); if (mem) memcpy( mem, pConn->mem, pConn->pRes->memlen); // reinit connection do { req.request = SMBREQ_INIT; req.param = (char *)0xFFFFFFFF; pConn->rc = DosTransactNPipe(pConn->pipe, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); break; } pConn->clientpid = resp.value & 0xFFFF; // client daemon pid changed pConn->rc = DosGiveSharedMem(pConn->mem, pConn->clientpid, PAG_READ | PAG_WRITE); if (pConn->rc) { rc = pConn->rc; break; } MemCpy(pConn->mem, &pConn->srv, sizeof(pConn->srv)); req.request = SMBREQ_CONNECT; req.param = pConn->mem; req.paramlen = sizeof(pConn->srv); req.length = req.paramlen; pConn->rc = DosTransactNPipe(pConn->pipe, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); break; } MemCpy(&pConn->srv, pConn->mem, sizeof(pConn->srv)); rc = NO_ERROR; } while (0); // if we are reconnecting pipe because of a broken pipe, we // need to restore shared memory content to allow operation retry if (mem) { memcpy( pConn->mem, mem, pConn->pRes->memlen); free( mem); } if (pConn->rc && pConn->pipe) { DosClose(pConn->pipe); pConn->pipe = 0; } return rc; } /* * YD Since DosQueryNPHState, * DosQueryNPipeInfo, DosPeekNPipe, DosResetBuffer, are all returning * NO_ERROR even if the other pipe end is closed (smbcd crash), * we can detect broken pipes only when writing/reading from the pipe. */ ULONG APIENTRY _DosTransactNPipe(Connection *pConn, PVOID pOutbuf, ULONG ulOutbufLength, PVOID pInbuf, ULONG ulInbufLength, PULONG pulBytesRead) { APIRET rc; // try first rc = DosTransactNPipe(pConn->pipe, pOutbuf, ulOutbufLength, pInbuf, ulInbufLength, pulBytesRead); if (rc != ERROR_BROKEN_PIPE) return rc; // client daemon closed, force open connection again pConn->rc = rc; checkconnection( pConn); // issue command again rc = DosTransactNPipe(pConn->pipe, pOutbuf, ulOutbufLength, pInbuf, ulInbufLength, pulBytesRead); 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; int newlevel = 0; smbwrp_server * tmp = (smbwrp_server *)pConn->mem; MemCpy(tmp, &pConn->srv, sizeof(pConn->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 unsigned long action; smb_request req = {0}; smb_response resp = {0}; req.request = SMBREQ_DISCONNECT; req.param = pConn->mem; req.length = 0; req.paramlen = 0; rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); req.request = SMBREQ_CONNECT; req.param = pConn->mem; req.length = pRes->memlen; req.paramlen = sizeof(pConn->srv); rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (rc || action < sizeof(resp) || resp.rc) { APIRET rc2; rc = rc ? rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); MemCpy(tmp, &pRes->srv, sizeof(pRes->srv)); rc2 = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); // TODO: what to do if the reconnect will fail ? } else { MemCpy(&pConn->srv, tmp, sizeof(pConn->srv)); } } } StrCpy(result, "\\"); StrNCat(result, path, CCHMAXPATH); return rc; } int APIENTRY NdpFreeResource (HRESOURCE resource) { Resource *pRes = (Resource *)resource; MemSet(&pRes->srv, 0, sizeof(pRes->srv)); DosFreeMem(pRes); log("NdpFreeResource %d\n", NO_ERROR); return NO_ERROR; } // ------------------------------------------------------------- /* check if the requested resource is available */ static int checkMountResource( Resource* pRes) { int rc; unsigned long action; smb_request req = {0}; smb_response resp = {0}; Connection Conn = {0}; debug_printf("checkMountResource in tid#%d\n", _gettid()); // open the pipe Conn.pRes = pRes; Conn.file.fd = -1; debug_printf("checkMountResource open pipe\n"); rc = openpipe(pRes, &Conn.pipe); if (rc) { debug_printf("checkMountResource open pipe failed rc=%d\n", rc); return rc; } // init, get client pid debug_printf("checkMountResource send INIT for '%s'\n", pRes->srv.share_name); req.request = SMBREQ_INIT; req.param = (char *)0xFFFFFFFF; rc = _DosTransactNPipe(&Conn, &req, sizeof(req), &resp, sizeof(resp), &action); if (rc || action < sizeof(resp) || resp.rc) { debug_printf("checkMountResource INIT failed rc=%d\n", rc); // close pipe DosClose( Conn.pipe); return rc; } Conn.clientpid = resp.value & 0xFFFF; // allocate shared memory rc = DosAllocSharedMem((PPVOID)&Conn.mem, NULL, pRes->memlen, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_GIVEABLE | pRes->objany); if (rc) { debug_printf("checkMountResource DosAllocSharedMem failed rc=%d\n", rc); // close pipe DosClose( Conn.pipe); return rc; } rc = DosGiveSharedMem( Conn.mem, Conn.clientpid, PAG_READ | PAG_WRITE); if (!rc) { // open connection with samba server, just to check share type debug_printf("checkMountResource send CONNECT\n"); MemCpy( Conn.mem, &pRes->srv, sizeof(pRes->srv)); req.request = SMBREQ_CONNECT; req.param = Conn.mem; req.paramlen = sizeof( Conn.srv); req.length = req.paramlen; rc = _DosTransactNPipe( &Conn, &req, sizeof(req), &resp, sizeof(resp), &action); if (rc || action < sizeof(resp) || resp.rc) { debug_printf("checkMountResource SMBREQ_CONNECT failed rc=%d, resp.rc=%d\n", rc, resp.rc); rc = (rc == NO_ERROR ? resp.rc : rc); } // no more data, close connection req.request = SMBREQ_DISCONNECT; req.param = Conn.mem; req.length = 0; req.paramlen = 0; _DosTransactNPipe( &Conn, &req, sizeof(req), &resp, sizeof(resp), &action); } // free memory DosFreeMem( Conn.mem); // close pipe DosClose( Conn.pipe); 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"); /* since samba plugin support only 1 type of resources we do not need */ /* to check what the found type really is */ rc = DosAllocMem((void **)&pRes, sizeof(Resource), PAG_COMMIT | PAG_READ | PAG_WRITE | objany); if (rc == ERROR_INVALID_PARAMETER) { objany = 0; rc = DosAllocMem((void **)&pRes, sizeof(Resource), PAG_COMMIT | PAG_READ | PAG_WRITE); } if (!rc && pRes == NULL) { rc = ERROR_NOT_ENOUGH_MEMORY; } if (!rc) { MemSet(pRes, 0, sizeof(Resource)); pRes->properties = properties; pRes->objany = objany; // parse init string rc = initResource (pRes); // 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 { NdpFreeResource((HRESOURCE)pRes); } } log("NdpMountResource rc=%d\n", rc); return rc; } // ------------------------------------------------------------- int APIENTRY NdpCreateConnection (HRESOURCE resource, HCONNECTION *pconn) { int rc; Resource * pRes = (Resource *)resource; unsigned long action; smb_request req = {0}; smb_response resp = {0}; Connection *pConn = NULL; log("NdpCreateConnection in\n"); rc = DosAllocMem((void **)&pConn, sizeof(Connection), PAG_COMMIT | PAG_READ | PAG_WRITE | pRes->objany); if (!rc && 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; do { log("NdpCreateConnection open pipe\n"); rc = openpipe(pRes, &pConn->pipe); if (rc) { pConn->pipe = 0; break; } log("NdpCreateConnection send INIT\n"); req.request = SMBREQ_INIT; req.param = (char *)0xFFFFFFFF; rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (rc || action < sizeof(resp) || resp.rc) { return rc ? rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } pConn->clientpid = resp.value & 0xFFFF; rc = DosAllocSharedMem((PPVOID)&pConn->mem, NULL, pRes->memlen, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_GIVEABLE | pRes->objany); if (rc) { break; } rc = DosGiveSharedMem(pConn->mem, pConn->clientpid, PAG_READ | PAG_WRITE); if (rc) { break; } log("NdpCreateConnection send CONNECT\n"); MemCpy(pConn->mem, &pRes->srv, sizeof(pRes->srv)); req.request = SMBREQ_CONNECT; req.param = pConn->mem; req.paramlen = sizeof(pConn->srv); req.length = req.paramlen; rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (rc || action < sizeof(resp) || resp.rc) { rc = rc ? rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } else { MemCpy(&pConn->srv, pConn->mem, sizeof(pConn->srv)); } } while (0); if (rc) { if (pConn->mem) { DosFreeMem(pConn->mem); } if (pConn->pipe) { DosClose(pConn->pipe); } MemSet(pConn, 0, sizeof(*pConn)); DosFreeMem(pConn); pConn = NULL; } *pconn = (HCONNECTION)pConn; log("NdpCreateConnection %d %d\n", rc, resp.rc); return rc; } // ------------------------------------------------------------- int APIENTRY NdpFreeConnection (HCONNECTION conn) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; log("NdpFreeConnection in\n"); if (pConn->mem) { smb_request req = {0}; smb_response resp = {0}; unsigned long action; if (pConn->file.fd >= 0) { MemCpy(pConn->mem, &pConn->file, sizeof(pConn->file)); req.request = SMBREQ_CLOSE; req.param = pConn->mem; req.length = sizeof(pConn->file); req.paramlen = sizeof(pConn->file); _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); pConn->file.fd = -1; } req.request = SMBREQ_DISCONNECT; req.param = pConn->mem; req.length = 0; req.paramlen = 0; _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); DosFreeMem(pConn->mem); DosClose(pConn->pipe); MemSet(pConn, 0, sizeof(*pConn)); } DosFreeMem(pConn); log("NdpFreeConnection %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) { int rc = NO_ERROR, rc1; Connection *pConn = 0; smb_request req = {0}; smb_response resp = {0}; unsigned long action = 0; log("NdpRsrcQueryFSAllocate %08x\n", pfsa); if (!pfsa) { return NO_ERROR; } rc = NdpCreateConnection (resource, (HCONNECTION *)&pConn); if (rc) { log("NdpCreateConnection failed rc=%d\n", rc); pfsa->cSectorUnit = 1; pfsa->cUnit = 123456; pfsa->cUnitAvail = 123456; pfsa->cbSector = 2048; return rc; } MemSet(pConn->mem, 0, sizeof(FSALLOCATE)); req.request = SMBREQ_DSKATTR; req.param = pConn->mem; req.paramlen = sizeof(FSALLOCATE); req.length = req.paramlen; rc = DosTransactNPipe( pConn->pipe, &req, sizeof(req), &resp, sizeof(resp), &action); if (rc || action < sizeof(resp) || resp.rc) { pfsa->cSectorUnit = 1; pfsa->cUnit = 123456; pfsa->cUnitAvail = 123456; pfsa->cbSector = 2048; rc = rc ? rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } else { FSALLOCATE * fsa = (FSALLOCATE *)pConn->mem; pfsa->cSectorUnit = fsa->cSectorUnit; pfsa->cUnit = fsa->cUnit; pfsa->cUnitAvail = fsa->cUnitAvail; pfsa->cbSector = fsa->cbSector; } rc1 = NdpFreeConnection((HCONNECTION)pConn); log("NdpRsrcQueryFSAllocate %d/%d/%d (cUnit = %d/cUnitAvail = %d/cbSector = %d)\n", rc, resp.rc, rc1, pfsa->cUnit, pfsa->cUnitAvail, pfsa->cbSector); 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; smb_request req = {0}; smb_response resp = {0}; char *mask = "*"; char dir[CCHMAXPATH+1] = {0}; char path[CCHMAXPATH+1] = {0}; char fullname[CCHMAXPATH+1] = {0}; smbwrp_fileinfo * data; NDPATHELEMENT *pel = ph->fsphNameElem(0); debug_printf("NdpFindStart in\n"); do { rc = checkconnection(pConn); if (rc) { break; } 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) { break; } action = StrLen(path) - 1; if (path[action] != '\\') { StrNCat(path, "\\", sizeof(path) - 1); } StrCpy(dir, path); StrNCat(path, mask, sizeof(path) - 1); MemCpy(pConn->mem, &pConn->srv, sizeof(pConn->srv)); StrCpy(pConn->mem + sizeof(pConn->srv), path); req.request = SMBREQ_FILELIST; req.param = pConn->mem; req.paramlen = sizeof(pConn->srv) + CCHMAXPATH + 1; req.length = pRes->memlen; data = (smbwrp_fileinfo *)(pConn->mem + sizeof(pConn->srv) + CCHMAXPATH + 1); do { int i; pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || (resp.rc && resp.rc != ERROR_MORE_DATA)) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); break; } log("NdpFindStart %d %d %d\n", pConn->rc, resp.rc, resp.length / sizeof(smbwrp_fileinfo)); if (ifL) { for (i = 0; i < resp.length / sizeof(smbwrp_fileinfo); i++) { smbwrp_fileinfo * finfo = data + i; log("NdpFindStart found <%s> %d\n", finfo->fname, finfo->easize); StrCpy(fullname, dir); StrCat(fullname, finfo->fname); StrCpy(finfo->fname, fullname); count += getfindinfoL(pConn, plist, finfo, ulAttribute, mask); } } else { FILEFINDBUF3 buf = {0}; for (i = 0; i < resp.length / sizeof(smbwrp_fileinfo); i++) { smbwrp_fileinfo * finfo = data + i; getfindinfo(pConn, &buf, finfo); if (ph->fsphAttrMatch(ulAttribute, buf.attrFile) && ph->fsphWildMatch(mask, buf.achName, ND_IGNORE_CASE)) { StrCpy(fullname, dir); StrCat(fullname, finfo->fname); StrCpy(finfo->fname, fullname); ph->fsphAddFileFind32(plist, &buf, finfo, sizeof(*finfo), 0); count++; } } } } while (resp.rc == ERROR_MORE_DATA); } while (0); log("NdpFindStart <%s> (%s) cnt %d %d %d\n", szPath, path, count, rc, pConn->rc); return rc; } int APIENTRY NdpQueryPathInfo (HCONNECTION conn, void *plist, char *szPath) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; unsigned long action; smb_request req = {0}; smb_response resp = {0}; smbwrp_fileinfo * finfo = (smbwrp_fileinfo *)pConn->mem; char path[CCHMAXPATH+1] = {0}; int retry = 0; do { debug_printf("NdpQueryInfo in <%s>, retry = %d\n", szPath, retry); do { if (ph->fsphStrChr(szPath, '*') || ph->fsphStrChr(szPath, '?')) { rc = ERROR_FILE_NOT_FOUND; break; } rc = checkconnection(pConn); if (rc) { break; } rc = pathparser(pRes, pConn, szPath, path); 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); req.request = SMBREQ_GETINFO; req.param = pConn->mem; req.paramlen = sizeof(*finfo); req.length = req.paramlen; pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { switch (resp.rc) { case NO_ERROR : case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: case ERROR_ACCESS_DENIED: case ERROR_INVALID_PARAMETER: break; default : { resp.rc = ERROR_PATH_NOT_FOUND; } } rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } else { finfo->easize = -1; if (ifL) { getfindinfoL(pConn, plist, finfo, 0, NULL); } else { int trc; FILEFINDBUF3 buf = {0}; getfindinfo(pConn, &buf, finfo); trc = ph->fsphAddFileFind32(plist, &buf, finfo, sizeof(*finfo), 0); log("NdpQueryInfo got info <%s> attr %08x size %d namelen %d date %lu %lu. Plist 0x%08x rc = %d\n", buf.achName, buf.attrFile, buf.cbFile, buf.cchName, buf.fdateLastWrite, buf.ftimeLastWrite, plist, trc); } } 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 = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? ERROR_PATH_NOT_FOUND : ERROR_INVALID_PARAMETER); } } } } while (0); log("NdpQueryInfo <%s> (%s) %d %d\n", szPath, path, rc, pConn->rc); retry = rc && !retry; } while (retry); 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; smb_request req = {0}; smb_response resp = {0}; smbwrp_fileinfo * finfo = (smbwrp_fileinfo *)pConn->mem; char path[CCHMAXPATH+1] = {0}; debug_printf("NdpSetPathInfo in\n"); do { rc = checkconnection(pConn); if (rc) { break; } 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)); if (ifL) { finfo->attr = pfi->stat.attrFile & 0x37; } else { FILESTATUS3 * stat = (FILESTATUS3 *)&(pfi->stat); finfo->attr = stat->attrFile & 0x37; } req.request = SMBREQ_SETINFO; req.param = pConn->mem; req.paramlen = sizeof(*finfo); req.length = req.paramlen; pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } } while (0); log("NdpSetPathInfo <%s> (%s) %d %d\n", szPathName, path, rc, pConn->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; smb_request req = {0}; smb_response resp = {0}; char * path = NULL; FEALIST * pFEASrc; NDDATABUF fdata = {0}; smbwrp_fileinfo *finfo; 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 = checkconnection(pConn); if (rc) { break; } StrNCpy(pConn->mem, path, CCHMAXPATH); req.request = SMBREQ_LISTEA; req.param = pConn->mem; req.paramlen = CCHMAXPATH + 1; req.length = pRes->memlen - req.paramlen; pFEASrc = (FEALIST *)(pConn->mem + req.paramlen); pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.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("NdpEAQuery <%s> %d %d %d %d %d\n", pfi->pszName, rc, pFEASrc->cbList, pFEAList->cbList, pConn->rc, resp.rc); return rc; } int APIENTRY NdpEASet (HCONNECTION conn, FEALIST *pFEAList, NDFILEINFOL *pfi) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; smb_request req = {0}; smb_response resp = {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; } if (pFEAList->cbList > pRes->memlen) { return ERROR_NOT_ENOUGH_MEMORY; } 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 { rc = checkconnection(pConn); if (rc) { break; } StrNCpy(pConn->mem, path, CCHMAXPATH); MemCpy(pConn->mem + CCHMAXPATH + 1, pFEAList, pFEAList->cbList); req.request = SMBREQ_SETEA; req.param = pConn->mem; req.paramlen = pFEAList->cbList + CCHMAXPATH + 1; req.length = req.paramlen; pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } } 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; smb_request req = {0}; smb_response resp = {0}; char * path = NULL; FEALIST * pfealist; NDDATABUF fdata = {0}; smbwrp_fileinfo *finfo; 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 = checkconnection(pConn); if (rc) { break; } StrNCpy(pConn->mem, path, CCHMAXPATH); req.request = SMBREQ_LISTEA; req.param = pConn->mem; req.paramlen = CCHMAXPATH + 1; req.length = pRes->memlen - req.paramlen; pfealist = (FEALIST *)(pConn->mem + req.paramlen); pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.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 %d %d\n", pfi->pszName, *pulEASize, rc, pConn->rc, resp.rc); return rc; } int APIENTRY NdpSetCurrentDir (HCONNECTION conn, NDFILEINFOL *pfi, char *szPath) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; smb_request req = {0}; smb_response resp = {0}; int rc = 0; unsigned long action; char path[CCHMAXPATH+1] = {0}; log("NdpSetCurrentDir in\n"); do { rc = checkconnection(pConn); if (rc) { break; } rc = pathparser(pRes, pConn, szPath, path); if (rc) { break; } StrNCpy(pConn->mem, path, CCHMAXPATH); req.request = SMBREQ_CHDIR; req.param = pConn->mem; req.paramlen = CCHMAXPATH + 1; req.length = req.paramlen; pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } } while (0); log("NdpSetCurrentDir <%s> (%s) %d %d\n", szPath, path, rc, pConn->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; smb_request req = {0}; smb_response resp = {0}; int rc = 0; unsigned long action; char path[CCHMAXPATH+1] = {0}; log("NdpForceDelete in\n"); do { rc = checkconnection(pConn); if (rc) { break; } rc = pathparser(pRes, pConn, szFile, path); if (rc) { break; } StrNCpy(pConn->mem, path, CCHMAXPATH); req.request = SMBREQ_UNLINK; req.param = pConn->mem; req.paramlen = CCHMAXPATH + 1; req.length = req.paramlen; pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } } while (0); log("NdpForceDelete <%s> (%s) %d %d\n", szFile, path, rc, pConn->rc); return rc; } int APIENTRY NdpCreateDir (HCONNECTION conn, NDFILEINFOL *pfiparent, char *szDirName, FEALIST *pFEAList) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; smb_request req = {0}; smb_response resp = {0}; int rc = 0; unsigned long action; char path[CCHMAXPATH+1] = {0}; log("NdpCreateDir in\n"); do { rc = checkconnection(pConn); if (rc) { break; } rc = pathparser(pRes, pConn, szDirName, path); if (rc) { break; } StrNCpy(pConn->mem, path, CCHMAXPATH); req.request = SMBREQ_MKDIR; req.param = pConn->mem; req.paramlen = CCHMAXPATH + 1; req.length = req.paramlen; pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } } while (0); log("NdpCreateDir <%s> (%s) %d %d\n", szDirName, path, rc, pConn->rc); return rc; } int APIENTRY NdpDeleteDir (HCONNECTION conn, NDFILEINFOL *pfi, char *szDir) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; smb_request req = {0}; smb_response resp = {0}; int rc = 0; unsigned long action; char path[CCHMAXPATH+1] = {0}; log("NdpDeleteDir in\n"); do { rc = checkconnection(pConn); if (rc) { break; } rc = pathparser(pRes, pConn, szDir, path); if (rc) { break; } StrNCpy(pConn->mem, path, CCHMAXPATH); req.request = SMBREQ_RMDIR; req.param = pConn->mem; req.paramlen = CCHMAXPATH + 1; req.length = req.paramlen; pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } } while (0); log("NdpDeleteDir <%s> (%s) %d %d\n", szDir, path, rc, pConn->rc); return rc; } int APIENTRY NdpMove (HCONNECTION conn, NDFILEINFOL *pfiDst, char *szDst, NDFILEINFOL *pfiSrc, char *szSrc) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; smb_request req = {0}; smb_response resp = {0}; int rc = 0; unsigned long action; char src[CCHMAXPATH+1] = {0}; int l1, l2; char * p = szDst; log("NdpMove in\n"); do { rc = checkconnection(pConn); if (rc) { break; } 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; } StrNCpy(pConn->mem, src, CCHMAXPATH); pConn->mem[CCHMAXPATH + 1] = '\\'; StrNCpy(pConn->mem + CCHMAXPATH + 2, p, CCHMAXPATH - 1); req.request = SMBREQ_RENAME; req.param = pConn->mem; req.paramlen = 2 * (CCHMAXPATH + 1); req.length = req.paramlen; pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } } while (0); log("NdpMove <%s> -> <%s> (%s) %d %d\n", szSrc, szDst, src, rc, pConn->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; smb_request req = {0}; smb_response resp = {0}; 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 = checkconnection(pConn); if (rc) { 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; MemCpy(pConn->mem, &pConn->file, sizeof(pConn->file)); req.request = SMBREQ_OPEN; req.param = pConn->mem; req.paramlen = sizeof(pConn->file); req.length = req.paramlen; pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } else { MemCpy(&pConn->file, pConn->mem, sizeof(pConn->file)); } } while (0); log("smbopen <%s> (%s) %08x %08x %08x %d %d. file = %d\n", szFileName, path, flags, ulOpenMode, ulAttribute, rc, pConn->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; smb_request req = {0}; smb_response resp = {0}; smbwrp_fileinfo * finfo = (smbwrp_fileinfo *)pConn->mem; char path[CCHMAXPATH+1] = {0}; log("NdpSetFileAttribute in\n"); do { rc = checkconnection(pConn); if (rc) { break; } 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; req.request = SMBREQ_SETINFO; req.param = pConn->mem; req.paramlen = sizeof(*finfo); req.length = req.paramlen; pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } } while (0); log("NdpSetFileAttribute <%s> (%s) %04x %d %d\n", szFileName, path, usAttr, rc, pConn->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; smb_request req = {0}; smb_response resp = {0}; FILEFINDBUF3 buf; smbwrp_fileinfo * finfo = (smbwrp_fileinfo *)(pConn->mem + sizeof(pConn->file)); debug_printf("NdpFileQueryInfo in\n"); do { if (pConn->file.fd < 0 || !*pConn->file.fname) { rc = ERROR_INVALID_HANDLE; break; } if (pConn->rc) { rc = ERROR_PIPE_NOT_CONNECTED; break; } MemCpy(pConn->mem, &pConn->file, sizeof(pConn->file)); StrNCpy(finfo->fname, pConn->file.fname, sizeof(finfo->fname) - 1); req.request = SMBREQ_FGETINFO; req.param = pConn->mem; req.paramlen = sizeof(pConn->file); req.length = req.paramlen + sizeof(*finfo); rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } else { finfo->easize = -1; if (ifL) { getfindinfoL(pConn, plist, finfo, 0, NULL); } else { getfindinfo(pConn, &buf, finfo); ph->fsphAddFileFind32(plist, &buf, finfo, sizeof(*finfo), 0); } } } while (0); log("NdpFileQueryInfo <%s> %d %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, rc, pConn->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; smb_request req = {0}; smb_response resp = {0}; 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; } if (pConn->rc) { rc = ERROR_PIPE_NOT_CONNECTED; break; } MemCpy(pConn->mem, &pConn->file, sizeof(pConn->file)); req.request = SMBREQ_FLISTEA; req.param = pConn->mem; req.paramlen = sizeof(pConn->file); req.length = pRes->memlen - req.paramlen; pFEASrc = (FEALIST *)(pConn->mem + req.paramlen); pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.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 %d %d\n", pConn->file.fname, pConn->file.fd, pFEASrc->cbList, pFEAList->cbList, rc, pConn->rc, resp.rc); return rc; } int APIENTRY NdpFileEASet (HCONNECTION conn, NDFILEHANDLE handle, FEALIST *pFEAList) { Connection *pConn = (Connection *)conn; Resource *pRes = pConn->pRes; int rc = 0; smb_request req = {0}; smb_response resp = {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; } if (pFEAList->cbList > pRes->memlen) { return ERROR_NOT_ENOUGH_MEMORY; } do { if (pConn->file.fd < 0) { rc = ERROR_INVALID_HANDLE; break; } if (pConn->rc) { rc = ERROR_PIPE_NOT_CONNECTED; break; } MemCpy(pConn->mem, &pConn->file, sizeof(pConn->file)); MemCpy(pConn->mem + sizeof(pConn->file), pFEAList, pFEAList->cbList); req.request = SMBREQ_FSETEA; req.param = pConn->mem; req.paramlen = pFEAList->cbList + sizeof(pConn->file); req.length = req.paramlen; pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } } 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; smb_request req = {0}; smb_response resp = {0}; char path[CCHMAXPATH+1] = {0}; FEALIST * pfealist; 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; } if (pConn->rc) { rc = ERROR_PIPE_NOT_CONNECTED; break; } MemCpy(pConn->mem, &pConn->file, sizeof(pConn->file)); req.request = SMBREQ_FLISTEA; req.param = pConn->mem; req.paramlen = sizeof(pConn->file); req.length = pRes->memlen - req.paramlen; pfealist = (FEALIST *)(pConn->mem + req.paramlen); pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.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 %d %d\n", *pulEASize, rc, pConn->rc, resp.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; smb_request req = {0}; smb_response resp = {0}; smbwrp_fileinfo * finfo = (smbwrp_fileinfo *)pConn->mem; debug_printf("NdpFileSetInfo in\n"); do { if (pConn->file.fd < 0 || !*pConn->file.fname) { rc = ERROR_INVALID_HANDLE; break; } if (pConn->rc) { rc = ERROR_PIPE_NOT_CONNECTED; break; } if (ifL) { attrFile = pfi->stat.attrFile; } else { FILESTATUS3 * stat = (FILESTATUS3 *)&(pfi->stat); attrFile = 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 %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, attrFile, rc, pConn->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; smb_request req = {0}; smb_response resp = {0}; log("NdpFileSetFilePtrl in\n"); do { if (pConn->file.fd < 0) { rc = ERROR_INVALID_HANDLE; break; } if (pConn->rc) { rc = ERROR_PIPE_NOT_CONNECTED; break; } MemCpy(pConn->mem, &pConn->file, sizeof(pConn->file)); *(unsigned long *)(pConn->mem + sizeof(pConn->file)) = ulMethod; *(long long *)(pConn->mem + sizeof(pConn->file) + sizeof(long)) = llOffset; req.request = SMBREQ_LSEEK; req.param = pConn->mem; req.paramlen = sizeof(pConn->file) + sizeof(long) + sizeof(long long); req.length = req.paramlen; pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } else { MemCpy(&pConn->file, pConn->mem, sizeof(pConn->file)); *pllActual = pConn->file.offset; } } while (0); log("NdpFileSetFilePtrL <%s> %lld %lu %lld %d %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, llOffset, ulMethod, *pllActual, rc, pConn->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; smb_request req = {0}; smb_response resp = {0}; 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; } if (pConn->rc) { rc = ERROR_PIPE_NOT_CONNECTED; break; } MemCpy(pConn->mem, &pConn->file, sizeof(pConn->file)); req.request = SMBREQ_CLOSE; req.param = pConn->mem; req.length = pRes->memlen; req.paramlen = sizeof(pConn->file); req.length = req.paramlen; pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } else { MemCpy(&pConn->file, pConn->mem, sizeof(pConn->file)); } } while (0); log("NdpFileClose %d %d %d\n", pConn->file.fd, rc, pConn->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; smb_request req = {0}; smb_response resp = {0}; log("NdpFileNewSizeL in\n"); do { if (pConn->file.fd < 0) { rc = ERROR_INVALID_HANDLE; break; } if (pConn->rc) { rc = ERROR_PIPE_NOT_CONNECTED; break; } MemCpy(pConn->mem, &pConn->file, sizeof(pConn->file)); *(long long *)(pConn->mem + sizeof(pConn->file)) = llLen; req.request = SMBREQ_NEWSIZE; req.param = pConn->mem; req.paramlen = sizeof(pConn->file) + sizeof(long long); req.length = req.paramlen; pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); } else { MemCpy(&pConn->file, pConn->mem, sizeof(pConn->file)); } } while (0); log("NdpFileNewSizeL <%s> %lld %d %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, llLen, rc, pConn->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; smb_request req = {0}; smb_response resp = {0}; log("NdpFileRead in\n"); // log("NdpFileRead <%s> %lu\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, ulRead); do { if (pConn->file.fd < 0) { rc = ERROR_INVALID_HANDLE; break; } if (pConn->rc) { rc = ERROR_PIPE_NOT_CONNECTED; break; } MemCpy(pConn->mem, &pConn->file, sizeof(pConn->file)); req.request = SMBREQ_READ; req.param = pConn->mem; req.paramlen = sizeof(pConn->file); while (done < ulRead) { req.length = req.paramlen + (pRes->memlen - req.paramlen < (ulRead - done) ? pRes->memlen - req.paramlen : (ulRead - done)); pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); break; } if (resp.value == 0) { break; } onedone = resp.value > req.length ? req.length : resp.value; MemCpy((char *)pBuffer + done, pConn->mem + sizeof(pConn->file), onedone); done += onedone; } MemCpy(&pConn->file, pConn->mem, sizeof(pConn->file)); *pulActual = done; } while (0); log("NdpFileRead <%s> %lu %lu %d %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, ulRead, *pulActual, rc, pConn->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; smb_request req = {0}; smb_response resp = {0}; log("NdpFileWrite in\n"); do { if (pConn->file.fd < 0) { rc = ERROR_INVALID_HANDLE; break; } if (pConn->rc) { rc = ERROR_PIPE_NOT_CONNECTED; break; } MemCpy(pConn->mem, &pConn->file, sizeof(pConn->file)); req.request = SMBREQ_WRITE; req.param = pConn->mem; req.paramlen = sizeof(pConn->file); while (done < ulWrite) { req.length = pRes->memlen - req.paramlen < (ulWrite - done) ? pRes->memlen - req.paramlen : (ulWrite - done); MemCpy(pConn->mem + sizeof(pConn->file), (char *)pBuffer + done, req.length); req.length += req.paramlen; pConn->rc = _DosTransactNPipe(pConn, &req, sizeof(req), &resp, sizeof(resp), &action); if (pConn->rc || action < sizeof(resp) || resp.rc) { rc = pConn->rc ? pConn->rc : (resp.rc ? resp.rc : ERROR_INVALID_PARAMETER); break; } done += resp.value & 0xFFFFFFFF; if (resp.value < req.length) { break; } } MemCpy(&pConn->file, pConn->mem, sizeof(pConn->file)); *pulActual = done; } while (0); log("NdpFileWrite <%s> %lu %lu %d %d\n", pConn->file.fd < 0 ? "!null!" : pConn->file.fname, ulWrite, *pulActual, rc, pConn->rc); return rc; }