开发者

stdio's remove() not always deleting on time

开发者 https://www.devze.com 2022-12-26 08:57 出处:网络
For a particular piece of homework, I\'m implementing a basic data storage system using sequential files under standard C, which cannot load more than 1 record at a time. So, the basic part is creatin

For a particular piece of homework, I'm implementing a basic data storage system using sequential files under standard C, which cannot load more than 1 record at a time. So, the basic part is creating a new file where the results of whatever we do with the original records are stored. The previous file's renamed, and a new one under the working name is created. The code's compiled with MinGW 5.1.6 on Windows 7.

Problem is, this particular version of the code (I've got nearly-identical versions of this floating around my functions) doesn't always remove the old file, so the rename fails and hence the stored data gets wiped by the fopen().

FILE *archivo, *antiguo;

remove("IndiceNecesidades.old");  // This randomly fails to work in time.
rename("IndiceNecesidades.dat", "IndiceNecesidades.old"); // So rename() fails.

antiguo = fopen("IndiceNecesidades.old", "rb");
// But apparently it still gets deleted, since this turns out null (and I never find the .old in my working folder after the program's done).
archivo = fopen("IndiceNecesidades.dat", "wb"); // And here the data gets wiped.

Basically, anytime the .old previously exists, there's a chance it's not removed in time for the rename() to take effect successfully. No possible name conflicts both internally and externally.

The we开发者_开发知识库ird thing's that it's only with this particular file. Identical snippets except with the name changed to Necesidades.dat (which happen in 3 different functions) work perfectly fine.

// I'm yet to see this snippet fail.
FILE *antiguo, *archivo;

remove("Necesidades.old");
rename("Necesidades.dat", "Necesidades.old");

antiguo = fopen("Necesidades.old", "rb");
archivo = fopen("Necesidades.dat", "wb");

Any ideas on why would this happen, and/or how can I ensure the remove() command has taken effect by the time rename() is executed? (I thought of just using a while loop to force call remove() again so long as fopen() returns a non-null pointer, but that sounds like begging for a crash due to overflowing the OS with delete requests or something.)


So suddenly, after reading Scott's mention of permissions, I thought about "Permission Denied" and applied some Google. Turned out it's a pretty common, if obscure, error. caf was right, it was in another piece of code. Namely, I had forgotten to fclose that same file in the function meant to show the contents. Since I wasn't tracking that particular detail, it appeared to be random.

Disclaimer: Weekly math assigments make for very little sleeptime. ¬¬


That sounds quite strange, and even more so when you say that the same code works OK with a different filename - I would strongly suspect a bug elsewhere in your code. However, you should be able to work around it by renaming the file you want to remove:

rename("IndiceNecesidades.old", "IndiceNecesidades.older");
remove("IndiceNecesidades.older");
rename("IndiceNecesidades.dat", "IndiceNecesidades.old");


It would probably be a good idea to check the remove() function for errors. man remove says that the function returns 0 on success and -1 on failure, setting errno to record the error. Try replacing the call with

if (remove("IndiceNecesidades.old") != 0){
   perror("remove(\"IndiceNecesidades.old\") failed");
}

which should give an error message saying what failed.

Further, it doesn't appear that the remove is neccessary

man rename()

The rename() system call causes the link named old to be renamed as new. If new exists, it is first removed. Both old and new must be of the same type (that is, both must be either directories or non-directories) and must reside on the same file system.

The rename() system call guarantees that an instance of new will always exist, even if the system should crash in the middle of the operation.

If the final component of old is a symbolic link, the symbolic link is renamed, not the file or directory to which it points.

EPERM will be returned if:

[EPERM] The directory containing old is marked sticky, and neither the containing directory nor old are owned by the effective user ID.

[EPERM] The new file exists, the directory containing new is marked sticky, and neither the containing directory nor new are owned by the effec- tive user ID.

so the next step would be to check you have permissions on the containing directory

0

精彩评论

暂无评论...
验证码 换一张
取 消