mirror of
https://github.com/mabam/afpfs-ng-mac.git
synced 2025-01-20 18:29:41 +00:00
514 lines
14 KiB
C
514 lines
14 KiB
C
|
|
/*
|
|
* files.c
|
|
*
|
|
* Copyright (C) 2006 Alex deVries
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "afpfs-ng/dsi.h"
|
|
#include "afpfs-ng/afp.h"
|
|
#include "afpfs-ng/utils.h"
|
|
#include "dsi_protocol.h"
|
|
#include "afpfs-ng/afp_protocol.h"
|
|
#include "afp_internal.h"
|
|
#include "afp_replies.h"
|
|
|
|
/* afp_setfileparms, afp_setdirparms and afpsetfiledirparms are all remarkably
|
|
similiar. We abstract them to afp-setparms_lowlevel. */
|
|
|
|
static int afp_setparms_lowlevel(struct afp_volume * volume,
|
|
unsigned int dirid, const char * pathname, unsigned short bitmap,
|
|
struct afp_file_info *fp, char command)
|
|
{
|
|
struct {
|
|
struct dsi_header dsi_header __attribute__((__packed__));
|
|
uint8_t command;
|
|
uint8_t pad;
|
|
uint16_t volid;
|
|
uint32_t dirid;
|
|
uint16_t bitmap;
|
|
} __attribute__((__packed__)) *request_packet;
|
|
struct afp_server * server=volume->server;
|
|
unsigned short result_bitmap=0;
|
|
unsigned int len = sizeof(*request_packet) +
|
|
sizeof_path_header(server)+strlen(pathname) +
|
|
200 + /* This is the max size of a data block */
|
|
1; /* In case we're not on an even boundary */
|
|
|
|
char * msg, * pathptr, *p;
|
|
int ret;
|
|
|
|
if ((msg=malloc(len))==NULL)
|
|
return -1;
|
|
pathptr= msg+sizeof(*request_packet);
|
|
p = pathptr + sizeof_path_header(server)+strlen(pathname);
|
|
|
|
if (((uintptr_t) p) & 0x1) p++; /* Make sure we're on an even boundary */
|
|
memset(msg,0,len);
|
|
request_packet = (void *) msg;
|
|
dsi_setup_header(server,&request_packet->dsi_header,DSI_DSICommand);
|
|
request_packet->command=command;
|
|
request_packet->pad=0;
|
|
request_packet->volid=htons(volume->volid);
|
|
request_packet->dirid=htonl(dirid);
|
|
request_packet->bitmap=htons(bitmap);
|
|
copy_path(server,pathptr,pathname,strlen(pathname));
|
|
unixpath_to_afppath(server,pathptr);
|
|
|
|
if (bitmap & kFPAttributeBit) {
|
|
/* Todo:
|
|
The spec says: "The following parameters may be set or cleared:
|
|
Attributes (all attributes except DAlreadyOpen,
|
|
RAlreadyOpen, and CopyProtect)". This should be checked.
|
|
*/
|
|
|
|
*p=htons(fp->attributes);
|
|
result_bitmap|=kFPAttributeBit;
|
|
p+=2;
|
|
}
|
|
|
|
if (bitmap & kFPCreateDateBit) {
|
|
unsigned int * date = (void *) p;
|
|
*date = AD_DATE_FROM_UNIX(fp->creation_date);
|
|
result_bitmap|=kFPCreateDateBit;
|
|
p+=4;
|
|
}
|
|
if (bitmap & kFPModDateBit) {
|
|
unsigned int * date = (void *) p;
|
|
*date = AD_DATE_FROM_UNIX(fp->modification_date);
|
|
result_bitmap|=kFPModDateBit;
|
|
p+=4;
|
|
|
|
}
|
|
if (bitmap & kFPBackupDateBit) {
|
|
unsigned int * date = (void *) p;
|
|
*date = AD_DATE_FROM_UNIX(fp->backup_date);
|
|
p+=4;
|
|
result_bitmap|=kFPBackupDateBit;
|
|
}
|
|
if (bitmap & kFPFinderInfoBit) {
|
|
result_bitmap|=kFPFinderInfoBit;
|
|
memcpy(p,fp->finderinfo,32);
|
|
p+=32;;
|
|
}
|
|
if (bitmap & kFPUnixPrivsBit) {
|
|
struct afp_unixprivs * t_unixprivs = (void *) p;
|
|
memcpy(t_unixprivs,&fp->unixprivs,
|
|
sizeof(struct afp_unixprivs));
|
|
/* Convert the different components */
|
|
t_unixprivs->uid=htonl(t_unixprivs->uid);
|
|
t_unixprivs->gid=htonl(t_unixprivs->gid);
|
|
t_unixprivs->permissions=htonl(t_unixprivs->permissions);
|
|
t_unixprivs->ua_permissions=htonl(t_unixprivs->ua_permissions);
|
|
|
|
p+=sizeof(struct afp_unixprivs);
|
|
result_bitmap|=kFPUnixPrivsBit;
|
|
|
|
|
|
}
|
|
|
|
ret=dsi_send(server, (char *) msg,p-msg,DSI_DEFAULT_TIMEOUT,
|
|
command,NULL);
|
|
|
|
free(msg);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int afp_setfileparms(struct afp_volume * volume,
|
|
unsigned int dirid, const char * pathname, unsigned short bitmap,
|
|
struct afp_file_info *fp)
|
|
{
|
|
return afp_setparms_lowlevel(volume,dirid,pathname,bitmap,
|
|
fp,afpSetFileParms);
|
|
}
|
|
|
|
int afp_setfiledirparms(struct afp_volume * volume,
|
|
unsigned int dirid, const char * pathname, unsigned short bitmap,
|
|
struct afp_file_info *fp)
|
|
{
|
|
return afp_setparms_lowlevel(volume,dirid,pathname,bitmap,
|
|
fp,afpSetFileDirParms);
|
|
}
|
|
|
|
int afp_setdirparms(struct afp_volume * volume,
|
|
unsigned int dirid, const char * pathname, unsigned short bitmap,
|
|
struct afp_file_info *fp)
|
|
{
|
|
return afp_setparms_lowlevel(volume,dirid,pathname,bitmap,
|
|
fp,afpSetDirParms);
|
|
}
|
|
|
|
int afp_delete(struct afp_volume * volume,
|
|
unsigned int dirid, char * pathname)
|
|
{
|
|
struct {
|
|
struct dsi_header dsi_header __attribute__((__packed__));
|
|
uint8_t command;
|
|
uint8_t pad;
|
|
uint16_t volid;
|
|
uint32_t dirid;
|
|
} __attribute__((__packed__)) *request_packet;
|
|
struct afp_server * server = volume->server;
|
|
unsigned int len = sizeof(*request_packet)+sizeof_path_header(server)+strlen(pathname);
|
|
char * pathptr, *msg;
|
|
int ret=0;
|
|
if ((msg=malloc(len))==NULL) {
|
|
log_for_client(NULL,AFPFSD,LOG_ERR,
|
|
"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=afpDelete;
|
|
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_read(struct afp_volume * volume, unsigned short forkid,
|
|
uint32_t offset,
|
|
uint32_t count,
|
|
struct afp_rx_buffer * rx)
|
|
{
|
|
int rc;
|
|
struct {
|
|
struct dsi_header dsi_header __attribute__((__packed__));
|
|
uint8_t command;
|
|
uint8_t pad;
|
|
uint16_t forkrefnum;
|
|
uint32_t offset;
|
|
uint32_t reqcount;
|
|
uint8_t newlinemask;
|
|
uint8_t newlinechar;
|
|
} __attribute__((__packed__)) readext_packet;
|
|
|
|
dsi_setup_header(volume->server,&readext_packet.dsi_header,DSI_DSICommand);
|
|
readext_packet.command=afpRead;
|
|
readext_packet.pad=0x0;
|
|
readext_packet.forkrefnum=htons(forkid);
|
|
readext_packet.offset=htonl(offset);
|
|
readext_packet.reqcount=htonl(count);
|
|
readext_packet.newlinemask=0;
|
|
readext_packet.newlinechar=0;
|
|
rc=dsi_send(volume->server, (char *) &readext_packet,
|
|
sizeof(readext_packet), DSI_DEFAULT_TIMEOUT,
|
|
afpRead, (void *) rx);
|
|
return rc;
|
|
}
|
|
|
|
int afp_read_reply(struct afp_server *server, char * buf, unsigned int size,void * other )
|
|
{
|
|
struct afp_rx_buffer * rx = other;
|
|
struct dsi_header * header = (void *) buf;
|
|
char * ptr = buf + sizeof(struct dsi_header);
|
|
unsigned int rx_quantum = server->rx_quantum;
|
|
|
|
size-=sizeof(struct dsi_header);
|
|
|
|
if (size>rx_quantum) {
|
|
log_for_client(NULL,AFPFSD,LOG_ERR,
|
|
"This is definitely weird, I guess I'll just drop %d bytes\n",size-rx_quantum);
|
|
size=rx_quantum;
|
|
}
|
|
memcpy(rx->data,ptr,size);
|
|
rx->size=size;
|
|
rx->errorcode=ntohl(header->return_code.error_code);
|
|
return 0;
|
|
}
|
|
|
|
int afp_readext(struct afp_volume * volume, unsigned short forkid,
|
|
uint64_t offset,
|
|
uint64_t count,
|
|
struct afp_rx_buffer * rx)
|
|
{
|
|
int rc;
|
|
struct {
|
|
struct dsi_header dsi_header __attribute__((__packed__));
|
|
uint8_t command;
|
|
uint8_t pad;
|
|
uint16_t forkrefnum;
|
|
uint64_t offset;
|
|
uint64_t reqcount;
|
|
} __attribute__((__packed__)) readext_packet;
|
|
|
|
dsi_setup_header(volume->server,&readext_packet.dsi_header,DSI_DSICommand);
|
|
readext_packet.command=afpReadExt;
|
|
readext_packet.pad=0x0;
|
|
readext_packet.forkrefnum=htons(forkid);
|
|
readext_packet.offset=hton64(offset);
|
|
readext_packet.reqcount=hton64(count);
|
|
rc=dsi_send(volume->server, (char *) &readext_packet,
|
|
sizeof(readext_packet), DSI_DEFAULT_TIMEOUT,
|
|
afpReadExt, (void *) rx);
|
|
return rc;
|
|
}
|
|
|
|
int afp_readext_reply(struct afp_server *server, char * buf, unsigned int size, void * other)
|
|
{
|
|
struct afp_rx_buffer * rx = other;
|
|
struct dsi_header * header = (void *) buf;
|
|
char * ptr = buf + sizeof(struct dsi_header);
|
|
unsigned int rx_quantum = server->rx_quantum;
|
|
|
|
size-=sizeof(struct dsi_header);
|
|
|
|
if (size>rx_quantum) {
|
|
log_for_client(NULL,AFPFSD,LOG_ERR,
|
|
"This is definitely weird, I guess I'll just drop %d bytes\n",size-rx_quantum);
|
|
size=rx_quantum;
|
|
}
|
|
memcpy(rx->data,ptr,size);
|
|
rx->size=size;
|
|
rx->errorcode=ntohl(header->return_code.error_code);
|
|
return 0;
|
|
}
|
|
|
|
int afp_getfiledirparms_reply(struct afp_server *server, char * buf, unsigned int size,
|
|
void * other)
|
|
{
|
|
struct {
|
|
struct dsi_header header __attribute__((__packed__));
|
|
uint16_t filebitmap;
|
|
uint16_t dirbitmap;
|
|
uint8_t isdir;
|
|
uint8_t pad;
|
|
} __attribute__((__packed__)) * reply_packet = (void *) buf;
|
|
struct afp_file_info * filecur = other;
|
|
|
|
if (reply_packet->header.return_code.error_code)
|
|
return reply_packet->header.return_code.error_code;
|
|
|
|
if (size<sizeof(*reply_packet))
|
|
return -1;
|
|
|
|
parse_reply_block(server,
|
|
buf + (sizeof(*reply_packet)),
|
|
size,
|
|
reply_packet->isdir,
|
|
ntohs(reply_packet->filebitmap),
|
|
ntohs(reply_packet->dirbitmap),
|
|
filecur);
|
|
filecur->isdir=reply_packet->isdir;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int afp_getfiledirparms(struct afp_volume *volume, unsigned int did, unsigned int filebitmap, unsigned int dirbitmap, const char * pathname,
|
|
struct afp_file_info *fpp)
|
|
{
|
|
struct {
|
|
struct dsi_header dsi_header __attribute__((__packed__));
|
|
uint8_t command;
|
|
uint8_t pad;
|
|
uint16_t volid;
|
|
uint32_t did;
|
|
uint16_t file_bitmap;
|
|
uint16_t directory_bitmap;
|
|
} __attribute__((__packed__)) * getfiledirparms;
|
|
struct afp_server * server = volume->server;
|
|
int ret = 0;
|
|
char *path, * msg;
|
|
unsigned int len;
|
|
|
|
if (!pathname) return -1;
|
|
|
|
len = sizeof(*getfiledirparms)+sizeof_path_header(server)+strlen(pathname);
|
|
|
|
if ((msg = malloc(len))==NULL)
|
|
return -1;
|
|
|
|
path = msg + (sizeof(*getfiledirparms));
|
|
getfiledirparms=(void *) msg;
|
|
|
|
dsi_setup_header(server,&getfiledirparms->dsi_header,DSI_DSICommand);
|
|
getfiledirparms->command=afpGetFileDirParms;
|
|
getfiledirparms->pad=0;
|
|
getfiledirparms->volid=htons(volume->volid);
|
|
getfiledirparms->did=htonl(did);
|
|
getfiledirparms->file_bitmap=htons(filebitmap);
|
|
getfiledirparms->directory_bitmap=htons(dirbitmap);
|
|
copy_path(server,path,pathname,strlen(pathname));
|
|
unixpath_to_afppath(server,path);
|
|
|
|
ret=dsi_send(server, (char *) getfiledirparms,len,DSI_DEFAULT_TIMEOUT,
|
|
afpGetFileDirParms,(void *) fpp);
|
|
|
|
free(msg);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int afp_createfile(struct afp_volume * volume, unsigned char flag,
|
|
unsigned int did,
|
|
char * pathname)
|
|
{
|
|
struct {
|
|
struct dsi_header dsi_header __attribute__((__packed__));
|
|
uint8_t command;
|
|
uint8_t flag;
|
|
uint16_t volid;
|
|
uint32_t did;
|
|
} __attribute__((__packed__)) * request_packet;
|
|
char * path, *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;
|
|
path = msg + (sizeof(*request_packet));
|
|
request_packet =(void *) msg;
|
|
dsi_setup_header(server,&request_packet->dsi_header,DSI_DSICommand);
|
|
|
|
request_packet->command=afpCreateFile;
|
|
request_packet->flag=flag;
|
|
request_packet->volid=htons(volume->volid);
|
|
request_packet->did=htonl(did);
|
|
copy_path(server,path,pathname,strlen(pathname));
|
|
unixpath_to_afppath(server,path);
|
|
|
|
ret=dsi_send(server, (char *) request_packet,len,DSI_DEFAULT_TIMEOUT,
|
|
afpCreateFile,NULL);
|
|
|
|
free(msg);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int afp_write(struct afp_volume * volume, unsigned short forkid,
|
|
uint32_t offset, uint32_t reqcount,
|
|
char * data,uint32_t * written)
|
|
{
|
|
struct {
|
|
struct dsi_header dsi_header __attribute__((__packed__));
|
|
uint8_t command;
|
|
uint8_t flag;
|
|
uint16_t forkid;
|
|
uint32_t offset;
|
|
uint32_t reqcount;
|
|
} __attribute__((__packed__)) * request_packet;
|
|
struct afp_server * server = volume->server;
|
|
|
|
unsigned int len = sizeof(*request_packet)+
|
|
reqcount;
|
|
int ret;
|
|
char * dataptr, * msg;
|
|
|
|
if ((msg = malloc(len))==NULL)
|
|
return -1;
|
|
|
|
request_packet =(void *) msg;
|
|
dataptr=msg+(sizeof(*request_packet));
|
|
memcpy(dataptr,data,reqcount);
|
|
dsi_setup_header(server,&request_packet->dsi_header,DSI_DSIWrite);
|
|
request_packet->dsi_header.return_code.data_offset=htonl(sizeof(*request_packet)-sizeof(struct dsi_header));
|
|
/* For writing data, set the offset correctly */
|
|
request_packet->command=afpWrite;
|
|
request_packet->flag=0; /* we'll always do this from the start */
|
|
request_packet->forkid=htons(forkid);
|
|
request_packet->offset=htonl(offset);
|
|
request_packet->reqcount=htonl(reqcount);
|
|
ret=dsi_send(server, (char *) request_packet,len,DSI_DEFAULT_TIMEOUT,
|
|
afpWrite,(void *) written);
|
|
|
|
free(msg);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int afp_write_reply(struct afp_server *server, char * buf, unsigned int size,
|
|
void * other)
|
|
{
|
|
uint32_t * written = other;
|
|
struct {
|
|
struct dsi_header header __attribute__((__packed__));
|
|
uint64_t written;
|
|
} __attribute__((__packed__)) * reply_packet = (void *) buf;
|
|
|
|
if (size<sizeof(*reply_packet))
|
|
*written=0;
|
|
else
|
|
*written=ntohl(reply_packet->written);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int afp_writeext(struct afp_volume * volume, unsigned short forkid,
|
|
uint64_t offset, uint64_t reqcount,
|
|
char * data,uint64_t * written)
|
|
{
|
|
struct {
|
|
struct dsi_header dsi_header __attribute__((__packed__));
|
|
uint8_t command;
|
|
uint8_t flag;
|
|
uint16_t forkid;
|
|
uint64_t offset;
|
|
uint64_t reqcount;
|
|
} __attribute__((__packed__)) * request_packet;
|
|
struct afp_server * server = volume->server;
|
|
|
|
unsigned int len = sizeof(*request_packet)+
|
|
reqcount;
|
|
int ret;
|
|
char * dataptr, * msg;
|
|
|
|
if ((msg = malloc(len))==NULL)
|
|
return -1;
|
|
|
|
request_packet =(void *) msg;
|
|
dataptr=msg+(sizeof(*request_packet));
|
|
memcpy(dataptr,data,reqcount);
|
|
dsi_setup_header(server,&request_packet->dsi_header,DSI_DSIWrite);
|
|
request_packet->dsi_header.return_code.data_offset=htonl(sizeof(*request_packet)-sizeof(struct dsi_header));
|
|
/* For writing data, set the offset correctly */
|
|
request_packet->command=afpWriteExt;
|
|
request_packet->flag=0; /* we'll always do this from the start */
|
|
request_packet->forkid=htons(forkid);
|
|
request_packet->offset=hton64(offset);
|
|
request_packet->reqcount=hton64(reqcount);
|
|
ret=dsi_send(server, (char *) request_packet,len,DSI_DEFAULT_TIMEOUT,
|
|
afpWriteExt,(void *) written);
|
|
|
|
free(msg);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int afp_writeext_reply(struct afp_server *server, char * buf, unsigned int size,
|
|
void * other)
|
|
{
|
|
uint64_t * written = other;
|
|
struct {
|
|
struct dsi_header header __attribute__((__packed__));
|
|
uint64_t written;
|
|
} __attribute__((__packed__)) * reply_packet = (void *) buf;
|
|
|
|
if (size<sizeof(*reply_packet))
|
|
*written=0;
|
|
else
|
|
*written=ntoh64(reply_packet->written);
|
|
|
|
return 0;
|
|
}
|
|
|