add cifsd
This commit is contained in:
parent
7dfb8b6ec5
commit
4b550911d9
16 changed files with 4439 additions and 0 deletions
105
sys/man/8/cifsd
Normal file
105
sys/man/8/cifsd
Normal file
|
@ -0,0 +1,105 @@
|
|||
.TH cifsd 8
|
||||
.SH NAME
|
||||
cifsd \- CIFS/SMB network daemon
|
||||
.SH SYNOPSIS
|
||||
.B ip/cifsd
|
||||
[
|
||||
.B -t
|
||||
] [
|
||||
.B -d
|
||||
] [
|
||||
.B -f
|
||||
.I debuglog
|
||||
] [
|
||||
.B -w
|
||||
.I name
|
||||
] [
|
||||
.B -o
|
||||
.I option
|
||||
] ... [
|
||||
.I conndir
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.I Cifsd
|
||||
exports filesystems to
|
||||
.SM CIFS or
|
||||
.SM SMB
|
||||
clients like Microsoft \(tm Windows.
|
||||
.PP
|
||||
It is normally started by the network listen process via the
|
||||
.B /rc/bin/service/tcp445
|
||||
service script (see
|
||||
.IR listen (8)),
|
||||
wich passes
|
||||
.I conndir
|
||||
and filedescriptors 0 and 1 to the incoming connection.
|
||||
.PP
|
||||
Users are authenticated by ther Inferno/pop secret held by the auth server.
|
||||
When successfull,
|
||||
.I cifsd
|
||||
changes its user id and namespace to the authenticated user.
|
||||
Informative log messages are appended to
|
||||
.B /sys/log/cifsd
|
||||
if it exists.
|
||||
.PP
|
||||
By default the share
|
||||
.B local
|
||||
is offered, which represents the root of the namespace
|
||||
described by
|
||||
.B /lib/namespace.
|
||||
If a different name is explicitly requested by the client then
|
||||
.B /bin/9fs
|
||||
(see
|
||||
.IR srv (4))
|
||||
is invoked to attach that filesystem, which is then exported instead.
|
||||
.PP
|
||||
The flags are:
|
||||
.TP
|
||||
.B t
|
||||
Run the server in trusted mode, so it will not require
|
||||
authentication from the client and keep running in the callers
|
||||
namespace.
|
||||
.TP
|
||||
.B d
|
||||
Enable or increases debug verbosity for the
|
||||
.I debuglog
|
||||
file. Debug messages are never written to the system logfile.
|
||||
.TP
|
||||
.B f
|
||||
Specify the filename for the
|
||||
.I debuglog
|
||||
file. If not specified no debug messages are generated.
|
||||
.TP
|
||||
.B w
|
||||
Set the workgroup (or primary domain) to
|
||||
.I name. The default is
|
||||
.SM WORKGROUP
|
||||
.TP
|
||||
.B o
|
||||
Enables the following
|
||||
.I option
|
||||
string.
|
||||
This flag can appear multiple times when more than one option has to
|
||||
be enabled. Valid options are:
|
||||
.RS
|
||||
.TP
|
||||
.B trspaces
|
||||
transforms whitespaces in filenames to non breaking whitespaces. This is usefull
|
||||
when exporting filesystems other than fossil.
|
||||
.TP
|
||||
.B casesensitive
|
||||
By default, filename lookups are done case insensitive to match
|
||||
windows filesystem sematics. This option disables case insensitive
|
||||
lookups wich can result in a performance improvement, but might break
|
||||
some applications.
|
||||
.SH FILES
|
||||
.B /rc/bin/service/tcp445
|
||||
.br
|
||||
.B /sys/log/cifsd
|
||||
.br
|
||||
.B /lib/namespace
|
||||
.SH SOURCE
|
||||
.B /sys/src/cmd/ip/cifsd
|
||||
.SH "SEE ALSO"
|
||||
.IR listen (8),
|
||||
.IR srv (4)
|
20
sys/src/cmd/ip/cifsd/README
Normal file
20
sys/src/cmd/ip/cifsd/README
Normal file
|
@ -0,0 +1,20 @@
|
|||
look at the cifsd.man manpage for instrctions.
|
||||
|
||||
check for new releases on the web:
|
||||
http://9hal.ath.cx/usr/cinap_lenrek/cifsd.tgz
|
||||
http://9hal.ath.cx/usr/cinap_lenrek/
|
||||
|
||||
or on sources:
|
||||
/n/sources/contrib/cinap_lenrek/cifsd.tgz
|
||||
/n/sources/contrib/cinap_lenrek
|
||||
|
||||
you can email me for requests/bugreports/contrib at:
|
||||
cinap_lenrek AT gmx DOT de
|
||||
|
||||
special thanks goes to:
|
||||
|
||||
capso (http://nanosouffle.net/)
|
||||
for testing and bug reporting
|
||||
|
||||
steve simon (http://quintile.net/)
|
||||
factotum/authsrv support for NTLM auth and cifsd testing and bug reporting
|
232
sys/src/cmd/ip/cifsd/dat.h
Normal file
232
sys/src/cmd/ip/cifsd/dat.h
Normal file
|
@ -0,0 +1,232 @@
|
|||
typedef struct Rop Rop;
|
||||
typedef struct Req Req;
|
||||
typedef struct Trans Trans;
|
||||
|
||||
typedef struct Share Share;
|
||||
typedef struct File File;
|
||||
typedef struct Find Find;
|
||||
typedef struct Tree Tree;
|
||||
|
||||
struct Rop
|
||||
{
|
||||
int (*strpack)(uchar *, uchar *, uchar *, void *);
|
||||
int (*strunpack)(uchar *, uchar *, uchar *, void *);
|
||||
int (*namepack)(uchar *, uchar *, uchar *, void *);
|
||||
int (*nameunpack)(uchar *, uchar *, uchar *, void *);
|
||||
int (*untermstrpack)(uchar *, uchar *, uchar *, void *);
|
||||
int (*untermnamepack)(uchar *, uchar *, uchar *, void *);
|
||||
};
|
||||
|
||||
struct Req
|
||||
{
|
||||
int cmd;
|
||||
int tid;
|
||||
int pid;
|
||||
int uid;
|
||||
int mid;
|
||||
int flags;
|
||||
int flags2;
|
||||
|
||||
uchar sig[8];
|
||||
|
||||
uchar *lh, *rh, *rp, *re;
|
||||
|
||||
Rop *o;
|
||||
char *name;
|
||||
void (*respond)(Req *r, int err);
|
||||
int (*namecmp)(char *, char *);
|
||||
};
|
||||
|
||||
struct Trans
|
||||
{
|
||||
int cmd;
|
||||
int flags;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
uchar *b, *p, *e;
|
||||
} param, data, setup;
|
||||
} in, out;
|
||||
|
||||
Req *r;
|
||||
Rop *o;
|
||||
char *name;
|
||||
void (*respond)(Trans *t, int err);
|
||||
int (*namecmp)(char *, char *);
|
||||
};
|
||||
|
||||
struct File
|
||||
{
|
||||
int ref;
|
||||
int fd;
|
||||
int rtype;
|
||||
int dacc;
|
||||
char *path;
|
||||
void *aux;
|
||||
};
|
||||
|
||||
struct Find
|
||||
{
|
||||
int ref;
|
||||
int attr;
|
||||
char *base;
|
||||
char *pattern;
|
||||
int casesensitive;
|
||||
int index;
|
||||
Dir *dotdot;
|
||||
Dir *dot;
|
||||
Dir *dir;
|
||||
int ndir;
|
||||
};
|
||||
|
||||
struct Share
|
||||
{
|
||||
Share *next;
|
||||
|
||||
char *service;
|
||||
int stype;
|
||||
|
||||
char *name;
|
||||
char *root;
|
||||
char *remark;
|
||||
|
||||
char *fsname;
|
||||
int namelen;
|
||||
vlong allocsize;
|
||||
vlong freesize;
|
||||
int sectorsize;
|
||||
int blocksize;
|
||||
};
|
||||
|
||||
struct Tree
|
||||
{
|
||||
int tid;
|
||||
|
||||
void **file;
|
||||
int nfile;
|
||||
|
||||
void **find;
|
||||
int nfind;
|
||||
|
||||
Share *share;
|
||||
};
|
||||
|
||||
int debug;
|
||||
int trspaces;
|
||||
int needauth;
|
||||
char *domain;
|
||||
char *progname;
|
||||
char *osname;
|
||||
|
||||
char *remotesys;
|
||||
char *remoteuser;
|
||||
int remotebuffersize;
|
||||
|
||||
long starttime;
|
||||
int tzoff;
|
||||
|
||||
enum
|
||||
{
|
||||
BUFFERSIZE = 0x8000,
|
||||
|
||||
STATUS_INVALID_SMB = 0x00010002,
|
||||
STATUS_SMB_BAD_TID = 0x00050002,
|
||||
STATUS_SMB_BAD_FID = 0x00060001,
|
||||
STATUS_OS2_INVALID_ACCESS = 0x000C0001,
|
||||
STATUS_SMB_BAD_UID = 0x005B0002,
|
||||
STATUS_OS2_INVALID_LEVEL = 0x007C0001,
|
||||
STATUS_NO_MORE_FILES = 0x80000006,
|
||||
STATUS_INVALID_HANDLE = 0xC0000008,
|
||||
STATUS_NO_SUCH_FILE = 0xC000000F,
|
||||
STATUS_ACCESS_DENIED = 0xC0000022,
|
||||
STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034,
|
||||
STATUS_OBJECT_NAME_COLLISION = 0xC0000035,
|
||||
STATUS_OBJECT_PATH_INVALID = 0xC0000039,
|
||||
STATUS_OBJECT_PATH_NOT_FOUND = 0xC000003A,
|
||||
STATUS_OBJECT_PATH_SYNTAX_BAD = 0xC000003B,
|
||||
STATUS_SHARING_VIOLATION = 0xC0000043,
|
||||
STATUS_LOGON_FAILURE = 0xC000006D,
|
||||
STATUS_FILE_IS_A_DIRECTORY = 0xC00000BA,
|
||||
STATUS_NOT_SUPPORTED = 0xC00000BB,
|
||||
STATUS_BAD_DEVICE_TYPE = 0xC00000CB,
|
||||
STATUS_BAD_NETWORK_NAME = 0xC00000CC,
|
||||
STATUS_NOT_SAME_DEVICE = 0xC00000D4,
|
||||
STATUS_DIRECTORY_NOT_EMPTY = 0xC0000101,
|
||||
|
||||
/* resource type */
|
||||
FileTypeDisk = 0,
|
||||
|
||||
/* stype */
|
||||
STYPE_DISKTREE = 0,
|
||||
STYPE_PRINTQ = 1,
|
||||
STYPE_DEVICE = 2,
|
||||
STYPE_IPC = 3,
|
||||
|
||||
/* capabilities */
|
||||
CAP_UNICODE = 0x4,
|
||||
CAP_LARGEFILES = 0x8,
|
||||
CAP_NT_SMBS = 0x10,
|
||||
CAP_NT_STATUS = 0x40,
|
||||
CAP_NT_FIND = 0x200,
|
||||
|
||||
/* extended file attributes */
|
||||
ATTR_READONLY = 0x1,
|
||||
ATTR_HIDDEN = 0x2,
|
||||
ATTR_SYSTEM = 0x4,
|
||||
ATTR_DIRECTORY = 0x10,
|
||||
ATTR_ARCHIVE = 0x20,
|
||||
ATTR_NORMAL = 0x80,
|
||||
|
||||
DOSMASK = 0x37,
|
||||
|
||||
/* access */
|
||||
FILE_READ_DATA = 0x1,
|
||||
FILE_WRITE_DATA = 0x2,
|
||||
FILE_APPEND_DATA = 0x4,
|
||||
FILE_EXECUTE = 0x20,
|
||||
FILE_DELETE = 0x10000,
|
||||
GENERIC_ALL = 0x10000000,
|
||||
GENERIC_EXECUTE = 0x20000000,
|
||||
GENERIC_WRITE = 0x40000000,
|
||||
GENERIC_READ = 0x80000000,
|
||||
|
||||
READMASK =
|
||||
FILE_READ_DATA |
|
||||
FILE_EXECUTE |
|
||||
GENERIC_ALL |
|
||||
GENERIC_EXECUTE |
|
||||
GENERIC_READ,
|
||||
|
||||
WRITEMASK =
|
||||
FILE_WRITE_DATA |
|
||||
FILE_APPEND_DATA |
|
||||
GENERIC_ALL |
|
||||
GENERIC_WRITE,
|
||||
|
||||
/* share access */
|
||||
FILE_SHARE_NONE = 0,
|
||||
FILE_SHARE_READ = 1,
|
||||
FILE_SHARE_WRITE = 2,
|
||||
FILE_SHARE_DELETE = 4,
|
||||
FILE_SHARE_COMPAT = -1,
|
||||
|
||||
/* createdisposition */
|
||||
FILE_SUPERSEDE = 0,
|
||||
FILE_OPEN,
|
||||
FILE_CREATE,
|
||||
FILE_OPEN_IF,
|
||||
FILE_OVERWRITE,
|
||||
FILE_OVERWRITE_IF,
|
||||
|
||||
/* createaction */
|
||||
FILE_SUPERSEDED = 0,
|
||||
FILE_OPEND,
|
||||
FILE_CREATED,
|
||||
FILE_OVERWRITTEN,
|
||||
|
||||
/* createoptions */
|
||||
FILE_DIRECTORY_FILE = 0x1,
|
||||
FILE_NON_DIRECTORY_FILE = 0x40,
|
||||
FILE_DELETE_ON_CLOSE = 0x1000,
|
||||
FILE_OPEN_BY_FILE_ID = 0x2000,
|
||||
};
|
218
sys/src/cmd/ip/cifsd/dir.c
Normal file
218
sys/src/cmd/ip/cifsd/dir.c
Normal file
|
@ -0,0 +1,218 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static char*
|
||||
append(char **p, char *s)
|
||||
{
|
||||
int n;
|
||||
char *o;
|
||||
|
||||
if(s == nil)
|
||||
return nil;
|
||||
n = strlen(s)+1;
|
||||
memmove(o = *p, s, n);
|
||||
*p += n;
|
||||
return o;
|
||||
}
|
||||
|
||||
static Dir*
|
||||
xdirdup(Dir *d, int n)
|
||||
{
|
||||
char *p;
|
||||
Dir *o;
|
||||
int i;
|
||||
|
||||
p = nil;
|
||||
for(i=0; i<n; i++){
|
||||
p += strlen(d[i].name)+1;
|
||||
if(d[i].uid) p += strlen(d[i].uid)+1;
|
||||
if(d[i].gid) p += strlen(d[i].gid)+1;
|
||||
if(d[i].muid) p += strlen(d[i].muid)+1;
|
||||
}
|
||||
o = malloc(n*sizeof(*d) + (int)p);
|
||||
memmove(o, d, n*sizeof(*d));
|
||||
p = (char*)&o[n];
|
||||
for(i=0; i<n; i++){
|
||||
o[i].name = append(&p, d[i].name);
|
||||
o[i].uid = append(&p, d[i].uid);
|
||||
o[i].gid = append(&p, d[i].gid);
|
||||
o[i].muid = append(&p, d[i].muid);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
static int xdirread0(char **path, int (*namecmp)(char *, char *), Dir **d);
|
||||
|
||||
int
|
||||
xdirread(char **path, int (*namecmp)(char *, char *), Dir **d)
|
||||
{
|
||||
Dir *t;
|
||||
int n;
|
||||
|
||||
if((n = xdirread0(path, namecmp, &t)) > 0)
|
||||
*d = xdirdup(t, n);
|
||||
else
|
||||
*d = nil;
|
||||
return n;
|
||||
}
|
||||
|
||||
static Dir*
|
||||
xdirstat0(char **path, int (*namecmp)(char *, char *), char *err)
|
||||
{
|
||||
char *base, *name;
|
||||
Dir *d, *t;
|
||||
int n, i;
|
||||
|
||||
if(d = dirstat(*path))
|
||||
return d;
|
||||
if(!splitpath(*path, &base, &name))
|
||||
return nil;
|
||||
if((n = xdirread0(&base, namecmp, &t)) < 0)
|
||||
goto out;
|
||||
for(i=0; i<n; i++){
|
||||
if(namecmp(t[i].name, name))
|
||||
continue;
|
||||
free(*path); *path = conspath(base, t[i].name);
|
||||
d = xdirdup(&t[i], 1);
|
||||
goto out;
|
||||
}
|
||||
werrstr("%s", err);
|
||||
out:
|
||||
free(base);
|
||||
free(name);
|
||||
return d;
|
||||
}
|
||||
|
||||
Dir*
|
||||
xdirstat(char **path, int (*namecmp)(char *, char *))
|
||||
{
|
||||
return xdirstat0(path, namecmp, "name not found");
|
||||
}
|
||||
|
||||
typedef struct XDir XDir;
|
||||
struct XDir
|
||||
{
|
||||
Qid qid;
|
||||
char *path;
|
||||
int ndir;
|
||||
Dir *dir;
|
||||
XDir *next;
|
||||
};
|
||||
|
||||
static void
|
||||
freexdir(XDir *x)
|
||||
{
|
||||
free(x->path);
|
||||
free(x->dir);
|
||||
free(x);
|
||||
}
|
||||
|
||||
static int
|
||||
qidcmp(Qid *q1, Qid *q2)
|
||||
{
|
||||
return (q1->type != q2->type) || (q1->path != q2->path) || (q1->vers != q2->vers);
|
||||
}
|
||||
|
||||
static XDir *xdirlist;
|
||||
static int xdircount;
|
||||
|
||||
static int
|
||||
xdirread0(char **path, int (*namecmp)(char *, char *), Dir **d)
|
||||
{
|
||||
XDir *x, *p;
|
||||
int fd, n;
|
||||
Dir *t;
|
||||
|
||||
t = nil;
|
||||
for(p = nil, x = xdirlist; x; p=x, x=x->next){
|
||||
if(namecmp(x->path, *path))
|
||||
continue;
|
||||
if(x == xdirlist)
|
||||
xdirlist = x->next;
|
||||
else
|
||||
p->next = x->next;
|
||||
while(t = dirstat(x->path)){
|
||||
if(qidcmp(&t->qid, &x->qid))
|
||||
break;
|
||||
free(t);
|
||||
x->next = xdirlist;
|
||||
xdirlist = x;
|
||||
if(strcmp(x->path, *path)){
|
||||
free(*path);
|
||||
*path = strdup(x->path);
|
||||
}
|
||||
if(d) *d = x->dir;
|
||||
return x->ndir;
|
||||
}
|
||||
xdircount--;
|
||||
freexdir(x);
|
||||
break;
|
||||
}
|
||||
if((fd = open(*path, OREAD)) < 0){
|
||||
free(t);
|
||||
if(t = xdirstat0(path, namecmp, "directory entry not found"))
|
||||
fd = open(*path, OREAD);
|
||||
} else if(t == nil)
|
||||
t = dirfstat(fd);
|
||||
|
||||
n = -1;
|
||||
if(fd < 0 || t == nil)
|
||||
goto out;
|
||||
if(t->qid.type != QTDIR){
|
||||
werrstr("not a directory");
|
||||
goto out;
|
||||
}
|
||||
if((n = dirreadall(fd, d)) < 0)
|
||||
goto out;
|
||||
|
||||
if(xdircount >= 8){
|
||||
xdircount--;
|
||||
for(p = xdirlist, x = xdirlist->next; x->next; p = x, x = x->next)
|
||||
;
|
||||
p->next = nil;
|
||||
freexdir(x);
|
||||
}
|
||||
|
||||
x = mallocz(sizeof(*x), 1);
|
||||
x->qid = t->qid;
|
||||
x->path = strdup(*path);
|
||||
x->ndir = n;
|
||||
x->dir = *d;
|
||||
|
||||
x->next = xdirlist;
|
||||
xdirlist = x;
|
||||
xdircount++;
|
||||
|
||||
out:
|
||||
if(fd >= 0)
|
||||
close(fd);
|
||||
free(t);
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
xdirflush(char *path, int (*namecmp)(char *, char *))
|
||||
{
|
||||
XDir **pp, **xx, *x;
|
||||
char *d, *s;
|
||||
int n;
|
||||
|
||||
n = strlen(path);
|
||||
if(s = strrchr(path, '/'))
|
||||
n = s - path;
|
||||
d = smprint("%.*s", n, path);
|
||||
s = malloc(++n);
|
||||
for(pp = &xdirlist; x = *pp; pp = xx){
|
||||
xx = &x->next;
|
||||
snprint(s, n, "%s", x->path);
|
||||
if(namecmp(d, s) == 0){
|
||||
*pp = *xx; xx = pp;
|
||||
xdircount--;
|
||||
freexdir(x);
|
||||
}
|
||||
}
|
||||
free(s);
|
||||
free(d);
|
||||
}
|
129
sys/src/cmd/ip/cifsd/error.c
Normal file
129
sys/src/cmd/ip/cifsd/error.c
Normal file
|
@ -0,0 +1,129 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
enum {
|
||||
/* error class */
|
||||
ERRDOS = 1,
|
||||
ERRSRV = 2,
|
||||
ERRHRD = 3,
|
||||
ERRCMD = 0xFF,
|
||||
|
||||
/* error codes */
|
||||
ERRbadfunc = 0x1,
|
||||
ERRbadfile = 0x2,
|
||||
ERRbadpath = 0x3,
|
||||
ERRnofids = 0x4,
|
||||
ERRnoaccess = 0x5,
|
||||
ERRbadfid = 0x6,
|
||||
ERRbadmcp = 0x7,
|
||||
ERRnomem = 0x8,
|
||||
ERRbadmem = 0x9,
|
||||
ERRbadenv = 0xA,
|
||||
ERRbadformat = 0xB,
|
||||
ERRbadaccess = 0xC,
|
||||
ERRbaddata = 0xD,
|
||||
ERRbaddrive = 0xF,
|
||||
ERRremcd = 0x10,
|
||||
ERRdiffdevice = 0x11,
|
||||
ERRnofiles = 0x12,
|
||||
ERRgeneral = 0x1F,
|
||||
ERRbadshare = 0x20,
|
||||
ERRlock = 0x21,
|
||||
ERReof = 0x26,
|
||||
ERRunsup = 0x32,
|
||||
ERRfilexists = 0x50,
|
||||
ERRinvalidparam = 0x57,
|
||||
ERRunknownlevel = 0x7C,
|
||||
ERRbadpipe = 0xE6,
|
||||
ERRinvnetname = 0x06,
|
||||
ERRreqnotaccep = 0x47,
|
||||
ERRnosuchshare = 0x43,
|
||||
ERRerror = 0x1,
|
||||
ERRbadpw = 0x2,
|
||||
ERRaccess = 0x4,
|
||||
ERRinvtid = 0x5,
|
||||
ERRinvdevice = 0x7,
|
||||
ERRbaduid = 0x5b,
|
||||
};
|
||||
|
||||
int
|
||||
doserror(int err)
|
||||
{
|
||||
#define SE(c,e) e<<16 | c
|
||||
static struct Ent {
|
||||
int error;
|
||||
int status;
|
||||
} tab[] = {
|
||||
SE(ERRSRV, ERRerror), STATUS_INVALID_SMB,
|
||||
SE(ERRSRV, ERRinvtid), STATUS_SMB_BAD_TID,
|
||||
SE(ERRDOS, ERRbadfid), STATUS_SMB_BAD_FID,
|
||||
SE(ERRDOS, ERRbadaccess), STATUS_OS2_INVALID_ACCESS,
|
||||
SE(ERRSRV, ERRbaduid), STATUS_SMB_BAD_UID,
|
||||
SE(ERRDOS, ERRunknownlevel), STATUS_OS2_INVALID_LEVEL,
|
||||
SE(ERRDOS, ERRnofiles), STATUS_NO_MORE_FILES,
|
||||
SE(ERRDOS, ERRbadfid), STATUS_INVALID_HANDLE,
|
||||
SE(ERRDOS, ERRnoaccess), STATUS_ACCESS_DENIED,
|
||||
SE(ERRDOS, ERRbadfile), STATUS_OBJECT_NAME_NOT_FOUND,
|
||||
SE(ERRDOS, ERRfilexists), STATUS_OBJECT_NAME_COLLISION,
|
||||
SE(ERRDOS, ERRbadpath), STATUS_OBJECT_PATH_INVALID,
|
||||
SE(ERRDOS, ERRbadpath), STATUS_OBJECT_PATH_NOT_FOUND,
|
||||
SE(ERRDOS, ERRbadpath), STATUS_OBJECT_PATH_SYNTAX_BAD,
|
||||
SE(ERRDOS, ERRbadshare), STATUS_SHARING_VIOLATION,
|
||||
SE(ERRSRV, ERRbadpw), STATUS_LOGON_FAILURE,
|
||||
SE(ERRDOS, ERRnoaccess), STATUS_FILE_IS_A_DIRECTORY,
|
||||
SE(ERRDOS, ERRunsup), STATUS_NOT_SUPPORTED,
|
||||
SE(ERRSRV, ERRinvdevice), STATUS_BAD_DEVICE_TYPE,
|
||||
SE(ERRSRV, ERRinvnetname), STATUS_BAD_NETWORK_NAME,
|
||||
SE(ERRDOS, ERRdiffdevice), STATUS_NOT_SAME_DEVICE,
|
||||
SE(ERRDOS, ERRremcd), STATUS_DIRECTORY_NOT_EMPTY,
|
||||
SE(ERRSRV, ERRerror), 0,
|
||||
};
|
||||
struct Ent *p;
|
||||
|
||||
for(p=tab; p->status; p++)
|
||||
if(p->status == err)
|
||||
break;
|
||||
return p->error;
|
||||
}
|
||||
|
||||
int
|
||||
smbmkerror(void)
|
||||
{
|
||||
static struct Ent {
|
||||
int status;
|
||||
char *str;
|
||||
} tab[] = {
|
||||
STATUS_ACCESS_DENIED, "permission denied",
|
||||
STATUS_ACCESS_DENIED, "access permission denied",
|
||||
STATUS_ACCESS_DENIED, "create prohibited",
|
||||
STATUS_ACCESS_DENIED, "mounted directory forbids creation",
|
||||
STATUS_DIRECTORY_NOT_EMPTY, "directory not empty",
|
||||
STATUS_NO_SUCH_FILE, "no such file",
|
||||
STATUS_OBJECT_NAME_NOT_FOUND, "name not found",
|
||||
STATUS_OBJECT_PATH_NOT_FOUND, "directory entry not found",
|
||||
STATUS_OBJECT_PATH_NOT_FOUND, "not a directory",
|
||||
STATUS_OBJECT_PATH_NOT_FOUND, "does not exist",
|
||||
STATUS_OBJECT_PATH_SYNTAX_BAD, "bad character",
|
||||
STATUS_OBJECT_PATH_SYNTAX_BAD, "file name syntax",
|
||||
STATUS_OBJECT_NAME_COLLISION, "file already exists",
|
||||
STATUS_FILE_IS_A_DIRECTORY, "is a directory",
|
||||
/* kenfs */
|
||||
STATUS_OBJECT_NAME_COLLISION, "create/wstat -- file exists",
|
||||
STATUS_ACCESS_DENIED, "wstat -- not owner",
|
||||
STATUS_ACCESS_DENIED, "wstat -- not in group",
|
||||
/* unknown error */
|
||||
STATUS_INVALID_SMB, nil,
|
||||
};
|
||||
char buf[ERRMAX];
|
||||
struct Ent *p;
|
||||
|
||||
rerrstr(buf, sizeof(buf));
|
||||
for(p = tab; p->str; p++)
|
||||
if(strstr(buf, p->str))
|
||||
break;
|
||||
if(debug)
|
||||
fprint(2, "smbmkerror: %s -> %lux\n", buf, (ulong)p->status);
|
||||
return p->status;
|
||||
}
|
319
sys/src/cmd/ip/cifsd/file.c
Normal file
319
sys/src/cmd/ip/cifsd/file.c
Normal file
|
@ -0,0 +1,319 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
typedef struct Opl Opl;
|
||||
struct Opl
|
||||
{
|
||||
int ref;
|
||||
ulong hash;
|
||||
char *path;
|
||||
Opl *next;
|
||||
File *locked;
|
||||
int dacc;
|
||||
int sacc;
|
||||
int delete;
|
||||
};
|
||||
|
||||
static Opl *locktab[64];
|
||||
|
||||
static Opl*
|
||||
getopl(char **path, int (*namecmp)(char *, char *), int dacc, int sacc)
|
||||
{
|
||||
Opl *opl, **pp;
|
||||
ulong h;
|
||||
|
||||
h = namehash(*path);
|
||||
for(pp = &locktab[h % nelem(locktab)]; *pp; pp=&((*pp)->next)){
|
||||
opl = *pp;
|
||||
if(namecmp(opl->path, *path))
|
||||
continue;
|
||||
if(sacc == FILE_SHARE_COMPAT){
|
||||
if(sacc != opl->sacc)
|
||||
return nil;
|
||||
if((opl->dacc | dacc) & WRITEMASK)
|
||||
return nil;
|
||||
} else {
|
||||
if(opl->sacc == FILE_SHARE_COMPAT)
|
||||
return nil;
|
||||
if((dacc & READMASK) && (opl->sacc & FILE_SHARE_READ)==0)
|
||||
return nil;
|
||||
if((dacc & WRITEMASK) && (opl->sacc & FILE_SHARE_WRITE)==0)
|
||||
return nil;
|
||||
if((dacc & FILE_DELETE) && (opl->sacc & FILE_SHARE_DELETE)==0)
|
||||
return nil;
|
||||
}
|
||||
opl->ref++;
|
||||
if(strcmp(opl->path, *path)){
|
||||
free(*path);
|
||||
*path = strdup(opl->path);
|
||||
}
|
||||
return opl;
|
||||
}
|
||||
|
||||
opl = mallocz(sizeof(*opl), 1);
|
||||
opl->ref = 1;
|
||||
opl->hash = h;
|
||||
opl->dacc = dacc;
|
||||
opl->sacc = sacc;
|
||||
*pp = opl;
|
||||
return opl;
|
||||
}
|
||||
|
||||
static void
|
||||
putopl(Opl *opl)
|
||||
{
|
||||
Opl **pp;
|
||||
|
||||
if(opl==nil || --opl->ref)
|
||||
return;
|
||||
for(pp = &locktab[opl->hash % nelem(locktab)]; *pp; pp=&((*pp)->next)){
|
||||
if(*pp == opl){
|
||||
*pp = opl->next;
|
||||
opl->next = nil;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(opl->path && opl->delete){
|
||||
if(debug)
|
||||
fprint(2, "remove on close: %s\n", opl->path);
|
||||
if(remove(opl->path) < 0)
|
||||
logit("remove %s: %r", opl->path);
|
||||
}
|
||||
free(opl->path);
|
||||
free(opl);
|
||||
}
|
||||
|
||||
File*
|
||||
createfile(char *path, int (*namecmp)(char *, char *),
|
||||
int dacc, int sacc, int cdisp, int copt, vlong csize, int fattr, int *pact, Dir **pdir, int *perr)
|
||||
{
|
||||
int err, act, fd, mode, perm, isdir, delete;
|
||||
Opl *o;
|
||||
File *f;
|
||||
Dir *d;
|
||||
|
||||
o = nil;
|
||||
f = nil;
|
||||
d = nil;
|
||||
fd = -1;
|
||||
path = strdup(path);
|
||||
|
||||
if(copt & FILE_OPEN_BY_FILE_ID){
|
||||
unsup:
|
||||
err = STATUS_NOT_SUPPORTED;
|
||||
goto out;
|
||||
}
|
||||
if((o = getopl(&path, namecmp, dacc, sacc)) == nil){
|
||||
err = STATUS_SHARING_VIOLATION;
|
||||
goto out;
|
||||
}
|
||||
mode = -1;
|
||||
if(dacc & READMASK)
|
||||
mode += 1;
|
||||
if(dacc & WRITEMASK)
|
||||
mode += 2;
|
||||
delete = isdir = 0;
|
||||
if(d = xdirstat(&path, namecmp)){
|
||||
if(mode >= 0 && d->type != '/' && d->type != 'M'){
|
||||
noaccess:
|
||||
err = STATUS_ACCESS_DENIED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
isdir = d->qid.type == QTDIR;
|
||||
switch(cdisp){
|
||||
case FILE_SUPERSEDE:
|
||||
act = FILE_SUPERSEDED;
|
||||
if(remove(path) < 0){
|
||||
logit("remove: %r");
|
||||
oserror:
|
||||
err = smbmkerror();
|
||||
goto out;
|
||||
}
|
||||
goto docreate;
|
||||
case FILE_OVERWRITE:
|
||||
case FILE_OVERWRITE_IF:
|
||||
act = FILE_OVERWRITTEN;
|
||||
if(isdir || (mode != OWRITE && mode != ORDWR))
|
||||
goto noaccess;
|
||||
d->length = 0;
|
||||
mode |= OTRUNC;
|
||||
break;
|
||||
case FILE_OPEN:
|
||||
case FILE_OPEN_IF:
|
||||
act = FILE_OPEND;
|
||||
break;
|
||||
case FILE_CREATE:
|
||||
err = STATUS_OBJECT_NAME_COLLISION;
|
||||
goto out;
|
||||
default:
|
||||
goto unsup;
|
||||
}
|
||||
if((copt & FILE_DIRECTORY_FILE) && !isdir)
|
||||
goto noaccess;
|
||||
if((copt & FILE_NON_DIRECTORY_FILE) && isdir){
|
||||
err = STATUS_FILE_IS_A_DIRECTORY;
|
||||
goto out;
|
||||
}
|
||||
if(copt & FILE_DELETE_ON_CLOSE){
|
||||
if(isdir || (dacc & FILE_DELETE)==0)
|
||||
goto noaccess;
|
||||
delete = 1;
|
||||
}
|
||||
if(mode >= 0 && !isdir)
|
||||
if((fd = open(path, mode)) < 0)
|
||||
goto oserror;
|
||||
} else {
|
||||
switch(cdisp){
|
||||
case FILE_SUPERSEDE:
|
||||
case FILE_CREATE:
|
||||
case FILE_OPEN_IF:
|
||||
case FILE_OVERWRITE_IF:
|
||||
act = FILE_CREATED;
|
||||
break;
|
||||
case FILE_OVERWRITE:
|
||||
case FILE_OPEN:
|
||||
err = smbmkerror();
|
||||
goto out;
|
||||
default:
|
||||
goto unsup;
|
||||
}
|
||||
|
||||
docreate:
|
||||
perm = 0666;
|
||||
if(fattr & ATTR_READONLY)
|
||||
perm &= ~0222;
|
||||
if(copt & FILE_DIRECTORY_FILE){
|
||||
perm |= DMDIR | 0111;
|
||||
mode = OREAD;
|
||||
isdir = 1;
|
||||
}
|
||||
if(mode < 0)
|
||||
mode = OREAD;
|
||||
if(copt & FILE_DELETE_ON_CLOSE){
|
||||
if(isdir || (dacc & FILE_DELETE)==0)
|
||||
goto noaccess;
|
||||
delete = 1;
|
||||
}
|
||||
if((fd = create(path, mode, perm)) < 0){
|
||||
char *name, *base;
|
||||
Dir *t;
|
||||
|
||||
err = smbmkerror();
|
||||
if(!splitpath(path, &base, &name))
|
||||
goto out;
|
||||
if((t = xdirstat(&base, namecmp)) == nil){
|
||||
free(base); free(name);
|
||||
goto out;
|
||||
}
|
||||
free(t);
|
||||
free(path); path = conspath(base, name);
|
||||
free(base); free(name);
|
||||
if((fd = create(path, mode, perm)) < 0)
|
||||
goto oserror;
|
||||
}
|
||||
if(csize > 0 && !isdir){
|
||||
Dir nd;
|
||||
|
||||
nulldir(&nd);
|
||||
nd.length = csize;
|
||||
if(dirfwstat(fd, &nd) < 0)
|
||||
goto oserror;
|
||||
}
|
||||
if(pdir)
|
||||
if((d = dirfstat(fd)) == nil)
|
||||
goto oserror;
|
||||
if(isdir){
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
f = mallocz(sizeof(*f), 1);
|
||||
f->ref = 1;
|
||||
f->fd = fd; fd = -1;
|
||||
f->rtype = FileTypeDisk;
|
||||
f->dacc = dacc;
|
||||
o->delete |= delete;
|
||||
if(o->path == nil){
|
||||
o->path = path;
|
||||
path = nil;
|
||||
}
|
||||
f->path = o->path;
|
||||
f->aux = o; o = nil;
|
||||
if(pact)
|
||||
*pact = act;
|
||||
if(pdir){
|
||||
*pdir = d;
|
||||
d = nil;
|
||||
}
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
if(perr)
|
||||
*perr = err;
|
||||
if(fd >= 0)
|
||||
close(fd);
|
||||
free(path);
|
||||
putopl(o);
|
||||
free(d);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
Dir*
|
||||
statfile(File *f)
|
||||
{
|
||||
if(f == nil)
|
||||
return nil;
|
||||
if(f->fd >= 0)
|
||||
return dirfstat(f->fd);
|
||||
else
|
||||
return dirstat(f->path);
|
||||
}
|
||||
|
||||
int
|
||||
lockfile(File *f)
|
||||
{
|
||||
Opl *opl = f->aux;
|
||||
if(opl->locked && opl->locked != f)
|
||||
return 0;
|
||||
opl->locked = f;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
deletefile(File *f, int delete)
|
||||
{
|
||||
Opl *opl = f->aux;
|
||||
if(opl->delete == delete)
|
||||
return;
|
||||
opl->delete = delete;
|
||||
}
|
||||
|
||||
int
|
||||
deletedfile(File *f)
|
||||
{
|
||||
Opl *opl = f->aux;
|
||||
return opl->delete;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
putfile(File *f)
|
||||
{
|
||||
Opl *opl;
|
||||
|
||||
if(f == nil || --f->ref)
|
||||
return;
|
||||
if(f->fd >= 0)
|
||||
close(f->fd);
|
||||
opl = f->aux;
|
||||
if(opl->locked == f)
|
||||
opl->locked = nil;
|
||||
putopl(opl);
|
||||
free(f);
|
||||
}
|
||||
|
191
sys/src/cmd/ip/cifsd/find.c
Normal file
191
sys/src/cmd/ip/cifsd/find.c
Normal file
|
@ -0,0 +1,191 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static int
|
||||
iswild(char *pattern)
|
||||
{
|
||||
return strchrs(pattern, "*?<>\"") != nil;
|
||||
}
|
||||
|
||||
static int
|
||||
matchpattern(char *name, char *pattern, int casesensitive)
|
||||
{
|
||||
Rune p, r;
|
||||
int n;
|
||||
|
||||
while(*pattern){
|
||||
pattern += chartorune(&p, pattern);
|
||||
n = chartorune(&r, name);
|
||||
switch(p){
|
||||
case '?':
|
||||
if(r == 0)
|
||||
return 0;
|
||||
name += n;
|
||||
break;
|
||||
case '>':
|
||||
switch(r){
|
||||
case '.':
|
||||
if(!name[1] && matchpattern(name+1, pattern, casesensitive))
|
||||
return 1;
|
||||
case 0:
|
||||
return matchpattern(name, pattern, casesensitive);
|
||||
}
|
||||
name += n;
|
||||
break;
|
||||
case '*':
|
||||
case '<':
|
||||
while(r){
|
||||
if(matchpattern(name, pattern, casesensitive))
|
||||
return 1;
|
||||
if(p == '<' && r == '.' && !strchrs(name+1, ".")){
|
||||
name++;
|
||||
break;
|
||||
}
|
||||
n = chartorune(&r, name += n);
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
if(r == 0 && matchpattern(name, pattern, casesensitive))
|
||||
return 1;
|
||||
if(r != '.')
|
||||
return 0;
|
||||
name += n;
|
||||
break;
|
||||
default:
|
||||
if(p != r && casesensitive || toupperrune(p) != toupperrune(r))
|
||||
return 0;
|
||||
name += n;
|
||||
}
|
||||
}
|
||||
return *name == 0;
|
||||
}
|
||||
|
||||
int
|
||||
matchattr(Dir *d, int s)
|
||||
{
|
||||
int a, m;
|
||||
|
||||
m = ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY;
|
||||
a = dosfileattr(d);
|
||||
if((a & ~s) & m)
|
||||
return 0;
|
||||
m = (s >> 8) & m;
|
||||
if(m && ((m & a) != m))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Find*
|
||||
openfind(char *path, int (*namecmp)(char *, char *), int attr, int withdot, int *perr)
|
||||
{
|
||||
char *base, *pattern, *parent;
|
||||
Dir *dir;
|
||||
int ndir, err;
|
||||
Find *f;
|
||||
|
||||
f = nil;
|
||||
path = strdup(path);
|
||||
base = pattern = parent = nil;
|
||||
if(!splitpath(path, &base, &pattern)){
|
||||
err = STATUS_OBJECT_PATH_SYNTAX_BAD;
|
||||
goto out;
|
||||
}
|
||||
if(debug)
|
||||
fprint(2, "base %s\npattern %s\nattr %x\nwithdot %d\n", base, pattern, attr, withdot);
|
||||
|
||||
if(iswild(pattern)){
|
||||
if((ndir = xdirread(&base, namecmp, &dir)) < 0){
|
||||
err = smbmkerror();
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
ndir = 0;
|
||||
withdot = 0;
|
||||
if(dir = xdirstat(&path, namecmp)){
|
||||
free(base);
|
||||
free(pattern);
|
||||
splitpath(path, &base, &pattern);
|
||||
ndir++;
|
||||
}
|
||||
}
|
||||
|
||||
f = mallocz(sizeof(*f), 1);
|
||||
f->ref = 1;
|
||||
f->base = base;
|
||||
f->pattern = pattern;
|
||||
f->attr = attr;
|
||||
f->dir = dir;
|
||||
f->ndir = ndir;
|
||||
f->index = 0;
|
||||
f->casesensitive = (namecmp == strcmp);
|
||||
|
||||
if(withdot){
|
||||
if(f->dot = dirstat(base))
|
||||
f->dot->name = ".";
|
||||
if(splitpath(base, &parent, nil))
|
||||
if(f->dotdot = dirstat(parent))
|
||||
f->dotdot->name = "..";
|
||||
}
|
||||
|
||||
base = nil;
|
||||
pattern = nil;
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
if(perr)
|
||||
*perr = err;
|
||||
|
||||
free(base);
|
||||
free(pattern);
|
||||
free(parent);
|
||||
free(path);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
int
|
||||
readfind(Find *f, int i, Dir **dp)
|
||||
{
|
||||
Dir *d;
|
||||
int x;
|
||||
|
||||
x = i;
|
||||
if(f->dot && f->dotdot)
|
||||
x -= 2;
|
||||
for(;;){
|
||||
if(x == -2){
|
||||
d = f->dot;
|
||||
} else if(x == -1){
|
||||
d = f->dotdot;
|
||||
} else if(x < f->ndir){
|
||||
d = f->dir + x;
|
||||
} else {
|
||||
d = nil;
|
||||
i = -1;
|
||||
break;
|
||||
}
|
||||
if(matchattr(d, f->attr) && matchpattern(d->name, f->pattern, f->casesensitive))
|
||||
break;
|
||||
i++; x++;
|
||||
}
|
||||
if(debug && d)
|
||||
fprint(2, "readfile [%d] attr=%x name=%s\n", i, extfileattr(d), d->name);
|
||||
*dp = d;
|
||||
return i;
|
||||
}
|
||||
|
||||
void
|
||||
putfind(Find *f)
|
||||
{
|
||||
if(f == nil || --f->ref)
|
||||
return;
|
||||
free(f->pattern);
|
||||
free(f->base);
|
||||
free(f->dot);
|
||||
free(f->dotdot);
|
||||
free(f->dir);
|
||||
free(f);
|
||||
}
|
85
sys/src/cmd/ip/cifsd/fns.h
Normal file
85
sys/src/cmd/ip/cifsd/fns.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
/* pack */
|
||||
int unpack(uchar *b, uchar *p, uchar *e, char *f, ...);
|
||||
int vunpack(uchar *b, uchar *p, uchar *e, char *f, va_list a);
|
||||
int pack(uchar *b, uchar *p, uchar *e, char *f, ...);
|
||||
int vpack(uchar *b, uchar *p, uchar *e, char *f, va_list a);
|
||||
|
||||
/* error */
|
||||
int smbmkerror(void);
|
||||
int doserror(int err);
|
||||
|
||||
/* util */
|
||||
void logit(char *fmt, ...);
|
||||
#pragma varargck argpos logit 1
|
||||
char *getremote(char *dir);
|
||||
char *conspath(char *base, char *name);
|
||||
int splitpath(char *path, char **base, char **name);
|
||||
void dumphex(char *s, uchar *h, uchar *e);
|
||||
void todatetime(long time, int *pdate, int *ptime);
|
||||
long fromdatetime(int date, int time);
|
||||
vlong tofiletime(long time);
|
||||
long fromfiletime(vlong filetime);
|
||||
int filesize32(vlong);
|
||||
vlong allocsize(vlong size, int blocksize);
|
||||
int extfileattr(Dir *d);
|
||||
int dosfileattr(Dir *d);
|
||||
ulong namehash(char *s);
|
||||
char *strtr(char *s, Rune (*tr)(Rune));
|
||||
char *strchrs(char *s, char *c);
|
||||
int smbstrpack8(uchar *, uchar *p, uchar *e, void *arg);
|
||||
int smbstrpack16(uchar *b, uchar *p, uchar *e, void *arg);
|
||||
int smbstrunpack8(uchar *, uchar *p, uchar *e, void *arg);
|
||||
int smbstrunpack16(uchar *b, uchar *p, uchar *e, void *arg);
|
||||
int smbnamepack8(uchar *b, uchar *p, uchar *e, void *arg);
|
||||
int smbnamepack16(uchar *b, uchar *p, uchar *e, void *arg);
|
||||
int smbnameunpack8(uchar *b, uchar *p, uchar *e, void *arg);
|
||||
int smbnameunpack16(uchar *b, uchar *p, uchar *e, void *arg);
|
||||
int smbuntermstrpack8(uchar *b, uchar *p, uchar *e, void *arg);
|
||||
int smbuntermstrpack16(uchar *b, uchar *p, uchar *e, void *arg);
|
||||
int smbuntermnamepack8(uchar *b, uchar *p, uchar *e, void *arg);
|
||||
int smbuntermnamepack16(uchar *b, uchar *p, uchar *e, void *arg);
|
||||
|
||||
/* smb */
|
||||
void smbcmd(Req *r, int cmd, uchar *h, uchar *p, uchar *e);
|
||||
|
||||
/* share */
|
||||
Share *mapshare(char *path);
|
||||
|
||||
/* rap */
|
||||
void transrap(Trans *t);
|
||||
|
||||
/* tree */
|
||||
Tree *connecttree(char *service, char *path, int *perr);
|
||||
int disconnecttree(int tid);
|
||||
void logoff(void);
|
||||
|
||||
Tree *gettree(int tid);
|
||||
int newfid(Tree *t, File *f);
|
||||
void delfid(Tree *t, int fid);
|
||||
File *getfile(int tid, int fid, Tree **ptree, int *perr);
|
||||
char *getpath(int tid, char *name, Tree **ptree, int *perr);
|
||||
|
||||
int newsid(Tree *t, Find *f);
|
||||
void delsid(Tree *t, int sid);
|
||||
Find *getfind(int tid, int sid, Tree **ptree, int *perr);
|
||||
|
||||
/* file */
|
||||
File* createfile(char *path, int (*namecmp)(char *, char *),
|
||||
int dacc, int sacc, int cdisp, int copt, vlong csize, int fattr, int *pact, Dir **pdir, int *perr);
|
||||
Dir* statfile(File *f);
|
||||
void putfile(File *f);
|
||||
int lockfile(File *f);
|
||||
void deletefile(File *f, int delete);
|
||||
int deletedfile(File *f);
|
||||
|
||||
/* find */
|
||||
Find *openfind(char *path, int (*namecmp)(char *, char *),
|
||||
int attr, int withdot, int *perr);
|
||||
int matchattr(Dir *d, int s);
|
||||
int readfind(Find *f, int i, Dir **dp);
|
||||
void putfind(Find *f);
|
||||
|
||||
/* dir */
|
||||
int xdirread(char **path, int (*namecmp)(char *, char *), Dir **d);
|
||||
Dir *xdirstat(char **path, int (*namecmp)(char *, char *));
|
||||
void xdirflush(char *path, int (*namecmp)(char *, char *));
|
214
sys/src/cmd/ip/cifsd/main.c
Normal file
214
sys/src/cmd/ip/cifsd/main.c
Normal file
|
@ -0,0 +1,214 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
enum {
|
||||
LENHDR = 4,
|
||||
|
||||
MAGIC = 0xFF | ('S'<<8) | ('M'<<16) | ('B'<<24),
|
||||
|
||||
SMB_FLAGS_CASE_INSENSITIVE = 0x08,
|
||||
SMB_FLAGS_CANONICALIZED_PATHS = 0x10,
|
||||
SMB_FLAGS_REPLY = 0x80,
|
||||
|
||||
NOCASEMASK = SMB_FLAGS_CASE_INSENSITIVE | SMB_FLAGS_CANONICALIZED_PATHS,
|
||||
|
||||
SMB_FLAGS2_LONG_NAMES = 0x0001,
|
||||
SMB_FLAGS2_EAS = 0x0002,
|
||||
SMB_FLAGS2_IS_LONG_NAME = 0x0040,
|
||||
SMB_FLAGS2_NT_STATUS = 0x4000,
|
||||
SMB_FLAGS2_UNICODE = 0x8000,
|
||||
};
|
||||
|
||||
static int casesensitive = 0;
|
||||
|
||||
static void
|
||||
respond(Req *r, int err)
|
||||
{
|
||||
int n, flags, flags2;
|
||||
|
||||
if(err && !(r->flags2 & SMB_FLAGS2_NT_STATUS))
|
||||
err = doserror(err);
|
||||
flags = (r->flags & (r->namecmp != strcmp ? NOCASEMASK : 0)) |
|
||||
SMB_FLAGS_REPLY;
|
||||
flags2 = (r->flags2 & (SMB_FLAGS2_NT_STATUS |
|
||||
SMB_FLAGS2_LONG_NAMES | SMB_FLAGS2_UNICODE)) |
|
||||
SMB_FLAGS2_IS_LONG_NAME;
|
||||
if(r->cmd != 0x73) /* SMB_COM_SESSION_SETUP_ANDX */
|
||||
memset(r->sig, 0, sizeof(r->sig));
|
||||
n = pack(r->rh, r->rh, r->rh+32, "lblbww[]__wwww",
|
||||
MAGIC, r->cmd, err, flags, flags2, r->pid>>16, r->sig, r->sig+sizeof(r->sig),
|
||||
r->tid, r->pid & 0xFFFF, r->uid, r->mid);
|
||||
if(err){
|
||||
r->rp = r->rh+n;
|
||||
r->rp += pack(r->rh, r->rp, r->re, "#0b{*2}#1w{}");
|
||||
}
|
||||
if(debug > 1)
|
||||
dumphex("respond", r->rh, r->rp);
|
||||
if(debug)
|
||||
fprint(2, "respond: err=%x\n\n", err);
|
||||
n = r->rp - r->rh;
|
||||
r->lh[0] = 0;
|
||||
r->lh[1] = 0;
|
||||
r->lh[2] = n>>8 & 0xFF;
|
||||
r->lh[3] = n & 0xFF;
|
||||
write(1, r->lh, LENHDR+n);
|
||||
}
|
||||
|
||||
static void
|
||||
receive(uchar *h, uchar *e)
|
||||
{
|
||||
static uchar buffer[LENHDR + BUFFERSIZE];
|
||||
static Rop rop8 = {
|
||||
.strpack = smbstrpack8,
|
||||
.strunpack = smbstrunpack8,
|
||||
.namepack = smbnamepack8,
|
||||
.nameunpack = smbnameunpack8,
|
||||
.untermstrpack = smbuntermstrpack8,
|
||||
.untermnamepack = smbuntermnamepack8,
|
||||
}, rop16 = {
|
||||
.strpack = smbstrpack16,
|
||||
.strunpack = smbstrunpack16,
|
||||
.namepack = smbnamepack16,
|
||||
.nameunpack = smbnameunpack16,
|
||||
.untermstrpack = smbuntermstrpack16,
|
||||
.untermnamepack = smbuntermnamepack16,
|
||||
};
|
||||
|
||||
uchar *sig;
|
||||
int n, hpid, magic;
|
||||
Req r;
|
||||
|
||||
if(debug > 1)
|
||||
dumphex("receive", h, e);
|
||||
if((n = unpack(h, h, e, "lb____bww{.________}__wwww", &magic,
|
||||
&r.cmd, &r.flags, &r.flags2, &hpid, &sig, &r.tid, &r.pid, &r.uid, &r.mid)) == 0){
|
||||
logit("bad smb header");
|
||||
return;
|
||||
}
|
||||
if(magic != MAGIC){
|
||||
logit("bad smb magic");
|
||||
return;
|
||||
}
|
||||
r.pid |= hpid<<16;
|
||||
r.lh = buffer;
|
||||
r.rh = r.lh + LENHDR;
|
||||
r.rp = r.rh + n;
|
||||
r.re = r.rh + remotebuffersize;
|
||||
r.o = (r.flags2 & SMB_FLAGS2_UNICODE) ? &rop16 : &rop8;
|
||||
memmove(r.sig, sig, sizeof(r.sig));
|
||||
r.name = nil;
|
||||
r.respond = respond;
|
||||
r.namecmp = ((r.flags & NOCASEMASK) && !casesensitive) ? cistrcmp : strcmp;
|
||||
smbcmd(&r, r.cmd, h, h+n, e);
|
||||
}
|
||||
|
||||
static void
|
||||
serve(void)
|
||||
{
|
||||
static uchar buffer[LENHDR + BUFFERSIZE];
|
||||
uchar *m, *me;
|
||||
uchar *p, *pe;
|
||||
uchar *hl;
|
||||
int n;
|
||||
|
||||
p = hl = buffer;
|
||||
pe = p + LENHDR+BUFFERSIZE;
|
||||
|
||||
for(;;){
|
||||
n = read(0, p, pe - p);
|
||||
if(n <= 0)
|
||||
break;
|
||||
p += n;
|
||||
Next:
|
||||
if(p - hl < LENHDR)
|
||||
continue;
|
||||
n = hl[2]<<8 | hl[3];
|
||||
m = hl + LENHDR;
|
||||
me = m + n;
|
||||
if(me > pe){
|
||||
logit("message too big");
|
||||
break;
|
||||
}
|
||||
if(me > p)
|
||||
continue;
|
||||
receive(m, me);
|
||||
n = p - me;
|
||||
p = hl + n;
|
||||
if(n > 0){
|
||||
memmove(hl, me, n);
|
||||
goto Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
static struct {
|
||||
char *s;
|
||||
int *v;
|
||||
} opts[] = {
|
||||
{ "trspaces", &trspaces },
|
||||
{ "casesensitive", &casesensitive },
|
||||
{ nil, nil }
|
||||
}, *o;
|
||||
|
||||
char *log, *opt;
|
||||
Tm *tm;
|
||||
int pid;
|
||||
|
||||
debug = 0;
|
||||
trspaces = 0;
|
||||
needauth = 1;
|
||||
domain = "WORKGROUP";
|
||||
progname = "cifsd";
|
||||
osname = "Plan 9";
|
||||
log = nil;
|
||||
|
||||
ARGBEGIN {
|
||||
case 't':
|
||||
needauth = 0;
|
||||
break;
|
||||
case 'd':
|
||||
debug++;
|
||||
break;
|
||||
case 'f':
|
||||
log = EARGF(exits("bad arg"));
|
||||
break;
|
||||
case 'w':
|
||||
domain = EARGF(exits("bad arg"));
|
||||
break;
|
||||
case 'o':
|
||||
opt = EARGF(exits("bad arg"));
|
||||
for(o=opts; o->s; o++)
|
||||
if(strcmp(opt, o->s) == 0){
|
||||
*o->v = 1;
|
||||
break;
|
||||
}
|
||||
if(o->s == nil)
|
||||
exits("bad arg");
|
||||
break;
|
||||
} ARGEND
|
||||
|
||||
close(2);
|
||||
if(!log || open(log, OWRITE) < 0){
|
||||
open("/dev/null", OWRITE);
|
||||
debug = 0;
|
||||
}
|
||||
|
||||
remotesys = argc ? getremote(argv[argc-1]) : nil;
|
||||
remoteuser = nil;
|
||||
remotebuffersize = BUFFERSIZE;
|
||||
starttime = time(nil);
|
||||
pid = getpid();
|
||||
srand(starttime ^ pid);
|
||||
tm = localtime(starttime);
|
||||
tzoff = tm->tzoff;
|
||||
|
||||
logit("started [%d]", pid);
|
||||
serve();
|
||||
logoff();
|
||||
logit("exited [%d]", pid);
|
||||
}
|
21
sys/src/cmd/ip/cifsd/mkfile
Normal file
21
sys/src/cmd/ip/cifsd/mkfile
Normal file
|
@ -0,0 +1,21 @@
|
|||
</$objtype/mkfile
|
||||
|
||||
BIN=/$objtype/bin/ip
|
||||
TARG=cifsd
|
||||
|
||||
HFILES=dat.h fns.h
|
||||
|
||||
OFILES=\
|
||||
pack.$O \
|
||||
util.$O \
|
||||
error.$O \
|
||||
smb.$O \
|
||||
rap.$O \
|
||||
share.$O \
|
||||
tree.$O \
|
||||
dir.$O \
|
||||
file.$O \
|
||||
find.$O \
|
||||
main.$O \
|
||||
|
||||
</sys/src/cmd/mkone
|
305
sys/src/cmd/ip/cifsd/pack.c
Normal file
305
sys/src/cmd/ip/cifsd/pack.c
Normal file
|
@ -0,0 +1,305 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
int
|
||||
unpack(uchar *b, uchar *p, uchar *e, char *f, ...)
|
||||
{
|
||||
va_list a;
|
||||
int r;
|
||||
|
||||
va_start(a, f);
|
||||
r = vunpack(b, p, e, f, a);
|
||||
va_end(a);
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
pack(uchar *b, uchar *p, uchar *e, char *f, ...)
|
||||
{
|
||||
va_list a;
|
||||
int r;
|
||||
|
||||
va_start(a, f);
|
||||
r = vpack(b, p, e, f, a);
|
||||
va_end(a);
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
vunpack(uchar *b, uchar *p, uchar *e, char *f, va_list a)
|
||||
{
|
||||
struct {
|
||||
void *prev;
|
||||
int o, c, i;
|
||||
uchar *e;
|
||||
uchar **ap, **ae;
|
||||
} sub[8], *sp, *sa;
|
||||
int (*funpack)(uchar *, uchar *, uchar *, void *);
|
||||
char c, ff[2];
|
||||
int i, x, n;
|
||||
uchar *t;
|
||||
|
||||
memset(sub, 0, sizeof(sub));
|
||||
for(sp = sub; sp < sub+nelem(sub); sp++){
|
||||
sp->o = -1;
|
||||
sp->c = -1;
|
||||
sp->i = 1;
|
||||
}
|
||||
|
||||
t = p;
|
||||
sp = nil;
|
||||
sa = sub;
|
||||
while(c = *f++){
|
||||
switch(c){
|
||||
case '_':
|
||||
case 'b':
|
||||
if(p >= e)
|
||||
return 0;
|
||||
if(c == 'b')
|
||||
*va_arg(a, int*) = *p;
|
||||
p++;
|
||||
break;
|
||||
case 'w':
|
||||
if(p+1 >= e)
|
||||
return 0;
|
||||
*va_arg(a, int*) = (int)p[1]<<8 | (int)p[0];
|
||||
p+=2;
|
||||
break;
|
||||
case 'l':
|
||||
if(p+3 >= e)
|
||||
return 0;
|
||||
*va_arg(a, int*) = (int)p[3]<<24 | (int)p[2]<<16 | (int)p[1]<<8 | (int)p[0];
|
||||
p+=4;
|
||||
break;
|
||||
case 'v':
|
||||
if(p+7 >= e)
|
||||
return 0;
|
||||
*va_arg(a, vlong*) =
|
||||
(vlong)p[7]<<56 |
|
||||
(vlong)p[6]<<48 |
|
||||
(vlong)p[5]<<40 |
|
||||
(vlong)p[4]<<32 |
|
||||
(vlong)p[3]<<24 |
|
||||
(vlong)p[2]<<16 |
|
||||
(vlong)p[1]<<8 |
|
||||
(vlong)p[0];
|
||||
p += 8;
|
||||
break;
|
||||
case '%':
|
||||
x = *f++ - '0';
|
||||
while((p - b) % x)
|
||||
p++;
|
||||
break;
|
||||
case 'f':
|
||||
funpack = va_arg(a, void*);
|
||||
if((n = funpack(b, p, e, va_arg(a, void*))) == 0)
|
||||
return 0;
|
||||
p += n;
|
||||
break;
|
||||
case '#':
|
||||
case '@':
|
||||
x = *f++ - '0';
|
||||
ff[0] = *f++;
|
||||
ff[1] = 0;
|
||||
if((n = unpack(b, p, e, ff, &i)) == 0)
|
||||
return 0;
|
||||
p += n;
|
||||
if(c == '#'){
|
||||
sub[x].c = i;
|
||||
} else {
|
||||
sub[x].o = i;
|
||||
}
|
||||
break;
|
||||
case '{':
|
||||
case '[':
|
||||
sa->prev = sp;
|
||||
sp = sa++;
|
||||
if(*f == '*'){
|
||||
sp->i = f[1]-'0';
|
||||
f += 2;
|
||||
}
|
||||
if(sp->o >= 0 && b + sp->o > p)
|
||||
if(b + sp->o <= e || *f != '?')
|
||||
p = b + sp->o;
|
||||
if(*f == '?')
|
||||
f++;
|
||||
sp->o = p - b;
|
||||
sp->e = e;
|
||||
if(sp->c >= 0){
|
||||
e = p + sp->c * sp->i;
|
||||
if(e > sp->e)
|
||||
return 0;
|
||||
}
|
||||
if(c == '['){
|
||||
sp->ap = va_arg(a, uchar**);
|
||||
sp->ae = va_arg(a, uchar**);
|
||||
}
|
||||
break;
|
||||
case '}':
|
||||
case ']':
|
||||
e = sp->e;
|
||||
if(sp->c < 0)
|
||||
sp->c = ((p - (b + sp->o))+sp->i-1)/sp->i;
|
||||
p = b + sp->o + sp->c * sp->i;
|
||||
if(p > e)
|
||||
return 0;
|
||||
if(sp->ap)
|
||||
*sp->ap = b + sp->o;
|
||||
if(sp->ae)
|
||||
*sp->ae = p;
|
||||
sp = sp->prev;
|
||||
break;
|
||||
case '.':
|
||||
*va_arg(a, uchar**) = p;
|
||||
break;
|
||||
}
|
||||
if(p > e)
|
||||
return 0;
|
||||
}
|
||||
return p - t;
|
||||
}
|
||||
|
||||
vpack(uchar *b, uchar *p, uchar *e, char *f, va_list a)
|
||||
{
|
||||
struct {
|
||||
void *prev;
|
||||
int o, i;
|
||||
uchar *wc, *wo, wcf, wof;
|
||||
} sub[8], *sp, *sa;
|
||||
int (*fpack)(uchar *, uchar *, uchar *, void *);
|
||||
char c, ff[2];
|
||||
int i, x, n;
|
||||
vlong v;
|
||||
uchar *t;
|
||||
|
||||
memset(sub, 0, sizeof(sub));
|
||||
for(sp = sub; sp < sub+nelem(sub); sp++){
|
||||
sp->o = -1;
|
||||
sp->i = 1;
|
||||
}
|
||||
|
||||
t = p;
|
||||
sp = nil;
|
||||
sa = sub;
|
||||
while(c = *f++){
|
||||
switch(c){
|
||||
case '_':
|
||||
case 'b':
|
||||
if(p >= e)
|
||||
return 0;
|
||||
if(c == 'b')
|
||||
*p++ = va_arg(a, int);
|
||||
else
|
||||
*p++ = 0;
|
||||
break;
|
||||
case 'w':
|
||||
if(p+1 >= e)
|
||||
return 0;
|
||||
i = va_arg(a, int);
|
||||
*p++ = i & 0xFF;
|
||||
*p++ = i>>8 & 0xFF;
|
||||
break;
|
||||
case 'l':
|
||||
if(p+3 >= e)
|
||||
return 0;
|
||||
i = va_arg(a, int);
|
||||
*p++ = i & 0xFF;
|
||||
*p++ = i>>8 & 0xFF;
|
||||
*p++ = i>>16 & 0xFF;
|
||||
*p++ = i>>24 & 0xFF;
|
||||
break;
|
||||
case 'v':
|
||||
if(p+7 >= e)
|
||||
return 0;
|
||||
v = va_arg(a, vlong);
|
||||
*p++ = v & 0xFF;
|
||||
*p++ = v>>8 & 0xFF;
|
||||
*p++ = v>>16 & 0xFF;
|
||||
*p++ = v>>24 & 0xFF;
|
||||
*p++ = v>>32 & 0xFF;
|
||||
*p++ = v>>40 & 0xFF;
|
||||
*p++ = v>>48 & 0xFF;
|
||||
*p++ = v>>56 & 0xFF;
|
||||
break;
|
||||
case '%':
|
||||
x = *f++ - '0';
|
||||
while((p - b) % x){
|
||||
if(p >= e)
|
||||
return 0;
|
||||
*p++ = 0;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
fpack = va_arg(a, void*);
|
||||
if((n = fpack(b, p, e, va_arg(a, void*))) == 0)
|
||||
return 0;
|
||||
p += n;
|
||||
break;
|
||||
case '#':
|
||||
case '@':
|
||||
x = *f++ - '0';
|
||||
ff[0] = *f++;
|
||||
ff[1] = 0;
|
||||
if((n = pack(b, p, e, ff, 0)) == 0)
|
||||
return 0;
|
||||
if(c == '#'){
|
||||
sub[x].wc = p;
|
||||
sub[x].wcf = ff[0];
|
||||
} else {
|
||||
sub[x].wo = p;
|
||||
sub[x].wof = ff[0];
|
||||
}
|
||||
p += n;
|
||||
break;
|
||||
case '{':
|
||||
case '[':
|
||||
sa->prev = sp;
|
||||
sp = sa++;
|
||||
if(*f == '*'){
|
||||
sp->i = f[1]-'0';
|
||||
f += 2;
|
||||
}
|
||||
if(*f == '?')
|
||||
f++;
|
||||
sp->o = p - b;
|
||||
if(c == '['){
|
||||
uchar *s, *se;
|
||||
|
||||
s = va_arg(a, uchar*);
|
||||
se = va_arg(a, uchar*);
|
||||
n = se - s;
|
||||
if(n < 0 || p + n > e)
|
||||
return 0;
|
||||
if(p != s)
|
||||
memmove(p, s, n);
|
||||
p += n;
|
||||
}
|
||||
break;
|
||||
case '}':
|
||||
case ']':
|
||||
n = ((p - (b + sp->o))+sp->i-1)/sp->i;
|
||||
p = b + sp->o + n * sp->i;
|
||||
if(sp->wc){
|
||||
ff[0] = sp->wcf;
|
||||
ff[1] = 0;
|
||||
pack(b, sp->wc, e, ff, n);
|
||||
}
|
||||
if(sp->wo){
|
||||
ff[0] = sp->wof;
|
||||
ff[1] = 0;
|
||||
pack(b, sp->wo, e, ff, sp->o);
|
||||
}
|
||||
sp = sp->prev;
|
||||
break;
|
||||
case '.':
|
||||
*va_arg(a, uchar**) = p;
|
||||
break;
|
||||
}
|
||||
if(p > e)
|
||||
return 0;
|
||||
}
|
||||
return p - t;
|
||||
}
|
||||
|
143
sys/src/cmd/ip/cifsd/rap.c
Normal file
143
sys/src/cmd/ip/cifsd/rap.c
Normal file
|
@ -0,0 +1,143 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <auth.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static void
|
||||
padname(uchar *buf, int len, char *name)
|
||||
{
|
||||
int n;
|
||||
n = strlen(name);
|
||||
if(n >= len)
|
||||
n = len-1;
|
||||
memset(buf, 0, len);
|
||||
memmove(buf, name, n);
|
||||
}
|
||||
|
||||
static int
|
||||
packshareinfo(Trans *t, int level, char *name, int *pstatus)
|
||||
{
|
||||
Share *share;
|
||||
uchar buf[13];
|
||||
|
||||
if((share = mapshare(name)) == nil){
|
||||
if(pstatus)
|
||||
*pstatus = 0x906; /* NERR_NetNameNotFound */
|
||||
return 0;
|
||||
}
|
||||
padname(buf, sizeof(buf), share->name);
|
||||
switch(level){
|
||||
case 0:
|
||||
return pack(t->out.data.b, t->out.data.p, t->out.data.e, "[]",
|
||||
buf, buf+sizeof(buf));
|
||||
case 1:
|
||||
return pack(t->out.data.b, t->out.data.p, t->out.data.e, "[]_w@1l{f}",
|
||||
buf, buf+sizeof(buf), share->stype, smbstrpack8, share->remark);
|
||||
case 2:
|
||||
return pack(t->out.data.b, t->out.data.p, t->out.data.e, "[]_w@1l__ww@2l__________{f}{f}",
|
||||
buf, buf+sizeof(buf), share->stype, 100, 1, smbstrpack8, share->remark,
|
||||
smbnamepack8, share->root);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
transrap(Trans *t)
|
||||
{
|
||||
char *pd, *dd, *name;
|
||||
int n, code, status, level, rbs;
|
||||
uchar *ip, *ipe, *op, *opb, *ope;
|
||||
uchar buf[16];
|
||||
|
||||
code = 0;
|
||||
name = nil;
|
||||
pd = dd = nil;
|
||||
ip = ipe = t->in.param.e;
|
||||
if(!unpack(t->in.param.b, t->in.param.p, t->in.param.e, "wff[]", &code,
|
||||
smbstrunpack8, &pd, smbstrunpack8, &dd, &ip, nil)){
|
||||
t->respond(t, STATUS_NOT_SUPPORTED);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ope = t->out.param.e;
|
||||
opb = op = t->out.param.b+2+2;
|
||||
|
||||
n = status = level = 0;
|
||||
switch(code){
|
||||
case 0x0000: /* NetShareEnum */
|
||||
op += pack(opb, op, ope, "ww", 0, 0);
|
||||
if(!unpack(ip, ip, ipe, "ww", &level, &rbs))
|
||||
break;
|
||||
if((n = packshareinfo(t, level, "local", nil)) > 0){
|
||||
t->out.data.p += n;
|
||||
pack(opb, opb, ope, "ww", 1, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0001: /* NetShareGetInfo */
|
||||
op += pack(opb, op, ope, "w", 0);
|
||||
if(!unpack(ip, ip, ipe, "fww", smbstrunpack8, &name, &level, &rbs))
|
||||
break;
|
||||
if((n = packshareinfo(t, level, name, &status)) > 0){
|
||||
outlen:
|
||||
t->out.data.p += n;
|
||||
pack(opb, opb, ope, "w", n);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x000d: /* NetServerGetInfo */
|
||||
op += pack(opb, op, ope, "w", 0);
|
||||
if(!unpack(ip, ip, ipe, "ww", &level, &rbs))
|
||||
break;
|
||||
padname(buf, sizeof(buf), "");
|
||||
switch(level){
|
||||
case 0:
|
||||
if((n = pack(t->out.data.b, t->out.data.p, t->out.data.e, "[]",
|
||||
buf, buf+sizeof(buf))) > 0)
|
||||
goto outlen;
|
||||
break;
|
||||
case 1:
|
||||
if((n = pack(t->out.data.b, t->out.data.p, t->out.data.e, "[]bbl@1l{f}",
|
||||
buf, buf+sizeof(buf), 0x05, 0x00, 2, smbstrpack8, osname)) > 0)
|
||||
goto outlen;
|
||||
default:
|
||||
n = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x003f: /* NetWrkstaGetInfo */
|
||||
op += pack(opb, op, ope, "w", 0);
|
||||
if(!unpack(ip, ip, ipe, "ww", &level, &rbs))
|
||||
break;
|
||||
if(level != 10){
|
||||
n = -1;
|
||||
break;
|
||||
}
|
||||
if((n = pack(t->out.data.b, t->out.data.p, t->out.data.e,
|
||||
"@0l____@1lbb________{f}{f}", 0x05, 0x00,
|
||||
smbstrpack8, sysname(), smbstrpack8, domain)) > 0)
|
||||
goto outlen;
|
||||
break;
|
||||
|
||||
default:
|
||||
logit("[%.4x] unknown rap command pd=%s dd=%s", code, pd, dd);
|
||||
}
|
||||
if(n < 0){
|
||||
logit("[%.4x] unknown rap level [%.4x]", code, level);
|
||||
status = 0x7C;
|
||||
}
|
||||
if((n = pack(t->out.param.b, t->out.param.p, t->out.param.e, "w__[]", status, opb, op)) == 0){
|
||||
t->respond(t, STATUS_INVALID_SMB);
|
||||
goto out;
|
||||
}
|
||||
t->out.param.p += n;
|
||||
t->respond(t, 0);
|
||||
|
||||
out:
|
||||
free(name);
|
||||
free(pd);
|
||||
free(dd);
|
||||
return;
|
||||
}
|
124
sys/src/cmd/ip/cifsd/share.c
Normal file
124
sys/src/cmd/ip/cifsd/share.c
Normal file
|
@ -0,0 +1,124 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static int
|
||||
run9fs(char *arg)
|
||||
{
|
||||
char buf[1024], *argv[3], *s;
|
||||
Waitmsg *w;
|
||||
int fd, pid;
|
||||
|
||||
switch(pid = rfork(RFCFDG|RFREND|RFPROC)){
|
||||
case -1:
|
||||
return -1;
|
||||
case 0:
|
||||
open("/dev/null", ORDWR);
|
||||
snprint(buf, sizeof(buf), "/sys/log/%s", progname);
|
||||
if((fd = open(buf, OWRITE)) >= 0)
|
||||
seek(fd, 0, 2);
|
||||
else
|
||||
fd = 0;
|
||||
dup(fd, 1);
|
||||
dup(fd, 2);
|
||||
argv[0] = "/bin/9fs";
|
||||
argv[1] = arg;
|
||||
argv[2] = 0;
|
||||
exec(argv[0], argv);
|
||||
exits("failed to exec 9fs");
|
||||
}
|
||||
for (;;) {
|
||||
if((w = wait()) == nil)
|
||||
return -1;
|
||||
if (w->pid == pid)
|
||||
break;
|
||||
free(w);
|
||||
}
|
||||
if(w->msg[0]){
|
||||
if(s = strchr(w->msg, ':'))
|
||||
s = s+1;
|
||||
else
|
||||
s = w->msg;
|
||||
werrstr("%s", s);
|
||||
free(w);
|
||||
return -1;
|
||||
} else {
|
||||
free(w);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static Share *shares;
|
||||
|
||||
Share*
|
||||
mapshare(char *path)
|
||||
{
|
||||
char *tmp, *tmp2, *name, *root, *service, *fsname, *remark;
|
||||
int stype;
|
||||
Share *s;
|
||||
|
||||
if(name = strrchr(path, '/'))
|
||||
name++;
|
||||
else if(name = strrchr(path, '\\'))
|
||||
name++;
|
||||
else
|
||||
name = path;
|
||||
if(name==nil || *name==0 || *name=='.' || strchrs(name, "\\* ") || strstr(name, ".."))
|
||||
return nil;
|
||||
root = tmp = smprint("/n/%s", name);
|
||||
name = strtr(strrchr(root, '/')+1, tolowerrune);
|
||||
service = "A:";
|
||||
stype = STYPE_DISKTREE;
|
||||
fsname = "9fs";
|
||||
remark = tmp2 = smprint("9fs %s; cd %s", name, root);
|
||||
if(!strcmp(name, "local")){
|
||||
root = "/";
|
||||
fsname = "local";
|
||||
remark = "The standard namespace";
|
||||
}
|
||||
if(!strcmp(name, "ipc$")){
|
||||
root = "/dev/null";
|
||||
name = "IPC$";
|
||||
fsname = "";
|
||||
service = "IPC";
|
||||
stype = STYPE_IPC;
|
||||
remark = "The IPC service";
|
||||
}
|
||||
|
||||
for(s = shares; s; s=s->next)
|
||||
if(!strcmp(s->name, name))
|
||||
goto out;
|
||||
|
||||
logit("mapshare %s -> %s %s %s", path, service, name, root);
|
||||
|
||||
if(!strcmp(service, "A:") && (stype == STYPE_DISKTREE)){
|
||||
if(!strcmp(fsname, "9fs") && (run9fs(name) < 0)){
|
||||
logit("9fs %s: %r", name);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
s = malloc(sizeof(*s));
|
||||
s->service = strdup(service);
|
||||
s->stype = stype;
|
||||
|
||||
s->name = strdup(name);
|
||||
s->root = strdup(root);
|
||||
|
||||
s->remark = strdup(remark);
|
||||
s->fsname = strdup(fsname);
|
||||
s->namelen = 255;
|
||||
s->sectorsize = 0x200;
|
||||
s->blocksize = 0x2000;
|
||||
s->allocsize = 0;
|
||||
s->freesize = s->blocksize;
|
||||
|
||||
s->next = shares;
|
||||
shares = s;
|
||||
|
||||
out:
|
||||
free(tmp);
|
||||
free(tmp2);
|
||||
return s;
|
||||
}
|
1691
sys/src/cmd/ip/cifsd/smb.c
Normal file
1691
sys/src/cmd/ip/cifsd/smb.c
Normal file
File diff suppressed because it is too large
Load diff
233
sys/src/cmd/ip/cifsd/tree.c
Normal file
233
sys/src/cmd/ip/cifsd/tree.c
Normal file
|
@ -0,0 +1,233 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static void*
|
||||
getid(void **a, int n, int i)
|
||||
{
|
||||
void *p;
|
||||
if(i <= 0 || i > n || (p = a[i-1]) == nil)
|
||||
return nil;
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
setid(void **a, int n, int i, void *p)
|
||||
{
|
||||
assert(i > 0 || i <= n);
|
||||
a[i-1] = p;
|
||||
}
|
||||
|
||||
static int
|
||||
newid(void ***pa, int *pn, void *p)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i < *pn; i++)
|
||||
if((*pa)[i] == nil)
|
||||
break;
|
||||
if(i == *pn){
|
||||
(*pn)++;
|
||||
if((i % 8) == 0)
|
||||
*pa = realloc(*pa, (i + 8) * sizeof(p));
|
||||
}
|
||||
(*pa)[i] = p;
|
||||
return i+1;
|
||||
}
|
||||
|
||||
static void **tree;
|
||||
static int ntree;
|
||||
|
||||
static void
|
||||
freetree(Tree *t)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(t == nil)
|
||||
return;
|
||||
for(i = 0; i < t->nfile; i++)
|
||||
putfile(t->file[i]);
|
||||
for(i = 0; i < t->nfind; i++)
|
||||
putfile(t->find[i]);
|
||||
free(t->file);
|
||||
free(t->find);
|
||||
free(t);
|
||||
}
|
||||
|
||||
Tree*
|
||||
connecttree(char *service, char *path, int *perr)
|
||||
{
|
||||
Share *s;
|
||||
Tree *t;
|
||||
int err;
|
||||
|
||||
t = nil;
|
||||
if((s = mapshare(path)) == nil){
|
||||
err = STATUS_BAD_NETWORK_NAME;
|
||||
goto out;
|
||||
}
|
||||
if(strcmp(service, "?????") && cistrcmp(service, s->service)){
|
||||
err = STATUS_BAD_DEVICE_TYPE;
|
||||
goto out;
|
||||
}
|
||||
t = mallocz(sizeof(*t), 1);
|
||||
t->share = s;
|
||||
t->tid = newid(&tree, &ntree, t);
|
||||
err = 0;
|
||||
out:
|
||||
if(perr)
|
||||
*perr = err;
|
||||
return t;
|
||||
}
|
||||
|
||||
int
|
||||
disconnecttree(int tid)
|
||||
{
|
||||
Tree *t;
|
||||
|
||||
if((t = gettree(tid)) == nil)
|
||||
return STATUS_SMB_BAD_TID;
|
||||
setid(tree, ntree, tid, nil);
|
||||
freetree(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
logoff(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<ntree; i++)
|
||||
freetree(tree[i]);
|
||||
free(tree);
|
||||
tree = nil;
|
||||
ntree = 0;
|
||||
}
|
||||
|
||||
Tree*
|
||||
gettree(int tid)
|
||||
{
|
||||
Tree *t;
|
||||
|
||||
if(t = getid(tree, ntree, tid))
|
||||
if(debug)
|
||||
fprint(2, "tree [%.4x] %s\n", tid, t->share->root);
|
||||
return t;
|
||||
}
|
||||
|
||||
int
|
||||
newfid(Tree *t, File *f)
|
||||
{
|
||||
f->ref++;
|
||||
return newid(&t->file, &t->nfile, f);
|
||||
}
|
||||
|
||||
void
|
||||
delfid(Tree *t, int fid)
|
||||
{
|
||||
File *f;
|
||||
|
||||
if(f = getid(t->file, t->nfile, fid)){
|
||||
setid(t->file, t->nfile, fid, nil);
|
||||
putfile(f);
|
||||
}
|
||||
}
|
||||
|
||||
File*
|
||||
getfile(int tid, int fid, Tree **ptree, int *perr)
|
||||
{
|
||||
Tree *t;
|
||||
File *f;
|
||||
int err;
|
||||
|
||||
f = nil;
|
||||
if((t = gettree(tid)) == nil){
|
||||
err = STATUS_SMB_BAD_TID;
|
||||
goto out;
|
||||
}
|
||||
if((f = getid(t->file, t->nfile, fid)) == nil){
|
||||
err = STATUS_SMB_BAD_FID;
|
||||
goto out;
|
||||
}
|
||||
f->ref++;
|
||||
err = 0;
|
||||
if(debug)
|
||||
fprint(2, "file [%x] %s\n", fid, f->path);
|
||||
out:
|
||||
if(perr)
|
||||
*perr = err;
|
||||
if(ptree)
|
||||
*ptree = t;
|
||||
return f;
|
||||
}
|
||||
|
||||
char*
|
||||
getpath(int tid, char *name, Tree **ptree, int *perr)
|
||||
{
|
||||
Tree *t;
|
||||
char *p;
|
||||
int err;
|
||||
|
||||
if(t = gettree(tid)){
|
||||
err = 0;
|
||||
p = conspath(t->share->root, name);
|
||||
if(debug)
|
||||
fprint(2, "path %s\n", p);
|
||||
} else {
|
||||
err = STATUS_SMB_BAD_TID;
|
||||
p = nil;
|
||||
}
|
||||
if(perr)
|
||||
*perr = err;
|
||||
if(ptree)
|
||||
*ptree = t;
|
||||
return p;
|
||||
}
|
||||
|
||||
int
|
||||
newsid(Tree *t, Find *f)
|
||||
{
|
||||
f->ref++;
|
||||
return newid(&t->find, &t->nfind, f);
|
||||
}
|
||||
|
||||
void
|
||||
delsid(Tree *t, int sid)
|
||||
{
|
||||
Find *f;
|
||||
|
||||
if(f = getid(t->find, t->nfind, sid)){
|
||||
setid(t->find, t->nfind, sid, nil);
|
||||
putfind(f);
|
||||
}
|
||||
}
|
||||
|
||||
Find*
|
||||
getfind(int tid, int sid, Tree **ptree, int *perr)
|
||||
{
|
||||
Tree *t;
|
||||
Find *f;
|
||||
int err;
|
||||
|
||||
f = nil;
|
||||
if((t = gettree(tid)) == nil){
|
||||
err = STATUS_SMB_BAD_TID;
|
||||
goto out;
|
||||
}
|
||||
if((f = getid(t->find, t->nfind, sid)) == nil){
|
||||
err = STATUS_SMB_BAD_FID;
|
||||
goto out;
|
||||
}
|
||||
f->ref++;
|
||||
err = 0;
|
||||
if(debug)
|
||||
fprint(2, "find [%x] %s %s\n", sid, f->base, f->pattern);
|
||||
out:
|
||||
if(perr)
|
||||
*perr = err;
|
||||
if(ptree)
|
||||
*ptree = t;
|
||||
return f;
|
||||
}
|
||||
|
||||
|
409
sys/src/cmd/ip/cifsd/util.c
Normal file
409
sys/src/cmd/ip/cifsd/util.c
Normal file
|
@ -0,0 +1,409 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
void
|
||||
logit(char *fmt, ...)
|
||||
{
|
||||
char buf[8192];
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, fmt);
|
||||
vseprint(buf, buf + sizeof(buf), fmt, arg);
|
||||
va_end(arg);
|
||||
if(debug)
|
||||
fprint(2, "%s\n", buf);
|
||||
syslog(0, progname, "(%s\\%s) %s", remotesys, remoteuser, buf);
|
||||
}
|
||||
|
||||
char*
|
||||
getremote(char *dir)
|
||||
{
|
||||
int fd, n;
|
||||
char remfile[256];
|
||||
static char buf[256];
|
||||
|
||||
sprint(remfile, "%s/remote", dir);
|
||||
fd = open(remfile, OREAD);
|
||||
if(fd < 0)
|
||||
return nil;
|
||||
if((n = read(fd, buf, sizeof(buf)-1))>0)
|
||||
buf[n-1] = 0;
|
||||
else
|
||||
strcpy(buf, remfile);
|
||||
close(fd);
|
||||
return buf;
|
||||
}
|
||||
|
||||
char*
|
||||
conspath(char *base, char *name)
|
||||
{
|
||||
return cleanname(smprint("%s/%s", base, name ? name : ""));
|
||||
}
|
||||
|
||||
int
|
||||
splitpath(char *path, char **base, char **name)
|
||||
{
|
||||
char *p, *b;
|
||||
|
||||
b = strdup(path);
|
||||
if((p = strrchr(b, '/')) == nil){
|
||||
free(b);
|
||||
if(name)
|
||||
*name = nil;
|
||||
if(base)
|
||||
*base = nil;
|
||||
return 0;
|
||||
}
|
||||
if(p == b){
|
||||
if(name) *name = strdup(p+1);
|
||||
p[1] = 0;
|
||||
} else {
|
||||
*p++ = 0;
|
||||
if(name) *name = strdup(p);
|
||||
}
|
||||
if(base)
|
||||
*base = b;
|
||||
else
|
||||
free(b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
dumphex(char *s, uchar *h, uchar *e)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
n = e - h;
|
||||
for(i=0; i<n; i++){
|
||||
if((i % 16) == 0)
|
||||
fprint(2, "%s%s: [%.4x] ", i ? "\n" : "", s, i);
|
||||
fprint(2, "%.2x ", (int)h[i]);
|
||||
}
|
||||
fprint(2, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
todatetime(long time, int *pdate, int *ptime)
|
||||
{
|
||||
Tm *tm;
|
||||
|
||||
tm = gmtime(time);
|
||||
if(pdate)
|
||||
*pdate = (tm->mday) | ((tm->mon + 1) << 5) | ((tm->year - 80) << 9);
|
||||
if(ptime)
|
||||
*ptime = (tm->sec >> 1) | (tm->min << 5) | (tm->hour << 11);
|
||||
}
|
||||
|
||||
long
|
||||
fromdatetime(int date, int time)
|
||||
{
|
||||
Tm tm;
|
||||
|
||||
strcpy(tm.zone, "GMT");
|
||||
tm.mday = date & 0x1f;
|
||||
tm.mon = ((date >> 5) & 0xf) - 1;
|
||||
tm.year = (date >> 9) + 80;
|
||||
tm.yday = 0;
|
||||
tm.sec = (time & 0x1f) << 1;
|
||||
tm.min = (time >> 5) & 0x3f;
|
||||
tm.hour = time >> 11;
|
||||
return tm2sec(&tm);
|
||||
}
|
||||
|
||||
vlong
|
||||
tofiletime(long time)
|
||||
{
|
||||
return ((vlong)time + 11644473600LL) * 10000000;
|
||||
}
|
||||
|
||||
long
|
||||
fromfiletime(vlong filetime)
|
||||
{
|
||||
return filetime / 10000000 - 11644473600LL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
filesize32(vlong size)
|
||||
{
|
||||
if(size > 0xFFFFFFFFUL)
|
||||
return 0xFFFFFFFF;
|
||||
return size;
|
||||
}
|
||||
|
||||
vlong
|
||||
allocsize(vlong size, int blocksize)
|
||||
{
|
||||
return ((size + blocksize-1)/blocksize)*blocksize;
|
||||
}
|
||||
|
||||
int
|
||||
extfileattr(Dir *d)
|
||||
{
|
||||
int a;
|
||||
|
||||
a = (d->qid.type == QTDIR) ? ATTR_DIRECTORY : ATTR_NORMAL;
|
||||
if((d->mode & 0222) == 0)
|
||||
a |= ATTR_READONLY;
|
||||
if(d->name[0] == '.' && d->name[1] && d->name[1] != '.')
|
||||
a |= ATTR_HIDDEN;
|
||||
return a;
|
||||
}
|
||||
|
||||
int
|
||||
dosfileattr(Dir *d)
|
||||
{
|
||||
return extfileattr(d) & DOSMASK;
|
||||
}
|
||||
|
||||
ulong
|
||||
namehash(char *s)
|
||||
{
|
||||
ulong h, t;
|
||||
Rune r;
|
||||
|
||||
h = 0;
|
||||
while(*s){
|
||||
s += chartorune(&r, s);
|
||||
r = toupperrune(r);
|
||||
t = h & 0xf8000000;
|
||||
h <<= 5;
|
||||
h ^= t>>27;
|
||||
h ^= (ulong)r;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
char*
|
||||
strtr(char *s, Rune (*tr)(Rune))
|
||||
{
|
||||
char buf[UTFmax], *p, *w;
|
||||
Rune r;
|
||||
int n;
|
||||
|
||||
p = s;
|
||||
w = s;
|
||||
while(*p){
|
||||
p += chartorune(&r, p);
|
||||
r = (*tr)(r);
|
||||
n = runetochar(buf, &r);
|
||||
if(w + n <= p){
|
||||
memmove(w, buf, n);
|
||||
w += n;
|
||||
}
|
||||
}
|
||||
*w = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
char*
|
||||
strchrs(char *s, char *c)
|
||||
{
|
||||
Rune r;
|
||||
int n;
|
||||
|
||||
while(*s){
|
||||
n = chartorune(&r, s);
|
||||
if(strchr(c, r))
|
||||
return s;
|
||||
s += n;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
static int
|
||||
strpack8(uchar *, uchar *p, uchar *e, char *s, int term, Rune (*tr)(Rune))
|
||||
{
|
||||
uchar *t;
|
||||
Rune r;
|
||||
|
||||
t = p;
|
||||
while((p < e) && *s){
|
||||
s += chartorune(&r, s);
|
||||
r = tr(r);
|
||||
*p++ = r & 0x7F;
|
||||
}
|
||||
if(p >= e)
|
||||
return 0;
|
||||
if(term)
|
||||
*p++ = 0;
|
||||
return p - t;
|
||||
}
|
||||
|
||||
static int
|
||||
strpack16(uchar *b, uchar *p, uchar *e, char *s, int term, Rune (*tr)(Rune))
|
||||
{
|
||||
unsigned int rr;
|
||||
uchar *t;
|
||||
Rune r;
|
||||
|
||||
t = p;
|
||||
if((p - b) % 2){
|
||||
if(p >= e)
|
||||
return 0;
|
||||
*p++ = 0;
|
||||
}
|
||||
while((p+1 < e) && *s){
|
||||
s += chartorune(&r, s);
|
||||
rr = tr(r);
|
||||
if(rr > 0xFFFF){
|
||||
if(p+3 >= e)
|
||||
break;
|
||||
rr -= 0x10000;
|
||||
*p++ = (rr>>10) & 0xFF;
|
||||
*p++ = ((rr>>18)&3) + 0xD8;
|
||||
*p++ = rr & 0xFF;
|
||||
*p++ = ((rr>>8)&3) + 0xDC;
|
||||
} else {
|
||||
*p++ = rr & 0xFF;
|
||||
*p++ = rr>>8;
|
||||
}
|
||||
}
|
||||
if(p+1 >= e)
|
||||
return 0;
|
||||
if(term){
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
}
|
||||
return p - t;
|
||||
}
|
||||
|
||||
static int
|
||||
strunpack8(uchar *, uchar *p, uchar *e, char **dp, int term, Rune (*tr)(Rune))
|
||||
{
|
||||
uchar *t;
|
||||
char *d;
|
||||
Rune r;
|
||||
int n;
|
||||
|
||||
t = p;
|
||||
n = 0;
|
||||
while((p < e) && (!term || *p)){
|
||||
p++;
|
||||
n++;
|
||||
}
|
||||
if(term && ((p >= e) || *p))
|
||||
return 0;
|
||||
p -= n;
|
||||
*dp = d = malloc(n*UTFmax+1);
|
||||
while(n--){
|
||||
r = *p & 0x7F;
|
||||
r = tr(r);
|
||||
d += runetochar(d, &r);
|
||||
p++;
|
||||
}
|
||||
*d = 0;
|
||||
if(term)
|
||||
p++;
|
||||
return p - t;
|
||||
}
|
||||
|
||||
static int
|
||||
strunpack16(uchar *b, uchar *p, uchar *e, char **dp, int term, Rune (*tr)(Rune))
|
||||
{
|
||||
unsigned int rr;
|
||||
uchar *t;
|
||||
char *d;
|
||||
Rune r;
|
||||
int n;
|
||||
|
||||
t = p;
|
||||
if((p - b) % 2)
|
||||
p++;
|
||||
n = 0;
|
||||
while((p+1 < e) && (!term || (p[0] || p[1]))){
|
||||
p += 2;
|
||||
n++;
|
||||
}
|
||||
if(term && ((p+1 >= e) || p[0] || p[1]))
|
||||
return 0;
|
||||
p -= 2*n;
|
||||
*dp = d = malloc(n*UTFmax+1);
|
||||
while(n--){
|
||||
if(p[1] >= 0xD8 && p[1] <= 0xDB){
|
||||
if(!n--)
|
||||
break;
|
||||
rr = ((p[0]<<10) | ((p[1]-0xD8)<<18) | p[2] | ((p[3]-0xDC)<<8))+0x10000;
|
||||
p += 2;
|
||||
} else
|
||||
rr = p[0] | (p[1]<<8);
|
||||
r = tr(rr);
|
||||
d += runetochar(d, &r);
|
||||
p += 2;
|
||||
}
|
||||
*d = 0;
|
||||
if(term)
|
||||
p += 2;
|
||||
return p - t;
|
||||
}
|
||||
|
||||
static Rune
|
||||
notr(Rune r)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
static Rune
|
||||
fromnametr(Rune r)
|
||||
{
|
||||
switch(r){
|
||||
case '\\':
|
||||
return '/';
|
||||
case ' ':
|
||||
if(trspaces)
|
||||
return 0xa0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static Rune
|
||||
tonametr(Rune r)
|
||||
{
|
||||
switch(r){
|
||||
case '/':
|
||||
return '\\';
|
||||
case 0xa0:
|
||||
if(trspaces)
|
||||
return ' ';
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int smbstrpack8(uchar *b, uchar *p, uchar *e, void *arg){
|
||||
return strpack8(b, p, e, (char*)arg, 1, notr);
|
||||
}
|
||||
int smbstrpack16(uchar *b, uchar *p, uchar *e, void *arg){
|
||||
return strpack16(b, p, e, (char*)arg, 1, notr);
|
||||
}
|
||||
int smbstrunpack8(uchar *b, uchar *p, uchar *e, void *arg){
|
||||
return strunpack8(b, p, e, (char**)arg, 1, notr);
|
||||
}
|
||||
int smbstrunpack16(uchar *b, uchar *p, uchar *e, void *arg){
|
||||
return strunpack16(b, p, e, (char**)arg, 1, notr);
|
||||
}
|
||||
int smbnamepack8(uchar *b, uchar *p, uchar *e, void *arg){
|
||||
return strpack8(b, p, e, (char*)arg, 1, tonametr);
|
||||
}
|
||||
int smbnamepack16(uchar *b, uchar *p, uchar *e, void *arg){
|
||||
return strpack16(b, p, e, (char*)arg, 1, tonametr);
|
||||
}
|
||||
int smbnameunpack8(uchar *b, uchar *p, uchar *e, void *arg){
|
||||
return strunpack8(b, p, e, (char**)arg, 1, fromnametr);
|
||||
}
|
||||
int smbnameunpack16(uchar *b, uchar *p, uchar *e, void *arg){
|
||||
return strunpack16(b, p, e, (char**)arg, 1, fromnametr);
|
||||
}
|
||||
int smbuntermstrpack8(uchar *b, uchar *p, uchar *e, void *arg){
|
||||
return strpack8(b, p, e, (char*)arg, 0, notr);
|
||||
}
|
||||
int smbuntermstrpack16(uchar *b, uchar *p, uchar *e, void *arg){
|
||||
return strpack16(b, p, e, (char*)arg, 0, notr);
|
||||
}
|
||||
int smbuntermnamepack8(uchar *b, uchar *p, uchar *e, void *arg){
|
||||
return strpack8(b, p, e, (char*)arg, 0, tonametr);
|
||||
}
|
||||
int smbuntermnamepack16(uchar *b, uchar *p, uchar *e, void *arg){
|
||||
return strpack16(b, p, e, (char*)arg, 0, tonametr);
|
||||
}
|
Loading…
Reference in a new issue