1 #include <limits.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include "afpfs-ng/afp.h"
7 #include "resource.h"
8 #include "lowlevel.h"
9 #include "did.h"
10 #include "afpfs-ng/midlevel.h"
11
12 #define appledouble ".AppleDouble"
13 #define finderinfo_string ".finderinfo"
14 #define comment_string ".comment"
15 #define servericon_string "/.servericon"
16
17 #define min(a,b) (((a)<(b)) ? (a) : (b))
18
extra_translate(struct afp_volume * volume,const char * path,char ** newpath_p)19 static unsigned int extra_translate(
20 struct afp_volume * volume, const char * path,
21 char ** newpath_p)
22 {
23
24 char * p;
25 char * newpath;
26 *newpath_p=NULL;
27 if (~volume->extra_flags & VOLUME_EXTRA_FLAGS_SHOW_APPLEDOUBLE)
28 return 0;
29
30 if (strcmp(path,servericon_string)==0)
31 return AFP_META_SERVER_ICON;
32
33 if (strlen(path)<(strlen(appledouble)+1))
34 return 0;
35
36 if ((p=strrchr(path,'/'))==NULL)
37 return 0;
38
39 p+=1;
40
41 if (strcmp(p,appledouble)==0) {
42
43 /* Okay, all we have is /foo/.AppleDouble */
44 /* Make a copy, but not the last .AppleDouble */
45 newpath = malloc(strlen(path));
46 memset(newpath,0,strlen(path));
47 if (strlen(path)==strlen(appledouble)+1)
48 newpath[0]='/';
49 else
50 memcpy(newpath,path,strlen(path)-(strlen(appledouble)+1));
51 *newpath_p=newpath;
52
53 return AFP_META_APPLEDOUBLE;
54 }
55
56 if ((p=strstr(path,appledouble))) {
57 /* So we have /foo/.AppleDouble/blah. */
58 newpath = malloc(strlen(path));
59 memset(newpath,0,strlen(path));
60 memcpy(newpath,path,p-path);
61 p+=strlen(appledouble);
62 strcat(newpath,p+1);
63 *newpath_p=newpath;
64
65 /* If the ending is .finderinfo, tag it */
66
67
68 if (strlen(newpath)>strlen(finderinfo_string)) {
69 p=newpath+strlen(newpath)-strlen(finderinfo_string);
70 if (strcmp(p,finderinfo_string)==0) {
71 *p='\0';
72 return AFP_META_FINDERINFO;
73 }
74 }
75
76 if (strlen(newpath)>strlen(comment_string)) {
77 p=newpath+strlen(newpath)-strlen(comment_string);
78 if (strcmp(p,comment_string)==0) {
79 *p='\0';
80 return AFP_META_COMMENT;
81 }
82 }
83
84 return AFP_META_RESOURCE;
85 }
86
87 return 0;
88 }
89
ensure_dt_opened(struct afp_volume * volume)90 static int ensure_dt_opened(struct afp_volume * volume)
91 {
92
93 if (volume->dtrefnum>0) return 0;
94
95 return (afp_opendt(volume,&volume->dtrefnum));
96
97 }
98
get_comment_size(struct afp_volume * volume,const char * basename,unsigned int did)99 static int get_comment_size(struct afp_volume * volume, const char * basename,
100 unsigned int did)
101 {
102 struct afp_comment comment;
103 int ret=0;
104 int size=1024;
105
106 if ((comment.data = malloc(size))==NULL)
107 return -1;
108 comment.maxsize=size;
109 comment.size=0;
110 if (volume->dtrefnum==0)
111 if (afp_opendt(volume,&volume->dtrefnum) <0) {
112 ret=-EIO;
113 goto out;
114 }
115
116 ret=(afp_getcomment(volume,did, basename, &comment));
117 switch(ret) {
118 case kFPAccessDenied:
119 ret=-EACCES;
120 break;
121 case kFPMiscErr:
122 case kFPParamErr:
123 ret=-EIO;
124 break;
125 case kFPItemNotFound:
126 case kFPObjectNotFound:
127 ret=-ENOENT;
128 break;
129 case kFPNoErr:
130 ret=comment.size;
131 default:
132 break;
133 }
134 out:
135 free(comment.data);
136 return ret;
137 }
138
appledouble_creat(struct afp_volume * volume,const char * path,mode_t mode)139 int appledouble_creat(struct afp_volume * volume, const char * path, mode_t mode)
140 {
141 int resource;
142 char * newpath;
143 resource = extra_translate(volume, path, &newpath);
144 switch(resource) {
145 case AFP_META_RESOURCE:
146 free(newpath);
147 return 1;
148 case AFP_META_APPLEDOUBLE:
149 free(newpath);
150 return -EBADF;
151 case AFP_META_SERVER_ICON:
152 return -EPERM;
153 return 1;
154 case AFP_META_FINDERINFO:
155 free(newpath);
156 return 1;
157 }
158 return 0;
159 }
160
appledouble_chmod(struct afp_volume * volume,const char * path,mode_t mode)161 int appledouble_chmod(struct afp_volume * volume, const char * path, mode_t mode)
162 {
163 int resource;
164 char * newpath;
165
166 /* There's no resource you can chmod */
167 resource = extra_translate(volume, path, &newpath);
168 free(newpath);
169 if (resource==0) return 0;
170 return -EPERM;
171 }
172
appledouble_unlink(struct afp_volume * volume,const char * path)173 int appledouble_unlink(struct afp_volume * volume, const char *path)
174 {
175 int resource;
176 char * newpath;
177
178 /* There's no resource you can unlink */
179 resource = extra_translate(volume, path, &newpath);
180 free(newpath);
181 if (resource==0) return 0;
182 return -EPERM;
183 }
184
appledouble_close(struct afp_volume * volume,struct afp_file_info * fp)185 int appledouble_close(struct afp_volume * volume, struct afp_file_info * fp)
186 {
187 switch(fp->resource) {
188 case AFP_META_RESOURCE:
189 switch(afp_closefork(volume,fp->forkid)) {
190 case kFPNoErr:
191 break;
192 default:
193 case kFPParamErr:
194 case kFPMiscErr:
195 return -EIO;
196 }
197
198 return 0;
199 case AFP_META_APPLEDOUBLE:
200 return -EBADF;
201 case AFP_META_SERVER_ICON:
202 return 1;
203 case AFP_META_FINDERINFO:
204 return 0;
205 }
206 return 0;
207 }
208
appledouble_write(struct afp_volume * volume,struct afp_file_info * fp,const char * data,size_t size,off_t offset,size_t * totalwritten)209 int appledouble_write(struct afp_volume * volume, struct afp_file_info *fp,
210 const char *data, size_t size, off_t offset, size_t *totalwritten)
211 {
212 int ret;
213 int towrite=size;
214 unsigned int did;
215 struct afp_file_info fp2;
216
217 switch(fp->resource) {
218 case AFP_META_RESOURCE:
219 ret=ll_write(volume,data,size,offset,fp,totalwritten);
220 return ret;
221 case AFP_META_APPLEDOUBLE:
222 return -EBADF;
223 case AFP_META_FINDERINFO:
224 if (offset>=32) return -EINVAL;
225 if (towrite>(32-offset)) towrite=32-offset;
226
227 /* Get the previous finderinfo */
228 ret=ll_get_directory_entry(volume,fp->basename,fp->did,
229 kFPFinderInfoBit,kFPFinderInfoBit,&fp2);
230 if (ret<0) return ret;
231
232 /* Copy in only the parts we got */
233 memcpy(fp->finderinfo+offset,data,towrite);
234
235 ret=afp_setfiledirparms(volume,
236 fp->did,fp->basename,
237 kFPFinderInfoBit, fp);
238 switch(ret) {
239 case kFPNoErr:
240 break;
241 case kFPAccessDenied:
242 return -EACCES;
243 case kFPObjectNotFound:
244 return -ENOENT;
245 case kFPBitmapErr:
246 case kFPMiscErr:
247 case kFPObjectTypeErr:
248 case kFPParamErr:
249 default:
250 break;
251
252 }
253 *totalwritten=towrite;
254
255 return 1;
256 case AFP_META_COMMENT:
257 switch(afp_addcomment(volume, fp->did,fp->basename,
258 (char *)data,(uint64_t *) totalwritten)) {
259 case kFPAccessDenied:
260 return -EACCES;
261 case kFPObjectNotFound:
262 return -ENOENT;
263 case kFPNoErr:
264 *totalwritten=size;
265 return 1;
266 case kFPMiscErr:
267 default:
268 return -EIO;
269 }
270 case AFP_META_SERVER_ICON:
271 return -EPERM;
272
273 }
274 return 0;
275
276
277 }
278
appledouble_read(struct afp_volume * volume,struct afp_file_info * fp,char * buf,size_t size,off_t offset,size_t * amount_read,int * eof)279 int appledouble_read(struct afp_volume * volume, struct afp_file_info *fp,
280 char * buf, size_t size, off_t offset, size_t * amount_read,
281 int * eof)
282 {
283 int tocopy;
284 int ret;
285 struct afp_comment comment;
286 *amount_read=0;
287 *eof=0;
288
289 comment.data=malloc(size);
290 comment.maxsize=size;
291
292 switch(fp->resource) {
293 case AFP_META_RESOURCE:
294 ret=ll_read(volume,buf,size,offset,fp,eof);
295 return ret;
296 case AFP_META_APPLEDOUBLE:
297 return -EBADF;
298 case AFP_META_FINDERINFO:
299 if (offset>32) return -EFAULT;
300 ret=ll_get_directory_entry(volume,fp->basename,fp->did,
301 kFPFinderInfoBit,kFPFinderInfoBit,fp);
302 if (ret<0) return ret;
303 tocopy=min(size,(32-offset));
304 memcpy(buf+offset,fp->finderinfo,tocopy);
305 if (offset+tocopy==32) *eof=1;
306 *amount_read=tocopy;
307 case AFP_META_COMMENT:
308 if (fp->eof) ret=1; else
309 switch(afp_getcomment(volume,fp->did, fp->basename, &comment)) {
310 case kFPAccessDenied:
311 ret=-EACCES;
312 break;
313 case kFPMiscErr:
314 case kFPParamErr:
315 ret=-EIO;
316 break;
317 case kFPItemNotFound:
318 case kFPObjectNotFound:
319 ret=-ENOENT;
320 break;
321 case kFPNoErr:
322 memcpy(buf,comment.data,comment.size);
323 *amount_read =comment.size;
324 ret=1;
325 *eof=1;
326 fp->eof=1;
327 default:
328 break;
329 }
330 free(comment.data);
331 return ret;
332 case AFP_META_SERVER_ICON:
333 if (offset>256) return -EFAULT;
334 tocopy=min(size,(256-offset));
335 memcpy(buf+offset,volume->server->icon,tocopy);
336 *eof=1;
337 fp->eof=1;
338 *amount_read=tocopy;
339 return 1;
340 }
341 return 0;
342 }
343
appledouble_truncate(struct afp_volume * volume,const char * path,int offset)344 int appledouble_truncate(struct afp_volume * volume, const char * path, int offset)
345 {
346
347 char * newpath;
348 int resource = extra_translate(volume, path, &newpath);
349 struct afp_file_info fp;
350 int ret;
351 int dirid;
352 char basename[AFP_MAX_PATH];
353
354 switch(resource) {
355 case AFP_META_RESOURCE:
356
357 get_dirid(volume,newpath,basename,&dirid);
358
359 ret=afp_openfork(volume,1,dirid,O_WRONLY,
360 basename,&fp);
361
362 ret=ll_zero_file(volume,fp.forkid,0);
363 if (ret<0) {
364 afp_closefork(volume,fp.forkid);
365 remove_opened_fork(volume,fp);
366 free(newpath);
367 return ret;
368 }
369 afp_closefork(volume,fp.forkid);
370 remove_opened_fork(volume,fp);
371
372 return 1;
373 case AFP_META_APPLEDOUBLE:
374 free(newpath);
375 return -EISDIR;
376 case AFP_META_FINDERINFO:
377 free(newpath);
378 return 1;
379 case AFP_META_COMMENT:
380 free(newpath);
381 return 1;
382 case AFP_META_SERVER_ICON:
383 free(newpath);
384 return -EPERM;
385 }
386 return 0;
387 }
388
appledouble_open(struct afp_volume * volume,const char * path,int flags,struct afp_file_info * fp)389 int appledouble_open(struct afp_volume * volume, const char * path, int flags,
390 struct afp_file_info *fp)
391 {
392 char * newpath;
393 int ret;
394
395 switch((fp->resource = extra_translate(volume, path, &newpath))) {
396 case AFP_META_RESOURCE:
397 if (get_dirid(volume,newpath,fp->basename,&fp->did)<0) {
398 ret=-ENOENT;
399 goto error;
400 }
401 ret=ll_open(volume,newpath,flags,fp);
402 free(newpath);
403 if (ret<0) return ret;
404 return 1;
405 case AFP_META_APPLEDOUBLE:
406 free(newpath);
407 return -EISDIR;
408 case AFP_META_FINDERINFO:
409 if (get_dirid(volume,newpath,fp->basename,&fp->did)<0)
410 return -ENOENT;
411 free(newpath);
412 return 1;
413 case AFP_META_COMMENT:
414 if (get_dirid(volume,newpath,fp->basename,&fp->did)<0) {
415 ret=-ENOENT;
416 goto error;
417 }
418 if (volume->dtrefnum==0) {
419 switch(afp_opendt(volume,&volume->dtrefnum)) {
420 case kFPParamErr:
421 case kFPMiscErr:
422 free(newpath);
423 return -EIO;
424 case kFPNoErr:
425 default:
426 break;
427 }
428 }
429 free(newpath);
430 return 1;
431 case AFP_META_SERVER_ICON:
432 free(newpath);
433 return 1;
434 }
435 return 0;
436 error:
437 free(newpath);
438 return ret;
439
440 }
441
appledouble_getattr(struct afp_volume * volume,const char * path,struct stat * stbuf)442 int appledouble_getattr(struct afp_volume * volume,
443 const char * path, struct stat *stbuf)
444 {
445 unsigned int resource;
446 char * newpath;
447 int ret;
448
449 resource = extra_translate(volume, path, &newpath);
450 switch(resource) {
451 case AFP_META_RESOURCE:
452 ll_getattr(volume,newpath,stbuf,1);
453 goto okay;
454 case AFP_META_APPLEDOUBLE:
455 stbuf->st_mode = 0700 | S_IFDIR;
456 goto okay;
457 case AFP_META_FINDERINFO:
458 ll_getattr(volume,newpath,stbuf,0);
459 stbuf->st_mode |= S_IFREG;
460 stbuf->st_size=32;
461 goto okay;
462 case AFP_META_COMMENT: {
463 unsigned int did;
464 char basename[AFP_MAX_PATH];
465
466 ret=ll_getattr(volume,newpath,stbuf,0);
467 if (ret<0)
468 goto error;
469
470 ret=get_dirid(volume,newpath,basename,&did);
471 if (ret<0)
472 goto error;
473
474 ret=get_comment_size(volume,basename,did);
475 if (ret<0)
476 goto error;
477
478 stbuf->st_mode |= S_IFREG;
479 stbuf->st_size=ret;
480 goto okay;
481 }
482 case AFP_META_SERVER_ICON:
483 stbuf->st_mode = S_IFREG | 0444;
484 stbuf->st_size=256;
485 goto okay;
486 }
487 return 0;
488 okay:
489 free(newpath);
490 return 1;
491 error:
492 free(newpath);
493 return ret;
494
495 }
496
remove_fp(struct afp_file_info ** base,struct afp_file_info * toremove)497 static void remove_fp(struct afp_file_info **base,struct afp_file_info * toremove)
498 {
499 struct afp_file_info *fp, *prev=NULL;
500
501 for (fp=*base;fp;fp=fp->next)
502 if (fp==toremove) {
503 if (prev==NULL) {
504 *base=fp->next;;
505 free(fp);
506 prev=NULL;
507 } else {
508 prev->next=fp->next;
509 prev=fp;
510 free(fp);
511 }
512 }
513
514 }
515
add_fp(struct afp_file_info ** newchain,struct afp_file_info * fp,char * suffix,unsigned int size)516 static int add_fp(struct afp_file_info **newchain, struct afp_file_info *fp,
517 char * suffix, unsigned int size)
518 {
519 struct afp_file_info * newfp;
520 newfp=malloc(sizeof(struct afp_file_info));
521 memcpy(newfp,fp,sizeof(struct afp_file_info));
522 strcat(newfp->name,suffix);
523 newfp->resourcesize=size;
524 newfp->unixprivs.permissions|=S_IFREG;
525 newfp->next=*newchain;
526 *newchain=newfp;
527 }
528
appledouble_readdir(struct afp_volume * volume,const char * path,struct afp_file_info ** base)529 int appledouble_readdir(struct afp_volume * volume,
530 const char *path, struct afp_file_info **base)
531 {
532 unsigned int resource;
533 char * newpath;
534
535 resource = extra_translate(volume, path, &newpath);
536
537 switch(resource) {
538 case 0:
539 return 0;
540 case AFP_META_APPLEDOUBLE: {
541 struct afp_file_info *fp, *prev=NULL,
542 *newfp=NULL, *newchain=NULL, *last=NULL;
543 ll_readdir(volume, newpath,base,1);
544
545 /* Add .finderinfo files */
546 for (fp=*base;fp;fp=fp->next) {
547 add_fp(&newchain,fp,finderinfo_string,32);
548
549 /* Add comments if it has a size > 0 */
550 if (ensure_dt_opened(volume)==0) {
551 int size=get_comment_size(volume,
552 fp->name,fp->did);
553
554 if (size>0)
555 add_fp(&newchain,fp,comment_string,32);
556 }
557
558 if (fp->unixprivs.permissions & S_IFREG) {
559 if (fp->resourcesize==0) {
560 remove_fp(base,fp);
561 }
562 } else {
563 remove_fp(base,fp);
564 }
565 last=fp;
566 }
567 if ((newchain) && (last)) {
568 last->next=newchain;
569 }
570
571 free(newpath);
572 return 1;
573 case AFP_META_RESOURCE:
574 case AFP_META_SERVER_ICON:
575 case AFP_META_COMMENT:
576 free(newpath);
577 return -ENOTDIR;
578 }
579 }
580
581 return 0;
582 }
583
appledouble_mkdir(struct afp_volume * volume,const char * path,mode_t mode)584 int appledouble_mkdir(struct afp_volume * volume, const char * path, mode_t mode)
585 {
586 int resource;
587 char * newpath;
588
589 /* You can't mkdir */
590 resource = extra_translate(volume, path, &newpath);
591 free(newpath);
592 if (resource==0) return 0;
593 return -EPERM;
594
595 }
596
appledouble_readlink(struct afp_volume * volume,const char * path,char * buf,size_t size)597 int appledouble_readlink(struct afp_volume * volume, const char * path,
598 char * buf, size_t size)
599 {
600 int resource;
601 char * newpath;
602
603 /* You can't readlink*/
604 resource = extra_translate(volume, path, &newpath);
605 free(newpath);
606 if (resource==0) return 0;
607 return -EPERM;
608
609 }
610
appledouble_rmdir(struct afp_volume * volume,const char * path)611 int appledouble_rmdir(struct afp_volume * volume, const char * path)
612 {
613 int resource;
614 char * newpath;
615
616 /* You can't rmdir*/
617 resource = extra_translate(volume, path, &newpath);
618 free(newpath);
619 if (resource==0) return 0;
620 return -EPERM;
621
622 }
623
appledouble_chown(struct afp_volume * volume,const char * path,uid_t uid,gid_t gid)624 int appledouble_chown(struct afp_volume * volume, const char * path,
625 uid_t uid, gid_t gid)
626 {
627 int resource;
628 char * newpath;
629
630 /* You can't chown*/
631 resource = extra_translate(volume, path, &newpath);
632 free(newpath);
633 if (resource==0) return 0;
634 return -EPERM;
635
636 }
637
appledouble_utime(struct afp_volume * volume,const char * path,struct utimbuf * timebuf)638 int appledouble_utime(struct afp_volume * volume, const char * path,
639 struct utimbuf * timebuf)
640 {
641 int resource;
642 char * newpath;
643
644 /* You can't utime*/
645 resource = extra_translate(volume, path, &newpath);
646 free(newpath);
647 if (resource==0) return 0;
648 return -EPERM;
649 }
650
appledouble_symlink(struct afp_volume * vol,const char * path1,const char * path2)651 int appledouble_symlink(struct afp_volume *vol, const char *path1, const char *path2)
652 {
653 int resource;
654 char * newpath;
655
656 /* You can't symlink*/
657 resource = extra_translate(vol, path1, &newpath);
658 free(newpath);
659 if (resource==0) return 0;
660 return -EPERM;
661 }
662
appledouble_rename(struct afp_volume * volume,const char * path_from,const char * path_to)663 int appledouble_rename(struct afp_volume * volume, const char * path_from,
664 const char * path_to)
665 {
666 int resource;
667 char * newpath;
668
669 /* You can't rename*/
670 resource = extra_translate(volume, path_to, &newpath);
671 free(newpath);
672 if (resource==0) return 0;
673 return -EPERM;
674 }
675
676