int appledouble_truncate(struct afp_volume * volume, const char * path, int offset) { char * newpath; int resource = extra_translate(volume, path, &newpath); struct afp_file_info fp; int ret; int dirid; char basename[AFP_MAX_PATH]; switch(resource) { case AFP_META_RESOURCE: get_dirid(volume,newpath,basename,&dirid); ret=afp_openfork(volume,1,dirid,O_WRONLY, basename,&fp); ret=ll_zero_file(volume,fp.forkid,0); if (ret<0) { afp_closefork(volume,fp.forkid); remove_opened_fork(volume,fp); free(newpath); return ret; } afp_closefork(volume,fp.forkid); remove_opened_fork(volume,fp); return 1; case AFP_META_APPLEDOUBLE: free(newpath); return -EISDIR; case AFP_META_FINDERINFO: free(newpath); return 1; case AFP_META_COMMENT: free(newpath); return 1; case AFP_META_SERVER_ICON: free(newpath); return -EPERM; } return 0; }
int ml_truncate(struct afp_volume * vol, const char * path, off_t offset) { int ret=0; char converted_path[AFP_MAX_PATH]; struct afp_file_info *fp; int flags; if (convert_path_to_afp(vol->server->path_encoding, converted_path,(char *) path,AFP_MAX_PATH)) return -EINVAL; /* The approach here is to get the forkid by calling ml_open() (and not afp_openfork). Note the fake afp_file_info used just to grab this forkid. */ if (invalid_filename(vol->server,converted_path)) return -ENAMETOOLONG; if (volume_is_readonly(vol)) return -EACCES; ret=appledouble_truncate(vol,path,offset); if (ret<0) return ret; if (ret==1) return 0; /* Here, we're going to use the untranslated path since it is translated through the ml_open() */ flags=O_WRONLY; if ((ml_open(vol,path,flags,&fp))) { return ret; }; if ((ret=ll_zero_file(vol,fp->forkid,0))) goto out; afp_closefork(vol,fp->forkid); remove_opened_fork(vol, fp); free(fp); out: return -ret; }
int ml_close(struct afp_volume * volume, const char * path, struct afp_file_info * fp) { int ret=0; char converted_path[AFP_MAX_PATH]; if (convert_path_to_afp(volume->server->path_encoding, converted_path, (char *) path,AFP_MAX_PATH)) { return -EINVAL; } if (invalid_filename(volume->server,converted_path)) return -ENAMETOOLONG; /* The logic here is that if we don't have an fp anymore, then the fork must already be closed. */ if (!fp) return EBADF; if (fp->icon) { free(fp->icon); } if (fp->resource) { return appledouble_close(volume,fp); } switch(afp_closefork(volume,fp->forkid)) { case kFPNoErr: break; default: case kFPParamErr: case kFPMiscErr: ret=EIO; goto error; } remove_opened_fork(volume, fp); error: return ret; }
int ml_readlink(struct afp_volume * vol, const char * path, char *buf, size_t size) { int rc,ret; struct afp_file_info fp; struct afp_rx_buffer buffer; char basename[AFP_MAX_PATH]; char converted_path[AFP_MAX_PATH]; unsigned int dirid; char link_path[AFP_MAX_PATH]; memset(buf,0,size); memset(link_path,0,AFP_MAX_PATH); buffer.data=link_path; buffer.maxsize=size; buffer.size=0; if (convert_path_to_afp(vol->server->path_encoding, converted_path,(char *) path,AFP_MAX_PATH)) { return -EINVAL; } get_dirid(vol, converted_path, basename, &dirid); /* Open the fork */ rc=afp_openfork(vol,0, dirid, AFP_OPENFORK_ALLOWWRITE|AFP_OPENFORK_ALLOWREAD, basename,&fp); switch (rc) { case kFPAccessDenied: ret=EACCES; goto error; case kFPObjectNotFound: ret=ENOENT; goto error; case kFPObjectLocked: ret=EROFS; goto error; case kFPObjectTypeErr: ret=EISDIR; goto error; case kFPParamErr: ret=EACCES; goto error; case kFPTooManyFilesOpen: ret=EMFILE; goto error; case kFPVolLocked: case kFPDenyConflict: case kFPMiscErr: case kFPBitmapErr: case 0: ret=0; break; case -1: default: ret=EFAULT; goto error; } add_opened_fork(vol, &fp); /* Read the name of the file from it */ if (vol->server->using_version->av_number < 30) rc=afp_read(vol, fp.forkid,0,size,&buffer); else rc=afp_readext(vol, fp.forkid,0,size,&buffer); switch(rc) { case kFPAccessDenied: ret=EACCES; goto error; case kFPLockErr: ret=EBUSY; goto error; case kFPMiscErr: case kFPParamErr: ret=EIO; goto error; case kFPEOFErr: case kFPNoErr: break; } switch(afp_closefork(vol,fp.forkid)) { case kFPNoErr: break; default: case kFPParamErr: case kFPMiscErr: ret=EIO; goto error; } remove_opened_fork(vol, &fp); /* Convert the name back precomposed UTF8 */ convert_path_to_unix(vol->server->path_encoding, buf,(char *) link_path,AFP_MAX_PATH); return 0; error: return -ret; }
int ml_symlink(struct afp_volume *vol, const char * path1, const char * path2) { int ret; struct afp_file_info fp; uint64_t written; int rc; unsigned int dirid2; char basename2[AFP_MAX_PATH]; char converted_path1[AFP_MAX_PATH]; char converted_path2[AFP_MAX_PATH]; if (vol->server->using_version->av_number<30) { /* No symlinks for AFP 2.x. */ ret=ENOSYS; goto error; } /* Yes, you can create symlinks for AFP >=30. Tested with 10.3.2 */ if (convert_path_to_afp(vol->server->path_encoding, converted_path1,(char *) path1,AFP_MAX_PATH)) return -EINVAL; if (convert_path_to_afp(vol->server->path_encoding, converted_path2,(char *) path2,AFP_MAX_PATH)) return -EINVAL; if (volume_is_readonly(vol)) return -EACCES; ret=appledouble_symlink(vol,path1,path2); if (ret<0) return ret; if (ret==1) return 0; get_dirid(vol,converted_path2,basename2,&dirid2 ); /* 1. create the file */ rc=afp_createfile(vol,kFPHardCreate,dirid2,basename2); switch (rc) { case kFPAccessDenied: ret=EACCES; goto error; case kFPDiskFull: ret=ENOSPC; goto error; case kFPObjectExists: ret=EEXIST; goto error; case kFPObjectNotFound: ret=ENOENT; goto error; case kFPFileBusy: case kFPVolLocked: ret=EBUSY; goto error; case kFPNoErr: ret=0; break; default: case kFPParamErr: case kFPMiscErr: ret=EIO; goto error; } /* Open the fork */ rc=afp_openfork(vol,0, dirid2, AFP_OPENFORK_ALLOWWRITE|AFP_OPENFORK_ALLOWREAD, basename2,&fp); switch (ret) { case kFPAccessDenied: ret=EACCES; goto error; case kFPObjectNotFound: ret=ENOENT; goto error; case kFPObjectLocked: ret=EROFS; goto error; case kFPObjectTypeErr: ret=EISDIR; goto error; case kFPParamErr: ret=EACCES; goto error; case kFPTooManyFilesOpen: ret=EMFILE; goto error; case 0: ret=0; break; case kFPVolLocked: case kFPDenyConflict: case kFPMiscErr: case kFPBitmapErr: case -1: default: ret=EFAULT; goto error; } add_opened_fork(vol, &fp); /* Write the name of the file to it */ rc=afp_writeext(vol,fp.forkid,0,strlen(converted_path1), converted_path1,&written); switch(afp_closefork(vol,fp.forkid)) { case kFPNoErr: break; default: case kFPParamErr: case kFPMiscErr: ret=EIO; goto error; } remove_opened_fork(vol, &fp); /* And now for the undocumented magic */ memset(&fp.finderinfo,0,32); fp.finderinfo[0]='s'; fp.finderinfo[1]='l'; fp.finderinfo[2]='n'; fp.finderinfo[3]='k'; fp.finderinfo[4]='r'; fp.finderinfo[5]='h'; fp.finderinfo[6]='a'; fp.finderinfo[7]='p'; rc=afp_setfiledirparms(vol,dirid2,basename2, kFPFinderInfoBit, &fp); switch (rc) { case kFPAccessDenied: ret=EPERM; goto error; case kFPBitmapErr: /* This is the case where it isn't supported */ ret=ENOSYS; goto error; case kFPObjectNotFound: ret=ENOENT; goto error; case 0: ret=0; break; case kFPMiscErr: case kFPObjectTypeErr: case kFPParamErr: default: ret=EIO; goto error; } error: return -ret; };