int afp_setforkparms(struct afp_volume * volume, unsigned short forkid, unsigned short bitmap, unsigned long len) { /* The implementation here deserves some explanation. * If the functin is called with an extended size, use 64 bits. * otherwise, 32. */ struct { struct dsi_header dsi_header __attribute__((__packed__)); uint8_t command; uint8_t pad; uint16_t forkid; uint16_t bitmap; union { uint64_t newlen64; struct { uint32_t newlen; uint32_t pad; } __attribute__((__packed__)) newlen32; } newlen; } __attribute__((__packed__)) request_packet; unsigned int actual_len = sizeof(request_packet); dsi_setup_header(volume->server,&request_packet.dsi_header,DSI_DSICommand); request_packet.command=afpSetForkParms; request_packet.pad=0; request_packet.forkid=htons(forkid); request_packet.bitmap=htons(bitmap); if (bitmap & ( kFPExtDataForkLenBit | kFPExtRsrcForkLenBit )) { /* Ah, so this is a long */ request_packet.newlen.newlen64=htonl(len); } else { request_packet.newlen.newlen32.newlen=htonl(len); actual_len-=4; } return dsi_send(volume->server, (char *) &request_packet, actual_len,DSI_DEFAULT_TIMEOUT,afpSetForkParms,NULL); }
int afp_listextattr(struct afp_volume * volume, unsigned int dirid, unsigned short bitmap, char * pathname, struct afp_extattr_info * info) { struct { struct dsi_header dsi_header __attribute__((__packed__)); uint8_t command; uint8_t pad; uint16_t volid ; uint32_t dirid ; uint16_t bitmap; uint16_t reqcount; uint32_t startindex; uint32_t maxreplysize; } __attribute__((__packed__)) *request_packet; struct afp_server * server=volume->server; unsigned int len = sizeof(*request_packet)+sizeof_path_header(server)+strlen(pathname); char * pathptr; int ret; char * msg = malloc(len); if (!msg) { log_for_client(NULL,AFPFSD,LOG_WARNING,"Out of memory\n"); return -1; }; pathptr = msg + (sizeof(*request_packet)); request_packet=(void *) msg; dsi_setup_header(server,&request_packet->dsi_header,DSI_DSICommand); request_packet->command=afpListExtAttrs; request_packet->pad=0; request_packet->volid=htons(volume->volid); request_packet->dirid=htonl(dirid); request_packet->reqcount=0; request_packet->startindex=0; request_packet->bitmap=htons(bitmap); request_packet->maxreplysize=hton64(info->maxsize); copy_path(server,pathptr,pathname,strlen(pathname)); unixpath_to_afppath(server,pathptr); ret=dsi_send(server, (char *) request_packet,len,DSI_DEFAULT_TIMEOUT, afpListExtAttrs , (void *) info); free(msg); return ret; }
int afp_openfork(struct afp_volume * volume, unsigned char forktype, unsigned int dirid, unsigned short accessmode, char * filename, struct afp_file_info * fp) { struct { struct dsi_header dsi_header __attribute__((__packed__)); uint8_t command; uint8_t forktype; uint16_t volid; uint32_t dirid ; uint16_t bitmap ; uint16_t accessmode; } __attribute__((__packed__)) * afp_openfork_request; char * msg; char *pathptr; struct afp_server * server = volume->server; unsigned int len = sizeof(*afp_openfork_request) + sizeof_path_header(server) + strlen(filename); int ret; if ((msg=malloc(len)) == NULL) return -1; pathptr=msg+sizeof(*afp_openfork_request); afp_openfork_request = (void *) msg; dsi_setup_header(server,&afp_openfork_request->dsi_header,DSI_DSICommand); afp_openfork_request->command=afpOpenFork; afp_openfork_request->forktype=forktype ? AFP_FORKTYPE_RESOURCE : AFP_FORKTYPE_DATA; afp_openfork_request->bitmap=0; afp_openfork_request->volid=htons(volume->volid); afp_openfork_request->dirid=htonl(dirid); afp_openfork_request->accessmode=htons(accessmode); copy_path(server,pathptr,filename,strlen(filename)); unixpath_to_afppath(server,pathptr); ret=dsi_send(server, (char *) msg,len,DSI_DEFAULT_TIMEOUT, afpOpenFork,(void *) fp); free(msg); return ret; }
int afp_closefork(struct afp_volume * volume, unsigned short forkid) { struct { struct dsi_header dsi_header __attribute__((__packed__)); uint8_t command; uint8_t pad; uint16_t forkid; } __attribute__((__packed__)) request_packet; dsi_setup_header(volume->server,&request_packet.dsi_header,DSI_DSICommand); request_packet.command=afpCloseFork; request_packet.pad=0; request_packet.forkid=htons(forkid); return dsi_send(volume->server, (char *) &request_packet, sizeof(request_packet),DSI_DEFAULT_TIMEOUT,afpFlushFork,NULL); }
int dsi_opensession(struct afp_server *server) { struct { struct dsi_header dsi_header __attribute__((__packed__)); uint8_t flags; uint8_t length; uint32_t rx_quantum ; } __attribute__((__packed__)) dsi_opensession_header; dsi_setup_header(server,&dsi_opensession_header.dsi_header,DSI_DSIOpenSession); /* Advertize our rx quantum */ dsi_opensession_header.flags=1; dsi_opensession_header.length=sizeof(unsigned int); dsi_opensession_header.rx_quantum=htonl(server->attention_quantum); dsi_send(server,(char *) &dsi_opensession_header, sizeof(dsi_opensession_header),1,DSI_BLOCK_TIMEOUT,NULL); return 0; }
int afp_syncdir(struct afp_volume * volume, unsigned int did) { struct { struct dsi_header dsi_header __attribute__((__packed__)); uint8_t command; uint8_t pad; uint16_t volid; uint32_t dirid; } __attribute__((__packed__)) request_packet; dsi_setup_header(volume->server,&request_packet.dsi_header,DSI_DSICommand); request_packet.command=afpSyncDir; request_packet.pad=0; request_packet.volid=htons(volume->volid); request_packet.dirid=htonl(did); return dsi_send(volume->server, (char *) &request_packet, sizeof(request_packet),DSI_DEFAULT_TIMEOUT,afpSyncDir,NULL); }
int afp_flush(struct afp_volume * volume) { struct { struct dsi_header dsi_header __attribute__((__packed__)); uint8_t command; uint8_t pad; uint16_t volid __attribute__((__packed__)); } __attribute__((__packed__)) afp_flush_request; int ret; dsi_setup_header(volume->server,&afp_flush_request.dsi_header,DSI_DSICommand); afp_flush_request.command=afpFlush; afp_flush_request.pad=0; afp_flush_request.volid=htons(volume->volid); ret=dsi_send(volume->server, (char *) &afp_flush_request, sizeof(afp_flush_request), DSI_DEFAULT_TIMEOUT, afpFlush,(void *) volume); return ret; }
int afp_setextattr(struct afp_volume * volume, unsigned int dirid, unsigned short bitmap, uint64_t offset, char * pathname, unsigned short namelen, char * name, unsigned int attribdatalen, char * attribdata) { struct { struct dsi_header dsi_header __attribute__((__packed__)); uint8_t command; uint8_t pad; uint16_t volid ; uint32_t dirid ; uint16_t bitmap ; uint64_t offset ; } __attribute__((__packed__)) *request_packet; struct afp_server * server = volume->server; unsigned int len = sizeof(*request_packet)+sizeof_path_header(server)+strlen(pathname); char * pathptr; int ret; char * msg = malloc(len); if (!msg) { log_for_client(NULL,AFPFSD,LOG_WARNING,"Out of memory\n"); return -1; }; pathptr = msg + (sizeof(*request_packet)); request_packet=(void *) msg; dsi_setup_header(server,&request_packet->dsi_header,DSI_DSICommand); request_packet->command=afpSetExtAttr; request_packet->pad=0; request_packet->volid=htons(volume->volid); request_packet->dirid=htonl(dirid); copy_path(server,pathptr,pathname,strlen(pathname)); unixpath_to_afppath(server,pathptr); ret=dsi_send(server, (char *) request_packet,len,DSI_DEFAULT_TIMEOUT, afpDelete ,NULL); free(msg); return ret; }
int afp_getvolparms(struct afp_volume * volume,unsigned short bitmap) { struct { struct dsi_header dsi_header __attribute__((__packed__)); uint8_t command; uint8_t pad; uint16_t volid __attribute__((__packed__)); uint16_t bitmap __attribute__((__packed__)); } __attribute__((__packed__)) afp_getvolparms_request; int ret; dsi_setup_header(volume->server,&afp_getvolparms_request.dsi_header,DSI_DSICommand); afp_getvolparms_request.command=afpGetVolParms; afp_getvolparms_request.pad=0; afp_getvolparms_request.volid=htons(volume->volid); afp_getvolparms_request.bitmap=htons(bitmap); ret=dsi_send(volume->server, (char *) &afp_getvolparms_request, sizeof(afp_getvolparms_request), DSI_DEFAULT_TIMEOUT, afpGetVolParms,(void *) volume); return ret; }
int afp_createdir(struct afp_volume * volume, unsigned int dirid, const char * pathname, unsigned int *did_p) { struct { struct dsi_header dsi_header __attribute__((__packed__)); uint8_t command; uint8_t pad; uint16_t volid; uint32_t dirid; } __attribute__((__packed__)) * request_packet; char * pathptr; char * msg; struct afp_server * server = volume->server; unsigned int len = sizeof(*request_packet) + sizeof_path_header(server) + strlen(pathname); int ret; if ((msg=malloc(len)) == NULL) return -1; pathptr=msg+sizeof(*request_packet); request_packet = (void *) msg; dsi_setup_header(server,&request_packet->dsi_header,DSI_DSICommand); request_packet->command=afpCreateDir; request_packet->pad=0; request_packet->volid=htons(volume->volid); request_packet->dirid=htonl(dirid); copy_path(server,pathptr,pathname,strlen(pathname)); unixpath_to_afppath(server,pathptr); ret=dsi_send(server, (char *) msg,len,DSI_DEFAULT_TIMEOUT, afpCreateDir,(void *)did_p); free(msg); return ret; }
/* hand off the command. return child connection to the main program */ afp_child_t *dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval) { pid_t pid; unsigned int ipc_fds[2]; afp_child_t *child; if (socketpair(PF_UNIX, SOCK_STREAM, 0, ipc_fds) < 0) { LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno)); exit( EXITERR_CLNT ); } if (setnonblock(ipc_fds[0], 1) != 0 || setnonblock(ipc_fds[1], 1) != 0) { LOG(log_error, logtype_dsi, "dsi_getsess: setnonblock: %s", strerror(errno)); exit(EXITERR_CLNT); } switch (pid = dsi->proto_open(dsi)) { /* in libatalk/dsi/dsi_tcp.c */ case -1: /* if we fail, just return. it might work later */ LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno)); return NULL; case 0: /* child. mostly handled below. */ break; default: /* parent */ /* using SIGQUIT is hokey, but the child might not have * re-established its signal handler for SIGTERM yet. */ if ((child = server_child_add(serv_children, CHILD_DSIFORK, pid, ipc_fds)) < 0) { LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno)); dsi->header.dsi_flags = DSIFL_REPLY; dsi->header.dsi_code = DSIERR_SERVBUSY; dsi_send(dsi); dsi->header.dsi_code = DSIERR_OK; kill(pid, SIGQUIT); } dsi->proto_close(dsi); return child; } /* child: check number of open connections. this is one off the * actual count. */ if ((serv_children->count >= serv_children->nsessions) && (dsi->header.dsi_command == DSIFUNC_OPEN)) { LOG(log_info, logtype_dsi, "dsi_getsess: too many connections"); dsi->header.dsi_flags = DSIFL_REPLY; dsi->header.dsi_code = DSIERR_TOOMANY; dsi_send(dsi); exit(EXITERR_CLNT); } /* get rid of some stuff */ close(dsi->serversock); server_child_free(serv_children); switch (dsi->header.dsi_command) { case DSIFUNC_STAT: /* send off status and return */ { /* OpenTransport 1.1.2 bug workaround: * * OT code doesn't currently handle close sockets well. urk. * the workaround: wait for the client to close its * side. timeouts prevent indefinite resource use. */ static struct timeval timeout = {120, 0}; fd_set readfds; dsi_getstatus(dsi); FD_ZERO(&readfds); FD_SET(dsi->socket, &readfds); free(dsi); select(FD_SETSIZE, &readfds, NULL, NULL, &timeout); exit(0); } break; case DSIFUNC_OPEN: /* setup session */ /* set up the tickle timer */ dsi->timer.it_interval.tv_sec = dsi->timer.it_value.tv_sec = tickleval; dsi->timer.it_interval.tv_usec = dsi->timer.it_value.tv_usec = 0; signal(SIGPIPE, SIG_IGN); /* we catch these ourselves */ dsi_opensession(dsi); if ((child = calloc(1, sizeof(afp_child_t))) == NULL) exit(EXITERR_SYS); child->ipc_fds[1] = ipc_fds[1]; return child; break; default: /* just close */ LOG(log_info, logtype_dsi, "DSIUnknown %d", dsi->header.dsi_command); dsi->proto_close(dsi); exit(EXITERR_CLNT); } }
int afp_enumerateext2( struct afp_volume * volume, unsigned int dirid, unsigned int filebitmap, unsigned int dirbitmap, unsigned short reqcount, unsigned long startindex, char * pathname, struct afp_file_info ** file_p) { struct { struct dsi_header dsi_header __attribute__((__packed__)); uint8_t command; uint8_t pad; uint16_t volid; uint32_t dirid; uint16_t filebitmap; uint16_t dirbitmap; uint16_t reqcount; uint32_t startindex; uint32_t maxreplysize; } __attribute__((__packed__)) * afp_enumerateext2_request_packet; unsigned short len; char * data; int rc; struct afp_file_info * files = NULL; struct afp_server * server = volume->server; char * path; len = sizeof_path_header(server) + strlen(pathname) + sizeof(*afp_enumerateext2_request_packet); if ((data=malloc(len))==NULL) return -1; path = data+sizeof(*afp_enumerateext2_request_packet); afp_enumerateext2_request_packet = (void *) data; dsi_setup_header(server,&afp_enumerateext2_request_packet->dsi_header,DSI_DSICommand); afp_enumerateext2_request_packet->command=afpEnumerateExt2; afp_enumerateext2_request_packet->pad=0; afp_enumerateext2_request_packet->volid=htons(volume->volid); afp_enumerateext2_request_packet->dirid=htonl(dirid); afp_enumerateext2_request_packet->filebitmap=htons(filebitmap); afp_enumerateext2_request_packet->dirbitmap=htons(dirbitmap); afp_enumerateext2_request_packet->reqcount=htons(reqcount); afp_enumerateext2_request_packet->startindex=htonl(startindex); afp_enumerateext2_request_packet->maxreplysize=htonl(5280); copy_path(server,path,pathname,strlen(pathname)); unixpath_to_afppath(server,path); //printf("afp_enumerateext2:\t"); //printf("volid:%x\t",volume->volid); //printf("dirid:%x\t",dirid); //printf("filebitmap:%x\t",filebitmap); //printf("dirbitmap:%x\t",dirbitmap); //printf("reqcount:%u\t",reqcount); //printf("startindex:%u\n",startindex); rc=dsi_send(server, (char *) data,len,DSI_DEFAULT_TIMEOUT, afpEnumerateExt2,(void **) &files); *file_p = files; free(data); return rc; }
int afp_moveandrename(struct afp_volume *volume, unsigned int src_did, unsigned int dst_did, char * src_path, char * dst_path, char *new_name) { struct { struct dsi_header dsi_header __attribute__((__packed__)); uint8_t command; uint8_t pad; uint16_t volid ; uint32_t src_did; uint32_t dst_did ; } __attribute__((__packed__)) * request_packet; char * p; char * msg; struct afp_server * server = volume->server; unsigned int len; unsigned int dlen=0,slen=0,nlen=0; int ret; unsigned short header_len=sizeof_path_header(server); char null_path[255]; if (dst_path==NULL) { null_path[0]='\0'; dlen=0; dst_path=null_path; } else { dlen=strlen(dst_path); } if (src_path) slen=strlen(src_path); if (new_name) nlen=strlen(new_name); len = sizeof(*request_packet) + (3* header_len) + dlen + slen + nlen; if ((msg=malloc(len)) == NULL) return -1; request_packet=(void *) msg; dsi_setup_header(server,&request_packet->dsi_header,DSI_DSICommand); request_packet->command=afpMoveAndRename; request_packet->pad=0; request_packet->volid=htons(volume->volid); request_packet->src_did=htonl(src_did); request_packet->dst_did=htonl(dst_did); p=msg+sizeof(*request_packet); copy_path(server,p,src_path,slen); unixpath_to_afppath(server,p); p+=sizeof_path_header(server)+slen; copy_path(server,p,dst_path,dlen); unixpath_to_afppath(server,p); p+=sizeof_path_header(server)+dlen; copy_path(server,p,new_name,nlen); unixpath_to_afppath(server,p); ret=dsi_send(server, (char *) msg,len,DSI_DEFAULT_TIMEOUT,afpMoveAndRename,NULL); free(msg); return ret; }