I have the following code snippet:
static const unsigned MAX_DIR_ITEMS = 4;
void fetchAlbum(int sd, const unsigned volref, const char *root, const char *name) {
int dirItems = MAX_DIR_ITEMS;
VFSDirInfo dirInfo[MAX_DIR_ITEMS];
FileRef dirRef;
if (dlp_VFSFileOpen(sd, volref, srcAlbumDir, vfsModeRead, &dirRef) < 0) {
jp_logf(L_GUI, "Could not open dir '%s' on volume %d\n", srcAlbumDir, volref);
return;
}
enum dlpVFSFileIteratorConstants itr = vfsIteratorStart;
while (itr != vfsIteratorStop) {
PI_ERR bytes;
itr = vfsIteratorStart;
jp_logf(L_DEBUG, "Enumerate dir '%s', dirRef=%d, itr=%d, dirItems=%d\n", srcAlbumDir, dirRef, (int)itr, dirItems);
if ((bytes = dlp_VFSDirEntryEnumerate(sd, dirRef, (unsigned long *)&itr, &dirItems, dirInfo)) < 0) {
jp_logf(L_FATAL, "Enumerate ERROR: bytes=%d, dirRef=%d, itr=%d, dirItems=%d\n", bytes, dirRef, (int)itr, dirItems);
break;
} else {
jp_logf(L_DEBUG, "Enumerate OK: bytes=%d, dirRef=%d, itr=%d, dirItems=%d\n", bytes, dirRef, (int)itr, dirItems);
}
The used functions are defined as:
/** @file pi-args.h
* @brief Macros for prototype definitions
*
*/
#if ((defined(__STDC__) || defined(SABER)) && !defined(NO_PROTOTYPE)) || defined(__cplusplus) || defined(USE_PROTOTYPE) || defined(CAN_PROTOTYPE)
# define PI_ARGS(x) x
# define PI_CONST const
#else
# define PI_ARGS(x) ()
# define PI_CONST
#endif
typedef unsigned long FileRef; /**< Type for file references when working with VFS files and directories. */
/** @name Expansion manager and VFS manager constants */
/*@{*/
/** @brief VFS file iterator constants */
enum dlpVFSFileIteratorConstants {
vfsIteratorStart = 0, /** < Indicates that iterator is beginning */
vfsIteratorStop = -1 /**< Indicate that iterator has gone through all items */
};
/*@}*/
/** @name Expansion manager functions */
/*@{*/
/** @brief Iterate through the entries in a directory
*
* Supported on Palm OS 4.0 and later. At the beginning you set
* @p dirIterator to #vfsIteratorStart, then call this function
* repeatedly until it returns an error code of the iterator becomes
* #vfsIteratorStop.
*
* @bug On some early OS 5 devices like Tungsten T and Sony NX70, NX73 this
* call crashes the device. This has been confirmed to be a bug in HotSync on
* the device, as tests showed that a regular HotSync conduit does crash the
* device with this call too.
*
* @param sd Socket number
* @param dirref Directory reference obtained from dlp_VFSFileOpen()
* @param diriterator Ptr to an iterator. Start with #vfsIteratorStart
* @param maxitems On input, the max number of VFSDirInfo structures stored in @p dirItems. On output, the actual number of items.
* @param diritems Preallocated array that contains a number of VFSDirInfo structures on return.
* @return A negative value if an error occured (see pi-error.h)
*/
extern PI_ERR dlp_VFSDirEntryEnumerate
PI_ARGS((int sd, FileRef dirref, unsigned long *diriterator,
int *maxitems, struct VFSDirInfo *diritems));
/*@}*/
With this code I get the following surprising output. So I'm wondering, how variable dirRef
could change its value.
Enumerate dir '/Photos & Videos', dirRef=445317240, itr=0, dirItems=4
Enumerate OK: bytes=170, dirRef=0, itr=-1, dirItems=4
The library I'm using comes from here: https://github.com/desrod/pilot-link
CodePudding user response:
Passing a variable by value does not provide a way to change it inside the function.
int foo(int x)
{
x = x *2;
return x;
}
The variable x
is automatic local variable and if you change it inside the function it will not affect the object which was passed to the function by value.
example:
int main(void)
{
int y = 4;
foo(y);
printf("%d\n", y);
}
Output: 4
.
You can be sure that the variable passed to this function will not change due to changes made to the parameter inside the function. It is guaranteed by the C standard.
Is it possible, that the macro PI_ARGS changes something in invisible way?
No, you can easily check it yourself by browsing the git repo you posted:
#if ((defined(__STDC__) || defined(SABER)) && !defined(NO_PROTOTYPE)) || defined(__cplusplus) || defined(USE_PROTOTYPE) || defined(CAN_PROTOTYPE)
# define PI_ARGS(x) x
# define PI_CONST const
#else
# define PI_ARGS(x) ()
# define PI_CONST
#endif
PS Sometimes people are confused by macros like functions.
#define X2(x) ((x) = (x) * 2)
int main(void)
{
int y = 5;
X2(y);
printf("%d\n", y);
}
CodePudding user response:
I've found out the cause for the problem with the following code.
It appears, that unsigned long
has 64 bits on my machine. I always thought, that for a 64 bit variable I would need unsigned long long
.
So when function dlp_VFSDirEntryEnumerate()
returns, itr
is written back as 64 bit value as fault and the variable dirItems
becomes partly overwritten. The still only mystery is, that dirItems
becomes 0
instead ffffffff
.
static const unsigned MIN_DIR_ITEMS = 16;
static const unsigned MAX_DIR_ITEMS = 1024;
void fetchAlbum(int sd, const unsigned volref, const char *root, const char *name) {
int dirItems = MIN_DIR_ITEMS;
VFSDirInfo dirInfos[MAX_DIR_ITEMS];
char srcAlbumDir[strlen(root) (name ? strlen(name) : 0) 2];
FileRef dirRef;
printf("[GUI] Fetching album '%s' on volume %d\n", name, volref);
strcpy(srcAlbumDir, root); // Album is in /<root>/<name>.
// Unfiled album is really just root dir.
if (name) {
strcat(strcat(srcAlbumDir, "/"), name);
}
if (dlp_VFSFileOpen(sd, volref, srcAlbumDir, vfsModeRead, &dirRef) < 0) {
return;
}
// Iterate over all the files in the album dir, looking for jpegs and 3gp's and 3g2's (videos).
enum dlpVFSFileIteratorConstants itr = vfsIteratorStart;
printf("[DEBUG] &dirItems='%p', sizeof(dirItems)=%lu\n", &dirItems, sizeof(dirItems));
printf("[DEBUG] &dirRef= '%p', sizeof(dirRef)=%lu\n", &dirRef, sizeof(dirRef));
printf("[DEBUG] &itr= '%p', sizeof(itr)=%lu\n", &itr, sizeof(itr));
printf("[DEBUG] sizeof(int)=%lu\n", sizeof(int));
printf("[DEBUG] sizeof(long)=%lu\n", sizeof(long));
printf("[DEBUG] sizeof(unsigned)=%lu\n", sizeof(unsigned));
printf("[DEBUG] sizeof(unsigned long)=%lu\n", sizeof(unsigned long));
printf("[DEBUG] sizeof(unsigned long long)=%lu\n", sizeof(unsigned long long));
for (int dirItems_backup; (dirItems_backup = dirItems) <= MAX_DIR_ITEMS; dirItems *= 2) {
PI_ERR bytes;
itr = vfsIteratorStart;
FileRef dirRef_backup = dirRef; // Unfortunately the following call deletes the original value
printf("[DEBUG] Enumerate album '%s', dirRef=%llx, itr=%llx, dirItems=%d\n", srcAlbumDir, dirRef, (long long int)itr, dirItems);
if ((bytes = dlp_VFSDirEntryEnumerate(sd, dirRef, (unsigned long *)&itr, &dirItems, dirInfos)) < 0) {
printf("[FATAL] Enumerate ERROR: bytes=%d, dirRef=%llx, itr=%llx, dirItems=%d\n", bytes, dirRef, (long long int)itr, dirItems);
break;
}
printf("[DEBUG] Enumerate OK: bytes=%d, dirRef=%llx, itr=%llx, dirItems=%d\n", bytes, dirRef, (long long int)itr, dirItems);
dirRef = dirRef_backup;
printf("[DEBUG] Rescued from backup: dirRef=%llx\n", dirRef);
if (dirItems < dirItems_backup) {
break;
}
}
dlp_VFSFileClose(sd, dirRef);
[.....] // process files from the retrieved dirInfos
return;
}
This is the output I get:
[GUI] Fetching album '(null)' on volume 1
[DEBUG] &dirItems='0x7ffee6335848', sizeof(dirItems)=4
[DEBUG] &dirRef= '0x7ffee6335850', sizeof(dirRef)=8
[DEBUG] &itr= '0x7ffee633584c', sizeof(itr)=4
[DEBUG] sizeof(int)=4
[DEBUG] sizeof(long)=8
[DEBUG] sizeof(unsigned)=4
[DEBUG] sizeof(unsigned long)=8
[DEBUG] sizeof(unsigned long long)=8
[DEBUG] Enumerate album '/Photos & Videos', dirRef=20a70070, itr=0, dirItems=16
[DEBUG] Enumerate OK: bytes=170, dirRef=0, itr=ffffffffffffffff, dirItems=8
[DEBUG] Rescued from backup: dirRef=20a70070
So the correct code now is:
unsigned long itr;
[.....]
itr = (unsigned long)vfsIteratorStart;
if ((bytes = dlp_VFSDirEntryEnumerate(sd, dirRef, &itr, &dirItems, dirInfos)) < 0) {