1 /*===========================================================================
2 *
3 *                            PUBLIC DOMAIN NOTICE
4 *               National Center for Biotechnology Information
5 *
6 *  This software/database is a "United States Government Work" under the
7 *  terms of the United States Copyright Act.  It was written as part of
8 *  the author's official duties as a United States Government employee and
9 *  thus cannot be copyrighted.  This software/database is freely available
10 *  to the public for use. The National Library of Medicine and the U.S.
11 *  Government have not placed any restriction on its use or reproduction.
12 *
13 *  Although all reasonable efforts have been taken to ensure the accuracy
14 *  and reliability of the software and data, the NLM and the U.S.
15 *  Government do not and cannot warrant the performance or results that
16 *  may be obtained by using this software or data. The NLM and the U.S.
17 *  Government disclaim all warranties, express or implied, including
18 *  warranties of performance, merchantability or fitness for any particular
19 *  purpose.
20 *
21 *  Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26 
27 #define TRACK_REFERENCES 0
28 
29 #include <kfs/extern.h>
30 #include <kfs/impl.h>
31 #include <klib/refcount.h>
32 #include <klib/rc.h>
33 #include <klib/text.h>
34 #include <klib/printf.h>
35 #include <sysalloc.h>
36 
37 #include <stdlib.h>
38 
39 /*--------------------------------------------------------------------------
40  * KDirectory
41  *  a directory
42  */
43 
44 static const char classname[] = "KDirectory";
45 
46 /* AddRef
47  *  creates a new reference
48  *  ignores NULL references
49  */
KDirectoryAddRef_v1(const KDirectory_v1 * self)50 LIB_EXPORT rc_t CC KDirectoryAddRef_v1 ( const KDirectory_v1 *self )
51 {
52     if ( self != NULL )
53     {
54         switch ( KRefcountAdd ( & self -> refcount, classname ) )
55         {
56         case krefLimit:
57             return RC ( rcFS, rcDirectory, rcAttaching, rcRange, rcExcessive );
58         }
59     }
60     return 0;
61 }
62 
63 /* Release
64  *  discard reference to directory
65  *  ignores NULL references
66  */
KDirectoryRelease_v1(const KDirectory_v1 * cself)67 LIB_EXPORT rc_t CC KDirectoryRelease_v1 ( const KDirectory_v1 *cself )
68 {
69     KDirectory_v1 *self = ( KDirectory* ) cself;
70     if ( cself != NULL )
71     {
72         switch ( KRefcountDrop ( & self -> refcount, classname ) )
73         {
74         case krefWhack:
75         {
76             rc_t rc;
77 
78             switch ( self -> vt -> v1 . maj )
79             {
80             case 1:
81                 rc = ( * self -> vt -> v1 . destroy ) ( self );
82                 break;
83 
84             default:
85                 rc = RC ( rcFS, rcDirectory, rcReleasing, rcInterface, rcBadVersion );
86             }
87 
88             if ( rc != 0 )
89                 KRefcountInit ( & self -> refcount, 1, classname, "failed-release", "orphan" );
90             return rc;
91         }
92         case krefNegative:
93             return RC ( rcDB, rcTable, rcReleasing, rcRange, rcExcessive );
94         }
95     }
96     return 0;
97 }
98 
99 /* List
100  *  create a directory listing
101  *
102  *  "list" [ OUT ] - return parameter for list object
103  *
104  *  "path" [ IN, NULL OKAY ] - optional parameter for target
105  *  directory. if NULL, interpreted to mean "." will be
106  *  interpreted as format string if arguments follow
107  */
KDirectoryList_v1(const KDirectory_v1 * self,struct KNamelist ** list,bool (CC * f)(const KDirectory_v1 * dir,const char * name,void * data),void * data,const char * path,...)108 LIB_EXPORT rc_t CC KDirectoryList_v1 ( const KDirectory_v1 *self, struct KNamelist **list,
109     bool ( CC * f ) ( const KDirectory_v1 *dir, const char *name, void *data ),
110     void *data, const char *path, ... )
111 {
112     rc_t rc;
113     va_list args;
114 
115     va_start ( args, path );
116     rc = KDirectoryVList ( self, list, f, data, path, args );
117     va_end ( args );
118 
119     return rc;
120 }
121 
KDirectoryVList(const KDirectory_v1 * self,struct KNamelist ** list,bool (CC * f)(const KDirectory_v1 * dir,const char * name,void * data),void * data,const char * path,va_list args)122 LIB_EXPORT rc_t CC KDirectoryVList ( const KDirectory_v1 *self, struct KNamelist **list,
123     bool ( CC * f ) ( const KDirectory_v1 *dir, const char *name, void *data ),
124     void *data, const char *path, va_list args )
125 {
126     if ( list == NULL )
127         return RC ( rcFS, rcDirectory, rcListing, rcParam, rcNull );
128 
129     * list = NULL;
130 
131     if ( self == NULL )
132         return RC ( rcFS, rcDirectory, rcListing, rcSelf, rcNull );
133 
134     if ( path == NULL || path [ 0 ] == 0 )
135         path = ".";
136 
137     switch ( self -> vt -> v1 . maj )
138     {
139     case 1:
140         return ( * self -> vt -> v1 . list_dir ) ( self, list, f, data, path, args );
141     }
142 
143     return RC ( rcFS, rcDirectory, rcListing, rcInterface, rcBadVersion );
144 }
145 
146 /* Visit
147  *  visit each path under designated directory,
148  *  recursively if so indicated
149  *
150  *  "recurse" [ IN ] - if non-zero, recursively visit sub-directories
151  *
152  *  "f" [ IN ] and "data" [ IN, OPAQUE ] - function to execute
153  *  on each path. receives a base directory and relative path
154  *  for each entry. if "f" returns non-zero, the iteration will
155  *  terminate and that value will be returned. NB - "dir" will not
156  *  be the same as "self".
157  *
158  *  "path" [ IN ] - NUL terminated string in directory-native character set
159  */
KDirectoryVisit_v1(const KDirectory_v1 * self,bool recurse,rc_t (CC * f)(const KDirectory_v1 * dir,uint32_t type,const char * name,void * data),void * data,const char * path,...)160 LIB_EXPORT rc_t CC KDirectoryVisit_v1 ( const KDirectory_v1 *self, bool recurse,
161     rc_t ( CC * f ) ( const KDirectory_v1 *dir, uint32_t type, const char *name, void *data ),
162     void *data, const char *path, ... )
163 {
164     rc_t rc;
165     va_list args;
166 
167     va_start ( args, path );
168     rc = KDirectoryVVisit ( self, recurse, f, data, path, args );
169     va_end ( args );
170 
171     return rc;
172 }
173 
KDirectoryVVisit(const KDirectory_v1 * self,bool recurse,rc_t (CC * f)(const KDirectory_v1 * dir,uint32_t type,const char * name,void * data),void * data,const char * path,va_list args)174 LIB_EXPORT rc_t CC KDirectoryVVisit ( const KDirectory_v1 *self, bool recurse,
175     rc_t ( CC * f ) ( const KDirectory_v1 *dir, uint32_t type, const char *name, void *data ),
176     void *data, const char *path, va_list args )
177 {
178     if ( self == NULL )
179         return RC ( rcFS, rcDirectory, rcVisiting, rcSelf, rcNull );
180     if ( f == NULL )
181         return RC ( rcFS, rcDirectory, rcVisiting, rcFunction, rcNull );
182 
183     if ( path == NULL || path [ 0 ] == 0 )
184         path = ".";
185 
186     switch ( self -> vt -> v1 . maj )
187     {
188     case 1:
189         return ( * self -> vt -> v1 . visit ) ( self, recurse, f, data, path, args );
190     }
191 
192     return RC ( rcFS, rcDirectory, rcVisiting, rcInterface, rcBadVersion );
193 }
194 
195 /* VisitUpdate
196  *
197  */
KDirectoryVisitUpdate_v1(KDirectory_v1 * self,bool recurse,rc_t (CC * f)(KDirectory_v1 * dir,uint32_t type,const char * name,void * data),void * data,const char * path,...)198 LIB_EXPORT rc_t CC KDirectoryVisitUpdate_v1 ( KDirectory_v1 *self, bool recurse,
199     rc_t ( CC * f ) ( KDirectory_v1 *dir, uint32_t type, const char *name, void *data ),
200     void *data, const char *path, ... )
201 {
202     rc_t rc;
203     va_list args;
204 
205     va_start ( args, path );
206     rc = KDirectoryVVisitUpdate ( self, recurse, f, data, path, args );
207     va_end ( args );
208 
209     return rc;
210 }
211 
KDirectoryVVisitUpdate(KDirectory_v1 * self,bool recurse,rc_t (CC * f)(KDirectory_v1 * dir,uint32_t type,const char * name,void * data),void * data,const char * path,va_list args)212 LIB_EXPORT rc_t CC KDirectoryVVisitUpdate ( KDirectory_v1 *self, bool recurse,
213     rc_t ( CC * f ) ( KDirectory_v1 *dir, uint32_t type, const char *name, void *data ),
214     void *data, const char *path, va_list args )
215 {
216     if ( self == NULL )
217         return RC ( rcFS, rcDirectory, rcVisiting, rcSelf, rcNull );
218     if ( f == NULL )
219         return RC ( rcFS, rcDirectory, rcVisiting, rcFunction, rcNull );
220 
221     if ( path == NULL || path [ 0 ] == 0 )
222         path = ".";
223 
224     if ( self -> read_only )
225         return RC ( rcFS, rcDirectory, rcVisiting, rcDirectory, rcReadonly );
226 
227     switch ( self -> vt -> v1 . maj )
228     {
229     case 1:
230         return ( * self -> vt -> v1 . visit_update )
231             ( self, recurse, f, data, path, args );
232     }
233 
234     return RC ( rcFS, rcDirectory, rcVisiting, rcInterface, rcBadVersion );
235 }
236 
237 /* PathType
238  *  returns a KPathType
239  *
240  *  "path" [ IN ] - NUL terminated string in directory-native character set
241  */
KDirectoryPathType_v1(const KDirectory_v1 * self,const char * path,...)242 LIB_EXPORT uint32_t CC KDirectoryPathType_v1 ( const KDirectory_v1 *self, const char *path, ... )
243 {
244     uint32_t type;
245     va_list args;
246 
247     va_start ( args, path );
248     type = KDirectoryVPathType ( self, path, args );
249     va_end ( args );
250 
251     return type;
252 }
253 
KDirectoryVPathType(const KDirectory_v1 * self,const char * path,va_list args)254 LIB_EXPORT uint32_t CC KDirectoryVPathType ( const KDirectory_v1 *self, const char *path, va_list args )
255 {
256     if ( self == NULL || path == NULL || path [ 0 ] == 0 )
257         return kptBadPath;
258 
259     switch ( self -> vt -> v1 . maj )
260     {
261     case 1:
262         return ( * self -> vt -> v1 . path_type ) ( self, path, args );
263     }
264 
265     return kptBadPath;
266 }
267 
268 /* ResolvePath
269  *  resolves path to an absolute or directory-relative path
270  *
271  *  "absolute" [ IN ] - if non-zero, always give a path starting
272  *  with '/'. NB - if the directory is chroot'd, the absolute path
273  *  will still be relative to directory root.
274  *
275  *  "resolved" [ OUT ] and "rsize" [ IN ] - buffer for
276  *  NUL terminated result path in directory-native character set
277  *  the resolved path will be directory relative
278  *
279  *  "path" [ IN ] - NUL terminated string in directory-native
280  *  character set denoting target path. NB - need not exist.
281  */
KDirectoryResolvePath_v1(const KDirectory_v1 * self,bool absolute,char * resolved,size_t rsize,const char * path,...)282 LIB_EXPORT rc_t CC KDirectoryResolvePath_v1 ( const KDirectory_v1 *self, bool absolute,
283     char *resolved, size_t rsize, const char *path, ... )
284 {
285     rc_t rc;
286     va_list args;
287 
288     va_start ( args, path );
289     rc = KDirectoryVResolvePath ( self, absolute,
290         resolved, rsize, path, args );
291     va_end ( args );
292 
293     return rc;
294 }
295 
KDirectoryVResolvePath(const KDirectory_v1 * self,bool absolute,char * resolved,size_t rsize,const char * path,va_list args)296 LIB_EXPORT rc_t CC KDirectoryVResolvePath ( const KDirectory_v1 *self, bool absolute,
297     char *resolved, size_t rsize, const char *path, va_list args )
298 {
299     if ( self == NULL )
300         return RC ( rcFS, rcDirectory, rcResolving, rcSelf, rcNull );
301 
302     /* allow NULL buffers of 0 size */
303     if ( resolved == NULL && rsize != 0 )
304         return RC ( rcFS, rcDirectory, rcResolving, rcBuffer, rcNull );
305 
306     if ( path == NULL )
307         return RC ( rcFS, rcDirectory, rcResolving, rcPath, rcNull );
308     if ( path [ 0 ] == 0 )
309         return RC ( rcFS, rcDirectory, rcResolving, rcPath, rcInvalid );
310 
311     switch ( self -> vt -> v1 . maj )
312     {
313     case 1:
314         return ( * self -> vt -> v1 . resolve_path )
315             ( self, absolute, resolved, rsize, path, args );
316     }
317 
318     return RC ( rcFS, rcDirectory, rcResolving, rcInterface, rcBadVersion );
319 }
320 
321 /* ResolveAlias
322  *  resolves an alias path to its immediate target
323  *  NB - the resolved path may be yet another alias
324  *
325  *  "absolute" [ IN ] - if non-zero, always give a path starting
326  *  with '/'. NB - if the directory is chroot'd, the absolute path
327  *  will still be relative to directory root.
328  *
329  *  "resolved" [ OUT ] and "rsize" [ IN ] - buffer for
330  *  NUL terminated result path in directory-native character set
331  *  the resolved path will be directory relative
332  *
333  *  "alias" [ IN ] - NUL terminated string in directory-native
334  *  character set denoting an object presumed to be an alias.
335  */
KDirectoryResolveAlias_v1(const KDirectory_v1 * self,bool absolute,char * resolved,size_t rsize,const char * alias,...)336 LIB_EXPORT rc_t CC KDirectoryResolveAlias_v1 ( const KDirectory_v1 *self, bool absolute,
337     char *resolved, size_t rsize, const char *alias, ... )
338 {
339     rc_t rc;
340     va_list args;
341 
342     va_start ( args, alias );
343     rc = KDirectoryVResolveAlias ( self, absolute,
344         resolved, rsize, alias, args );
345     va_end ( args );
346 
347     return rc;
348 }
349 
KDirectoryVResolveAlias(const KDirectory_v1 * self,bool absolute,char * resolved,size_t rsize,const char * alias,va_list args)350 LIB_EXPORT rc_t CC KDirectoryVResolveAlias ( const KDirectory_v1 *self, bool absolute,
351     char *resolved, size_t rsize, const char *alias, va_list args )
352 {
353     if ( self == NULL )
354         return RC ( rcFS, rcDirectory, rcResolving, rcSelf, rcNull );
355 
356     /* allow NULL buffers of 0 size */
357     if ( resolved == NULL && rsize != 0 )
358         return RC ( rcFS, rcDirectory, rcResolving, rcBuffer, rcNull );
359 
360     if ( alias == NULL )
361         return RC ( rcFS, rcDirectory, rcResolving, rcPath, rcNull );
362     if ( alias [ 0 ] == 0 )
363         return RC ( rcFS, rcDirectory, rcResolving, rcPath, rcInvalid );
364 
365     switch ( self -> vt -> v1 . maj )
366     {
367     case 1:
368         return ( * self -> vt -> v1 . resolve_alias )
369             ( self, absolute, resolved, rsize, alias, args );
370     }
371 
372     return RC ( rcFS, rcDirectory, rcResolving, rcInterface, rcBadVersion );
373 }
374 
375 /* Rename
376  *  rename an object accessible from directory, replacing
377  *  any existing target object of the same type
378  *
379  *  "from" [ IN ] - NUL terminated string in directory-native
380  *  character set denoting existing object
381  *
382  *  "to" [ IN ] - NUL terminated string in directory-native
383  *  character set denoting existing object
384  */
KDirectoryRename_v1(KDirectory_v1 * self,bool force,const char * from,const char * to)385 LIB_EXPORT rc_t CC KDirectoryRename_v1 ( KDirectory_v1 *self, bool force, const char *from, const char *to )
386 {
387     if ( self == NULL )
388         return RC ( rcFS, rcDirectory, rcRenaming, rcSelf, rcNull );
389 
390     if ( from == NULL || to == NULL )
391         return RC ( rcFS, rcDirectory, rcRenaming, rcPath, rcNull );
392     if ( from [ 0 ] == 0 || to [ 0 ] == 0 )
393         return RC ( rcFS, rcDirectory, rcRenaming, rcPath, rcInvalid );
394 
395     if ( self -> read_only )
396         return RC ( rcFS, rcDirectory, rcRenaming, rcDirectory, rcReadonly );
397 
398     switch ( self -> vt -> v1 . maj )
399     {
400     case 1:
401         return ( * self -> vt -> v1 . rename ) ( self, force, from, to );
402     }
403 
404     return RC ( rcFS, rcDirectory, rcRenaming, rcInterface, rcBadVersion );
405 }
406 
407 /* Remove
408  *  remove an accessible object from its directory
409  *
410  *  "force" [ IN ] - if non-zero and target is a directory,
411  *  remove recursively
412  *
413  *  "path" [ IN ] - NUL terminated string in directory-native
414  *  character set denoting target object
415  */
KDirectoryRemove_v1(KDirectory_v1 * self,bool force,const char * path,...)416 LIB_EXPORT rc_t CC KDirectoryRemove_v1 ( KDirectory_v1 *self, bool force, const char *path, ... )
417 {
418     rc_t rc;
419     va_list args;
420 
421     va_start ( args, path );
422     rc = KDirectoryVRemove ( self, force, path, args );
423     va_end ( args );
424 
425     return rc;
426 }
427 
KDirectoryVRemove(KDirectory_v1 * self,bool force,const char * path,va_list args)428 LIB_EXPORT rc_t CC KDirectoryVRemove ( KDirectory_v1 *self, bool force, const char *path, va_list args )
429 {
430     if ( self == NULL )
431         return RC ( rcFS, rcDirectory, rcRemoving, rcSelf, rcNull );
432 
433     if ( path == NULL )
434         return RC ( rcFS, rcDirectory, rcRemoving, rcPath, rcNull );
435     if ( path [ 0 ] == 0 )
436         return RC ( rcFS, rcDirectory, rcRemoving, rcPath, rcInvalid );
437 
438     if ( self -> read_only )
439         return RC ( rcFS, rcDirectory, rcRemoving, rcDirectory, rcReadonly );
440 
441     switch ( self -> vt -> v1 . maj )
442     {
443     case 1:
444         return ( * self -> vt -> v1 . remove ) ( self, force, path, args );
445     }
446 
447     return RC ( rcFS, rcDirectory, rcRemoving, rcInterface, rcBadVersion );
448 }
449 
450 /* ClearDir
451  *  remove all directory contents
452  *
453  *  "force" [ IN ] - if non-zero and directory entry is a
454  *  sub-directory, remove recursively
455  *
456  *  "path" [ IN ] - NUL terminated string in directory-native
457  *  character set denoting target directory
458  */
KDirectoryClearDir_v1(KDirectory_v1 * self,bool force,const char * path,...)459 LIB_EXPORT rc_t CC KDirectoryClearDir_v1 ( KDirectory_v1 *self, bool force, const char *path, ... )
460 {
461     rc_t rc;
462     va_list args;
463 
464     va_start ( args, path );
465     rc = KDirectoryVClearDir ( self, force, path, args );
466     va_end ( args );
467 
468     return rc;
469 }
470 
KDirectoryVClearDir(KDirectory_v1 * self,bool force,const char * path,va_list args)471 LIB_EXPORT rc_t CC KDirectoryVClearDir ( KDirectory_v1 *self, bool force, const char *path, va_list args )
472 {
473     if ( self == NULL )
474         return RC ( rcFS, rcDirectory, rcRemoving, rcSelf, rcNull );
475 
476     if ( path == NULL )
477         return RC ( rcFS, rcDirectory, rcRemoving, rcPath, rcNull );
478     if ( path [ 0 ] == 0 )
479         return RC ( rcFS, rcDirectory, rcRemoving, rcPath, rcInvalid );
480 
481     if ( self -> read_only )
482         return RC ( rcFS, rcDirectory, rcRemoving, rcDirectory, rcReadonly );
483 
484     switch ( self -> vt -> v1 . maj )
485     {
486     case 1:
487         return ( * self -> vt -> v1 . clear_dir ) ( self, force, path, args );
488     }
489 
490     return RC ( rcFS, rcDirectory, rcRemoving, rcInterface, rcBadVersion );
491 }
492 
493 /* Access
494  *  get access to object
495  *
496  *  "access" [ OUT ] - return parameter for Unix access mode
497  *
498  *  "path" [ IN ] - NUL terminated string in directory-native
499  *  character set denoting target object
500  */
KDirectoryAccess_v1(const KDirectory_v1 * self,uint32_t * access,const char * path,...)501 LIB_EXPORT rc_t CC KDirectoryAccess_v1 ( const KDirectory_v1 *self,
502     uint32_t *access, const char *path, ... )
503 {
504     rc_t rc;
505     va_list args;
506 
507     va_start ( args, path );
508     rc = KDirectoryVAccess ( self, access, path, args );
509     va_end ( args );
510 
511     return rc;
512 }
513 
KDirectoryVAccess(const KDirectory_v1 * self,uint32_t * access,const char * path,va_list args)514 LIB_EXPORT rc_t CC KDirectoryVAccess ( const KDirectory_v1 *self,
515     uint32_t *access, const char *path, va_list args )
516 {
517     if ( access == NULL )
518         return RC ( rcFS, rcDirectory, rcAccessing, rcParam, rcNull );
519 
520     * access = 0;
521 
522     if ( self == NULL )
523         return RC ( rcFS, rcDirectory, rcAccessing, rcSelf, rcNull );
524 
525     if ( path == NULL )
526         return RC ( rcFS, rcDirectory, rcAccessing, rcPath, rcNull );
527     if ( path [ 0 ] == 0 )
528         return RC ( rcFS, rcDirectory, rcAccessing, rcPath, rcInvalid );
529 
530     switch ( self -> vt -> v1 . maj )
531     {
532     case 1:
533         return ( * self -> vt -> v1 . access ) ( self, access, path, args );
534     }
535 
536     return RC ( rcFS, rcDirectory, rcAccessing, rcInterface, rcBadVersion );
537 }
538 
539 /* SetAccess
540  *  set access to object a la Unix "chmod"
541  *
542  *  "recurse" [ IN ] - if non zero and "path" is a directory,
543  *  apply changes recursively.
544  *
545  *  "access" [ IN ] and "mask" [ IN ] - definition of change
546  *  where "access" contains new bit values and "mask defines
547  *  which bits should be changed.
548  *
549  *  "path" [ IN ] - NUL terminated string in directory-native
550  *  character set denoting target object
551  */
KDirectorySetAccess_v1(KDirectory_v1 * self,bool recurse,uint32_t access,uint32_t mask,const char * path,...)552 LIB_EXPORT rc_t CC KDirectorySetAccess_v1 ( KDirectory_v1 *self, bool recurse,
553     uint32_t access, uint32_t mask, const char *path, ... )
554 {
555     rc_t rc;
556     va_list args;
557 
558     va_start ( args, path );
559     rc = KDirectoryVSetAccess ( self, recurse,
560         access, mask, path, args );
561     va_end ( args );
562 
563     return rc;
564 }
565 
KDirectoryVSetAccess(KDirectory_v1 * self,bool recurse,uint32_t access,uint32_t mask,const char * path,va_list args)566 LIB_EXPORT rc_t CC KDirectoryVSetAccess ( KDirectory_v1 *self, bool recurse,
567     uint32_t access, uint32_t mask, const char *path, va_list args )
568 {
569     if ( self == NULL )
570         return RC ( rcFS, rcDirectory, rcUpdating, rcSelf, rcNull );
571 
572     if ( path == NULL )
573         return RC ( rcFS, rcDirectory, rcUpdating, rcPath, rcNull );
574     if ( path [ 0 ] == 0 )
575         return RC ( rcFS, rcDirectory, rcUpdating, rcPath, rcInvalid );
576 
577     if ( self -> read_only )
578         return RC ( rcFS, rcDirectory, rcUpdating, rcDirectory, rcReadonly );
579 
580     switch ( self -> vt -> v1 . maj )
581     {
582     case 1:
583         /* TBD - perhaps limit bits to lower 9 */
584         return ( * self -> vt -> v1 . set_access )
585             ( self, recurse, access, mask, path, args );
586     }
587 
588     return RC ( rcFS, rcDirectory, rcUpdating, rcInterface, rcBadVersion );
589 }
590 
591 /* Date
592  *  get date/time to object
593  *
594  *  "date" [ OUT ] - return parameter
595  *
596  *  "path" [ IN ] - NUL terminated string in directory-native
597  *  character set denoting target object
598  */
KDirectoryDate_v1(const KDirectory_v1 * self,KTime_t * date,const char * path,...)599 LIB_EXPORT rc_t CC KDirectoryDate_v1 ( const KDirectory_v1 *self,
600     KTime_t *date, const char *path, ... )
601 {
602     rc_t rc;
603     va_list args;
604 
605     va_start ( args, path );
606     rc = KDirectoryVDate ( self, date, path, args );
607     va_end ( args );
608 
609     return rc;
610 }
KDirectoryVDate(const KDirectory_v1 * self,KTime_t * date,const char * path,va_list args)611 LIB_EXPORT rc_t CC KDirectoryVDate ( const KDirectory_v1 *self,
612     KTime_t *date, const char *path, va_list args )
613 {
614     if ( date == NULL )
615         return RC ( rcFS, rcDirectory, rcAccessing, rcParam, rcNull );
616 
617     * date = 0;
618 
619     if ( self == NULL )
620         return RC ( rcFS, rcDirectory, rcAccessing, rcSelf, rcNull );
621 
622     if ( path == NULL )
623         return RC ( rcFS, rcDirectory, rcAccessing, rcPath, rcNull );
624     if ( path [ 0 ] == 0 )
625         return RC ( rcFS, rcDirectory, rcAccessing, rcPath, rcInvalid );
626 
627     switch ( self -> vt -> v1 . maj )
628     {
629     case 1:
630         if ( self -> vt -> v1 . min >= 1 )
631             return ( * self -> vt -> v1 . date ) ( self, date, path, args );
632         break;
633     }
634 
635     return RC ( rcFS, rcDirectory, rcAccessing, rcInterface, rcBadVersion );
636 }
637 
638 
639 /* SetDate
640  *  set date to object
641  *
642  *  "recurse" [ IN ] - if non zero and "path" is a directory,
643  *  apply changes recursively.
644  *
645  *  "date" [ IN ] - new time and date for the object
646  *
647  *  "path" [ IN ] - NUL terminated string in directory-native
648  *  character set denoting target object
649  */
KDirectorySetDate_v1(KDirectory_v1 * self,bool recurse,KTime_t date,const char * path,...)650 LIB_EXPORT rc_t CC KDirectorySetDate_v1 ( KDirectory_v1 *self, bool recurse,
651     KTime_t date, const char *path, ... )
652 {
653     rc_t rc;
654     va_list args;
655 
656     va_start ( args, path );
657     rc = KDirectoryVSetDate ( self, recurse,
658 			      date, path, args );
659     va_end ( args );
660 
661     return rc;
662 }
663 
KDirectoryVSetDate(KDirectory_v1 * self,bool recurse,KTime_t date,const char * path,va_list args)664 LIB_EXPORT rc_t CC KDirectoryVSetDate ( KDirectory_v1 *self, bool recurse,
665     KTime_t date, const char *path, va_list args )
666 {
667     if ( self == NULL )
668         return RC ( rcFS, rcDirectory, rcUpdating, rcSelf, rcNull );
669 
670     if ( path == NULL )
671         return RC ( rcFS, rcDirectory, rcUpdating, rcPath, rcNull );
672     if ( path [ 0 ] == 0 )
673         return RC ( rcFS, rcDirectory, rcUpdating, rcPath, rcInvalid );
674 
675     if ( self -> read_only )
676         return RC ( rcFS, rcDirectory, rcUpdating, rcDirectory, rcReadonly );
677 
678     switch ( self -> vt -> v1 . maj )
679     {
680     case 1:
681         /* TBD - perhaps limit bits to lower 9 */
682         if ( self -> vt -> v1 . min >= 1 )
683             return ( * self -> vt -> v1 . setdate ) ( self, recurse, date, path, args );
684         break;
685     }
686 
687     return RC ( rcFS, rcDirectory, rcUpdating, rcInterface, rcBadVersion );
688 }
689 
690 
691 /* CreateAlias
692  *  creates a path alias according to create mode
693  *
694  *  "access" [ IN ] - standard Unix directory access mode
695  *  used when "mode" has kcmParents set and alias path does
696  *  not exist.
697  *
698  *  "mode" [ IN ] - a creation mode ( see explanation above ).
699  *
700  *  "targ" [ IN ] - NUL terminated string in directory-native
701  *  character set denoting target object
702  *
703  *  "alias" [ IN ] - NUL terminated string in directory-native
704  *  character set denoting target alias
705  */
KDirectoryCreateAlias_v1(KDirectory_v1 * self,uint32_t access,KCreateMode mode,const char * targ,const char * alias)706 LIB_EXPORT rc_t CC KDirectoryCreateAlias_v1 ( KDirectory_v1 *self,
707     uint32_t access, KCreateMode mode,
708     const char *targ, const char *alias )
709 {
710     if ( self == NULL )
711         return RC ( rcFS, rcDirectory, rcUpdating, rcSelf, rcNull );
712 
713     if ( targ == NULL || alias == NULL )
714         return RC ( rcFS, rcDirectory, rcCreating, rcPath, rcNull );
715     if ( targ [ 0 ] == 0 || alias [ 0 ] == 0 )
716         return RC ( rcFS, rcDirectory, rcCreating, rcPath, rcInvalid );
717 
718     if ( self -> read_only )
719         return RC ( rcFS, rcDirectory, rcUpdating, rcDirectory, rcReadonly );
720 
721     switch ( self -> vt -> v1 . maj )
722     {
723     case 1:
724         return ( * self -> vt -> v1 . create_alias )
725             ( self, access, mode, targ, alias );
726     }
727 
728     return RC ( rcFS, rcDirectory, rcUpdating, rcInterface, rcBadVersion );
729 }
730 
731 
732 /* CreateLink ( v1.5 )
733  *  creates a new link (also known as a hard link).
734  *
735  *  "access" [ IN ] - standard Unix directory access mode
736  *  used when "mode" has kcmParents set and new link path does
737  *  not exist.
738  *
739  *  "mode" [ IN ] - a creation mode ( see explanation in kfs/defs.h ).
740  *
741  *  "oldpath" [ IN ] - NUL terminated string in directory-native
742  *  character set denoting existing object. THE PATH IS GIVEN RELATIVE
743  *  TO DIRECTORY ( "self" ), NOT LINK ( "newpath" )!
744  *
745  *  "newpath" [ IN ] - NUL terminated string in directory-native
746  *  character set denoting a new link.
747  */
KDirectoryCreateLink_v1(KDirectory_v1 * self,uint32_t access,KCreateMode mode,const char * oldpath,const char * newpath)748 LIB_EXPORT rc_t CC KDirectoryCreateLink_v1 ( KDirectory_v1 *self,
749     uint32_t access, KCreateMode mode,
750     const char *oldpath, const char *newpath )
751 {
752     if ( self == NULL )
753         return RC ( rcFS, rcDirectory, rcUpdating, rcSelf, rcNull );
754 
755     if ( oldpath == NULL || newpath == NULL )
756         return RC ( rcFS, rcDirectory, rcCreating, rcPath, rcNull );
757     if ( oldpath [ 0 ] == 0 || newpath [ 0 ] == 0 )
758         return RC ( rcFS, rcDirectory, rcCreating, rcPath, rcInvalid );
759 
760     if ( self -> read_only )
761         return RC ( rcFS, rcDirectory, rcUpdating, rcDirectory, rcReadonly );
762 
763     switch ( self -> vt -> v1 . maj )
764     {
765     case 1:
766         if ( self -> vt -> v1 . min >= 5 )
767         {
768             return ( * self -> vt -> v1 . create_link )
769                 ( self, access, mode, oldpath, newpath );
770         }
771         break;
772     }
773 
774     return RC ( rcFS, rcDirectory, rcUpdating, rcInterface, rcBadVersion );
775 }
776 
777 /* OpenFileRead
778  *  opens an existing file with read-only access
779  *
780  *  "f" [ OUT ] - return parameter for newly opened file
781  *
782  *  "path" [ IN ] - NUL terminated string in directory-native
783  *  character set denoting target file
784  */
KDirectoryOpenFileRead_v1(const KDirectory_v1 * self,struct KFile const ** f,const char * path,...)785 LIB_EXPORT rc_t CC KDirectoryOpenFileRead_v1 ( const KDirectory_v1 *self,
786     struct KFile const **f, const char *path, ... )
787 {
788     rc_t rc;
789     va_list args;
790 
791     va_start ( args, path );
792     rc = KDirectoryVOpenFileRead ( self, f, path, args );
793     va_end ( args );
794 
795     return rc;
796 }
797 
KDirectoryVOpenFileRead(const KDirectory_v1 * self,struct KFile const ** f,const char * path,va_list args)798 LIB_EXPORT rc_t CC KDirectoryVOpenFileRead ( const KDirectory_v1 *self,
799     struct KFile const **f, const char *path, va_list args )
800 {
801     if ( f == NULL )
802         return RC ( rcFS, rcDirectory, rcOpening, rcFile, rcNull );
803 
804     * f = NULL;
805 
806     if ( self == NULL )
807         return RC ( rcFS, rcDirectory, rcOpening, rcSelf, rcNull );
808 
809     if ( path == NULL )
810         return RC ( rcFS, rcDirectory, rcOpening, rcPath, rcNull );
811     if ( path [ 0 ] == 0 )
812         return RC ( rcFS, rcDirectory, rcOpening, rcPath, rcInvalid );
813 
814     switch ( self -> vt -> v1 . maj )
815     {
816     case 1:
817         return ( * self -> vt -> v1 . open_file_read ) ( self, f, path, args );
818     }
819 
820     return RC ( rcFS, rcDirectory, rcOpening, rcInterface, rcBadVersion );
821 }
822 
823 /* OpenFileWrite
824  *  opens an existing file with write access
825  *
826  *  "f" [ OUT ] - return parameter for newly opened file
827  *
828  *  "update" [ IN ] - if non-zero, open in read/write mode
829  *  otherwise, open in write-only mode
830  *
831  *  "path" [ IN ] - NUL terminated string in directory-native
832  *  character set denoting target file
833  */
KDirectoryOpenFileWrite_v1(KDirectory_v1 * self,struct KFile ** f,bool update,const char * path,...)834 LIB_EXPORT rc_t CC KDirectoryOpenFileWrite_v1 ( KDirectory_v1 *self,
835     struct KFile **f, bool update, const char *path, ... )
836 {
837     rc_t rc;
838     va_list args;
839 
840     va_start ( args, path );
841     rc = KDirectoryVOpenFileWrite ( self, f, update, path, args );
842     va_end ( args );
843 
844     return rc;
845 }
846 
KDirectoryVOpenFileWrite(KDirectory_v1 * self,struct KFile ** f,bool update,const char * path,va_list args)847 LIB_EXPORT rc_t CC KDirectoryVOpenFileWrite ( KDirectory_v1 *self,
848     struct KFile **f, bool update, const char *path, va_list args )
849 {
850     if ( f == NULL )
851         return RC ( rcFS, rcDirectory, rcOpening, rcFile, rcNull );
852 
853     * f = NULL;
854 
855     if ( self == NULL )
856         return RC ( rcFS, rcDirectory, rcOpening, rcSelf, rcNull );
857 
858     if ( path == NULL )
859         return RC ( rcFS, rcDirectory, rcOpening, rcPath, rcNull );
860     if ( path [ 0 ] == 0 )
861         return RC ( rcFS, rcDirectory, rcOpening, rcPath, rcInvalid );
862 
863 
864     if ( self -> read_only )
865         return RC ( rcFS, rcDirectory, rcOpening, rcDirectory, rcReadonly );
866 
867     switch ( self -> vt -> v1 . maj )
868     {
869     case 1:
870         return ( * self -> vt -> v1 . open_file_write )
871             ( self, f, update, path, args );
872     }
873 
874     return RC ( rcFS, rcDirectory, rcOpening, rcInterface, rcBadVersion );
875 }
876 
877 /* OpenFileSharedWrite ( v1.4 )
878  *  opens an existing file with shared write access
879  *
880  *  "f" [ OUT ] - return parameter for newly opened file
881  *
882  *  "update" [ IN ] - if true, open in read/write mode
883  *  otherwise, open in write-only mode
884  *
885  *  "path" [ IN ] - NUL terminated string in directory-native
886  *  character set denoting target file
887  */
KDirectoryOpenFileSharedWrite_v1(KDirectory_v1 * self,struct KFile ** f,bool update,const char * path,...)888 LIB_EXPORT rc_t CC KDirectoryOpenFileSharedWrite_v1 ( KDirectory_v1 *self,
889     struct KFile **f, bool update, const char *path, ... )
890 {
891     rc_t rc;
892     va_list args;
893 
894     va_start ( args, path );
895     rc = KDirectoryVOpenFileSharedWrite ( self, f, update, path, args );
896     va_end ( args );
897 
898     return rc;
899 }
900 
KDirectoryVOpenFileSharedWrite(KDirectory_v1 * self,struct KFile ** f,bool update,const char * path,va_list args)901 LIB_EXPORT rc_t CC KDirectoryVOpenFileSharedWrite ( KDirectory_v1 *self,
902     struct KFile **f, bool update, const char *path, va_list args )
903 {
904     if ( f == NULL )
905         return RC ( rcFS, rcDirectory, rcOpening, rcFile, rcNull );
906 
907     * f = NULL;
908 
909     if ( self == NULL )
910         return RC ( rcFS, rcDirectory, rcOpening, rcSelf, rcNull );
911 
912     if ( path == NULL )
913         return RC ( rcFS, rcDirectory, rcOpening, rcPath, rcNull );
914     if ( path [ 0 ] == 0 )
915         return RC ( rcFS, rcDirectory, rcOpening, rcPath, rcInvalid );
916 
917 
918     if ( self -> read_only )
919         return RC ( rcFS, rcDirectory, rcOpening, rcDirectory, rcReadonly );
920 
921     switch ( self -> vt -> v1 . maj )
922     {
923     case 1:
924         if ( self -> vt -> v1 . min >= 4 )
925         {
926             return ( * self -> vt -> v1 . open_file_shared_write )
927                 ( self, f, update, path, args );
928         }
929         break;
930     }
931 
932     return RC ( rcFS, rcDirectory, rcOpening, rcInterface, rcBadVersion );
933 }
934 
935 /* CreateFile
936  *  opens a file with write access
937  *
938  *  "f" [ OUT ] - return parameter for newly opened file
939  *
940  *  "update" [ IN ] - if non-zero, open in read/write mode
941  *  otherwise, open in write-only mode
942  *
943  *  "access" [ IN ] - standard Unix access mode, e.g. 0664
944  *
945  *  "mode" [ IN ] - a creation mode ( see explanation above ).
946  *
947  *  "path" [ IN ] - NUL terminated string in directory-native
948  *  character set denoting target file
949  */
KDirectoryCreateFile_v1(KDirectory_v1 * self,struct KFile ** f,bool update,uint32_t access,KCreateMode mode,const char * path,...)950 LIB_EXPORT rc_t CC KDirectoryCreateFile_v1 ( KDirectory_v1 *self, struct KFile **f,
951     bool update, uint32_t access, KCreateMode mode, const char *path, ... )
952 {
953     rc_t rc;
954     va_list args;
955 
956     va_start ( args, path );
957     rc = KDirectoryVCreateFile ( self, f, update,
958         access, mode, path, args );
959     va_end ( args );
960 
961     return rc;
962 }
963 
KDirectoryVCreateFile(KDirectory_v1 * self,struct KFile ** f,bool update,uint32_t access,KCreateMode mode,const char * path,va_list args)964 LIB_EXPORT rc_t CC KDirectoryVCreateFile ( KDirectory_v1 *self, struct KFile **f,
965     bool update, uint32_t access, KCreateMode mode, const char *path, va_list args )
966 {
967     if ( f == NULL )
968         return RC ( rcFS, rcDirectory, rcCreating, rcFile, rcNull );
969 
970     * f = NULL;
971 
972     if ( self == NULL )
973         return RC ( rcFS, rcDirectory, rcCreating, rcSelf, rcNull );
974 
975     if ( path == NULL )
976         return RC ( rcFS, rcDirectory, rcCreating, rcPath, rcNull );
977     if ( path [ 0 ] == 0 )
978         return RC ( rcFS, rcDirectory, rcCreating, rcPath, rcInvalid );
979 
980 
981     if ( self -> read_only )
982         return RC ( rcFS, rcDirectory, rcCreating, rcDirectory, rcReadonly );
983 
984     switch ( self -> vt -> v1 . maj )
985     {
986     case 1:
987         return ( * self -> vt -> v1 . create_file )
988             ( self, f, update, access, mode, path, args );
989     }
990 
991     return RC ( rcFS, rcDirectory, rcCreating, rcInterface, rcBadVersion );
992 }
993 
994 /* FileLocator
995  *  returns locator in bytes of target file
996  *
997  *  "locator" [ OUT ] - return parameter for file locator
998  *
999  *  "path" [ IN ] - NUL terminated string in directory-native
1000  *  character set denoting target file
1001  */
KDirectoryFileLocator_v1(const KDirectory_v1 * self,uint64_t * locator,const char * path,...)1002 LIB_EXPORT rc_t CC KDirectoryFileLocator_v1 ( const KDirectory_v1 *self,
1003     uint64_t *locator, const char *path, ... )
1004 {
1005     rc_t rc;
1006     va_list args;
1007 
1008     va_start ( args, path );
1009     rc = KDirectoryVFileLocator ( self, locator, path, args );
1010     va_end ( args );
1011 
1012     return rc;
1013 }
1014 
KDirectoryVFileLocator(const KDirectory_v1 * self,uint64_t * locator,const char * path,va_list args)1015 LIB_EXPORT rc_t CC KDirectoryVFileLocator ( const KDirectory_v1 *self,
1016     uint64_t *locator, const char *path, va_list args )
1017 {
1018     if ( locator == NULL )
1019         return RC ( rcFS, rcDirectory, rcAccessing, rcParam, rcNull );
1020 
1021     * locator = 0;
1022 
1023     if ( self == NULL )
1024         return RC ( rcFS, rcDirectory, rcAccessing, rcSelf, rcNull );
1025     if ( path == NULL )
1026         return RC ( rcFS, rcDirectory, rcAccessing, rcPath, rcNull );
1027     if ( path [ 0 ] == 0 )
1028         return RC ( rcFS, rcDirectory, rcAccessing, rcPath, rcInvalid );
1029 
1030     switch ( self -> vt -> v1 . maj )
1031     {
1032     case 1:
1033         if ( self -> vt -> v1 . min >= 2 )
1034             return ( * self -> vt -> v1 . file_locator ) ( self, locator, path, args );
1035         break;
1036     }
1037 
1038     return RC ( rcFS, rcDirectory, rcAccessing, rcInterface, rcBadVersion );
1039 }
1040 
1041 /* FileSize
1042  *  returns size in bytes of target file
1043  *
1044  *  "size" [ OUT ] - return parameter for file size
1045  *
1046  *  "path" [ IN ] - NUL terminated string in directory-native
1047  *  character set denoting target file
1048  */
KDirectoryFileSize_v1(const KDirectory_v1 * self,uint64_t * size,const char * path,...)1049 LIB_EXPORT rc_t CC KDirectoryFileSize_v1 ( const KDirectory_v1 *self,
1050     uint64_t *size, const char *path, ... )
1051 {
1052     rc_t rc;
1053     va_list args;
1054 
1055     va_start ( args, path );
1056     rc = KDirectoryVFileSize ( self, size, path, args );
1057     va_end ( args );
1058 
1059     return rc;
1060 }
1061 
KDirectoryVFileSize(const KDirectory_v1 * self,uint64_t * size,const char * path,va_list args)1062 LIB_EXPORT rc_t CC KDirectoryVFileSize ( const KDirectory_v1 *self,
1063     uint64_t *size, const char *path, va_list args )
1064 {
1065     if ( size == NULL )
1066         return RC ( rcFS, rcDirectory, rcAccessing, rcParam, rcNull );
1067 
1068     * size = 0;
1069 
1070     if ( self == NULL )
1071         return RC ( rcFS, rcDirectory, rcAccessing, rcSelf, rcNull );
1072     if ( path == NULL )
1073         return RC ( rcFS, rcDirectory, rcAccessing, rcPath, rcNull );
1074     if ( path [ 0 ] == 0 )
1075         return RC ( rcFS, rcDirectory, rcAccessing, rcPath, rcInvalid );
1076 
1077     switch ( self -> vt -> v1 . maj )
1078     {
1079     case 1:
1080         return ( * self -> vt -> v1 . file_size ) ( self, size, path, args );
1081     }
1082 
1083     return RC ( rcFS, rcDirectory, rcAccessing, rcInterface, rcBadVersion );
1084 }
1085 
1086 /* FilePhysicalSize
1087  *  returns size in bytes of target file
1088  *
1089  *  "size" [ OUT ] - return parameter for file size
1090  *
1091  *  "path" [ IN ] - NUL terminated string in directory-native
1092  *  character set denoting target file
1093  */
KDirectoryFilePhysicalSize_v1(const KDirectory_v1 * self,uint64_t * size,const char * path,...)1094 LIB_EXPORT rc_t CC KDirectoryFilePhysicalSize_v1 ( const KDirectory_v1 *self,
1095     uint64_t *size, const char *path, ... )
1096 {
1097     rc_t rc;
1098     va_list args;
1099 
1100     va_start ( args, path );
1101     rc = KDirectoryVFilePhysicalSize ( self, size, path, args );
1102     va_end ( args );
1103 
1104     return rc;
1105 }
1106 
KDirectoryVFilePhysicalSize(const KDirectory_v1 * self,uint64_t * size,const char * path,va_list args)1107 LIB_EXPORT rc_t CC KDirectoryVFilePhysicalSize ( const KDirectory_v1 *self,
1108     uint64_t *size, const char *path, va_list args )
1109 {
1110     if ( size == NULL )
1111         return RC ( rcFS, rcDirectory, rcAccessing, rcParam, rcNull );
1112 
1113     * size = 0;
1114 
1115     if ( self == NULL )
1116         return RC ( rcFS, rcDirectory, rcAccessing, rcSelf, rcNull );
1117     if ( path == NULL )
1118         return RC ( rcFS, rcDirectory, rcAccessing, rcPath, rcNull );
1119     if ( path [ 0 ] == 0 )
1120         return RC ( rcFS, rcDirectory, rcAccessing, rcPath, rcInvalid );
1121 
1122     switch ( self -> vt -> v1 . maj )
1123     {
1124     case 1:
1125         if ( self -> vt -> v1 . min >= 3 )
1126             return ( * self -> vt -> v1 . file_phys_size ) ( self, size, path, args );
1127         break;
1128     }
1129 
1130     return RC ( rcFS, rcDirectory, rcAccessing, rcInterface, rcBadVersion );
1131 }
1132 
1133 /* SetFileSize
1134  *  sets size in bytes of target file
1135  *
1136  *  "size" [ IN ] - new file size
1137  *
1138  *  "path" [ IN ] - NUL terminated string in directory-native
1139  *  character set denoting target file
1140  */
KDirectorySetFileSize_v1(KDirectory_v1 * self,uint64_t size,const char * path,...)1141 LIB_EXPORT rc_t CC KDirectorySetFileSize_v1 ( KDirectory_v1 *self,
1142     uint64_t size, const char *path, ... )
1143 {
1144     rc_t rc;
1145     va_list args;
1146 
1147     va_start ( args, path );
1148     rc = KDirectoryVSetFileSize ( self, size, path, args );
1149     va_end ( args );
1150 
1151     return rc;
1152 }
1153 
KDirectoryVSetFileSize(KDirectory_v1 * self,uint64_t size,const char * path,va_list args)1154 LIB_EXPORT rc_t CC KDirectoryVSetFileSize ( KDirectory_v1 *self,
1155     uint64_t size, const char *path, va_list args )
1156 {
1157     if ( self == NULL )
1158         return RC ( rcFS, rcDirectory, rcUpdating, rcSelf, rcNull );
1159 
1160     if ( path == NULL )
1161         return RC ( rcFS, rcDirectory, rcUpdating, rcPath, rcNull );
1162     if ( path [ 0 ] == 0 )
1163         return RC ( rcFS, rcDirectory, rcUpdating, rcPath, rcInvalid );
1164 
1165     if ( self -> read_only )
1166         return RC ( rcFS, rcDirectory, rcUpdating, rcDirectory, rcReadonly );
1167 
1168     switch ( self -> vt -> v1 . maj )
1169     {
1170     case 1:
1171         return ( * self -> vt -> v1 . set_size ) ( self, size, path, args );
1172     }
1173 
1174     return RC ( rcFS, rcDirectory, rcAccessing, rcInterface, rcBadVersion );
1175 }
1176 
1177 /* FileContiguous
1178  *  returns true if the file is "contiguous".  Chunked or sparse files are not
1179  *  contiguous while most data files are.  Virtual generated files would likely
1180  *  not be contiguous.
1181  *
1182  *  "contiguous" [ OUT ] - return parameter for file contiguous
1183  *
1184  *  "path" [ IN ] - NUL terminated string in directory-native
1185  *  character set denoting target file
1186  */
KDirectoryFileContiguous_v1(const KDirectory_v1 * self,bool * contiguous,const char * path,...)1187 LIB_EXPORT rc_t CC KDirectoryFileContiguous_v1 ( const KDirectory_v1 *self,
1188     bool *contiguous, const char *path, ... )
1189 {
1190     rc_t rc;
1191     va_list args;
1192 
1193     va_start ( args, path );
1194     rc = KDirectoryVFileContiguous ( self, contiguous, path, args );
1195     va_end ( args );
1196 
1197     return rc;
1198 }
1199 
KDirectoryVFileContiguous(const KDirectory_v1 * self,bool * contiguous,const char * path,va_list args)1200 LIB_EXPORT rc_t CC KDirectoryVFileContiguous ( const KDirectory_v1 *self,
1201     bool *contiguous, const char *path, va_list args )
1202 {
1203     if ( contiguous == NULL )
1204         return RC ( rcFS, rcDirectory, rcAccessing, rcParam, rcNull );
1205 
1206     * contiguous = 0;
1207 
1208     if ( self == NULL )
1209         return RC ( rcFS, rcDirectory, rcAccessing, rcSelf, rcNull );
1210     if ( path == NULL )
1211         return RC ( rcFS, rcDirectory, rcAccessing, rcPath, rcNull );
1212     if ( path [ 0 ] == 0 )
1213         return RC ( rcFS, rcDirectory, rcAccessing, rcPath, rcInvalid );
1214 
1215     switch ( self -> vt -> v1 . maj )
1216     {
1217     case 1:
1218         if ( self -> vt -> v1 . min >= 3 )
1219             return ( * self -> vt -> v1 . file_contiguous ) ( self, contiguous, path, args );
1220         break;
1221     }
1222 
1223     return RC ( rcFS, rcDirectory, rcAccessing, rcInterface, rcBadVersion );
1224 }
1225 
1226 /* OpenDirRead
1227  * KDirectoryOpenDirUpdate
1228  *  opens a sub-directory
1229  *
1230  *  "chroot" [ IN ] - if non-zero, the new directory becomes
1231  *  chroot'd and will interpret paths beginning with '/'
1232  *  relative to itself.
1233  *
1234  *  "path" [ IN ] - NUL terminated string in directory-native
1235  *  character set denoting target directory
1236  */
KDirectoryOpenDirRead_v1(const KDirectory_v1 * self,const KDirectory_v1 ** sub,bool chroot,const char * path,...)1237 LIB_EXPORT rc_t CC KDirectoryOpenDirRead_v1 ( const KDirectory_v1 *self,
1238     const KDirectory_v1 **sub, bool chroot, const char *path, ... )
1239 {
1240     rc_t rc;
1241     va_list args;
1242 
1243     va_start ( args, path );
1244     rc = KDirectoryVOpenDirRead ( self, sub, chroot, path, args );
1245     va_end ( args );
1246 
1247     return rc;
1248 }
1249 
KDirectoryVOpenDirRead(const KDirectory_v1 * self,const KDirectory_v1 ** sub,bool chroot,const char * path,va_list args)1250 LIB_EXPORT rc_t CC KDirectoryVOpenDirRead ( const KDirectory_v1 *self,
1251     const KDirectory_v1 **sub, bool chroot, const char *path, va_list args )
1252 {
1253     if ( sub == NULL )
1254         return RC ( rcFS, rcDirectory, rcOpening, rcDirectory, rcNull );
1255 
1256     * sub = NULL;
1257 
1258     if ( self == NULL )
1259         return RC ( rcFS, rcDirectory, rcOpening, rcSelf, rcNull );
1260 
1261     if ( path == NULL || path [ 0 ] == 0 )
1262         path = ".";
1263 
1264     switch ( self -> vt -> v1 . maj )
1265     {
1266     case 1:
1267         return ( * self -> vt -> v1 . open_dir_read )
1268             ( self, sub, chroot, path, args );
1269     }
1270 
1271     return RC ( rcFS, rcDirectory, rcOpening, rcInterface, rcBadVersion );
1272 }
1273 
KDirectoryOpenDirUpdate_v1(KDirectory_v1 * self,KDirectory_v1 ** sub,bool chroot,const char * path,...)1274 LIB_EXPORT rc_t CC KDirectoryOpenDirUpdate_v1 ( KDirectory_v1 *self,
1275     KDirectory_v1 **sub, bool chroot, const char *path, ... )
1276 {
1277     rc_t rc;
1278     va_list args;
1279 
1280     va_start ( args, path );
1281     rc = KDirectoryVOpenDirUpdate ( self, sub, chroot, path, args );
1282     va_end ( args );
1283 
1284     return rc;
1285 }
1286 
KDirectoryVOpenDirUpdate(KDirectory_v1 * self,KDirectory_v1 ** sub,bool chroot,const char * path,va_list args)1287 LIB_EXPORT rc_t CC KDirectoryVOpenDirUpdate ( KDirectory_v1 *self,
1288     KDirectory_v1 **sub, bool chroot, const char *path, va_list args )
1289 {
1290     if ( sub == NULL )
1291         return RC ( rcFS, rcDirectory, rcOpening, rcDirectory, rcNull );
1292 
1293     * sub = NULL;
1294 
1295     if ( self == NULL )
1296         return RC ( rcFS, rcDirectory, rcOpening, rcSelf, rcNull );
1297 
1298     if ( self -> read_only )
1299         /* TODO: Maybe for writing wncbi-vdb we need to return RC */
1300         return SILENT_RC ( rcFS, rcDirectory, rcOpening, rcDirectory, rcReadonly );
1301 
1302     if ( path == NULL || path [ 0 ] == 0 )
1303         path = ".";
1304 
1305     switch ( self -> vt -> v1 . maj )
1306     {
1307     case 1:
1308         return ( * self -> vt -> v1 . open_dir_update )
1309             ( self, sub, chroot, path, args );
1310     }
1311 
1312     return RC ( rcFS, rcDirectory, rcOpening, rcInterface, rcBadVersion );
1313 }
1314 
1315 /* CreateDir
1316  *  create a sub-directory
1317  *
1318  *  "access" [ IN ] - standard Unix directory mode, e.g.0775
1319  *
1320  *  "mode" [ IN ] - a creation mode ( see explanation above ).
1321  *
1322  *  "path" [ IN ] - NUL terminated string in directory-native
1323  *  character set denoting target directory
1324  */
KDirectoryCreateDir_v1(KDirectory_v1 * self,uint32_t access,KCreateMode mode,const char * path,...)1325 LIB_EXPORT rc_t CC KDirectoryCreateDir_v1 ( KDirectory_v1 *self,
1326     uint32_t access, KCreateMode mode, const char *path, ... )
1327 {
1328     rc_t rc;
1329     va_list args;
1330 
1331     va_start ( args, path );
1332     rc = KDirectoryVCreateDir ( self, access, mode, path, args );
1333     va_end ( args );
1334 
1335     return rc;
1336 }
1337 
KDirectoryVCreateDir(KDirectory_v1 * self,uint32_t access,KCreateMode mode,const char * path,va_list args)1338 LIB_EXPORT rc_t CC KDirectoryVCreateDir ( KDirectory_v1 *self,
1339     uint32_t access, KCreateMode mode, const char *path, va_list args )
1340 {
1341     if ( self == NULL )
1342         return RC ( rcFS, rcDirectory, rcCreating, rcSelf, rcNull );
1343 
1344     if ( path == NULL )
1345         return RC ( rcFS, rcDirectory, rcCreating, rcPath, rcNull );
1346     if ( path [ 0 ] == 0 )
1347         return RC ( rcFS, rcDirectory, rcCreating, rcPath, rcInvalid );
1348 
1349     if ( self -> read_only )
1350         return RC ( rcFS, rcDirectory, rcCreating, rcDirectory, rcReadonly );
1351 
1352     switch ( self -> vt -> v1 . maj )
1353     {
1354     case 1:
1355         return ( * self -> vt -> v1 . create_dir ) ( self, access, mode, path, args );
1356     }
1357 
1358     return RC ( rcFS, rcDirectory, rcCreating, rcInterface, rcBadVersion );
1359 }
1360 
1361 /* Init
1362  *  initialize a newly allocated directory object
1363  */
KDirectoryInit_v1(KDirectory_v1 * self,const KDirectory_vt * vt,const char * class_name,const char * path,bool update)1364 LIB_EXPORT rc_t CC KDirectoryInit_v1 ( KDirectory_v1 *self, const KDirectory_vt *vt,
1365     const char * class_name, const char * path, bool update )
1366 {
1367     if ( self == NULL )
1368         return RC ( rcFS, rcDirectory, rcConstructing, rcSelf, rcNull );
1369     if ( vt == NULL )
1370         return RC ( rcFS, rcDirectory, rcConstructing, rcInterface, rcNull );
1371     switch ( vt -> v1 . maj )
1372     {
1373     case 0:
1374         return RC ( rcFS, rcDirectory, rcConstructing, rcInterface, rcInvalid );
1375     case 1:
1376         switch ( vt -> v1 . min )
1377         {
1378             /* ADD NEW MINOR VERSION CASES HERE */
1379         case 5:
1380 #if _DEBUGGING
1381             if ( vt -> v1 . create_link == NULL )
1382                 return RC ( rcFS, rcFile, rcConstructing,
1383                     rcInterface, rcNull );
1384 #endif
1385             /* no break */
1386         case 4:
1387 #if _DEBUGGING
1388             if ( vt -> v1 . open_file_shared_write == NULL )
1389                 return RC ( rcFS, rcFile, rcConstructing, rcInterface, rcNull );
1390 #endif
1391             /* no break */
1392         case 3:
1393 #if _DEBUGGING
1394             if ( vt -> v1 . file_phys_size == NULL  ||
1395                  vt -> v1 . file_contiguous == NULL )
1396                 return RC ( rcFS, rcFile, rcConstructing, rcInterface, rcNull );
1397 #endif
1398             /* no break */
1399         case 2:
1400 #if _DEBUGGING
1401             if ( vt -> v1 . file_locator == NULL )
1402                 return RC ( rcFS, rcFile, rcConstructing, rcInterface, rcNull );
1403 #endif
1404             /* no break */
1405         case 1:
1406 #if _DEBUGGING
1407             if ( vt -> v1 . get_sysdir == NULL      ||
1408                  vt -> v1 . setdate == NULL         ||
1409                  vt -> v1 . date == NULL )
1410                 return RC ( rcFS, rcFile, rcConstructing, rcInterface, rcNull );
1411 #endif
1412             /* no break */
1413         case 0:
1414 #if _DEBUGGING
1415             /* vt -> v1 . destroy_file CAN be NULL */
1416             if ( vt -> v1 . create_dir == NULL      ||
1417                  vt -> v1 . open_dir_update == NULL ||
1418                  vt -> v1 . open_dir_read == NULL   ||
1419                  vt -> v1 . set_size == NULL        ||
1420                  vt -> v1 . file_size == NULL       ||
1421                  vt -> v1 . create_file == NULL     ||
1422                  vt -> v1 . open_file_write == NULL ||
1423                  vt -> v1 . open_file_read == NULL  ||
1424                  vt -> v1 . create_alias == NULL    ||
1425                  vt -> v1 . set_access == NULL      ||
1426                  vt -> v1 . access == NULL          ||
1427                  vt -> v1 . clear_dir == NULL       ||
1428                  vt -> v1 . remove == NULL          ||
1429                  vt -> v1 . rename == NULL          ||
1430                  vt -> v1 . resolve_alias == NULL   ||
1431                  vt -> v1 . resolve_path == NULL    ||
1432                  vt -> v1 . path_type == NULL       ||
1433                  vt -> v1 . visit_update == NULL    ||
1434                  vt -> v1 . visit == NULL           ||
1435                  vt -> v1 . list_dir == NULL        ||
1436                  vt -> v1 . destroy == NULL )
1437                 return RC ( rcFS, rcFile, rcConstructing, rcInterface, rcNull );
1438 #endif
1439             break;
1440         default:
1441             return RC ( rcFS, rcDirectory, rcConstructing, rcInterface, rcBadVersion );
1442         }
1443         break;
1444     default:
1445         return RC ( rcFS, rcDirectory, rcConstructing, rcInterface, rcBadVersion );
1446     }
1447 
1448     self -> vt = vt;
1449     self -> read_only = ( uint8_t ) ( update == 0 );
1450 
1451 
1452     KRefcountInit ( &self->refcount, 1, class_name, "init", path );
1453 
1454     return 0;
1455 }
1456 
1457 /* DestroyFile
1458  *  does whatever is necessary with an unreferenced file
1459  */
KDirectoryDestroyFile_v1(const KDirectory_v1 * self,KFile * f)1460 LIB_EXPORT rc_t CC KDirectoryDestroyFile_v1 ( const KDirectory_v1 *self, KFile *f )
1461 {
1462     const KDirectory_vt *vt = self -> vt;
1463     switch ( vt -> v1 . maj )
1464     {
1465     case 1:
1466         if ( vt -> v1 . destroy_file != NULL )
1467             return ( * vt -> v1 . destroy_file ) ( ( KDirectory_v1* ) self, f );
1468         return KFileDestroy_v1 ( f );
1469     }
1470 
1471     return RC ( rcFS, rcDirectory, rcDestroying, rcInterface, rcBadVersion );
1472 }
1473 
1474 /* GetSysDir
1475  *  returns an underlying system file object
1476  */
KDirectoryGetSysDir_v1(const KDirectory_v1 * self)1477 LIB_EXPORT struct KSysDir_v1* CC KDirectoryGetSysDir_v1 ( const KDirectory_v1 *self )
1478 {
1479     if ( self != NULL )
1480     {
1481         switch ( self -> vt -> v1 . maj )
1482         {
1483         case 1:
1484             if ( self -> vt -> v1 . min > 0 )
1485                 return ( * self -> vt -> v1 . get_sysdir ) ( self );
1486             break;
1487         }
1488     }
1489     return NULL;
1490 }
1491 
1492 
copy_loop(const KFile * src,KFile * dst,size_t bsize)1493 static rc_t copy_loop( const KFile *src, KFile *dst, size_t bsize )
1494 {
1495     rc_t rc = 0;
1496     uint64_t pos = 0;
1497     size_t num_read = 1;
1498 
1499     char * buffer = malloc( bsize );
1500     if ( buffer == NULL )
1501         return RC( rcFS, rcDirectory, rcCopying, rcMemory, rcExhausted );
1502 
1503     while ( rc == 0 && num_read > 0 )
1504     {
1505         rc = KFileRead ( src, pos, buffer, bsize, &num_read );
1506         if ( rc == 0 && num_read > 0 )
1507         {
1508             size_t num_writ;
1509             rc = KFileWrite ( dst, pos, buffer, num_read, &num_writ );
1510             pos += num_read;
1511         }
1512     }
1513     free( buffer );
1514     return rc;
1515 }
1516 
1517 
KDirectoryCopyPath(const KDirectory_v1 * src_dir,KDirectory_v1 * dst_dir,const char * src_path,const char * dst_path)1518 LIB_EXPORT rc_t CC KDirectoryCopyPath ( const KDirectory_v1 *src_dir,
1519     KDirectory_v1 *dst_dir, const char *src_path, const char * dst_path )
1520 {
1521     rc_t rc;
1522     struct KFile const *f_src;
1523 
1524     if ( src_dir == NULL || dst_dir == NULL )
1525         return RC ( rcFS, rcDirectory, rcCopying, rcSelf, rcNull );
1526     if ( src_path == NULL || dst_path == NULL )
1527         return RC ( rcFS, rcDirectory, rcCopying, rcParam, rcNull );
1528 
1529     rc = KDirectoryOpenFileRead ( src_dir, &f_src, "%s", src_path );
1530     if ( rc == 0 )
1531     {
1532         uint32_t pt = KDirectoryPathType ( dst_dir, "%s", dst_path );
1533         switch( pt )
1534         {
1535             case kptFile : ; /* intentional fall through! */
1536             case kptDir  : rc = KDirectoryRemove ( dst_dir, true, "%s", dst_path ); break;
1537         }
1538         if ( rc == 0 )
1539         {
1540             struct KFile *f_dst;
1541             uint32_t access = 0664;
1542             rc = KDirectoryCreateFile ( dst_dir, &f_dst, false, access, kcmCreate, "%s", dst_path );
1543             if ( rc == 0 )
1544             {
1545                 rc = copy_loop( f_src, f_dst, 1024 * 1024 );
1546                 KFileRelease(f_dst);
1547             }
1548         }
1549         KFileRelease(f_src);
1550     }
1551     return rc;
1552 }
1553 
1554 
build_obj_path(char ** s,const char * path,const char * objname)1555 static rc_t build_obj_path( char **s, const char *path, const char * objname )
1556 {
1557     rc_t rc;
1558     size_t lp = string_size( path );
1559     size_t l = lp + string_size( objname ) + 2;
1560     *s = malloc( l );
1561     if ( *s == NULL )
1562         rc = RC( rcFS, rcDirectory, rcCopying, rcMemory, rcExhausted );
1563     else
1564     {
1565         size_t written;
1566         const char * concat = ( ( path[ lp - 1 ] == '/' ) ? "%s%s" : "%s/%s" );
1567         rc = string_printf( *s, l, &written, concat, path, objname );
1568     }
1569     return rc;
1570 }
1571 
1572 
KDirectoryCopyPaths(const KDirectory_v1 * src_dir,KDirectory_v1 * dst_dir,bool recursive,const char * src,const char * dst)1573 LIB_EXPORT rc_t CC KDirectoryCopyPaths( const KDirectory_v1 * src_dir,
1574     KDirectory_v1 * dst_dir, bool recursive, const char *src, const char *dst )
1575 {
1576     rc_t rc;
1577     struct KNamelist *list;
1578 
1579     if ( src_dir == NULL || dst_dir == NULL )
1580         return RC ( rcFS, rcDirectory, rcCopying, rcSelf, rcNull );
1581     if ( src == NULL || dst == NULL )
1582         return RC ( rcFS, rcDirectory, rcCopying, rcParam, rcNull );
1583 
1584     rc = KDirectoryList ( src_dir, &list, NULL, NULL, "%s", src );
1585     if ( rc == 0 )
1586     {
1587         uint32_t pt = KDirectoryPathType ( dst_dir, "%s", dst );
1588         /* if the output-directory does not exist: create it! */
1589         switch( pt )
1590         {
1591             case kptFile : rc = KDirectoryRemove ( dst_dir, true, "%s", dst );
1592                             /* intentially no break ! */
1593 
1594             case kptNotFound : if ( rc == 0 )
1595                                     rc = KDirectoryCreateDir ( dst_dir, 0775, kcmCreate | kcmParents, "%s", dst );
1596                                break;
1597         }
1598         if ( rc == 0 )
1599         {
1600             uint32_t i, n;
1601             rc = KNamelistCount ( list, &n );
1602             for ( i = 0; i < n && rc == 0; ++i )
1603             {
1604                 const char *name;
1605                 rc = KNamelistGet ( list, i, &name );
1606                 if ( rc == 0 )
1607                 {
1608                     char *src_obj;
1609                     rc = build_obj_path( &src_obj, src, name );
1610                     if ( rc == 0 )
1611                     {
1612                         char *dst_obj;
1613                         rc = build_obj_path( &dst_obj, dst, name );
1614                         if ( rc == 0 )
1615                         {
1616                             pt = KDirectoryPathType ( src_dir, "%s", src_obj );
1617                             switch( pt )
1618                             {
1619                                 case kptFile : rc = KDirectoryCopyPath ( src_dir, dst_dir, src_obj, dst_obj );
1620                                                break;
1621 
1622                                 case kptDir  : if ( recursive )
1623                                                     rc = KDirectoryCopyPaths( src_dir, dst_dir, true, src_obj, dst_obj );
1624                                                break;
1625                             }
1626                             free( dst_obj );
1627                         }
1628                         free( src_obj );
1629                     }
1630                 }
1631             }
1632         }
1633         KNamelistRelease ( list );
1634     }
1635     return rc;
1636 }
1637 
1638 
KDirectoryCopy(const KDirectory_v1 * src_dir,KDirectory_v1 * dst_dir,bool recursive,const char * src,const char * dst)1639 LIB_EXPORT rc_t CC KDirectoryCopy( const KDirectory_v1 * src_dir,
1640     KDirectory_v1 * dst_dir, bool recursive, const char *src, const char *dst )
1641 {
1642     rc_t rc = 0;
1643     uint32_t pt;
1644 
1645     if ( src_dir == NULL || dst_dir == NULL )
1646         return RC ( rcFS, rcDirectory, rcCopying, rcSelf, rcNull );
1647     if ( src == NULL || dst == NULL )
1648         return RC ( rcFS, rcDirectory, rcCopying, rcParam, rcNull );
1649 
1650     pt = KDirectoryPathType ( src_dir, "%s", src );
1651     switch( pt )
1652     {
1653         case kptFile : rc = KDirectoryCopyPath ( src_dir, dst_dir, src, dst );
1654                         break;
1655         case kptDir  : rc = KDirectoryCopyPaths ( src_dir, dst_dir, recursive, src, dst );
1656                         break;
1657     }
1658     return rc;
1659 }
1660