1 /* Copyright ©2007 Kris Maglione <fbsdaemon@gmail.com>
2 * See LICENSE file for license details.
9 #include <sys/socket.h>
10 #include <sys/types.h>
12 #include "mixp_local.h"
13 #include <9p-mixp/stat.h>
14 #include <9p-mixp/err.h>
15 #include <9p-mixp/convert.h>
19 #define nelem(ary) (sizeof(ary) / sizeof(*ary))
33 getfid(MIXP_CLIENT
*c
) {
36 mixp_thread
->lock(&c
->lk
);
41 f
= calloc(1,sizeof *f
);
43 f
->fid
= ++c
->lastfid
;
44 mixp_thread
->initmutex(&f
->iolock
);
48 mixp_thread
->unlock(&c
->lk
);
53 putfid(MIXP_CFID
*f
) {
57 mixp_thread
->lock(&c
->lk
);
58 if(f
->fid
== c
->lastfid
) {
60 mixp_thread
->mdestroy(&f
->iolock
);
66 mixp_thread
->unlock(&c
->lk
);
69 static IxpFcall
* do_fcall(MIXP_CLIENT
* c
, IxpFcall
* fcall
)
73 ret
= muxrpc(c
, fcall
);
76 // fprintf(mixp_error_stream,"MIXP: fcall without reply\n");
80 if(ret
->type
== P9_RError
) {
81 mixp_werrstr("%s", ret
->Rerror
.ename
);
82 fprintf(mixp_error_stream
, "MIXP: fcall returned error %s\n", ret
->Rerror
.ename
);
85 if(ret
->type
!= (fcall
->type
^1)) {
86 mixp_werrstr("received mismatched fcall");
87 fprintf(mixp_error_stream
, "MIXP: received mismatched fcall\n");
94 dofcall(MIXP_CLIENT
*c
, IxpFcall
*fcall
) {
97 ret
= muxrpc(c
, fcall
);
100 if(ret
->type
== P9_RError
) {
101 mixp_werrstr("%s", ret
->Rerror
.ename
);
104 if(ret
->type
!= (fcall
->type
^1)) {
105 mixp_werrstr("received mismatched fcall");
108 memcpy(fcall
, ret
, sizeof(IxpFcall
));
112 mixp_fcall_free(fcall
);
117 mixp_unmount(MIXP_CLIENT
*c
) {
120 shutdown(c
->fd
, SHUT_RDWR
);
125 while((f
= c
->freefid
)) {
126 c
->freefid
= f
->next
;
127 mixp_thread
->mdestroy(&f
->iolock
);
130 MIXP_FREE(c
->rmsg
.data
);
131 MIXP_FREE(c
->wmsg
.data
);
136 allocmsg(MIXP_CLIENT
*c
, int n
) {
139 c
->rmsg
.data
= ixp_erealloc(c
->rmsg
.data
, n
);
140 c
->wmsg
.data
= ixp_erealloc(c
->wmsg
.data
, n
);
144 mixp_mountfd(int fd
) {
146 IxpFcall
* fcall
= (IxpFcall
*)calloc(1,sizeof(IxpFcall
));
147 IxpFcall
* retfcall
= NULL
;
149 c
= calloc(1,sizeof(*c
));
155 c
->lastfid
= RootFid
;
156 /* Override tag matching on P9_TVersion */
157 c
->mintag
= IXP_NOTAG
;
158 c
->maxtag
= IXP_NOTAG
+1;
160 fcall
->type
= P9_TVersion
;
161 fcall
->Tversion
.msize
= IXP_MAX_MSG
;
162 fcall
->Tversion
.version
= IXP_VERSION
;
164 if ((retfcall
= do_fcall(c
, fcall
))==NULL
)
167 mixp_fcall_free(fcall
);
171 if(strcmp(retfcall
->Rversion
.version
, IXP_VERSION
) ||
172 retfcall
->Rversion
.msize
> IXP_MAX_MSG
) {
173 mixp_werrstr("bad 9P version response");
175 mixp_fcall_free(fcall
);
176 mixp_fcall_free(retfcall
);
183 allocmsg(c
, retfcall
->Tversion
.msize
);
185 mixp_fcall_free(fcall
);
186 mixp_fcall_free(retfcall
);
188 fcall
= (IxpFcall
*)calloc(1,sizeof(IxpFcall
));
190 fcall
->type
= P9_TAttach
;
191 fcall
->fid
= RootFid
;
192 fcall
->Tattach
.afid
= IXP_NOFID
;
193 fcall
->Tattach
.uname
= getenv("USER");
194 fcall
->Tattach
.aname
= "";
195 if((retfcall
= do_fcall(c
, fcall
)) == NULL
) {
197 mixp_fcall_free(fcall
);
201 mixp_fcall_free(fcall
);
202 mixp_fcall_free(retfcall
);
207 mixp_mount(const char *address
) {
210 fd
= mixp_dial(address
);
213 return mixp_mountfd(fd
);
216 MIXP_CLIENT
* mixp_mount_addr(MIXP_SERVER_ADDRESS
*addr
)
220 fd
= mixp_dial_addr(addr
);
223 return mixp_mountfd(fd
);
227 walk(MIXP_CLIENT
*c
, const char *pathname
) {
231 IxpFcall
* fcall
= (IxpFcall
*)calloc(1,sizeof(IxpFcall
));
232 IxpFcall
* retfcall
= NULL
;
234 char* path
= strdup(pathname
);
235 n
= ixp_tokenize(fcall
->Twalk
.wname
, nelem(fcall
->Twalk
.wname
), path
, '/');
239 fcall
->type
= P9_TWalk
;
240 fcall
->fid
= RootFid
;
241 fcall
->Twalk
.nwname
= n
;
242 fcall
->Twalk
.newfid
= f
->fid
;
243 if((retfcall
=do_fcall(c
, fcall
)) == NULL
)
245 if(retfcall
->Rwalk
.nwqid
< n
)
248 f
->qid
= fcall
->Rwalk
.wqid
[n
-1];
255 mixp_fcall_free(fcall
);
256 mixp_fcall_free(retfcall
);
262 walkdir(MIXP_CLIENT
*c
, char *path
, char **rest
) {
265 p
= path
+ strlen(path
) - 1;
270 while((p
> path
) && (*p
!= '/'))
273 mixp_werrstr("bad path");
279 return walk(c
, path
);
283 clunk(MIXP_CFID
*f
) {
285 IxpFcall
* fcall
= (IxpFcall
*)calloc(1,sizeof(IxpFcall
));
286 IxpFcall
* retfcall
= NULL
;
290 fcall
->type
= P9_TClunk
;
292 if ((retfcall
=do_fcall(c
,fcall
))==NULL
)
294 mixp_fcall_free(fcall
);
300 mixp_fcall_free(retfcall
);
301 mixp_fcall_free(fcall
);
307 mixp_remove(MIXP_CLIENT
*c
, const char *path
)
310 if((f
= walk(c
, path
)) == NULL
)
313 IxpFcall
*fcall
= calloc(1,sizeof(IxpFcall
));
314 fcall
->type
= P9_TRemove
;
317 IxpFcall
*retfcall
= NULL
;
318 if ((retfcall
= do_fcall(c
, fcall
))==NULL
)
320 mixp_fcall_free(fcall
);
326 mixp_fcall_free(fcall
);
327 mixp_fcall_free(retfcall
);
333 initfid(MIXP_CFID
*f
, IxpFcall
*fcall
)
339 f
->iounit
= min(fcall
->Ropen
.iounit
, IXP_MAX_MSG
-17);
340 f
->qid
= fcall
->Ropen
.qid
;
344 // fprintf(mixp_error_stream,"initfid() iounit missing. fixing to %d\n", DEFAULT_IOUNIT);
345 f
->iounit
=DEFAULT_IOUNIT
;
350 // fprintf(mixp_error_stream,"initfid() iounit <0: %d .. fixing to %d\n", f->iounit, DEFAULT_IOUNIT);
351 f
->iounit
=DEFAULT_IOUNIT
;
356 mixp_create(MIXP_CLIENT
*c
, const char *filename
, unsigned int perm
, unsigned char mode
)
359 char *path
= strdup(filename
);
360 char *name
= strdup(filename
); // FIXME: correct ?!
362 if ((f
= walkdir(c
, path
, &name
))==NULL
)
368 IxpFcall
*fcall
= (IxpFcall
*)calloc(1,sizeof(IxpFcall
));
369 fcall
->type
= P9_TCreate
;
371 fcall
->Tcreate
.name
= name
;
372 fcall
->Tcreate
.perm
= perm
;
373 fcall
->Tcreate
.mode
= mode
;
376 if ((retfcall
= do_fcall(c
, fcall
)) == NULL
)
383 initfid(f
, retfcall
);
385 mixp_fcall_free(retfcall
);
391 mixp_open(MIXP_CLIENT
*c
, const char *name
, unsigned char mode
)
399 IxpFcall
* fcall
= (IxpFcall
*)calloc(1,sizeof(IxpFcall
));
400 fcall
->type
= P9_TOpen
;
402 fcall
->Topen
.mode
= mode
;
406 if ((retfcall
=do_fcall(c
, fcall
)) == NULL
)
409 mixp_fcall_free(fcall
);
413 initfid(f
, retfcall
);
415 mixp_fcall_free(fcall
);
416 mixp_fcall_free(retfcall
);
420 int mixp_close(MIXP_CFID
*f
)
426 mixp_stat(MIXP_CLIENT
*c
, const char *path
)
437 IxpFcall
* fcall
= (IxpFcall
*)calloc(1,sizeof(IxpFcall
));
438 fcall
->type
= P9_TStat
;
442 if((retfcall
= do_fcall(c
, fcall
))==NULL
)
445 msg
= mixp_message(retfcall
->Rstat
.stat
, retfcall
->Rstat
.nstat
, MsgUnpack
);
447 stat
= malloc(sizeof(MIXP_STAT
));
448 mixp_pstat(&msg
, stat
);
449 mixp_fcall_free(fcall
);
450 if(msg
.pos
> msg
.end
) {
457 mixp_fcall_free(fcall
);
458 mixp_fcall_free(retfcall
);
462 static long _pread(MIXP_CFID
*f
, void *buf
, size_t count
, int64_t offset
)
466 IxpFcall
* fcall
= NULL
;
467 IxpFcall
* retfcall
= NULL
;
471 mixp_fcall_free(fcall
); fcall
= NULL
;
472 mixp_fcall_free(retfcall
); retfcall
= NULL
;
474 fcall
= (IxpFcall
*)calloc(1,sizeof(IxpFcall
));
475 int n
= min(count
-len
, f
->iounit
);
477 fcall
->type
= P9_TRead
;
479 fcall
->Tread
.offset
= offset
;
480 fcall
->Tread
.count
= n
;
482 if ((retfcall
= do_fcall(f
->client
, fcall
)) == NULL
)
484 fprintf(mixp_error_stream
,"MIXP: _pread() fcall failed\n");
488 if (retfcall
->Rread
.count
> n
)
490 fprintf(mixp_error_stream
,"MIXP: _pread() received more (%d) than requested (%d)\n", retfcall
->Rread
.count
, n
);
494 memcpy(buf
+len
, retfcall
->Rread
.data
, retfcall
->Rread
.count
);
495 offset
+= retfcall
->Rread
.count
;
496 len
+= retfcall
->Rread
.count
;
498 if(retfcall
->Rread
.count
< n
)
501 mixp_fcall_free(fcall
);
502 mixp_fcall_free(retfcall
);
505 mixp_fcall_free(fcall
);
506 mixp_fcall_free(retfcall
);
510 long mixp_read(MIXP_CFID
*f
, void *buf
, size_t count
)
514 mixp_thread
->lock(&f
->iolock
);
515 n
= _pread(f
, buf
, count
, f
->offset
);
518 mixp_thread
->unlock(&f
->iolock
);
522 long mixp_pread(MIXP_CFID
*f
, void *buf
, long count
, int64_t offset
)
526 mixp_thread
->lock(&f
->iolock
);
527 n
= _pread(f
, buf
, count
, offset
);
528 mixp_thread
->unlock(&f
->iolock
);
532 static long _pwrite(MIXP_CFID
*f
, const void *buf
, long count
, int64_t offset
)
538 IxpFcall
* fcall
= (IxpFcall
*)calloc(1,sizeof(IxpFcall
));
539 IxpFcall
* retfcall
= NULL
;
541 n
= min(count
-len
, f
->iounit
);
542 fcall
->type
= P9_TWrite
;
544 fcall
->Twrite
.offset
= f
->offset
;
545 fcall
->Twrite
.data
= (char*)(buf
+ len
);
546 fcall
->Twrite
.count
= n
;
547 if ((retfcall
= do_fcall(f
->client
, fcall
)) == NULL
)
549 mixp_fcall_free(fcall
);
553 f
->offset
+= retfcall
->Rwrite
.count
;
554 len
+= retfcall
->Rwrite
.count
;
556 if(fcall
->Rwrite
.count
< n
)
558 mixp_fcall_free(fcall
);
559 mixp_fcall_free(retfcall
);
562 mixp_fcall_free(fcall
);
563 mixp_fcall_free(retfcall
);
564 } while(len
< count
);
569 mixp_write(MIXP_CFID
*f
, const void *buf
, long count
) {
572 mixp_thread
->lock(&f
->iolock
);
573 n
= _pwrite(f
, buf
, count
, f
->offset
);
576 mixp_thread
->unlock(&f
->iolock
);
581 mixp_pwrite(MIXP_CFID
*f
, const void *buf
, long count
, int64_t offset
) {
584 mixp_thread
->lock(&f
->iolock
);
585 n
= _pwrite(f
, buf
, count
, offset
);
586 mixp_thread
->unlock(&f
->iolock
);